From bdc2295ee46e92a92df085025cc15e00e5278393 Mon Sep 17 00:00:00 2001 From: KoDer Date: Fri, 29 May 2026 13:04:54 +0700 Subject: [PATCH] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D0=B0=20=D0=BF=D0=B0=D0=BF=D0=BA=D0=B0=20source=20=D0=B2?= =?UTF-8?q?=20CristalDiskMark?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../source/CrystalDiskMark/AboutDlg.cpp | 279 + .../source/CrystalDiskMark/AboutDlg.h | 67 + .../CrystalDiskMark/DeclareDPIAware.manifest | 22 + .../source/CrystalDiskMark/DiskBench.cpp | 935 ++ .../source/CrystalDiskMark/DiskBench.h | 88 + .../source/CrystalDiskMark/DiskMark.cpp | 117 + .../source/CrystalDiskMark/DiskMark.h | 24 + .../source/CrystalDiskMark/DiskMark.rc | 477 + .../source/CrystalDiskMark/DiskMark.sln | 114 + .../source/CrystalDiskMark/DiskMark.vcxproj | 3345 ++++++ .../CrystalDiskMark/DiskMark.vcxproj.filters | 171 + .../source/CrystalDiskMark/DiskMarkDlg.cpp | 3793 +++++++ .../source/CrystalDiskMark/DiskMarkDlg.h | 292 + .../CrystalDiskMark/FontSelectionDlg.cpp | 243 + .../source/CrystalDiskMark/FontSelectionDlg.h | 48 + .../source/CrystalDiskMark/Library/Resource.h | 183 + .../source/CrystalDiskMark/Library/stdafx.cpp | 5 + .../source/CrystalDiskMark/Library/stdafx.h | 228 + .../CrystalDiskMark/Priscilla/ButtonFx.cpp | 991 ++ .../CrystalDiskMark/Priscilla/ButtonFx.h | 131 + .../CrystalDiskMark/Priscilla/ComboBoxFx.cpp | 836 ++ .../CrystalDiskMark/Priscilla/ComboBoxFx.h | 130 + .../CrystalDiskMark/Priscilla/CommonFx.h | 89 + .../CrystalDiskMark/Priscilla/DarkMode.cpp | 261 + .../CrystalDiskMark/Priscilla/DarkMode.h | 18 + .../CrystalDiskMark/Priscilla/DialogFx.cpp | 738 ++ .../CrystalDiskMark/Priscilla/DialogFx.h | 156 + .../CrystalDiskMark/Priscilla/EditFx.cpp | 629 ++ .../source/CrystalDiskMark/Priscilla/EditFx.h | 98 + .../Priscilla/FontComboBoxFx.cpp | 134 + .../Priscilla/FontComboBoxFx.h | 27 + .../Priscilla/HeaderCtrlFx.cpp | 203 + .../CrystalDiskMark/Priscilla/HeaderCtrlFx.h | 45 + .../CrystalDiskMark/Priscilla/IatHook.h | 99 + .../CrystalDiskMark/Priscilla/ImageFx.h | 420 + .../CrystalDiskMark/Priscilla/ImageToast.cpp | 269 + .../CrystalDiskMark/Priscilla/ImageToast.h | 60 + .../CrystalDiskMark/Priscilla/ListCtrlFx.cpp | 372 + .../CrystalDiskMark/Priscilla/ListCtrlFx.h | 85 + .../Priscilla/MainDialogFx.cpp | 1070 ++ .../CrystalDiskMark/Priscilla/MainDialogFx.h | 85 + .../CrystalDiskMark/Priscilla/OsInfoFx.cpp | 1558 +++ .../CrystalDiskMark/Priscilla/OsInfoFx.h | 242 + .../CrystalDiskMark/Priscilla/ScrollBarFx.cpp | 93 + .../CrystalDiskMark/Priscilla/ScrollBarFx.h | 40 + .../Priscilla/SliderCtrlFx.cpp | 129 + .../CrystalDiskMark/Priscilla/SliderCtrlFx.h | 48 + .../CrystalDiskMark/Priscilla/StaticFx.cpp | 917 ++ .../CrystalDiskMark/Priscilla/StaticFx.h | 135 + .../Priscilla/SystemInfoFx.cpp | 1887 ++++ .../CrystalDiskMark/Priscilla/SystemInfoFx.h | 30 + .../CrystalDiskMark/Priscilla/UAHMenuBar.cpp | 205 + .../CrystalDiskMark/Priscilla/UAHMenuBar.h | 78 + .../CrystalDiskMark/Priscilla/UtilityFx.cpp | 1038 ++ .../CrystalDiskMark/Priscilla/UtilityFx.h | 143 + .../source/CrystalDiskMark/Priscilla/md5.cpp | 226 + .../source/CrystalDiskMark/Priscilla/md5.h | 29 + .../CrystalDiskMark/Priscilla/stb_image.h | 7988 ++++++++++++++ .../Priscilla/stb_image_impl.cpp | 17 + .../Priscilla/stb_image_write.h | 1724 +++ .../Priscilla/stb_image_write_impl.cpp | 13 + .../source/CrystalDiskMark/SettingsDlg.cpp | 700 ++ .../source/CrystalDiskMark/SettingsDlg.h | 108 + .../source/CrystalDiskMark/res/DiskMark.ico | Bin 0 -> 103179 bytes .../source/CrystalDiskMark/res/DiskMark.rc2 | 13 + .../source/CrystalDiskMark/res/DiskMark16.ico | Bin 0 -> 2550 bytes .../source/CrystalDiskMark/res/DiskMarkA.ico | Bin 0 -> 59640 bytes .../CrystalDiskMark/res/DiskMarkA16.ico | Bin 0 -> 26054 bytes .../source/CrystalDiskMark/res/DiskMarkS.ico | Bin 0 -> 60200 bytes .../CrystalDiskMark/res/DiskMarkS16.ico | Bin 0 -> 6030 bytes .../source/License/COPYRIGHT-ja.txt | 17 + CristalDiskMark/source/License/COPYRIGHT.txt | 19 + .../source/License/DiskSpd-LICENSE.txt | 19 + .../source/License/PolyHook_2_0-LICENSE.txt | 21 + ...in32-custom-menubar-aero-theme-LICENSE.txt | 21 + .../source/License/win32-darkmode-LICENSE.txt | 21 + .../source/diskspd22/.gitattributes | 26 + CristalDiskMark/source/diskspd22/.gitignore | 184 + .../diskspd22/CmdLineParser/CmdLineParser.cpp | 2080 ++++ .../CmdRequestCreator/CmdRequestCreator.cpp | 230 + .../diskspd22/CmdRequestCreator/diskspd.rc | 19 + .../source/diskspd22/Common/CmdLineParser.h | 73 + .../diskspd22/Common/CmdRequestCreator.h | 38 + .../source/diskspd22/Common/Common.cpp | 1273 +++ .../source/diskspd22/Common/Common.h | 2695 +++++ .../source/diskspd22/Common/Histogram.h | 330 + .../diskspd22/Common/IORequestGenerator.h | 84 + .../source/diskspd22/Common/IoBucketizer.cpp | 228 + .../source/diskspd22/Common/IoBucketizer.h | 73 + .../source/diskspd22/Common/OverlappedQueue.h | 50 + .../source/diskspd22/Common/ResultParser.h | 76 + .../source/diskspd22/Common/ThroughputMeter.h | 61 + .../source/diskspd22/Common/Version.h | 52 + .../diskspd22/Common/XmlProfileParser.h | 65 + .../source/diskspd22/Common/XmlResultParser.h | 61 + .../source/diskspd22/Common/errors.h | 38 + CristalDiskMark/source/diskspd22/Common/etw.h | 41 + .../Frameworks/VMFleet/ArcVM-Setup.md | 329 + .../diskspd22/Frameworks/VMFleet/Profile.psm1 | 1031 ++ .../Frameworks/VMFleet/VMFleet.Tests.ps1 | 728 ++ .../Frameworks/VMFleet/VMFleet.format.ps1xml | 82 + .../diskspd22/Frameworks/VMFleet/VMFleet.psd1 | 197 + .../diskspd22/Frameworks/VMFleet/VMFleet.psm1 | 9294 +++++++++++++++++ .../Frameworks/VMFleet/WatchCPU.psm1 | 282 + .../Frameworks/VMFleet/WatchCluster.psm1 | 552 + .../diskspd22/Frameworks/VMFleet1.0/README.md | 47 + .../VMFleet1.0/analyze-cputarget.ps1 | 79 + .../Frameworks/VMFleet1.0/check-outlier.ps1 | 201 + .../Frameworks/VMFleet1.0/check-pause.ps1 | 90 + .../Frameworks/VMFleet1.0/check-vmfleet.ps1 | 126 + .../Frameworks/VMFleet1.0/clear-pause.ps1 | 38 + .../Frameworks/VMFleet1.0/create-vmfleet.ps1 | 366 + .../diskspd22/Frameworks/VMFleet1.0/demo.ps1 | 72 + .../Frameworks/VMFleet1.0/destroy-vmfleet.ps1 | 102 + .../Frameworks/VMFleet1.0/get-cluspc.ps1 | 281 + .../Frameworks/VMFleet1.0/get-linfit.ps1 | 143 + .../Frameworks/VMFleet1.0/get-log.ps1 | 80 + .../Frameworks/VMFleet1.0/install-vmfleet.ps1 | 74 + .../Frameworks/VMFleet1.0/launch-template.ps1 | 34 + .../Frameworks/VMFleet1.0/master.ps1 | 225 + .../Frameworks/VMFleet1.0/run-demo-100r.ps1 | 39 + .../Frameworks/VMFleet1.0/run-demo-7030.ps1 | 38 + .../Frameworks/VMFleet1.0/run-demo-9010.ps1 | 38 + .../VMFleet1.0/run-sweeptemplate.ps1 | 78 + .../diskspd22/Frameworks/VMFleet1.0/run.ps1 | 94 + .../Frameworks/VMFleet1.0/s2d-vmfleet.docx | Bin 0 -> 46220 bytes .../Frameworks/VMFleet1.0/s2d-vmfleet.pdf | Bin 0 -> 1043401 bytes .../Frameworks/VMFleet1.0/set-pause.ps1 | 36 + .../Frameworks/VMFleet1.0/set-storageqos.ps1 | 54 + .../Frameworks/VMFleet1.0/set-vmfleet.ps1 | 157 + .../Frameworks/VMFleet1.0/start-sweep.ps1 | 506 + .../Frameworks/VMFleet1.0/start-vmfleet.ps1 | 53 + .../Frameworks/VMFleet1.0/stop-vmfleet.ps1 | 53 + .../Frameworks/VMFleet1.0/sweep-cputarget.ps1 | 212 + .../VMFleet1.0/test-clusterhealth.ps1 | 637 ++ .../Frameworks/VMFleet1.0/update-csv.ps1 | 132 + .../Frameworks/VMFleet1.0/wait-result.ps1 | 36 + .../Frameworks/VMFleet1.0/watch-cluster.ps1 | 531 + .../Frameworks/VMFleet1.0/watch-cpu.ps1 | 210 + .../IORequestGenerator/IORequestGenerator.cpp | 2866 +++++ .../IORequestGenerator/OverlappedQueue.cpp | 79 + .../IORequestGenerator/ThroughputMeter.cpp | 143 + .../diskspd22/IORequestGenerator/etw.cpp | 498 + CristalDiskMark/source/diskspd22/LICENSE | 21 + .../source/diskspd22/Process-DiskSpd.ps1 | 228 + CristalDiskMark/source/diskspd22/README.md | 150 + .../diskspd22/ResultParser/ResultParser.cpp | 1334 +++ CristalDiskMark/source/diskspd22/SECURITY.md | 41 + .../CmdLineParser/CmdLineParser.UnitTests.cpp | 4771 +++++++++ .../CmdLineParser/CmdLineParser.UnitTests.h | 117 + .../UnitTests/CmdLineParser/CmdLineParser.rc | 17 + .../UnitTests/CmdLineParser/stdafx.h | 33 + .../UnitTests/Common/Common.UnitTests.cpp | 1229 +++ .../UnitTests/Common/Common.UnitTests.h | 130 + .../diskspd22/UnitTests/Common/Common.rc | 17 + .../diskspd22/UnitTests/Common/stdafx.h | 33 + .../IORequestGenerator.UnitTests.cpp | 1327 +++ .../IORequestGenerator.UnitTests.h | 64 + .../IORequestGenerator/IORequestGenerator.rc | 17 + .../UnitTests/IORequestGenerator/stdafx.h | 33 + .../ResultParser/ResultParser.UnitTests.cpp | 965 ++ .../ResultParser/ResultParser.UnitTests.h | 52 + .../UnitTests/ResultParser/ResultParser.rc | 17 + .../diskspd22/UnitTests/ResultParser/stdafx.h | 33 + .../XmlProfileParser.UnitTests.cpp | 1672 +++ .../XmlProfileParser.UnitTests.h | 116 + .../XmlProfileParser/XmlProfileParser.rc | 19 + .../UnitTests/XmlProfileParser/stdafx.h | 32 + .../XmlResultParser.UnitTests.cpp | 464 + .../XmlResultParser.UnitTests.h | 47 + .../XmlResultParser/XmlResultParser.rc | 17 + .../UnitTests/XmlResultParser/stdafx.h | 32 + .../XmlProfileParser/XmlProfileParser.cpp | 1533 +++ .../diskspd22/XmlProfileParser/diskspd.xsd | 400 + .../XmlResultParser/XmlResultParser.cpp | 620 ++ CristalDiskMark/source/diskspd22/diskspd.wprp | 39 + .../CmdLineParser/CmdLineParser.vcxproj | 272 + .../CmdRequestCreator.vcxproj | 300 + .../diskspd_vs/Common/Common.vcxproj | 248 + .../IORequestGenerator.vcxproj | 278 + .../ResultParser/ResultParser.vcxproj | 272 + .../source/diskspd22/diskspd_vs/UnitTests.sln | 81 + .../CmdLineParser/CmdLineParser.vcxproj | 174 + .../UnitTests/Common/Common.vcxproj | 174 + .../IORequestGenerator.vcxproj | 174 + .../ResultParser/ResultParser.vcxproj | 174 + .../XmlProfileParser/XmlProfileParser.vcxproj | 174 + .../XmlResultParser/XmlResultParser.vcxproj | 174 + .../XmlProfileParser/XmlProfileParser.vcxproj | 275 + .../XmlResultParser/XmlResultParser.vcxproj | 301 + .../source/diskspd22/diskspd_vs/diskspd.sln | 159 + .../CmdLineParser/CmdLineParser.cpp | 1120 ++ .../CmdLineParser/CmdLineParser.h | 64 + .../CmdRequestCreator/CmdRequestCreator.cpp | 219 + .../CmdRequestCreator/CmdRequestCreator.h | 38 + .../diskspd2_0_15a/CmdRequestCreator/errors.h | 38 + .../source/diskspd2_0_15a/Common/Common.cpp | 685 ++ .../source/diskspd2_0_15a/Common/Common.h | 814 ++ .../source/diskspd2_0_15a/Common/Histogram.h | 273 + .../diskspd2_0_15a/Common/IoBucketizer.cpp | 143 + .../diskspd2_0_15a/Common/IoBucketizer.h | 52 + .../diskspd2_0_15a/DiskSpd_Documentation.docx | Bin 0 -> 220916 bytes .../diskspd2_0_15a/DiskSpd_Documentation.pdf | Bin 0 -> 1277955 bytes .../IORequestGenerator/IORequestGenerator.cpp | 2771 +++++ .../IORequestGenerator/IORequestGenerator.h | 87 + .../IORequestGenerator/OverlappedQueue.cpp | 79 + .../IORequestGenerator/OverlappedQueue.h | 50 + .../IORequestGenerator/ThroughputMeter.cpp | 123 + .../IORequestGenerator/ThroughputMeter.h | 61 + .../diskspd2_0_15a/IORequestGenerator/etw.cpp | 502 + .../diskspd2_0_15a/IORequestGenerator/etw.h | 41 + CristalDiskMark/source/diskspd2_0_15a/LICENSE | 21 + .../source/diskspd2_0_15a/LICENSE.txt | 21 + .../source/diskspd2_0_15a/README.md | 14 + .../ResultParser/ResultParser.cpp | 848 ++ .../ResultParser/ResultParser.h | 65 + .../XmlProfileParser/XmlProfileParser.cpp | 885 ++ .../XmlProfileParser/XmlProfileParser.h | 57 + .../diskspd2_0_15a/XmlProfileParser/diskspd.h | 273 + .../XmlProfileParser/diskspd.xsd | 236 + .../XmlResultParser/exe/DiskSpd32.exe | Bin 0 -> 365112 bytes .../XmlResultParser/exe/DiskSpd64.exe | Bin 0 -> 414776 bytes .../XmlResultParser/exe/DiskSpdA32.exe | Bin 0 -> 314424 bytes .../XmlResultParser/exe/DiskSpdA64.exe | Bin 0 -> 408632 bytes .../XmlResultParser/xmlresultparser.cpp | 482 + .../XmlResultParser/xmlresultparser.h | 53 + .../CmdLineParser/CmdLineParser.vcxproj | 153 + .../CmdLineParser/CmdLineParser.vcxproj.user | 4 + .../CmdRequestCreator.vcxproj | 166 + .../CmdRequestCreator.vcxproj.user | 4 + .../diskspd_vs2015/Common/Common.vcxproj | 145 + .../IORequestGenerator.vcxproj | 163 + .../ResultParser/ResultParser.vcxproj | 157 + .../XmlProfileParser/XmlProfileParser.vcxproj | 159 + .../diskspd_vs2015/XmlProfileParser/diskspd.h | 277 + .../XmlResultParser/XmlResultParser.vcxproj | 170 + .../diskspd_vs2015/diskspd_vs2013.v12.suo | Bin 0 -> 61952 bytes .../diskspd_vs2015/diskspd_vs2015.sln | 96 + .../source/diskspd2_0_15a/exe/DiskSpd32L.exe | Bin 0 -> 294968 bytes .../source/diskspd2_0_15a/exe/DiskSpd64L.exe | Bin 0 -> 350264 bytes 240 files changed, 94035 insertions(+) create mode 100644 CristalDiskMark/source/CrystalDiskMark/AboutDlg.cpp create mode 100644 CristalDiskMark/source/CrystalDiskMark/AboutDlg.h create mode 100644 CristalDiskMark/source/CrystalDiskMark/DeclareDPIAware.manifest create mode 100644 CristalDiskMark/source/CrystalDiskMark/DiskBench.cpp create mode 100644 CristalDiskMark/source/CrystalDiskMark/DiskBench.h create mode 100644 CristalDiskMark/source/CrystalDiskMark/DiskMark.cpp create mode 100644 CristalDiskMark/source/CrystalDiskMark/DiskMark.h create mode 100644 CristalDiskMark/source/CrystalDiskMark/DiskMark.rc create mode 100644 CristalDiskMark/source/CrystalDiskMark/DiskMark.sln create mode 100644 CristalDiskMark/source/CrystalDiskMark/DiskMark.vcxproj create mode 100644 CristalDiskMark/source/CrystalDiskMark/DiskMark.vcxproj.filters create mode 100644 CristalDiskMark/source/CrystalDiskMark/DiskMarkDlg.cpp create mode 100644 CristalDiskMark/source/CrystalDiskMark/DiskMarkDlg.h create mode 100644 CristalDiskMark/source/CrystalDiskMark/FontSelectionDlg.cpp create mode 100644 CristalDiskMark/source/CrystalDiskMark/FontSelectionDlg.h create mode 100644 CristalDiskMark/source/CrystalDiskMark/Library/Resource.h create mode 100644 CristalDiskMark/source/CrystalDiskMark/Library/stdafx.cpp create mode 100644 CristalDiskMark/source/CrystalDiskMark/Library/stdafx.h create mode 100644 CristalDiskMark/source/CrystalDiskMark/Priscilla/ButtonFx.cpp create mode 100644 CristalDiskMark/source/CrystalDiskMark/Priscilla/ButtonFx.h create mode 100644 CristalDiskMark/source/CrystalDiskMark/Priscilla/ComboBoxFx.cpp create mode 100644 CristalDiskMark/source/CrystalDiskMark/Priscilla/ComboBoxFx.h create mode 100644 CristalDiskMark/source/CrystalDiskMark/Priscilla/CommonFx.h create mode 100644 CristalDiskMark/source/CrystalDiskMark/Priscilla/DarkMode.cpp create mode 100644 CristalDiskMark/source/CrystalDiskMark/Priscilla/DarkMode.h create mode 100644 CristalDiskMark/source/CrystalDiskMark/Priscilla/DialogFx.cpp create mode 100644 CristalDiskMark/source/CrystalDiskMark/Priscilla/DialogFx.h create mode 100644 CristalDiskMark/source/CrystalDiskMark/Priscilla/EditFx.cpp create mode 100644 CristalDiskMark/source/CrystalDiskMark/Priscilla/EditFx.h create mode 100644 CristalDiskMark/source/CrystalDiskMark/Priscilla/FontComboBoxFx.cpp create mode 100644 CristalDiskMark/source/CrystalDiskMark/Priscilla/FontComboBoxFx.h create mode 100644 CristalDiskMark/source/CrystalDiskMark/Priscilla/HeaderCtrlFx.cpp create mode 100644 CristalDiskMark/source/CrystalDiskMark/Priscilla/HeaderCtrlFx.h create mode 100644 CristalDiskMark/source/CrystalDiskMark/Priscilla/IatHook.h create mode 100644 CristalDiskMark/source/CrystalDiskMark/Priscilla/ImageFx.h create mode 100644 CristalDiskMark/source/CrystalDiskMark/Priscilla/ImageToast.cpp create mode 100644 CristalDiskMark/source/CrystalDiskMark/Priscilla/ImageToast.h create mode 100644 CristalDiskMark/source/CrystalDiskMark/Priscilla/ListCtrlFx.cpp create mode 100644 CristalDiskMark/source/CrystalDiskMark/Priscilla/ListCtrlFx.h create mode 100644 CristalDiskMark/source/CrystalDiskMark/Priscilla/MainDialogFx.cpp create mode 100644 CristalDiskMark/source/CrystalDiskMark/Priscilla/MainDialogFx.h create mode 100644 CristalDiskMark/source/CrystalDiskMark/Priscilla/OsInfoFx.cpp create mode 100644 CristalDiskMark/source/CrystalDiskMark/Priscilla/OsInfoFx.h create mode 100644 CristalDiskMark/source/CrystalDiskMark/Priscilla/ScrollBarFx.cpp create mode 100644 CristalDiskMark/source/CrystalDiskMark/Priscilla/ScrollBarFx.h create mode 100644 CristalDiskMark/source/CrystalDiskMark/Priscilla/SliderCtrlFx.cpp create mode 100644 CristalDiskMark/source/CrystalDiskMark/Priscilla/SliderCtrlFx.h create mode 100644 CristalDiskMark/source/CrystalDiskMark/Priscilla/StaticFx.cpp create mode 100644 CristalDiskMark/source/CrystalDiskMark/Priscilla/StaticFx.h create mode 100644 CristalDiskMark/source/CrystalDiskMark/Priscilla/SystemInfoFx.cpp create mode 100644 CristalDiskMark/source/CrystalDiskMark/Priscilla/SystemInfoFx.h create mode 100644 CristalDiskMark/source/CrystalDiskMark/Priscilla/UAHMenuBar.cpp create mode 100644 CristalDiskMark/source/CrystalDiskMark/Priscilla/UAHMenuBar.h create mode 100644 CristalDiskMark/source/CrystalDiskMark/Priscilla/UtilityFx.cpp create mode 100644 CristalDiskMark/source/CrystalDiskMark/Priscilla/UtilityFx.h create mode 100644 CristalDiskMark/source/CrystalDiskMark/Priscilla/md5.cpp create mode 100644 CristalDiskMark/source/CrystalDiskMark/Priscilla/md5.h create mode 100644 CristalDiskMark/source/CrystalDiskMark/Priscilla/stb_image.h create mode 100644 CristalDiskMark/source/CrystalDiskMark/Priscilla/stb_image_impl.cpp create mode 100644 CristalDiskMark/source/CrystalDiskMark/Priscilla/stb_image_write.h create mode 100644 CristalDiskMark/source/CrystalDiskMark/Priscilla/stb_image_write_impl.cpp create mode 100644 CristalDiskMark/source/CrystalDiskMark/SettingsDlg.cpp create mode 100644 CristalDiskMark/source/CrystalDiskMark/SettingsDlg.h create mode 100644 CristalDiskMark/source/CrystalDiskMark/res/DiskMark.ico create mode 100644 CristalDiskMark/source/CrystalDiskMark/res/DiskMark.rc2 create mode 100644 CristalDiskMark/source/CrystalDiskMark/res/DiskMark16.ico create mode 100644 CristalDiskMark/source/CrystalDiskMark/res/DiskMarkA.ico create mode 100644 CristalDiskMark/source/CrystalDiskMark/res/DiskMarkA16.ico create mode 100644 CristalDiskMark/source/CrystalDiskMark/res/DiskMarkS.ico create mode 100644 CristalDiskMark/source/CrystalDiskMark/res/DiskMarkS16.ico create mode 100644 CristalDiskMark/source/License/COPYRIGHT-ja.txt create mode 100644 CristalDiskMark/source/License/COPYRIGHT.txt create mode 100644 CristalDiskMark/source/License/DiskSpd-LICENSE.txt create mode 100644 CristalDiskMark/source/License/PolyHook_2_0-LICENSE.txt create mode 100644 CristalDiskMark/source/License/win32-custom-menubar-aero-theme-LICENSE.txt create mode 100644 CristalDiskMark/source/License/win32-darkmode-LICENSE.txt create mode 100644 CristalDiskMark/source/diskspd22/.gitattributes create mode 100644 CristalDiskMark/source/diskspd22/.gitignore create mode 100644 CristalDiskMark/source/diskspd22/CmdLineParser/CmdLineParser.cpp create mode 100644 CristalDiskMark/source/diskspd22/CmdRequestCreator/CmdRequestCreator.cpp create mode 100644 CristalDiskMark/source/diskspd22/CmdRequestCreator/diskspd.rc create mode 100644 CristalDiskMark/source/diskspd22/Common/CmdLineParser.h create mode 100644 CristalDiskMark/source/diskspd22/Common/CmdRequestCreator.h create mode 100644 CristalDiskMark/source/diskspd22/Common/Common.cpp create mode 100644 CristalDiskMark/source/diskspd22/Common/Common.h create mode 100644 CristalDiskMark/source/diskspd22/Common/Histogram.h create mode 100644 CristalDiskMark/source/diskspd22/Common/IORequestGenerator.h create mode 100644 CristalDiskMark/source/diskspd22/Common/IoBucketizer.cpp create mode 100644 CristalDiskMark/source/diskspd22/Common/IoBucketizer.h create mode 100644 CristalDiskMark/source/diskspd22/Common/OverlappedQueue.h create mode 100644 CristalDiskMark/source/diskspd22/Common/ResultParser.h create mode 100644 CristalDiskMark/source/diskspd22/Common/ThroughputMeter.h create mode 100644 CristalDiskMark/source/diskspd22/Common/Version.h create mode 100644 CristalDiskMark/source/diskspd22/Common/XmlProfileParser.h create mode 100644 CristalDiskMark/source/diskspd22/Common/XmlResultParser.h create mode 100644 CristalDiskMark/source/diskspd22/Common/errors.h create mode 100644 CristalDiskMark/source/diskspd22/Common/etw.h create mode 100644 CristalDiskMark/source/diskspd22/Frameworks/VMFleet/ArcVM-Setup.md create mode 100644 CristalDiskMark/source/diskspd22/Frameworks/VMFleet/Profile.psm1 create mode 100644 CristalDiskMark/source/diskspd22/Frameworks/VMFleet/VMFleet.Tests.ps1 create mode 100644 CristalDiskMark/source/diskspd22/Frameworks/VMFleet/VMFleet.format.ps1xml create mode 100644 CristalDiskMark/source/diskspd22/Frameworks/VMFleet/VMFleet.psd1 create mode 100644 CristalDiskMark/source/diskspd22/Frameworks/VMFleet/VMFleet.psm1 create mode 100644 CristalDiskMark/source/diskspd22/Frameworks/VMFleet/WatchCPU.psm1 create mode 100644 CristalDiskMark/source/diskspd22/Frameworks/VMFleet/WatchCluster.psm1 create mode 100644 CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/README.md create mode 100644 CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/analyze-cputarget.ps1 create mode 100644 CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/check-outlier.ps1 create mode 100644 CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/check-pause.ps1 create mode 100644 CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/check-vmfleet.ps1 create mode 100644 CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/clear-pause.ps1 create mode 100644 CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/create-vmfleet.ps1 create mode 100644 CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/demo.ps1 create mode 100644 CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/destroy-vmfleet.ps1 create mode 100644 CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/get-cluspc.ps1 create mode 100644 CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/get-linfit.ps1 create mode 100644 CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/get-log.ps1 create mode 100644 CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/install-vmfleet.ps1 create mode 100644 CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/launch-template.ps1 create mode 100644 CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/master.ps1 create mode 100644 CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/run-demo-100r.ps1 create mode 100644 CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/run-demo-7030.ps1 create mode 100644 CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/run-demo-9010.ps1 create mode 100644 CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/run-sweeptemplate.ps1 create mode 100644 CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/run.ps1 create mode 100644 CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/s2d-vmfleet.docx create mode 100644 CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/s2d-vmfleet.pdf create mode 100644 CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/set-pause.ps1 create mode 100644 CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/set-storageqos.ps1 create mode 100644 CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/set-vmfleet.ps1 create mode 100644 CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/start-sweep.ps1 create mode 100644 CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/start-vmfleet.ps1 create mode 100644 CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/stop-vmfleet.ps1 create mode 100644 CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/sweep-cputarget.ps1 create mode 100644 CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/test-clusterhealth.ps1 create mode 100644 CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/update-csv.ps1 create mode 100644 CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/wait-result.ps1 create mode 100644 CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/watch-cluster.ps1 create mode 100644 CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/watch-cpu.ps1 create mode 100644 CristalDiskMark/source/diskspd22/IORequestGenerator/IORequestGenerator.cpp create mode 100644 CristalDiskMark/source/diskspd22/IORequestGenerator/OverlappedQueue.cpp create mode 100644 CristalDiskMark/source/diskspd22/IORequestGenerator/ThroughputMeter.cpp create mode 100644 CristalDiskMark/source/diskspd22/IORequestGenerator/etw.cpp create mode 100644 CristalDiskMark/source/diskspd22/LICENSE create mode 100644 CristalDiskMark/source/diskspd22/Process-DiskSpd.ps1 create mode 100644 CristalDiskMark/source/diskspd22/README.md create mode 100644 CristalDiskMark/source/diskspd22/ResultParser/ResultParser.cpp create mode 100644 CristalDiskMark/source/diskspd22/SECURITY.md create mode 100644 CristalDiskMark/source/diskspd22/UnitTests/CmdLineParser/CmdLineParser.UnitTests.cpp create mode 100644 CristalDiskMark/source/diskspd22/UnitTests/CmdLineParser/CmdLineParser.UnitTests.h create mode 100644 CristalDiskMark/source/diskspd22/UnitTests/CmdLineParser/CmdLineParser.rc create mode 100644 CristalDiskMark/source/diskspd22/UnitTests/CmdLineParser/stdafx.h create mode 100644 CristalDiskMark/source/diskspd22/UnitTests/Common/Common.UnitTests.cpp create mode 100644 CristalDiskMark/source/diskspd22/UnitTests/Common/Common.UnitTests.h create mode 100644 CristalDiskMark/source/diskspd22/UnitTests/Common/Common.rc create mode 100644 CristalDiskMark/source/diskspd22/UnitTests/Common/stdafx.h create mode 100644 CristalDiskMark/source/diskspd22/UnitTests/IORequestGenerator/IORequestGenerator.UnitTests.cpp create mode 100644 CristalDiskMark/source/diskspd22/UnitTests/IORequestGenerator/IORequestGenerator.UnitTests.h create mode 100644 CristalDiskMark/source/diskspd22/UnitTests/IORequestGenerator/IORequestGenerator.rc create mode 100644 CristalDiskMark/source/diskspd22/UnitTests/IORequestGenerator/stdafx.h create mode 100644 CristalDiskMark/source/diskspd22/UnitTests/ResultParser/ResultParser.UnitTests.cpp create mode 100644 CristalDiskMark/source/diskspd22/UnitTests/ResultParser/ResultParser.UnitTests.h create mode 100644 CristalDiskMark/source/diskspd22/UnitTests/ResultParser/ResultParser.rc create mode 100644 CristalDiskMark/source/diskspd22/UnitTests/ResultParser/stdafx.h create mode 100644 CristalDiskMark/source/diskspd22/UnitTests/XmlProfileParser/XmlProfileParser.UnitTests.cpp create mode 100644 CristalDiskMark/source/diskspd22/UnitTests/XmlProfileParser/XmlProfileParser.UnitTests.h create mode 100644 CristalDiskMark/source/diskspd22/UnitTests/XmlProfileParser/XmlProfileParser.rc create mode 100644 CristalDiskMark/source/diskspd22/UnitTests/XmlProfileParser/stdafx.h create mode 100644 CristalDiskMark/source/diskspd22/UnitTests/XmlResultParser/XmlResultParser.UnitTests.cpp create mode 100644 CristalDiskMark/source/diskspd22/UnitTests/XmlResultParser/XmlResultParser.UnitTests.h create mode 100644 CristalDiskMark/source/diskspd22/UnitTests/XmlResultParser/XmlResultParser.rc create mode 100644 CristalDiskMark/source/diskspd22/UnitTests/XmlResultParser/stdafx.h create mode 100644 CristalDiskMark/source/diskspd22/XmlProfileParser/XmlProfileParser.cpp create mode 100644 CristalDiskMark/source/diskspd22/XmlProfileParser/diskspd.xsd create mode 100644 CristalDiskMark/source/diskspd22/XmlResultParser/XmlResultParser.cpp create mode 100644 CristalDiskMark/source/diskspd22/diskspd.wprp create mode 100644 CristalDiskMark/source/diskspd22/diskspd_vs/CmdLineParser/CmdLineParser.vcxproj create mode 100644 CristalDiskMark/source/diskspd22/diskspd_vs/CmdRequestCreator/CmdRequestCreator.vcxproj create mode 100644 CristalDiskMark/source/diskspd22/diskspd_vs/Common/Common.vcxproj create mode 100644 CristalDiskMark/source/diskspd22/diskspd_vs/IORequestGenerator/IORequestGenerator.vcxproj create mode 100644 CristalDiskMark/source/diskspd22/diskspd_vs/ResultParser/ResultParser.vcxproj create mode 100644 CristalDiskMark/source/diskspd22/diskspd_vs/UnitTests.sln create mode 100644 CristalDiskMark/source/diskspd22/diskspd_vs/UnitTests/CmdLineParser/CmdLineParser.vcxproj create mode 100644 CristalDiskMark/source/diskspd22/diskspd_vs/UnitTests/Common/Common.vcxproj create mode 100644 CristalDiskMark/source/diskspd22/diskspd_vs/UnitTests/IORequestGenerator/IORequestGenerator.vcxproj create mode 100644 CristalDiskMark/source/diskspd22/diskspd_vs/UnitTests/ResultParser/ResultParser.vcxproj create mode 100644 CristalDiskMark/source/diskspd22/diskspd_vs/UnitTests/XmlProfileParser/XmlProfileParser.vcxproj create mode 100644 CristalDiskMark/source/diskspd22/diskspd_vs/UnitTests/XmlResultParser/XmlResultParser.vcxproj create mode 100644 CristalDiskMark/source/diskspd22/diskspd_vs/XmlProfileParser/XmlProfileParser.vcxproj create mode 100644 CristalDiskMark/source/diskspd22/diskspd_vs/XmlResultParser/XmlResultParser.vcxproj create mode 100644 CristalDiskMark/source/diskspd22/diskspd_vs/diskspd.sln create mode 100644 CristalDiskMark/source/diskspd2_0_15a/CmdLineParser/CmdLineParser.cpp create mode 100644 CristalDiskMark/source/diskspd2_0_15a/CmdLineParser/CmdLineParser.h create mode 100644 CristalDiskMark/source/diskspd2_0_15a/CmdRequestCreator/CmdRequestCreator.cpp create mode 100644 CristalDiskMark/source/diskspd2_0_15a/CmdRequestCreator/CmdRequestCreator.h create mode 100644 CristalDiskMark/source/diskspd2_0_15a/CmdRequestCreator/errors.h create mode 100644 CristalDiskMark/source/diskspd2_0_15a/Common/Common.cpp create mode 100644 CristalDiskMark/source/diskspd2_0_15a/Common/Common.h create mode 100644 CristalDiskMark/source/diskspd2_0_15a/Common/Histogram.h create mode 100644 CristalDiskMark/source/diskspd2_0_15a/Common/IoBucketizer.cpp create mode 100644 CristalDiskMark/source/diskspd2_0_15a/Common/IoBucketizer.h create mode 100644 CristalDiskMark/source/diskspd2_0_15a/DiskSpd_Documentation.docx create mode 100644 CristalDiskMark/source/diskspd2_0_15a/DiskSpd_Documentation.pdf create mode 100644 CristalDiskMark/source/diskspd2_0_15a/IORequestGenerator/IORequestGenerator.cpp create mode 100644 CristalDiskMark/source/diskspd2_0_15a/IORequestGenerator/IORequestGenerator.h create mode 100644 CristalDiskMark/source/diskspd2_0_15a/IORequestGenerator/OverlappedQueue.cpp create mode 100644 CristalDiskMark/source/diskspd2_0_15a/IORequestGenerator/OverlappedQueue.h create mode 100644 CristalDiskMark/source/diskspd2_0_15a/IORequestGenerator/ThroughputMeter.cpp create mode 100644 CristalDiskMark/source/diskspd2_0_15a/IORequestGenerator/ThroughputMeter.h create mode 100644 CristalDiskMark/source/diskspd2_0_15a/IORequestGenerator/etw.cpp create mode 100644 CristalDiskMark/source/diskspd2_0_15a/IORequestGenerator/etw.h create mode 100644 CristalDiskMark/source/diskspd2_0_15a/LICENSE create mode 100644 CristalDiskMark/source/diskspd2_0_15a/LICENSE.txt create mode 100644 CristalDiskMark/source/diskspd2_0_15a/README.md create mode 100644 CristalDiskMark/source/diskspd2_0_15a/ResultParser/ResultParser.cpp create mode 100644 CristalDiskMark/source/diskspd2_0_15a/ResultParser/ResultParser.h create mode 100644 CristalDiskMark/source/diskspd2_0_15a/XmlProfileParser/XmlProfileParser.cpp create mode 100644 CristalDiskMark/source/diskspd2_0_15a/XmlProfileParser/XmlProfileParser.h create mode 100644 CristalDiskMark/source/diskspd2_0_15a/XmlProfileParser/diskspd.h create mode 100644 CristalDiskMark/source/diskspd2_0_15a/XmlProfileParser/diskspd.xsd create mode 100644 CristalDiskMark/source/diskspd2_0_15a/XmlResultParser/exe/DiskSpd32.exe create mode 100644 CristalDiskMark/source/diskspd2_0_15a/XmlResultParser/exe/DiskSpd64.exe create mode 100644 CristalDiskMark/source/diskspd2_0_15a/XmlResultParser/exe/DiskSpdA32.exe create mode 100644 CristalDiskMark/source/diskspd2_0_15a/XmlResultParser/exe/DiskSpdA64.exe create mode 100644 CristalDiskMark/source/diskspd2_0_15a/XmlResultParser/xmlresultparser.cpp create mode 100644 CristalDiskMark/source/diskspd2_0_15a/XmlResultParser/xmlresultparser.h create mode 100644 CristalDiskMark/source/diskspd2_0_15a/diskspd_vs2015/CmdLineParser/CmdLineParser.vcxproj create mode 100644 CristalDiskMark/source/diskspd2_0_15a/diskspd_vs2015/CmdLineParser/CmdLineParser.vcxproj.user create mode 100644 CristalDiskMark/source/diskspd2_0_15a/diskspd_vs2015/CmdRequestCreator/CmdRequestCreator.vcxproj create mode 100644 CristalDiskMark/source/diskspd2_0_15a/diskspd_vs2015/CmdRequestCreator/CmdRequestCreator.vcxproj.user create mode 100644 CristalDiskMark/source/diskspd2_0_15a/diskspd_vs2015/Common/Common.vcxproj create mode 100644 CristalDiskMark/source/diskspd2_0_15a/diskspd_vs2015/IORequestGenerator/IORequestGenerator.vcxproj create mode 100644 CristalDiskMark/source/diskspd2_0_15a/diskspd_vs2015/ResultParser/ResultParser.vcxproj create mode 100644 CristalDiskMark/source/diskspd2_0_15a/diskspd_vs2015/XmlProfileParser/XmlProfileParser.vcxproj create mode 100644 CristalDiskMark/source/diskspd2_0_15a/diskspd_vs2015/XmlProfileParser/diskspd.h create mode 100644 CristalDiskMark/source/diskspd2_0_15a/diskspd_vs2015/XmlResultParser/XmlResultParser.vcxproj create mode 100644 CristalDiskMark/source/diskspd2_0_15a/diskspd_vs2015/diskspd_vs2013.v12.suo create mode 100644 CristalDiskMark/source/diskspd2_0_15a/diskspd_vs2015/diskspd_vs2015.sln create mode 100644 CristalDiskMark/source/diskspd2_0_15a/exe/DiskSpd32L.exe create mode 100644 CristalDiskMark/source/diskspd2_0_15a/exe/DiskSpd64L.exe diff --git a/CristalDiskMark/source/CrystalDiskMark/AboutDlg.cpp b/CristalDiskMark/source/CrystalDiskMark/AboutDlg.cpp new file mode 100644 index 0000000..deaf8d3 --- /dev/null +++ b/CristalDiskMark/source/CrystalDiskMark/AboutDlg.cpp @@ -0,0 +1,279 @@ +/*---------------------------------------------------------------------------*/ +// Author : hiyohiyo +// Mail : hiyohiyo@crystalmark.info +// Web : https://crystalmark.info/ +// License : MIT License +/*---------------------------------------------------------------------------*/ + +#include "stdafx.h" +#include "DiskMark.h" +#include "DiskMarkDlg.h" +#include "AboutDlg.h" + +IMPLEMENT_DYNCREATE(CAboutDlg, CDialog) + +CAboutDlg::CAboutDlg(CWnd* pParent /*=NULL*/) + : CDialogFx(CAboutDlg::IDD, pParent) +{ + CMainDialogFx* p = (CMainDialogFx*)pParent; + + m_ZoomType = p->GetZoomType(); + m_FontScale = p->GetFontScale(); + m_FontRatio = p->GetFontRatio(); + m_FontFace = p->GetFontFace(); + m_FontRender = p->GetFontRender(); + m_CurrentLangPath = p->GetCurrentLangPath(); + m_DefaultLangPath = p->GetDefaultLangPath(); + m_ThemeDir = p->GetThemeDir(); + m_CurrentTheme = p->GetCurrentTheme(); + m_DefaultTheme = p->GetDefaultTheme(); + m_Ini = p->GetIniPath(); + +#ifdef SUISHO_SHIZUKU_SUPPORT + m_BackgroundName = L"About"; +#else + m_BackgroundName = L""; +#endif +} + +CAboutDlg::~CAboutDlg() +{ +} + +void CAboutDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialogFx::DoDataExchange(pDX); + DDX_Control(pDX, IDC_LOGO, m_CtrlLogo); + + DDX_Control(pDX, IDC_PROJECT_SITE_1, m_CtrlProjectSite1); + DDX_Control(pDX, IDC_PROJECT_SITE_2, m_CtrlProjectSite2); + DDX_Control(pDX, IDC_PROJECT_SITE_3, m_CtrlProjectSite3); + DDX_Control(pDX, IDC_PROJECT_SITE_4, m_CtrlProjectSite4); + DDX_Control(pDX, IDC_PROJECT_SITE_5, m_CtrlProjectSite5); + + DDX_Control(pDX, IDC_VERSION, m_CtrlVersion); + DDX_Control(pDX, IDC_LICENSE, m_CtrlLicense); + DDX_Control(pDX, IDC_RELEASE, m_CtrlRelease); + DDX_Control(pDX, IDC_COPYRIGHT1, m_CtrlCopyright1); + DDX_Control(pDX, IDC_COPYRIGHT2, m_CtrlCopyright2); + DDX_Control(pDX, IDC_COPYRIGHT3, m_CtrlCopyright3); + DDX_Control(pDX, IDC_EDITION, m_CtrlEdition); +} + +BOOL CAboutDlg::OnInitDialog() +{ + CDialogFx::OnInitDialog(); + + SetWindowTitle(i18n(L"WindowTitle", L"ABOUT")); + + m_bShowWindow = TRUE; + m_CtrlVersion.SetWindowTextW(PRODUCT_NAME L" " PRODUCT_VERSION); + m_CtrlEdition.SetWindowTextW(PRODUCT_EDITION); + m_CtrlRelease.SetWindowTextW(L"Release: " PRODUCT_RELEASE); + m_CtrlCopyright1.SetWindowTextW(PRODUCT_COPYRIGHT_1); + m_CtrlCopyright2.SetWindowTextW(PRODUCT_COPYRIGHT_2); + m_CtrlCopyright3.SetWindowTextW(PRODUCT_COPYRIGHT_3); + m_CtrlLicense.SetWindowTextW(PRODUCT_LICENSE); + + UpdateDialogSize(); + + CenterWindow(); + ShowWindow(SW_SHOW); + return TRUE; +} + +BEGIN_MESSAGE_MAP(CAboutDlg, CDialogFx) + ON_BN_CLICKED(IDC_LOGO, &CAboutDlg::OnLogo) + ON_BN_CLICKED(IDC_LICENSE, &CAboutDlg::OnLicense) + ON_BN_CLICKED(IDC_VERSION, &CAboutDlg::OnVersion) +#ifdef SUISHO_SHIZUKU_SUPPORT + ON_BN_CLICKED(IDC_PROJECT_SITE_1, &CAboutDlg::OnProjectSite1) + ON_BN_CLICKED(IDC_PROJECT_SITE_2, &CAboutDlg::OnProjectSite2) + ON_BN_CLICKED(IDC_PROJECT_SITE_3, &CAboutDlg::OnProjectSite3) + ON_BN_CLICKED(IDC_PROJECT_SITE_4, &CAboutDlg::OnProjectSite4) + ON_BN_CLICKED(IDC_PROJECT_SITE_5, &CAboutDlg::OnProjectSite5) +#endif +END_MESSAGE_MAP() + + +void CAboutDlg::UpdateDialogSize() +{ + CDialogFx::UpdateDialogSize(); + m_bHighContrast = FALSE; + + ChangeZoomType(m_ZoomType); + SetClientSize(SIZE_X, SIZE_Y, m_ZoomRatio); + UpdateBackground(TRUE, m_bDarkMode); + +#ifdef SUISHO_AOI_SUPPORT + m_CtrlLogo.InitControl(32, 484, 128, 144, m_ZoomRatio, m_hPal, &m_BkDC, NULL, 0, BS_CENTER, OwnerDrawTransparent, FALSE, FALSE, FALSE); + m_CtrlSecretVoice.InitControl(392, 288, 60, 20, m_ZoomRatio, m_hPal, &m_BkDC, NULL, 0, BS_CENTER, OwnerDrawTransparent, FALSE, FALSE, FALSE); + m_CtrlProjectSite1.InitControl(184, 508, 148, 16, m_ZoomRatio, m_hPal, &m_BkDC, NULL, 0, BS_CENTER, OwnerDrawTransparent, FALSE, FALSE, FALSE); + m_CtrlProjectSite2.InitControl(244, 540, 108, 16, m_ZoomRatio, m_hPal, &m_BkDC, NULL, 0, BS_CENTER, OwnerDrawTransparent, FALSE, FALSE, FALSE); + m_CtrlProjectSite3.InitControl(232, 556, 180, 16, m_ZoomRatio, m_hPal, &m_BkDC, NULL, 0, BS_CENTER, OwnerDrawTransparent, FALSE, FALSE, FALSE); + m_CtrlProjectSite4.InitControl(244, 576, 120, 16, m_ZoomRatio, m_hPal, &m_BkDC, NULL, 0, BS_CENTER, OwnerDrawTransparent, FALSE, FALSE, FALSE); + m_CtrlProjectSite5.InitControl(0, 0, 0, 0, m_ZoomRatio, m_hPal, &m_BkDC, NULL, 0, BS_CENTER, OwnerDrawTransparent, FALSE, FALSE, FALSE); + m_CtrlSecretVoice.SetHandCursor(); + m_CtrlProjectSite1.SetHandCursor(); + m_CtrlProjectSite2.SetHandCursor(); + m_CtrlProjectSite3.SetHandCursor(); + m_CtrlProjectSite4.SetHandCursor(); + m_CtrlProjectSite5.SetHandCursor(); + +#elif MSI_MEI_SUPPORT + m_CtrlProjectSite1.InitControl(24, 460, 348, 128, m_ZoomRatio, m_hPal, &m_BkDC, NULL, 0, BS_CENTER, OwnerDrawTransparent, FALSE, FALSE, FALSE); + m_CtrlProjectSite2.InitControl(168, 604, 36, 24, m_ZoomRatio, m_hPal, &m_BkDC, NULL, 0, BS_CENTER, OwnerDrawTransparent, FALSE, FALSE, FALSE); + m_CtrlProjectSite3.InitControl(332, 604, 104, 24, m_ZoomRatio, m_hPal, &m_BkDC, NULL, 0, BS_CENTER, OwnerDrawTransparent, FALSE, FALSE, FALSE); + m_CtrlProjectSite4.InitControl(20, 20, 120, 40, m_ZoomRatio, m_hPal, &m_BkDC, NULL, 0, BS_CENTER, OwnerDrawTransparent, FALSE, FALSE, FALSE); + m_CtrlProjectSite5.InitControl(464, 604, 168, 24, m_ZoomRatio, m_hPal, &m_BkDC, NULL, 0, BS_CENTER, OwnerDrawTransparent, FALSE, FALSE, FALSE); + m_CtrlLogo.InitControl(80, 64, 128, 128, m_ZoomRatio, m_hPal, &m_BkDC, IP(L"Logo"), 1, BS_CENTER, OwnerDrawImage, FALSE, FALSE, FALSE); + m_CtrlProjectSite1.SetHandCursor(); + m_CtrlProjectSite2.SetHandCursor(); + m_CtrlProjectSite3.SetHandCursor(); + m_CtrlProjectSite4.SetHandCursor(); + m_CtrlProjectSite5.SetHandCursor(); + +#elif SUISHO_SHIZUKU_SUPPORT + m_CtrlProjectSite1.InitControl(64, 372, 140, 16, m_ZoomRatio, m_hPal, &m_BkDC, NULL, 0, BS_CENTER, OwnerDrawTransparent, FALSE, FALSE, FALSE); + m_CtrlProjectSite2.InitControl(64, 416, 148, 16, m_ZoomRatio, m_hPal, &m_BkDC, NULL, 0, BS_CENTER, OwnerDrawTransparent, FALSE, FALSE, FALSE); + m_CtrlProjectSite3.InitControl(64, 432, 184, 16, m_ZoomRatio, m_hPal, &m_BkDC, NULL, 0, BS_CENTER, OwnerDrawTransparent, FALSE, FALSE, FALSE); + m_CtrlProjectSite4.InitControl(40, 460, 208, 16, m_ZoomRatio, m_hPal, &m_BkDC, NULL, 0, BS_CENTER, OwnerDrawTransparent, FALSE, FALSE, FALSE); + m_CtrlProjectSite5.InitControl(92, 504, 432, 124, m_ZoomRatio, m_hPal, &m_BkDC, NULL, 0, BS_CENTER, OwnerDrawTransparent, FALSE, FALSE, FALSE); + m_CtrlLogo.InitControl(80, 12, 128, 128, m_ZoomRatio, m_hPal, &m_BkDC, IP(L"Logo"), 1, BS_CENTER, OwnerDrawImage, FALSE, FALSE, FALSE); + m_CtrlProjectSite1.SetHandCursor(); + m_CtrlProjectSite2.SetHandCursor(); + m_CtrlProjectSite3.SetHandCursor(); + m_CtrlProjectSite4.SetHandCursor(); + m_CtrlProjectSite5.SetHandCursor(); +#else + m_CtrlLogo.InitControl(20, 20, 128, 128, m_ZoomRatio, m_hPal, &m_BkDC, IP(L"Logo"), 1, BS_CENTER, OwnerDrawImage, FALSE, FALSE, FALSE); + m_CtrlProjectSite1.ShowWindow(SW_HIDE); + m_CtrlProjectSite2.ShowWindow(SW_HIDE); + m_CtrlProjectSite3.ShowWindow(SW_HIDE); + m_CtrlProjectSite4.ShowWindow(SW_HIDE); + m_CtrlProjectSite5.ShowWindow(SW_HIDE); +#endif + + m_CtrlLogo.SetHandCursor(); + +#ifdef MSI_MEI_SUPPORT + COLORREF fontColor = RGB(255, 255, 255); +#else + COLORREF fontColor = RGB(0, 0, 0); +#endif + + m_CtrlVersion.SetFontEx(m_FontFace, 20, 20, m_ZoomRatio, m_FontRatio, fontColor, FW_BOLD, m_FontRender); + m_CtrlEdition.SetFontEx(m_FontFace, 20, 20, m_ZoomRatio, m_FontRatio, fontColor, FW_BOLD, m_FontRender); + m_CtrlRelease.SetFontEx(m_FontFace, 16, 16, m_ZoomRatio, m_FontRatio, fontColor, FW_NORMAL, m_FontRender); + m_CtrlCopyright1.SetFontEx(m_FontFace, 16, 16, m_ZoomRatio, m_FontRatio, fontColor, FW_NORMAL, m_FontRender); + m_CtrlCopyright2.SetFontEx(m_FontFace, 16, 16, m_ZoomRatio, m_FontRatio, fontColor, FW_NORMAL, m_FontRender); + m_CtrlCopyright3.SetFontEx(m_FontFace, 16, 16, m_ZoomRatio, m_FontRatio, fontColor, FW_NORMAL, m_FontRender); + m_CtrlLicense.SetFontEx(m_FontFace, 16, 16, m_ZoomRatio, m_FontRatio, fontColor, FW_NORMAL, m_FontRender); + + m_CtrlVersion.SetHandCursor(); + m_CtrlLicense.SetHandCursor(); + +#ifdef SUISHO_AOI_SUPPORT + m_CtrlVersion.InitControl(0, 136, 288, 28, m_ZoomRatio, m_hPal, &m_BkDC, NULL, 0, BS_CENTER, OwnerDrawTransparent, FALSE, FALSE, FALSE); + m_CtrlEdition.InitControl(0, 164, 288, 28, m_ZoomRatio, m_hPal, &m_BkDC, NULL, 0, SS_CENTER, OwnerDrawTransparent, FALSE, FALSE, FALSE); + m_CtrlRelease.InitControl(0, 200, 288, 20, m_ZoomRatio, m_hPal, &m_BkDC, NULL, 0, SS_CENTER, OwnerDrawTransparent, FALSE, FALSE, FALSE); + m_CtrlCopyright1.InitControl(0, 220, 288, 20, m_ZoomRatio, m_hPal, &m_BkDC, NULL, 0, SS_CENTER, OwnerDrawTransparent, FALSE, FALSE, FALSE); + m_CtrlCopyright2.InitControl(0, 240, 288, 20, m_ZoomRatio, m_hPal, &m_BkDC, NULL, 0, SS_CENTER, OwnerDrawTransparent, FALSE, FALSE, FALSE); + m_CtrlCopyright3.InitControl(0, 260, 288, 20, m_ZoomRatio, m_hPal, &m_BkDC, NULL, 0, SS_CENTER, OwnerDrawTransparent, FALSE, FALSE, FALSE); + m_CtrlLicense.InitControl(0, 280, 288, 20, m_ZoomRatio, m_hPal, &m_BkDC, NULL, 0, BS_CENTER, OwnerDrawTransparent, FALSE, FALSE, FALSE); + +#elif MSI_MEI_SUPPORT + m_CtrlVersion.InitControl(0, 204, 288, 28, m_ZoomRatio, m_hPal, &m_BkDC, NULL, 0, BS_CENTER, OwnerDrawTransparent, FALSE, FALSE, FALSE); + m_CtrlEdition.InitControl(0, 232, 288, 28, m_ZoomRatio, m_hPal, &m_BkDC, NULL, 0, SS_CENTER, OwnerDrawTransparent, FALSE, FALSE, FALSE); + m_CtrlRelease.InitControl(0, 268, 288, 20, m_ZoomRatio, m_hPal, &m_BkDC, NULL, 0, SS_CENTER, OwnerDrawTransparent, FALSE, FALSE, FALSE); + m_CtrlCopyright1.InitControl(0, 288, 288, 20, m_ZoomRatio, m_hPal, &m_BkDC, NULL, 0, SS_CENTER, OwnerDrawTransparent, FALSE, FALSE, FALSE); + m_CtrlCopyright2.InitControl(0, 308, 288, 20, m_ZoomRatio, m_hPal, &m_BkDC, NULL, 0, SS_CENTER, OwnerDrawTransparent, FALSE, FALSE, FALSE); + m_CtrlCopyright3.InitControl(0, 328, 288, 20, m_ZoomRatio, m_hPal, &m_BkDC, NULL, 0, SS_CENTER, OwnerDrawTransparent, FALSE, FALSE, FALSE); + m_CtrlLicense.InitControl(0, 0, 0, 0, m_ZoomRatio, m_hPal, &m_BkDC, NULL, 0, BS_CENTER, OwnerDrawTransparent, FALSE, FALSE, FALSE); + +#elif SUISHO_SHIZUKU_SUPPORT + m_CtrlVersion.InitControl(0, 152, 288, 28, m_ZoomRatio, m_hPal, &m_BkDC, NULL, 0, BS_CENTER, OwnerDrawTransparent, FALSE, FALSE, FALSE); + m_CtrlEdition.InitControl(0, 180, 288, 28, m_ZoomRatio, m_hPal, &m_BkDC, NULL, 0, SS_CENTER, OwnerDrawTransparent, FALSE, FALSE, FALSE); + m_CtrlRelease.InitControl(0, 216, 288, 20, m_ZoomRatio, m_hPal, &m_BkDC, NULL, 0, SS_CENTER, OwnerDrawTransparent, FALSE, FALSE, FALSE); + m_CtrlCopyright1.InitControl(0, 236, 288, 20, m_ZoomRatio, m_hPal, &m_BkDC, NULL, 0, SS_CENTER, OwnerDrawTransparent, FALSE, FALSE, FALSE); + m_CtrlCopyright2.InitControl(0, 256, 288, 20, m_ZoomRatio, m_hPal, &m_BkDC, NULL, 0, SS_CENTER, OwnerDrawTransparent, FALSE, FALSE, FALSE); + m_CtrlCopyright3.InitControl(0, 276, 288, 20, m_ZoomRatio, m_hPal, &m_BkDC, NULL, 0, SS_CENTER, OwnerDrawTransparent, FALSE, FALSE, FALSE); + m_CtrlLicense.InitControl(0, 296, 288, 20, m_ZoomRatio, m_hPal, &m_BkDC, NULL, 0, BS_CENTER, OwnerDrawTransparent, FALSE, FALSE, FALSE); + +#else + m_CtrlVersion.InitControl(160, 12, 364, 28, m_ZoomRatio, m_hPal, &m_BkDC, NULL, 0, BS_CENTER, OwnerDrawTransparent, m_bHighContrast, m_bDarkMode, FALSE); + m_CtrlEdition.InitControl(160, 40, 364, 28, m_ZoomRatio, m_hPal, &m_BkDC, NULL, 0, SS_CENTER, OwnerDrawTransparent, m_bHighContrast, m_bDarkMode, FALSE); + m_CtrlRelease.InitControl(160, 76, 364, 20, m_ZoomRatio, m_hPal, &m_BkDC, NULL, 0, SS_CENTER, OwnerDrawTransparent, m_bHighContrast, m_bDarkMode, FALSE); + m_CtrlCopyright1.InitControl(160, 96, 364, 20, m_ZoomRatio, m_hPal, &m_BkDC, NULL, 0, SS_CENTER, OwnerDrawTransparent, m_bHighContrast, m_bDarkMode, FALSE); + m_CtrlCopyright2.InitControl(160, 116, 364, 20, m_ZoomRatio, m_hPal, &m_BkDC, NULL, 0, SS_CENTER, OwnerDrawTransparent, m_bHighContrast, m_bDarkMode, FALSE); + m_CtrlCopyright3.InitControl(160, 136, 364, 20, m_ZoomRatio, m_hPal, &m_BkDC, NULL, 0, SS_CENTER, OwnerDrawTransparent, m_bHighContrast, m_bDarkMode, FALSE); + m_CtrlLicense.InitControl(160, 136, 364, 20, m_ZoomRatio, m_hPal, &m_BkDC, NULL, 0, BS_CENTER, OwnerDrawTransparent, m_bHighContrast, m_bDarkMode, FALSE); + m_CtrlCopyright3.ShowWindow(SW_HIDE); + +#endif + + Invalidate(); +} + +void CAboutDlg::OnLogo() +{ + if (GetUserDefaultLCID() == 0x0411)// Japanese + { + OpenUrl(URL_MAIN_JA); + } + else // Other Language + { + OpenUrl(URL_MAIN_EN); + } +} + +void CAboutDlg::OnVersion() +{ + if (GetUserDefaultLCID() == 0x0411)// Japanese + { + OpenUrl(URL_VERSION_JA); + } + else // Other Language + { + OpenUrl(URL_VERSION_EN); + } + +} +void CAboutDlg::OnLicense() +{ + if (GetUserDefaultLCID() == 0x0411)// Japanese + { + OpenUrl(URL_LICENSE_JA); + } + else // Other Language + { + OpenUrl(URL_LICENSE_EN); + } +} + +#ifdef SUISHO_SHIZUKU_SUPPORT +void CAboutDlg::OnProjectSite1() +{ + OpenUrl(URL_PROJECT_SITE_1); +} + +void CAboutDlg::OnProjectSite2() +{ + OpenUrl(URL_PROJECT_SITE_2); +} + +void CAboutDlg::OnProjectSite3() +{ + OpenUrl(URL_PROJECT_SITE_3); +} + +void CAboutDlg::OnProjectSite4() +{ + OpenUrl(URL_PROJECT_SITE_4); +} + +void CAboutDlg::OnProjectSite5() +{ + OpenUrl(URL_PROJECT_SITE_5); +} +#endif \ No newline at end of file diff --git a/CristalDiskMark/source/CrystalDiskMark/AboutDlg.h b/CristalDiskMark/source/CrystalDiskMark/AboutDlg.h new file mode 100644 index 0000000..93809ee --- /dev/null +++ b/CristalDiskMark/source/CrystalDiskMark/AboutDlg.h @@ -0,0 +1,67 @@ +/*---------------------------------------------------------------------------*/ +// Author : hiyohiyo +// Mail : hiyohiyo@crystalmark.info +// Web : https://crystalmark.info/ +// License : MIT License +/*---------------------------------------------------------------------------*/ + +#pragma once +#include "DialogFx.h" +#include "StaticFx.h" +#include "ButtonFx.h" + +class CAboutDlg : public CDialogFx +{ + DECLARE_DYNCREATE(CAboutDlg) + +#ifdef SUISHO_AOI_SUPPORT + static const int SIZE_X = 640; + static const int SIZE_Y = 640; +#elif MSI_MEI_SUPPORT + static const int SIZE_X = 640; + static const int SIZE_Y = 640; +#elif SUISHO_SHIZUKU_SUPPORT + static const int SIZE_X = 640; + static const int SIZE_Y = 660; +#else + static const int SIZE_X = 540; + static const int SIZE_Y = 168; +#endif + +public: + CAboutDlg(CWnd* pParent = NULL); + virtual ~CAboutDlg(); + + enum { IDD = IDD_ABOUT }; + +protected: + virtual void DoDataExchange(CDataExchange* pDX); + virtual BOOL OnInitDialog(); + virtual void UpdateDialogSize(); + + DECLARE_MESSAGE_MAP() + afx_msg void OnLogo(); + afx_msg void OnVersion(); + afx_msg void OnLicense(); + afx_msg void OnProjectSite1(); + afx_msg void OnProjectSite2(); + afx_msg void OnProjectSite3(); + afx_msg void OnProjectSite4(); + afx_msg void OnProjectSite5(); + + CButtonFx m_CtrlLogo; + CButtonFx m_CtrlSecretVoice; + CButtonFx m_CtrlProjectSite1; + CButtonFx m_CtrlProjectSite2; + CButtonFx m_CtrlProjectSite3; + CButtonFx m_CtrlProjectSite4; + CButtonFx m_CtrlProjectSite5; + CButtonFx m_CtrlVersion; + CButtonFx m_CtrlLicense; + + CStaticFx m_CtrlEdition; + CStaticFx m_CtrlRelease; + CStaticFx m_CtrlCopyright1; + CStaticFx m_CtrlCopyright2; + CStaticFx m_CtrlCopyright3; +}; diff --git a/CristalDiskMark/source/CrystalDiskMark/DeclareDPIAware.manifest b/CristalDiskMark/source/CrystalDiskMark/DeclareDPIAware.manifest new file mode 100644 index 0000000..76a25be --- /dev/null +++ b/CristalDiskMark/source/CrystalDiskMark/DeclareDPIAware.manifest @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + True/PM + PerMonitorV2, PerMonitor + + + diff --git a/CristalDiskMark/source/CrystalDiskMark/DiskBench.cpp b/CristalDiskMark/source/CrystalDiskMark/DiskBench.cpp new file mode 100644 index 0000000..cb0fdac --- /dev/null +++ b/CristalDiskMark/source/CrystalDiskMark/DiskBench.cpp @@ -0,0 +1,935 @@ +/*---------------------------------------------------------------------------*/ +// Author : hiyohiyo +// Mail : hiyohiyo@crystalmark.info +// Web : https://crystalmark.info/ +// License : MIT License +/*---------------------------------------------------------------------------*/ + +#include "stdafx.h" +#include "DiskMark.h" +#include "DiskMarkDlg.h" +#include "DiskBench.h" + +#include +#include +#include +#pragma comment(lib,"winmm.lib") + +#pragma warning(disable : 4996) + +static CString TestFilePath; +static CString TestFileDir; +static CString DiskSpdExe; + +static HANDLE hFile; +static int DiskTestCount; +static UINT64 DiskTestSize; +static int BenchType[9]; +static int BenchSize[9]; +static int BenchQueues[9]; +static int BenchThreads[9]; +// static int Affinity; +static BOOL MixMode; +static int MixRatio; + +static void ShowErrorMessage(CString message); +static void Interval(void* dlg); + +static BOOL Init(void* dlg); +static void DiskSpd(void* dlg, DISK_SPD_CMD cmd); + +static UINT Exit(void* dlg); +static void CALLBACK TimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime); +static volatile BOOL WaitFlag; + +#define DISK_SPD_EXE_32 L"CdmResource\\diskspd\\diskspd32.exe" +#define DISK_SPD_EXE_64 L"CdmResource\\diskspd\\diskspd64.exe" +#define DISK_SPD_EXE_32_LEGACY L"CdmResource\\diskspd\\diskspd32L.exe" +#define DISK_SPD_EXE_64_LEGACY L"CdmResource\\diskspd\\diskspd64L.exe" +#define DISK_SPD_EXE_ARM32 L"CdmResource\\diskspd\\diskspdA32.exe" +#define DISK_SPD_EXE_ARM64 L"CdmResource\\diskspd\\diskspdA64.exe" + +PROCESS_INFORMATION pi; + +int ExecAndWait(TCHAR *pszCmd, BOOL bNoWindow, double *latency) +{ + DWORD Code = 0; + BOOL bSuccess; + STARTUPINFO si; + + memset(&si, 0, sizeof(STARTUPINFO)); + si.cb = sizeof(STARTUPINFO); + + if (bNoWindow) { + si.dwFlags = STARTF_USESHOWWINDOW; + si.wShowWindow = SW_HIDE; + } + + CString name; + name.Format(L"CrystalDiskMark%08X", GetCurrentProcessId()); + auto size = 8; + + HANDLE hSharedMemory = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, NULL, size, name.GetString()); + if (hSharedMemory != NULL) + { + auto pMemory = (double*)MapViewOfFile(hSharedMemory, FILE_MAP_ALL_ACCESS, NULL, NULL, size); + if (pMemory != NULL) + { + bSuccess = CreateProcess(NULL, pszCmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); + if (bSuccess != TRUE) + { + UnmapViewOfFile(pMemory); + CloseHandle(hSharedMemory); + return 0; + } + + WaitForInputIdle(pi.hProcess, INFINITE); + WaitForSingleObject(pi.hProcess, INFINITE); + GetExitCodeProcess(pi.hProcess, &Code); + + CloseHandle(pi.hThread); + CloseHandle(pi.hProcess); + + pi.hProcess = NULL; + + *latency = (double)*pMemory * 1000; // milli sec to micro sec + + UnmapViewOfFile(pMemory); + CloseHandle(hSharedMemory); + } + } + + return Code; +} + + +void ShowErrorMessage(CString message) +{ + DWORD lastErrorCode = GetLastError(); + CString errorMessage; + LPVOID lpMessageBuffer; + FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, lastErrorCode, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMessageBuffer, 0, NULL); + errorMessage.Format(L"0x%08X:%s", lastErrorCode, (LPTSTR) lpMessageBuffer); + + AfxMessageBox(message + L"\r\n" + errorMessage); + LocalFree( lpMessageBuffer ); +} + +void Interval(void* dlg) +{ + int intervalTime = ((CDiskMarkDlg*) dlg)->m_IntervalTime; + CString title; + + for (int i = 0; i < intervalTime; i++) + { + if (!((CDiskMarkDlg*) dlg)->m_DiskBenchStatus) + { + return; + } + title.Format(L"Interval Time %d/%d sec", i, intervalTime); + ::PostMessage(((CDiskMarkDlg*) dlg)->GetSafeHwnd(), WM_UPDATE_MESSAGE, (WPARAM) &title, 0); + Sleep(1000); + } +} + +UINT ExecDiskBenchAll(LPVOID dlg) +{ + int benchmark = ((CDiskMarkDlg*)dlg)->m_Benchmark; + + if(Init(dlg)) + { + if (benchmark & BENCHMARK_READ) + { + DiskSpd(dlg, TEST_READ_0); Interval(dlg); + DiskSpd(dlg, TEST_READ_1); Interval(dlg); + DiskSpd(dlg, TEST_READ_2); Interval(dlg); + DiskSpd(dlg, TEST_READ_3); + } + if ((benchmark & BENCHMARK_READ) && (benchmark & BENCHMARK_WRITE)) + { + Interval(dlg); + } + if (benchmark & BENCHMARK_WRITE) + { + DiskSpd(dlg, TEST_WRITE_0); Interval(dlg); + DiskSpd(dlg, TEST_WRITE_1); Interval(dlg); + DiskSpd(dlg, TEST_WRITE_2); Interval(dlg); + DiskSpd(dlg, TEST_WRITE_3); + } + +#ifdef MIX_MODE + if (MixMode) + { + Interval(dlg); + DiskSpd(dlg, TEST_MIX_0); Interval(dlg); + DiskSpd(dlg, TEST_MIX_1); Interval(dlg); + DiskSpd(dlg, TEST_MIX_2); Interval(dlg); + DiskSpd(dlg, TEST_MIX_3); + } +#endif + } + + return Exit(dlg); +} + +UINT ExecDiskBenchAllPeak(LPVOID dlg) +{ + int benchmark = ((CDiskMarkDlg*)dlg)->m_Benchmark; + + if (Init(dlg)) + { + if (benchmark & BENCHMARK_READ) + { + DiskSpd(dlg, TEST_READ_4); Interval(dlg); + DiskSpd(dlg, TEST_READ_5); + } + if ((benchmark & BENCHMARK_READ) && (benchmark & BENCHMARK_WRITE)) + { + Interval(dlg); + } + if (benchmark & BENCHMARK_WRITE) + { + DiskSpd(dlg, TEST_WRITE_4); Interval(dlg); + DiskSpd(dlg, TEST_WRITE_5); + } + +#ifdef MIX_MODE + if (MixMode) + { + Interval(dlg); + DiskSpd(dlg, TEST_MIX_4); Interval(dlg); + DiskSpd(dlg, TEST_MIX_5); + } +#endif + } + + return Exit(dlg); +} + +UINT ExecDiskBenchAllReal(LPVOID dlg) +{ + int benchmark = ((CDiskMarkDlg*)dlg)->m_Benchmark; + + if (Init(dlg)) + { + if (benchmark & BENCHMARK_READ) + { + DiskSpd(dlg, TEST_READ_6); Interval(dlg); + DiskSpd(dlg, TEST_READ_7); + } + if ((benchmark & BENCHMARK_READ) && (benchmark & BENCHMARK_WRITE)) + { + Interval(dlg); + } + if (benchmark & BENCHMARK_WRITE) + { + DiskSpd(dlg, TEST_WRITE_6); Interval(dlg); + DiskSpd(dlg, TEST_WRITE_7); + } + +#ifdef MIX_MODE + if (MixMode) + { + Interval(dlg); + DiskSpd(dlg, TEST_MIX_6); Interval(dlg); + DiskSpd(dlg, TEST_MIX_7); + } +#endif + } + + return Exit(dlg); +} + +UINT ExecDiskBenchAllDemo(LPVOID dlg) +{ + int benchmark = ((CDiskMarkDlg*)dlg)->m_Benchmark; + + if (Init(dlg)) + { + if (benchmark & BENCHMARK_READ) + { + DiskSpd(dlg, TEST_READ_8); + } + if ((benchmark & BENCHMARK_READ) && (benchmark & BENCHMARK_WRITE)) + { + Interval(dlg); + } + if (benchmark & BENCHMARK_WRITE) + { + DiskSpd(dlg, TEST_WRITE_8); + } + } + + return Exit(dlg); +} + +UINT ExecDiskBench0(LPVOID dlg) +{ + int benchmark = ((CDiskMarkDlg*)dlg)->m_Benchmark; + + if (Init(dlg)) + { + if (benchmark & BENCHMARK_READ) + { + DiskSpd(dlg, TEST_READ_0); + } + if ((benchmark & BENCHMARK_READ) && (benchmark & BENCHMARK_WRITE)) + { + Interval(dlg); + } + if (benchmark & BENCHMARK_WRITE) + { + DiskSpd(dlg, TEST_WRITE_0); + } + +#ifdef MIX_MODE + if (MixMode) + { + Interval(dlg); + DiskSpd(dlg, TEST_MIX_0); + } +#endif + } + return Exit(dlg); +} + +UINT ExecDiskBench1(LPVOID dlg) +{ + int benchmark = ((CDiskMarkDlg*)dlg)->m_Benchmark; + + if (Init(dlg)) + { + if (benchmark & BENCHMARK_READ) + { + DiskSpd(dlg, TEST_READ_1); + } + if ((benchmark & BENCHMARK_READ) && (benchmark & BENCHMARK_WRITE)) + { + Interval(dlg); + } + if (benchmark & BENCHMARK_WRITE) + { + DiskSpd(dlg, TEST_WRITE_1); + } +#ifdef MIX_MODE + if (MixMode) + { + Interval(dlg); + DiskSpd(dlg, TEST_MIX_1); + } +#endif + } + return Exit(dlg); +} + +UINT ExecDiskBench2(LPVOID dlg) +{ + int benchmark = ((CDiskMarkDlg*)dlg)->m_Benchmark; + + if (Init(dlg)) + { + if (benchmark & BENCHMARK_READ) + { + DiskSpd(dlg, TEST_READ_2); + } + if ((benchmark & BENCHMARK_READ) && (benchmark & BENCHMARK_WRITE)) + { + Interval(dlg); + } + if (benchmark & BENCHMARK_WRITE) + { + DiskSpd(dlg, TEST_WRITE_2); + } +#ifdef MIX_MODE + if (MixMode) + { + Interval(dlg); + DiskSpd(dlg, TEST_MIX_2); + } +#endif + } + return Exit(dlg); +} + +UINT ExecDiskBench3(LPVOID dlg) +{ + int benchmark = ((CDiskMarkDlg*)dlg)->m_Benchmark; + + if (Init(dlg)) + { + if (benchmark & BENCHMARK_READ) + { + DiskSpd(dlg, TEST_READ_3); + } + if ((benchmark & BENCHMARK_READ) && (benchmark & BENCHMARK_WRITE)) + { + Interval(dlg); + } + if (benchmark & BENCHMARK_WRITE) + { + DiskSpd(dlg, TEST_WRITE_3); + } +#ifdef MIX_MODE + if (MixMode) + { + Interval(dlg); + DiskSpd(dlg, TEST_MIX_3); + } +#endif + } + return Exit(dlg); +} + +UINT ExecDiskBench4(LPVOID dlg) +{ + int benchmark = ((CDiskMarkDlg*)dlg)->m_Benchmark; + + if (Init(dlg)) + { + if (benchmark & BENCHMARK_READ) + { + DiskSpd(dlg, TEST_READ_4); + } + if ((benchmark & BENCHMARK_READ) && (benchmark & BENCHMARK_WRITE)) + { + Interval(dlg); + } + if (benchmark & BENCHMARK_WRITE) + { + DiskSpd(dlg, TEST_WRITE_4); + } +#ifdef MIX_MODE + if (MixMode) + { + Interval(dlg); + DiskSpd(dlg, TEST_MIX_4); + } +#endif + } + return Exit(dlg); +} + +UINT ExecDiskBench5(LPVOID dlg) +{ + int benchmark = ((CDiskMarkDlg*)dlg)->m_Benchmark; + + if (Init(dlg)) + { + if (benchmark & BENCHMARK_READ) + { + DiskSpd(dlg, TEST_READ_5); + } + if ((benchmark & BENCHMARK_READ) && (benchmark & BENCHMARK_WRITE)) + { + Interval(dlg); + } + if (benchmark & BENCHMARK_WRITE) + { + DiskSpd(dlg, TEST_WRITE_5); + } +#ifdef MIX_MODE + if (MixMode) + { + Interval(dlg); + DiskSpd(dlg, TEST_MIX_5); + } +#endif + } + return Exit(dlg); +} + +UINT ExecDiskBench6(LPVOID dlg) +{ + int benchmark = ((CDiskMarkDlg*)dlg)->m_Benchmark; + + if (Init(dlg)) + { + if (benchmark & BENCHMARK_READ) + { + DiskSpd(dlg, TEST_READ_6); + } + if ((benchmark & BENCHMARK_READ) && (benchmark & BENCHMARK_WRITE)) + { + Interval(dlg); + } + if (benchmark & BENCHMARK_WRITE) + { + DiskSpd(dlg, TEST_WRITE_6); + } +#ifdef MIX_MODE + if (MixMode) + { + Interval(dlg); + DiskSpd(dlg, TEST_MIX_6); + } +#endif + } + return Exit(dlg); +} + +UINT ExecDiskBench7(LPVOID dlg) +{ + int benchmark = ((CDiskMarkDlg*)dlg)->m_Benchmark; + + if (Init(dlg)) + { + if (benchmark & BENCHMARK_READ) + { + DiskSpd(dlg, TEST_READ_7); + } + if ((benchmark & BENCHMARK_READ) && (benchmark & BENCHMARK_WRITE)) + { + Interval(dlg); + } + if (benchmark & BENCHMARK_WRITE) + { + DiskSpd(dlg, TEST_WRITE_7); + } +#ifdef MIX_MODE + if (MixMode) + { + Interval(dlg); + DiskSpd(dlg, TEST_MIX_7); + } +#endif + } + return Exit(dlg); +} + +BOOL Init(void* dlg) +{ + BOOL FlagArc; + BOOL result; + static CString cstr; + TCHAR drive; + + ULARGE_INTEGER freeBytesAvailableToCaller; + ULARGE_INTEGER totalNumberOfBytes; + ULARGE_INTEGER totalNumberOfFreeBytes; + + // Init m_Ini + TCHAR *ptrEnd; + TCHAR temp[MAX_PATH]; + ::GetModuleFileName(NULL, temp, MAX_PATH); + if ((ptrEnd = _tcsrchr(temp, '\\')) != NULL) + { + *ptrEnd = '\0'; + } + + pi.hProcess = NULL; + +#ifdef _M_ARM + DiskSpdExe.Format(L"%s\\%s", temp, DISK_SPD_EXE_ARM32); +#elif _M_ARM64 + DiskSpdExe.Format(L"%s\\%s", temp, DISK_SPD_EXE_ARM64); +#elif _M_X64 + if(IsWin8orLater()) + { + DiskSpdExe.Format(L"%s\\%s", temp, DISK_SPD_EXE_64); + } + else + { + DiskSpdExe.Format(L"%s\\%s", temp, DISK_SPD_EXE_64_LEGACY); + } +#else + if (IsWin8orLater()) + { + DiskSpdExe.Format(L"%s\\%s", temp, DISK_SPD_EXE_32); + } + else + { + DiskSpdExe.Format(L"%s\\%s", temp, DISK_SPD_EXE_32_LEGACY); + } +#endif + + if (! IsFileExist(DiskSpdExe)) + { + AfxMessageBox(((CDiskMarkDlg*) dlg)->m_MesDiskSpdNotFound); + ((CDiskMarkDlg*) dlg)->m_DiskBenchStatus = FALSE; + return FALSE; + } + DiskTestCount = ((CDiskMarkDlg*) dlg)->m_IndexTestCount + 1; + + CString testSize = ((CDiskMarkDlg*)dlg)->m_ValueTestSize; + if (testSize.Find(L"M") == -1) // GiB + { + DiskTestSize = (UINT64)_tstoi(testSize) * 1024; + } + else // MiB + { + DiskTestSize = (UINT64)_tstoi(testSize); + } + + for (int i = 0; i < 9; i++) + { + BenchType[i] = ((CDiskMarkDlg*)dlg)->m_BenchType[i]; + BenchSize[i] = ((CDiskMarkDlg*)dlg)->m_BenchSize[i]; + BenchQueues[i] = ((CDiskMarkDlg*)dlg)->m_BenchQueues[i]; + BenchThreads[i] = ((CDiskMarkDlg*)dlg)->m_BenchThreads[i]; + } + + MixMode = ((CDiskMarkDlg*)dlg)->m_MixMode; + MixRatio = ((CDiskMarkDlg*)dlg)->m_MixRatio; + + CString RootPath; + if(((CDiskMarkDlg*)dlg)->m_MaxIndexTestDrive != ((CDiskMarkDlg*)dlg)->m_IndexTestDrive) + { + + drive = ((CDiskMarkDlg*)dlg)->m_ValueTestDrive.GetAt(0); + cstr.Format(L"%C:\\", drive); + GetDiskFreeSpaceEx(cstr, &freeBytesAvailableToCaller, &totalNumberOfBytes, &totalNumberOfFreeBytes); + if (totalNumberOfBytes.QuadPart < ((ULONGLONG)8 * 1024 * 1024 * 1024)) // < 8 GB + { + ((CDiskMarkDlg*)dlg)->m_TestDriveInfo.Format(L"%C: %.1f%% (%.1f/%.1f MiB)", drive, + (double)(totalNumberOfBytes.QuadPart - totalNumberOfFreeBytes.QuadPart) / (double)totalNumberOfBytes.QuadPart * 100, + (totalNumberOfBytes.QuadPart - totalNumberOfFreeBytes.QuadPart) / 1024 / 1024.0, + totalNumberOfBytes.QuadPart / 1024 / 1024.0); + } + else + { + ((CDiskMarkDlg*)dlg)->m_TestDriveInfo.Format(L"%C: %.1f%% (%.1f/%.1f GiB)", drive, + (double)(totalNumberOfBytes.QuadPart - totalNumberOfFreeBytes.QuadPart) / (double)totalNumberOfBytes.QuadPart * 100, + (totalNumberOfBytes.QuadPart - totalNumberOfFreeBytes.QuadPart) / 1024 / 1024 / 1024.0, + totalNumberOfBytes.QuadPart / 1024 / 1024 / 1024.0); + } + RootPath.Format(L"%c:\\", drive); + } + else + { + RootPath = ((CDiskMarkDlg*)dlg)->m_TestTargetPath; + RootPath += L"\\"; + } + + TestFileDir.Format(L"%sCrystalDiskMark%08X", (LPTSTR)RootPath.GetString(), timeGetTime()); + CreateDirectory(TestFileDir, NULL); + TestFilePath.Format(L"%s\\CrystalDiskMark%08X.tmp", (LPTSTR)TestFileDir.GetString(), timeGetTime()); + + DWORD FileSystemFlags; + GetVolumeInformation(RootPath, NULL, NULL, NULL, NULL, &FileSystemFlags, NULL, NULL); + if(FileSystemFlags & FS_VOL_IS_COMPRESSED) + { + FlagArc = TRUE; + } + else + { + FlagArc = FALSE; + } + +// Check Disk Capacity // + OSVERSIONINFO osVersionInfo; + osVersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + GetVersionEx(&osVersionInfo); + + ULARGE_INTEGER FreeBytesAvailableToCaller, TotalNumberOfBytes, TotalNumberOfFreeBytes; + GetDiskFreeSpaceEx(RootPath, &FreeBytesAvailableToCaller, &TotalNumberOfBytes, &TotalNumberOfFreeBytes); + if(DiskTestSize > TotalNumberOfFreeBytes.QuadPart / 1024 / 1024 ) + { + AfxMessageBox(((CDiskMarkDlg*)dlg)->m_MesDiskCapacityError); + ((CDiskMarkDlg*)dlg)->m_DiskBenchStatus = FALSE; + return FALSE; + } + + CString title; + title.Format(L"Preparing... Create Test File"); + ::PostMessage(((CDiskMarkDlg*)dlg)->GetSafeHwnd(), WM_UPDATE_MESSAGE, (WPARAM)& title, 0); + +// Preapare Test File + hFile = ::CreateFile(TestFilePath, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL|FILE_FLAG_NO_BUFFERING|FILE_FLAG_SEQUENTIAL_SCAN, NULL); + + if(hFile == INVALID_HANDLE_VALUE) + { + AfxMessageBox(((CDiskMarkDlg*)dlg)->m_MesDiskCreateFileError); + ((CDiskMarkDlg*)dlg)->m_DiskBenchStatus = FALSE; + return FALSE; + } + +// Set End Of File to prevent fragmentation of test file + LARGE_INTEGER nFileSize; + nFileSize.QuadPart = 1024 * 1024 * DiskTestSize; + + LARGE_INTEGER nStart; + nStart.QuadPart = 0; + + SetFilePointerEx(hFile, nFileSize, NULL, FILE_BEGIN); + SetEndOfFile(hFile); + SetFilePointerEx(hFile, nStart, NULL, FILE_BEGIN); + +// COMPRESSION_FORMAT_NONE + USHORT lpInBuffer = COMPRESSION_FORMAT_NONE; + DWORD lpBytesReturned = 0; + DeviceIoControl(hFile, FSCTL_SET_COMPRESSION, (LPVOID) &lpInBuffer, + sizeof(USHORT), NULL, 0, (LPDWORD)&lpBytesReturned, NULL); + +// Fill Test Data + char* buf = NULL; + int BufSize; + int Loop; + int i; + DWORD writesize; + BufSize = 1024 * 1024; + Loop = (int)DiskTestSize; + + buf = (char*) VirtualAlloc(NULL, BufSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); + if (buf == NULL) + { + AfxMessageBox(L"Failed VirtualAlloc()."); + ((CDiskMarkDlg*) dlg)->m_DiskBenchStatus = FALSE; + return FALSE; + } + + if (((CDiskMarkDlg*) dlg)->m_TestData == TEST_DATA_ALL0X00) + { + for (i = 0; i < BufSize; i++) + { + buf[i] = 0; + } + } + else + { + // Compatible with DiskSpd + for (i = 0; i < BufSize; i++) + { + buf[i] = (char) (rand() % 256); + } + } + + for (i = 0; i < Loop; i++) + { + if (((CDiskMarkDlg*) dlg)->m_DiskBenchStatus) + { + result = WriteFile(hFile, buf, BufSize, &writesize, NULL); + } + else + { + CloseHandle(hFile); + VirtualFree(buf, 0, MEM_RELEASE); + ((CDiskMarkDlg*) dlg)->m_DiskBenchStatus = FALSE; + return FALSE; + } + } + VirtualFree(buf, 0, MEM_RELEASE); + CloseHandle(hFile); + + return TRUE; +} + +void CALLBACK TimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime) +{ + if(idEvent == TIMER_ID) + { + WaitFlag = FALSE; + KillTimer(hwnd, idEvent); + } +} + +UINT Exit(void* dlg) +{ + DeleteFile(TestFilePath); + RemoveDirectory(TestFileDir); + + static CString cstr; + cstr = L""; + + if(((CDiskMarkDlg*)dlg)->m_TestData == TEST_DATA_ALL0X00) + { + cstr = ALL_0X00_0FILL; + } + + ::PostMessage(((CDiskMarkDlg*)dlg)->GetSafeHwnd(), WM_UPDATE_MESSAGE, NULL, (LPARAM)&cstr); + ::PostMessage(((CDiskMarkDlg*)dlg)->GetSafeHwnd(), WM_EXIT_BENCHMARK, 0, 0); + + ((CDiskMarkDlg*)dlg)->m_DiskBenchStatus = FALSE; + ((CDiskMarkDlg*)dlg)->m_WinThread = NULL; + + return 0; +} + +void DiskSpd(void* dlg, DISK_SPD_CMD cmd) +{ + static CString cstr; + double *maxScore = NULL; + double *minLatency = NULL; + CString command; + CString title; + CString option; + CString bufOption; + + int duration = 5; + int index = 0; + int j = 0; + + if (!((CDiskMarkDlg*) dlg)->m_DiskBenchStatus) + { + return; + } + + if (((CDiskMarkDlg*) dlg)->m_TestData == TEST_DATA_ALL0X00) + { + bufOption += L" -Z"; + } + else + { + switch (cmd) + { + case TEST_WRITE_0: + case TEST_WRITE_1: + case TEST_WRITE_2: + case TEST_WRITE_3: + case TEST_WRITE_4: + case TEST_WRITE_5: + case TEST_WRITE_6: + case TEST_WRITE_7: + case TEST_WRITE_8: + index = cmd - TEST_WRITE_0; + cstr.Format(L" -Z%dK", BenchSize[index]); + bufOption += cstr; + break; + case TEST_MIX_0: + case TEST_MIX_1: + case TEST_MIX_2: + case TEST_MIX_3: + case TEST_MIX_4: + case TEST_MIX_5: + case TEST_MIX_6: + case TEST_MIX_7: + case TEST_MIX_8: + index = cmd - TEST_MIX_0; + cstr.Format(L" -Z%dK", BenchSize[index]); + bufOption += cstr; + break; + } + } + + switch (cmd) + { + case TEST_READ_0: + case TEST_READ_1: + case TEST_READ_2: + case TEST_READ_3: + case TEST_READ_4: + case TEST_READ_5: + case TEST_READ_6: + case TEST_READ_7: + case TEST_READ_8: + index = cmd - TEST_READ_0; + if (BenchType[index]) + { + title.Format(L"Random Read"); + option.Format(L"-b%dK -o%d -t%d -W0 -S -w0 -r", BenchSize[index], BenchQueues[index], BenchThreads[index]); + } + else + { + title.Format(L"Sequential Read"); + option.Format(L"-b%dK -o%d -t%d -W0 -S -w0", BenchSize[index], BenchQueues[index], BenchThreads[index]); + } + maxScore = &(((CDiskMarkDlg*) dlg)->m_ReadScore[index]); + minLatency = &(((CDiskMarkDlg*)dlg)->m_ReadLatency[index]); + break; + case TEST_WRITE_0: + case TEST_WRITE_1: + case TEST_WRITE_2: + case TEST_WRITE_3: + case TEST_WRITE_4: + case TEST_WRITE_5: + case TEST_WRITE_6: + case TEST_WRITE_7: + case TEST_WRITE_8: + index = cmd - TEST_WRITE_0; + if (BenchType[index]) + { + title.Format(L"Random Write"); + option.Format(L"-b%dK -o%d -t%d -W0 -S -w100 -r", BenchSize[index], BenchQueues[index], BenchThreads[index]); + } + else + { + title.Format(L"Sequential Write"); + option.Format(L"-b%dK -o%d -t%d -W0 -S -w100", BenchSize[index], BenchQueues[index], BenchThreads[index]); + } + option += bufOption; + maxScore = &(((CDiskMarkDlg*)dlg)->m_WriteScore[index]); + minLatency = &(((CDiskMarkDlg*)dlg)->m_WriteLatency[index]); + break; +#ifdef MIX_MODE + case TEST_MIX_0: + case TEST_MIX_1: + case TEST_MIX_2: + case TEST_MIX_3: + case TEST_MIX_4: + case TEST_MIX_5: + case TEST_MIX_6: + case TEST_MIX_7: + case TEST_MIX_8: + index = cmd - TEST_MIX_0; + if (BenchType[index]) + { + title.Format(L"Random Mix"); + option.Format(L"-b%dK -o%d -t%d -W0 -S -w%d -r", BenchSize[index], BenchQueues[index], BenchThreads[index], MixRatio); + } + else + { + title.Format(L"Sequential Mix"); + option.Format(L"-b%dK -o%d -t%d -W0 -S -w%d", BenchSize[index], BenchQueues[index], BenchThreads[index], MixRatio); + } + option += bufOption; + maxScore = &(((CDiskMarkDlg*)dlg)->m_MixScore[index]); + minLatency = &(((CDiskMarkDlg*)dlg)->m_MixLatency[index]); + break; +#endif + } + + option += L" -ag"; + if(IsWin8orLater() && BenchType[index] == 0 && BenchThreads[index] > 1) // Sequential + { + option += L" -si"; + } + + double score = 0.0; + double latency = 0.0; + + if (maxScore == NULL || minLatency == NULL) + { + return ; + } + *maxScore = 0.0; + *minLatency = -1.0; + + for (j = 0; j <= DiskTestCount; j++) + { + if (j == 0) + { + duration = ((CDiskMarkDlg*)dlg)->m_MeasureTime; + cstr.Format(L"Preparing... %s", title.GetString()); + } + else + { + duration = ((CDiskMarkDlg*)dlg)->m_MeasureTime; + cstr.Format(L"%s (%d/%d)", title.GetString(), j, DiskTestCount); + } + ::PostMessage(((CDiskMarkDlg*) dlg)->GetSafeHwnd(), WM_UPDATE_MESSAGE, (WPARAM) &cstr, 0); + + + command.Format(L"\"%s\" %s -d%d -A%d -L \"%s\"", (LPTSTR)DiskSpdExe.GetString(), (LPTSTR)option.GetString(), duration, GetCurrentProcessId(), (LPTSTR)TestFilePath.GetString()); + + score = ExecAndWait((TCHAR*) (command.GetString()), TRUE, &latency) / 10 / 1000.0; + + if (j > 0 && score > *maxScore) + { + *maxScore = score; + ::PostMessage(((CDiskMarkDlg*) dlg)->GetSafeHwnd(), WM_UPDATE_SCORE, 0, 0); + } + + if (j > 0 && score > 0.0 && (latency < *minLatency || *minLatency < 0)) + { + *minLatency = latency; + ::PostMessage(((CDiskMarkDlg*)dlg)->GetSafeHwnd(), WM_UPDATE_SCORE, 0, 0); + } + + if (!((CDiskMarkDlg*) dlg)->m_DiskBenchStatus) + { + return; + } + } + ::PostMessage(((CDiskMarkDlg*) dlg)->GetSafeHwnd(), WM_UPDATE_SCORE, 0, 0); +} diff --git a/CristalDiskMark/source/CrystalDiskMark/DiskBench.h b/CristalDiskMark/source/CrystalDiskMark/DiskBench.h new file mode 100644 index 0000000..583bbd0 --- /dev/null +++ b/CristalDiskMark/source/CrystalDiskMark/DiskBench.h @@ -0,0 +1,88 @@ +/*---------------------------------------------------------------------------*/ +// Author : hiyohiyo +// Mail : hiyohiyo@crystalmark.info +// Web : https://crystalmark.info/ +// License : MIT License +/*---------------------------------------------------------------------------*/ + +#pragma once + +#define TIMER_ID 5963 + +// Common Message +#define ALL_0X00_0FILL L"<0Fill>" + +// Benchmark +#define BENCHMARK_READ 1 +#define BENCHMARK_WRITE 2 +#define BENCHMARK_READ_WRITE 3 + +enum TEST_DATA_TYPE +{ + TEST_DATA_RANDOM = 0, + TEST_DATA_ALL0X00, + TEST_DATA_ALL0XFF, +}; + +enum AFFINITY_MODE +{ + AFFINITY_DISABLED = 0, + AFFINITY_ENABLED, +}; + +enum PROFILE +{ + PROFILE_DEFAULT = 0, + PROFILE_PEAK, + PROFILE_REAL, + PROFILE_DEMO, + PROFILE_DEFAULT_MIX, + PROFILE_PEAK_MIX, + PROFILE_REAL_MIX, +}; + +enum DISK_SPD_CMD +{ + TEST_CREATE_FILE = 0, + TEST_DELETE_FILE, + TEST_READ_0, + TEST_READ_1, + TEST_READ_2, + TEST_READ_3, + TEST_READ_4, + TEST_READ_5, + TEST_READ_6, + TEST_READ_7, + TEST_READ_8, + TEST_WRITE_0, + TEST_WRITE_1, + TEST_WRITE_2, + TEST_WRITE_3, + TEST_WRITE_4, + TEST_WRITE_5, + TEST_WRITE_6, + TEST_WRITE_7, + TEST_WRITE_8, + TEST_MIX_0, + TEST_MIX_1, + TEST_MIX_2, + TEST_MIX_3, + TEST_MIX_4, + TEST_MIX_5, + TEST_MIX_6, + TEST_MIX_7, + TEST_MIX_8, +}; + +UINT ExecDiskBenchAll(LPVOID dlg); +UINT ExecDiskBenchAllPeak(LPVOID dlg); +UINT ExecDiskBenchAllReal(LPVOID dlg); +UINT ExecDiskBenchAllDemo(LPVOID dlg); +UINT ExecDiskBench0(LPVOID dlg); +UINT ExecDiskBench1(LPVOID dlg); +UINT ExecDiskBench2(LPVOID dlg); +UINT ExecDiskBench3(LPVOID dlg); +UINT ExecDiskBench4(LPVOID dlg); +UINT ExecDiskBench5(LPVOID dlg); +UINT ExecDiskBench6(LPVOID dlg); +UINT ExecDiskBench7(LPVOID dlg); diff --git a/CristalDiskMark/source/CrystalDiskMark/DiskMark.cpp b/CristalDiskMark/source/CrystalDiskMark/DiskMark.cpp new file mode 100644 index 0000000..bc48171 --- /dev/null +++ b/CristalDiskMark/source/CrystalDiskMark/DiskMark.cpp @@ -0,0 +1,117 @@ +/*---------------------------------------------------------------------------*/ +// Author : hiyohiyo +// Mail : hiyohiyo@crystalmark.info +// Web : https://crystalmark.info/ +// License : MIT License +/*---------------------------------------------------------------------------*/ + +#include "stdafx.h" +#include "DiskMark.h" +#include "DiskMarkDlg.h" + +#include +#pragma comment(lib, "winmm.lib") + +#include + +#ifdef _DEBUG +#define new DEBUG_NEW +#endif + +BEGIN_MESSAGE_MAP(CDiskMarkApp, CWinApp) + ON_COMMAND(ID_HELP, &CWinApp::OnHelp) +END_MESSAGE_MAP() + +CDiskMarkApp::CDiskMarkApp() +{ +} + +CDiskMarkApp theApp; + +//----------------------------------------------------------------------------- +// Prototypes +//----------------------------------------------------------------------------- +static BOOL IsFileExistEx(const TCHAR* path, const TCHAR* fileName); +static BOOL RunAsRestart(); + +BOOL CDiskMarkApp::InitInstance() +{ + // Remove current directory from DLL search order to prevent DLL hijacking + typedef BOOL(WINAPI* PFN_SetDllDirectory)(LPCTSTR); + PFN_SetDllDirectory pfnSetDllDirectory = (PFN_SetDllDirectory)GetProcAddress( + GetModuleHandle(_T("kernel32")), "SetDllDirectoryW"); + if (pfnSetDllDirectory) { pfnSetDllDirectory(_T("")); } + + INITCOMMONCONTROLSEX InitCtrls; + InitCtrls.dwSize = sizeof(InitCtrls); + InitCtrls.dwICC = ICC_WIN95_CLASSES; + InitCommonControlsEx(&InitCtrls); + + CWinApp::InitInstance(); + +#ifndef UWP + if (! IsUserAnAdmin()) + { + if (RunAsRestart()) + { + return FALSE; + } + } +#endif + + // Multimedia Timer Setting + TIMECAPS tc; + timeGetDevCaps(&tc,sizeof(TIMECAPS)); + timeBeginPeriod(tc.wPeriodMin); + + BOOL flagReExec = FALSE; + + CDiskMarkDlg dlg; + m_pMainWnd = &dlg; + + if (dlg.DoModal() == RE_EXEC) + { + flagReExec = TRUE; + } + + timeEndPeriod(tc.wPeriodMin); + + if(flagReExec) + { + TCHAR str[MAX_PATH]; + ::GetModuleFileName(NULL, str, MAX_PATH); + ShellExecute(NULL, NULL, str, NULL, NULL, SW_SHOWNORMAL); + } + + return FALSE; +} + +BOOL IsFileExistEx(const TCHAR* path, const TCHAR* fileName) +{ + if(! IsFileExist(path)) + { + CString cstr; + cstr.Format(L"Not Found \"%s\".", fileName); + AfxMessageBox(cstr); + return FALSE; + } + return TRUE; +} + +BOOL RunAsRestart() +{ + int count; + + TCHAR** cmd = ::CommandLineToArgvW(::GetCommandLine(), &count); + + if (count < 2 || _tcscmp(cmd[1], L"runas") != 0) + { + TCHAR path[MAX_PATH]; + ::GetModuleFileName(NULL, path, MAX_PATH); + if (::ShellExecute(NULL, L"runas", path, L"runas", NULL, SW_SHOWNORMAL) > (HINSTANCE)32) + { + return TRUE; + } + } + return FALSE; +} \ No newline at end of file diff --git a/CristalDiskMark/source/CrystalDiskMark/DiskMark.h b/CristalDiskMark/source/CrystalDiskMark/DiskMark.h new file mode 100644 index 0000000..15a70b8 --- /dev/null +++ b/CristalDiskMark/source/CrystalDiskMark/DiskMark.h @@ -0,0 +1,24 @@ +/*---------------------------------------------------------------------------*/ +// Author : hiyohiyo +// Mail : hiyohiyo@crystalmark.info +// Web : https://crystalmark.info/ +// License : MIT License +/*---------------------------------------------------------------------------*/ + +#pragma once + +#include "resource.h" + +class CDiskMarkApp : public CWinApp +{ +public: + CDiskMarkApp(); + +public: + virtual BOOL InitInstance(); + + + DECLARE_MESSAGE_MAP() +}; + +extern CDiskMarkApp theApp; \ No newline at end of file diff --git a/CristalDiskMark/source/CrystalDiskMark/DiskMark.rc b/CristalDiskMark/source/CrystalDiskMark/DiskMark.rc new file mode 100644 index 0000000..bc527d4 --- /dev/null +++ b/CristalDiskMark/source/CrystalDiskMark/DiskMark.rc @@ -0,0 +1,477 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// { ({) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_JPN) +LANGUAGE LANG_JAPANESE, SUBLANG_DEFAULT +#pragma code_page(932) + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "#define _AFX_NO_SPLITTER_RESOURCES\r\n" + "#define _AFX_NO_OLE_RESOURCES\r\n" + "#define _AFX_NO_TRACKER_RESOURCES\r\n" + "#define _AFX_NO_PROPERTY_RESOURCES\r\n" + "\r\n" + "#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_JPN)\r\n" + "LANGUAGE 17, 1\r\n" + "#pragma code_page(932)\r\n" + "#include ""res\\DiskMark.rc2"" // non-Microsoft Visual C++ edited resources\r\n" + "#include ""afxres.rc"" // Standard components\r\n" + "#endif\r\n" + "\0" +END + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_DISKMARK_DIALOG DIALOGEX 0, 0, 267, 344 +STYLE DS_SETFONT | DS_MODALFRAME | WS_MINIMIZEBOX | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +EXSTYLE WS_EX_APPWINDOW +CAPTION "CrystalDiskMark" +MENU IDR_MENU +FONT 8, "MS Shell Dlg", 400, 0, 0x0 +BEGIN + PUSHBUTTON "", IDC_HIDE, 0, 0, 0, 0 | WS_TABSTOP + PUSHBUTTON "All",IDC_BUTTON_ALL,7,32,62,37, BS_CENTER | BS_MULTILINE | BS_NOTIFY | WS_TABSTOP + COMBOBOX IDC_COMBO_COUNT,56,14,39,200, CBS_DROPDOWNLIST | CBS_OWNERDRAWVARIABLE | CBS_HASSTRINGS | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_COMBO_SIZE,103,14,45,200, CBS_DROPDOWNLIST | CBS_OWNERDRAWVARIABLE | CBS_HASSTRINGS | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_COMBO_DRIVE,160,14,99,200, CBS_DROPDOWNLIST | CBS_OWNERDRAWVARIABLE | CBS_HASSTRINGS | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_COMBO_UNIT, 0, 14, 39, 200, CBS_DROPDOWNLIST | CBS_OWNERDRAWVARIABLE | CBS_HASSTRINGS | WS_VSCROLL | WS_TABSTOP +#ifdef _MIX_MODE + COMBOBOX IDC_COMBO_MIX, 56, 14, 39, 200, CBS_DROPDOWNLIST | CBS_OWNERDRAWVARIABLE | CBS_HASSTRINGS | WS_VSCROLL | WS_TABSTOP +#endif + PUSHBUTTON "TEST0",IDC_BUTTON_TEST_0,7,70,62,37, BS_CENTER | BS_MULTILINE | BS_NOTIFY + PUSHBUTTON "TEST1",IDC_BUTTON_TEST_1,7,109,62,37, BS_CENTER | BS_MULTILINE | BS_NOTIFY + PUSHBUTTON "TEST2",IDC_BUTTON_TEST_2,7,149,62,37, BS_CENTER | BS_MULTILINE | BS_NOTIFY + PUSHBUTTON "TEST3",IDC_BUTTON_TEST_3,7,189,62,37, BS_CENTER | BS_MULTILINE | BS_NOTIFY + LTEXT "",IDC_TEST_READ_0,72,69,77,37, + LTEXT "",IDC_TEST_READ_1,71,108,77,37 + LTEXT "",IDC_TEST_READ_2,70,149,77,37 + LTEXT "",IDC_TEST_READ_3,71,189,77,37 + LTEXT "",IDC_TEST_WRITE_0,160,69,77,37 + LTEXT "",IDC_TEST_WRITE_1,160,109,77,37 + LTEXT "",IDC_TEST_WRITE_2,156,149,77,37 + LTEXT "",IDC_TEST_WRITE_3,156,190,77,37 + CONTROL "", IDC_COMMENT, "EDIT", WS_CHILD | ES_MULTILINE | ES_WANTRETURN | WS_TABSTOP, 7, 269, 252, 21, + LTEXT "Read [MB/s]",IDC_READ_UNIT,76,58,29,8 + LTEXT "Write [MB/s]",IDC_WRITE_UNIT,160,60,29,8 + LTEXT "Demo", IDC_DEMO_SETTING, 76, 58, 29, 8 + +#ifdef _MIX_MODE + LTEXT "", IDC_TEST_MIX_0, 160, 69, 77, 37, SS_NOTIFY + LTEXT "", IDC_TEST_MIX_1, 160, 109, 77, 37, SS_NOTIFY + LTEXT "", IDC_TEST_MIX_2, 156, 149, 77, 37, SS_NOTIFY + LTEXT "", IDC_TEST_MIX_3, 156, 190, 77, 37, SS_NOTIFY + LTEXT "Mix [MB/s]",IDC_MIX_UNIT,160,60,29,8 +#endif +END + +IDD_ABOUT DIALOGEX 0, 0, 477, 362 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "CrystalDiskMark" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + PUSHBUTTON "",IDC_LOGO,26,17,156,107 + PUSHBUTTON "",IDC_VERSION,240,18,193,8 + LTEXT "",IDC_EDITION,241,38,33,8 + LTEXT "",IDC_RELEASE,239,62,33,8 + LTEXT "",IDC_COPYRIGHT1,241,84,33,8 + LTEXT "",IDC_COPYRIGHT2, 241, 84, 33, 8 + LTEXT "",IDC_COPYRIGHT3, 241, 84, 33, 8 + PUSHBUTTON "",IDC_LICENSE,239,110,33,8 + PUSHBUTTON "",IDC_PROJECT_SITE_1,77,144,228,21 + PUSHBUTTON "",IDC_PROJECT_SITE_2,77,194,232,22 + PUSHBUTTON "",IDC_PROJECT_SITE_3,196,229,270,31 + PUSHBUTTON "",IDC_PROJECT_SITE_4,196,267,270,31 + PUSHBUTTON "",IDC_PROJECT_SITE_5,196,267,270,31 +END + +IDD_SETTINGS DIALOGEX 0, 0, 154, 76 +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Queues&Threads" +FONT 8, "MS Shell Dlg", 400, 0, 0x0 +BEGIN + LTEXT "Default", IDC_LABEL_DEFAULT, 72, 69, 77, 37 + LTEXT "Peak", IDC_LABEL_PEAK, 72, 69, 77, 37 + LTEXT "Demo", IDC_LABEL_DEMO, 72, 69, 77, 37 + LTEXT "Measure Time", IDC_LABEL_MEASURE_TIME, 72, 69, 77, 37 + LTEXT "Interval Time", IDC_LABEL_INTERVAL_TIME, 72, 69, 77, 37 + LTEXT "Type",IDC_LABEL_TYPE, 72, 69, 77, 37 + LTEXT "Size",IDC_LABEL_SIZE,72,69,77,37 + LTEXT "Queues",IDC_LABEL_QUEUES,71,108,77,37 + LTEXT "Threads",IDC_LABEL_THREADS,71,108,77,37 + + COMBOBOX IDC_COMBO_BENCH_TYPE_0, 1, 1, 1, 1, CBS_DROPDOWNLIST | CBS_OWNERDRAWVARIABLE | CBS_HASSTRINGS | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_COMBO_BENCH_SIZE_0, 1, 1, 1, 1, CBS_DROPDOWNLIST | CBS_OWNERDRAWVARIABLE | CBS_HASSTRINGS | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_COMBO_BENCH_QUEUE_0, 1, 1, 1, 1, CBS_DROPDOWNLIST | CBS_OWNERDRAWVARIABLE | CBS_HASSTRINGS | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_COMBO_BENCH_THREAD_0, 1, 1, 1, 1, CBS_DROPDOWNLIST | CBS_OWNERDRAWVARIABLE | CBS_HASSTRINGS | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_COMBO_BENCH_TYPE_1, 1, 1, 1, 1, CBS_DROPDOWNLIST | CBS_OWNERDRAWVARIABLE | CBS_HASSTRINGS | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_COMBO_BENCH_SIZE_1, 1, 1, 1, 1, CBS_DROPDOWNLIST | CBS_OWNERDRAWVARIABLE | CBS_HASSTRINGS | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_COMBO_BENCH_QUEUE_1, 1, 1, 1, 1, CBS_DROPDOWNLIST | CBS_OWNERDRAWVARIABLE | CBS_HASSTRINGS | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_COMBO_BENCH_THREAD_1, 1, 1, 1, 1, CBS_DROPDOWNLIST | CBS_OWNERDRAWVARIABLE | CBS_HASSTRINGS | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_COMBO_BENCH_TYPE_2, 1, 1, 1, 1, CBS_DROPDOWNLIST | CBS_OWNERDRAWVARIABLE | CBS_HASSTRINGS | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_COMBO_BENCH_SIZE_2, 1, 1, 1, 1, CBS_DROPDOWNLIST | CBS_OWNERDRAWVARIABLE | CBS_HASSTRINGS | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_COMBO_BENCH_QUEUE_2, 1, 1, 1, 1, CBS_DROPDOWNLIST | CBS_OWNERDRAWVARIABLE | CBS_HASSTRINGS | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_COMBO_BENCH_THREAD_2, 1, 1, 1, 1, CBS_DROPDOWNLIST | CBS_OWNERDRAWVARIABLE | CBS_HASSTRINGS | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_COMBO_BENCH_TYPE_3, 1, 1, 1, 1, CBS_DROPDOWNLIST | CBS_OWNERDRAWVARIABLE | CBS_HASSTRINGS | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_COMBO_BENCH_SIZE_3, 1, 1, 1, 1, CBS_DROPDOWNLIST | CBS_OWNERDRAWVARIABLE | CBS_HASSTRINGS | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_COMBO_BENCH_QUEUE_3, 1, 1, 1, 1, CBS_DROPDOWNLIST | CBS_OWNERDRAWVARIABLE | CBS_HASSTRINGS | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_COMBO_BENCH_THREAD_3, 1, 1, 1, 1, CBS_DROPDOWNLIST | CBS_OWNERDRAWVARIABLE | CBS_HASSTRINGS | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_COMBO_BENCH_TYPE_4, 1, 1, 1, 1, CBS_DROPDOWNLIST | CBS_OWNERDRAWVARIABLE | CBS_HASSTRINGS | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_COMBO_BENCH_SIZE_4, 1, 1, 1, 1, CBS_DROPDOWNLIST | CBS_OWNERDRAWVARIABLE | CBS_HASSTRINGS | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_COMBO_BENCH_QUEUE_4, 1, 1, 1, 1, CBS_DROPDOWNLIST | CBS_OWNERDRAWVARIABLE | CBS_HASSTRINGS | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_COMBO_BENCH_THREAD_4, 1, 1, 1, 1, CBS_DROPDOWNLIST | CBS_OWNERDRAWVARIABLE | CBS_HASSTRINGS | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_COMBO_BENCH_TYPE_5, 1, 1, 1, 1, CBS_DROPDOWNLIST | CBS_OWNERDRAWVARIABLE | CBS_HASSTRINGS | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_COMBO_BENCH_SIZE_5, 1, 1, 1, 1, CBS_DROPDOWNLIST | CBS_OWNERDRAWVARIABLE | CBS_HASSTRINGS | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_COMBO_BENCH_QUEUE_5, 1, 1, 1, 1, CBS_DROPDOWNLIST | CBS_OWNERDRAWVARIABLE | CBS_HASSTRINGS | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_COMBO_BENCH_THREAD_5, 1, 1, 1, 1, CBS_DROPDOWNLIST | CBS_OWNERDRAWVARIABLE | CBS_HASSTRINGS | WS_VSCROLL | WS_TABSTOP + + COMBOBOX IDC_COMBO_BENCH_TYPE_8, 1, 1, 1, 1, CBS_DROPDOWNLIST | CBS_OWNERDRAWVARIABLE | CBS_HASSTRINGS | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_COMBO_BENCH_SIZE_8, 1, 1, 1, 1, CBS_DROPDOWNLIST | CBS_OWNERDRAWVARIABLE | CBS_HASSTRINGS | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_COMBO_BENCH_QUEUE_8, 1, 1, 1, 1, CBS_DROPDOWNLIST | CBS_OWNERDRAWVARIABLE | CBS_HASSTRINGS | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_COMBO_BENCH_THREAD_8, 1, 1, 1, 1, CBS_DROPDOWNLIST | CBS_OWNERDRAWVARIABLE | CBS_HASSTRINGS | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_COMBO_MEASURE_TIME, 56, 14, 39, 30, CBS_DROPDOWNLIST | CBS_OWNERDRAWVARIABLE | CBS_HASSTRINGS | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_COMBO_INTERVAL_TIME, 56, 14, 39, 30, CBS_DROPDOWNLIST | CBS_OWNERDRAWVARIABLE | CBS_HASSTRINGS | WS_VSCROLL | WS_TABSTOP + + PUSHBUTTON "Default", IDC_SET_DEFAULT, 26, 17, 156, 107, BS_CENTER | BS_MULTILINE + PUSHBUTTON "NVMe SSD", IDC_SET_NVME_8, 26, 17, 156, 107, BS_CENTER | BS_MULTILINE + PUSHBUTTON "Flash Memory", IDC_SET_FLASH_MEMORY, 26, 17, 156, 107, BS_CENTER | BS_MULTILINE + PUSHBUTTON "OK", IDC_OK, 48, 68, 83, 14, BS_CENTER +END + +IDD_FONT DIALOGEX 0, 0, 180, 89 +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Font Setting" +FONT 12, "MS Shell Dlg", 400, 0, 0x80 +BEGIN + LTEXT "Font Face", IDC_FONT_FACE, 1, 1, 1, 1 + LTEXT "Font Scale", IDC_FONT_SCALE, 1, 1, 1, 1 + LTEXT "Render Method", IDC_FONT_RENDER, 1, 1, 1, 1 + + COMBOBOX IDC_FONT_FACE_COMBO,7,6,166,20,CBS_DROPDOWNLIST | CBS_OWNERDRAWVARIABLE | CBS_HASSTRINGS | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_FONT_SCALE_COMBO, 7, 28, 166, 148, CBS_DROPDOWNLIST | CBS_OWNERDRAWVARIABLE | CBS_HASSTRINGS | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_FONT_RENDER_COMBO, 7, 28, 166, 148, CBS_DROPDOWNLIST | CBS_OWNERDRAWVARIABLE | CBS_HASSTRINGS | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Default", IDC_SET_DEFAULT, 26, 17, 156, 107, BS_CENTER + PUSHBUTTON "OK",IDC_OK,48,68,83,14,BS_CENTER +END + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 9,0,3,0 + PRODUCTVERSION 9,0,3,0 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x1L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "041103a4" + BEGIN + VALUE "FileVersion", "9.0.3.0" + VALUE "ProductVersion", "9.0.3.0" + VALUE "OriginalFilename", "DiskMark.exe" + VALUE "InternalName", "DiskMark.exe" + VALUE "Comments", "https://crystalmark.info/" + VALUE "CompanyName", "Crystal Dew World" + +#ifdef SUISHO_AOI_SUPPORT + VALUE "FileDescription", "CrystalDiskMark Aoi Edition" + VALUE "ProductName", "CrystalDiskMark Aoi Edition" + VALUE "LegalCopyright", "(C) 2007-2026 hiyohiyo, (C) 2023-2026 nijihashi sola" +#elif MSI_MEI_SUPPORT + VALUE "FileDescription", "CrystalDiskMark MSI Mei Mihoshi Edition" + VALUE "ProductName", "CrystalDiskMark MSI Mei Mihoshi Edition" + VALUE "LegalCopyright", "(C) 2007-2026 hiyohiyo, (C) 2024-2026 Micro-Star INT'L CO., LTD." +#elif SUISHO_SHIZUKU_SUPPORT + VALUE "FileDescription", "CrystalDiskMark Shizuku Edition" + VALUE "ProductName", "CrystalDiskMark Shizuku Edition" + VALUE "LegalCopyright", "(C) 2007-2026 hiyohiyo, (C) 2012-2026 kirino kasumu" +#else + VALUE "FileDescription", "CrystalDiskMark" + VALUE "ProductName", "CrystalDiskMark" + VALUE "LegalCopyright", "(C) 2007-2026 hiyohiyo6" +#endif + + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x411, 932 + END +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_DISKMARK_DIALOG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 259 + TOPMARGIN, 7 + BOTTOMMARGIN, 338 + END + + IDD_ABOUT, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 161 + TOPMARGIN, 7 + BOTTOMMARGIN, 95 + END + + IDD_SETTINGS, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 147 + TOPMARGIN, 7 + BOTTOMMARGIN, 69 + END + + IDD_FONT, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 173 + TOPMARGIN, 6 + BOTTOMMARGIN, 82 + END +END +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Menu +// + +IDR_MENU MENU +BEGIN + POPUP "&File" + BEGIN + MENUITEM "Copy", ID_COPY + MENUITEM "Save (text)", ID_SAVE_TEXT + MENUITEM "Save (image)", ID_SAVE_IMAGE + MENUITEM "Exit", ID_EXIT + END + POPUP "&Settings" + BEGIN + POPUP "Test Mode" + BEGIN + MENUITEM "Default (Random)", ID_MODE_DEFAULT + MENUITEM "All 0x00 (0 Fill)", ID_MODE_ALL0X00 + END + MENUITEM SEPARATOR + MENUITEM "Default", ID_SETTING_DEFAULT + MENUITEM "NVMe SSD", ID_SETTING_NVME_8 + MENUITEM "Flash Memory", ID_SETTING_FLASH_MEMORY + MENUITEM SEPARATOR + MENUITEM "&Settings", ID_SETTINGS_QUEUESTHREADS + END + POPUP "&Profile" + BEGIN + MENUITEM "Default", ID_PROFILE_DEFAULT + MENUITEM "Peak Performance", ID_PROFILE_PEAK + MENUITEM "Real World Performance", ID_PROFILE_REAL + MENUITEM "Demonstration", ID_PROFILE_DEMO + +#ifdef _MIX_MODE + MENUITEM "Default w/MIX", ID_PROFILE_DEFAULT_MIX + MENUITEM "Peak Performance w/ MIX", ID_PROFILE_PEAK_MIX + MENUITEM "Real World Performance w/ MIX", ID_PROFILE_REAL_MIX +#endif + MENUITEM SEPARATOR + +#ifdef SUISHO_SHIZUKU_SUPPORT + MENUITEM "Read&&Wr&ite", ID_BENCHMARK_READ_WRITE + MENUITEM "Re&ad", ID_BENCHMARK_READ_ONLY + MENUITEM "&Write", ID_BENCHMARK_WRITE_ONLY +#else + MENUITEM "Read&&Wr&ite [+Mix]", ID_BENCHMARK_READ_WRITE + MENUITEM "Re&ad [+Mix]", ID_BENCHMARK_READ_ONLY + MENUITEM "&Write [+Mix]", ID_BENCHMARK_WRITE_ONLY +#endif + + END + POPUP "&Theme" + BEGIN + POPUP "Zoom" + BEGIN + MENUITEM "100%", ID_ZOOM_100 + MENUITEM "125%", ID_ZOOM_125 + MENUITEM "150%", ID_ZOOM_150 + MENUITEM "200%", ID_ZOOM_200 + MENUITEM "250%", ID_ZOOM_250 + MENUITEM "300%", ID_ZOOM_300 + MENUITEM "Auto", ID_ZOOM_AUTO + END + MENUITEM "Font Setting", ID_FONT_SETTING + MENUITEM SEPARATOR + END + POPUP "&Help" + BEGIN + MENUITEM "Help", ID_HELP + MENUITEM "Crystal Dew World [Web]", ID_CRYSTALDEWWORLD + MENUITEM SEPARATOR + MENUITEM "About CrystalDiskMark", ID_ABOUT + END + POPUP "&Language" + BEGIN + POPUP "A-N" + BEGIN + MENUITEM "DUMMY", ID_A_DUMMY + END + POPUP "O-Z" + BEGIN + MENUITEM "DUMMY", ID_O_DUMMY + END + END +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +#ifdef SUISHO_AOI_SUPPORT +IDR_MAINFRAME ICON "res\\DiskMarkA.ico" +IDI_TRAY_ICON ICON "res\\DiskMarkA16.ico" +#elif MSI_MEI_SUPPORT +IDR_MAINFRAME ICON "res\\DiskMarkM.ico" +IDI_TRAY_ICON ICON "res\\DiskMarkM16.ico" +#elif SUISHO_SHIZUKU_SUPPORT +IDR_MAINFRAME ICON "res\\DiskMarkS.ico" +IDI_TRAY_ICON ICON "res\\DiskMarkS16.ico" +#else +IDR_MAINFRAME ICON "res\\DiskMark.ico" +IDI_TRAY_ICON ICON "res\\DiskMark16.ico" +#endif + +///////////////////////////////////////////////////////////////////////////// +// +// Accelerator +// + +IDR_ACCELERATOR ACCELERATORS +BEGIN + "C", ID_COPY, VIRTKEY, CONTROL, SHIFT, NOINVERT + "T", ID_SAVE_TEXT, VIRTKEY, CONTROL, NOINVERT + "S", ID_SAVE_IMAGE, VIRTKEY, CONTROL, NOINVERT + VK_F4, ID_EXIT, VIRTKEY, ALT, NOINVERT + VK_F1, ID_HELP, VIRTKEY, NOINVERT + "Q", ID_SETTINGS_QUEUESTHREADS, VIRTKEY, CONTROL, NOINVERT + "F", ID_FONT_SETTING, VIRTKEY, CONTROL, NOINVERT + VK_ESCAPE, IDOK, VIRTKEY, NOINVERT + VK_F5, IDOK, VIRTKEY, NOINVERT +END + + +///////////////////////////////////////////////////////////////////////////// +// +// AFX_DIALOG_LAYOUT +// + +IDD_DISKMARK_DIALOG AFX_DIALOG_LAYOUT +BEGIN + 0 +END + +IDD_SETTINGS AFX_DIALOG_LAYOUT +BEGIN + 0 +END + +#endif // { ({) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// +#define _AFX_NO_SPLITTER_RESOURCES +#define _AFX_NO_OLE_RESOURCES +#define _AFX_NO_TRACKER_RESOURCES +#define _AFX_NO_PROPERTY_RESOURCES + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_JPN) +LANGUAGE 17, 1 +#pragma code_page(932) +#include "res\DiskMark.rc2" // non-Microsoft Visual C++ edited resources +#include "afxres.rc" // Standard components +#endif + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/CristalDiskMark/source/CrystalDiskMark/DiskMark.sln b/CristalDiskMark/source/CrystalDiskMark/DiskMark.sln new file mode 100644 index 0000000..f4bb214 --- /dev/null +++ b/CristalDiskMark/source/CrystalDiskMark/DiskMark.sln @@ -0,0 +1,114 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.5.33502.453 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DiskMark", "DiskMark.vcxproj", "{CDF33C67-147E-4C50-BC76-99A6BCB214D9}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|ARM = Debug|ARM + Debug|ARM64 = Debug|ARM64 + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release(UWP)|ARM = Release(UWP)|ARM + Release(UWP)|ARM64 = Release(UWP)|ARM64 + Release(UWP)|Win32 = Release(UWP)|Win32 + Release(UWP)|x64 = Release(UWP)|x64 + Release|ARM = Release|ARM + Release|ARM64 = Release|ARM64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + ReleaseAoi(UWP)|ARM = ReleaseAoi(UWP)|ARM + ReleaseAoi(UWP)|ARM64 = ReleaseAoi(UWP)|ARM64 + ReleaseAoi(UWP)|Win32 = ReleaseAoi(UWP)|Win32 + ReleaseAoi(UWP)|x64 = ReleaseAoi(UWP)|x64 + ReleaseAoi|ARM = ReleaseAoi|ARM + ReleaseAoi|ARM64 = ReleaseAoi|ARM64 + ReleaseAoi|Win32 = ReleaseAoi|Win32 + ReleaseAoi|x64 = ReleaseAoi|x64 + ReleaseMSIMei|ARM = ReleaseMSIMei|ARM + ReleaseMSIMei|ARM64 = ReleaseMSIMei|ARM64 + ReleaseMSIMei|Win32 = ReleaseMSIMei|Win32 + ReleaseMSIMei|x64 = ReleaseMSIMei|x64 + ReleaseShizuku(UWP)|ARM = ReleaseShizuku(UWP)|ARM + ReleaseShizuku(UWP)|ARM64 = ReleaseShizuku(UWP)|ARM64 + ReleaseShizuku(UWP)|Win32 = ReleaseShizuku(UWP)|Win32 + ReleaseShizuku(UWP)|x64 = ReleaseShizuku(UWP)|x64 + ReleaseShizuku|ARM = ReleaseShizuku|ARM + ReleaseShizuku|ARM64 = ReleaseShizuku|ARM64 + ReleaseShizuku|Win32 = ReleaseShizuku|Win32 + ReleaseShizuku|x64 = ReleaseShizuku|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {CDF33C67-147E-4C50-BC76-99A6BCB214D9}.Debug|ARM.ActiveCfg = Debug|ARM + {CDF33C67-147E-4C50-BC76-99A6BCB214D9}.Debug|ARM.Build.0 = Debug|ARM + {CDF33C67-147E-4C50-BC76-99A6BCB214D9}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {CDF33C67-147E-4C50-BC76-99A6BCB214D9}.Debug|ARM64.Build.0 = Debug|ARM64 + {CDF33C67-147E-4C50-BC76-99A6BCB214D9}.Debug|Win32.ActiveCfg = Debug|Win32 + {CDF33C67-147E-4C50-BC76-99A6BCB214D9}.Debug|Win32.Build.0 = Debug|Win32 + {CDF33C67-147E-4C50-BC76-99A6BCB214D9}.Debug|x64.ActiveCfg = Debug|x64 + {CDF33C67-147E-4C50-BC76-99A6BCB214D9}.Debug|x64.Build.0 = Debug|x64 + {CDF33C67-147E-4C50-BC76-99A6BCB214D9}.Release(UWP)|ARM.ActiveCfg = Release(UWP)|ARM + {CDF33C67-147E-4C50-BC76-99A6BCB214D9}.Release(UWP)|ARM.Build.0 = Release(UWP)|ARM + {CDF33C67-147E-4C50-BC76-99A6BCB214D9}.Release(UWP)|ARM64.ActiveCfg = Release(UWP)|ARM64 + {CDF33C67-147E-4C50-BC76-99A6BCB214D9}.Release(UWP)|ARM64.Build.0 = Release(UWP)|ARM64 + {CDF33C67-147E-4C50-BC76-99A6BCB214D9}.Release(UWP)|Win32.ActiveCfg = Release(UWP)|Win32 + {CDF33C67-147E-4C50-BC76-99A6BCB214D9}.Release(UWP)|Win32.Build.0 = Release(UWP)|Win32 + {CDF33C67-147E-4C50-BC76-99A6BCB214D9}.Release(UWP)|x64.ActiveCfg = Release(UWP)|x64 + {CDF33C67-147E-4C50-BC76-99A6BCB214D9}.Release(UWP)|x64.Build.0 = Release(UWP)|x64 + {CDF33C67-147E-4C50-BC76-99A6BCB214D9}.Release|ARM.ActiveCfg = Release|ARM + {CDF33C67-147E-4C50-BC76-99A6BCB214D9}.Release|ARM.Build.0 = Release|ARM + {CDF33C67-147E-4C50-BC76-99A6BCB214D9}.Release|ARM64.ActiveCfg = Release|ARM64 + {CDF33C67-147E-4C50-BC76-99A6BCB214D9}.Release|ARM64.Build.0 = Release|ARM64 + {CDF33C67-147E-4C50-BC76-99A6BCB214D9}.Release|Win32.ActiveCfg = Release|Win32 + {CDF33C67-147E-4C50-BC76-99A6BCB214D9}.Release|Win32.Build.0 = Release|Win32 + {CDF33C67-147E-4C50-BC76-99A6BCB214D9}.Release|x64.ActiveCfg = Release|x64 + {CDF33C67-147E-4C50-BC76-99A6BCB214D9}.Release|x64.Build.0 = Release|x64 + {CDF33C67-147E-4C50-BC76-99A6BCB214D9}.ReleaseAoi(UWP)|ARM.ActiveCfg = ReleaseAoi(UWP)|ARM + {CDF33C67-147E-4C50-BC76-99A6BCB214D9}.ReleaseAoi(UWP)|ARM.Build.0 = ReleaseAoi(UWP)|ARM + {CDF33C67-147E-4C50-BC76-99A6BCB214D9}.ReleaseAoi(UWP)|ARM64.ActiveCfg = ReleaseAoi(UWP)|ARM64 + {CDF33C67-147E-4C50-BC76-99A6BCB214D9}.ReleaseAoi(UWP)|ARM64.Build.0 = ReleaseAoi(UWP)|ARM64 + {CDF33C67-147E-4C50-BC76-99A6BCB214D9}.ReleaseAoi(UWP)|Win32.ActiveCfg = ReleaseAoi(UWP)|Win32 + {CDF33C67-147E-4C50-BC76-99A6BCB214D9}.ReleaseAoi(UWP)|Win32.Build.0 = ReleaseAoi(UWP)|Win32 + {CDF33C67-147E-4C50-BC76-99A6BCB214D9}.ReleaseAoi(UWP)|x64.ActiveCfg = ReleaseAoi(UWP)|x64 + {CDF33C67-147E-4C50-BC76-99A6BCB214D9}.ReleaseAoi(UWP)|x64.Build.0 = ReleaseAoi(UWP)|x64 + {CDF33C67-147E-4C50-BC76-99A6BCB214D9}.ReleaseAoi|ARM.ActiveCfg = ReleaseAoi|ARM + {CDF33C67-147E-4C50-BC76-99A6BCB214D9}.ReleaseAoi|ARM.Build.0 = ReleaseAoi|ARM + {CDF33C67-147E-4C50-BC76-99A6BCB214D9}.ReleaseAoi|ARM64.ActiveCfg = ReleaseAoi|ARM64 + {CDF33C67-147E-4C50-BC76-99A6BCB214D9}.ReleaseAoi|ARM64.Build.0 = ReleaseAoi|ARM64 + {CDF33C67-147E-4C50-BC76-99A6BCB214D9}.ReleaseAoi|Win32.ActiveCfg = ReleaseAoi|Win32 + {CDF33C67-147E-4C50-BC76-99A6BCB214D9}.ReleaseAoi|Win32.Build.0 = ReleaseAoi|Win32 + {CDF33C67-147E-4C50-BC76-99A6BCB214D9}.ReleaseAoi|x64.ActiveCfg = ReleaseAoi|x64 + {CDF33C67-147E-4C50-BC76-99A6BCB214D9}.ReleaseAoi|x64.Build.0 = ReleaseAoi|x64 + {CDF33C67-147E-4C50-BC76-99A6BCB214D9}.ReleaseMSIMei|ARM.ActiveCfg = ReleaseMSIMei|ARM + {CDF33C67-147E-4C50-BC76-99A6BCB214D9}.ReleaseMSIMei|ARM.Build.0 = ReleaseMSIMei|ARM + {CDF33C67-147E-4C50-BC76-99A6BCB214D9}.ReleaseMSIMei|ARM64.ActiveCfg = ReleaseMSIMei|ARM64 + {CDF33C67-147E-4C50-BC76-99A6BCB214D9}.ReleaseMSIMei|ARM64.Build.0 = ReleaseMSIMei|ARM64 + {CDF33C67-147E-4C50-BC76-99A6BCB214D9}.ReleaseMSIMei|Win32.ActiveCfg = ReleaseMSIMei|Win32 + {CDF33C67-147E-4C50-BC76-99A6BCB214D9}.ReleaseMSIMei|Win32.Build.0 = ReleaseMSIMei|Win32 + {CDF33C67-147E-4C50-BC76-99A6BCB214D9}.ReleaseMSIMei|x64.ActiveCfg = ReleaseMSIMei|x64 + {CDF33C67-147E-4C50-BC76-99A6BCB214D9}.ReleaseMSIMei|x64.Build.0 = ReleaseMSIMei|x64 + {CDF33C67-147E-4C50-BC76-99A6BCB214D9}.ReleaseShizuku(UWP)|ARM.ActiveCfg = ReleaseShizuku(UWP)|ARM + {CDF33C67-147E-4C50-BC76-99A6BCB214D9}.ReleaseShizuku(UWP)|ARM.Build.0 = ReleaseShizuku(UWP)|ARM + {CDF33C67-147E-4C50-BC76-99A6BCB214D9}.ReleaseShizuku(UWP)|ARM64.ActiveCfg = ReleaseShizuku(UWP)|ARM64 + {CDF33C67-147E-4C50-BC76-99A6BCB214D9}.ReleaseShizuku(UWP)|ARM64.Build.0 = ReleaseShizuku(UWP)|ARM64 + {CDF33C67-147E-4C50-BC76-99A6BCB214D9}.ReleaseShizuku(UWP)|Win32.ActiveCfg = ReleaseShizuku(UWP)|Win32 + {CDF33C67-147E-4C50-BC76-99A6BCB214D9}.ReleaseShizuku(UWP)|Win32.Build.0 = ReleaseShizuku(UWP)|Win32 + {CDF33C67-147E-4C50-BC76-99A6BCB214D9}.ReleaseShizuku(UWP)|x64.ActiveCfg = ReleaseShizuku(UWP)|x64 + {CDF33C67-147E-4C50-BC76-99A6BCB214D9}.ReleaseShizuku(UWP)|x64.Build.0 = ReleaseShizuku(UWP)|x64 + {CDF33C67-147E-4C50-BC76-99A6BCB214D9}.ReleaseShizuku|ARM.ActiveCfg = ReleaseShizuku|ARM + {CDF33C67-147E-4C50-BC76-99A6BCB214D9}.ReleaseShizuku|ARM.Build.0 = ReleaseShizuku|ARM + {CDF33C67-147E-4C50-BC76-99A6BCB214D9}.ReleaseShizuku|ARM64.ActiveCfg = ReleaseShizuku|ARM64 + {CDF33C67-147E-4C50-BC76-99A6BCB214D9}.ReleaseShizuku|ARM64.Build.0 = ReleaseShizuku|ARM64 + {CDF33C67-147E-4C50-BC76-99A6BCB214D9}.ReleaseShizuku|Win32.ActiveCfg = ReleaseShizuku|Win32 + {CDF33C67-147E-4C50-BC76-99A6BCB214D9}.ReleaseShizuku|Win32.Build.0 = ReleaseShizuku|Win32 + {CDF33C67-147E-4C50-BC76-99A6BCB214D9}.ReleaseShizuku|x64.ActiveCfg = ReleaseShizuku|x64 + {CDF33C67-147E-4C50-BC76-99A6BCB214D9}.ReleaseShizuku|x64.Build.0 = ReleaseShizuku|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {81DC78FD-9979-489D-930A-DA0CD60B9148} + EndGlobalSection +EndGlobal diff --git a/CristalDiskMark/source/CrystalDiskMark/DiskMark.vcxproj b/CristalDiskMark/source/CrystalDiskMark/DiskMark.vcxproj new file mode 100644 index 0000000..b86e789 --- /dev/null +++ b/CristalDiskMark/source/CrystalDiskMark/DiskMark.vcxproj @@ -0,0 +1,3345 @@ + + + + + Debug + ARM + + + Debug + ARM64 + + + Debug + Win32 + + + Debug + x64 + + + Release(UWP) + ARM + + + Release(UWP) + ARM64 + + + Release(UWP) + Win32 + + + Release(UWP) + x64 + + + ReleaseAoi(UWP) + ARM + + + ReleaseAoi(UWP) + ARM64 + + + ReleaseAoi(UWP) + Win32 + + + ReleaseAoi(UWP) + x64 + + + ReleaseMSIMei + ARM + + + ReleaseMSIMei + ARM64 + + + ReleaseMSIMei + Win32 + + + ReleaseMSIMei + x64 + + + ReleaseShizuku(UWP) + ARM + + + ReleaseShizuku(UWP) + ARM64 + + + ReleaseShizuku(UWP) + Win32 + + + ReleaseShizuku(UWP) + x64 + + + ReleaseShizuku + ARM + + + ReleaseShizuku + ARM64 + + + ReleaseShizuku + Win32 + + + ReleaseShizuku + x64 + + + ReleaseAoi + ARM + + + ReleaseAoi + ARM64 + + + ReleaseAoi + Win32 + + + ReleaseAoi + x64 + + + Release + ARM + + + Release + ARM64 + + + Release + Win32 + + + Release + x64 + + + + {CDF33C67-147E-4C50-BC76-99A6BCB214D9} + DiskMark + MFCProj + 10.0.22621.0 + + + + Application + Static + Unicode + true + v142 + + + Application + Static + Unicode + true + v142 + + + Application + Static + Unicode + true + v142 + + + Application + Static + Unicode + true + v142 + + + Application + Static + Unicode + true + v142 + + + Application + Static + Unicode + true + v142 + + + Application + Static + Unicode + true + v142 + + + Application + Static + Unicode + v142 + + + Application + Static + Unicode + true + v142 + + + Application + Static + Unicode + true + v142 + + + Application + Static + Unicode + true + v142 + + + Application + Static + Unicode + true + v143 + true + + + Application + Static + Unicode + true + v143 + true + + + Application + Static + Unicode + true + v143 + true + + + Application + Static + Unicode + true + v143 + true + + + Application + Static + Unicode + true + v143 + true + + + Application + Static + Unicode + true + v143 + true + + + Application + Static + Unicode + true + v142 + + + Application + Static + Unicode + true + v142 + + + Application + Static + Unicode + true + v143 + true + + + Application + Static + Unicode + true + v143 + true + + + Application + Static + Unicode + true + v143 + true + + + Application + Static + Unicode + true + v143 + true + + + Application + Static + Unicode + true + v142 + + + Application + Static + Unicode + true + v143 + true + + + Application + Static + Unicode + true + v143 + true + + + Application + Static + Unicode + true + v142 + + + Application + Static + Unicode + true + v143 + true + + + Application + Static + Unicode + true + v143 + true + + + Application + Static + Unicode + v142 + + + Application + Static + Unicode + v143 + true + + + Application + Static + Unicode + v143 + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\Hotori\ + Build\$(Platform)\$(Configuration)\ + true + ..\Hotori\ + Build\$(Platform)\$(Configuration)\ + true + true + true + ..\Hotori\ + ..\Hotori\ + ..\Hotori\ + ..\Hotori\ + ..\Hotori\ + ..\Hotori\ + ..\Hotori\ + Build\$(Platform)\$(Configuration)\ + Build\$(Platform)\$(Configuration)\ + Build\$(Platform)\$(Configuration)\ + Build\$(Platform)\$(Configuration)\ + Build\$(Platform)\$(Configuration)\ + Build\$(Platform)\$(Configuration)\ + Build\$(Platform)\$(Configuration)\ + false + false + false + false + false + false + false + true + true + true + true + true + true + true + ..\Hotori\ + ..\Hotori\ + ..\Hotori\ + ..\Hotori\ + ..\Hotori\ + ..\Hotori\ + ..\Hotori\ + Build\$(Platform)\$(Configuration)\ + Build\$(Platform)\$(Configuration)\ + Build\$(Platform)\$(Configuration)\ + Build\$(Platform)\$(Configuration)\ + Build\$(Platform)\$(Configuration)\ + Build\$(Platform)\$(Configuration)\ + Build\$(Platform)\$(Configuration)\ + Build\$(Platform)\$(Configuration)\ + Build\$(Platform)\$(Configuration)\ + Build\$(Platform)\$(Configuration)\ + Build\$(Platform)\$(Configuration)\ + Build\$(Platform)\$(Configuration)\ + Build\$(Platform)\$(Configuration)\ + Build\$(Platform)\$(Configuration)\ + Build\$(Platform)\$(Configuration)\ + Build\$(Platform)\$(Configuration)\ + Build\$(Platform)\$(Configuration)\ + Build\$(Platform)\$(Configuration)\ + Build\$(Platform)\$(Configuration)\ + Build\$(Platform)\$(Configuration)\ + Build\$(Platform)\$(Configuration)\ + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + + + $(ProjectName)64S + .\Library;.\Priscilla;$(IncludePath) + + + $(ProjectName)64A + .\Library;.\Priscilla;$(IncludePath) + + + $(ProjectName)64M + .\Library;.\Priscilla;$(IncludePath) + + + $(ProjectName)A64S + ..\Hotori\ + .\Library;.\Priscilla;$(IncludePath) + + + $(ProjectName)A64A + ..\Hotori\ + .\Library;.\Priscilla;$(IncludePath) + + + $(ProjectName)A64M + ..\Hotori\ + .\Library;.\Priscilla;$(IncludePath) + + + $(ProjectName)A32S + ..\Hotori\ + .\Library;.\Priscilla;$(IncludePath) + + + $(ProjectName)A32A + ..\Hotori\ + .\Library;.\Priscilla;$(IncludePath) + + + $(ProjectName)A32M + ..\Hotori\ + .\Library;.\Priscilla;$(IncludePath) + + + $(ProjectName)64S_UWP + .\Library;.\Priscilla;$(IncludePath) + + + $(ProjectName)64A_UWP + .\Library;.\Priscilla;$(IncludePath) + + + $(ProjectName)A64S_UWP + ..\Hotori\ + .\Library;.\Priscilla;$(IncludePath) + + + $(ProjectName)A64A_UWP + ..\Hotori\ + .\Library;.\Priscilla;$(IncludePath) + + + $(ProjectName)A32S_UWP + ..\Hotori\ + .\Library;.\Priscilla;$(IncludePath) + + + $(ProjectName)A32A_UWP + ..\Hotori\ + .\Library;.\Priscilla;$(IncludePath) + + + $(ProjectName)64 + .\Library;.\Priscilla;$(IncludePath) + + + $(ProjectName)A64 + ..\Hotori\ + .\Library;.\Priscilla;$(IncludePath) + + + $(ProjectName)A32 + ..\Hotori\ + .\Library;.\Priscilla;$(IncludePath) + + + $(ProjectName)64_UWP + .\Library;.\Priscilla;$(IncludePath) + + + $(ProjectName)A64_UWP + ..\Hotori\ + .\Library;.\Priscilla;$(IncludePath) + + + $(ProjectName)A32_UWP + ..\Hotori\ + .\Library;.\Priscilla;$(IncludePath) + + + $(ProjectName)32S + .\Library;.\Priscilla;$(IncludePath) + + + $(ProjectName)32A + .\Library;.\Priscilla;$(IncludePath) + + + $(ProjectName)32M + .\Library;.\Priscilla;$(IncludePath) + + + $(ProjectName)32S_UWP + .\Library;.\Priscilla;$(IncludePath) + + + $(ProjectName)32A_UWP + .\Library;.\Priscilla;$(IncludePath) + + + $(ProjectName)32 + .\Library;.\Priscilla;$(IncludePath) + + + $(ProjectName)32_UWP + .\Library;.\Priscilla;$(IncludePath) + + + Build\$(Platform)\$(Configuration)\ + .\Library;.\Priscilla;$(IncludePath) + + + Build\$(Platform)\$(Configuration)\ + .\Library;.\Priscilla;$(IncludePath) + + + .\Library;.\Priscilla;$(IncludePath) + + + .\Library;.\Priscilla;$(IncludePath) + + + + _DEBUG;%(PreprocessorDefinitions) + false + false + + + Disabled + MIX_MODE;WIN32;_WINDOWS;_DEBUG;%(PreprocessorDefinitions) + false + EnableFastChecks + MultiThreadedDebug + Use + Level3 + EditAndContinue + /FS %(AdditionalOptions) + ..\stdafx.h + true + + + _MIX_MODE;_DEBUG;%(PreprocessorDefinitions) + 0x0411 + $(IntDir);%(AdditionalIncludeDirectories) + + + true + Windows + true + + + MachineX86 + ..\Hotori\DiskMark.exe + + + %(AdditionalManifestFiles) + PerMonitorHighDPIAware + + + + + _DEBUG;%(PreprocessorDefinitions) + false + X64 + + + Disabled + MIX_MODE;WIN32;_WINDOWS;_DEBUG;%(PreprocessorDefinitions) + false + EnableFastChecks + MultiThreadedDebug + Use + Level3 + ProgramDatabase + true + ..\stdafx.h + + + _MIX_MODE;_DEBUG;%(PreprocessorDefinitions) + 0x0411 + $(IntDir);%(AdditionalIncludeDirectories) + + + true + Windows + true + + + MachineX64 + /DEPENDENTLOADFLAG:0x800 /SUBSYSTEM:WINDOWS,5.02 %(AdditionalOptions) + + + %(AdditionalManifestFiles) + PerMonitorHighDPIAware + + + + + _DEBUG;%(PreprocessorDefinitions) + false + + + Disabled + WIN32;_WINDOWS;_DEBUG;%(PreprocessorDefinitions) + false + EnableFastChecks + MultiThreadedDebug + Use + Level3 + ProgramDatabase + ..\stdafx.h + true + + + _DEBUG;%(PreprocessorDefinitions) + 0x0411 + $(IntDir);%(AdditionalIncludeDirectories) + + + true + Windows + true + + + /DEPENDENTLOADFLAG:0x800 %(AdditionalOptions) + + + %(AdditionalManifestFiles) + PerMonitorHighDPIAware + + + + + _DEBUG;%(PreprocessorDefinitions) + false + + + Disabled + WIN32;_WINDOWS;_DEBUG;%(PreprocessorDefinitions) + false + EnableFastChecks + MultiThreadedDebug + Use + Level3 + ProgramDatabase + ..\stdafx.h + true + + + _DEBUG;%(PreprocessorDefinitions) + 0x0411 + $(IntDir);%(AdditionalIncludeDirectories) + + + true + Windows + true + + + + + %(AdditionalManifestFiles) + PerMonitorHighDPIAware + + + + + NDEBUG;%(PreprocessorDefinitions) + false + false + + + MaxSpeed + Speed + SUISHO_SHIZUKU_SUPPORT;WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) + false + MultiThreaded + Use + Level3 + ProgramDatabase + NoExtensions + true + ..\stdafx.h + true + + + SUISHO_SHIZUKU_SUPPORT;NDEBUG;%(PreprocessorDefinitions) + 0x0411 + $(IntDir);%(AdditionalIncludeDirectories) + + + ..\Hotori\$(ProjectName)32S.exe + false + Windows + true + true + true + + + MachineX86 + /SUBSYSTEM:WINDOWS,5.01 %(AdditionalOptions) + + + %(AdditionalManifestFiles) + PerMonitorHighDPIAware + + + + + NDEBUG;%(PreprocessorDefinitions) + false + false + + + MaxSpeed + Speed + SUISHO_AOI_SUPPORT;SUISHO_SHIZUKU_SUPPORT;WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) + false + MultiThreaded + Use + Level3 + ProgramDatabase + NoExtensions + true + ..\stdafx.h + true + + + SUISHO_AOI_SUPPORT;SUISHO_SHIZUKU_SUPPORT;NDEBUG;%(PreprocessorDefinitions) + 0x0411 + $(IntDir);%(AdditionalIncludeDirectories) + + + ..\Hotori\$(ProjectName)32A.exe + false + Windows + true + true + true + + + MachineX86 + /SUBSYSTEM:WINDOWS,5.01 %(AdditionalOptions) + + + %(AdditionalManifestFiles) + PerMonitorHighDPIAware + + + + + NDEBUG;%(PreprocessorDefinitions) + false + false + + + MaxSpeed + Speed + MSI_MEI_SUPPORT;SUISHO_SHIZUKU_SUPPORT;WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) + false + MultiThreaded + Use + Level3 + ProgramDatabase + NoExtensions + true + ..\stdafx.h + true + + + MSI_MEI_SUPPORT;SUISHO_SHIZUKU_SUPPORT;NDEBUG;%(PreprocessorDefinitions) + 0x0411 + $(IntDir);%(AdditionalIncludeDirectories) + + + ..\Hotori\$(ProjectName)32M.exe + false + Windows + true + true + true + + + MachineX86 + /SUBSYSTEM:WINDOWS,5.01 %(AdditionalOptions) + + + %(AdditionalManifestFiles) + PerMonitorHighDPIAware + + + + + NDEBUG;%(PreprocessorDefinitions) + false + false + + + MaxSpeed + Speed + UWP;SUISHO_SHIZUKU_SUPPORT;WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) + false + MultiThreaded + Use + Level3 + ProgramDatabase + NoExtensions + true + ..\stdafx.h + true + + + SUISHO_SHIZUKU_SUPPORT;NDEBUG;%(PreprocessorDefinitions) + 0x0411 + $(IntDir);%(AdditionalIncludeDirectories) + + + ..\Hotori\$(ProjectName)32S_UWP.exe + false + Windows + true + true + true + + + MachineX86 + /SUBSYSTEM:WINDOWS,5.01 %(AdditionalOptions) + + + %(AdditionalManifestFiles) + PerMonitorHighDPIAware + + + + + NDEBUG;%(PreprocessorDefinitions) + false + false + + + MaxSpeed + Speed + UWP;SUISHO_AOI_SUPPORT;SUISHO_SHIZUKU_SUPPORT;WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) + false + MultiThreaded + Use + Level3 + ProgramDatabase + NoExtensions + true + ..\stdafx.h + true + + + SUISHO_AOI_SUPPORT;SUISHO_SHIZUKU_SUPPORT;NDEBUG;%(PreprocessorDefinitions) + 0x0411 + $(IntDir);%(AdditionalIncludeDirectories) + + + ..\Hotori\$(ProjectName)32A_UWP.exe + false + Windows + true + true + true + + + MachineX86 + /SUBSYSTEM:WINDOWS,5.01 %(AdditionalOptions) + + + %(AdditionalManifestFiles) + PerMonitorHighDPIAware + + + + + NDEBUG;%(PreprocessorDefinitions) + false + false + + + MaxSpeed + Speed + MIX_MODE;WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) + false + MultiThreaded + Use + Level3 + ProgramDatabase + NoExtensions + true + ..\stdafx.h + true + + + _MIX_MODE;NDEBUG;%(PreprocessorDefinitions) + 0x0411 + $(IntDir);%(AdditionalIncludeDirectories) + + + ..\Hotori\$(ProjectName)32.exe + false + Windows + true + true + true + + + MachineX86 + /SUBSYSTEM:WINDOWS,5.01 %(AdditionalOptions) + + + %(AdditionalManifestFiles) + PerMonitorHighDPIAware + + + + + NDEBUG;%(PreprocessorDefinitions) + false + false + + + MaxSpeed + Speed + MIX_MODE;UWP;WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) + false + MultiThreaded + Use + Level3 + ProgramDatabase + NoExtensions + true + ..\stdafx.h + true + + + _MIX_MODE;NDEBUG;%(PreprocessorDefinitions) + 0x0411 + $(IntDir);%(AdditionalIncludeDirectories) + + + ..\Hotori\$(ProjectName)32_UWP.exe + false + Windows + true + true + true + + + MachineX86 + /SUBSYSTEM:WINDOWS,5.01 %(AdditionalOptions) + + + %(AdditionalManifestFiles) + PerMonitorHighDPIAware + + + + + NDEBUG;%(PreprocessorDefinitions) + false + X64 + + + Speed + SUISHO_SHIZUKU_SUPPORT;WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) + false + MultiThreaded + Use + Level3 + ProgramDatabase + MaxSpeed + + + true + ..\stdafx.h + + + SUISHO_SHIZUKU_SUPPORT;NDEBUG;%(PreprocessorDefinitions) + 0x0411 + $(IntDir);%(AdditionalIncludeDirectories) + + + false + Windows + true + true + true + + + MachineX64 + ..\Hotori\$(ProjectName)64S.exe + /DEPENDENTLOADFLAG:0x800 /SUBSYSTEM:WINDOWS,5.02 %(AdditionalOptions) + + + %(AdditionalManifestFiles) + PerMonitorHighDPIAware + + + + + NDEBUG;%(PreprocessorDefinitions) + false + X64 + + + Speed + SUISHO_AOI_SUPPORT;SUISHO_SHIZUKU_SUPPORT;WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) + false + MultiThreaded + Use + Level3 + ProgramDatabase + MaxSpeed + + + true + ..\stdafx.h + + + SUISHO_AOI_SUPPORT;SUISHO_SHIZUKU_SUPPORT;NDEBUG;%(PreprocessorDefinitions) + 0x0411 + $(IntDir);%(AdditionalIncludeDirectories) + + + false + Windows + true + true + true + + + MachineX64 + ..\Hotori\$(ProjectName)64A.exe + /DEPENDENTLOADFLAG:0x800 /SUBSYSTEM:WINDOWS,5.02 %(AdditionalOptions) + + + %(AdditionalManifestFiles) + PerMonitorHighDPIAware + + + + + NDEBUG;%(PreprocessorDefinitions) + false + X64 + + + Speed + MSI_MEI_SUPPORT;SUISHO_SHIZUKU_SUPPORT;WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) + false + MultiThreaded + Use + Level3 + ProgramDatabase + MaxSpeed + + + true + ..\stdafx.h + + + MSI_MEI_SUPPORT;SUISHO_SHIZUKU_SUPPORT;NDEBUG;%(PreprocessorDefinitions) + 0x0411 + $(IntDir);%(AdditionalIncludeDirectories) + + + false + Windows + true + true + true + + + MachineX64 + ..\Hotori\$(ProjectName)64M.exe + /DEPENDENTLOADFLAG:0x800 /SUBSYSTEM:WINDOWS,5.02 %(AdditionalOptions) + + + %(AdditionalManifestFiles) + PerMonitorHighDPIAware + + + + + NDEBUG;%(PreprocessorDefinitions) + false + + + Speed + SUISHO_SHIZUKU_SUPPORT;WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) + false + MultiThreaded + Use + Level3 + ProgramDatabase + MaxSpeed + true + ..\stdafx.h + true + + + SUISHO_SHIZUKU_SUPPORT;NDEBUG;%(PreprocessorDefinitions) + 0x0411 + $(IntDir);%(AdditionalIncludeDirectories) + + + false + Windows + true + true + true + + + ..\Hotori\$(ProjectName)A64S.exe + /DEPENDENTLOADFLAG:0x800 %(AdditionalOptions) + + + %(AdditionalManifestFiles) + PerMonitorHighDPIAware + + + + + NDEBUG;%(PreprocessorDefinitions) + false + + + Speed + SUISHO_AOI_SUPPORT;SUISHO_SHIZUKU_SUPPORT;WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) + false + MultiThreaded + Use + Level3 + ProgramDatabase + MaxSpeed + true + ..\stdafx.h + true + + + SUISHO_AOI_SUPPORT;SUISHO_SHIZUKU_SUPPORT;NDEBUG;%(PreprocessorDefinitions) + 0x0411 + $(IntDir);%(AdditionalIncludeDirectories) + + + false + Windows + true + true + true + + + ..\Hotori\$(ProjectName)A64A.exe + /DEPENDENTLOADFLAG:0x800 %(AdditionalOptions) + + + %(AdditionalManifestFiles) + PerMonitorHighDPIAware + + + + + NDEBUG;%(PreprocessorDefinitions) + false + + + Speed + MSI_MEI_SUPPORT;SUISHO_SHIZUKU_SUPPORT;WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) + false + MultiThreaded + Use + Level3 + ProgramDatabase + MaxSpeed + true + ..\stdafx.h + true + + + MSI_MEI_SUPPORT;SUISHO_SHIZUKU_SUPPORT;NDEBUG;%(PreprocessorDefinitions) + 0x0411 + $(IntDir);%(AdditionalIncludeDirectories) + + + false + Windows + true + true + true + + + ..\Hotori\$(ProjectName)A64M.exe + /DEPENDENTLOADFLAG:0x800 %(AdditionalOptions) + + + %(AdditionalManifestFiles) + PerMonitorHighDPIAware + + + + + NDEBUG;%(PreprocessorDefinitions) + false + + + Speed + SUISHO_SHIZUKU_SUPPORT;WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) + false + MultiThreaded + Use + Level3 + ProgramDatabase + MaxSpeed + true + ..\stdafx.h + true + + + SUISHO_SHIZUKU_SUPPORT;NDEBUG;%(PreprocessorDefinitions) + 0x0411 + $(IntDir);%(AdditionalIncludeDirectories) + + + false + Windows + true + true + true + + + ..\Hotori\$(ProjectName)A32S.exe + + + %(AdditionalManifestFiles) + PerMonitorHighDPIAware + + + + + NDEBUG;%(PreprocessorDefinitions) + false + + + Speed + SUISHO_AOI_SUPPORT;SUISHO_SHIZUKU_SUPPORT;WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) + false + MultiThreaded + Use + Level3 + ProgramDatabase + MaxSpeed + true + ..\stdafx.h + true + + + SUISHO_AOI_SUPPORT;SUISHO_SHIZUKU_SUPPORT;NDEBUG;%(PreprocessorDefinitions) + 0x0411 + $(IntDir);%(AdditionalIncludeDirectories) + + + false + Windows + true + true + true + + + ..\Hotori\$(ProjectName)A32A.exe + + + %(AdditionalManifestFiles) + PerMonitorHighDPIAware + + + + + NDEBUG;%(PreprocessorDefinitions) + false + + + Speed + MSI_MEI_SUPPORT;SUISHO_SHIZUKU_SUPPORT;WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) + false + MultiThreaded + Use + Level3 + ProgramDatabase + MaxSpeed + true + ..\stdafx.h + true + + + MSI_MEI_SUPPORT;SUISHO_SHIZUKU_SUPPORT;NDEBUG;%(PreprocessorDefinitions) + 0x0411 + $(IntDir);%(AdditionalIncludeDirectories) + + + false + Windows + true + true + true + + + ..\Hotori\$(ProjectName)A32M.exe + + + %(AdditionalManifestFiles) + PerMonitorHighDPIAware + + + + + NDEBUG;%(PreprocessorDefinitions) + false + X64 + + + Speed + UWP;SUISHO_SHIZUKU_SUPPORT;WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) + false + MultiThreaded + Use + Level3 + ProgramDatabase + MaxSpeed + true + ..\stdafx.h + + + SUISHO_SHIZUKU_SUPPORT;NDEBUG;%(PreprocessorDefinitions) + 0x0411 + $(IntDir);%(AdditionalIncludeDirectories) + + + false + Windows + true + true + true + + + MachineX64 + ..\Hotori\$(ProjectName)64S_UWP.exe + /DEPENDENTLOADFLAG:0x800 /SUBSYSTEM:WINDOWS,5.02 %(AdditionalOptions) + + + %(AdditionalManifestFiles) + PerMonitorHighDPIAware + + + + + NDEBUG;%(PreprocessorDefinitions) + false + X64 + + + Speed + UWP;SUISHO_AOI_SUPPORT;SUISHO_SHIZUKU_SUPPORT;WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) + false + MultiThreaded + Use + Level3 + ProgramDatabase + MaxSpeed + true + ..\stdafx.h + + + SUISHO_AOI_SUPPORT;SUISHO_SHIZUKU_SUPPORT;NDEBUG;%(PreprocessorDefinitions) + 0x0411 + $(IntDir);%(AdditionalIncludeDirectories) + + + false + Windows + true + true + true + + + MachineX64 + ..\Hotori\$(ProjectName)64A_UWP.exe + /DEPENDENTLOADFLAG:0x800 /SUBSYSTEM:WINDOWS,5.02 %(AdditionalOptions) + + + %(AdditionalManifestFiles) + PerMonitorHighDPIAware + + + + + NDEBUG;%(PreprocessorDefinitions) + false + + + Speed + UWP;SUISHO_SHIZUKU_SUPPORT;WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) + false + MultiThreaded + Use + Level3 + ProgramDatabase + MaxSpeed + true + ..\stdafx.h + true + + + SUISHO_SHIZUKU_SUPPORT;NDEBUG;%(PreprocessorDefinitions) + 0x0411 + $(IntDir);%(AdditionalIncludeDirectories) + + + false + Windows + true + true + true + + + ..\Hotori\$(ProjectName)A64S_UWP.exe + /DEPENDENTLOADFLAG:0x800 %(AdditionalOptions) + + + %(AdditionalManifestFiles) + PerMonitorHighDPIAware + + + + + NDEBUG;%(PreprocessorDefinitions) + false + + + Speed + UWP;SUISHO_AOI_SUPPORT;SUISHO_SHIZUKU_SUPPORT;WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) + false + MultiThreaded + Use + Level3 + ProgramDatabase + MaxSpeed + true + ..\stdafx.h + true + + + SUISHO_AOI_SUPPORT;SUISHO_SHIZUKU_SUPPORT;NDEBUG;%(PreprocessorDefinitions) + 0x0411 + $(IntDir);%(AdditionalIncludeDirectories) + + + false + Windows + true + true + true + + + ..\Hotori\$(ProjectName)A64A_UWP.exe + /DEPENDENTLOADFLAG:0x800 %(AdditionalOptions) + + + %(AdditionalManifestFiles) + PerMonitorHighDPIAware + + + + + NDEBUG;%(PreprocessorDefinitions) + false + + + Speed + UWP;SUISHO_SHIZUKU_SUPPORT;WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) + false + MultiThreaded + Use + Level3 + ProgramDatabase + MaxSpeed + true + ..\stdafx.h + true + + + SUISHO_SHIZUKU_SUPPORT;NDEBUG;%(PreprocessorDefinitions) + 0x0411 + $(IntDir);%(AdditionalIncludeDirectories) + + + false + Windows + true + true + true + + + ..\Hotori\$(ProjectName)A32S_UWP.exe + + + %(AdditionalManifestFiles) + PerMonitorHighDPIAware + + + + + NDEBUG;%(PreprocessorDefinitions) + false + + + Speed + UWP;SUISHO_AOI_SUPPORT;SUISHO_SHIZUKU_SUPPORT;WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) + false + MultiThreaded + Use + Level3 + ProgramDatabase + MaxSpeed + true + ..\stdafx.h + true + + + SUISHO_AOI_SUPPORT;SUISHO_SHIZUKU_SUPPORT;NDEBUG;%(PreprocessorDefinitions) + 0x0411 + $(IntDir);%(AdditionalIncludeDirectories) + + + false + Windows + true + true + true + + + ..\Hotori\$(ProjectName)A32A_UWP.exe + + + %(AdditionalManifestFiles) + PerMonitorHighDPIAware + + + + + NDEBUG;%(PreprocessorDefinitions) + false + X64 + + + Speed + MIX_MODE;WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) + MultiThreaded + Use + Level3 + ProgramDatabase + MaxSpeed + true + + + true + ..\stdafx.h + + + _MIX_MODE;NDEBUG;%(PreprocessorDefinitions) + 0x0411 + $(IntDir);%(AdditionalIncludeDirectories) + + + false + Windows + true + true + true + + + MachineX64 + ..\Hotori\$(ProjectName)64.exe + /DEPENDENTLOADFLAG:0x800 /SUBSYSTEM:WINDOWS,5.02 %(AdditionalOptions) + + + %(AdditionalManifestFiles) + PerMonitorHighDPIAware + + + + + NDEBUG;%(PreprocessorDefinitions) + false + + + Speed + MIX_MODE;WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) + false + MultiThreaded + Use + Level3 + ProgramDatabase + MaxSpeed + true + ..\stdafx.h + true + + + _MIX_MODE;NDEBUG;%(PreprocessorDefinitions) + 0x0411 + $(IntDir);%(AdditionalIncludeDirectories) + + + false + Windows + true + true + true + + + ..\Hotori\$(ProjectName)A64.exe + /DEPENDENTLOADFLAG:0x800 %(AdditionalOptions) + + + %(AdditionalManifestFiles) + PerMonitorHighDPIAware + + + + + NDEBUG;%(PreprocessorDefinitions) + false + + + Speed + MIX_MODE;WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) + false + MultiThreaded + Use + Level3 + ProgramDatabase + MaxSpeed + true + ..\stdafx.h + true + + + _MIX_MODE;NDEBUG;%(PreprocessorDefinitions) + 0x0411 + $(IntDir);%(AdditionalIncludeDirectories) + + + false + Windows + true + true + true + + + ..\Hotori\$(ProjectName)A32.exe + + + %(AdditionalManifestFiles) + PerMonitorHighDPIAware + + + + + NDEBUG;%(PreprocessorDefinitions) + false + X64 + + + Speed + MIX_MODE;UWP;WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) + false + MultiThreaded + Use + Level3 + ProgramDatabase + MaxSpeed + true + ..\stdafx.h + + + _MIX_MODE;NDEBUG;%(PreprocessorDefinitions) + 0x0411 + $(IntDir);%(AdditionalIncludeDirectories) + + + false + Windows + true + true + true + + + MachineX64 + ..\Hotori\$(ProjectName)64_UWP.exe + /DEPENDENTLOADFLAG:0x800 /SUBSYSTEM:WINDOWS,5.02 %(AdditionalOptions) + + + %(AdditionalManifestFiles) + PerMonitorHighDPIAware + + + + + NDEBUG;%(PreprocessorDefinitions) + false + + + Speed + MIX_MODE;UWP;WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) + false + MultiThreaded + Use + Level3 + ProgramDatabase + MaxSpeed + true + ..\stdafx.h + true + + + _MIX_MODE;NDEBUG;%(PreprocessorDefinitions) + 0x0411 + $(IntDir);%(AdditionalIncludeDirectories) + + + false + Windows + true + true + true + + + ..\Hotori\$(ProjectName)A64_UWP.exe + /DEPENDENTLOADFLAG:0x800 %(AdditionalOptions) + + + %(AdditionalManifestFiles) + PerMonitorHighDPIAware + + + + + NDEBUG;%(PreprocessorDefinitions) + false + + + Speed + MIX_MODE;UWP;WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) + false + MultiThreaded + Use + Level3 + ProgramDatabase + MaxSpeed + true + ..\stdafx.h + true + + + _MIX_MODE;NDEBUG;%(PreprocessorDefinitions) + 0x0411 + $(IntDir);%(AdditionalIncludeDirectories) + + + false + Windows + true + true + true + + + ..\Hotori\$(ProjectName)A32_UWP.exe + + + %(AdditionalManifestFiles) + PerMonitorHighDPIAware + + + + + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + Sync + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + NotUsing + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + NotUsing + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + NotUsing + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + NotUsing + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + + + NotUsing + stdafx.h + NotUsing + stdafx.h + NotUsing + stdafx.h + NotUsing + stdafx.h + NotUsing + stdafx.h + NotUsing + stdafx.h + NotUsing + stdafx.h + NotUsing + stdafx.h + NotUsing + stdafx.h + NotUsing + stdafx.h + NotUsing + stdafx.h + NotUsing + stdafx.h + NotUsing + stdafx.h + NotUsing + stdafx.h + NotUsing + stdafx.h + NotUsing + stdafx.h + NotUsing + stdafx.h + NotUsing + stdafx.h + NotUsing + stdafx.h + NotUsing + stdafx.h + NotUsing + stdafx.h + NotUsing + stdafx.h + NotUsing + stdafx.h + NotUsing + stdafx.h + NotUsing + stdafx.h + NotUsing + stdafx.h + NotUsing + stdafx.h + NotUsing + stdafx.h + NotUsing + stdafx.h + NotUsing + stdafx.h + NotUsing + stdafx.h + NotUsing + stdafx.h + + + NotUsing + stdafx.h + NotUsing + stdafx.h + NotUsing + stdafx.h + NotUsing + stdafx.h + NotUsing + stdafx.h + NotUsing + stdafx.h + NotUsing + stdafx.h + NotUsing + stdafx.h + NotUsing + stdafx.h + NotUsing + stdafx.h + NotUsing + stdafx.h + NotUsing + stdafx.h + NotUsing + stdafx.h + NotUsing + stdafx.h + NotUsing + stdafx.h + NotUsing + stdafx.h + NotUsing + stdafx.h + NotUsing + stdafx.h + NotUsing + stdafx.h + NotUsing + stdafx.h + NotUsing + stdafx.h + NotUsing + stdafx.h + NotUsing + stdafx.h + NotUsing + stdafx.h + NotUsing + stdafx.h + NotUsing + stdafx.h + NotUsing + stdafx.h + NotUsing + stdafx.h + NotUsing + stdafx.h + NotUsing + stdafx.h + NotUsing + stdafx.h + NotUsing + stdafx.h + + + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + stdafx.h + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + MIX_MODE;_DEBUG;%(PreprocessorDefinitions) + SUISHO_SHIZUKU_SUPPORT;MIX_MODE;_DEBUG;%(PreprocessorDefinitions) + MIX_MODE;NDEBUG;%(PreprocessorDefinitions) + MIX_MODE;NDEBUG;%(PreprocessorDefinitions) + MIX_MODE;NDEBUG;%(PreprocessorDefinitions) + MIX_MODE;NDEBUG;%(PreprocessorDefinitions) + MIX_MODE;NDEBUG;%(PreprocessorDefinitions) + MIX_MODE;NDEBUG;%(PreprocessorDefinitions) + MIX_MODE;NDEBUG;%(PreprocessorDefinitions) + MIX_MODE;NDEBUG;%(PreprocessorDefinitions) + + + + + + + + + + + + + + \ No newline at end of file diff --git a/CristalDiskMark/source/CrystalDiskMark/DiskMark.vcxproj.filters b/CristalDiskMark/source/CrystalDiskMark/DiskMark.vcxproj.filters new file mode 100644 index 0000000..a10f1e7 --- /dev/null +++ b/CristalDiskMark/source/CrystalDiskMark/DiskMark.vcxproj.filters @@ -0,0 +1,171 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav + + + {342a84d1-5b9a-4a10-b0ca-cc618409b820} + + + {1e1cebf3-7ec5-4e7b-b130-da0db639e588} + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Priscilla + + + Priscilla + + + Priscilla + + + Priscilla + + + Source Files + + + Priscilla + + + Priscilla + + + Priscilla + + + Priscilla + + + Priscilla + + + Priscilla + + + Library + + + Priscilla + + + Priscilla + + + Priscilla + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Priscilla + + + Priscilla + + + Priscilla + + + Priscilla + + + Priscilla + + + Priscilla + + + Header Files + + + Priscilla + + + Priscilla + + + Priscilla + + + Priscilla + + + Priscilla + + + Library + + + Library + + + Priscilla + + + Priscilla + + + + + Resource Files + + + Resource Files + + + Resource Files + + + + + Resource Files + + + + + Resource Files + + + \ No newline at end of file diff --git a/CristalDiskMark/source/CrystalDiskMark/DiskMarkDlg.cpp b/CristalDiskMark/source/CrystalDiskMark/DiskMarkDlg.cpp new file mode 100644 index 0000000..46aba55 --- /dev/null +++ b/CristalDiskMark/source/CrystalDiskMark/DiskMarkDlg.cpp @@ -0,0 +1,3793 @@ +/*---------------------------------------------------------------------------*/ +// Author : hiyohiyo +// Mail : hiyohiyo@crystalmark.info +// Web : https://crystalmark.info/ +// License : MIT License +/*---------------------------------------------------------------------------*/ + +#include "stdafx.h" +#include "DiskMark.h" +#include "DiskMarkDlg.h" +#include "DiskBench.h" +#include "AboutDlg.h" + +#include + +#ifdef SUISHO_SHIZUKU_SUPPORT +#define SIZE_X 1000 +#define SIZE_Y 500 +#define SIZE_MIN_Y 500 +#define OFFSET_X 200 +#define MAX_METER_LENGTH 320 +#else +#define SIZE_X 480 +#define SIZE_X_MIX 680 +#define SIZE_Y 300 +#define SIZE_MIN_Y 300 +#define OFFSET_X 0 +#define MAX_METER_LENGTH 192 +#endif + +#ifdef _DEBUG +#define new DEBUG_NEW +#endif + +extern PROCESS_INFORMATION pi; + +CDiskMarkDlg::CDiskMarkDlg(CWnd* pParent /*=NULL*/) + : CMainDialogFx(CDiskMarkDlg::IDD, pParent) +{ + m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); + m_hIconMini = AfxGetApp()->LoadIcon(IDI_TRAY_ICON); + + m_AboutDlg = NULL; + m_SettingsDlg = NULL; + +#ifdef SUISHO_AOI_SUPPORT + m_DefaultTheme = L"Aoi"; + m_RecommendTheme = L"AoiLightAnimalEars~TenmuShinryuusai"; + m_ThemeKeyName = L"ThemeAoi"; + + m_MarginButtonTop = 16; + m_MarginButtonLeft = 0; + m_MarginButtonBottom = 16; + m_MarginButtonRight = 0; + m_MarginMeterTop = 0; + m_MarginMeterLeft = 0; + m_MarginMeterBottom = 0; + m_MarginMeterRight = 16; + m_MarginCommentTop = 0; + m_MarginCommentLeft = 16; + m_MarginCommentBottom = 0; + m_MarginCommentRight = 16; + m_MarginDemoTop = 24; + m_MarginDemoLeft = 24; + m_MarginDemoBottom = 24; + m_MarginDemoRight = 24; +#elif MSI_MEI_SUPPORT + m_DefaultTheme = L"MSIMei"; + m_RecommendTheme = L"MSIMei"; + m_ThemeKeyName = L"ThemeMSIMei"; + + m_MarginButtonTop = 8; + m_MarginButtonLeft = 0; + m_MarginButtonBottom = 8; + m_MarginButtonRight = 0; + m_MarginMeterTop = 0; + m_MarginMeterLeft = 0; + m_MarginMeterBottom = 0; + m_MarginMeterRight = 16; + m_MarginCommentTop = 0; + m_MarginCommentLeft = 16; + m_MarginCommentBottom = 0; + m_MarginCommentRight = 64; + m_MarginDemoTop = 24; + m_MarginDemoLeft = 24; + m_MarginDemoBottom = 24; + m_MarginDemoRight = 24; +#elif SUISHO_SHIZUKU_SUPPORT + m_DefaultTheme = L"Shizuku"; + m_RecommendTheme = L"ShizukuLightAnimalEars~TenmuShinryuusai"; + m_ThemeKeyName = L"ThemeShizuku"; + + m_MarginButtonTop = 8; + m_MarginButtonLeft = 0; + m_MarginButtonBottom = 8; + m_MarginButtonRight = 0; + m_MarginMeterTop = 0; + m_MarginMeterLeft = 0; + m_MarginMeterBottom = 0; + m_MarginMeterRight = 16; + m_MarginCommentTop = 0; + m_MarginCommentLeft = 16; + m_MarginCommentBottom = 0; + m_MarginCommentRight = 64; + m_MarginDemoTop = 24; + m_MarginDemoLeft = 24; + m_MarginDemoBottom = 24; + m_MarginDemoRight = 24; +#else + m_DefaultTheme = L"Default"; + m_ThemeKeyName = L"Theme"; + + m_MarginButtonTop = 4; + m_MarginButtonLeft = 0; + m_MarginButtonBottom = 4; + m_MarginButtonRight = 0; + m_MarginMeterTop = 0; + m_MarginMeterLeft = 0; + m_MarginMeterBottom = 0; + m_MarginMeterRight = 4; + m_MarginCommentTop = 0; + m_MarginCommentLeft = 4; + m_MarginCommentBottom = 0; + m_MarginCommentRight = 4; + m_MarginDemoTop = 8; + m_MarginDemoLeft = 8; + m_MarginDemoBottom = 8; + m_MarginDemoRight = 8; +#endif + + m_BackgroundName = L"Background"; + m_RandomThemeLabel = L"Random"; + m_RandomThemeName = L""; + + m_AdminMode = IsUserAnAdmin(); +} + + +void CDiskMarkDlg::UpdateThemeInfo() +{ + CMainDialogFx::UpdateThemeInfo(); + + CString theme = m_ThemeDir + m_CurrentTheme + L"\\theme.ini"; + +#ifdef SUISHO_AOI_SUPPORT + m_MarginButtonTop = GetPrivateProfileInt(L"Margin", L"ButtonTop", 16, theme); + m_MarginButtonLeft = GetPrivateProfileInt(L"Margin", L"ButtonLeft", 0, theme); + m_MarginButtonBottom = GetPrivateProfileInt(L"Margin", L"ButtonBottom", 16, theme); + m_MarginButtonRight = GetPrivateProfileInt(L"Margin", L"ButtonRight", 0, theme); + m_MarginMeterTop = GetPrivateProfileInt(L"Margin", L"MeterTop", 0, theme); + m_MarginMeterLeft = GetPrivateProfileInt(L"Margin", L"MeterLeft", 0, theme); + m_MarginMeterBottom = GetPrivateProfileInt(L"Margin", L"MeterBottom", 0, theme); + m_MarginMeterRight = GetPrivateProfileInt(L"Margin", L"MeterRight", 16, theme); + m_MarginCommentTop = GetPrivateProfileInt(L"Margin", L"CommentTop", 0, theme); + m_MarginCommentLeft = GetPrivateProfileInt(L"Margin", L"CommentLeft", 4, theme); + m_MarginCommentBottom = GetPrivateProfileInt(L"Margin", L"CommentBottom", 0, theme); + m_MarginCommentRight = GetPrivateProfileInt(L"Margin", L"CommentRight", 4, theme); + m_MarginDemoTop = GetPrivateProfileInt(L"Margin", L"DemoTop", 24, theme); + m_MarginDemoLeft = GetPrivateProfileInt(L"Margin", L"DemoLeft", 24, theme); + m_MarginDemoBottom = GetPrivateProfileInt(L"Margin", L"DemoBottom", 24, theme); + m_MarginDemoRight = GetPrivateProfileInt(L"Margin", L"DemoRight", 24, theme); + +#elif MSI_MEI_SUPPORT + m_MarginButtonTop = GetPrivateProfileInt(L"Margin", L"ButtonTop", 8, theme); + m_MarginButtonLeft = GetPrivateProfileInt(L"Margin", L"ButtonLeft", 0, theme); + m_MarginButtonBottom = GetPrivateProfileInt(L"Margin", L"ButtonBottom", 8, theme); + m_MarginButtonRight = GetPrivateProfileInt(L"Margin", L"ButtonRight", 0, theme); + m_MarginMeterTop = GetPrivateProfileInt(L"Margin", L"MeterTop", 0, theme); + m_MarginMeterLeft = GetPrivateProfileInt(L"Margin", L"MeterLeft", 0, theme); + m_MarginMeterBottom = GetPrivateProfileInt(L"Margin", L"MeterBottom", 0, theme); + m_MarginMeterRight = GetPrivateProfileInt(L"Margin", L"MeterRight", 16, theme); + m_MarginCommentTop = GetPrivateProfileInt(L"Margin", L"CommentTop", 0, theme); + m_MarginCommentLeft = GetPrivateProfileInt(L"Margin", L"CommentLeft", 16, theme); + m_MarginCommentBottom = GetPrivateProfileInt(L"Margin", L"CommentBottom", 0, theme); + m_MarginCommentRight = GetPrivateProfileInt(L"Margin", L"CommentRight", 16, theme); + m_MarginDemoTop = GetPrivateProfileInt(L"Margin", L"DemoTop", 24, theme); + m_MarginDemoLeft = GetPrivateProfileInt(L"Margin", L"DemoLeft", 24, theme); + m_MarginDemoBottom = GetPrivateProfileInt(L"Margin", L"DemoBottom", 24, theme); + m_MarginDemoRight = GetPrivateProfileInt(L"Margin", L"DemoRight", 24, theme); + +#elif SUISHO_SHIZUKU_SUPPORT + m_MarginButtonTop = GetPrivateProfileInt(L"Margin", L"ButtonTop", 8, theme); + m_MarginButtonLeft = GetPrivateProfileInt(L"Margin", L"ButtonLeft", 0, theme); + m_MarginButtonBottom = GetPrivateProfileInt(L"Margin", L"ButtonBottom", 8, theme); + m_MarginButtonRight = GetPrivateProfileInt(L"Margin", L"ButtonRight", 0, theme); + m_MarginMeterTop = GetPrivateProfileInt(L"Margin", L"MeterTop", 0, theme); + m_MarginMeterLeft = GetPrivateProfileInt(L"Margin", L"MeterLeft", 0, theme); + m_MarginMeterBottom = GetPrivateProfileInt(L"Margin", L"MeterBottom", 0, theme); + m_MarginMeterRight = GetPrivateProfileInt(L"Margin", L"MeterRight", 16, theme); + m_MarginCommentTop = GetPrivateProfileInt(L"Margin", L"CommentTop", 0, theme); + m_MarginCommentLeft = GetPrivateProfileInt(L"Margin", L"CommentLeft", 16, theme); + m_MarginCommentBottom = GetPrivateProfileInt(L"Margin", L"CommentBottom", 0, theme); + m_MarginCommentRight = GetPrivateProfileInt(L"Margin", L"CommentRight", 16, theme); + m_MarginDemoTop = GetPrivateProfileInt(L"Margin", L"DemoTop", 24, theme); + m_MarginDemoLeft = GetPrivateProfileInt(L"Margin", L"DemoLeft", 24, theme); + m_MarginDemoBottom = GetPrivateProfileInt(L"Margin", L"DemoBottom", 24, theme); + m_MarginDemoRight = GetPrivateProfileInt(L"Margin", L"DemoRight", 24, theme); +#else + m_MarginButtonTop = GetPrivateProfileInt(L"Margin", L"ButtonTop", 4, theme); + m_MarginButtonLeft = GetPrivateProfileInt(L"Margin", L"ButtonLeft", 0, theme); + m_MarginButtonBottom = GetPrivateProfileInt(L"Margin", L"ButtonBottom", 4, theme); + m_MarginButtonRight = GetPrivateProfileInt(L"Margin", L"ButtonRight", 0, theme); + m_MarginMeterTop = GetPrivateProfileInt(L"Margin", L"MeterTop", 0, theme); + m_MarginMeterLeft = GetPrivateProfileInt(L"Margin", L"MeterLeft", 0, theme); + m_MarginMeterBottom = GetPrivateProfileInt(L"Margin", L"MeterBottom", 0, theme); + m_MarginMeterRight = GetPrivateProfileInt(L"Margin", L"MeterRight", 4, theme); + m_MarginCommentTop = GetPrivateProfileInt(L"Margin", L"CommentTop", 0, theme); + m_MarginCommentLeft = GetPrivateProfileInt(L"Margin", L"CommentLeft", 8, theme); + m_MarginCommentBottom = GetPrivateProfileInt(L"Margin", L"CommentBottom", 0, theme); + m_MarginCommentRight = GetPrivateProfileInt(L"Margin", L"CommentRight", 8, theme); + m_MarginDemoTop = GetPrivateProfileInt(L"Margin", L"DemoTop", 8, theme); + m_MarginDemoLeft = GetPrivateProfileInt(L"Margin", L"DemoLeft", 8, theme); + m_MarginDemoBottom = GetPrivateProfileInt(L"Margin", L"DemoBottom", 8, theme); + m_MarginDemoRight = GetPrivateProfileInt(L"Margin", L"DemoRight", 8, theme); +#endif +} + + +CDiskMarkDlg::~CDiskMarkDlg() +{ +} + +void CDiskMarkDlg::DoDataExchange(CDataExchange* pDX) +{ + CMainDialogFx::DoDataExchange(pDX); + + DDX_Control(pDX, IDC_BUTTON_ALL, m_ButtonAll); + DDX_Control(pDX, IDC_BUTTON_TEST_0, m_ButtonTest0); + DDX_Control(pDX, IDC_BUTTON_TEST_1, m_ButtonTest1); + DDX_Control(pDX, IDC_BUTTON_TEST_2, m_ButtonTest2); + DDX_Control(pDX, IDC_BUTTON_TEST_3, m_ButtonTest3); + + DDX_Control(pDX, IDC_TEST_READ_0, m_TestRead0); + DDX_Control(pDX, IDC_TEST_READ_1, m_TestRead1); + DDX_Control(pDX, IDC_TEST_READ_2, m_TestRead2); + DDX_Control(pDX, IDC_TEST_READ_3, m_TestRead3); + + DDX_Control(pDX, IDC_TEST_WRITE_0, m_TestWrite0); + DDX_Control(pDX, IDC_TEST_WRITE_1, m_TestWrite1); + DDX_Control(pDX, IDC_TEST_WRITE_2, m_TestWrite2); + DDX_Control(pDX, IDC_TEST_WRITE_3, m_TestWrite3); + +#ifdef MIX_MODE + DDX_Control(pDX, IDC_TEST_MIX_0, m_TestMix0); + DDX_Control(pDX, IDC_TEST_MIX_1, m_TestMix1); + DDX_Control(pDX, IDC_TEST_MIX_2, m_TestMix2); + DDX_Control(pDX, IDC_TEST_MIX_3, m_TestMix3); + DDX_Control(pDX, IDC_COMBO_MIX, m_ComboMix); +#endif + + DDX_Control(pDX, IDC_COMMENT, m_Comment); + + DDX_Control(pDX, IDC_COMBO_COUNT, m_ComboCount); + DDX_Control(pDX, IDC_COMBO_SIZE, m_ComboSize); + DDX_Control(pDX, IDC_COMBO_DRIVE, m_ComboDrive); + DDX_Control(pDX, IDC_COMBO_UNIT, m_ComboUnit); + + DDX_Control(pDX, IDC_DEMO_SETTING, m_DemoSetting); + DDX_Control(pDX, IDC_READ_UNIT, m_ReadUnit); + DDX_Control(pDX, IDC_WRITE_UNIT, m_WriteUnit); + +#ifdef MIX_MODE + DDX_Control(pDX, IDC_MIX_UNIT, m_MixUnit); +#endif + + DDX_Text(pDX, IDC_COMBO_COUNT, m_ValueTestCount); + DDX_Text(pDX, IDC_COMBO_SIZE, m_ValueTestSize); + DDX_Text(pDX, IDC_COMBO_DRIVE, m_ValueTestDrive); + DDX_Text(pDX, IDC_COMBO_UNIT, m_ValueTestUnit); + DDX_CBIndex(pDX, IDC_COMBO_COUNT, m_IndexTestCount); + DDX_CBIndex(pDX, IDC_COMBO_SIZE, m_IndexTestSize); + DDX_CBIndex(pDX, IDC_COMBO_DRIVE, m_IndexTestDrive); + DDX_CBIndex(pDX, IDC_COMBO_UNIT, m_IndexTestUnit); +#ifdef MIX_MODE + DDX_CBIndex(pDX, IDC_COMBO_MIX, m_IndexTestMix); +#endif +} + +BEGIN_MESSAGE_MAP(CDiskMarkDlg, CMainDialogFx) + //}}AFX_MSG_MAP +#ifdef SUISHO_SHIZUKU_SUPPORT + ON_WM_GETMINMAXINFO() + ON_WM_SIZE() +#endif + ON_COMMAND(ID_EXIT, OnExit) + ON_COMMAND(ID_ABOUT, OnAbout) + ON_COMMAND(ID_COPY, OnCopy) + ON_MESSAGE(WM_UPDATE_SCORE, OnUpdateScore) + ON_MESSAGE(WM_UPDATE_MESSAGE, OnUpdateMessage) + ON_MESSAGE(WM_EXIT_BENCHMARK, OnExitBenchmark) + ON_WM_LBUTTONDOWN() + + ON_COMMAND(ID_ZOOM_100, &CDiskMarkDlg::OnZoom100) + ON_COMMAND(ID_ZOOM_125, &CDiskMarkDlg::OnZoom125) + ON_COMMAND(ID_ZOOM_150, &CDiskMarkDlg::OnZoom150) + ON_COMMAND(ID_ZOOM_200, &CDiskMarkDlg::OnZoom200) + ON_COMMAND(ID_ZOOM_250, &CDiskMarkDlg::OnZoom250) + ON_COMMAND(ID_ZOOM_300, &CDiskMarkDlg::OnZoom300) + ON_COMMAND(ID_ZOOM_AUTO, &CDiskMarkDlg::OnZoomAuto) + + ON_COMMAND(ID_HELP, &CDiskMarkDlg::OnHelp) + ON_COMMAND(ID_CRYSTALDEWWORLD, &CDiskMarkDlg::OnCrystalDewWorld) + ON_COMMAND(ID_MODE_DEFAULT, &CDiskMarkDlg::OnModeDefault) + ON_COMMAND(ID_MODE_ALL0X00, &CDiskMarkDlg::OnModeAll0x00) + + ON_COMMAND(ID_SETTING_DEFAULT, &CDiskMarkDlg::OnSettingDefault) + ON_COMMAND(ID_SETTING_NVME_8, &CDiskMarkDlg::OnSettingNVMe8) + ON_COMMAND(ID_SETTING_FLASH_MEMORY, &CDiskMarkDlg::OnSettingFlashMemory) + + ON_COMMAND(ID_PROFILE_DEFAULT, &CDiskMarkDlg::OnProfileDefault) + ON_COMMAND(ID_PROFILE_REAL, &CDiskMarkDlg::OnProfileReal) + ON_COMMAND(ID_PROFILE_PEAK, &CDiskMarkDlg::OnProfilePeak) + ON_COMMAND(ID_PROFILE_DEMO, &CDiskMarkDlg::OnProfileDemo) + +#ifdef MIX_MODE + ON_COMMAND(ID_PROFILE_DEFAULT_MIX, &CDiskMarkDlg::OnProfileDefaultMix) + ON_COMMAND(ID_PROFILE_REAL_MIX, &CDiskMarkDlg::OnProfileRealMix) + ON_COMMAND(ID_PROFILE_PEAK_MIX, &CDiskMarkDlg::OnProfilePeakMix) +#endif + + ON_COMMAND(ID_BENCHMARK_READ_WRITE, &CDiskMarkDlg::OnBenchmarkReadWrite) + ON_COMMAND(ID_BENCHMARK_READ_ONLY, &CDiskMarkDlg::OnBenchmarkReadOnly) + ON_COMMAND(ID_BENCHMARK_WRITE_ONLY, &CDiskMarkDlg::OnBenchmarkWriteOnly) + + //}}AFX_MSG_MAP + ON_COMMAND(ID_SAVE_TEXT, &CDiskMarkDlg::OnSaveText) + ON_COMMAND(ID_SAVE_IMAGE, &CDiskMarkDlg::OnSaveImage) + ON_COMMAND(ID_SETTINGS_QUEUESTHREADS, &CDiskMarkDlg::OnSettingsQueuesThreads) + ON_COMMAND(ID_FONT_SETTING, &CDiskMarkDlg::OnFontSetting) + ON_WM_NCCREATE() + ON_MESSAGE(WM_QUERYENDSESSION, &CDiskMarkDlg::OnQueryEndSession) + + ON_BN_CLICKED(IDC_BUTTON_ALL, &CDiskMarkDlg::OnAll) + ON_BN_CLICKED(IDC_BUTTON_TEST_0, &CDiskMarkDlg::OnTest0) + ON_BN_CLICKED(IDC_BUTTON_TEST_1, &CDiskMarkDlg::OnTest1) + ON_BN_CLICKED(IDC_BUTTON_TEST_2, &CDiskMarkDlg::OnTest2) + ON_BN_CLICKED(IDC_BUTTON_TEST_3, &CDiskMarkDlg::OnTest3) + ON_CBN_SELCHANGE(IDC_COMBO_DRIVE, &CDiskMarkDlg::OnCbnSelchangeComboDrive) + ON_CBN_SELCHANGE(IDC_COMBO_UNIT, &CDiskMarkDlg::OnCbnSelchangeComboUnit) +#ifdef MIX_MODE + ON_CBN_SELCHANGE(IDC_COMBO_MIX, &CDiskMarkDlg::OnCbnSelchangeComboMix) +#endif + +END_MESSAGE_MAP() + +LRESULT CDiskMarkDlg::OnQueryEndSession(WPARAM wParam, LPARAM lParam) +{ + return TRUE; +} + +BOOL CDiskMarkDlg::CheckThemeEdition(CString name) +{ +#ifdef SUISHO_AOI_SUPPORT + if (name.Find(L"Aoi") == 0) { return TRUE; } +#elif MSI_MEI_SUPPORT + if (name.Find(L"MSIMei") == 0) { return TRUE; } +#elif SUISHO_SHIZUKU_SUPPORT + if(name.Find(L"Shizuku") == 0) { return TRUE; } +#elif KUREI_KEI_SUPPORT + if(name.Find(L"KureiKei") == 0) { return TRUE; } +#else + if(name.Find(L"Shizuku") != 0 && name.Find(L"Aoi") != 0 && name.Find(L"MSIMei") != 0 && name.Find(L"Tokka") != 0 && name.Find(L"KureiKei") != 0 && name.Find(L".") != 0) { return TRUE; } +#endif + + return FALSE; +} + +int CALLBACK EnumFontFamExProcDefaultFont(ENUMLOGFONTEX* lpelfe, NEWTEXTMETRICEX* lpntme, int FontType, LPARAM lParam) +{ + if (_tcscmp(lpelfe->elfLogFont.lfFaceName, DEFAULT_FONT_FACE_1) == 0) + { + *((BOOL*)lParam) = TRUE; + } + return TRUE; +} + +BOOL CDiskMarkDlg::IsDefaultMode() +{ + if (m_MeasureTime == 5 + && m_BenchSize[0] == 1024 && m_BenchQueues[0] == 8 && m_BenchThreads[0] == 1 && m_BenchType[0] == BENCH_SEQ + && m_BenchSize[1] == 1024 && m_BenchQueues[1] == 1 && m_BenchThreads[1] == 1 && m_BenchType[1] == BENCH_SEQ + && m_BenchSize[2] == 4 && m_BenchQueues[2] == 32 && m_BenchThreads[2] == 1 && m_BenchType[2] == BENCH_RND + && m_BenchSize[3] == 4 && m_BenchQueues[3] == 1 && m_BenchThreads[3] == 1 && m_BenchType[3] == BENCH_RND + && m_BenchSize[4] == 1024 && m_BenchQueues[4] == 8 && m_BenchThreads[4] == 1 && m_BenchType[4] == BENCH_SEQ + && m_BenchSize[5] == 4 && m_BenchQueues[5] == 32 && m_BenchThreads[5] == 1 && m_BenchType[5] == BENCH_RND + && m_BenchSize[8] == 1024 && m_BenchQueues[8] == 8 && m_BenchThreads[8] == 1 && m_BenchType[8] == BENCH_SEQ + ) + { + return TRUE; + } + return FALSE; +} + +BOOL CDiskMarkDlg::IsNVMe8Mode() +{ + if (m_MeasureTime == 5 + && m_BenchSize[0] == 1024 && m_BenchQueues[0] == 8 && m_BenchThreads[0] == 1 && m_BenchType[0] == BENCH_SEQ + && m_BenchSize[1] == 128 && m_BenchQueues[1] == 32 && m_BenchThreads[1] == 1 && m_BenchType[1] == BENCH_SEQ + && m_BenchSize[2] == 4 && m_BenchQueues[2] == 32 && m_BenchThreads[2] == 16 && m_BenchType[2] == BENCH_RND + && m_BenchSize[3] == 4 && m_BenchQueues[3] == 1 && m_BenchThreads[3] == 1 && m_BenchType[3] == BENCH_RND + && m_BenchSize[4] == 1024 && m_BenchQueues[4] == 8 && m_BenchThreads[4] == 1 && m_BenchType[4] == BENCH_SEQ + && m_BenchSize[5] == 4 && m_BenchQueues[5] == 32 && m_BenchThreads[5] == 16 && m_BenchType[5] == BENCH_RND + && m_BenchSize[8] == 1024 && m_BenchQueues[8] == 8 && m_BenchThreads[8] == 1 && m_BenchType[8] == BENCH_SEQ + ) + { + return TRUE; + } + return FALSE; +} + + +BOOL CDiskMarkDlg::IsFlashMemoryMode() +{ + if (m_MeasureTime == 1 + && m_BenchSize[0] == 1024 && m_BenchQueues[0] == 8 && m_BenchThreads[0] == 1 && m_BenchType[0] == BENCH_SEQ + && m_BenchSize[1] == 1024 && m_BenchQueues[1] == 1 && m_BenchThreads[1] == 1 && m_BenchType[1] == BENCH_SEQ + && m_BenchSize[2] == 4 && m_BenchQueues[2] == 32 && m_BenchThreads[2] == 1 && m_BenchType[2] == BENCH_RND + && m_BenchSize[3] == 4 && m_BenchQueues[3] == 1 && m_BenchThreads[3] == 1 && m_BenchType[3] == BENCH_RND + && m_BenchSize[4] == 1024 && m_BenchQueues[4] == 8 && m_BenchThreads[4] == 1 && m_BenchType[4] == BENCH_SEQ + && m_BenchSize[5] == 4 && m_BenchQueues[5] == 32 && m_BenchThreads[5] == 1 && m_BenchType[5] == BENCH_RND + && m_BenchSize[8] == 1024 && m_BenchQueues[8] == 8 && m_BenchThreads[8] == 1 && m_BenchType[8] == BENCH_SEQ + ) + { + return TRUE; + } + return FALSE; +} + +BOOL CDiskMarkDlg::OnInitDialog() +{ + CMainDialogFx::OnInitDialog(); + + m_hAccelerator = ::LoadAccelerators(AfxGetInstanceHandle(), + MAKEINTRESOURCE(IDR_ACCELERATOR)); + + SetIcon(m_hIcon, TRUE); + SetIcon(m_hIconMini, FALSE); + + TCHAR str[256]; + + CClientDC dc(this); + LOGFONT logfont; + CString defaultFontFace; + BOOL hasDefaultFont = FALSE; + ZeroMemory(&logfont, sizeof(LOGFONT)); + logfont.lfCharSet = DEFAULT_CHARSET; + ::EnumFontFamiliesExW(dc.m_hDC, &logfont, (FONTENUMPROC)EnumFontFamExProcDefaultFont, (INT_PTR)(&hasDefaultFont), 0); + + if (hasDefaultFont) + { + defaultFontFace = DEFAULT_FONT_FACE_1; + } + else + { + defaultFontFace = DEFAULT_FONT_FACE_2; + } + + GetPrivateProfileString(L"Setting", L"FontFace", defaultFontFace, str, 256, m_Ini); + m_FontFace = str; + + m_TestData = GetPrivateProfileInt(L"Setting", L"TestData", TEST_DATA_RANDOM, m_Ini); + if (m_TestData != TEST_DATA_ALL0X00) + { + m_TestData = TEST_DATA_RANDOM; + } + + m_Profile = GetPrivateProfileInt(L"Setting", L"Profile", PROFILE_DEFAULT, m_Ini); + +#ifdef MIX_MODE + if (PROFILE_DEFAULT > m_Profile || m_Profile > PROFILE_REAL_MIX) +#else + if (PROFILE_DEFAULT > m_Profile || m_Profile > PROFILE_DEMO) +#endif + { + m_Profile = PROFILE_DEFAULT; + } + + m_Benchmark = GetPrivateProfileInt(L"Setting", L"Benchmark", BENCHMARK_READ_WRITE, m_Ini); + if (BENCHMARK_READ > m_Benchmark || m_Benchmark > BENCHMARK_READ_WRITE) + { + m_Benchmark = BENCHMARK_READ_WRITE; + } + + if (m_Profile == PROFILE_DEFAULT_MIX || m_Profile == PROFILE_PEAK_MIX || m_Profile == PROFILE_REAL_MIX) + { + m_MixMode = TRUE; + } + else + { + m_MixMode = FALSE; + } + + m_FontScale = GetPrivateProfileInt(L"Setting", L"FontScale", 100, m_Ini); + if (m_FontScale > 200 || m_FontScale < 50) + { + m_FontScale = 100; + m_FontRatio = 1.0; + } + else + { + m_FontRatio = m_FontScale / 100.0; + } + + m_FontRender = GetPrivateProfileInt(L"Setting", L"FontRender", CLEARTYPE_NATURAL_QUALITY, m_Ini); + if (m_FontRender > CLEARTYPE_NATURAL_QUALITY) + { + m_FontRender = CLEARTYPE_NATURAL_QUALITY; + } + + // Unit + m_ComboUnit.AddString(L"MB/s"); + m_ComboUnit.AddString(L"GB/s"); + m_ComboUnit.AddString(L"IOPS"); + m_ComboUnit.AddString(L"μs"); + + // Count + for (int i = 1; i < 10; i++) + { + CString cstr; + cstr.Format(L"%d", i); + m_ComboCount.AddString(cstr); + } + +#ifdef MIX_MODE + // Mix + for (int i = 1; i < 10; i++) + { + CString cstr; + cstr.Format(L"R%d%%/W%d%%", i * 10, 100 - i*10); + m_ComboMix.AddString(cstr); + } +#endif + + m_WinThread = NULL; + m_DiskBenchStatus = FALSE; + + InitThemeLang(); + InitMenu(); + UpdateThemeInfo(); + ChangeLang(m_CurrentLang); + + UpdateQueuesThreads(); + + m_IndexTestCount = GetPrivateProfileInt(L"Setting", L"TestCount", 2, m_Ini); + if (m_IndexTestCount < 0 || m_IndexTestCount >= 9) + { + m_IndexTestCount = 2; // default value is 3. + } + m_ComboCount.SetCurSel(m_IndexTestCount); + + // Size + TCHAR size[13][8] = { L"16MiB", L"32MiB", L"64MiB", L"128MiB", L"256MiB", L"512MiB", L"1GiB", L"2GiB", L"4GiB", L"8GiB", L"16GiB", L"32GiB", L"64GiB" }; + + for (int i = 0; i < 13; i++) + { + CString cstr; + cstr.Format(L"%s", size[i]); + m_ComboSize.AddString(cstr); + } + m_IndexTestSize = GetPrivateProfileInt(L"Setting", L"TestSize", 6, m_Ini); + if (m_IndexTestSize < 0 || m_IndexTestSize > 13) + { + m_IndexTestSize = 6; // default value is 1GiB; + } + m_ComboSize.SetCurSel(m_IndexTestSize); + + m_IndexTestUnit = GetPrivateProfileInt(L"Setting", L"TestUnit", 0, m_Ini); + if (m_IndexTestUnit < 0 || m_IndexTestUnit >= 3) + { + m_IndexTestUnit = 0; + } + m_ComboUnit.SetCurSel(m_IndexTestUnit); + + m_IndexTestMix = GetPrivateProfileInt(L"Setting", L"TestMix", 6, m_Ini); + if (m_IndexTestMix < 0 || m_IndexTestMix > 10) + { + m_IndexTestMix = 6; // default retio is R70W30; + } + m_MixRatio = (9 - m_IndexTestMix) * 10; + +#ifdef MIX_MODE + m_ComboMix.SetCurSel(m_IndexTestMix); +#endif + + UpdateData(FALSE); + + // Drive + InitDrive(); + + InitScore(); + UpdateUnitLabel(); + + switch(GetPrivateProfileInt(L"Setting", L"ZoomType", 0, m_Ini)) + { + case 100: CheckRadioZoomType(ID_ZOOM_100, 100); break; + case 125: CheckRadioZoomType(ID_ZOOM_125, 125); break; + case 150: CheckRadioZoomType(ID_ZOOM_150, 150); break; + case 200: CheckRadioZoomType(ID_ZOOM_200, 200); break; + case 250: CheckRadioZoomType(ID_ZOOM_250, 250); break; + case 300: CheckRadioZoomType(ID_ZOOM_300, 300); break; + default: CheckRadioZoomType(ID_ZOOM_AUTO, 0); break; + } + + ChangeZoomType(m_ZoomType); + + m_SizeX = SIZE_X; + m_SizeY = SIZE_Y; + +#ifdef MIX_MODE + if (m_MixMode) + { + m_SizeX = SIZE_X_MIX; + } +#endif + + SetWindowTitle(L""); + + SetClientSize(m_SizeX, m_SizeY, m_ZoomRatio); + + m_bShowWindow = TRUE; + + CenterWindow(); + + UpdateDialogSize(); + ChangeButtonStatus(TRUE); + + m_bInitializing = FALSE; + + SetForegroundWindow(); + + return TRUE; +} + +void CDiskMarkDlg::UpdateDialogSize() +{ + CDialogFx::UpdateDialogSize(); + m_bHighContrast = FALSE; + + ShowWindow(SW_HIDE); + int offsetX = 0; + int comboDriveX = 0; + + m_SizeX = SIZE_X; + m_SizeY = SIZE_Y; +#ifdef MIX_MODE + if (m_MixMode) + { + m_SizeX = SIZE_X_MIX; + } +#endif + SetClientSize(m_SizeX, m_SizeY, m_ZoomRatio); + +#ifdef SUISHO_SHIZUKU_SUPPORT + if (m_CharacterPosition == 0) + { + offsetX = OFFSET_X; + } +#endif + + UpdateBackground(TRUE, m_bDarkMode); + SetControlFont(); + + if (m_Profile != PROFILE_DEFAULT && m_Profile != PROFILE_DEFAULT_MIX) + { +#ifdef SUISHO_SHIZUKU_SUPPORT + comboDriveX = 120; +#else + comboDriveX = 72; +#endif + } + else + { + comboDriveX = 0; + } + + m_TestRead0.SetDrawFrame(m_bHighContrast); + m_TestRead1.SetDrawFrame(m_bHighContrast); + m_TestRead2.SetDrawFrame(m_bHighContrast); + m_TestRead3.SetDrawFrame(m_bHighContrast); + m_TestWrite0.SetDrawFrame(m_bHighContrast); + m_TestWrite1.SetDrawFrame(m_bHighContrast); + m_TestWrite2.SetDrawFrame(m_bHighContrast); + m_TestWrite3.SetDrawFrame(m_bHighContrast); + m_Comment.SetDrawFrame(m_bHighContrast); + +#ifdef MIX_MODE + m_TestMix0.SetDrawFrame(m_bHighContrast); + m_TestMix1.SetDrawFrame(m_bHighContrast); + m_TestMix2.SetDrawFrame(m_bHighContrast); + m_TestMix3.SetDrawFrame(m_bHighContrast); +#endif + + if (m_Profile == PROFILE_DEMO) + { + m_ReadUnit.ShowWindow(SW_HIDE); + m_WriteUnit.ShowWindow(SW_HIDE); + + m_TestRead1.ShowWindow(SW_HIDE); + m_TestRead2.ShowWindow(SW_HIDE); + m_TestRead3.ShowWindow(SW_HIDE); + m_TestWrite1.ShowWindow(SW_HIDE); + m_TestWrite2.ShowWindow(SW_HIDE); + m_TestWrite3.ShowWindow(SW_HIDE); + + m_DemoSetting.ShowWindow(SW_SHOW); + } + else + { + m_ReadUnit.ShowWindow(SW_SHOW); + m_WriteUnit.ShowWindow(SW_SHOW); + + m_TestRead1.ShowWindow(SW_SHOW); + m_TestRead2.ShowWindow(SW_SHOW); + m_TestRead3.ShowWindow(SW_SHOW); + m_TestWrite1.ShowWindow(SW_SHOW); + m_TestWrite2.ShowWindow(SW_SHOW); + m_TestWrite3.ShowWindow(SW_SHOW); + + m_DemoSetting.ShowWindow(SW_HIDE); + } + + if (m_Profile == PROFILE_DEMO) + { +#ifdef SUISHO_SHIZUKU_SUPPORT + m_ButtonAll.InitControl(12 + offsetX, 8, 120, 80, m_ZoomRatio, m_hPal, &m_BkDC, IP(L"Button"), 3, BS_CENTER, OwnerDrawImage, m_bHighContrast, FALSE, FALSE); + m_ButtonAll.SetHandCursor(TRUE); +/* + m_TestRead0.SetGlassColor(m_Glass, m_GlassAlpha); + m_TestWrite0.SetGlassColor(m_Glass, m_GlassAlpha); + + m_TestRead0.InitControl(12 + offsetX, 96, 384, 348, m_ZoomRatio, &m_BkDC, NULL, 0, SS_CENTER, OwnerDrawGlass, m_bHighContrast, FALSE); + m_TestWrite0.InitControl(404 + offsetX, 96, 384, 348, m_ZoomRatio, &m_BkDC, NULL, 0, SS_CENTER, OwnerDrawGlass, m_bHighContrast, FALSE); +*/ +#ifdef SUISHO_AOI_SUPPORT + m_TestRead0.InitControl(12 + offsetX, 96, 384, 344, m_ZoomRatio, m_hPal, &m_BkDC, IP(L"Demo"), 1, SS_CENTER, OwnerDrawImage, FALSE, FALSE, FALSE); + m_TestWrite0.InitControl(404 + offsetX, 96, 384, 344, m_ZoomRatio, m_hPal, &m_BkDC, IP(L"Demo"), 1, SS_CENTER, OwnerDrawImage, FALSE, FALSE, FALSE); + m_Comment.InitControl(12 + offsetX, 440, 776, 60, m_ZoomRatio, &m_BkDC, IP(L"Comment"), 1, ES_LEFT, OwnerDrawImage, m_bHighContrast, FALSE, FALSE); +#else + m_TestRead0.InitControl(12 + offsetX, 96, 384, 348, m_ZoomRatio, m_hPal, &m_BkDC, IP(L"Demo"), 1, SS_CENTER, OwnerDrawImage, FALSE, FALSE, FALSE); + m_TestWrite0.InitControl(404 + offsetX, 96, 384, 348, m_ZoomRatio, m_hPal, &m_BkDC, IP(L"Demo"), 1, SS_CENTER, OwnerDrawImage, FALSE, FALSE, FALSE); + m_Comment.InitControl(12 + offsetX, 452, 776, 40, m_ZoomRatio, &m_BkDC, IP(L"Comment"), 1, ES_LEFT, OwnerDrawImage, m_bHighContrast, FALSE, FALSE); +#endif + m_Comment.SetMargin(m_MarginCommentTop, m_MarginCommentLeft, m_MarginCommentBottom, m_MarginCommentRight, m_ZoomRatio); + m_Comment.Adjust(); + + m_DemoSetting.InitControl(140 + offsetX, 56, 528, 40, m_ZoomRatio, m_hPal, &m_BkDC, NULL, 0, SS_CENTER, OwnerDrawTransparent, m_bHighContrast, FALSE, FALSE); + m_ReadUnit.InitControl(12 + offsetX, 96, 120, 32, m_ZoomRatio, m_hPal, &m_BkDC, NULL, 0, SS_CENTER, OwnerDrawTransparent, m_bHighContrast, FALSE, FALSE); + m_WriteUnit.InitControl(672 + offsetX, 96, 116, 32, m_ZoomRatio, m_hPal, &m_BkDC, NULL, 0, SS_CENTER, OwnerDrawTransparent, m_bHighContrast, FALSE, FALSE); + + m_ComboCount.InitControl(140 + offsetX, 8, 60, 500, m_ZoomRatio, &m_BkDC, NULL, 0, ES_LEFT, OwnerDrawGlass, m_bHighContrast, FALSE, m_ComboBk, m_ComboBkSelected, m_Glass, m_GlassAlpha); + m_ComboSize.InitControl(204 + offsetX, 8, 140, 500, m_ZoomRatio, &m_BkDC, NULL, 0, ES_LEFT, OwnerDrawGlass, m_bHighContrast, FALSE, m_ComboBk, m_ComboBkSelected, m_Glass, m_GlassAlpha); + m_ComboDrive.InitControl(348 + offsetX, 8, 320, 500, m_ZoomRatio, &m_BkDC, NULL, 0, ES_LEFT, OwnerDrawGlass, m_bHighContrast, FALSE, m_ComboBk, m_ComboBkSelected, m_Glass, m_GlassAlpha); + m_ComboUnit.InitControl(672 + offsetX, 8, 116, 500, m_ZoomRatio, &m_BkDC, NULL, 0, ES_LEFT, OwnerDrawGlass, m_bHighContrast, FALSE, m_ComboBk, m_ComboBkSelected, m_Glass, m_GlassAlpha); +#else + m_TestRead0.SetDrawFrameEx(TRUE, m_Frame); + m_TestWrite0.SetDrawFrameEx(TRUE, m_Frame); + + m_ButtonAll.InitControl(8 + offsetX, 8, 72, 48, m_ZoomRatio, m_hPal, &m_BkDC, IP(L"Button"), 3, BS_CENTER, OwnerDrawImage, m_bHighContrast, FALSE, FALSE); + m_ButtonAll.SetHandCursor(TRUE); + + m_TestRead0.SetGlassColor(m_Glass, m_GlassAlpha); + m_TestWrite0.SetGlassColor(m_Glass, m_GlassAlpha); + + m_TestRead0.InitControl(8 + offsetX, 64, 228, 196, m_ZoomRatio, m_hPal, &m_BkDC, NULL, 0, SS_CENTER, OwnerDrawGlass, m_bHighContrast, TRUE, FALSE); + m_TestWrite0.InitControl(244 + offsetX, 64, 228, 196, m_ZoomRatio, m_hPal, &m_BkDC, NULL, 0, SS_CENTER, OwnerDrawGlass, m_bHighContrast, TRUE, FALSE); + + m_Comment.InitControl(8 + offsetX, 268, 464, 24, m_ZoomRatio, &m_BkDC, IP(L"Comment"), 1, ES_LEFT, OwnerDrawImage, m_bHighContrast, FALSE, FALSE); + m_Comment.SetMargin(m_MarginCommentTop, m_MarginCommentLeft, m_MarginCommentBottom, m_MarginCommentRight, m_ZoomRatio); + m_Comment.Adjust(); + + m_DemoSetting.InitControl(84 + offsetX, 36, 320, 24, m_ZoomRatio, m_hPal, &m_BkDC, NULL, 0, SS_CENTER, OwnerDrawTransparent, m_bHighContrast, FALSE, FALSE); + m_ReadUnit.InitControl(84 + offsetX, 36, 124, 24, m_ZoomRatio, m_hPal, &m_BkDC, NULL, 0, SS_CENTER, OwnerDrawTransparent, m_bHighContrast, FALSE, FALSE); + m_WriteUnit.InitControl(280 + offsetX, 36, 124, 24, m_ZoomRatio, m_hPal, &m_BkDC, NULL, 0, SS_CENTER, OwnerDrawTransparent, m_bHighContrast, FALSE, FALSE); + + m_ComboCount.InitControl(84 + offsetX, 8, 40, 300, m_ZoomRatio, &m_BkDC, NULL, 0, ES_LEFT, OwnerDrawGlass, m_bHighContrast, FALSE, m_ComboBk, m_ComboBkSelected, m_Glass, m_GlassAlpha); + m_ComboSize.InitControl(128 + offsetX, 8, 80, 300, m_ZoomRatio, &m_BkDC, NULL, 0, ES_LEFT, OwnerDrawGlass, m_bHighContrast, FALSE, m_ComboBk, m_ComboBkSelected, m_Glass, m_GlassAlpha); + m_ComboDrive.InitControl(212 + offsetX, 8, 188, 300, m_ZoomRatio, &m_BkDC, NULL, 0, ES_LEFT, OwnerDrawGlass, m_bHighContrast, FALSE, m_ComboBk, m_ComboBkSelected, m_Glass, m_GlassAlpha); + m_ComboUnit.InitControl(404 + offsetX, 8, 68, 300, m_ZoomRatio, &m_BkDC, NULL, 0, ES_LEFT, OwnerDrawGlass, m_bHighContrast, FALSE, m_ComboBk, m_ComboBkSelected, m_Glass, m_GlassAlpha); +#endif + } + else + { +#ifdef SUISHO_SHIZUKU_SUPPORT + m_ButtonAll.InitControl(12 + offsetX, 8, 120, 80, m_ZoomRatio, m_hPal, &m_BkDC, IP(L"Button"), 3, BS_CENTER, OwnerDrawImage, m_bHighContrast, FALSE, FALSE); + m_ButtonTest0.InitControl(12 + offsetX, 96, 120, 80, m_ZoomRatio, m_hPal, &m_BkDC, IP(L"Button"), 3, BS_CENTER, OwnerDrawImage, m_bHighContrast, FALSE, FALSE); + m_ButtonTest1.InitControl(12 + offsetX, 184, 120, 80, m_ZoomRatio, m_hPal, &m_BkDC, IP(L"Button"), 3, BS_CENTER, OwnerDrawImage, m_bHighContrast, FALSE, FALSE); + m_ButtonTest2.InitControl(12 + offsetX, 272, 120, 80, m_ZoomRatio, m_hPal, &m_BkDC, IP(L"Button"), 3, BS_CENTER, OwnerDrawImage, m_bHighContrast, FALSE, FALSE); + m_ButtonTest3.InitControl(12 + offsetX, 360, 120, 80, m_ZoomRatio, m_hPal, &m_BkDC, IP(L"Button"), 3, BS_CENTER, OwnerDrawImage, m_bHighContrast, FALSE, FALSE); + + m_ButtonAll.SetHandCursor(TRUE); + m_ButtonTest0.SetHandCursor(TRUE); + m_ButtonTest1.SetHandCursor(TRUE); + m_ButtonTest2.SetHandCursor(TRUE); + m_ButtonTest3.SetHandCursor(TRUE); + + m_TestRead0.InitControl(140 + offsetX, 96, 320, 80, m_ZoomRatio, m_hPal, &m_BkDC, IP(L"Meter"), 2, SS_RIGHT, OwnerDrawImage, m_bHighContrast, FALSE, FALSE); + m_TestRead1.InitControl(140 + offsetX, 184, 320, 80, m_ZoomRatio, m_hPal, &m_BkDC, IP(L"Meter"), 2, SS_RIGHT, OwnerDrawImage, m_bHighContrast, FALSE, FALSE); + m_TestRead2.InitControl(140 + offsetX, 272, 320, 80, m_ZoomRatio, m_hPal, &m_BkDC, IP(L"Meter"), 2, SS_RIGHT, OwnerDrawImage, m_bHighContrast, FALSE, FALSE); + m_TestRead3.InitControl(140 + offsetX, 360, 320, 80, m_ZoomRatio, m_hPal, &m_BkDC, IP(L"Meter"), 2, SS_RIGHT, OwnerDrawImage, m_bHighContrast, FALSE, FALSE); + + m_TestWrite0.InitControl(468 + offsetX, 96, 320, 80, m_ZoomRatio, m_hPal, &m_BkDC, IP(L"Meter"), 2, SS_RIGHT, OwnerDrawImage, m_bHighContrast, FALSE, FALSE); + m_TestWrite1.InitControl(468 + offsetX, 184, 320, 80, m_ZoomRatio, m_hPal, &m_BkDC, IP(L"Meter"), 2, SS_RIGHT, OwnerDrawImage, m_bHighContrast, FALSE, FALSE); + m_TestWrite2.InitControl(468 + offsetX, 272, 320, 80, m_ZoomRatio, m_hPal, &m_BkDC, IP(L"Meter"), 2, SS_RIGHT, OwnerDrawImage, m_bHighContrast, FALSE, FALSE); + m_TestWrite3.InitControl(468 + offsetX, 360, 320, 80, m_ZoomRatio, m_hPal, &m_BkDC, IP(L"Meter"), 2, SS_RIGHT, OwnerDrawImage, m_bHighContrast, FALSE, FALSE); + +#ifdef SUISHO_AOI_SUPPORT + m_Comment.InitControl(12 + offsetX, 440, 776, 60, m_ZoomRatio, &m_BkDC, IP(L"Comment"), 1, ES_LEFT, OwnerDrawImage, m_bHighContrast, FALSE, FALSE); +#else + m_Comment.InitControl(12 + offsetX, 452, 776, 40, m_ZoomRatio, &m_BkDC, IP(L"Comment"), 1, ES_LEFT, OwnerDrawImage, m_bHighContrast, FALSE, FALSE); +#endif + + m_Comment.SetMargin(m_MarginCommentTop, m_MarginCommentLeft, m_MarginCommentBottom, m_MarginCommentRight, m_ZoomRatio); + m_Comment.Adjust(); + + m_ReadUnit.InitControl(140 + offsetX, 56, 320, 40, m_ZoomRatio, m_hPal, &m_BkDC, NULL, 0, SS_CENTER, OwnerDrawTransparent, m_bHighContrast, FALSE, FALSE); + m_WriteUnit.InitControl(468 + offsetX, 56, 320, 40, m_ZoomRatio, m_hPal, &m_BkDC, NULL, 0, SS_CENTER, OwnerDrawTransparent, m_bHighContrast, FALSE, FALSE); + + m_ComboCount.InitControl(140 + offsetX, 8, 60, 500, m_ZoomRatio, &m_BkDC, NULL, 0, ES_LEFT, OwnerDrawGlass, m_bHighContrast, FALSE, m_ComboBk, m_ComboBkSelected, m_Glass, m_GlassAlpha); + m_ComboSize.InitControl(204 + offsetX, 8, 140, 500, m_ZoomRatio, &m_BkDC, NULL, 0, ES_LEFT, OwnerDrawGlass, m_bHighContrast, FALSE, m_ComboBk, m_ComboBkSelected, m_Glass, m_GlassAlpha); + m_ComboUnit.InitControl(672 + offsetX, 8, 116, 500, m_ZoomRatio, &m_BkDC, NULL, 0, ES_LEFT, OwnerDrawGlass, m_bHighContrast, FALSE, m_ComboBk, m_ComboBkSelected, m_Glass, m_GlassAlpha); + + if (m_Profile == PROFILE_PEAK || m_Profile == PROFILE_REAL) + { + m_ComboDrive.InitControl(348 + offsetX, 8, 440, 500, m_ZoomRatio, &m_BkDC, NULL, 0, ES_LEFT, OwnerDrawGlass, m_bHighContrast, FALSE, m_ComboBk, m_ComboBkSelected, m_Glass, m_GlassAlpha); + } + else + { + m_ComboDrive.InitControl(348 + offsetX, 8, 320, 500, m_ZoomRatio, &m_BkDC, NULL, 0, ES_LEFT, OwnerDrawGlass, m_bHighContrast, FALSE, m_ComboBk, m_ComboBkSelected, m_Glass, m_GlassAlpha); + } +#else + + m_ButtonAll.InitControl(8 + offsetX, 8, 72, 48, m_ZoomRatio, m_hPal, &m_BkDC, IP(L"Button"), 3, BS_CENTER, OwnerDrawImage, m_bHighContrast, FALSE, FALSE); + m_ButtonTest0.InitControl(8 + offsetX, 60, 72, 48, m_ZoomRatio, m_hPal, &m_BkDC, IP(L"Button"), 3, BS_CENTER, OwnerDrawImage, m_bHighContrast, FALSE, FALSE); + m_ButtonTest1.InitControl(8 + offsetX, 112, 72, 48, m_ZoomRatio, m_hPal, &m_BkDC, IP(L"Button"), 3, BS_CENTER, OwnerDrawImage, m_bHighContrast, FALSE, FALSE); + m_ButtonTest2.InitControl(8 + offsetX, 164, 72, 48, m_ZoomRatio, m_hPal, &m_BkDC, IP(L"Button"), 3, BS_CENTER, OwnerDrawImage, m_bHighContrast, FALSE, FALSE); + m_ButtonTest3.InitControl(8 + offsetX, 216, 72, 48, m_ZoomRatio, m_hPal, &m_BkDC, IP(L"Button"), 3, BS_CENTER, OwnerDrawImage, m_bHighContrast, FALSE, FALSE); + + m_ButtonAll.SetHandCursor(TRUE); + m_ButtonTest0.SetHandCursor(TRUE); + m_ButtonTest1.SetHandCursor(TRUE); + m_ButtonTest2.SetHandCursor(TRUE); + m_ButtonTest3.SetHandCursor(TRUE); + + m_TestRead0.InitControl(84 + offsetX, 60, 192, 48, m_ZoomRatio, m_hPal, &m_BkDC, IP(L"Meter"), 2, SS_RIGHT, OwnerDrawImage, m_bHighContrast, FALSE, FALSE); + m_TestRead1.InitControl(84 + offsetX, 112, 192, 48, m_ZoomRatio, m_hPal, &m_BkDC, IP(L"Meter"), 2, SS_RIGHT, OwnerDrawImage, m_bHighContrast, FALSE, FALSE); + m_TestRead2.InitControl(84 + offsetX, 164, 192, 48, m_ZoomRatio, m_hPal, &m_BkDC, IP(L"Meter"), 2, SS_RIGHT, OwnerDrawImage, m_bHighContrast, FALSE, FALSE); + m_TestRead3.InitControl(84 + offsetX, 216, 192, 48, m_ZoomRatio, m_hPal, &m_BkDC, IP(L"Meter"), 2, SS_RIGHT, OwnerDrawImage, m_bHighContrast, FALSE, FALSE); + + m_TestWrite0.InitControl(280 + offsetX, 60, 192, 48, m_ZoomRatio, m_hPal, &m_BkDC, IP(L"Meter"), 2, SS_RIGHT, OwnerDrawImage, m_bHighContrast, FALSE, FALSE); + m_TestWrite1.InitControl(280 + offsetX, 112, 192, 48, m_ZoomRatio, m_hPal, &m_BkDC, IP(L"Meter"), 2, SS_RIGHT, OwnerDrawImage, m_bHighContrast, FALSE, FALSE); + m_TestWrite2.InitControl(280 + offsetX, 164, 192, 48, m_ZoomRatio, m_hPal, &m_BkDC, IP(L"Meter"), 2, SS_RIGHT, OwnerDrawImage, m_bHighContrast, FALSE, FALSE); + m_TestWrite3.InitControl(280 + offsetX, 216, 192, 48, m_ZoomRatio, m_hPal, &m_BkDC, IP(L"Meter"), 2, SS_RIGHT, OwnerDrawImage, m_bHighContrast, FALSE, FALSE); + if (m_MixMode) + { + m_Comment.InitControl(8 + offsetX, 268, 664, 24, m_ZoomRatio, &m_BkDC, IP(L"CommentL"), 1, ES_LEFT, OwnerDrawImage, m_bHighContrast, FALSE, FALSE); + } + else + { + m_Comment.InitControl(8 + offsetX, 268, 464, 24, m_ZoomRatio, &m_BkDC, IP(L"Comment"), 1, ES_LEFT, OwnerDrawImage, m_bHighContrast, FALSE, FALSE); + } + m_Comment.SetMargin(m_MarginCommentTop, m_MarginCommentLeft, m_MarginCommentBottom, m_MarginCommentRight, m_ZoomRatio); + m_Comment.Adjust(); + + m_ReadUnit.InitControl(84 + offsetX, 36, 192, 24, m_ZoomRatio, m_hPal, &m_BkDC, NULL, 0, SS_CENTER, OwnerDrawTransparent, m_bHighContrast, FALSE, FALSE); + m_WriteUnit.InitControl(280 + offsetX, 36, 192, 24, m_ZoomRatio, m_hPal, &m_BkDC, NULL, 0, SS_CENTER, OwnerDrawTransparent, m_bHighContrast, FALSE, FALSE); + + m_ComboCount.InitControl(84 + offsetX, 8, 40, 300, m_ZoomRatio, &m_BkDC, NULL, 0, ES_LEFT, OwnerDrawGlass, m_bHighContrast, FALSE, m_ComboBk, m_ComboBkSelected, m_Glass, m_GlassAlpha); + m_ComboSize.InitControl(128 + offsetX, 8, 80, 300, m_ZoomRatio, &m_BkDC, NULL, 0, ES_LEFT, OwnerDrawGlass, m_bHighContrast, FALSE, m_ComboBk, m_ComboBkSelected, m_Glass, m_GlassAlpha); + m_ComboUnit.InitControl(404 + offsetX, 8, 68, 300, m_ZoomRatio, &m_BkDC, NULL, 0, ES_LEFT, OwnerDrawGlass, m_bHighContrast, FALSE, m_ComboBk, m_ComboBkSelected, m_Glass, m_GlassAlpha); + + if (m_Profile == PROFILE_PEAK || m_Profile == PROFILE_REAL || m_Profile == PROFILE_PEAK_MIX || m_Profile == PROFILE_REAL_MIX) + { + m_ComboDrive.InitControl(212 + offsetX, 8, 260, 300, m_ZoomRatio, &m_BkDC, NULL, 0, ES_LEFT, OwnerDrawGlass, m_bHighContrast, FALSE, m_ComboBk, m_ComboBkSelected, m_Glass, m_GlassAlpha); + } + else + { + m_ComboDrive.InitControl(212 + offsetX, 8, 188, 300, m_ZoomRatio, &m_BkDC, NULL, 0, ES_LEFT, OwnerDrawGlass, m_bHighContrast, FALSE, m_ComboBk, m_ComboBkSelected, m_Glass, m_GlassAlpha); + } +#endif + } + + if(m_Profile == PROFILE_DEMO) + { + m_TestRead0.SetMargin(m_MarginDemoTop, m_MarginDemoLeft, m_MarginDemoBottom, m_MarginDemoRight, m_ZoomRatio); + m_TestWrite0.SetMargin(m_MarginDemoTop, m_MarginDemoLeft, m_MarginDemoBottom, m_MarginDemoRight, m_ZoomRatio); + +#ifdef SUISHO_AOI_SUPPORT + m_TestRead0.SetLabelUnitFormat(DT_LEFT | DT_BOTTOM | DT_SINGLELINE, DT_RIGHT | DT_BOTTOM | DT_SINGLELINE); + m_TestWrite0.SetLabelUnitFormat(DT_LEFT | DT_BOTTOM | DT_SINGLELINE, DT_RIGHT | DT_BOTTOM | DT_SINGLELINE); +#endif + } + else + { + m_TestRead0.SetMargin(m_MarginMeterTop, m_MarginMeterLeft, m_MarginMeterBottom, m_MarginMeterRight, m_ZoomRatio); + m_TestRead1.SetMargin(m_MarginMeterTop, m_MarginMeterLeft, m_MarginMeterBottom, m_MarginMeterRight, m_ZoomRatio); + m_TestRead2.SetMargin(m_MarginMeterTop, m_MarginMeterLeft, m_MarginMeterBottom, m_MarginMeterRight, m_ZoomRatio); + m_TestRead3.SetMargin(m_MarginMeterTop, m_MarginMeterLeft, m_MarginMeterBottom, m_MarginMeterRight, m_ZoomRatio); + + m_TestWrite0.SetMargin(m_MarginMeterTop, m_MarginMeterLeft, m_MarginMeterBottom, m_MarginMeterRight, m_ZoomRatio); + m_TestWrite1.SetMargin(m_MarginMeterTop, m_MarginMeterLeft, m_MarginMeterBottom, m_MarginMeterRight, m_ZoomRatio); + m_TestWrite2.SetMargin(m_MarginMeterTop, m_MarginMeterLeft, m_MarginMeterBottom, m_MarginMeterRight, m_ZoomRatio); + m_TestWrite3.SetMargin(m_MarginMeterTop, m_MarginMeterLeft, m_MarginMeterBottom, m_MarginMeterRight, m_ZoomRatio); + } + + m_ComboCount.SetMargin(0, 4, 0, 0, m_ZoomRatio); + m_ComboSize.SetMargin (0, 4, 0, 0, m_ZoomRatio); + m_ComboDrive.SetMargin(0, 4, 0, 0, m_ZoomRatio); + m_ComboUnit.SetMargin (0, 4, 0, 0, m_ZoomRatio); + +#ifdef MIX_MODE + m_TestMix0.InitControl(480 + offsetX, 60, 192, 48, m_ZoomRatio, m_hPal, &m_BkDC, IP(L"Meter"), 2, SS_RIGHT, OwnerDrawImage, m_bHighContrast, FALSE, FALSE); + m_TestMix1.InitControl(480 + offsetX, 112, 192, 48, m_ZoomRatio, m_hPal, &m_BkDC, IP(L"Meter"), 2, SS_RIGHT, OwnerDrawImage, m_bHighContrast, FALSE, FALSE); + m_TestMix2.InitControl(480 + offsetX, 164, 192, 48, m_ZoomRatio, m_hPal, &m_BkDC, IP(L"Meter"), 2, SS_RIGHT, OwnerDrawImage, m_bHighContrast, FALSE, FALSE); + m_TestMix3.InitControl(480 + offsetX, 216, 192, 48, m_ZoomRatio, m_hPal, &m_BkDC, IP(L"Meter"), 2, SS_RIGHT, OwnerDrawImage, m_bHighContrast, FALSE, FALSE); + m_ComboMix.InitControl(480 + offsetX, 8, 192, 300, m_ZoomRatio, &m_BkDC, NULL, 0, ES_LEFT, OwnerDrawGlass, m_bHighContrast, FALSE, m_ComboBk, m_ComboBkSelected, m_Glass, m_GlassAlpha); + m_MixUnit.InitControl(480 + offsetX, 36, 192, 24, m_ZoomRatio, m_hPal, &m_BkDC, NULL, 0, SS_CENTER, OwnerDrawTransparent, m_bHighContrast, FALSE, FALSE); + + m_TestMix0.SetMargin(m_MarginMeterTop, m_MarginMeterLeft, m_MarginMeterBottom, m_MarginMeterRight, m_ZoomRatio); + m_TestMix1.SetMargin(m_MarginMeterTop, m_MarginMeterLeft, m_MarginMeterBottom, m_MarginMeterRight, m_ZoomRatio); + m_TestMix2.SetMargin(m_MarginMeterTop, m_MarginMeterLeft, m_MarginMeterBottom, m_MarginMeterRight, m_ZoomRatio); + m_TestMix3.SetMargin(m_MarginMeterTop, m_MarginMeterLeft, m_MarginMeterBottom, m_MarginMeterRight, m_ZoomRatio); + m_ComboMix.SetMargin(0, 4, 0, 0, m_ZoomRatio); + + if (m_MixMode) + { + m_TestMix0.ShowWindow(SW_SHOW); + m_TestMix1.ShowWindow(SW_SHOW); + m_TestMix2.ShowWindow(SW_SHOW); + m_TestMix3.ShowWindow(SW_SHOW); + m_ComboMix.ShowWindow(SW_SHOW); + m_MixUnit.ShowWindow(SW_SHOW); + } + else + { + m_TestMix0.ShowWindow(SW_HIDE); + m_TestMix1.ShowWindow(SW_HIDE); + m_TestMix2.ShowWindow(SW_HIDE); + m_TestMix3.ShowWindow(SW_HIDE); + m_ComboMix.ShowWindow(SW_HIDE); + m_MixUnit.ShowWindow(SW_HIDE); + } +#endif + + m_Comment.Adjust(); + + UpdateScore(); + + Invalidate(); + + m_ComboCount.ShowWindow(SW_HIDE); + m_ComboSize.ShowWindow(SW_HIDE); + m_ComboDrive.ShowWindow(SW_HIDE); + + COMBOBOXINFO info = { 0 }; + info.cbSize = sizeof(COMBOBOXINFO); + m_ComboCount.GetComboBoxInfo(&info); + SetLayeredWindow(info.hwndList, m_ComboAlpha); + m_ComboSize.GetComboBoxInfo(&info); + SetLayeredWindow(info.hwndList, m_ComboAlpha); + m_ComboDrive.GetComboBoxInfo(&info); + SetLayeredWindow(info.hwndList, m_ComboAlpha); + m_ComboUnit.GetComboBoxInfo(&info); + SetLayeredWindow(info.hwndList, m_ComboAlpha); +#ifdef MIX_MODE + if (m_MixMode) + { + m_ComboMix.GetComboBoxInfo(&info); + SetLayeredWindow(info.hwndList, m_ComboAlpha); + m_ComboMix.ShowWindow(SW_SHOW); + } +#endif + + m_ComboCount.ShowWindow(SW_SHOW); + m_ComboSize.ShowWindow(SW_SHOW); + m_ComboDrive.ShowWindow(SW_SHOW); + + if (m_Profile != PROFILE_DEFAULT && m_Profile != PROFILE_DEFAULT_MIX && m_Profile != PROFILE_DEMO) + { + m_ComboUnit.ShowWindow(SW_HIDE); + } + else + { + m_ComboUnit.ShowWindow(SW_SHOW); + } + + UpdateComboTooltip(); + + ShowWindow(SW_SHOW); +} + +void CDiskMarkDlg::UpdateComboTooltip() +{ + m_ComboCount.SetToolTipText(i18n(L"Title", L"TEST_COUNT")); + m_ComboSize.SetToolTipText(i18n(L"Title", L"TEST_SIZE")); + m_ComboUnit.SetToolTipText(i18n(L"Title", L"TEST_UNIT")); +#ifdef MIX_MODE + if (m_MixMode) + { + m_ComboMix.SetToolTipText(i18n(L"Title", L"TEST_MIX")); + } +#endif +} + +void CDiskMarkDlg::SetLayeredWindow(HWND hWnd, BYTE alpha) +{ + if (IsWin2k()) { return; } + + ::SetWindowLong(hWnd, GWL_EXSTYLE, ::GetWindowLong(hWnd, GWL_EXSTYLE) ^ WS_EX_LAYERED); + ::SetWindowLong(hWnd, GWL_EXSTYLE, ::GetWindowLong(hWnd, GWL_EXSTYLE) | WS_EX_LAYERED); + if (m_bHighContrast) + { + ::SetLayeredWindowAttributes(hWnd, 0, 255, LWA_ALPHA); + } + else + { + ::SetLayeredWindowAttributes(hWnd, 0, alpha, LWA_ALPHA); + } +} + + +void CDiskMarkDlg::SetControlFont() +{ +#ifdef SUISHO_SHIZUKU_SUPPORT + BYTE textAlpha = 255; + COLORREF textColor = RGB(0, 0, 0); +#else + BYTE textAlpha = 255; + COLORREF textColor = RGB(0, 0, 0); +#endif + +#ifdef SUISHO_SHIZUKU_SUPPORT + m_ButtonAll.SetFontEx(m_FontFace, 20, 20, m_ZoomRatio, m_FontRatio, m_ButtonText, FW_BOLD, m_FontRender); + m_ButtonTest0.SetFontEx(m_FontFace, 20, 20, m_ZoomRatio, m_FontRatio, m_ButtonText, FW_BOLD, m_FontRender); + m_ButtonTest1.SetFontEx(m_FontFace, 20, 20, m_ZoomRatio, m_FontRatio, m_ButtonText, FW_BOLD, m_FontRender); + m_ButtonTest2.SetFontEx(m_FontFace, 20, 20, m_ZoomRatio, m_FontRatio, m_ButtonText, FW_BOLD, m_FontRender); + m_ButtonTest3.SetFontEx(m_FontFace, 20, 20, m_ZoomRatio, m_FontRatio, m_ButtonText, FW_BOLD, m_FontRender); + + if (m_Profile == PROFILE_DEMO) + { + m_TestRead0.SetFontEx(m_FontFace, 80, 28, m_ZoomRatio, m_FontRatio, m_MeterText, FW_BOLD, m_FontRender); + m_TestWrite0.SetFontEx(m_FontFace,80, 28, m_ZoomRatio, m_FontRatio, m_MeterText, FW_BOLD, m_FontRender); + } + else + { + m_TestRead0.SetFontEx(m_FontFace, 52, 28, m_ZoomRatio, m_FontRatio, m_MeterText, FW_BOLD, m_FontRender); + m_TestWrite0.SetFontEx(m_FontFace, 52, 28, m_ZoomRatio, m_FontRatio, m_MeterText, FW_BOLD, m_FontRender); + } + + m_TestRead1.SetFontEx(m_FontFace, 52, 28, m_ZoomRatio, m_FontRatio, m_MeterText, FW_BOLD, m_FontRender); + m_TestRead2.SetFontEx(m_FontFace, 52, 28, m_ZoomRatio, m_FontRatio, m_MeterText, FW_BOLD, m_FontRender); + m_TestRead3.SetFontEx(m_FontFace, 52, 28, m_ZoomRatio, m_FontRatio, m_MeterText, FW_BOLD, m_FontRender); + + m_TestWrite1.SetFontEx(m_FontFace, 52, 28, m_ZoomRatio, m_FontRatio, m_MeterText, FW_BOLD, m_FontRender); + m_TestWrite2.SetFontEx(m_FontFace, 52, 28, m_ZoomRatio, m_FontRatio, m_MeterText, FW_BOLD, m_FontRender); + m_TestWrite3.SetFontEx(m_FontFace, 52, 28, m_ZoomRatio, m_FontRatio, m_MeterText, FW_BOLD, m_FontRender); + + m_Comment.SetFontEx(m_FontFace, 28, 28, m_ZoomRatio, m_FontRatio, m_EditText, FW_BOLD, m_FontRender); + + m_ReadUnit.SetFontEx(m_FontFace, 28, 28, m_ZoomRatio, m_FontRatio, m_LabelText, FW_BOLD, m_FontRender); + m_WriteUnit.SetFontEx(m_FontFace, 28, 28, m_ZoomRatio, m_FontRatio, m_LabelText, FW_BOLD, m_FontRender); + m_DemoSetting.SetFontEx(m_FontFace, 28, 28, m_ZoomRatio, m_FontRatio, m_MeterText, FW_BOLD, m_FontRender); + + m_ComboCount.SetFontEx(m_FontFace, 28, 28, m_ZoomRatio, m_FontRatio, m_ComboText, m_ComboTextSelected, FW_NORMAL, m_FontRender); + m_ComboSize.SetFontEx(m_FontFace, 28, 28, m_ZoomRatio, m_FontRatio, m_ComboText, m_ComboTextSelected, FW_NORMAL, m_FontRender); + m_ComboDrive.SetFontEx(m_FontFace, 28, 28, m_ZoomRatio, m_FontRatio, m_ComboText, m_ComboTextSelected, FW_NORMAL, m_FontRender); + m_ComboUnit.SetFontEx(m_FontFace, 28, 28, m_ZoomRatio, m_FontRatio, m_ComboText, m_ComboTextSelected, FW_NORMAL, m_FontRender); + + m_ButtonTest0.SetMargin(m_MarginButtonTop, m_MarginButtonLeft, m_MarginButtonBottom, m_MarginButtonRight, m_ZoomRatio); + m_ButtonTest1.SetMargin(m_MarginButtonTop, m_MarginButtonLeft, m_MarginButtonBottom, m_MarginButtonRight, m_ZoomRatio); + m_ButtonTest2.SetMargin(m_MarginButtonTop, m_MarginButtonLeft, m_MarginButtonBottom, m_MarginButtonRight, m_ZoomRatio); + m_ButtonTest3.SetMargin(m_MarginButtonTop, m_MarginButtonLeft, m_MarginButtonBottom, m_MarginButtonRight, m_ZoomRatio); + + m_ComboCount.SetItemHeightAll(40, m_ZoomRatio, m_FontRatio); + m_ComboSize.SetItemHeightAll(40, m_ZoomRatio, m_FontRatio); + m_ComboDrive.SetItemHeightAll(40, m_ZoomRatio, m_FontRatio); + m_ComboUnit.SetItemHeightAll(40, m_ZoomRatio, m_FontRatio); +#else + m_ButtonAll.SetFontEx(m_FontFace, 12, 16, m_ZoomRatio, m_FontRatio, m_ButtonText, FW_BOLD, m_FontRender); + m_ButtonTest0.SetFontEx(m_FontFace, 12, 16, m_ZoomRatio, m_FontRatio, m_ButtonText, FW_BOLD, m_FontRender); + m_ButtonTest1.SetFontEx(m_FontFace, 12, 16, m_ZoomRatio, m_FontRatio, m_ButtonText, FW_BOLD, m_FontRender); + m_ButtonTest2.SetFontEx(m_FontFace, 12, 16, m_ZoomRatio, m_FontRatio, m_ButtonText, FW_BOLD, m_FontRender); + m_ButtonTest3.SetFontEx(m_FontFace, 12, 16, m_ZoomRatio, m_FontRatio, m_ButtonText, FW_BOLD, m_FontRender); + + if (m_Profile == PROFILE_DEMO) + { + m_TestRead0.SetFontEx(m_FontFace, 48, 16, m_ZoomRatio, m_FontRatio, m_MeterText, FW_BOLD, m_FontRender); + m_TestWrite0.SetFontEx(m_FontFace, 48, 16, m_ZoomRatio, m_FontRatio, m_MeterText, FW_BOLD, m_FontRender); + } + else + { + m_TestRead0.SetFontEx(m_FontFace, 35, 16, m_ZoomRatio, m_FontRatio, m_MeterText, FW_BOLD, m_FontRender); + m_TestWrite0.SetFontEx(m_FontFace, 35, 16, m_ZoomRatio, m_FontRatio, m_MeterText, FW_BOLD, m_FontRender); + } + + m_TestRead1.SetFontEx(m_FontFace, 35, 16, m_ZoomRatio, m_FontRatio, m_MeterText, FW_BOLD, m_FontRender); + m_TestRead2.SetFontEx(m_FontFace, 35, 16, m_ZoomRatio, m_FontRatio, m_MeterText, FW_BOLD, m_FontRender); + m_TestRead3.SetFontEx(m_FontFace, 35, 16, m_ZoomRatio, m_FontRatio, m_MeterText, FW_BOLD, m_FontRender); + + m_TestWrite1.SetFontEx(m_FontFace, 35, 16, m_ZoomRatio, m_FontRatio, m_MeterText, FW_BOLD, m_FontRender); + m_TestWrite2.SetFontEx(m_FontFace, 35, 16, m_ZoomRatio, m_FontRatio, m_MeterText, FW_BOLD, m_FontRender); + m_TestWrite3.SetFontEx(m_FontFace, 35, 16, m_ZoomRatio, m_FontRatio, m_MeterText, FW_BOLD, m_FontRender); + + m_Comment.SetFontEx(m_FontFace, 16, 16, m_ZoomRatio, m_FontRatio, m_EditText, FW_BOLD, m_FontRender); + + m_ReadUnit.SetFontEx(m_FontFace, 16, 16, m_ZoomRatio, m_FontRatio, m_LabelText, FW_BOLD, m_FontRender); + m_WriteUnit.SetFontEx(m_FontFace, 16, 16, m_ZoomRatio, m_FontRatio, m_LabelText, FW_BOLD, m_FontRender); + m_DemoSetting.SetFontEx(m_FontFace, 16, 16, m_ZoomRatio, m_FontRatio, m_MeterText, FW_BOLD, m_FontRender); + + m_ComboCount.SetFontEx(m_FontFace, 16, 16, m_ZoomRatio, m_FontRatio, m_ComboText, m_ComboTextSelected, FW_NORMAL, m_FontRender); + m_ComboSize.SetFontEx(m_FontFace, 16, 16, m_ZoomRatio, m_FontRatio, m_ComboText, m_ComboTextSelected, FW_NORMAL, m_FontRender); + m_ComboDrive.SetFontEx(m_FontFace, 16, 16, m_ZoomRatio, m_FontRatio, m_ComboText, m_ComboTextSelected, FW_NORMAL, m_FontRender); + m_ComboUnit.SetFontEx(m_FontFace, 16, 16, m_ZoomRatio, m_FontRatio, m_ComboText, m_ComboTextSelected, FW_NORMAL, m_FontRender); + + m_ButtonTest0.SetMargin(m_MarginButtonTop, m_MarginButtonLeft, m_MarginButtonBottom, m_MarginButtonRight, m_ZoomRatio); + m_ButtonTest1.SetMargin(m_MarginButtonTop, m_MarginButtonLeft, m_MarginButtonBottom, m_MarginButtonRight, m_ZoomRatio); + m_ButtonTest2.SetMargin(m_MarginButtonTop, m_MarginButtonLeft, m_MarginButtonBottom, m_MarginButtonRight, m_ZoomRatio); + m_ButtonTest3.SetMargin(m_MarginButtonTop, m_MarginButtonLeft, m_MarginButtonBottom, m_MarginButtonRight, m_ZoomRatio); + + m_ComboCount.SetItemHeightAll(24, m_ZoomRatio, m_FontRatio); + m_ComboSize.SetItemHeightAll(24, m_ZoomRatio, m_FontRatio); + m_ComboDrive.SetItemHeightAll(24, m_ZoomRatio, m_FontRatio); + m_ComboUnit.SetItemHeightAll(24, m_ZoomRatio, m_FontRatio); + +#ifdef MIX_MODE + if(m_MixMode) + { + m_ComboMix.SetFontEx(m_FontFace, 16, 16, m_ZoomRatio, m_FontRatio, m_ComboText, m_ComboTextSelected, FW_NORMAL, m_FontRender); + m_ComboMix.SetItemHeightAll(24, m_ZoomRatio, m_FontRatio); + + m_MixUnit.SetFontEx(m_FontFace, 16, 16, m_ZoomRatio, m_FontRatio, m_LabelText, FW_BOLD, m_FontRender); + + m_TestMix0.SetFontEx(m_FontFace, 35, 35, m_ZoomRatio, m_FontRatio, m_MeterText, FW_BOLD, m_FontRender); + m_TestMix1.SetFontEx(m_FontFace, 35, 35, m_ZoomRatio, m_FontRatio, m_MeterText, FW_BOLD, m_FontRender); + m_TestMix2.SetFontEx(m_FontFace, 35, 35, m_ZoomRatio, m_FontRatio, m_MeterText, FW_BOLD, m_FontRender); + m_TestMix3.SetFontEx(m_FontFace, 35, 35, m_ZoomRatio, m_FontRatio, m_MeterText, FW_BOLD, m_FontRender); + } +#endif + +#endif + +} + +void CDiskMarkDlg::UpdateQueuesThreads() +{ + CString cstr; + + int type[9] = { 0, 0, 1, 1, 0, 1, 0, 1, 0 }; + int size[9] = { 1024, 1024, 4, 4, 1024, 4, 1024, 4, 1024 }; + int queues[9] = { 8, 1, 32, 1, 8, 32, 1, 1, 8 }; + int threads[9] ={ 1, 1, 1, 1, 1, 1, 1, 1, 1 }; + int measureTimes[13] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 20, 30, 60 }; + int intervalTimes[10] = { 0, 1, 3, 5, 10, 30, 60, 180, 300, 600 }; + + for (int i = 0; i < 9; i++) + { + cstr.Format(L"BenchType%d", i); + m_BenchType[i] = GetPrivateProfileInt(L"Setting", cstr, type[i], m_Ini); + if (m_BenchType[i] < 0 || m_BenchSize[i] > 1) { m_BenchSize[i] = type[i]; } + + cstr.Format(L"BenchSize%d", i); + m_BenchSize[i] = GetPrivateProfileInt(L"Setting", cstr, size[i], m_Ini); + if (m_BenchSize[i] <= 0 || m_BenchSize[i] > 8192) { m_BenchSize[i] = size[i]; } + + cstr.Format(L"BenchQueues%d", i); + m_BenchQueues[i] = GetPrivateProfileInt(L"Setting", cstr,queues[i], m_Ini); + if (m_BenchQueues[i] <= 0 || m_BenchQueues[i] > MAX_QUEUES) { m_BenchQueues[i] = queues[i]; } + + cstr.Format(L"BenchThreads%d", i); + m_BenchThreads[i] = GetPrivateProfileInt(L"Setting", cstr, threads[i], m_Ini); + if (m_BenchThreads[i] <= 0 || m_BenchThreads[i] > MAX_THREADS) { m_BenchThreads[i] = threads[i]; } + } + + m_TestData = GetPrivateProfileInt(L"Setting", L"TestData", TEST_DATA_RANDOM, m_Ini); + if (m_TestData < 0 || m_TestData > 1) + { + m_TestData = TEST_DATA_RANDOM; + } + SetWindowTitle(L""); + + BOOL bMeasureflag = FALSE; + m_MeasureTime = GetPrivateProfileInt(L"Setting", L"MeasureTime", 5, m_Ini); + for (int i = 0; i < 13; i++) + { + if (m_MeasureTime == measureTimes[i]) + { + bMeasureflag = TRUE; + } + } + if (! bMeasureflag) + { + m_MeasureTime = 5; + } + + BOOL bIntervalFlag = FALSE; + m_IntervalTime = GetPrivateProfileInt(L"Setting", L"IntervalTime", 5, m_Ini); + for (int i = 0; i < 10; i++) + { + if (m_IntervalTime == intervalTimes[i]) + { + bIntervalFlag = TRUE; + } + } + if (! bIntervalFlag) + { + m_IntervalTime = 5; + } + + CheckRadioPresetMode(); +} + +void CDiskMarkDlg::SettingsQueuesThreads(int type) +{ + CString key, value; + CString cstr; + + switch (type) + { + case 0:// Default + { + int type[9] = { 0, 0, 1, 1, 0, 1, 0, 1, 0 }; + int size[9] = { 1024, 1024, 4, 4, 1024, 4, 1024, 4, 1024 }; + int queues[9] = { 8, 1, 32, 1, 8, 32, 1, 1, 8 }; + int threads[9] ={ 1, 1, 1, 1, 1, 1, 1, 1, 1 }; + + for (int i = 0; i < 9; i++) + { + key.Format(L"BenchType%d", i); value.Format(L"%d", type[i]); + WritePrivateProfileString(L"Setting", key, value, m_Ini); + key.Format(L"BenchSize%d", i); value.Format(L"%d", size[i]); + WritePrivateProfileString(L"Setting", key, value, m_Ini); + key.Format(L"BenchQueues%d", i); value.Format(L"%d",queues[i]); + WritePrivateProfileString(L"Setting", key, value, m_Ini); + key.Format(L"BenchThreads%d", i); value.Format(L"%d", threads[i]); + WritePrivateProfileString(L"Setting", key, value, m_Ini); + } + WritePrivateProfileString(L"Setting", L"Affinity", L"1", m_Ini); + } + m_MeasureTime = 5; cstr.Format(L"%d", m_MeasureTime); + WritePrivateProfileString(L"Setting", L"MeasureTime", cstr, m_Ini); + m_IntervalTime = 5; cstr.Format(L"%d", m_IntervalTime); + WritePrivateProfileString(L"Setting", L"IntervalTime", cstr, m_Ini); + UpdateQueuesThreads(); + ChangeButtonStatus(TRUE); + break; + case 1: // NVMe SSD Ver.8 + { + int type[9] = { 0, 0, 1, 1, 0, 1, 0, 1, 0 }; + int size[9] = { 1024, 128, 4, 4, 1024, 4, 1024, 4, 1024 }; + int queues[9] = { 8, 32, 32, 1, 8, 32, 1, 1, 8 }; + int threads[9] = { 1, 1, 16, 1, 1, 16, 1, 1, 1 }; + for (int i = 0; i < 9; i++) + { + key.Format(L"BenchType%d", i); value.Format(L"%d", type[i]); + WritePrivateProfileString(L"Setting", key, value, m_Ini); + key.Format(L"BenchSize%d", i); value.Format(L"%d", size[i]); + WritePrivateProfileString(L"Setting", key, value, m_Ini); + key.Format(L"BenchQueues%d", i); value.Format(L"%d", queues[i]); + WritePrivateProfileString(L"Setting", key, value, m_Ini); + key.Format(L"BenchThreads%d", i); value.Format(L"%d", threads[i]); + WritePrivateProfileString(L"Setting", key, value, m_Ini); + } + WritePrivateProfileString(L"Setting", L"Affinity", L"1", m_Ini); + } + m_MeasureTime = 5; cstr.Format(L"%d", m_MeasureTime); + WritePrivateProfileString(L"Setting", L"MeasureTime", cstr, m_Ini); + m_IntervalTime = 5; cstr.Format(L"%d", m_IntervalTime); + WritePrivateProfileString(L"Setting", L"IntervalTime", cstr, m_Ini); + UpdateQueuesThreads(); + ChangeButtonStatus(TRUE); + break; + case 2: // Flash Memory + { + int type[9] = { 0, 0, 1, 1, 0, 1, 0, 1, 0 }; + int size[9] = { 1024, 1024, 4, 4, 1024, 4, 1024, 4, 1024 }; + int queues[9] = { 8, 1, 32, 1, 8, 32, 1, 1, 8 }; + int threads[9] ={ 1, 1, 1, 1, 1, 1, 1, 1, 1 }; + for (int i = 0; i < 9; i++) + { + key.Format(L"BenchType%d", i); value.Format(L"%d", type[i]); + WritePrivateProfileString(L"Setting", key, value, m_Ini); + key.Format(L"BenchSize%d", i); value.Format(L"%d", size[i]); + WritePrivateProfileString(L"Setting", key, value, m_Ini); + key.Format(L"BenchQueues%d", i); value.Format(L"%d", queues[i]); + WritePrivateProfileString(L"Setting", key, value, m_Ini); + key.Format(L"BenchThreads%d", i); value.Format(L"%d", threads[i]); + WritePrivateProfileString(L"Setting", key, value, m_Ini); + } + WritePrivateProfileString(L"Setting", L"Affinity", L"1", m_Ini); + } + m_MeasureTime = 1; cstr.Format(L"%d", m_MeasureTime); + WritePrivateProfileString(L"Setting", L"MeasureTime", cstr, m_Ini); + m_IntervalTime = 30; cstr.Format(L"%d", m_IntervalTime); + WritePrivateProfileString(L"Setting", L"IntervalTime", cstr, m_Ini); + UpdateQueuesThreads(); + ChangeButtonStatus(TRUE); + break; + default: + OnSettingsQueuesThreads(); + break; + } +} + +BOOL CDiskMarkDlg::PreTranslateMessage(MSG* pMsg) +{ + if( 0 != ::TranslateAccelerator(m_hWnd, m_hAccelerator, pMsg) ) + { + return TRUE; + } + + return CDialog::PreTranslateMessage(pMsg); +} + +#define STRICT_TYPED_ITEMIDS // Better type safety for IDLists +#include // Typical Shell header file + +INT_PTR CALLBACK BrowseCallbackProc(HWND hWnd, UINT uMsg, LPARAM lParam, LPARAM lpData) +{ + switch (uMsg) + { + case BFFM_INITIALIZED: + if (lpData != NULL) + { + ::SendMessage(hWnd, BFFM_SETSELECTION, TRUE, lpData); + } + break; + } + return 0; +} + +void CDiskMarkDlg::SelectDrive() +{ + CString cstr; + if (m_DiskBenchStatus) + { + return ; + } + + int previousComboDriveIndex = m_IndexTestDrive; + + UpdateData(TRUE); + + if (m_ComboDrive.GetCurSel() == m_MaxIndexTestDrive) + { + BROWSEINFO bi; + ZeroMemory(&bi, sizeof(BROWSEINFO)); + ITEMIDLIST __unaligned *idl; + LPMALLOC g_pMalloc; + TCHAR szTmp[MAX_PATH]; + + HRESULT hResult = SHGetMalloc(&g_pMalloc); + if (hResult == NOERROR) + { + bi.hwndOwner = this->m_hWnd; + bi.lpfn = (BFFCALLBACK)BrowseCallbackProc; + bi.lParam = (LPARAM)m_TestTargetPath.GetString(); + bi.pszDisplayName = szTmp; + bi.lpszTitle = L""; + bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_USENEWUI | BIF_NONEWFOLDERBUTTON; + idl = SHBrowseForFolderW(&bi); + if (idl != NULL) + { + if (SHGetPathFromIDList(idl, szTmp) != FALSE) + { + WritePrivateProfileString(L"Setting", L"TargetPath", szTmp, m_Ini); + m_TestTargetPath = szTmp; + } + g_pMalloc->Free(idl); + m_ComboDrive.SetToolTipText(m_TestTargetPath); + } + else + { + m_IndexTestDrive = previousComboDriveIndex; + m_ComboDrive.SetCurSel(m_IndexTestDrive); + m_ComboDrive.SetToolTipText(i18n(L"Title", L"TEST_DRIVE")); + + } + g_pMalloc->Release(); + } + } + else + { + m_ComboDrive.SetToolTipText(i18n(L"Title", L"TEST_DRIVE")); + } +} + + +LRESULT CDiskMarkDlg::OnUpdateScore(WPARAM wParam, LPARAM lParam) +{ + UpdateScore(); + return 0; +} + +LRESULT CDiskMarkDlg::OnExitBenchmark(WPARAM wParam, LPARAM lParam) +{ + ChangeButtonStatus(TRUE); + EnableMenus(); + + return 0; +} + +void CDiskMarkDlg::OnPaint() +{ + if (IsIconic()) + { + CPaintDC dc(this); // device context for painting + + SendMessage(WM_ICONERASEBKGND, reinterpret_cast(dc.GetSafeHdc()), 0); + + // Center icon in client rectangle + int cxIcon = GetSystemMetrics(SM_CXICON); + int cyIcon = GetSystemMetrics(SM_CYICON); + CRect rect; + GetClientRect(&rect); + int x = (rect.Width() - cxIcon + 1) / 2; + int y = (rect.Height() - cyIcon + 1) / 2; + + // Draw the icon + dc.DrawIcon(x, y, m_hIcon); + } + else + { + CMainDialogFx::OnPaint(); + } +} + +HCURSOR CDiskMarkDlg::OnQueryDragIcon() +{ + return static_cast(m_hIcon); +} + +void CDiskMarkDlg::OnOK() +{ + +} + +void CDiskMarkDlg::OnExit() +{ + OnCancel(); +} + +void CDiskMarkDlg::OnAbout() +{ + m_AboutDlg = new CAboutDlg(this); + m_AboutDlg->Create(CAboutDlg::IDD, m_AboutDlg, ID_ABOUT, this); +} + +void CDiskMarkDlg::OnCancel() +{ + if (m_WinThread != NULL) + { + AfxMessageBox(m_MesStopBenchmark); + return; + } + + UpdateData(TRUE); + CString cstr; + cstr.Format(L"%d", m_IndexTestUnit); + WritePrivateProfileString(L"Setting", L"TestUnit", cstr, m_Ini); + cstr.Format(L"%d", m_IndexTestCount); + WritePrivateProfileString(L"Setting", L"TestCount", cstr, m_Ini); + cstr.Format(L"%d", m_IndexTestSize); + WritePrivateProfileString(L"Setting", L"TestSize", cstr, m_Ini); +#ifdef MIX_MODE + if (m_MixMode) + { + cstr.Format(L"%d", m_IndexTestMix); + WritePrivateProfileString(L"Setting", L"TestMix", cstr, m_Ini); + } +#endif + + if(m_IndexTestDrive != m_MaxIndexTestDrive) + { + cstr.Format(L"%d", m_ValueTestDrive.GetAt(0) - 'A'); + } + else + { + cstr.Format(L"%d", 99); + } + WritePrivateProfileString(L"Setting", L"DriveLetter", cstr, m_Ini); + + CMainDialogFx::OnCancel(); +} + +void CDiskMarkDlg::InitScore() +{ + for (int i = 0; i < 9; i++) + { + m_ReadScore[i] = 0.0; + m_ReadLatency[i] = 0.0; + m_WriteScore[i] = 0.0; + m_WriteLatency[i] = 0.0; +#ifdef MIX_MODE + m_MixScore[i] = 0.0; + m_MixLatency[i] = 0.0; +#endif + } + + UpdateScore(); +} + +void CDiskMarkDlg::UpdateScore() +{ + UpdateData(TRUE); + if (m_Profile == PROFILE_DEMO) + { + SetMeter(&m_TestRead0, m_ReadScore[8], m_ReadLatency[8], m_BenchSize[8] * 1024, m_IndexTestUnit); + SetMeter(&m_TestWrite0, m_WriteScore[8], m_WriteLatency[8], m_BenchSize[8] * 1024, m_IndexTestUnit); + } + else if (m_Profile == PROFILE_PEAK || m_Profile == PROFILE_PEAK_MIX) + { + SetMeter(&m_TestRead0, m_ReadScore[4], m_ReadLatency[4], m_BenchSize[4] * 1024, SCORE_MBS); + SetMeter(&m_TestRead1, m_ReadScore[5], m_ReadLatency[5], m_BenchSize[5] * 1024, SCORE_MBS); + SetMeter(&m_TestRead2, m_ReadScore[5], m_ReadLatency[5], m_BenchSize[5] * 1024, SCORE_IOPS); + SetMeter(&m_TestRead3, m_ReadScore[5], m_ReadLatency[5], m_BenchSize[5] * 1024, SCORE_US); + SetMeter(&m_TestWrite0, m_WriteScore[4], m_WriteLatency[4], m_BenchSize[4] * 1024, SCORE_MBS); + SetMeter(&m_TestWrite1, m_WriteScore[5], m_WriteLatency[5], m_BenchSize[5] * 1024, SCORE_MBS); + SetMeter(&m_TestWrite2, m_WriteScore[5], m_WriteLatency[5], m_BenchSize[5] * 1024, SCORE_IOPS); + SetMeter(&m_TestWrite3, m_WriteScore[5], m_WriteLatency[5], m_BenchSize[5] * 1024, SCORE_US); +#ifdef MIX_MODE + if (m_MixMode) + { + SetMeter(&m_TestMix0, m_MixScore[4], m_MixLatency[4], m_BenchSize[4] * 1024, SCORE_MBS); + SetMeter(&m_TestMix1, m_MixScore[5], m_MixLatency[5], m_BenchSize[5] * 1024, SCORE_MBS); + SetMeter(&m_TestMix2, m_MixScore[5], m_MixLatency[5], m_BenchSize[5] * 1024, SCORE_IOPS); + SetMeter(&m_TestMix3, m_MixScore[5], m_MixLatency[5], m_BenchSize[5] * 1024, SCORE_US); + } +#endif + } + else if (m_Profile == PROFILE_REAL || m_Profile == PROFILE_REAL_MIX) + { + SetMeter(&m_TestRead0, m_ReadScore[6], m_ReadLatency[6], 1024 * 1024, SCORE_MBS); + SetMeter(&m_TestRead1, m_ReadScore[7], m_ReadLatency[7], 4 * 1024, SCORE_MBS); + SetMeter(&m_TestRead2, m_ReadScore[7], m_ReadLatency[7], 4 * 1024, SCORE_IOPS); + SetMeter(&m_TestRead3, m_ReadScore[7], m_ReadLatency[7], 4 * 1024, SCORE_US); + SetMeter(&m_TestWrite0, m_WriteScore[6], m_WriteLatency[6], 1024 * 1024, SCORE_MBS); + SetMeter(&m_TestWrite1, m_WriteScore[7], m_WriteLatency[7], 4 * 1024, SCORE_MBS); + SetMeter(&m_TestWrite2, m_WriteScore[7], m_WriteLatency[7], 4 * 1024, SCORE_IOPS); + SetMeter(&m_TestWrite3, m_WriteScore[7], m_WriteLatency[7], 4 * 1024, SCORE_US); +#ifdef MIX_MODE + if (m_MixMode) + { + SetMeter(&m_TestMix0, m_MixScore[6], m_MixLatency[6], 1024 * 1024, SCORE_MBS); + SetMeter(&m_TestMix1, m_MixScore[7], m_MixLatency[7], 4 * 1024, SCORE_MBS); + SetMeter(&m_TestMix2, m_MixScore[7], m_MixLatency[7], 4 * 1024, SCORE_IOPS); + SetMeter(&m_TestMix3, m_MixScore[7], m_MixLatency[7], 4 * 1024, SCORE_US); + } +#endif + } + else + { + SetMeter(&m_TestRead0, m_ReadScore[0], m_ReadLatency[0], m_BenchSize[0] * 1024, m_IndexTestUnit); + SetMeter(&m_TestRead1, m_ReadScore[1], m_ReadLatency[1], m_BenchSize[1] * 1024, m_IndexTestUnit); + SetMeter(&m_TestRead2, m_ReadScore[2], m_ReadLatency[2], m_BenchSize[2] * 1024, m_IndexTestUnit); + SetMeter(&m_TestRead3, m_ReadScore[3], m_ReadLatency[3], m_BenchSize[3] * 1024, m_IndexTestUnit); + SetMeter(&m_TestWrite0, m_WriteScore[0], m_WriteLatency[0], m_BenchSize[0] * 1024, m_IndexTestUnit); + SetMeter(&m_TestWrite1, m_WriteScore[1], m_WriteLatency[1], m_BenchSize[1] * 1024, m_IndexTestUnit); + SetMeter(&m_TestWrite2, m_WriteScore[2], m_WriteLatency[2], m_BenchSize[2] * 1024, m_IndexTestUnit); + SetMeter(&m_TestWrite3, m_WriteScore[3], m_WriteLatency[3], m_BenchSize[3] * 1024, m_IndexTestUnit); +#ifdef MIX_MODE + if (m_MixMode) + { + SetMeter(&m_TestMix0, m_MixScore[0], m_MixLatency[0], m_BenchSize[0] * 1024, m_IndexTestUnit); + SetMeter(&m_TestMix1, m_MixScore[1], m_MixLatency[1], m_BenchSize[1] * 1024, m_IndexTestUnit); + SetMeter(&m_TestMix2, m_MixScore[2], m_MixLatency[2], m_BenchSize[2] * 1024, m_IndexTestUnit); + SetMeter(&m_TestMix3, m_MixScore[3], m_MixLatency[3], m_BenchSize[3] * 1024, m_IndexTestUnit); + } +#endif + } +} + +void CDiskMarkDlg::SetScoreToolTip(CStaticFx* control, double score, double latency, int blockSize) +{ + CString cstr; + if (blockSize == -1) + { + cstr.Format(L"%.3f MB/s\r\n%.3f GB/s", score, score / 1000); + } + else if (score <= 0.0) + { + cstr.Format(L"%.3f MB/s\r\n%.3f GB/s\r\n%.3f IOPS\r\n%.3f μs", 0.0, 0.0, 0.0, 0.0); + } + else + { + cstr.Format(L"%.3f MB/s\r\n%.3f GB/s\r\n%.3f IOPS\r\n%.3f μs", score, score / 1000, score * 1000 * 1000 / blockSize, latency); + } + control->SetToolTipText(cstr); +} + +void CDiskMarkDlg::OnSequentialPeak() +{ + if (m_WinThread == NULL) + { + UpdateData(TRUE); + + m_ReadScore[4] = 0.0; + m_WriteScore[4] = 0.0; + m_ReadLatency[4] = 0.0; + m_WriteLatency[4] = 0.0; +#ifdef MIX_MODE + m_MixScore[4] = 0.0; + m_MixLatency[4] = 0.0; +#endif + UpdateScore(); + m_DiskBenchStatus = TRUE; + m_WinThread = AfxBeginThread(ExecDiskBench4, (void*)this); + if (m_WinThread == NULL) + { + m_DiskBenchStatus = FALSE; + } + else + { + ChangeButtonStatus(FALSE); + } + DisableMenus(); + } + else + { + Stop(); + } +} + +void CDiskMarkDlg::OnRandomPeak() +{ + if (m_WinThread == NULL) + { + UpdateData(TRUE); + + m_ReadScore[5] = 0.0; + m_WriteScore[5] = 0.0; + m_ReadLatency[5] = 0.0; + m_WriteLatency[5] = 0.0; +#ifdef MIX_MODE + m_MixScore[5] = 0.0; + m_MixLatency[5] = 0.0; +#endif + UpdateScore(); + m_DiskBenchStatus = TRUE; + m_WinThread = AfxBeginThread(ExecDiskBench5, (void*)this); + if (m_WinThread == NULL) + { + m_DiskBenchStatus = FALSE; + } + else + { + ChangeButtonStatus(FALSE); + } + DisableMenus(); + } + else + { + Stop(); + } +} + +void CDiskMarkDlg::OnSequentialReal() +{ + if (m_WinThread == NULL) + { + UpdateData(TRUE); + + m_ReadScore[6] = 0.0; + m_WriteScore[6] = 0.0; + m_ReadLatency[6] = 0.0; + m_WriteLatency[6] = 0.0; +#ifdef MIX_MODE + m_MixScore[6] = 0.0; + m_MixLatency[6] = 0.0; +#endif + UpdateScore(); + m_DiskBenchStatus = TRUE; + m_WinThread = AfxBeginThread(ExecDiskBench6, (void*)this); + if (m_WinThread == NULL) + { + m_DiskBenchStatus = FALSE; + } + else + { + ChangeButtonStatus(FALSE); + } + DisableMenus(); + } + else + { + Stop(); + } +} + +void CDiskMarkDlg::OnRandomReal() +{ + if (m_WinThread == NULL) + { + UpdateData(TRUE); + + m_ReadScore[7] = 0.0; + m_WriteScore[7] = 0.0; + m_ReadLatency[7] = 0.0; + m_WriteLatency[7] = 0.0; +#ifdef MIX_MODE + m_MixScore[7] = 0.0; + m_MixLatency[7] = 0.0; +#endif + UpdateScore(); + m_DiskBenchStatus = TRUE; + m_WinThread = AfxBeginThread(ExecDiskBench7, (void*)this); + if (m_WinThread == NULL) + { + m_DiskBenchStatus = FALSE; + } + else + { + ChangeButtonStatus(FALSE); + } + DisableMenus(); + } + else + { + Stop(); + } +} + +void CDiskMarkDlg::OnTest0() +{ + if (m_Profile == PROFILE_PEAK || m_Profile == PROFILE_PEAK_MIX) + { + OnSequentialPeak(); + return; + } + else if (m_Profile == PROFILE_REAL || m_Profile == PROFILE_REAL_MIX) + { + OnSequentialReal(); + return; + } + + if(m_WinThread == NULL) + { + UpdateData(TRUE); + + m_ReadScore[0] = 0.0; + m_WriteScore[0] = 0.0; + m_ReadLatency[0] = 0.0; + m_WriteLatency[0] = 0.0; +#ifdef MIX_MODE + m_MixScore[0] = 0.0; + m_MixLatency[0] = 0.0; +#endif + UpdateScore(); + m_DiskBenchStatus = TRUE; + m_WinThread = AfxBeginThread(ExecDiskBench0, (void*)this); + if(m_WinThread == NULL) + { + m_DiskBenchStatus = FALSE; + } + else + { + ChangeButtonStatus(FALSE); + } + DisableMenus(); + } + else + { + Stop(); + } +} + +void CDiskMarkDlg::OnTest1() +{ + if (m_Profile == PROFILE_PEAK || m_Profile == PROFILE_PEAK_MIX) + { + OnRandomPeak(); + return; + } + else if (m_Profile == PROFILE_REAL || m_Profile == PROFILE_REAL_MIX) + { + OnRandomReal(); + return; + } + + if (m_WinThread == NULL) + { + UpdateData(TRUE); + + m_ReadScore[1] = 0.0; + m_WriteScore[1] = 0.0; + m_ReadLatency[1] = 0.0; + m_WriteLatency[1] = 0.0; +#ifdef MIX_MODE + m_MixScore[1] = 0.0; + m_MixLatency[1] = 0.0; +#endif + UpdateScore(); + m_DiskBenchStatus = TRUE; + m_WinThread = AfxBeginThread(ExecDiskBench1, (void*)this); + if (m_WinThread == NULL) + { + m_DiskBenchStatus = FALSE; + } + else + { + ChangeButtonStatus(FALSE); + } + DisableMenus(); + } + else + { + Stop(); + } +} + +void CDiskMarkDlg::OnTest2() +{ + if (m_Profile == PROFILE_PEAK || m_Profile == PROFILE_PEAK_MIX) + { + OnRandomPeak(); + return; + } + else if (m_Profile == PROFILE_REAL || m_Profile == PROFILE_REAL_MIX) + { + OnRandomReal(); + return; + } + + if(m_WinThread == NULL) + { + UpdateData(TRUE); + + m_ReadScore[2] = 0.0; + m_WriteScore[2] = 0.0; + m_ReadLatency[2] = 0.0; + m_WriteLatency[2] = 0.0; +#ifdef MIX_MODE + m_MixScore[2] = 0.0; + m_MixLatency[2] = 0.0; +#endif + UpdateScore(); + m_DiskBenchStatus = TRUE; + m_WinThread = AfxBeginThread(ExecDiskBench2, (void*)this); + if(m_WinThread == NULL) + { + m_DiskBenchStatus = FALSE; + } + else + { + ChangeButtonStatus(FALSE); + } + DisableMenus(); + } + else + { + Stop(); + } +} + +void CDiskMarkDlg::OnTest3() +{ + if (m_Profile == PROFILE_PEAK || m_Profile == PROFILE_PEAK_MIX) + { + OnRandomPeak(); + return; + } + else if (m_Profile == PROFILE_REAL || m_Profile == PROFILE_REAL_MIX) + { + OnRandomReal(); + return; + } + + if(m_WinThread == NULL) + { + UpdateData(TRUE); + + m_ReadScore[3] = 0.0; + m_WriteScore[3] = 0.0; + m_ReadLatency[3] = 0.0; + m_WriteLatency[3] = 0.0; +#ifdef MIX_MODE + m_MixScore[3] = 0.0; + m_MixLatency[3] = 0.0; +#endif + UpdateScore(); + m_DiskBenchStatus = TRUE; + m_WinThread = AfxBeginThread(ExecDiskBench3, (void*)this); + if(m_WinThread == NULL) + { + m_DiskBenchStatus = FALSE; + } + else + { + ChangeButtonStatus(FALSE); + } + DisableMenus(); + } + else + { + Stop(); + } +} + +void CDiskMarkDlg::OnAll() +{ + if(m_WinThread == NULL) + { + UpdateData(TRUE); + InitScore(); + m_DiskBenchStatus = TRUE; + if (m_Profile == PROFILE_DEMO) + { + m_WinThread = AfxBeginThread(ExecDiskBenchAllDemo, (void*)this); + } + else if (m_Profile == PROFILE_PEAK || m_Profile == PROFILE_PEAK_MIX) + { + m_WinThread = AfxBeginThread(ExecDiskBenchAllPeak, (void*)this); + } + else if (m_Profile == PROFILE_REAL || m_Profile == PROFILE_REAL_MIX) + { + m_WinThread = AfxBeginThread(ExecDiskBenchAllReal, (void*)this); + } + else + { + m_WinThread = AfxBeginThread(ExecDiskBenchAll, (void*)this); + } + + if(m_WinThread == NULL) + { + m_DiskBenchStatus = FALSE; + } + else + { + ChangeButtonStatus(FALSE); + } + DisableMenus(); + } + else + { + Stop(); + } +} + +void CDiskMarkDlg::Stop() +{ + if(m_DiskBenchStatus) + { + m_DiskBenchStatus = FALSE; + + if (pi.hProcess != NULL) + { + TerminateProcess(pi.hProcess, 0); + } + } + EnableMenus(); +} + +void CDiskMarkDlg::EnableMenus() +{ + CMenu *menu = GetMenu(); + menu->EnableMenuItem(0, MF_BYPOSITION | MF_ENABLED); + menu->EnableMenuItem(1, MF_BYPOSITION | MF_ENABLED); + menu->EnableMenuItem(2, MF_BYPOSITION | MF_ENABLED); + menu->EnableMenuItem(3, MF_BYPOSITION | MF_ENABLED); + menu->EnableMenuItem(4, MF_BYPOSITION | MF_ENABLED); + menu->EnableMenuItem(5, MF_BYPOSITION | MF_ENABLED); + SetMenu(menu); +} + +void CDiskMarkDlg::DisableMenus() +{ + CMenu *menu = GetMenu(); + menu->EnableMenuItem(0, MF_BYPOSITION | MF_GRAYED); + menu->EnableMenuItem(1, MF_BYPOSITION | MF_GRAYED); + menu->EnableMenuItem(2, MF_BYPOSITION | MF_GRAYED); + menu->EnableMenuItem(3, MF_BYPOSITION | MF_GRAYED); + menu->EnableMenuItem(4, MF_BYPOSITION | MF_GRAYED); + menu->EnableMenuItem(5, MF_BYPOSITION | MF_GRAYED); + SetMenu(menu); +} + +CString CDiskMarkDlg::GetButtonText(int type, int size, int queues, int threads, int unit) +{ + CString text; + + if (size >= 1024) + { + if (type == BENCH_RND) + { + if (m_Profile == PROFILE_PEAK || m_Profile == PROFILE_PEAK_MIX || m_Profile == PROFILE_REAL || m_Profile == PROFILE_REAL_MIX) + { + if (unit == SCORE_IOPS) + { + text.Format(L"RND%dM\r\n(IOPS)", size / 1024); + } + else if (unit == SCORE_US) + { + text.Format(L"RND%dM\r\n(μs)", size / 1024); + } + else if (unit == SCORE_GBS) + { + text.Format(L"RND%dM\r\nQ%dT%d", size / 1024, queues, threads); + } + else + { + text.Format(L"RND%dM\r\nQ%dT%d", size / 1024, queues, threads); + } + } + else + { + if (unit == SCORE_GBS) + { + text.Format(L"RND%dM\r\nQ%dT%d", size / 1024, queues, threads); + } + else + { + text.Format(L"RND%dM\r\nQ%dT%d", size / 1024, queues, threads); + } + } + } + else + { + if (unit == SCORE_GBS) + { + text.Format(L"SEQ%dM\r\nQ%dT%d", size / 1024, queues, threads); + } + else + { + text.Format(L"SEQ%dM\r\nQ%dT%d", size / 1024, queues, threads); + } + } + } + else + { + if (type == BENCH_RND) + { + if (m_Profile == PROFILE_PEAK || m_Profile == PROFILE_PEAK_MIX || m_Profile == PROFILE_REAL || m_Profile == PROFILE_REAL_MIX) + { + if (unit == SCORE_IOPS) + { + text.Format(L"RND%dK\r\n(IOPS)", size); + } + else if (unit == SCORE_US) + { + text.Format(L"RND%dK\r\n(μs)", size); + } + else if (unit == SCORE_GBS) + { + text.Format(L"RND%dK\r\nQ%dT%d", size, queues, threads); + } + else + { + text.Format(L"RND%dK\r\nQ%dT%d", size, queues, threads); + } + } + else + { + if (unit == SCORE_GBS) + { + text.Format(L"RND%dK\r\nQ%dT%d", size, queues, threads); + } + else + { + text.Format(L"RND%dK\r\nQ%dT%d", size, queues, threads); + } + } + } + else + { + if (unit == SCORE_GBS) + { + text.Format(L"SEQ%dK\r\nQ%dT%d", size, queues, threads); + } + else + { + text.Format(L"SEQ%dK\r\nQ%dT%d", size, queues, threads); + } + } + } + + return text; +} + +CString CDiskMarkDlg::GetButtonToolTipText(int type, int size, int queues, int threads, int unit) +{ + CString text; + + if (size >= 1024) + { + if (type == BENCH_RND) + { + if (unit == SCORE_IOPS) + { + text.Format(L"Random %dMiB\r\nQueues=%d\r\nThreads=%d\r\n(IOPS)", size / 1024, queues, threads); + } + else if (unit == SCORE_US) + { + text.Format(L"Random %dMiB\r\nQueues=%d\r\nThreads=%d\r\n(μs)", size / 1024, queues, threads); + } + else if (unit == SCORE_GBS) + { + text.Format(L"Random %dMiB\r\nQueues=%d\r\nThreads=%d\r\n(GB/s)", size / 1024, queues, threads); + } + else + { + text.Format(L"Random %dMiB\r\nQueues=%d\r\nThreads=%d\r\n(MB/s)", size / 1024, queues, threads); + } + } + else + { + if (unit == SCORE_GBS) + { + text.Format(L"Sequential %dMiB\r\nQueues=%d\r\nThreads=%d\r\n(GB/s)", size / 1024, queues, threads); + } + else + { + text.Format(L"Sequential %dMiB\r\nQueues=%d\r\nThreads=%d\r\n(MB/s)", size / 1024, queues, threads); + } + } + } + else + { + if (type == BENCH_RND) + { + if (unit == SCORE_IOPS) + { + text.Format(L"Random %dKiB\r\nQueues=%d\r\nThreads=%d\r\n(IOPS)", size, queues, threads); + } + else if (unit == SCORE_US) + { + text.Format(L"Random %dKiB\r\nQueues=%d\r\nThreads=%d\r\n(μs)", size, queues, threads); + } + else if (unit == SCORE_GBS) + { + text.Format(L"Random %dKiB\r\nQueues=%d\r\nThreads=%d\r\n(GB/s)", size, queues, threads); + } + else + { + text.Format(L"Random %dKiB\r\nQueues=%d\r\nThreads=%d\r\n(MB/s)", size, queues, threads); + } + } + else + { + if (unit == SCORE_GBS) + { + text.Format(L"Sequential %dKiB\r\nQueues=%d\r\nThreads=%d\r\n(GB/s)", size, queues, threads); + } + else + { + text.Format(L"Sequential %dKiB\r\nQueues=%d\r\nThreads=%d\r\n(MB/s)", size, queues, threads); + } + } + } + + return text; +} + +void CDiskMarkDlg::ChangeButtonStatus(BOOL status) +{ + if(status) + { + CString title; + CString toolTip; + +#ifdef MIX_MODE + m_ComboMix.EnableWindow(TRUE); +#endif + m_ComboCount.EnableWindow(TRUE); + m_ComboSize.EnableWindow(TRUE); + m_ComboDrive.EnableWindow(TRUE); + m_ComboUnit.EnableWindow(TRUE); + + CString cstr; + if (m_MeasureTime == 5) + { + cstr.Format(L"All"); + } + else + { + cstr.Format(L"All\n%dsec", m_MeasureTime); + } + + m_ButtonAll.SetWindowTextW(cstr); + + if (m_Profile == PROFILE_DEMO) + { + m_ButtonTest0.ShowWindow(SW_HIDE); + m_ButtonTest1.ShowWindow(SW_HIDE); + m_ButtonTest2.ShowWindow(SW_HIDE); + m_ButtonTest3.ShowWindow(SW_HIDE); + + CString text, type; + if (m_BenchType[8] == BENCH_SEQ) + { + type = L"SEQ"; + } + else + { + type = L"RND"; + } + if (m_BenchSize[8] > 1000) + { + text.Format(L"%s %dMiB, Q=%d, T=%d", type.GetString(), m_BenchSize[8] / 1024, m_BenchQueues[8], m_BenchThreads[8]); + } + else + { + text.Format(L"%s %dKiB, Q=%d, T=%d", type.GetString(), m_BenchSize[8], m_BenchQueues[8], m_BenchThreads[8]); + } + + m_DemoSetting.SetWindowTextW(text); + } + else if (m_Profile == PROFILE_PEAK || m_Profile == PROFILE_PEAK_MIX) + { + m_ButtonTest0.ShowWindow(SW_SHOW); + m_ButtonTest1.ShowWindow(SW_SHOW); + m_ButtonTest2.ShowWindow(SW_SHOW); + m_ButtonTest3.ShowWindow(SW_SHOW); + + m_ButtonTest0.SetWindowTextW(GetButtonText(BENCH_SEQ, m_BenchSize[4], m_BenchQueues[4], m_BenchThreads[4], SCORE_MBS)); + m_ButtonTest1.SetWindowTextW(GetButtonText(BENCH_RND, m_BenchSize[5], m_BenchQueues[5], m_BenchThreads[5], SCORE_MBS)); + m_ButtonTest2.SetWindowTextW(GetButtonText(BENCH_RND, m_BenchSize[5], m_BenchQueues[5], m_BenchThreads[5], SCORE_IOPS)); + m_ButtonTest3.SetWindowTextW(GetButtonText(BENCH_RND, m_BenchSize[5], m_BenchQueues[5], m_BenchThreads[5], SCORE_US)); + + m_ButtonTest0.SetToolTipText(GetButtonToolTipText(BENCH_SEQ, m_BenchSize[4], m_BenchQueues[4], m_BenchThreads[4], SCORE_MBS)); + m_ButtonTest1.SetToolTipText(GetButtonToolTipText(BENCH_RND, m_BenchSize[5], m_BenchQueues[5], m_BenchThreads[5], SCORE_MBS)); + m_ButtonTest2.SetToolTipText(GetButtonToolTipText(BENCH_RND, m_BenchSize[5], m_BenchQueues[5], m_BenchThreads[5], SCORE_IOPS)); + m_ButtonTest3.SetToolTipText(GetButtonToolTipText(BENCH_RND, m_BenchSize[5], m_BenchQueues[5], m_BenchThreads[5], SCORE_US)); + } + else if (m_Profile == PROFILE_REAL || m_Profile == PROFILE_REAL_MIX) + { + m_ButtonTest0.ShowWindow(SW_SHOW); + m_ButtonTest1.ShowWindow(SW_SHOW); + m_ButtonTest2.ShowWindow(SW_SHOW); + m_ButtonTest3.ShowWindow(SW_SHOW); + + m_ButtonTest0.SetWindowTextW(GetButtonText(BENCH_SEQ, 1024, 1, 1, SCORE_MBS)); + m_ButtonTest1.SetWindowTextW(GetButtonText(BENCH_RND, 4, 1, 1, SCORE_MBS)); + m_ButtonTest2.SetWindowTextW(GetButtonText(BENCH_RND, 4, 1, 1, SCORE_IOPS)); + m_ButtonTest3.SetWindowTextW(GetButtonText(BENCH_RND, 4, 1, 1, SCORE_US)); + + m_ButtonTest0.SetToolTipText(GetButtonToolTipText(BENCH_SEQ, 1024, 1, 1, SCORE_MBS)); + m_ButtonTest1.SetToolTipText(GetButtonToolTipText(BENCH_RND, 4, 1, 1, SCORE_MBS)); + m_ButtonTest2.SetToolTipText(GetButtonToolTipText(BENCH_RND, 4, 1, 1, SCORE_IOPS)); + m_ButtonTest3.SetToolTipText(GetButtonToolTipText(BENCH_RND, 4, 1, 1, SCORE_US)); + } + else + { + m_ButtonTest0.ShowWindow(SW_SHOW); + m_ButtonTest1.ShowWindow(SW_SHOW); + m_ButtonTest2.ShowWindow(SW_SHOW); + m_ButtonTest3.ShowWindow(SW_SHOW); + + m_ButtonTest0.SetWindowTextW(GetButtonText(m_BenchType[0], m_BenchSize[0], m_BenchQueues[0], m_BenchThreads[0], m_IndexTestUnit)); + m_ButtonTest1.SetWindowTextW(GetButtonText(m_BenchType[1], m_BenchSize[1], m_BenchQueues[1], m_BenchThreads[1], m_IndexTestUnit)); + m_ButtonTest2.SetWindowTextW(GetButtonText(m_BenchType[2], m_BenchSize[2], m_BenchQueues[2], m_BenchThreads[2], m_IndexTestUnit)); + m_ButtonTest3.SetWindowTextW(GetButtonText(m_BenchType[3], m_BenchSize[3], m_BenchQueues[3], m_BenchThreads[3], m_IndexTestUnit)); + + m_ButtonTest0.SetToolTipText(GetButtonToolTipText(m_BenchType[0], m_BenchSize[0], m_BenchQueues[0], m_BenchThreads[0], m_IndexTestUnit)); + m_ButtonTest1.SetToolTipText(GetButtonToolTipText(m_BenchType[1], m_BenchSize[1], m_BenchQueues[1], m_BenchThreads[1], m_IndexTestUnit)); + m_ButtonTest2.SetToolTipText(GetButtonToolTipText(m_BenchType[2], m_BenchSize[2], m_BenchQueues[2], m_BenchThreads[2], m_IndexTestUnit)); + m_ButtonTest3.SetToolTipText(GetButtonToolTipText(m_BenchType[3], m_BenchSize[3], m_BenchQueues[3], m_BenchThreads[3], m_IndexTestUnit)); + } + } + else + { +#ifdef MIX_MODE + m_ComboMix.EnableWindow(FALSE); +#endif + m_ComboCount.EnableWindow(FALSE); + m_ComboSize.EnableWindow(FALSE); + m_ComboDrive.EnableWindow(FALSE); + m_ComboUnit.EnableWindow(FALSE); + + m_ButtonAll.SetWindowTextW(L"Stop"); + m_ButtonTest0.SetWindowTextW(L"Stop"); + m_ButtonTest1.SetWindowTextW(L"Stop"); + m_ButtonTest2.SetWindowTextW(L"Stop"); + m_ButtonTest3.SetWindowTextW(L"Stop"); + } +} + +LRESULT CDiskMarkDlg::OnUpdateMessage(WPARAM wParam, LPARAM lParam) +{ + CString wstr = L""; + CString lstr = L""; + + if(wParam != NULL) + { + wstr = *((CString*)wParam); + } + + if(lParam != NULL) + { + lstr = *((CString*)lParam); + } + + SetWindowTitle(wstr); + return 0; +} + +void CDiskMarkDlg::SetMeter(CStaticFx* control, double score, double latency, int blockSize, int unit) +{ + CString cstr; + + double meterRatio = 0.0; + + if (unit == SCORE_UNIT::SCORE_US) + { + if (latency > 0.0000000001) + { + meterRatio = 1 - 0.16666666666666 * log10(latency); + } + else + { + meterRatio = 0; + } + } + else + { + if (score > 0.1) + { + meterRatio = 0.16666666666666 * log10(score * 10); + } + else + { + meterRatio = 0; + } + } + + if (meterRatio > 1.0) + { + meterRatio = 1.0; + } + + if (unit == SCORE_UNIT::SCORE_IOPS) + { + double iops = score * 1000 * 1000 / blockSize; + if (m_Profile == PROFILE_DEMO) + { + if (iops >= 100000.0) + { + cstr.Format(L"%dk", (int)iops / 1000); + } + else + { + cstr.Format(L"%d", (int)iops); + } + } + else + { + if (iops >= 1000000.0) + { + cstr.Format(L"%d", (int)iops); + } + else + { + cstr.Format(L"%.2f", iops); + } + } + } + else if (unit == SCORE_UNIT::SCORE_US) + { + if (m_Profile == PROFILE_DEMO) + { + if (score <= 0.0) + { + cstr.Format(L"%.1f", 0.0); + if (*control == m_TestRead0) { m_TestRead0.SetLabelUnit(L"Read", L"μs"); } + if (*control == m_TestWrite0) { m_TestWrite0.SetLabelUnit(L"Write", L"μs"); } + } + else if (latency >= 1000000.0) + { + cstr.Format(L"%d", (int)latency / 1000); + if (*control == m_TestRead0) { m_TestRead0.SetLabelUnit(L"Read", L"ms"); } + if (*control == m_TestWrite0) { m_TestWrite0.SetLabelUnit(L"Write", L"ms"); } + } + else if (latency >= 1000.0) + { + cstr.Format(L"%d", (int)latency); + if (*control == m_TestRead0) { m_TestRead0.SetLabelUnit(L"Read", L"μs"); } + if (*control == m_TestWrite0) { m_TestWrite0.SetLabelUnit(L"Write", L"μs"); } + } + else + { + cstr.Format(L"%.1f", latency); + if (*control == m_TestRead0) { m_TestRead0.SetLabelUnit(L"Read", L"μs"); } + if (*control == m_TestWrite0) { m_TestWrite0.SetLabelUnit(L"Write", L"μs"); } + } + } + else + { + if (score <= 0.0) + { + cstr.Format(L"%.2f", 0.0); + } + else if (latency >= 1000000.0) + { + cstr.Format(L"%d", (int)latency); + } + else + { + cstr.Format(L"%.2f", latency); + } + } + } + else if (unit == SCORE_UNIT::SCORE_GBS) + { + if (m_Profile == PROFILE_DEMO) + { + cstr.Format(L"%.1f", score / 1000.0); + } + else + { + cstr.Format(L"%.3f", score / 1000.0); + } + } + else + { + if (m_Profile == PROFILE_DEMO) + { + if (score >= 1000.0) + { + cstr.Format(L"%d", (int)score); + } + else + { + cstr.Format(L"%.1f", score); + } + } + else + { + if (score >= 1000000.0) + { + cstr.Format(L"%d", (int)score); + } + else + { + cstr.Format(L"%.2f", score); + } + } + } + + UpdateData(FALSE); + if (m_Profile == PROFILE_DEMO) + { + control->SetMeter(FALSE, meterRatio); + } + else + { + control->SetMeter(TRUE, meterRatio); + } + control->SetWindowTextW(cstr); + + SetScoreToolTip(control, score, latency, blockSize); +} + +void CDiskMarkDlg::InitDrive() +{ + while (m_ComboDrive.GetCount()) + { + m_ComboDrive.DeleteString(0); + } + + CString cstr; + CString select; + + // list up drive + TCHAR szDrives[256] = {0}; + LPTSTR pDrive = szDrives; + TCHAR rootPath[4] = {0}; + TCHAR fileSystem[32] = {0}; + int count = 0; + GetLogicalDriveStrings(255, szDrives); + + m_IndexTestDrive = 0; + m_TestDriveLetter = GetPrivateProfileInt(L"Setting", L"DriveLetter", 2, m_Ini); // Default "C:\" + + while( pDrive[0] != L'\0' ) + { + ULARGE_INTEGER freeBytesAvailableToCaller = {0}; + ULARGE_INTEGER totalNumberOfBytes = {0}; + ULARGE_INTEGER totalNumberOfFreeBytes = {0}; + + // _tcsupr_s(pDrive, sizeof(TCHAR) * 4); + int result = GetDriveType(pDrive); + + int forward = (int)_tcslen( pDrive ); + + if(result == DRIVE_FIXED || result == DRIVE_REMOTE || result == DRIVE_REMOVABLE || result == DRIVE_RAMDISK) + { + pDrive[1] = L'\0'; + cstr.Format(L"%C: ", pDrive[0]); + freeBytesAvailableToCaller.QuadPart = 0; + totalNumberOfBytes.QuadPart = 0; + totalNumberOfFreeBytes.QuadPart = 0; + if(GetDiskFreeSpaceEx(cstr, &freeBytesAvailableToCaller, &totalNumberOfBytes, &totalNumberOfFreeBytes) != 0) + { + select += cstr; + if(totalNumberOfBytes.QuadPart < ((ULONGLONG)8 * 1024 * 1024 * 1024)) // < 8 GB + { + cstr.Format(L"%s: %.0f%% (%.0f/%.0fMiB)", pDrive, + (double)(totalNumberOfBytes.QuadPart - totalNumberOfFreeBytes.QuadPart) / (double)totalNumberOfBytes.QuadPart * 100, + (totalNumberOfBytes.QuadPart - totalNumberOfFreeBytes.QuadPart) / 1024 / 1024.0, + totalNumberOfBytes.QuadPart / 1024 / 1024.0); + } + else + { + cstr.Format(L"%s: %.0f%% (%.0f/%.0fGiB)", pDrive, + (double)(totalNumberOfBytes.QuadPart - totalNumberOfFreeBytes.QuadPart) / (double)totalNumberOfBytes.QuadPart * 100, + (totalNumberOfBytes.QuadPart - totalNumberOfFreeBytes.QuadPart) / 1024 / 1024 / 1024.0, + totalNumberOfBytes.QuadPart / 1024 / 1024 / 1024.0); + } + select += cstr; + + if(m_TestDriveLetter == pDrive[0] - 'A') + { + m_IndexTestDrive = count; + } + count++; + + m_ComboDrive.AddString(cstr); + } + } + pDrive += forward + 1; + } + + m_ComboDrive.AddString(i18n(L"Menu", L"SELECT_FOLDER")); + + TCHAR str[256]; + GetPrivateProfileString(L"Setting", L"TargetPath", L"", str, 256, m_Ini); + m_TestTargetPath = str; + + if (m_TestDriveLetter == 99) + { + m_IndexTestDrive = count; + } + m_MaxIndexTestDrive = count; + + UpdateDriveToolTip(); + + UpdateData(FALSE); +} + +void CDiskMarkDlg::UpdateDriveToolTip() +{ + m_ComboDrive.SetCurSel(m_IndexTestDrive); + if (m_TestDriveLetter == 99 && !m_TestTargetPath.IsEmpty()) + { + m_ComboDrive.SetToolTipText(m_TestTargetPath); + } + else + { + m_ComboDrive.SetToolTipText(i18n(L"Title", L"TEST_DRIVE")); + } +} + +void CDiskMarkDlg::ChangeLang(CString LangName) +{ + m_CurrentLangPath.Format(L"%s\\%s.lang", (LPTSTR)m_LangDir.GetString(), (LPTSTR)LangName.GetString()); + + CString cstr; + CMenu *menu = GetMenu(); + CMenu subMenu; + + cstr = i18n(L"Menu", L"FILE"); + menu->ModifyMenu(0, MF_BYPOSITION | MF_STRING, 0, cstr); + cstr = i18n(L"Menu", L"SETTINGS"); + menu->ModifyMenu(1, MF_BYPOSITION | MF_STRING, 1, cstr); + cstr = i18n(L"Menu", L"PROFILE"); + menu->ModifyMenu(2, MF_BYPOSITION | MF_STRING, 2, cstr); + cstr = i18n(L"Menu", L"THEME"); + menu->ModifyMenu(3, MF_BYPOSITION | MF_STRING, 3, cstr); + cstr = i18n(L"Menu", L"HELP"); + menu->ModifyMenu(4, MF_BYPOSITION | MF_STRING, 4, cstr); + cstr = i18n(L"Menu", L"LANGUAGE"); + if(cstr.Find(L"Language") >= 0) + { + cstr = L"&Language"; + menu->ModifyMenu(5, MF_BYPOSITION | MF_STRING, 5, cstr); + } + else + { + menu->ModifyMenu(5, MF_BYPOSITION | MF_STRING, 5, cstr + L"(&Language)"); + } + + cstr = i18n(L"Menu", L"FILE_EXIT") + L"\tAlt + F4"; + menu->ModifyMenu(ID_EXIT, MF_STRING, ID_EXIT, cstr); + cstr = i18n(L"Menu", L"SAVE_TEXT") + L"\tCtrl + T"; + menu->ModifyMenu(ID_SAVE_TEXT, MF_STRING, ID_SAVE_TEXT, cstr); + cstr = i18n(L"Menu", L"SAVE_IMAGE") + L"\tCtrl + S"; + menu->ModifyMenu(ID_SAVE_IMAGE, MF_STRING, ID_SAVE_IMAGE, cstr); + + cstr = i18n(L"Menu", L"EDIT_COPY") + L"\tCtrl + Shift + C"; + menu->ModifyMenu(ID_COPY, MF_STRING, ID_COPY, cstr); + + subMenu.Attach(menu->GetSubMenu(1)->GetSafeHmenu()); + cstr = i18n(L"Menu", L"TEST_DATA"); + subMenu.ModifyMenu(0, MF_BYPOSITION, 0, cstr); + subMenu.Detach(); + + cstr = i18n(L"Menu", L"DEFAULT_RANDOM"); + menu->ModifyMenu(ID_MODE_DEFAULT, MF_STRING, ID_MODE_DEFAULT, cstr); + cstr = i18n(L"Menu", L"ALL_ZERO"); + menu->ModifyMenu(ID_MODE_ALL0X00, MF_STRING, ID_MODE_ALL0X00, cstr); + + if (m_TestData == TEST_DATA_ALL0X00) + { + OnModeAll0x00(); + } + else + { + OnModeDefault(); + } + + cstr = i18n(L"Dialog", L"DEFAULT"); + menu->ModifyMenu(ID_SETTING_DEFAULT, MF_STRING, ID_SETTING_DEFAULT, cstr); + + CheckRadioPresetMode(); + + cstr = i18n(L"Menu", L"SETTINGS") + L"\tCtrl + Q"; + menu->ModifyMenu(ID_SETTINGS_QUEUESTHREADS, MF_STRING, ID_SETTINGS_QUEUESTHREADS, cstr); + + cstr = i18n(L"Menu", L"PROFILE_DEFAULT"); + menu->ModifyMenu(ID_PROFILE_DEFAULT, MF_STRING, ID_PROFILE_DEFAULT, cstr); + cstr = i18n(L"Menu", L"PROFILE_PEAK"); + menu->ModifyMenu(ID_PROFILE_PEAK, MF_STRING, ID_PROFILE_PEAK, cstr); + cstr = i18n(L"Menu", L"PROFILE_REAL"); + menu->ModifyMenu(ID_PROFILE_REAL, MF_STRING, ID_PROFILE_REAL, cstr); + cstr = i18n(L"Menu", L"PROFILE_DEMO"); + menu->ModifyMenu(ID_PROFILE_DEMO, MF_STRING, ID_PROFILE_DEMO, cstr); + +#ifdef MIX_MODE + cstr = i18n(L"Menu", L"PROFILE_DEFAULT") + L" [+Mix]"; + menu->ModifyMenu(ID_PROFILE_DEFAULT_MIX, MF_STRING, ID_PROFILE_DEFAULT_MIX, cstr); + cstr = i18n(L"Menu", L"PROFILE_PEAK") + L" [+Mix]"; + menu->ModifyMenu(ID_PROFILE_PEAK_MIX, MF_STRING, ID_PROFILE_PEAK_MIX, cstr); + cstr = i18n(L"Menu", L"PROFILE_REAL") + L" [+Mix]"; + menu->ModifyMenu(ID_PROFILE_REAL_MIX, MF_STRING, ID_PROFILE_REAL_MIX, cstr); +#endif + + cstr = i18n(L"Menu", L"HELP") + L" [Web]" + L"\tF1"; + menu->ModifyMenu(ID_HELP, MF_STRING, ID_HELP, cstr); + cstr = i18n(L"Menu", L"HELP_ABOUT"); + menu->ModifyMenu(ID_ABOUT, MF_STRING, ID_ABOUT, cstr); + + // Theme + subMenu.Attach(menu->GetSubMenu(3)->GetSafeHmenu()); + cstr = i18n(L"Menu", L"ZOOM"); + subMenu.ModifyMenu(0, MF_BYPOSITION, 0, cstr); + subMenu.Detach(); + + cstr = i18n(L"Menu", L"AUTO"); + menu->ModifyMenu(ID_ZOOM_AUTO, MF_STRING, ID_ZOOM_AUTO, cstr); + + cstr = i18n(L"Menu", L"FONT_SETTING") + L"\tCtrl + F"; + menu->ModifyMenu(ID_FONT_SETTING, MF_STRING, ID_FONT_SETTING, cstr); + + CheckRadioZoomType(); + + switch (m_Profile) + { + case PROFILE_DEFAULT: + ProfileDefault(); + break; + case PROFILE_PEAK: + ProfilePeak(); + break; + case PROFILE_REAL: + ProfileReal(); + break; + case PROFILE_DEMO: + ProfileDemo(); + break; +#ifdef MIX_MODE + case PROFILE_DEFAULT_MIX: + ProfileDefaultMix(); + break; + case PROFILE_PEAK_MIX: + ProfilePeakMix(); + break; + case PROFILE_REAL_MIX: + ProfileRealMix(); + break; +#endif + default: + ProfileDefault(); + break; + } + + switch (m_Benchmark) + { + case BENCHMARK_READ_WRITE: + BenchmarkReadWrite(); + break; + case BENCHMARK_READ: + BenchmarkReadOnly(); + break; + case BENCHMARK_WRITE: + BenchmarkWriteOnly(); + break; + default: + BenchmarkReadWrite(); + break; + } + + SetMenu(menu); + + m_MesStopBenchmark = i18n(L"Message", L"STOP_BENCHMARK"); + m_MesDiskCapacityError = i18n(L"Message", L"DISK_CAPACITY_ERROR"); + m_MesDiskCreateFileError = i18n(L"Message", L"DISK_CREATE_FILE_ERROR"); + m_MesDiskWriteError = i18n(L"Message", L"DISK_WRITE_ERROR"); + m_MesDiskReadError = i18n(L"Message", L"DISK_READ_ERROR"); + m_MesDiskSpdNotFound = i18n(L"Message", L"DISK_SPD_NOT_FOUND"); + + UpdateDriveToolTip(); + + WritePrivateProfileString(L"Setting", L"Language", LangName, m_Ini); +} + +BOOL CDiskMarkDlg::OnCommand(WPARAM wParam, LPARAM lParam) +{ + // Select Theme + if (WM_THEME_ID <= wParam && wParam < WM_THEME_ID + (UINT)m_MenuArrayTheme.GetSize()) + { + CMenu menu; + CMenu subMenu; + menu.Attach(GetMenu()->GetSafeHmenu()); + subMenu.Attach(menu.GetSubMenu(MENU_THEME_INDEX)->GetSafeHmenu()); + + m_CurrentTheme = m_MenuArrayTheme.GetAt(wParam - WM_THEME_ID); + if (m_CurrentTheme.Compare(m_RandomThemeLabel) == 0) + { + m_CurrentTheme = GetRandomTheme(); + m_RandomThemeLabel = L"Random"; + m_RandomThemeName = L" (" + m_CurrentTheme + L")"; + + // ChangeTheme save the theme configuration to profile; so if we are on + // Random, then save Random to profile. + ChangeTheme(m_RandomThemeLabel); + } + else + { + ChangeTheme(m_MenuArrayTheme.GetAt(wParam - WM_THEME_ID)); + m_RandomThemeName = L""; + } + + subMenu.ModifyMenu(WM_THEME_ID, MF_STRING, WM_THEME_ID, m_RandomThemeLabel + m_RandomThemeName); + subMenu.CheckMenuRadioItem(WM_THEME_ID, WM_THEME_ID + (UINT)m_MenuArrayTheme.GetSize(), + (UINT)wParam, MF_BYCOMMAND); + subMenu.Detach(); + menu.Detach(); + + if (m_Profile == PROFILE_DEMO && IsFileExist(m_ThemeDir + m_CurrentTheme + L"\\BackgroundDemo-300.png")) + { + m_BackgroundName = L"BackgroundDemo"; + } + else + { + m_BackgroundName = L"Background"; + } + + UpdateThemeInfo(); + UpdateDialogSize(); + + return TRUE; + } + + // Select Language + if(WM_LANGUAGE_ID <= wParam && wParam < WM_LANGUAGE_ID + (UINT)m_MenuArrayLang.GetSize()) + { + CMenu menu; + CMenu subMenu; + CMenu subMenuAN; + CMenu subMenuOZ; + menu.Attach(GetMenu()->GetSafeHmenu()); + subMenu.Attach(menu.GetSubMenu(MENU_LANG_INDEX)->GetSafeHmenu()); + subMenuAN.Attach(subMenu.GetSubMenu(0)->GetSafeHmenu()); + subMenuOZ.Attach(subMenu.GetSubMenu(1)->GetSafeHmenu()); + + m_CurrentLang = m_MenuArrayLang.GetAt(wParam - WM_LANGUAGE_ID); + ChangeLang(m_MenuArrayLang.GetAt(wParam - WM_LANGUAGE_ID)); + subMenuAN.CheckMenuRadioItem(WM_LANGUAGE_ID, WM_LANGUAGE_ID + (UINT)m_MenuArrayLang.GetSize(), + (UINT)wParam, MF_BYCOMMAND); + subMenuOZ.CheckMenuRadioItem(WM_LANGUAGE_ID, WM_LANGUAGE_ID + (UINT)m_MenuArrayLang.GetSize(), + (UINT)wParam, MF_BYCOMMAND); + + subMenuOZ.Detach(); + subMenuAN.Detach(); + subMenu.Detach(); + menu.Detach(); + + UpdateComboTooltip(); + } + + return CMainDialogFx::OnCommand(wParam, lParam); +} + +void CDiskMarkDlg::OnCopy() +{ + SaveText(L""); +} + +void CDiskMarkDlg::OnSaveText() +{ + CString path; + SYSTEMTIME st; + GetLocalTime(&st); + path.Format(L"%s_%04d%02d%02d%02d%02d%02d", PRODUCT_NAME, st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond); + + CString filter = L"TEXT (*.txt)|*.txt||"; + CFileDialog save(FALSE, L"txt", path, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT | OFN_EXPLORER, filter); + + if (save.DoModal() == IDOK) + { + SaveText(save.GetPathName()); + } +} + +void CDiskMarkDlg::OnSaveImage() +{ + SaveImage(); +} + +CString CDiskMarkDlg::GetResultString(int type, double score, double latency, int size, int queues, int threads) +{ + CString result; + double iops = 0.0; + + iops = score * 1000 * 1000 / ((double)size * 1024); + if (latency < 0.0) + { + latency = 0.0; + } + + if (type == BENCH_RND) + { + if (size >= 1024) + { + result.Format(L" RND %4dMiB (Q=%3d, T=%2d): %9.3f MB/s [%9.1f IOPS] <%9.2f us>", size / 1024, queues, threads, score, iops, latency); + } + else + { + result.Format(L" RND %4dKiB (Q=%3d, T=%2d): %9.3f MB/s [%9.1f IOPS] <%9.2f us>", size, queues, threads, score, iops, latency); + } + } + else + { + if (size >= 1024) + { + result.Format(L" SEQ %4dMiB (Q=%3d, T=%2d): %9.3f MB/s [%9.1f IOPS] <%9.2f us>", size / 1024, queues, threads, score, iops, latency); + } + else + { + result.Format(L" SEQ %4dKiB (Q=%3d, T=%2d): %9.3f MB/s [%9.1f IOPS] <%9.2f us>", size, queues, threads, score, iops, latency); + } + } + + return result; +} + +void CDiskMarkDlg::SaveText(CString fileName) +{ + CString cstr, clip; + + UpdateData(TRUE); + + if (m_Profile == PROFILE_DEMO) + { + clip = L"\ +------------------------------------------------------------------------------\r\n\ +%PRODUCT% %VERSION%%EDITION% (C) %COPY_YEAR% hiyohiyo\r\n\ + Crystal Dew World: https://crystalmark.info/\r\n\ +------------------------------------------------------------------------------\r\n\ +* MB/s = 1,000,000 bytes/s [SATA/600 = 600,000,000 bytes/s]\r\n\ +* KB = 1000 bytes, KiB = 1024 bytes\r\n\ +\r\n\ +[Read]\r\n\ +%BenchRead1%\r\n\ +\r\n\ +[Write]\r\n\ +%BenchWrite1%\r\n\ +\r\n\ +Profile: Demo\r\n\ + Test: %TestSize% (x%TestCount%)%Capacity%\r\n\ + Mode:%TestMode%\r\n\ + Time: Measure %MeasureTime% / Interval %IntervalTime% \r\n\ + Date: %Date%\r\n\ + OS: %OS%\r\n\ +%Comment%"; + } + else if (m_Profile == PROFILE_DEFAULT || m_Profile == PROFILE_DEFAULT_MIX) + { + clip = L"\ +------------------------------------------------------------------------------\r\n\ +%PRODUCT% %VERSION%%EDITION% (C) %COPY_YEAR% hiyohiyo\r\n\ + Crystal Dew World: https://crystalmark.info/\r\n\ +------------------------------------------------------------------------------\r\n\ +* MB/s = 1,000,000 bytes/s [SATA/600 = 600,000,000 bytes/s]\r\n\ +* KB = 1000 bytes, KiB = 1024 bytes\r\n\ +\r\n\ +[Read]\r\n\ +%BenchRead1%\r\n\ +%BenchRead2%\r\n\ +%BenchRead3%\r\n\ +%BenchRead4%\r\n\ +\r\n\ +[Write]\r\n\ +%BenchWrite1%\r\n\ +%BenchWrite2%\r\n\ +%BenchWrite3%\r\n\ +%BenchWrite4%\r\n\ +\r\n\ +"; + +#ifdef MIX_MODE + if (m_MixMode) + { + clip += L"\ +[Mix] %MixRatio%\r\n\ +%BenchMix1%\r\n\ +%BenchMix2%\r\n\ +%BenchMix3%\r\n\ +%BenchMix4%\r\n\ +\r\n\ +"; + } +#endif + + clip += L"\ +Profile: Default\r\n\ + Test: %TestSize% (x%TestCount%)%Capacity%\r\n\ + Mode:%TestMode%\r\n\ + Time: Measure %MeasureTime% / Interval %IntervalTime% \r\n\ + Date: %Date%\r\n\ + OS: %OS%\r\n\ +%Comment%"; + } + else + { + clip = L"\ +------------------------------------------------------------------------------\r\n\ +%PRODUCT% %VERSION%%EDITION% (C) %COPY_YEAR% hiyohiyo\r\n\ + Crystal Dew World: https://crystalmark.info/\r\n\ +------------------------------------------------------------------------------\r\n\ +* MB/s = 1,000,000 bytes/s [SATA/600 = 600,000,000 bytes/s]\r\n\ +* KB = 1000 bytes, KiB = 1024 bytes\r\n\ +\r\n\ +[Read]\r\n\ +%SequentialRead1%\r\n\ +%RandomRead1%\r\n\ +\r\n\ +[Write]\r\n\ +%SequentialWrite1%\r\n\ +%RandomWrite1%\r\n\ +\r\n\ +"; + +#ifdef MIX_MODE + if (m_MixMode) + { + clip += L"\ +[Mix] %MixRatio%\r\n\ +%SequentialMix1%\r\n\ +%RandomMix1%\r\n\ +\r\n\ +"; + } +#endif + + if (m_Profile == PROFILE_PEAK || m_Profile == PROFILE_PEAK_MIX) + { + clip += L"\ +Profile: Peak\r\n\ +"; + } + else + { + clip += L"\ +Profile: Real\r\n\ +"; + } + + clip += L"\ + Test: %TestSize% (x%TestCount%)%Capacity%\r\n\ + Mode:%TestMode%\r\n\ + Time: Measure %MeasureTime% / Interval %IntervalTime% \r\n\ + Date: %Date%\r\n\ + OS: %OS%\r\n\ +%Comment%"; + } + + clip.Replace(L"%PRODUCT%", PRODUCT_NAME); + clip.Replace(L"%VERSION%", PRODUCT_VERSION); + + cstr = PRODUCT_EDITION; + if(! cstr.IsEmpty()) + { + clip.Replace(L"%EDITION%", L" " PRODUCT_EDITION); + } + else + { + clip.Replace(L"%EDITION%", PRODUCT_EDITION); + } + clip.Replace(L"%COPY_YEAR%", PRODUCT_COPY_YEAR); + + double iops = 0.0; + double latency = 0.0; + + if (m_Profile == PROFILE_DEMO) + { + clip.Replace(L"%BenchRead1%", GetResultString(m_BenchType[8], m_ReadScore[8], m_ReadLatency[8], m_BenchSize[8], m_BenchQueues[8], m_BenchThreads[8])); + clip.Replace(L"%BenchWrite1%", GetResultString(m_BenchType[8], m_WriteScore[8], m_WriteLatency[8], m_BenchSize[8], m_BenchQueues[8], m_BenchThreads[8])); + + } + else if (m_Profile == PROFILE_PEAK || m_Profile == PROFILE_PEAK_MIX) + { + clip.Replace(L"%SequentialRead1%", GetResultString(BENCH_SEQ, m_ReadScore[4], m_ReadLatency[4], m_BenchSize[4], m_BenchQueues[4], m_BenchThreads[4])); + clip.Replace(L"%SequentialWrite1%", GetResultString(BENCH_SEQ, m_WriteScore[4], m_WriteLatency[4], m_BenchSize[4], m_BenchQueues[4], m_BenchThreads[4])); + clip.Replace(L"%RandomRead1%", GetResultString(BENCH_RND, m_ReadScore[5], m_ReadLatency[5], m_BenchSize[5], m_BenchQueues[5], m_BenchThreads[5])); + clip.Replace(L"%RandomWrite1%", GetResultString(BENCH_RND, m_WriteScore[5], m_WriteLatency[5], m_BenchSize[5], m_BenchQueues[5], m_BenchThreads[5])); + +#ifdef MIX_MODE + if (m_MixMode) + { + clip.Replace(L"%SequentialMix1%", GetResultString(BENCH_SEQ, m_MixScore[4], m_MixLatency[4], m_BenchSize[4], m_BenchQueues[4], m_BenchThreads[4])); + clip.Replace(L"%RandomMix1%", GetResultString(BENCH_RND, m_MixScore[5], m_MixLatency[5], m_BenchSize[5], m_BenchQueues[5], m_BenchThreads[5])); + cstr.Format(L"Read %d%%/Write %d%%", 100 - m_MixRatio, m_MixRatio); + clip.Replace(L"%MixRatio%", cstr); + } +#endif + } + else if (m_Profile == PROFILE_REAL || m_Profile == PROFILE_REAL_MIX) + { + clip.Replace(L"%SequentialRead1%", GetResultString(BENCH_SEQ, m_ReadScore[6], m_ReadLatency[6], 1024, 1, 1)); + clip.Replace(L"%SequentialWrite1%", GetResultString(BENCH_SEQ, m_WriteScore[6], m_WriteLatency[6], 1024, 1, 1)); + clip.Replace(L"%RandomRead1%", GetResultString(BENCH_RND, m_ReadScore[7], m_ReadLatency[7], 4, 1, 1)); + clip.Replace(L"%RandomWrite1%", GetResultString(BENCH_RND, m_WriteScore[7], m_WriteLatency[7], 4, 1, 1)); + +#ifdef MIX_MODE + if (m_MixMode) + { + clip.Replace(L"%SequentialMix1%", GetResultString(BENCH_SEQ, m_MixScore[6], m_MixLatency[6], 1024, 1, 1)); + clip.Replace(L"%RandomMix1%", GetResultString(BENCH_RND, m_MixScore[7], m_MixLatency[7], 4, 1, 1)); + cstr.Format(L"Read %d%%/Write %d%%", 100 - m_MixRatio, m_MixRatio); + clip.Replace(L"%MixRatio%", cstr); + } +#endif + } + + else + { + clip.Replace(L"%BenchRead1%", GetResultString(m_BenchType[0], m_ReadScore[0], m_ReadLatency[0], m_BenchSize[0], m_BenchQueues[0], m_BenchThreads[0])); + clip.Replace(L"%BenchRead2%", GetResultString(m_BenchType[1], m_ReadScore[1], m_ReadLatency[1], m_BenchSize[1], m_BenchQueues[1], m_BenchThreads[1])); + clip.Replace(L"%BenchRead3%", GetResultString(m_BenchType[2], m_ReadScore[2], m_ReadLatency[2], m_BenchSize[2], m_BenchQueues[2], m_BenchThreads[2])); + clip.Replace(L"%BenchRead4%", GetResultString(m_BenchType[3], m_ReadScore[3], m_ReadLatency[3], m_BenchSize[3], m_BenchQueues[3], m_BenchThreads[3])); + + clip.Replace(L"%BenchWrite1%", GetResultString(m_BenchType[0], m_WriteScore[0], m_WriteLatency[0], m_BenchSize[0], m_BenchQueues[0], m_BenchThreads[0])); + clip.Replace(L"%BenchWrite2%", GetResultString(m_BenchType[1], m_WriteScore[1], m_WriteLatency[1], m_BenchSize[1], m_BenchQueues[1], m_BenchThreads[1])); + clip.Replace(L"%BenchWrite3%", GetResultString(m_BenchType[2], m_WriteScore[2], m_WriteLatency[2], m_BenchSize[2], m_BenchQueues[2], m_BenchThreads[2])); + clip.Replace(L"%BenchWrite4%", GetResultString(m_BenchType[3], m_WriteScore[3], m_WriteLatency[3], m_BenchSize[3], m_BenchQueues[3], m_BenchThreads[3])); + +#ifdef MIX_MODE + if (m_MixMode) + { + clip.Replace(L"%BenchMix1%", GetResultString(m_BenchType[0], m_MixScore[0], m_MixLatency[0], m_BenchSize[0], m_BenchQueues[0], m_BenchThreads[0])); + clip.Replace(L"%BenchMix2%", GetResultString(m_BenchType[1], m_MixScore[1], m_MixLatency[1], m_BenchSize[1], m_BenchQueues[1], m_BenchThreads[1])); + clip.Replace(L"%BenchMix3%", GetResultString(m_BenchType[2], m_MixScore[2], m_MixLatency[2], m_BenchSize[2], m_BenchQueues[2], m_BenchThreads[2])); + clip.Replace(L"%BenchMix4%", GetResultString(m_BenchType[3], m_MixScore[3], m_MixLatency[3], m_BenchSize[3], m_BenchQueues[3], m_BenchThreads[3])); + + cstr.Format(L"Read %d%%/Write %d%%", 100 - m_MixRatio, m_MixRatio); + clip.Replace(L"%MixRatio%", cstr); + } +#endif + } + + if (m_ValueTestSize.Find(L"MiB") == -1) + { + cstr.Format(L"%d GiB", _tstoi(m_ValueTestSize)); + } + else + { + cstr.Format(L"%d MiB", _tstoi(m_ValueTestSize)); + } + + clip.Replace(L"%TestSize%", cstr); + cstr.Format(L"%d", _tstoi(m_ValueTestCount)); + clip.Replace(L"%TestCount%", cstr); + + cstr = L""; + if (m_AdminMode){ cstr += L" [Admin]"; } + if (m_TestData) { cstr += L" <0Fill>"; } + clip.Replace(L"%TestMode%", cstr); + + m_Comment.GetWindowText(cstr); + if (cstr.IsEmpty()) + { + clip.Replace(L"%Comment%", L""); + }else + { + clip.Replace(L"%Comment%", L"Comment: " + cstr + L"\r\n"); + } + + cstr.Format(L"%d sec", m_IntervalTime); + clip.Replace(L"%IntervalTime%", cstr); + cstr.Format(L"%d sec", m_MeasureTime); + clip.Replace(L"%MeasureTime%", cstr); + + CString null; + GetOsName(cstr, null, null, null); + clip.Replace(L"%OS%", cstr); + + SYSTEMTIME st; + GetLocalTime(&st); + cstr.Format(L"%04d/%02d/%02d %d:%02d:%02d", st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond); + clip.Replace(L"%Date%", cstr); + + if (m_ValueTestDrive.FindOneOf(L":") != -1) + { + clip.Replace(L"%Capacity%", L" [" + m_ValueTestDrive + L"]"); + } + else + { + clip.Replace(L"%Capacity%", L""); + } + + if (fileName.IsEmpty()) + { + if (OpenClipboard()) + { + HGLOBAL clipbuffer; + TCHAR* buffer; + EmptyClipboard(); + clipbuffer = GlobalAlloc(GMEM_DDESHARE, sizeof(TCHAR) * (clip.GetLength() + 1)); + if (clipbuffer != NULL) + { + buffer = (TCHAR*)GlobalLock(clipbuffer); + if (buffer == NULL) + { + GlobalFree(clipbuffer); + CloseClipboard(); + return; + } + else + { + _tcscpy_s(buffer, clip.GetLength() + 1, LPCTSTR(clip)); + GlobalUnlock(clipbuffer); + SetClipboardData(CF_UNICODETEXT, clipbuffer); + } + } + CloseClipboard(); + } + } + else + { + CT2A utf8(clip, CP_UTF8); + + CFile file; + if (file.Open(fileName, CFile::modeCreate | CFile::modeWrite)) + { + file.Write((char*)utf8, (UINT)strlen(utf8)); + file.Close(); + } + } +} + +void CDiskMarkDlg::OnZoom100() +{ + if (CheckRadioZoomType(ID_ZOOM_100, 100)) + { + UpdateDialogSize(); + } +} + +void CDiskMarkDlg::CheckRadioPresetMode() +{ + if (IsDefaultMode()) + { + CMenu* menu = GetMenu(); + menu->CheckMenuRadioItem(ID_SETTING_DEFAULT, ID_SETTING_FLASH_MEMORY, ID_SETTING_DEFAULT, MF_BYCOMMAND); + SetMenu(menu); + DrawMenuBar(); + } + else if (IsNVMe8Mode()) + { + CMenu* menu = GetMenu(); + menu->CheckMenuRadioItem(ID_SETTING_DEFAULT, ID_SETTING_FLASH_MEMORY, ID_SETTING_NVME_8, MF_BYCOMMAND); + SetMenu(menu); + DrawMenuBar(); + } + + else if (IsFlashMemoryMode()) + { + CMenu* menu = GetMenu(); + menu->CheckMenuRadioItem(ID_SETTING_DEFAULT, ID_SETTING_FLASH_MEMORY, ID_SETTING_FLASH_MEMORY, MF_BYCOMMAND); + SetMenu(menu); + DrawMenuBar(); + } + else + { + CMenu* menu = GetMenu(); + menu->CheckMenuRadioItem(ID_SETTING_DEFAULT, ID_SETTING_FLASH_MEMORY, 0, MF_BYCOMMAND); + SetMenu(menu); + DrawMenuBar(); + } +} + +void CDiskMarkDlg::OnZoom125() +{ + if (CheckRadioZoomType(ID_ZOOM_125, 125)) + { + UpdateDialogSize(); + } +} + +void CDiskMarkDlg::OnZoom150() +{ + if (CheckRadioZoomType(ID_ZOOM_150, 150)) + { + UpdateDialogSize(); + } +} + +void CDiskMarkDlg::OnZoom200() +{ + if (CheckRadioZoomType(ID_ZOOM_200, 200)) + { + UpdateDialogSize(); + } +} + +void CDiskMarkDlg::OnZoom250() +{ + if (CheckRadioZoomType(ID_ZOOM_250, 250)) + { + UpdateDialogSize(); + } +} + +void CDiskMarkDlg::OnZoom300() +{ + if (CheckRadioZoomType(ID_ZOOM_300, 300)) + { + UpdateDialogSize(); + } +} + +void CDiskMarkDlg::OnZoomAuto() +{ + if (CheckRadioZoomType(ID_ZOOM_AUTO, 0)) + { + UpdateDialogSize(); + } +} + +BOOL CDiskMarkDlg::CheckRadioZoomType(int id, int value) +{ + if(m_ZoomType == value) + { + return FALSE; + } + + CMenu *menu = GetMenu(); + menu->CheckMenuRadioItem(ID_ZOOM_100, ID_ZOOM_AUTO, id, MF_BYCOMMAND); + SetMenu(menu); + DrawMenuBar(); + + m_ZoomType = value; + + CString cstr; + cstr.Format(L"%d", value); + WritePrivateProfileString(L"Setting", L"ZoomType", cstr, m_Ini); + + ChangeZoomType(m_ZoomType); + + return TRUE; +} + +void CDiskMarkDlg::CheckRadioZoomType() +{ + int id = ID_ZOOM_AUTO; + + switch(m_ZoomType) + { + case 100: id = ID_ZOOM_100; break; + case 125: id = ID_ZOOM_125; break; + case 150: id = ID_ZOOM_150; break; + case 200: id = ID_ZOOM_200; break; + case 250: id = ID_ZOOM_250; break; + case 300: id = ID_ZOOM_300; break; + default: id = ID_ZOOM_AUTO;break; + } + + CMenu *menu = GetMenu(); + menu->CheckMenuRadioItem(ID_ZOOM_100, ID_ZOOM_AUTO, id, MF_BYCOMMAND); + SetMenu(menu); + DrawMenuBar(); +} + +void CDiskMarkDlg::OnHelp() +{ + if (GetUserDefaultLCID() == 0x0411) // Japanese + { + OpenUrl(URL_HELP_JA); + } + else // Other Language + { + OpenUrl(URL_HELP_EN); + } +} + +void CDiskMarkDlg::OnCrystalDewWorld() +{ + if (GetUserDefaultLCID() == 0x0411) // Japanese + { + OpenUrl(URL_CRYSTAL_DEW_WORLD_JA); + } + else // Other Language + { + OpenUrl(URL_CRYSTAL_DEW_WORLD_EN); + } +} + +#ifdef MIX_MODE + #define ID_PROFILE_MAX ID_PROFILE_REAL_MIX +#else + #define ID_PROFILE_MAX ID_PROFILE_DEMO +#endif + +void CDiskMarkDlg::OnSettingDefault() +{ + CMenu* menu = GetMenu(); + menu->CheckMenuRadioItem(ID_SETTING_DEFAULT, ID_SETTING_FLASH_MEMORY, ID_SETTING_DEFAULT, MF_BYCOMMAND); + SetMenu(menu); + DrawMenuBar(); + + SettingsQueuesThreads(0); +} + +void CDiskMarkDlg::OnSettingNVMe8() +{ + CMenu* menu = GetMenu(); + menu->CheckMenuRadioItem(ID_SETTING_DEFAULT, ID_SETTING_FLASH_MEMORY, ID_SETTING_NVME_8, MF_BYCOMMAND); + SetMenu(menu); + DrawMenuBar(); + + SettingsQueuesThreads(1); +} + +void CDiskMarkDlg::OnSettingFlashMemory() +{ + CMenu* menu = GetMenu(); + menu->CheckMenuRadioItem(ID_SETTING_DEFAULT, ID_SETTING_FLASH_MEMORY, ID_SETTING_FLASH_MEMORY, MF_BYCOMMAND); + SetMenu(menu); + DrawMenuBar(); + + SettingsQueuesThreads(2); +} + +void CDiskMarkDlg::OnModeDefault() +{ + CMenu *menu = GetMenu(); + menu->CheckMenuRadioItem(ID_MODE_DEFAULT, ID_MODE_ALL0X00, ID_MODE_DEFAULT, MF_BYCOMMAND); + SetMenu(menu); + DrawMenuBar(); + + m_TestData = TEST_DATA_RANDOM; + WritePrivateProfileString(L"Setting", L"TestData", L"0", m_Ini); + SetWindowTitle(L""); +} + +void CDiskMarkDlg::OnModeAll0x00() +{ + CMenu *menu = GetMenu(); + menu->CheckMenuRadioItem(ID_MODE_DEFAULT, ID_MODE_ALL0X00, ID_MODE_ALL0X00, MF_BYCOMMAND); + SetMenu(menu); + DrawMenuBar(); + + m_TestData = TEST_DATA_ALL0X00; + WritePrivateProfileString(L"Setting", L"TestData", L"1", m_Ini); + SetWindowTitle(L""); +} + +void CDiskMarkDlg::OnProfileDefault() +{ + ShowWindow(SW_HIDE); + ProfileDefault(); + UpdateUnitLabel(); + InitScore(); + UpdateDialogSize(); + ChangeButtonStatus(TRUE); + SetWindowTitle(L""); +} + +void CDiskMarkDlg::ProfileDefault() +{ + CMenu* menu = GetMenu(); + menu->CheckMenuRadioItem(ID_PROFILE_DEFAULT, ID_PROFILE_MAX, ID_PROFILE_DEFAULT, MF_BYCOMMAND); + SetMenu(menu); + DrawMenuBar(); + + m_Profile = PROFILE_DEFAULT; + m_MixMode = FALSE; + WritePrivateProfileString(L"Setting", L"Profile", L"0", m_Ini); + m_BackgroundName = L"Background"; +} + +void CDiskMarkDlg::OnProfilePeak() +{ + ShowWindow(SW_HIDE); + ProfilePeak(); + UpdateUnitLabel(); + InitScore(); + UpdateDialogSize(); + ChangeButtonStatus(TRUE); + SetWindowTitle(L""); +} + +void CDiskMarkDlg::ProfilePeak() +{ + CMenu* menu = GetMenu(); + menu->CheckMenuRadioItem(ID_PROFILE_DEFAULT, ID_PROFILE_MAX, ID_PROFILE_PEAK, MF_BYCOMMAND); + SetMenu(menu); + DrawMenuBar(); + + m_Profile = PROFILE_PEAK; + m_MixMode = FALSE; + WritePrivateProfileString(L"Setting", L"Profile", L"1", m_Ini); + m_BackgroundName = L"Background"; +} + +void CDiskMarkDlg::OnProfileReal() +{ + ShowWindow(SW_HIDE); + ProfileReal(); + UpdateUnitLabel(); + InitScore(); + UpdateDialogSize(); + ChangeButtonStatus(TRUE); + SetWindowTitle(L""); +} + +void CDiskMarkDlg::ProfileReal() +{ + CMenu* menu = GetMenu(); + menu->CheckMenuRadioItem(ID_PROFILE_DEFAULT, ID_PROFILE_MAX, ID_PROFILE_REAL, MF_BYCOMMAND); + SetMenu(menu); + DrawMenuBar(); + + m_Profile = PROFILE_REAL; + m_MixMode = FALSE; + WritePrivateProfileString(L"Setting", L"Profile", L"2", m_Ini); + m_BackgroundName = L"Background"; +} + +void CDiskMarkDlg::OnProfileDemo() +{ + ShowWindow(SW_HIDE); + ProfileDemo(); + UpdateUnitLabel(); + InitScore(); + UpdateDialogSize(); + ChangeButtonStatus(TRUE); + SetWindowTitle(L""); +} + +void CDiskMarkDlg::ProfileDemo() +{ + CMenu* menu = GetMenu(); + menu->CheckMenuRadioItem(ID_PROFILE_DEFAULT, ID_PROFILE_MAX, ID_PROFILE_DEMO, MF_BYCOMMAND); + SetMenu(menu); + DrawMenuBar(); + + m_Profile = PROFILE_DEMO; + m_MixMode = FALSE; + WritePrivateProfileString(L"Setting", L"Profile", L"3", m_Ini); + + if (IsFileExist(m_ThemeDir + m_CurrentTheme + L"\\BackgroundDemo-300.png")) + { + m_BackgroundName = L"BackgroundDemo"; + } + else + { + m_BackgroundName = L"Background"; + } +} + +#ifdef MIX_MODE +void CDiskMarkDlg::OnProfileDefaultMix() +{ + ProfileDefaultMix(); + UpdateUnitLabel(); + InitScore(); + UpdateDialogSize(); + ChangeButtonStatus(TRUE); + SetWindowTitle(L""); +} + +void CDiskMarkDlg::ProfileDefaultMix() +{ + CMenu* menu = GetMenu(); + menu->CheckMenuRadioItem(ID_PROFILE_DEFAULT, ID_PROFILE_REAL_MIX, ID_PROFILE_DEFAULT_MIX, MF_BYCOMMAND); + SetMenu(menu); + DrawMenuBar(); + + m_Profile = PROFILE_DEFAULT_MIX; + m_MixMode = TRUE; + WritePrivateProfileString(L"Setting", L"Profile", L"4", m_Ini); + m_BackgroundName = L"Background"; +} + +void CDiskMarkDlg::OnProfilePeakMix() +{ + ProfilePeakMix(); + ChangeButtonStatus(TRUE); + UpdateUnitLabel(); + InitScore(); + UpdateDialogSize(); + SetWindowTitle(L""); +} + +void CDiskMarkDlg::ProfilePeakMix() +{ + CMenu* menu = GetMenu(); + menu->CheckMenuRadioItem(ID_PROFILE_DEFAULT, ID_PROFILE_REAL_MIX, ID_PROFILE_PEAK_MIX, MF_BYCOMMAND); + SetMenu(menu); + DrawMenuBar(); + + m_Profile = PROFILE_PEAK_MIX; + m_MixMode = TRUE; + WritePrivateProfileString(L"Setting", L"Profile", L"5", m_Ini); + m_BackgroundName = L"Background"; +} + +void CDiskMarkDlg::OnProfileRealMix() +{ + ProfileRealMix(); + ChangeButtonStatus(TRUE); + UpdateUnitLabel(); + InitScore(); + UpdateDialogSize(); + SetWindowTitle(L""); +} + +void CDiskMarkDlg::ProfileRealMix() +{ + CMenu* menu = GetMenu(); + menu->CheckMenuRadioItem(ID_PROFILE_DEFAULT, ID_PROFILE_REAL_MIX, ID_PROFILE_REAL_MIX, MF_BYCOMMAND); + SetMenu(menu); + DrawMenuBar(); + + m_Profile = PROFILE_REAL_MIX; + m_MixMode = TRUE; + WritePrivateProfileString(L"Setting", L"Profile", L"6", m_Ini); + m_BackgroundName = L"Background"; +} +#endif + +void CDiskMarkDlg::OnBenchmarkReadWrite() +{ + BenchmarkReadWrite(); +} + +void CDiskMarkDlg::BenchmarkReadWrite() +{ + CMenu* menu = GetMenu(); + menu->CheckMenuRadioItem(ID_BENCHMARK_READ_WRITE, ID_BENCHMARK_WRITE_ONLY, ID_BENCHMARK_READ_WRITE, MF_BYCOMMAND); + SetMenu(menu); + DrawMenuBar(); + + m_Benchmark = BENCHMARK_READ_WRITE; + WritePrivateProfileString(L"Setting", L"Benchmark", L"3", m_Ini); +} + +void CDiskMarkDlg::OnBenchmarkReadOnly() +{ + BenchmarkReadOnly(); +} + +void CDiskMarkDlg::BenchmarkReadOnly() +{ + CMenu* menu = GetMenu(); + menu->CheckMenuRadioItem(ID_BENCHMARK_READ_WRITE, ID_BENCHMARK_WRITE_ONLY, ID_BENCHMARK_READ_ONLY, MF_BYCOMMAND); + SetMenu(menu); + DrawMenuBar(); + + m_Benchmark = BENCHMARK_READ; + WritePrivateProfileString(L"Setting", L"Benchmark", L"1", m_Ini); +} + +void CDiskMarkDlg::OnBenchmarkWriteOnly() +{ + BenchmarkWriteOnly(); +} + +void CDiskMarkDlg::BenchmarkWriteOnly() +{ + CMenu* menu = GetMenu(); + menu->CheckMenuRadioItem(ID_BENCHMARK_READ_WRITE, ID_BENCHMARK_WRITE_ONLY, ID_BENCHMARK_WRITE_ONLY, MF_BYCOMMAND); + SetMenu(menu); + DrawMenuBar(); + + m_Benchmark = BENCHMARK_WRITE; + WritePrivateProfileString(L"Setting", L"Benchmark", L"2", m_Ini); +} + +void CDiskMarkDlg::OnSettingsQueuesThreads() +{ + if (! m_DiskBenchStatus) + { + CSettingsDlg* dlg = new CSettingsDlg(this); + dlg->DoModal(); + UpdateQueuesThreads(); + ChangeButtonStatus(TRUE); + + UpdateData(FALSE); + + delete dlg; + } +} + +void CDiskMarkDlg::OnFontSetting() +{ + CFontSelectionDlg fontSelection(this); + if (fontSelection.DoModal() == IDOK) + { + m_FontFace = fontSelection.GetFontFace(); + m_FontScale = fontSelection.GetFontScale(); + m_FontRatio = m_FontScale / 100.0; + m_FontRender = fontSelection.GetFontRender(); + + CString cstr; + WritePrivateProfileString(L"Setting", L"FontFace", L"\"" + m_FontFace + L"\"", m_Ini); + cstr.Format(L"%d", m_FontScale); + WritePrivateProfileString(L"Setting", L"FontScale", cstr, m_Ini); + cstr.Format(L"%d", m_FontRender); + WritePrivateProfileString(L"Setting", L"FontRender", cstr, m_Ini); + + UpdateDialogSize(); + } +} + +void CDiskMarkDlg::OnCbnSelchangeComboDrive() +{ + SelectDrive(); +} + +void CDiskMarkDlg::OnCbnSelchangeComboUnit() +{ + UpdateScore(); + UpdateUnitLabel(); +} + +#ifdef MIX_MODE +void CDiskMarkDlg::OnCbnSelchangeComboMix() +{ + UpdateData(TRUE); + + m_MixRatio = (9 - m_IndexTestMix) * 10; + + CString cstr; + cstr.Format(L"%d", m_MixRatio); + WritePrivateProfileString(L"Setting", L"TestMix", cstr, m_Ini); +} +#endif + +void CDiskMarkDlg::UpdateUnitLabel() +{ + if (m_Profile == PROFILE_DEMO) + { + if (m_IndexTestUnit == SCORE_UNIT::SCORE_IOPS) + { + m_TestRead0.SetLabelUnit(L"Read", L"IOPS"); + m_TestWrite0.SetLabelUnit(L"Write", L"IOPS"); + } + else if (m_IndexTestUnit == SCORE_UNIT::SCORE_US) + { + if (m_ReadLatency[8] >= 1000000) + { + m_TestRead0.SetLabelUnit(L"Read", L"ms"); + } + else + { + m_TestRead0.SetLabelUnit(L"Read", L"μs"); + } + + if (m_WriteLatency[8] >= 1000000) + { + m_TestWrite0.SetLabelUnit(L"Write", L"ms"); + } + else + { + m_TestWrite0.SetLabelUnit(L"Write", L"μs"); + } + } + else if (m_IndexTestUnit == SCORE_UNIT::SCORE_GBS) + { + m_TestRead0.SetLabelUnit(L"Read", L"GB/s"); + m_TestWrite0.SetLabelUnit(L"Write", L"GB/s"); + } + else + { + m_TestRead0.SetLabelUnit(L"Read", L"MB/s"); + m_TestWrite0.SetLabelUnit(L"Write", L"MB/s"); + } + } + else + { + m_TestRead0.SetLabelUnit(L"", L""); + m_TestWrite0.SetLabelUnit(L"", L""); + } + + m_TestRead0.Invalidate(); + m_TestWrite0.Invalidate(); + + if (m_Profile == PROFILE_REAL || m_Profile == PROFILE_REAL_MIX) + { + m_ReadUnit.SetWindowTextW(L"Read (MB/s)"); + m_WriteUnit.SetWindowTextW(L"Write (MB/s)"); +#ifdef MIX_MODE + m_MixUnit.SetWindowTextW(L"Mix (MB/s)"); +#endif + return; + } + else if (m_Profile == PROFILE_PEAK || m_Profile == PROFILE_PEAK_MIX) + { + m_ReadUnit.SetWindowTextW(L"Read (MB/s)"); + m_WriteUnit.SetWindowTextW(L"Write (MB/s)"); +#ifdef MIX_MODE + m_MixUnit.SetWindowTextW(L"Mix (MB/s)"); +#endif + return; + } + + if (m_IndexTestUnit == SCORE_UNIT::SCORE_IOPS) + { + m_ReadUnit.SetWindowTextW(L"Read (IOPS)"); + m_WriteUnit.SetWindowTextW(L"Write (IOPS)"); +#ifdef MIX_MODE + m_MixUnit.SetWindowTextW(L"Mix (IOPS)"); +#endif + } + else if (m_IndexTestUnit == SCORE_UNIT::SCORE_US) + { + m_ReadUnit.SetWindowTextW(L"Read (μs)"); + m_WriteUnit.SetWindowTextW(L"Write (μs)"); +#ifdef MIX_MODE + m_MixUnit.SetWindowTextW(L"Mix (μs)"); +#endif + } + else if (m_IndexTestUnit == SCORE_UNIT::SCORE_GBS) + { + m_ReadUnit.SetWindowTextW(L"Read (GB/s)"); + m_WriteUnit.SetWindowTextW(L"Write (GB/s)"); +#ifdef MIX_MODE + m_MixUnit.SetWindowTextW(L"Mix (GB/s)"); +#endif + } + else + { + m_ReadUnit.SetWindowTextW(L"Read (MB/s)"); + m_WriteUnit.SetWindowTextW(L"Write (MB/s)"); +#ifdef MIX_MODE + m_MixUnit.SetWindowTextW(L"Mix (MB/s)"); +#endif + } +} + +void CDiskMarkDlg::SetWindowTitle(CString message) +{ + CString title; + + if (!message.IsEmpty()) + { + title.Format(L"%s", message.GetString()); + } + else + { + title.Format(L"%s %s %s", PRODUCT_NAME, PRODUCT_VERSION, PRODUCT_EDITION); + } + + if (m_AdminMode) + { + title += L" [Admin]"; + } + + if (m_TestData == TEST_DATA_ALL0X00) + { + title += L" <0Fill>"; + } + + SetWindowText(L" " + title + L" "); +} + +void CDiskMarkDlg::OnLButtonDown(UINT nFlags, CPoint point) +{ + // Move Focus to Hide Control + GetDlgItem(IDC_HIDE)->SetFocus(); + + CMainDialogFx::OnLButtonDown(nFlags, point); +} \ No newline at end of file diff --git a/CristalDiskMark/source/CrystalDiskMark/DiskMarkDlg.h b/CristalDiskMark/source/CrystalDiskMark/DiskMarkDlg.h new file mode 100644 index 0000000..46d5a1a --- /dev/null +++ b/CristalDiskMark/source/CrystalDiskMark/DiskMarkDlg.h @@ -0,0 +1,292 @@ +/*---------------------------------------------------------------------------*/ +// Author : hiyohiyo +// Mail : hiyohiyo@crystalmark.info +// Web : https://crystalmark.info/ +// License : MIT License +/*---------------------------------------------------------------------------*/ + +#pragma once + +#include "AboutDlg.h" +#include "SettingsDlg.h" +#include "FontSelectionDlg.h" + +#include "DialogFx.h" +#include "MainDialogFx.h" +#include "ButtonFx.h" +#include "StaticFx.h" +#include "ComboBoxFx.h" +#include "EditFx.h" +#include "UtilityFx.h" +#include "OsInfoFx.h" +#include "DarkMode.h" + +class CDiskMarkDlg : public CMainDialogFx +{ +public: + CDiskMarkDlg(CWnd* pParent = NULL); + ~CDiskMarkDlg(); + + enum { IDD = IDD_DISKMARK_DIALOG }; + + enum SCORE_UNIT + { + SCORE_MBS = 0, + SCORE_GBS, + SCORE_IOPS, + SCORE_US, + }; + + enum BENCH_TYPE + { + BENCH_SEQ = 0, + BENCH_RND, + }; + + volatile CWinThread* m_WinThread; + volatile BOOL m_DiskBenchStatus; + + void InitScore(); + void UpdateScore(); + + double m_ReadScore[9]; + double m_WriteScore[9]; + double m_ReadLatency[9]; + double m_WriteLatency[9]; + +#ifdef MIX_MODE + double m_MixScore[9]; + double m_MixLatency[9]; +#endif + + void SetMeter(CStaticFx* control, double score, double latency, int blockSize, int unit); + void ChangeLang(CString LangName); + void UpdateDialogSize(); + void ChangeButtonStatus(BOOL status); + void SetScoreToolTip(CStaticFx* cx, double score, double latency, int blockSize); + void UpdateThemeInfo(); + + CString m_ValueTestUnit; + CString m_ValueTestCount; + CString m_ValueTestSize; + CString m_ValueTestDrive; + CString m_TestDriveInfo; + CString m_TestTargetPath; + long m_TestDriveLetter; + + int m_MaxIndexTestDrive; + int m_IndexTestUnit; + int m_IndexTestCount; + int m_IndexTestSize; + int m_IndexTestDrive; + int m_IndexTestMix; + + int m_BenchType[9]; + int m_BenchSize[9]; + int m_BenchQueues[9]; + int m_BenchThreads[9]; + int m_IntervalTime; + int m_MeasureTime; + + int m_TestData; + int m_Profile; + int m_Benchmark; + + int m_MarginButtonTop; + int m_MarginButtonLeft; + int m_MarginButtonBottom; + int m_MarginButtonRight; + int m_MarginMeterTop; + int m_MarginMeterLeft; + int m_MarginMeterBottom; + int m_MarginMeterRight; + int m_MarginCommentTop; + int m_MarginCommentLeft; + int m_MarginCommentBottom; + int m_MarginCommentRight; + int m_MarginDemoTop; + int m_MarginDemoLeft; + int m_MarginDemoBottom; + int m_MarginDemoRight; + + BOOL m_AdminMode; + BOOL m_MixMode; + int m_MixRatio; + + // Message // + CString m_MesDiskCapacityError; + CString m_MesDiskWriteError; + CString m_MesDiskReadError; + CString m_MesStopBenchmark; + CString m_MesDiskCreateFileError; + CString m_MesDiskSpdNotFound; + + void SetWindowTitle(CString message); + +protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + + void OnAll(); + void OnTest0(); + void OnTest1(); + void OnTest2(); + void OnTest3(); + void Stop(); + void OnSequentialPeak(); + void OnRandomPeak(); + void OnSequentialReal(); + void OnRandomReal(); + + void SelectDrive(); + CString GetResultString(int type, double score, double latency, int size, int queues, int threads); + CString GetButtonText(int type, int size, int queues, int threads, int unit); + CString GetButtonToolTipText(int type, int size, int queues, int threads, int unit); + + CString m_TitleTestDrive; + CString m_TitleTestCount; + CString m_TitleTestSize; + CString m_TitleTestQSize; + +protected: + HICON m_hIcon; + HICON m_hIconMini; + HACCEL m_hAccelerator; + + int m_SizeX; + int m_SizeY; + + CAboutDlg* m_AboutDlg; + CSettingsDlg* m_SettingsDlg; + + void SetControlFont(); + void InitDrive(); + void UpdateDriveToolTip(); + + BOOL CheckRadioZoomType(int id, int value); + void CheckRadioZoomType(); + void CheckRadioPresetMode(); + void UpdateQueuesThreads(); + + void EnableMenus(); + void DisableMenus(); + + void SaveText(CString fileName); + + void SetLayeredWindow(HWND hWnd, BYTE alpha); + void UpdateComboTooltip(); + + virtual BOOL CheckThemeEdition(CString name); + + BOOL IsDefaultMode(); + BOOL IsNVMe8Mode(); + BOOL IsFlashMemoryMode(); + +#ifdef MIX_MODE + CStaticFx m_TestMix0; + CStaticFx m_TestMix1; + CStaticFx m_TestMix2; + CStaticFx m_TestMix3; + CStaticFx m_MixUnit; + CComboBoxFx m_ComboMix; +#endif + + CButtonFx m_ButtonAll; + CButtonFx m_ButtonTest0; + CButtonFx m_ButtonTest1; + CButtonFx m_ButtonTest2; + CButtonFx m_ButtonTest3; + + CStaticFx m_TestRead0; + CStaticFx m_TestRead1; + CStaticFx m_TestRead2; + CStaticFx m_TestRead3; + + CStaticFx m_TestWrite0; + CStaticFx m_TestWrite1; + CStaticFx m_TestWrite2; + CStaticFx m_TestWrite3; + + CEditFx m_Comment; + + CComboBoxFx m_ComboCount; + CComboBoxFx m_ComboSize; + CComboBoxFx m_ComboDrive; + CComboBoxFx m_ComboUnit; + + CStaticFx m_WriteUnit; + CStaticFx m_ReadUnit; + CStaticFx m_DemoSetting; + + virtual BOOL OnInitDialog(); + virtual void OnOK(); + virtual void OnCancel(); + virtual BOOL OnCommand(WPARAM wParam, LPARAM lParam); + virtual BOOL PreTranslateMessage(MSG* pMsg); + + afx_msg void OnPaint(); + afx_msg HCURSOR OnQueryDragIcon(); + afx_msg LRESULT OnUpdateScore(WPARAM wParam, LPARAM lParam); + afx_msg LRESULT OnUpdateMessage(WPARAM wParam, LPARAM lParam); + afx_msg LRESULT OnExitBenchmark(WPARAM wParam, LPARAM lParam); + afx_msg void OnZoom100(); + afx_msg void OnZoom125(); + afx_msg void OnZoom150(); + afx_msg void OnZoom200(); + afx_msg void OnZoom250(); + afx_msg void OnZoom300(); + afx_msg void OnZoomAuto(); + + afx_msg void OnExit(); + afx_msg void OnAbout(); + afx_msg void OnFontSetting(); + + LRESULT OnQueryEndSession(WPARAM wParam, LPARAM lParam); + + DECLARE_MESSAGE_MAP() + +public: + afx_msg void OnCopy(); + afx_msg void OnHelp(); + afx_msg void OnCrystalDewWorld(); + afx_msg void OnModeDefault(); + afx_msg void OnModeAll0x00(); + afx_msg void OnSettingDefault(); + afx_msg void OnSettingNVMe8(); + afx_msg void OnSettingFlashMemory(); + + afx_msg void OnProfileDefault(); + afx_msg void OnProfilePeak(); + afx_msg void OnProfileReal(); + afx_msg void OnProfileDemo(); + afx_msg void OnSaveText(); + afx_msg void OnSaveImage(); + afx_msg void OnSettingsQueuesThreads(); + afx_msg void OnCbnSelchangeComboDrive(); + afx_msg void OnCbnSelchangeComboUnit(); + afx_msg void UpdateUnitLabel(); + afx_msg void OnLButtonDown(UINT nFlags, CPoint point); + + void ProfileDefault(); + void ProfilePeak(); + void ProfileReal(); + void ProfileDemo(); + + void SettingsQueuesThreads(int type); + +#ifdef MIX_MODE + afx_msg void OnProfileDefaultMix(); + afx_msg void OnProfilePeakMix(); + afx_msg void OnProfileRealMix(); + void ProfileDefaultMix(); + void ProfilePeakMix(); + void ProfileRealMix(); + afx_msg void OnCbnSelchangeComboMix(); +#endif + + afx_msg void OnBenchmarkReadWrite(); + afx_msg void OnBenchmarkReadOnly(); + afx_msg void OnBenchmarkWriteOnly(); + void BenchmarkReadWrite(); + void BenchmarkReadOnly(); + void BenchmarkWriteOnly(); +}; diff --git a/CristalDiskMark/source/CrystalDiskMark/FontSelectionDlg.cpp b/CristalDiskMark/source/CrystalDiskMark/FontSelectionDlg.cpp new file mode 100644 index 0000000..4172419 --- /dev/null +++ b/CristalDiskMark/source/CrystalDiskMark/FontSelectionDlg.cpp @@ -0,0 +1,243 @@ +/*---------------------------------------------------------------------------*/ +// Author : hiyohiyo +// Mail : hiyohiyo@crystalmark.info +// Web : https://crystalmark.info/ +// License : MIT License +/*---------------------------------------------------------------------------*/ + +#include "stdafx.h" +#include "DiskMark.h" +#include "DiskMarkDlg.h" +#include "FontSelectionDlg.h" + +int CALLBACK EnumFontFamExProc(ENUMLOGFONTEX *lpelfe, NEWTEXTMETRICEX *lpntme, int FontType, LPARAM lParam); + +IMPLEMENT_DYNAMIC(CFontSelectionDlg, CDialog) + +CFontSelectionDlg::CFontSelectionDlg(CWnd* pParent) + : CDialogFx(CFontSelectionDlg::IDD, pParent) +{ + CMainDialogFx* p = (CMainDialogFx*)pParent; + + m_ZoomType = p->GetZoomType(); + m_FontScale = p->GetFontScale(); + m_FontRatio = 1.0; // p->GetFontRatio(); + m_FontFace = p->GetFontFace(); + m_FontRender = p->GetFontRender(); + m_CurrentLangPath = p->GetCurrentLangPath(); + m_DefaultLangPath = p->GetDefaultLangPath(); + m_ThemeDir = p->GetThemeDir(); + m_CurrentTheme = p->GetCurrentTheme(); + m_DefaultTheme = p->GetDefaultTheme(); + m_Ini = p->GetIniPath(); + + m_BackgroundName = L""; +} + +CFontSelectionDlg::~CFontSelectionDlg() +{ +} + +void CFontSelectionDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + DDX_Control(pDX, IDC_OK, m_CtrlOk); + DDX_Control(pDX, IDC_FONT_FACE, m_LabelFontFace); + DDX_Control(pDX, IDC_FONT_SCALE, m_LabelFontScale); + DDX_Control(pDX, IDC_FONT_RENDER, m_LabelFontRender); + DDX_Control(pDX, IDC_FONT_FACE_COMBO, m_CtrlFontFace); + DDX_Control(pDX, IDC_FONT_SCALE_COMBO, m_CtrlFontScale); + DDX_Control(pDX, IDC_FONT_RENDER_COMBO, m_CtrlFontRender); + DDX_Control(pDX, IDC_SET_DEFAULT, m_CtrlDefault); +} + +BEGIN_MESSAGE_MAP(CFontSelectionDlg, CDialogFx) + ON_BN_CLICKED(IDC_OK, &CFontSelectionDlg::OnOk) + ON_BN_CLICKED(IDC_SET_DEFAULT, &CFontSelectionDlg::OnSetDefault) +END_MESSAGE_MAP() + +BOOL CFontSelectionDlg::OnInitDialog() +{ + CDialogFx::OnInitDialog(); + + SetWindowTitle(i18n(L"WindowTitle", L"FONT_SETTING")); + + SetDefaultFont(m_FontFace); + + CString cstr; + for (int i = 50; i <= 150; i += 10) + { + cstr.Format(L"%d", i); + m_CtrlFontScale.AddString(cstr); + if (m_FontScale == i) { m_CtrlFontScale.SetCurSel(m_CtrlFontScale.GetCount() - 1); } + } + + m_CtrlFontRender.AddString(i18n(L"Dialog", L"ENABLED")); + m_CtrlFontRender.AddString(i18n(L"Dialog", L"DISABLED")); + + if (m_FontRender == CLEARTYPE_NATURAL_QUALITY) + { + m_CtrlFontRender.SetCurSel(0); + } + else + { + m_CtrlFontRender.SetCurSel(1); + } + + m_LabelFontFace.SetWindowTextW(i18n(L"Dialog", L"FONT_FACE")); + m_LabelFontScale.SetWindowTextW(i18n(L"Dialog", L"FONT_SCALE")); + m_LabelFontRender.SetWindowTextW(L"ClearType"); + m_CtrlDefault.SetWindowTextW(i18n(L"Dialog", L"DEFAULT")); + + UpdateDialogSize(); + + return TRUE; +} + +void CFontSelectionDlg::UpdateDialogSize() +{ + CDialogFx::UpdateDialogSize(); + + COLORREF textColor = RGB(0, 0, 0); + COLORREF textSelectedColor = RGB(0, 0, 0); + + ChangeZoomType(m_ZoomType); + SetClientSize(SIZE_X, SIZE_Y, m_ZoomRatio); + + UpdateBackground(FALSE, m_bDarkMode); + + m_LabelFontFace.SetFontEx(m_FontFace, 16, 16, m_ZoomRatio, m_FontRatio, RGB(0, 0, 0), FW_NORMAL, m_FontRender); + m_LabelFontScale.SetFontEx(m_FontFace, 16, 16, m_ZoomRatio, m_FontRatio, RGB(0, 0, 0), FW_NORMAL, m_FontRender); + m_LabelFontRender.SetFontEx(m_FontFace, 16, 16, m_ZoomRatio, m_FontRatio, RGB(0, 0, 0), FW_NORMAL, m_FontRender); + + m_LabelFontFace.InitControl(8, 8, 432, 24, m_ZoomRatio, m_hPal, &m_BkDC, NULL, 0, SS_LEFT, OwnerDrawTransparent, m_bHighContrast, m_bDarkMode, FALSE); + m_LabelFontScale.InitControl(8, 80, 208, 24, m_ZoomRatio, m_hPal, &m_BkDC, NULL, 0, SS_LEFT, OwnerDrawTransparent, m_bHighContrast, m_bDarkMode, FALSE); + m_LabelFontRender.InitControl(240, 80, 208, 24, m_ZoomRatio, m_hPal, &m_BkDC, NULL, 0, SS_LEFT, OwnerDrawTransparent, m_bHighContrast, m_bDarkMode, FALSE); + m_CtrlFontFace.InitControl(20, 32, 440, 360, m_ZoomRatio, &m_BkDC, NULL, 0, ES_LEFT, OwnerDrawTransparent, m_bHighContrast, m_bDarkMode, RGB(255, 255, 255), RGB(160, 220, 255), RGB(255, 255, 255), 0); + m_CtrlFontScale.InitControl(20, 104, 208, 360, m_ZoomRatio, &m_BkDC, NULL, 0, ES_LEFT, OwnerDrawTransparent, m_bHighContrast, m_bDarkMode, RGB(255, 255, 255), RGB(160, 220, 255), RGB(255, 255, 255), 0); + m_CtrlFontRender.InitControl(252, 104, 208, 360, m_ZoomRatio, &m_BkDC, NULL, 0, ES_LEFT, OwnerDrawTransparent, m_bHighContrast, m_bDarkMode, RGB(255, 255, 255), RGB(160, 220, 255), RGB(255, 255, 255), 0); + + m_CtrlDefault.InitControl(40, 156, 168, 32, m_ZoomRatio, m_hPal, &m_BkDC, NULL, 0, BS_CENTER, SystemDraw, m_bHighContrast, m_bDarkMode, FALSE); + m_CtrlOk.InitControl(272, 156, 168, 32, m_ZoomRatio, m_hPal, &m_BkDC, NULL, 0, BS_CENTER, SystemDraw, m_bHighContrast, m_bDarkMode, FALSE); + + m_CtrlFontFace.SetMargin(0, 4, 0, 0, m_ZoomRatio); + m_CtrlFontScale.SetMargin(0, 4, 0, 0, m_ZoomRatio); + m_CtrlFontRender.SetMargin(0, 4, 0, 0, m_ZoomRatio); + + m_CtrlFontFace.SetFontHeight(20, m_ZoomRatio, m_FontRatio); + m_CtrlFontFace.SetFontEx(m_FontFace, 20, 20, m_ZoomRatio, m_FontRatio, textColor, textSelectedColor, FW_NORMAL, m_FontRender); + m_CtrlFontFace.SetItemHeightEx(-1, 36, m_ZoomRatio, m_FontRatio); + for (int i = 0; i < m_CtrlFontFace.GetCount(); i++) + { + m_CtrlFontFace.SetItemHeightEx(i, 32, m_ZoomRatio, m_FontRatio); + } + + m_CtrlFontScale.SetFontHeight(20, m_ZoomRatio, m_FontRatio); + m_CtrlFontScale.SetFontEx(m_FontFace, 20, 20, m_ZoomRatio, m_FontRatio, textColor, textSelectedColor, FW_NORMAL, m_FontRender); + m_CtrlFontScale.SetItemHeightEx(-1, 36, m_ZoomRatio, m_FontRatio); + for (int i = 0; i < m_CtrlFontScale.GetCount(); i++) + { + m_CtrlFontScale.SetItemHeightEx(i, 32, m_ZoomRatio, m_FontRatio); + } + + m_CtrlFontRender.SetFontHeight(20, m_ZoomRatio, m_FontRatio); + m_CtrlFontRender.SetFontEx(m_FontFace, 20, 20, m_ZoomRatio, m_FontRatio, textColor, textSelectedColor, FW_NORMAL, m_FontRender); + m_CtrlFontRender.SetItemHeightEx(-1, 36, m_ZoomRatio, m_FontRatio); + for (int i = 0; i < m_CtrlFontRender.GetCount(); i++) + { + m_CtrlFontRender.SetItemHeightEx(i, 32, m_ZoomRatio, m_FontRatio); + } + + m_CtrlDefault.SetFontEx(m_FontFace, 16, 16, m_ZoomRatio, m_FontRatio, FW_NORMAL, m_FontRender); + m_CtrlOk.SetFontEx(m_FontFace, 16, 16, m_ZoomRatio, m_FontRatio, FW_NORMAL, m_FontRender); + + m_CtrlDefault.SetHandCursor(); + m_CtrlOk.SetHandCursor(); + + SetDarkModeControl(m_CtrlDefault.GetSafeHwnd(), m_bDarkMode); + SetDarkModeControl(m_CtrlOk.GetSafeHwnd(), m_bDarkMode); + + Invalidate(); +} + +void CFontSelectionDlg::OnOk() +{ + CString cstr; + + m_CtrlFontFace.GetLBText(m_CtrlFontFace.GetCurSel(), m_FontFace); + m_CtrlFontScale.GetLBText(m_CtrlFontScale.GetCurSel(), cstr); + m_FontScale = _wtoi(cstr); + if (m_CtrlFontRender.GetCurSel() == 0) + { + m_FontRender = CLEARTYPE_NATURAL_QUALITY; + } + else + { + m_FontRender = ANTIALIASED_QUALITY; + } + + CDialog::OnOK(); +} + +int CALLBACK EnumFontFamExProc(ENUMLOGFONTEX *lpelfe, NEWTEXTMETRICEX *lpntme, int FontType, LPARAM lParam) +{ + CFontComboBox* pFontComboBox = (CFontComboBox*)lParam; + if(pFontComboBox->FindStringExact(0, (TCHAR*)lpelfe->elfLogFont.lfFaceName) == CB_ERR + && _tcschr((TCHAR*)lpelfe->elfLogFont.lfFaceName, L'@') == NULL + && lpelfe->elfLogFont.lfCharSet != SYMBOL_CHARSET + ) + { + pFontComboBox->AddString((TCHAR*)lpelfe->elfLogFont.lfFaceName); + } + return TRUE; +} + +void CFontSelectionDlg::OnSetDefault() +{ + SetDefaultFont(L""); + m_CtrlFontScale.SetCurSel(5); + m_CtrlFontRender.SetCurSel(0); +} + +void CFontSelectionDlg::SetDefaultFont(CString fontFace) +{ + m_CtrlFontFace.ResetContent(); + + CClientDC dc(this); + LOGFONT logfont; + ZeroMemory(&logfont, sizeof(LOGFONT)); + logfont.lfCharSet = DEFAULT_CHARSET; + + ::EnumFontFamiliesExW(dc.m_hDC, &logfont, (FONTENUMPROC)EnumFontFamExProc, (LPARAM)&m_CtrlFontFace, 0); + + int no = m_CtrlFontFace.FindStringExact(0, fontFace); + if (no >= 0) + { + m_CtrlFontFace.SetCurSel(no); + } + else + { + no = m_CtrlFontFace.FindStringExact(0, DEFAULT_FONT_FACE_1); + if (no >= 0) + { + m_CtrlFontFace.SetCurSel(no); + } + else + { + no = m_CtrlFontFace.FindStringExact(0, DEFAULT_FONT_FACE_2); + if (no >= 0) + { + m_CtrlFontFace.SetCurSel(no); + } + else + { + m_CtrlFontFace.SetCurSel(0); + } + } + } + + for (int i = 0; i < m_CtrlFontFace.GetCount(); i++) + { + m_CtrlFontFace.SetItemHeightEx(i, 32, m_ZoomRatio, m_FontRatio); + } +} \ No newline at end of file diff --git a/CristalDiskMark/source/CrystalDiskMark/FontSelectionDlg.h b/CristalDiskMark/source/CrystalDiskMark/FontSelectionDlg.h new file mode 100644 index 0000000..56dcfaa --- /dev/null +++ b/CristalDiskMark/source/CrystalDiskMark/FontSelectionDlg.h @@ -0,0 +1,48 @@ +/*---------------------------------------------------------------------------*/ +// Author : hiyohiyo +// Mail : hiyohiyo@crystalmark.info +// Web : https://crystalmark.info/ +// License : MIT License +/*---------------------------------------------------------------------------*/ + +#pragma once + +#include "afxwin.h" +#include "ButtonFx.h" +#include "ComboBoxFx.h" +#include "FontComboBoxFx.h" + +class CFontSelectionDlg : public CDialogFx +{ + DECLARE_DYNAMIC(CFontSelectionDlg) + + static const int SIZE_X = 480; + static const int SIZE_Y = 204; + enum { IDD = IDD_FONT }; + +public: + CFontSelectionDlg(CWnd* pParent = NULL); + virtual ~CFontSelectionDlg(); + +protected: + virtual void DoDataExchange(CDataExchange* pDX); + virtual BOOL OnInitDialog(); + virtual void UpdateDialogSize(); + + void SetDefaultFont(CString fontFace); + + DECLARE_MESSAGE_MAP() + afx_msg void OnSetDefault(); + afx_msg void OnOk(); + + CStaticFx m_LabelFontFace; + CStaticFx m_LabelFontScale; + CStaticFx m_LabelFontRender; + CButtonFx m_CtrlOk; + CButtonFx m_CtrlDefault; + + CFontComboBox m_CtrlFontFace; + CComboBoxFx m_CtrlFontScale; + CComboBoxFx m_CtrlFontRender; + +}; diff --git a/CristalDiskMark/source/CrystalDiskMark/Library/Resource.h b/CristalDiskMark/source/CrystalDiskMark/Library/Resource.h new file mode 100644 index 0000000..9fa0a4e --- /dev/null +++ b/CristalDiskMark/source/CrystalDiskMark/Library/Resource.h @@ -0,0 +1,183 @@ +//{{NO_DEPENDENCIES}} +// +#define IDD_DISKMARK_DIALOG 102 +#define IDR_MENU 129 +#define IDR_MAINFRAME 130 +#define IDD_ABOUT 131 +#define IDD_COMMENT 132 +#define IDR_PNG1 134 +#define IDR_PNG2 135 +#define IDR_ACCELERATOR 136 +#define IDI_ICON1 138 +#define IDI_TRAY_ICON 138 +#define IDD_SETTINGS 139 +#define IDD_FONT 140 + +#define IDC_OK 1001 +#define IDC_BUTTON_ALL 1003 +#define IDC_BUTTON_TEST_0 1004 +#define IDC_BUTTON_TEST_1 1005 +#define IDC_BUTTON_TEST_2 1006 +#define IDC_BUTTON_TEST_3 1007 +#define IDC_TEST_READ_0 1009 +#define IDC_TEST_READ_1 1010 +#define IDC_TEST_READ_2 1011 +#define IDC_TEST_READ_3 1012 +#define IDC_TEST_WRITE_0 1014 +#define IDC_TEST_WRITE_1 1015 +#define IDC_TEST_WRITE_2 1016 +#define IDC_TEST_WRITE_3 1017 +#define IDC_TEST_MIX_0 1019 +#define IDC_TEST_MIX_1 1020 +#define IDC_TEST_MIX_2 1021 +#define IDC_TEST_MIX_3 1022 +#define IDC_COMMENT 1023 +#define IDC_COMMENT_EX 1024 +#define IDC_COMBO_UNIT 1025 +#define IDC_COMBO_COUNT 1026 +#define IDC_COMBO_DRIVE 1027 +#define IDC_COMBO_SIZE 1028 +#define IDC_READ_UNIT 1029 +#define IDC_WRITE_UNIT 1030 +#define IDC_MIX_UNIT 1031 +#define IDC_COMBO_MIX 1032 +#define IDC_DEMO_SETTING 1033 +#define IDC_HIDE 1034 + +#define IDC_LOGO 1100 +#define IDC_PROJECT_SITE_1 1101 +#define IDC_PROJECT_SITE_2 1102 +#define IDC_PROJECT_SITE_3 1103 +#define IDC_PROJECT_SITE_4 1104 +#define IDC_PROJECT_SITE_5 1105 +#define IDC_VERSION 1106 +#define IDC_RELEASE 1107 +#define IDC_COPYRIGHT1 1108 +#define IDC_COPYRIGHT2 1109 +#define IDC_COPYRIGHT3 1110 +#define IDC_LICENSE 1111 +#define IDC_EDITION 1112 + +#define IDC_FONT_FACE_COMBO 1201 +#define IDC_FONT_SCALE_COMBO 1202 +#define IDC_FONT_RENDER_COMBO 1203 +#define IDC_FONT_FACE 1204 +#define IDC_FONT_SCALE 1205 +#define IDC_FONT_RENDER 1206 + +#define IDC_LABEL_DEMO 1301 +#define IDC_COMBO_DATA 1302 +#define IDC_LABEL_DATA 1303 +#define IDC_SET_DEFAULT 1304 +#define IDC_SET_NVME_8 1306 +#define IDC_SET_FLASH_MEMORY 1307 +#define IDC_LABEL_AFFINITY 1308 +#define IDC_COMBO_AFFINITY 1309 +#define IDC_LABEL_PEAK 1310 +#define IDC_LABEL_TYPE 1311 +#define IDC_LABEL_SIZE 1312 +#define IDC_LABEL_QUEUES 1313 +#define IDC_LABEL_THREADS 1314 +#define IDC_LABEL_MEASURE_TIME 1315 +#define IDC_LABEL_INTERVAL_TIME 1316 +#define IDC_COMBO_MEASURE_TIME 1317 +#define IDC_COMBO_INTERVAL_TIME 1318 +#define IDC_LABEL_DEFAULT 1319 + +#define IDC_COMBO_BENCH_TYPE_0 1320 +#define IDC_COMBO_BENCH_TYPE_1 1321 +#define IDC_COMBO_BENCH_TYPE_2 1322 +#define IDC_COMBO_BENCH_TYPE_3 1323 +#define IDC_COMBO_BENCH_TYPE_4 1324 +#define IDC_COMBO_BENCH_TYPE_5 1325 +#define IDC_COMBO_BENCH_TYPE_8 1328 + +#define IDC_COMBO_BENCH_SIZE_0 1330 +#define IDC_COMBO_BENCH_SIZE_1 1331 +#define IDC_COMBO_BENCH_SIZE_2 1332 +#define IDC_COMBO_BENCH_SIZE_3 1333 +#define IDC_COMBO_BENCH_SIZE_4 1334 +#define IDC_COMBO_BENCH_SIZE_5 1335 +#define IDC_COMBO_BENCH_SIZE_8 1338 + +#define IDC_COMBO_BENCH_QUEUE_0 1340 +#define IDC_COMBO_BENCH_QUEUE_1 1341 +#define IDC_COMBO_BENCH_QUEUE_2 1342 +#define IDC_COMBO_BENCH_QUEUE_3 1343 +#define IDC_COMBO_BENCH_QUEUE_4 1344 +#define IDC_COMBO_BENCH_QUEUE_5 1345 +#define IDC_COMBO_BENCH_QUEUE_8 1348 + +#define IDC_COMBO_BENCH_THREAD_0 1350 +#define IDC_COMBO_BENCH_THREAD_1 1351 +#define IDC_COMBO_BENCH_THREAD_2 1352 +#define IDC_COMBO_BENCH_THREAD_3 1353 +#define IDC_COMBO_BENCH_THREAD_4 1354 +#define IDC_COMBO_BENCH_THREAD_5 1355 +#define IDC_COMBO_BENCH_THREAD_8 1358 + +#define ID_EXIT 32771 +#define ID_ABOUT 32772 +#define ID_THEME 32775 +#define ID_THEME_DUMMY 32776 +#define ID_COPY 32777 +#define ID_LANGUAGE_DUMMY 32778 +#define ID_LANGUAGE_A 32779 +#define ID_LANGUAGE_O 32780 +#define ID_A_DUMMY 32781 +#define ID_O_DUMMY 32782 +#define ID_BACK_PAGE 32787 +#define ID_PRINT 32788 +#define ID_FUNCTION_ZOOM 32789 +#define ID_ZOOM_100 32803 +#define ID_ZOOM_125 32804 +#define ID_ZOOM_150 32805 +#define ID_ZOOM_200 32806 +#define ID_ZOOM_250 32807 +#define ID_ZOOM_300 32808 +#define ID_ZOOM_AUTO 33809 +#define ID_HELP_HELP 32810 +#define ID_CRYSTALDEWWORLD 32811 +#define ID_FILE_BENCHMARKMODE 32812 +#define ID_MODE_DEFAULT 32815 +#define ID_MODE_ALL0X00 32816 +#define ID_MODE_ALL0XFF 32817 +#define ID_SETTINGS_QUEUESTHREADS 32818 +#define ID_SAVE_TEXT 32819 +#define ID_SAVE_IMAGE 32820 +#define ID_FONT_SETTING 32821 +#define ID_SETTING_DEFAULT 32822 +#define ID_SETTING_NVME_8 32823 +#define ID_SETTING_FLASH_MEMORY 32824 + +#define ID_INTERVAL_TIME_0 33820 +#define ID_INTERVAL_TIME_1 33821 +#define ID_INTERVAL_TIME_3 33822 +#define ID_INTERVAL_TIME_5 33823 +#define ID_INTERVAL_TIME_10 33824 +#define ID_INTERVAL_TIME_30 33825 +#define ID_INTERVAL_TIME_60 33826 +#define ID_INTERVAL_TIME_180 33827 +#define ID_INTERVAL_TIME_300 33828 +#define ID_INTERVAL_TIME_600 33829 +#define ID_PROFILE_DEFAULT 33830 +#define ID_PROFILE_PEAK 33831 +#define ID_PROFILE_REAL 33832 +#define ID_PROFILE_DEMO 33833 +#define ID_PROFILE_DEFAULT_MIX 33834 +#define ID_PROFILE_PEAK_MIX 33835 +#define ID_PROFILE_REAL_MIX 33836 +#define ID_BENCHMARK_READ_WRITE 33837 +#define ID_BENCHMARK_READ_ONLY 33838 +#define ID_BENCHMARK_WRITE_ONLY 33839 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 141 +#define _APS_NEXT_COMMAND_VALUE 33840 +#define _APS_NEXT_CONTROL_VALUE 1360 +#define _APS_NEXT_SYMED_VALUE 107 +#endif +#endif diff --git a/CristalDiskMark/source/CrystalDiskMark/Library/stdafx.cpp b/CristalDiskMark/source/CrystalDiskMark/Library/stdafx.cpp new file mode 100644 index 0000000..ca35402 --- /dev/null +++ b/CristalDiskMark/source/CrystalDiskMark/Library/stdafx.cpp @@ -0,0 +1,5 @@ +// stdafx.cpp : source file that includes just the standard includes +// DiskInfo.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" diff --git a/CristalDiskMark/source/CrystalDiskMark/Library/stdafx.h b/CristalDiskMark/source/CrystalDiskMark/Library/stdafx.h new file mode 100644 index 0000000..a06429c --- /dev/null +++ b/CristalDiskMark/source/CrystalDiskMark/Library/stdafx.h @@ -0,0 +1,228 @@ +/*---------------------------------------------------------------------------*/ +// Author : hiyohiyo +// Mail : hiyohiyo@crystalmark.info +// Web : https://crystalmark.info/ +// License : MIT License +/*---------------------------------------------------------------------------*/ + +#pragma once + +#ifndef _SECURE_ATL +#define _SECURE_ATL 1 +#endif + +#ifndef VC_EXTRALEAN +#define VC_EXTRALEAN +#endif + +#ifndef WINVER +#define WINVER 0x0501 +#endif + +#ifndef _WIN32_WINNT +#define _WIN32_WINNT 0x0501 +#endif + +#ifndef _WIN32_WINDOWS +#define _WIN32_WINDOWS 0x0410 +#endif + +#ifndef _WIN32_IE +#define _WIN32_IE 0x0600 +#endif + +#define _AFX_NO_MFC_CONTROLS_IN_DIALOGS +#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS +#define _AFX_ALL_WARNINGS + +#include // MFC core and standard component +#include // Extended MFC +#include // MFC IE4 Common Control support +#include // MFC Windows Common Control support + +#include "CommonFx.h" +#include "UtilityFx.h" + +#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"") + +#ifdef UWP +#ifdef SUISHO_SHIZUKU_SUPPORT +#ifdef _M_ARM +#define PRODUCT_EDITION L"Shizuku Edition ARM32" +#elif _M_ARM64 +#define PRODUCT_EDITION L"Shizuku Edition ARM64" +#elif _M_X64 +#define PRODUCT_EDITION L"Shizuku Edition x64" +#else +#define PRODUCT_EDITION L"Shizuku Edition x86" +#endif +#else +#ifdef _M_ARM +#define PRODUCT_EDITION L"ARM32" +#elif _M_ARM64 +#define PRODUCT_EDITION L"ARM64" +#elif _M_X64 +#define PRODUCT_EDITION L"x64" +#else +#define PRODUCT_EDITION L"x86" +#endif +#endif + +#else + +#ifdef SUISHO_AOI_SUPPORT +#ifdef _M_ARM +#define PRODUCT_EDITION L"Aoi Edition ARM32" +#elif _M_ARM64 +#define PRODUCT_EDITION L"Aoi Edition ARM64" +#elif _M_X64 +#define PRODUCT_EDITION L"Aoi Edition x64" +#else +#define PRODUCT_EDITION L"Aoi Edition x86" +#endif + +#elif MSI_MEI_SUPPORT +#ifdef _M_ARM +#define PRODUCT_EDITION L"MSI Mei Mihoshi Edition ARM32" +#elif _M_ARM64 +#define PRODUCT_EDITION L"MSI Mei Mihoshi Edition ARM64" +#elif _M_X64 +#define PRODUCT_EDITION L"MSI Mei Mihoshi Edition x64" +#else +#define PRODUCT_EDITION L"MSI Mei Mihoshi Edition x86" +#endif + +#elif SUISHO_SHIZUKU_SUPPORT +#ifdef _M_ARM +#define PRODUCT_EDITION L"Shizuku Edition ARM32" +#elif _M_ARM64 +#define PRODUCT_EDITION L"Shizuku Edition ARM64" +#elif _M_X64 +#define PRODUCT_EDITION L"Shizuku Edition x64" +#else +#define PRODUCT_EDITION L"Shizuku Edition x86" +#endif + +#else +#ifdef _M_ARM +#define PRODUCT_EDITION L"ARM32" +#elif _M_ARM64 +#define PRODUCT_EDITION L"ARM64" +#elif _M_X64 +#define PRODUCT_EDITION L"x64" +#else +#define PRODUCT_EDITION L"x86" +#endif +#endif +#endif + +// Version Information +#define PRODUCT_NAME L"CrystalDiskMark" +#define PRODUCT_FILENAME L"CrystalDiskMark" +#define PRODUCT_VERSION L"9.0.3" +#define PRODUCT_SHORT_NAME L"CDM" + +#define PRODUCT_RELEASE L"2026/05/24" +#define PRODUCT_COPY_YEAR L"2007-2026" +#define PRODUCT_LICENSE L"MIT License" + +#ifdef SUISHO_AOI_SUPPORT +#define PRODUCT_COPYRIGHT_1 L"© 2007-2026 hiyohiyo" +#define PRODUCT_COPYRIGHT_2 L"© 2023-2026 nijihashi sola" +#define PRODUCT_COPYRIGHT_3 L"" + +#elif MSI_MEI_SUPPORT +#define PRODUCT_COPYRIGHT_1 L"© 2007-2026 hiyohiyo" +#define PRODUCT_COPYRIGHT_2 L"© 2024-2026 Micro-Star INT'L CO., LTD." +#define PRODUCT_COPYRIGHT_3 L"" + +#elif SUISHO_SHIZUKU_SUPPORT +#define PRODUCT_COPYRIGHT_1 L"© 2007-2026 hiyohiyo" +#define PRODUCT_COPYRIGHT_2 L"© 2012-2026 kirino kasumu" +#define PRODUCT_COPYRIGHT_3 L"" + +#else +#define PRODUCT_COPYRIGHT_1 L"© 2007-2026 hiyohiyo" +#define PRODUCT_COPYRIGHT_2 L"" +#define PRODUCT_COPYRIGHT_3 L"" +#endif + +#ifdef MSI_MEI_SUPPORT +#define URL_MAIN_JA L"https://jp.msi.com/" +#define URL_MAIN_EN L"https://www.msi.com/" +#else +#define URL_MAIN_JA L"https://crystalmark.info/ja/" +#define URL_MAIN_EN L"https://crystalmark.info/en/" +#endif + +#define URL_CRYSTAL_DEW_WORLD_JA L"https://crystalmark.info/ja/" +#define URL_CRYSTAL_DEW_WORLD_EN L"https://crystalmark.info/en/" + +#define URL_VERSION_JA L"https://crystalmark.info/ja/software/crystaldiskmark/crystaldiskmark-history/" +#define URL_VERSION_EN L"https://crystalmark.info/en/software/crystaldiskmark/crystaldiskmark-history/" +#define URL_LICENSE_JA L"https://crystalmark.info/ja/software/crystaldiskmark/crystaldiskmark-license/" +#define URL_LICENSE_EN L"https://crystalmark.info/en/software/crystaldiskmark/crystaldiskmark-license/" +#define URL_HELP_JA L"https://crystalmark.info/ja/software/crystaldiskmark/" +#define URL_HELP_EN L"https://crystalmark.info/en/software/crystaldiskmark/" + +#define URL_DISKSPD L"https://github.com/microsoft/diskspd" + +#ifdef SUISHO_AOI_SUPPORT +#define URL_PROJECT_SITE_1 L"https://twitter.com/sola_no_crayon" +#define URL_PROJECT_SITE_2 L"https://twitter.com/harakeiko0718" +#define URL_PROJECT_SITE_3 L"https://instagram.com/kotomi_wicke?igshid=OGQ5ZDc2ODk2ZA==" +#define URL_PROJECT_SITE_4 L"https://twitter.com/bellche" +#define URL_PROJECT_SITE_5 L"" + +#elif MSI_MEI_SUPPORT +#define URL_PROJECT_SITE_1 L"https://jp.msi.com/Landing/mihoshimei/nb" +#define URL_PROJECT_SITE_2 L"https://twitter.com/hoshi_u3" +#define URL_PROJECT_SITE_3 L"https://twitter.com/mokowata" +#define URL_PROJECT_SITE_4 L"https://jp.msi.com/" +#define URL_PROJECT_SITE_5 L"https://jp.msi.com/" + +#elif SUISHO_SHIZUKU_SUPPORT +#define URL_PROJECT_SITE_1 L"https://twitter.com/kirinokasumu" +#define URL_PROJECT_SITE_2 L"https://linux-ha.osdn.jp/wp/" +#define URL_PROJECT_SITE_3 L"https://ch.nicovideo.jp/oss" +#define URL_PROJECT_SITE_4 L"https://twitter.com/bellche" +#define URL_PROJECT_SITE_5 L"https://suishoshizuku.com/" +#endif + +#define MAX_THREADS 64 +#define MAX_QUEUES 512 + +static const int RE_EXEC = 5963; + +#pragma warning(disable : 4996) + +//------------------------------------------------ +// Option Flags +//------------------------------------------------ + +// For Task Tray Icon Feature +// #define OPTION_TASK_TRAY + +//------------------------------------------------ +// Global Sttings +//------------------------------------------------ + +#define DEFAULT_FONT_FACE_1 L"Segoe UI" +#define DEFAULT_FONT_FACE_2 L"Tahoma" + +#define THEME_DIR L"CdmResource\\themes\\" +#define LANGUAGE_DIR L"CdmResource\\language\\" +#define VOICE_DIR L"CdmResource\\voice\\" + + +#define MENU_THEME_INDEX 3 +#define MENU_LANG_INDEX 5 + +#define DEFAULT_THEME L"Default" +#define DEFAULT_LANGUAGE L"English" + +#define TIMER_UPDATE_DIALOG 500 + +#define WM_UPDATE_SCORE (WM_APP+0x1001) +#define WM_UPDATE_MESSAGE (WM_APP+0x1002) +#define WM_EXIT_BENCHMARK (WM_APP+0x1003) \ No newline at end of file diff --git a/CristalDiskMark/source/CrystalDiskMark/Priscilla/ButtonFx.cpp b/CristalDiskMark/source/CrystalDiskMark/Priscilla/ButtonFx.cpp new file mode 100644 index 0000000..60c4ef4 --- /dev/null +++ b/CristalDiskMark/source/CrystalDiskMark/Priscilla/ButtonFx.cpp @@ -0,0 +1,991 @@ +/*---------------------------------------------------------------------------*/ +// Author : hiyohiyo +// Mail : hiyohiyo@crystalmark.info +// Web : https://crystalmark.info/ +// License : MIT License +/*---------------------------------------------------------------------------*/ + +#include "stdafx.h" +#include "ButtonFx.h" + +#if _MSC_VER <= 1310 +#define ON_WM_MOUSEHOVER() \ + { 0x2A1 /*WM_MOUSEHOVER*/, 0, 0, 0, AfxSig_vwp, \ + (AFX_PMSG)(AFX_PMSGW) \ + (static_cast< void (AFX_MSG_CALL CWnd::*)(UINT, CPoint) > (OnMouseHover)) }, + +#define ON_WM_MOUSELEAVE() \ + { 0x2A3 /*WM_MOUSELEAVE*/, 0, 0, 0, AfxSig_vv, \ + (AFX_PMSG)(AFX_PMSGW) \ + (static_cast< void (AFX_MSG_CALL CWnd::*)(void) > (OnMouseLeave)) }, +#endif + +////------------------------------------------------ +// CButtonFx +////------------------------------------------------ + +CButtonFx::CButtonFx() +{ + // Control + m_X = 0; + m_Y = 0; + m_RenderMode = SystemDraw; + m_bHighContrast = FALSE; + m_bDarkMode = FALSE; + m_bDrawFrame = FALSE; + m_FrameColor = RGB(128, 128, 128); + m_hPal = NULL; + + // Glass + m_GlassColor = RGB(255, 255, 255); + m_GlassAlpha = 255; + + // Meter + m_bMeter = FALSE; + m_MeterRatio = 0.0; + + // Image + m_ImageCount = 0; + m_BkDC = NULL; + m_bBkBitmapInit = FALSE; + m_bBkLoad = FALSE; + + // Font + m_TextAlign = BS_LEFT; + m_TextColor = RGB(0, 0, 0); + + // Mouse + m_bHover = FALSE; + m_bFocas = FALSE; + m_bTrackingNow = FALSE; + m_bHandCursor = FALSE; + m_bSelected = FALSE; + + // Text Format + m_TextFormat = 0; + m_LabelFormat = DT_LEFT | DT_TOP | DT_SINGLELINE; + m_UnitFormat = DT_RIGHT | DT_BOTTOM | DT_SINGLELINE; + + // Margin + m_Margin.top = 0; + m_Margin.left = 0; + m_Margin.bottom = 0; + m_Margin.right = 0; +} + +CButtonFx::~CButtonFx() +{ +} + +IMPLEMENT_DYNAMIC(CButtonFx, CButton) + +BEGIN_MESSAGE_MAP(CButtonFx, CButton) + //{{AFX_MSG_MAP(CButtonFx) + ON_WM_ERASEBKGND() + ON_WM_MOUSEMOVE() + ON_WM_MOUSEHOVER() + ON_WM_MOUSELEAVE() + ON_WM_KILLFOCUS() + ON_WM_SETFOCUS() + ON_WM_SETCURSOR() + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +//------------------------------------------------ +// Control +//------------------------------------------------ + +BOOL CButtonFx::InitControl(int x, int y, int width, int height, double zoomRatio, HPALETTE hPal, CDC* bkDC, + LPCTSTR imagePath, int imageCount, DWORD textAlign, int renderMode, BOOL bHighContrast, BOOL bDarkMode, BOOL bDrawFrame) +{ + m_X = (int)(x * zoomRatio); + m_Y = (int)(y * zoomRatio); + m_CtrlSize.cx = (int)(width * zoomRatio + 0.5); + m_CtrlSize.cy = (int)(height * zoomRatio + 0.5); + MoveWindow(m_X, m_Y, m_CtrlSize.cx, m_CtrlSize.cy); + + m_hPal = hPal; + m_BkDC = bkDC; + m_ImagePath = imagePath; + m_ImageCount = imageCount; + m_RenderMode = renderMode; + + if (BS_LEFT <= textAlign && textAlign <= BS_CENTER) + { + m_TextAlign = textAlign; + } + + if(m_ToolTip.m_hWnd != NULL) + { + if (m_ToolTip.GetToolCount() != 0) + { + m_ToolTip.DelTool(this, 1); + } + CRect rect; + GetClientRect(rect); + m_ToolTip.AddTool(this, m_ToolTipText, rect, 1); + } + + m_bHighContrast = bHighContrast; + m_bDarkMode = bDarkMode; + m_bDrawFrame = bDrawFrame; + + if (m_bHighContrast) + { + ModifyStyle(BS_OWNERDRAW, m_TextAlign); + + return TRUE; + } + else if(renderMode & SystemDraw) + { + ModifyStyle(BS_OWNERDRAW, m_TextAlign); + + return TRUE; + } + else + { + SetBkReload(); + ModifyStyle(0, BS_OWNERDRAW); + } + + if (renderMode & OwnerDrawImage) + { + if (!LoadBitmap(imagePath)) + { + ModifyStyle(BS_OWNERDRAW, m_TextAlign); + } + } + else + { + m_ImageCount = 1; + m_CtrlImage.Destroy(); + m_CtrlImage.Create(m_CtrlSize.cx, m_CtrlSize.cy * m_ImageCount, 32); + m_CtrlBitmap.Detach(); + m_CtrlBitmap.Attach((HBITMAP)m_CtrlImage); + DWORD length = m_CtrlSize.cx * m_CtrlSize.cy * m_ImageCount * 4; + BYTE* bitmapBits = new BYTE[length]; + m_CtrlBitmap.GetBitmapBits(length, bitmapBits); + + BYTE r, g, b, a; + if (renderMode & OwnerDrawGlass) + { + r = (BYTE)GetRValue(m_GlassColor); + g = (BYTE)GetGValue(m_GlassColor); + b = (BYTE)GetBValue(m_GlassColor); + a = m_GlassAlpha; + } + else // OwnerDrawTransparent + { + r = 0; + g = 0; + b = 0; + a = 0; + } + + for (int y = 0; y < (int)(m_CtrlSize.cy * m_ImageCount); y++) + { + for (int x = 0; x < m_CtrlSize.cx; x++) + { + DWORD p = (y * m_CtrlSize.cx + x) * 4; +#if _MSC_VER > 1310 +#pragma warning( disable : 6386 ) +#endif + bitmapBits[p + 0] = b; + bitmapBits[p + 1] = g; + bitmapBits[p + 2] = r; + bitmapBits[p + 3] = a; +#if _MSC_VER > 1310 +#pragma warning( default : 6386 ) +#endif + } + } + + m_CtrlBitmap.SetBitmapBits(length, bitmapBits); + delete[] bitmapBits; + } + + Invalidate(); + + return TRUE; +} + +BOOL CButtonFx::ReloadImage(LPCTSTR imagePath, UINT imageCount) +{ + if (imagePath != NULL && m_ImagePath.Compare(imagePath) == 0) + { + return FALSE; + } + + m_ImagePath = imagePath; + m_ImageCount = imageCount; + + LoadBitmap(imagePath); + + Invalidate(); + return TRUE; +} + +void CButtonFx::SetMargin(int top, int left, int bottom, int right, double zoomRatio) +{ + m_Margin.top = (int)(top * zoomRatio); + m_Margin.left = (int)(left * zoomRatio); + m_Margin.bottom = (int)(bottom * zoomRatio); + m_Margin.right = (int)(right * zoomRatio); +} + +CSize CButtonFx::GetSize(void) +{ + return m_CtrlSize; +} + +void CButtonFx::SetDrawFrame(BOOL bDrawFrame) +{ + if (bDrawFrame && m_bHighContrast) + { + ModifyStyleEx(0, WS_EX_STATICEDGE, SWP_DRAWFRAME); + } + else + { + ModifyStyleEx(WS_EX_STATICEDGE, 0, SWP_DRAWFRAME); + } + m_bDrawFrame = bDrawFrame; +} + +void CButtonFx::SetGlassColor(COLORREF glassColor, BYTE glassAlpha) +{ + m_GlassColor = glassColor; + m_GlassAlpha = glassAlpha; +} + +void CButtonFx::SetMeter(BOOL bMeter, double meterRatio) +{ + m_bMeter = bMeter; + if (meterRatio > 1.0) + { + m_MeterRatio = 1.0; + } + else if (meterRatio > 0) + { + m_MeterRatio = meterRatio; + } + else + { + m_MeterRatio = 0.0; + } + + Invalidate(); +} + +void CButtonFx::SetLabelUnit(CString label, CString unit) +{ + m_Label = label; + m_Unit = unit; +} + +void CButtonFx::SetLabelUnitFormat(UINT labelFormat, UINT unitFormat) +{ + m_LabelFormat = labelFormat; + m_UnitFormat = unitFormat; +} + +void CButtonFx::SetTextFormat(UINT format) +{ + m_TextFormat = format; +} + +//------------------------------------------------ +// Draw Control +//------------------------------------------------ + +void CButtonFx::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) +{ + if (m_bHighContrast) { return CButton::DrawItem(lpDrawItemStruct); } + + CDC* drawDC = CDC::FromHandle(lpDrawItemStruct->hDC); + LoadCtrlBk(drawDC); + + if (! (GetStyle() & BS_NOTIFY)) + { + DrawControl(drawDC, lpDrawItemStruct, m_CtrlBitmap, m_BkBitmap, ControlImageNormal); + } + else if (IsWindowEnabled()) + { + if (m_bSelected && m_ImageCount > ControlImageSelected) + { + DrawControl(drawDC, lpDrawItemStruct, m_CtrlBitmap, m_BkBitmap, ControlImageSelected); + } + else if ((lpDrawItemStruct->itemState & ODS_SELECTED || m_bHover) && m_ImageCount > ControlImageHover) + { + DrawControl(drawDC, lpDrawItemStruct, m_CtrlBitmap, m_BkBitmap, ControlImageHover); + } + else if ((lpDrawItemStruct->itemState & ODS_FOCUS || m_bFocas) && m_ImageCount > ControlImageFocus) + { + DrawControl(drawDC, lpDrawItemStruct, m_CtrlBitmap, m_BkBitmap, ControlImageFocus); + } + else + { + DrawControl(drawDC, lpDrawItemStruct, m_CtrlBitmap, m_BkBitmap, ControlImageNormal); + } + } + else + { + if (m_ImageCount > ControlImageDisabled) + { + DrawControl(drawDC, lpDrawItemStruct, m_CtrlBitmap, m_BkBitmap, ControlImageDisabled); + } + else + { + DrawControl(drawDC, lpDrawItemStruct, m_CtrlBitmap, m_BkBitmap, ControlImageNormal); + } + } +} + +void CButtonFx::DrawControl(CDC* drawDC, LPDRAWITEMSTRUCT lpDrawItemStruct, CBitmap& ctrlBitmap, CBitmap& bkBitmap, int no) +{ + CDC* pMemDC = new CDC; + CBitmap* pOldMemBitmap; + if(m_hPal && drawDC->GetDeviceCaps(RASTERCAPS) & RC_PALETTE) + { + SelectPalette( drawDC->GetSafeHdc(), m_hPal, FALSE ); + drawDC->RealizePalette(); + drawDC->SetStretchBltMode(HALFTONE); + } + pMemDC->CreateCompatibleDC(drawDC); + if(m_hPal && pMemDC->GetDeviceCaps(RASTERCAPS) & RC_PALETTE) + { + SelectPalette( pMemDC->GetSafeHdc(), m_hPal, FALSE ); + pMemDC->RealizePalette(); + pMemDC->SetStretchBltMode(HALFTONE); + } + pOldMemBitmap = pMemDC->SelectObject(&ctrlBitmap); + CDC* pBkDC = new CDC; + CBitmap* pOldBkBitmap; + pBkDC->CreateCompatibleDC(drawDC); + if(m_hPal && pBkDC->GetDeviceCaps(RASTERCAPS) & RC_PALETTE) + { + SelectPalette( pBkDC->GetSafeHdc(), m_hPal, FALSE ); + pBkDC->RealizePalette(); + pBkDC->SetStretchBltMode(HALFTONE); + } + pOldBkBitmap = pBkDC->SelectObject(&bkBitmap); + + CBitmap DrawBmp; + DrawBmp.CreateCompatibleBitmap(drawDC, m_CtrlSize.cx, m_CtrlSize.cy); + CDC* pDrawBmpDC = new CDC; + CBitmap* pOldDrawBitmap; + pDrawBmpDC->CreateCompatibleDC(drawDC); + if(m_hPal && pDrawBmpDC->GetDeviceCaps(RASTERCAPS) & RC_PALETTE) + { + SelectPalette( pDrawBmpDC->GetSafeHdc(), m_hPal, FALSE ); + pDrawBmpDC->RealizePalette(); + pDrawBmpDC->SetStretchBltMode(HALFTONE); + } + pOldDrawBitmap = pDrawBmpDC->SelectObject(&DrawBmp); + + int color = drawDC->GetDeviceCaps(BITSPIXEL) * drawDC->GetDeviceCaps(PLANES); + + if (!m_CtrlImage.IsNull()) + { + if (m_CtrlImage.GetBPP() == 32) + { + CBitmap* bk32Bitmap; + CImage bk32Image; + if (color == 32) + { + bk32Bitmap = &bkBitmap; + } + else + { + bk32Image.Create(m_CtrlSize.cx, m_CtrlSize.cy, 32); + ::StretchBlt(bk32Image.GetDC(), 0, 0, m_CtrlSize.cx, m_CtrlSize.cy, *pBkDC, 0, 0, m_CtrlSize.cx, m_CtrlSize.cy, SRCCOPY); + bk32Bitmap = CBitmap::FromHandle((HBITMAP)bk32Image); + } + + BITMAP CtlBmpInfo, DstBmpInfo; + bk32Bitmap->GetBitmap(&DstBmpInfo); + DWORD DstLineBytes = DstBmpInfo.bmWidthBytes; + DWORD DstMemSize = DstLineBytes * DstBmpInfo.bmHeight; + ctrlBitmap.GetBitmap(&CtlBmpInfo); + DWORD CtlLineBytes = CtlBmpInfo.bmWidthBytes; + DWORD CtlMemSize = CtlLineBytes * CtlBmpInfo.bmHeight; + + if ((DstBmpInfo.bmWidthBytes != CtlBmpInfo.bmWidthBytes) + || (DstBmpInfo.bmHeight != CtlBmpInfo.bmHeight / m_ImageCount)) + { + // Error Check // + } + else + { + BYTE* DstBuffer = new BYTE[DstMemSize]; + bk32Bitmap->GetBitmapBits(DstMemSize, DstBuffer); + BYTE* CtlBuffer = new BYTE[CtlMemSize]; + ctrlBitmap.GetBitmapBits(CtlMemSize, CtlBuffer); + + if (m_bMeter) + { + int meter = (int)(m_CtrlSize.cx * m_MeterRatio); + int baseY; + baseY = m_CtrlSize.cy; + for (LONG py = 0; py < DstBmpInfo.bmHeight; py++) + { + int dn = py * DstLineBytes; + int cn = (baseY + py) * CtlLineBytes; + for (LONG px = 0; px < meter; px++) + { + BYTE a = CtlBuffer[cn + 3]; + BYTE na = 255 - a; + DstBuffer[dn + 0] = (BYTE)((CtlBuffer[cn + 0] * a + DstBuffer[dn + 0] * na) / 255); + DstBuffer[dn + 1] = (BYTE)((CtlBuffer[cn + 1] * a + DstBuffer[dn + 1] * na) / 255); + DstBuffer[dn + 2] = (BYTE)((CtlBuffer[cn + 2] * a + DstBuffer[dn + 2] * na) / 255); + dn += (DstBmpInfo.bmBitsPixel / 8); + cn += (CtlBmpInfo.bmBitsPixel / 8); + } + cn -= baseY * CtlLineBytes; + for (LONG px = meter; px < DstBmpInfo.bmWidth; px++) + { + BYTE a = CtlBuffer[cn + 3]; + BYTE na = 255 - a; + DstBuffer[dn + 0] = (BYTE)((CtlBuffer[cn + 0] * a + DstBuffer[dn + 0] * na) / 255); + DstBuffer[dn + 1] = (BYTE)((CtlBuffer[cn + 1] * a + DstBuffer[dn + 1] * na) / 255); + DstBuffer[dn + 2] = (BYTE)((CtlBuffer[cn + 2] * a + DstBuffer[dn + 2] * na) / 255); + dn += (DstBmpInfo.bmBitsPixel / 8); + cn += (CtlBmpInfo.bmBitsPixel / 8); + } + } + } + else + { + int baseY = m_CtrlSize.cy * no; + for (LONG py = 0; py < DstBmpInfo.bmHeight; py++) + { + int dn = py * DstLineBytes; + int cn = (baseY + py) * CtlLineBytes; + for (LONG px = 0; px < DstBmpInfo.bmWidth; px++) + { +#if _MSC_VER > 1310 +#pragma warning( disable : 6385 ) +#pragma warning( disable : 6386 ) +#endif + BYTE a = CtlBuffer[cn + 3]; + BYTE na = 255 - a; + DstBuffer[dn + 0] = (BYTE)((CtlBuffer[cn + 0] * a + DstBuffer[dn + 0] * na) / 255); + DstBuffer[dn + 1] = (BYTE)((CtlBuffer[cn + 1] * a + DstBuffer[dn + 1] * na) / 255); + DstBuffer[dn + 2] = (BYTE)((CtlBuffer[cn + 2] * a + DstBuffer[dn + 2] * na) / 255); + dn += (DstBmpInfo.bmBitsPixel / 8); + cn += (CtlBmpInfo.bmBitsPixel / 8); +#if _MSC_VER > 1310 +#pragma warning( default : 6386 ) +#pragma warning( default : 6385 ) +#endif + } + } + } + + if (color == 32) + { + DrawBmp.SetBitmapBits(DstMemSize, DstBuffer); + } + else + { + bk32Bitmap->SetBitmapBits(DstMemSize, DstBuffer); + ::StretchBlt(pDrawBmpDC->GetSafeHdc(), 0, 0, m_CtrlSize.cx, m_CtrlSize.cy, bk32Image.GetDC(), 0, 0, m_CtrlSize.cx, m_CtrlSize.cy, SRCCOPY); + bk32Image.ReleaseDC(); + } + DrawString(pDrawBmpDC, lpDrawItemStruct); + drawDC->StretchBlt(0, 0, m_CtrlSize.cx, m_CtrlSize.cy, pDrawBmpDC, 0, 0, m_CtrlSize.cx, m_CtrlSize.cy, SRCCOPY); + + delete[] DstBuffer; + delete[] CtlBuffer; + } + } + else + { + if (m_bMeter) + { + int meter = (int)(m_CtrlSize.cx * (m_MeterRatio)); + pDrawBmpDC->StretchBlt(meter, 0, m_CtrlSize.cx - meter, m_CtrlSize.cy, pMemDC, meter, m_CtrlSize.cy * 0, m_CtrlSize.cx - meter, m_CtrlSize.cy, SRCCOPY); + pDrawBmpDC->StretchBlt(0, 0, meter, m_CtrlSize.cy, pMemDC, 0, m_CtrlSize.cy * 1, meter, m_CtrlSize.cy, SRCCOPY); + DrawString(pDrawBmpDC, lpDrawItemStruct); + drawDC->StretchBlt(0, 0, m_CtrlSize.cx, m_CtrlSize.cy, pDrawBmpDC, 0, 0, m_CtrlSize.cx, m_CtrlSize.cy, SRCCOPY); + } + else + { + pDrawBmpDC->StretchBlt(0, 0, m_CtrlSize.cx, m_CtrlSize.cy, pMemDC, 0, m_CtrlSize.cy * no, m_CtrlSize.cx, m_CtrlSize.cy, SRCCOPY); + DrawString(pDrawBmpDC, lpDrawItemStruct); + drawDC->StretchBlt(0, 0, m_CtrlSize.cx, m_CtrlSize.cy, pDrawBmpDC, 0, 0, m_CtrlSize.cx, m_CtrlSize.cy, SRCCOPY); + } + } + } + else + { + pDrawBmpDC->StretchBlt(0, 0, m_CtrlSize.cx, m_CtrlSize.cy, pBkDC, 0, m_CtrlSize.cy * no, m_CtrlSize.cx, m_CtrlSize.cy, SRCCOPY); + DrawString(pDrawBmpDC, lpDrawItemStruct); + drawDC->StretchBlt(0, 0, m_CtrlSize.cx, m_CtrlSize.cy, pDrawBmpDC, 0, 0, m_CtrlSize.cx, m_CtrlSize.cy, SRCCOPY); + } + + if (m_bDrawFrame) + { + HGDIOBJ oldPen; + POINT point; + + COLORREF color1; + COLORREF color2; + + if (m_bHover) + { + color1 = RGB(0x20, 0x98, 0xF4); + color2 = RGB(0x20, 0x8B, 0xDE); + } + else + { + // Windows 11 color + color1 = RGB(0x00, 0x78, 0xD4); + color2 = RGB(0x00, 0x6B, 0xBE); + } + + CPen pen1; pen1.CreatePen(PS_SOLID, 1, color1); + CPen pen2; pen2.CreatePen(PS_SOLID, 1, color2); + + oldPen = SelectObject(drawDC->m_hDC, pen1); + MoveToEx(drawDC->m_hDC, 0, m_CtrlSize.cy - 1, &point); + LineTo(drawDC->m_hDC, m_CtrlSize.cx - 1, m_CtrlSize.cy - 1); + LineTo(drawDC->m_hDC, m_CtrlSize.cx - 1, 0); + LineTo(drawDC->m_hDC, m_CtrlSize.cx - 1, m_CtrlSize.cy - 1); + SelectObject(drawDC->m_hDC, pen2); + MoveToEx(drawDC->m_hDC, 0, m_CtrlSize.cy - 2, &point); + LineTo(drawDC->m_hDC, 0, 0); + LineTo(drawDC->m_hDC, m_CtrlSize.cx - 1, 0); + SelectObject(drawDC->m_hDC, oldPen); + + pen1.DeleteObject(); + pen2.DeleteObject(); + } + + pDrawBmpDC->SelectObject(&pOldDrawBitmap); + pDrawBmpDC->DeleteDC(); + delete pDrawBmpDC; + pMemDC->SelectObject(&pOldMemBitmap); + pMemDC->DeleteDC(); + delete pMemDC; + pBkDC->SelectObject(&pOldBkBitmap); + pBkDC->DeleteDC(); + delete pBkDC; +} + +void CButtonFx::DrawString(CDC* drawDC, LPDRAWITEMSTRUCT lpDrawItemStruct) +{ + CString title; + GetWindowText(title); + + if (title.IsEmpty()) + { + return; + } + + drawDC->SetBkMode(TRANSPARENT); + CRect rect = (CRect)(lpDrawItemStruct->rcItem); + rect.top += m_Margin.top; + rect.left += m_Margin.left; + rect.bottom -= m_Margin.bottom; + rect.right -= m_Margin.right; + + HGDIOBJ oldFont = drawDC->SelectObject(m_Font); + CArray arr; + arr.RemoveAll(); + + CString resToken; + int curPos = 0; + resToken = title.Tokenize(_T("\r\n"), curPos); + while (resToken != _T("")) + { + arr.Add(resToken); + resToken = title.Tokenize(_T("\r\n"), curPos); + } + + CSize extent; + if ((m_RenderMode & OwnerDrawTransparent) && m_bDarkMode) + { + SetTextColor(drawDC->m_hDC, RGB(255, 255, 255)); + } + else + { + SetTextColor(drawDC->m_hDC, m_TextColor); + } + + if (m_bMeter && rect.Width() < extent.cx) + { + title.Replace(_T(","), _T(".")); + int score = _tstoi((LPCTSTR)title); + title.Format(_T("%d"), score); + extent = drawDC->GetTextExtent(title); + } + + if (!m_Label.IsEmpty() && m_TextFormat != BS_CENTER) + { + drawDC->DrawText(title, title.GetLength(), rect, m_TextFormat); + drawDC->SelectObject(oldFont); + + oldFont = drawDC->SelectObject(m_FontToolTip); + drawDC->DrawText(m_Label, m_Label.GetLength(), rect, m_LabelFormat); + drawDC->DrawText(m_Unit, m_Unit.GetLength(), rect, m_UnitFormat); + } + else if (!m_Label.IsEmpty()) + { + drawDC->DrawText(title, title.GetLength(), rect, DT_CENTER | DT_VCENTER | DT_SINGLELINE); + drawDC->SelectObject(oldFont); + + oldFont = drawDC->SelectObject(m_FontToolTip); + drawDC->DrawText(m_Label, m_Label.GetLength(), rect, m_LabelFormat); + drawDC->DrawText(m_Unit, m_Unit.GetLength(), rect, m_UnitFormat); + } + else + { + for (int i = 0; i < arr.GetCount(); i++) + { + CRect r; + r.top = rect.top + (LONG)(((double)rect.Height()) / arr.GetCount() * i); + r.bottom = rect.top + (LONG)(((double)rect.Height()) / arr.GetCount() * (i + 1.0)); + r.left = rect.left; + r.right = rect.right; + + CRect rectI; + HGDIOBJ oldFont = drawDC->SelectObject(m_Font); + if ((m_RenderMode & OwnerDrawTransparent) && m_bDarkMode) + { + SetTextColor(drawDC->m_hDC, RGB(255, 255, 255)); + } + else + { + SetTextColor(drawDC->m_hDC, m_TextColor); + } + GetTextExtentPoint32(drawDC->m_hDC, arr.GetAt(i), arr.GetAt(i).GetLength() + 1, &extent); + + if (m_TextAlign == BS_LEFT) + { + drawDC->DrawText(arr.GetAt(i), arr.GetAt(i).GetLength(), r, DT_LEFT | DT_VCENTER | DT_SINGLELINE); + } + else if (m_TextAlign == BS_RIGHT) + { + drawDC->DrawText(arr.GetAt(i), arr.GetAt(i).GetLength(), r, DT_RIGHT | DT_VCENTER | DT_SINGLELINE); + } + else + { + drawDC->DrawText(arr.GetAt(i), arr.GetAt(i).GetLength(), r, DT_CENTER | DT_VCENTER | DT_SINGLELINE); + } + + drawDC->SelectObject(oldFont); + } + } +} + +//------------------------------------------------ +// Image +//------------------------------------------------ + +BOOL CButtonFx::LoadBitmap(LPCTSTR fileName) +{ + if (m_bHighContrast) { return FALSE; } + if (fileName == NULL) { return FALSE; } + + m_CtrlImage.Destroy(); + m_CtrlImage.Load(fileName); + if (m_CtrlImage.IsNull()) { return FALSE; } + + return LoadBitmap((HBITMAP)m_CtrlImage); +} + +BOOL CButtonFx::LoadBitmap(HBITMAP hBitmap) +{ + if (m_bHighContrast) { return FALSE; } + + m_CtrlBitmap.Detach(); + m_CtrlBitmap.Attach(hBitmap); + + return SetBitmap(m_CtrlBitmap); +} + +void CButtonFx::SetBkReload(void) +{ + m_bBkBitmapInit = FALSE; + m_bBkLoad = FALSE; +} + +BOOL CButtonFx::SetBitmap(CBitmap& bitmap) +{ + if (m_bHighContrast) { return FALSE; } + + BITMAP bitmapInfo; + bitmap.GetBitmap(&bitmapInfo); + + if (m_CtrlSize.cx != bitmapInfo.bmWidth + || m_CtrlSize.cy != bitmapInfo.bmHeight / m_ImageCount) + { + ModifyStyle(BS_OWNERDRAW, 0); + return FALSE; + } + else + { + ModifyStyle(0, BS_OWNERDRAW); + return TRUE; + } +} + +void CButtonFx::LoadCtrlBk(CDC* drawDC) +{ + if (m_bHighContrast) { SetBkReload(); return; } + + if (m_BkBitmap.m_hObject != NULL) + { + BITMAP bitmapInfo; + m_BkBitmap.GetBitmap(&bitmapInfo); + if (bitmapInfo.bmBitsPixel != drawDC->GetDeviceCaps(BITSPIXEL)) + { + SetBkReload(); + } + } + + if (&m_CtrlBitmap != NULL) + { + if (!m_bBkBitmapInit) + { + m_BkBitmap.DeleteObject(); + m_BkBitmap.CreateCompatibleBitmap(drawDC, m_CtrlSize.cx, m_CtrlSize.cy); + m_bBkBitmapInit = TRUE; + } + + if (!m_bBkLoad) + { + CBitmap* pOldBitmap; + CDC* pMemDC = new CDC; + pMemDC->CreateCompatibleDC(drawDC); + pOldBitmap = pMemDC->SelectObject(&m_BkBitmap); + pMemDC->StretchBlt(0, 0, m_CtrlSize.cx, m_CtrlSize.cy, m_BkDC, m_X, m_Y, m_CtrlSize.cx, m_CtrlSize.cy, SRCCOPY); + pMemDC->SelectObject(pOldBitmap); + pMemDC->DeleteDC(); + delete pMemDC; + m_bBkLoad = TRUE; + } + } +} + +//------------------------------------------------ +// Font +//------------------------------------------------ + +void CButtonFx::SetFontEx(CString face, int size, int sizeToolTip, double zoomRatio, double fontRatio, COLORREF textColor, LONG fontWeight, BYTE fontRender) +{ + LOGFONT logFont = { 0 }; + logFont.lfCharSet = DEFAULT_CHARSET; + logFont.lfHeight = (LONG)(-1 * size * zoomRatio * fontRatio); + logFont.lfQuality = fontRender; + logFont.lfWeight = fontWeight; + + if (face.GetLength() < 32) + { + wsprintf(logFont.lfFaceName, _T("%s"), (LPCTSTR)face); + } + else + { + wsprintf(logFont.lfFaceName, _T("")); + } + + m_Font.DeleteObject(); + m_Font.CreateFontIndirect(&logFont); + SetFont(&m_Font); + + logFont.lfHeight = (LONG)(-1 * sizeToolTip * zoomRatio * fontRatio); + m_FontToolTip.DeleteObject(); + m_FontToolTip.CreateFontIndirect(&logFont); + + m_TextColor = textColor; + + if (m_ToolTip.m_hWnd != NULL) + { + m_ToolTip.SetFont(&m_FontToolTip); + } +} + +//------------------------------------------------ +// Mouse +//------------------------------------------------ + +void CButtonFx::SetHandCursor(BOOL bHandCuror) +{ + m_bHandCursor = bHandCuror; +} + +void CButtonFx::OnMouseMove(UINT nFlags, CPoint point) +{ + if (!m_bTrackingNow) + { +#if _MSC_VER <= 1310 + typedef BOOL(WINAPI* Func_TrackMouseEvent)(LPTRACKMOUSEEVENT); + static Func_TrackMouseEvent p_TrackMouseEvent = NULL; + static BOOL bInit_TrackMouseEvent = FALSE; + + if (bInit_TrackMouseEvent && p_TrackMouseEvent == NULL) + { + return; // TrackMouseEvent is not available + } + else + { + HMODULE hModule = GetModuleHandle(_T("user32.dll")); + if (hModule) + { + p_TrackMouseEvent = (Func_TrackMouseEvent)GetProcAddress(hModule, "TrackMouseEvent"); + } + } + + if (p_TrackMouseEvent != NULL) + { + TRACKMOUSEEVENT tme = { sizeof(TRACKMOUSEEVENT) }; + tme.hwndTrack = m_hWnd; + tme.dwFlags = TME_LEAVE | TME_HOVER; + tme.dwHoverTime = 1; + m_bTrackingNow = p_TrackMouseEvent(&tme); + } + bInit_TrackMouseEvent = TRUE; +#else + if (!m_bTrackingNow) + { + TRACKMOUSEEVENT tme = { sizeof(TRACKMOUSEEVENT) }; + tme.hwndTrack = m_hWnd; + tme.dwFlags = TME_LEAVE | TME_HOVER; + tme.dwHoverTime = 1; + m_bTrackingNow = _TrackMouseEvent(&tme); + } +#endif + } + + CButton::OnMouseMove(nFlags, point); +} + +void CButtonFx::OnMouseHover(UINT nFlags, CPoint point) +{ +#if _MSC_VER > 1310 + CButton::OnMouseHover(nFlags, point); +#endif + + m_bHover = TRUE; + Invalidate(); +} + +void CButtonFx::OnMouseLeave() +{ +#if _MSC_VER > 1310 + CButton::OnMouseLeave(); +#endif + + m_bTrackingNow = FALSE; + m_bHover = FALSE; + Invalidate(); +} + +void CButtonFx::OnSetfocus() +{ + m_bFocas = TRUE; + Invalidate(); +} + +void CButtonFx::OnKillfocus() +{ + m_bFocas = FALSE; + Invalidate(); +} + +BOOL CButtonFx::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message) +{ + HCURSOR hCursor = NULL; + if (m_bHandCursor) + { + hCursor = AfxGetApp()->LoadStandardCursor(IDC_HAND); + if (hCursor) + { + ::SetCursor(hCursor); + } + } + else + { + hCursor = AfxGetApp()->LoadStandardCursor(IDC_ARROW); + if (hCursor) + { + ::SetCursor(hCursor); + } + } + + return TRUE; +} + +void CButtonFx::SetSelected(BOOL bSelected) +{ + m_bSelected = bSelected; + Invalidate(); +} + +//------------------------------------------------ +// ToolTip +//------------------------------------------------ + +void CButtonFx::SetToolTipText(LPCTSTR text) +{ + if (text == NULL) { return; } + + InitToolTip(); + m_ToolTipText = text; + if (m_ToolTip.GetToolCount() == 0) + { + CRect rect; + GetClientRect(rect); + m_ToolTip.AddTool(this, m_ToolTipText, rect, 1); + } + else + { + m_ToolTip.UpdateTipText(m_ToolTipText, this, 1); + } + + SetToolTipActivate(TRUE); +} + +void CButtonFx::SetToolTipActivate(BOOL bActivate) +{ + if (m_ToolTip.GetToolCount() == 0) { return; } + m_ToolTip.Activate(bActivate); +} + +void CButtonFx::SetToolTipWindowText(LPCTSTR text) +{ + SetToolTipText(text); + SetWindowText(text); +} + +CString CButtonFx::GetToolTipText() +{ + return m_ToolTipText; +} + +void CButtonFx::InitToolTip() +{ + if (m_ToolTip.m_hWnd == NULL) + { + m_ToolTip.Create(this, TTS_ALWAYSTIP | TTS_BALLOON | TTS_NOANIMATE | TTS_NOFADE); + m_ToolTip.Activate(FALSE); + m_ToolTip.SetFont(&m_FontToolTip); + m_ToolTip.SendMessage(TTM_SETMAXTIPWIDTH, 0, 1024); + m_ToolTip.SetDelayTime(TTDT_AUTOPOP, 8000); + m_ToolTip.SetDelayTime(TTDT_INITIAL, 500); + m_ToolTip.SetDelayTime(TTDT_RESHOW, 100); + } +} + +BOOL CButtonFx::PreTranslateMessage(MSG* pMsg) +{ + InitToolTip(); + m_ToolTip.RelayEvent(pMsg); + + return CButton::PreTranslateMessage(pMsg); +} + +BOOL CButtonFx::OnEraseBkgnd(CDC* pDC) +{ + return TRUE; +} \ No newline at end of file diff --git a/CristalDiskMark/source/CrystalDiskMark/Priscilla/ButtonFx.h b/CristalDiskMark/source/CrystalDiskMark/Priscilla/ButtonFx.h new file mode 100644 index 0000000..0431d18 --- /dev/null +++ b/CristalDiskMark/source/CrystalDiskMark/Priscilla/ButtonFx.h @@ -0,0 +1,131 @@ +/*---------------------------------------------------------------------------*/ +// Author : hiyohiyo +// Mail : hiyohiyo@crystalmark.info +// Web : https://crystalmark.info/ +// License : MIT License +/*---------------------------------------------------------------------------*/ + +#pragma once + +#include + +#include "ImageFx.h" + +class CButtonFx : public CButton +{ + DECLARE_DYNAMIC(CButtonFx); + +public: + // Constructors + CButtonFx(); + virtual ~CButtonFx(); + + // Control + BOOL InitControl(int x, int y, int width, int height, double zoomRatio, HPALETTE hPal, CDC* bkDC, + LPCTSTR imagePath, int imageCount, DWORD textAlign, int renderMode, BOOL bHighContrast, BOOL bDarkMode, BOOL bDrawFrame); + BOOL ReloadImage(LPCTSTR imagePath, UINT imageCount); + void SetMargin(int top, int left, int bottom, int right, double zoomRatio); + CSize GetSize(void); + void SetDrawFrame(BOOL bDrawFrame); + void SetGlassColor(COLORREF glassColor, BYTE glassAlpha); + void SetMeter(BOOL bMeter, double meterRatio); + void SetLabelUnit(CString label, CString unit); + void SetLabelUnitFormat(UINT labelFormat, UINT unitFormat); + void SetTextFormat(UINT format); + + // Font + void SetFontEx(CString face, int size, int sizeToolTip, double zoomRatio, double fontRatio = 1.0, + COLORREF textColor = RGB(0, 0, 0), LONG fontWeight = FW_NORMAL, BYTE fontRender = CLEARTYPE_NATURAL_QUALITY); + + // Mouse + void SetHandCursor(BOOL bHandCuror = TRUE); + void SetSelected(BOOL bSelected = TRUE); + + // ToolTip + void SetToolTipText(LPCTSTR text); + void SetToolTipActivate(BOOL bActivate = TRUE); + void SetToolTipWindowText(LPCTSTR text); + CString GetToolTipText(); + +protected: + // Draw Control + virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct); + virtual void DrawControl(CDC* drawDC, LPDRAWITEMSTRUCT lpDrawItemStruct, CBitmap& ctrlBitmap, CBitmap& bkBitmap, int no); + virtual void DrawString(CDC* drawDC, LPDRAWITEMSTRUCT lpDrawItemStruct); + + // Image + BOOL LoadBitmap(LPCTSTR pFileName); + BOOL LoadBitmap(HBITMAP hBitmap); + void SetBkReload(void); + BOOL SetBitmap(CBitmap& bitmap); + void LoadCtrlBk(CDC* drawDC); + + // ToolTip + void InitToolTip(); + virtual BOOL PreTranslateMessage(MSG* pMsg); + + // Message Map + DECLARE_MESSAGE_MAP() + afx_msg BOOL OnEraseBkgnd(CDC* pDC); + afx_msg void OnMouseMove(UINT nFlags, CPoint point); + afx_msg void OnMouseHover(UINT nFlags, CPoint point); + afx_msg void OnMouseLeave(); + afx_msg void OnKillfocus(); + afx_msg void OnSetfocus(); + afx_msg BOOL OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message); + +protected: + // Control + int m_X; + int m_Y; + CSize m_CtrlSize; + CRect m_Margin; + int m_RenderMode; + BOOL m_bHighContrast; + BOOL m_bDarkMode; + BOOL m_bDrawFrame; + COLORREF m_FrameColor; + HPALETTE m_hPal; + + CString m_Label; + CString m_Unit; + + UINT m_TextFormat; + UINT m_LabelFormat; + UINT m_UnitFormat; + + // Glass + COLORREF m_GlassColor; + BYTE m_GlassAlpha; + + // Meter + BOOL m_bMeter; + double m_MeterRatio; + + // Image + CString m_ImagePath; + int m_ImageCount; + CDC* m_BkDC; + CBitmap m_BkBitmap; + BOOL m_bBkBitmapInit; + BOOL m_bBkLoad; + CBitmap m_CtrlBitmap; + CImage m_CtrlImage; + + // Font + DWORD m_TextAlign; + CFont m_Font; + CFont m_FontToolTip; + COLORREF m_TextColor; + + // ToolTip + CToolTipCtrl m_ToolTip; + CString m_ToolTipText; + + // Mouse + BOOL m_bHover; + BOOL m_bFocas; + BOOL m_bTrackingNow; + BOOL m_bHandCursor; + BOOL m_bSelected; +}; diff --git a/CristalDiskMark/source/CrystalDiskMark/Priscilla/ComboBoxFx.cpp b/CristalDiskMark/source/CrystalDiskMark/Priscilla/ComboBoxFx.cpp new file mode 100644 index 0000000..83237c9 --- /dev/null +++ b/CristalDiskMark/source/CrystalDiskMark/Priscilla/ComboBoxFx.cpp @@ -0,0 +1,836 @@ +/*---------------------------------------------------------------------------*/ +// Author : hiyohiyo +// Mail : hiyohiyo@crystalmark.info +// Web : https://crystalmark.info/ +// License : MIT License +/*---------------------------------------------------------------------------*/ + +#include "stdafx.h" +#include "ComboBoxFx.h" + +#if _MSC_VER <= 1310 +#define ON_WM_MOUSEHOVER() \ + { 0x2A1 /*WM_MOUSEHOVER*/, 0, 0, 0, AfxSig_vwp, \ + (AFX_PMSG)(AFX_PMSGW) \ + (static_cast< void (AFX_MSG_CALL CWnd::*)(UINT, CPoint) > (OnMouseHover)) }, + +#define ON_WM_MOUSELEAVE() \ + { 0x2A3 /*WM_MOUSELEAVE*/, 0, 0, 0, AfxSig_vv, \ + (AFX_PMSG)(AFX_PMSGW) \ + (static_cast< void (AFX_MSG_CALL CWnd::*)(void) > (OnMouseLeave)) }, +#endif + +////------------------------------------------------ +// CComboBoxFx +////------------------------------------------------ + +CComboBoxFx::CComboBoxFx() +{ + // Control + m_X = 0; + m_Y = 0; + m_ZoomRatio = 1.0; + m_bHighContrast = FALSE; + m_bDarkMode = FALSE; + m_RenderMode = SystemDraw; + m_Margin.top = 0; + m_Margin.left = 0; + m_Margin.bottom = 0; + m_Margin.right = 0; + + // Alpha/Glass + m_Alpha = 255; + m_GlassColor = RGB(255, 255, 255); + m_GlassAlpha = 255; + + // Image + m_ImageCount = 0; + m_ImagePath = _T(""); + m_BkDC = NULL; + m_bBkBitmapInit = FALSE; + m_bBkLoad = FALSE; + + // Font + m_TextAlign = SS_LEFT; + m_TextColor = RGB(0, 0, 0); + m_TextColorSelected = RGB(255, 255, 255); + m_BkColor = RGB(255, 255, 255); + m_BkColorSelected = RGB(230, 230, 230); + m_TextColorHc = RGB(255, 255, 255); + m_TextColorSelectedHc = RGB(0, 0, 0); + m_BkColorHc = RGB(0, 0, 0); + m_BkColorSelectedHc = RGB(0, 255, 255); + m_FontHeight = 16; + m_FontRender = CLEARTYPE_NATURAL_QUALITY; + + // Mouse + m_bHover = FALSE; + m_bFocas = FALSE; + m_bTrackingNow = FALSE; + m_bHandCursor = FALSE; +} + +CComboBoxFx::~CComboBoxFx() +{ + m_BkBrush.DeleteObject(); +} + +IMPLEMENT_DYNAMIC(CComboBoxFx, CComboBox) + +BEGIN_MESSAGE_MAP(CComboBoxFx, CComboBox) + //{{AFX_MSG_MAP(CComboBoxFx) + ON_WM_CTLCOLOR() + ON_WM_MOUSEMOVE() + ON_WM_MOUSEHOVER() + ON_WM_MOUSELEAVE() + ON_WM_KILLFOCUS() + ON_WM_SETFOCUS() + ON_WM_SETCURSOR() + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +//------------------------------------------------ +// Control +//------------------------------------------------ + +BOOL CComboBoxFx::InitControl(int x, int y, int width, int height, double zoomRatio, CDC* bkDC, + LPCWSTR imagePath, int imageCount, DWORD textAlign, int renderMode, BOOL bHighContrast, BOOL bDarkMode, + COLORREF bkColor, COLORREF bkColorSelected, COLORREF glassColor, BYTE glassAlpha) +{ + m_X = (int)(x * zoomRatio); + m_Y = (int)(y * zoomRatio); + m_ZoomRatio = zoomRatio; + m_CtrlSize.cx = (int)(width * zoomRatio); + m_CtrlSize.cy = (int)(height * zoomRatio); + MoveWindow(m_X, m_Y, m_CtrlSize.cx, m_CtrlSize.cy); + + m_BkDC = bkDC; + m_ImagePath = imagePath; + m_ImageCount = imageCount; + m_RenderMode = renderMode; + + m_BkColor = bkColor; + m_BkColorSelected = bkColorSelected; + m_GlassColor = glassColor; + m_GlassAlpha = glassAlpha; + + // BkBrush + m_BkBrush.DeleteObject(); + if (bDarkMode) + { + m_BkBrush.CreateSolidBrush(RGB(32, 32, 32)); + } + else + { + m_BkBrush.CreateSolidBrush(bkColor); + } + + if (ES_LEFT <= textAlign && textAlign <= ES_RIGHT) + { + m_TextAlign = textAlign; + ModifyStyle(0, m_TextAlign); + } + + if (m_ToolTip.m_hWnd != NULL) + { + if (m_ToolTip.GetToolCount() != 0) + { + m_ToolTip.DelTool(this, 1); + } + CRect rect; + GetClientRect(rect); + m_ToolTip.AddTool(this, m_ToolTipText, rect, 1); + } + + m_bHighContrast = bHighContrast; + m_bDarkMode = bDarkMode; + + if (renderMode & SystemDraw) + { +#if _MSC_VER <= 1310 + if (IsNT3()) + { + ModifyStyle(0, WS_BORDER, SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_FRAMECHANGED); + } +#endif + + return TRUE; + } + else + { + m_ImageCount = 1; + m_CtrlImage.Destroy(); + m_CtrlImage.Create(m_CtrlSize.cx, m_CtrlSize.cy * m_ImageCount, 32); + m_CtrlBitmap.Detach(); + m_CtrlBitmap.Attach((HBITMAP)m_CtrlImage); + DWORD length = m_CtrlSize.cx * m_CtrlSize.cy * m_ImageCount * 4; + BYTE* bitmapBits = new BYTE[length]; + m_CtrlBitmap.GetBitmapBits(length, bitmapBits); + + BYTE r, g, b, a; + if (renderMode & OwnerDrawGlass) + { + r = (BYTE)GetRValue(m_GlassColor); + g = (BYTE)GetGValue(m_GlassColor); + b = (BYTE)GetBValue(m_GlassColor); + a = m_GlassAlpha; + } + else // OwnerDrawTransparent + { + r = 0; + g = 0; + b = 0; + a = 0; + } + + for (int y = 0; y < (int)(m_CtrlSize.cy * m_ImageCount); y++) + { + for (int x = 0; x < m_CtrlSize.cx; x++) + { + DWORD p = (y * m_CtrlSize.cx + x) * 4; +#if _MSC_VER > 1310 +#pragma warning( disable : 6386 ) +#endif + bitmapBits[p + 0] = b; + bitmapBits[p + 1] = g; + bitmapBits[p + 2] = r; + bitmapBits[p + 3] = a; +#if _MSC_VER > 1310 +#pragma warning( default : 6386 ) +#endif + } + } + + m_CtrlBitmap.SetBitmapBits(length, bitmapBits); + delete[] bitmapBits; + } + + SetBkReload(); + Invalidate(); + + return TRUE; +} + +void CComboBoxFx::SetFontHeight(int height, double zoomRatio, double fontRatio) +{ + m_FontHeight = (LONG)(-1 * height * zoomRatio * fontRatio); +} + +void CComboBoxFx::SetItemHeightEx(int nIndex, int height, double zoomRatio, double fontRatio) +{ + if (nIndex == -1) + { + CRect rc; + GetWindowRect(&rc); + CComboBox::SetItemHeight(-1, (UINT)(height * zoomRatio - rc.Height() + GetItemHeight(-1))); + } + else + { + CComboBox::SetItemHeight(nIndex, (UINT)(height * zoomRatio * fontRatio)); + } +} + +void CComboBoxFx::SetItemHeightAll(int height, double zoomRatio, double fontRatio) +{ + m_FontHeight = (LONG)(-1 * height * zoomRatio * fontRatio); + + CRect rc; + GetWindowRect(&rc); + CComboBox::SetItemHeight(-1, (UINT)(height * zoomRatio - rc.Height() + GetItemHeight(-1))); + + for(int i = 0; i < this->GetCount(); i++) + { + CComboBox::SetItemHeight(i, (UINT)(height * zoomRatio * fontRatio)); + } +} + +void CComboBoxFx::SetMargin(int top, int left, int bottom, int right, double zoomRatio) +{ + m_Margin.top = (int)(top * zoomRatio); + m_Margin.left = (int)(left * zoomRatio); + m_Margin.bottom = (int)(bottom * zoomRatio); + m_Margin.right = (int)(right * zoomRatio); + m_ZoomRatio = zoomRatio; +} + +CSize CComboBoxFx::GetSize(void) +{ + return m_CtrlSize; +} + +void CComboBoxFx::SetGlassColor(COLORREF glassColor, BYTE glassAlpha) +{ + m_GlassColor = glassColor; + m_GlassAlpha = glassAlpha; +} + +void CComboBoxFx::SetAlpha(BYTE alpha) +{ + m_Alpha = alpha; +} + +HWND CComboBoxFx::GetListHwnd() +{ +#if _MSC_VER > 1310 + COMBOBOXINFO info = { 0 }; + info.cbSize = sizeof(COMBOBOXINFO); + GetComboBoxInfo(&info); + + return info.hwndList; +#else + return NULL; +#endif +} + +HBRUSH CComboBoxFx::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) +{ + HBRUSH hbr = CComboBox::OnCtlColor(pDC, pWnd, nCtlColor); + switch (nCtlColor) { + case CTLCOLOR_EDIT: + pDC->SetBkMode(TRANSPARENT); + return hbr; + case CTLCOLOR_LISTBOX: + pDC->SetBkMode(TRANSPARENT); + return m_BkBrush; + default: + return hbr; + } +} + +//------------------------------------------------ +// Draw Control +//------------------------------------------------ + +void CComboBoxFx::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) +{ + if (lpDrawItemStruct->itemID == -1) { return; } + + static COLORREF textColor; + static COLORREF textColorSelected; + static COLORREF bkColor; + static COLORREF bkColorSelected; + + static int count = 0; + if (m_bHighContrast) + { + textColor = GetTextColor(lpDrawItemStruct->hDC); + textColorSelected = RGB(0, 0, 0); + bkColor = GetBkColor(lpDrawItemStruct->hDC); + bkColorSelected = RGB(0, 255, 255); + + if (bkColor <= RGB(0x80, 0x80, 0x80)) { textColor = RGB(255, 255, 255); } + else { textColor = RGB(0, 0, 0); } + } + else if (m_bDarkMode) + { + textColor = RGB(255, 255, 255); + textColorSelected = RGB(255, 255, 255); + bkColor = RGB(32, 32, 32); + bkColorSelected = RGB(77, 77, 77); + } + else + { + textColor = m_TextColor; + textColorSelected = m_TextColorSelected; + bkColor = m_BkColor; + bkColorSelected = m_BkColorSelected; + } + + CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC); + LoadCtrlBk(pDC); + CString title; + GetLBText(lpDrawItemStruct->itemID, title); + + CBrush Brush; + CBrush* pOldBrush; + if (lpDrawItemStruct->rcItem.left != 0 && !m_bHighContrast) + { + DrawControl(title, pDC, lpDrawItemStruct, m_CtrlBitmap, m_BkBitmap, ControlImageNormal); + Brush.CreateSolidBrush(bkColorSelected); + pOldBrush = pDC->SelectObject(&Brush); + if (lpDrawItemStruct->itemState & ODS_SELECTED) + { + RECT rc = lpDrawItemStruct->rcItem; + // rc.top = (LONG)(rc.bottom - 2 * m_ZoomRatio); + rc.right = (LONG)(rc.left + 3 * m_ZoomRatio); + FillRect(lpDrawItemStruct->hDC, &rc, (HBRUSH)Brush); + } + DrawString(title, pDC, lpDrawItemStruct, textColor); + +#if _MSC_VER <= 1310 + if (IsNT3() && IsWindowEnabled()) + { + DWORD oldTextAlign = m_TextAlign; + m_TextAlign = ES_RIGHT; + DrawString(_T("v"), pDC, lpDrawItemStruct, textColor); + m_TextAlign = oldTextAlign; + } +#endif + } + else + { + if (lpDrawItemStruct->itemState & ODS_SELECTED) + { + Brush.CreateSolidBrush(bkColorSelected); + pOldBrush = pDC->SelectObject(&Brush); + FillRect(lpDrawItemStruct->hDC, &lpDrawItemStruct->rcItem, (HBRUSH)Brush); + DrawString(title, pDC, lpDrawItemStruct, textColorSelected); + } + else + { + Brush.CreateSolidBrush(bkColor); + pOldBrush = pDC->SelectObject(&Brush); + FillRect(lpDrawItemStruct->hDC, &lpDrawItemStruct->rcItem, (HBRUSH)Brush); + DrawString(title, pDC, lpDrawItemStruct, textColor); + } + } + pDC->SelectObject(pOldBrush); + Brush.DeleteObject(); +} + +void CComboBoxFx::MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct) +{ + lpMeasureItemStruct->itemHeight = abs(m_FontHeight); +} + +void CComboBoxFx::DrawControl(CString title, CDC* drawDC, LPDRAWITEMSTRUCT lpDrawItemStruct, CBitmap& ctrlBitmap, CBitmap& bkBitmap, int no) +{ + CDC* pMemDC = new CDC; + CBitmap* pOldMemBitmap; + pMemDC->CreateCompatibleDC(drawDC); + pOldMemBitmap = pMemDC->SelectObject(&ctrlBitmap); + CDC* pBkDC = new CDC; + CBitmap* pOldBkBitmap; + pBkDC->CreateCompatibleDC(drawDC); + pOldBkBitmap = pBkDC->SelectObject(&bkBitmap); + + CBitmap DrawBmp; + DrawBmp.CreateCompatibleBitmap(drawDC, m_CtrlSize.cx, m_CtrlSize.cy); + CDC* pDrawBmpDC = new CDC; + CBitmap* pOldDrawBitmap; + pDrawBmpDC->CreateCompatibleDC(drawDC); + pOldDrawBitmap = pDrawBmpDC->SelectObject(&DrawBmp); + + int color = drawDC->GetDeviceCaps(BITSPIXEL) * drawDC->GetDeviceCaps(PLANES); + + if (!m_CtrlImage.IsNull()) + { + if (m_CtrlImage.GetBPP() == 32) + { + CBitmap* bk32Bitmap; + CImage bk32Image; + if (color == 32) + { + bk32Bitmap = &bkBitmap; + } + else + { + bk32Image.Create(m_CtrlSize.cx, m_CtrlSize.cy, 32); + ::BitBlt(bk32Image.GetDC(), 0, 0, m_CtrlSize.cx, m_CtrlSize.cy, *pBkDC, 0, 0, SRCCOPY); + bk32Bitmap = CBitmap::FromHandle((HBITMAP)bk32Image); + } + + BITMAP CtlBmpInfo, DstBmpInfo; + bk32Bitmap->GetBitmap(&DstBmpInfo); + DWORD DstLineBytes = DstBmpInfo.bmWidthBytes; + DWORD DstMemSize = DstLineBytes * DstBmpInfo.bmHeight; + ctrlBitmap.GetBitmap(&CtlBmpInfo); + DWORD CtlLineBytes = CtlBmpInfo.bmWidthBytes; + DWORD CtlMemSize = CtlLineBytes * CtlBmpInfo.bmHeight; + BYTE* DstBuffer = new BYTE[DstMemSize]; + bk32Bitmap->GetBitmapBits(DstMemSize, DstBuffer); + BYTE* CtlBuffer = new BYTE[CtlMemSize]; + ctrlBitmap.GetBitmapBits(CtlMemSize, CtlBuffer); + + int baseY = m_CtrlSize.cy * no; + for (LONG py = 0; py < DstBmpInfo.bmHeight; py++) + { + int dn = py * DstLineBytes; + int cn = (baseY + py) * CtlLineBytes; + for (LONG px = 0; px < DstBmpInfo.bmWidth; px++) + { +#if _MSC_VER > 1310 +#pragma warning( disable : 6385 ) +#pragma warning( disable : 6386 ) +#endif + BYTE a = CtlBuffer[cn + 3]; + BYTE na = 255 - a; + DstBuffer[dn + 0] = (BYTE)((CtlBuffer[cn + 0] * a + DstBuffer[dn + 0] * na) / 255); + DstBuffer[dn + 1] = (BYTE)((CtlBuffer[cn + 1] * a + DstBuffer[dn + 1] * na) / 255); + DstBuffer[dn + 2] = (BYTE)((CtlBuffer[cn + 2] * a + DstBuffer[dn + 2] * na) / 255); + dn += (DstBmpInfo.bmBitsPixel / 8); + cn += (CtlBmpInfo.bmBitsPixel / 8); +#if _MSC_VER > 1310 +#pragma warning( default : 6386 ) +#pragma warning( default : 6385 ) +#endif + } + } + + if (color == 32) + { + DrawBmp.SetBitmapBits(DstMemSize, DstBuffer); + } + else + { + bk32Bitmap->SetBitmapBits(DstMemSize, DstBuffer); + ::BitBlt(pDrawBmpDC->GetSafeHdc(), 0, 0, m_CtrlSize.cx, m_CtrlSize.cy, bk32Image.GetDC(), 0, 0, SRCCOPY); + bk32Image.ReleaseDC(); + } + drawDC->BitBlt(0, 0, m_CtrlSize.cx, m_CtrlSize.cy, pDrawBmpDC, 0, 0, SRCCOPY); + + delete[] DstBuffer; + delete[] CtlBuffer; + } + else + { + pDrawBmpDC->BitBlt(0, 0, m_CtrlSize.cx, m_CtrlSize.cy, pMemDC, 0, m_CtrlSize.cy * no, SRCCOPY); + drawDC->BitBlt(0, 0, m_CtrlSize.cx, m_CtrlSize.cy, pDrawBmpDC, 0, 0, SRCCOPY); + } + } + else + { + pDrawBmpDC->BitBlt(0, 0, m_CtrlSize.cx, m_CtrlSize.cy, pBkDC, 0, m_CtrlSize.cy * no, SRCCOPY); + drawDC->BitBlt(0, 0, m_CtrlSize.cx, m_CtrlSize.cy, pDrawBmpDC, 0, 0, SRCCOPY); + } + + pDrawBmpDC->SelectObject(&pOldDrawBitmap); + pDrawBmpDC->DeleteDC(); + delete pDrawBmpDC; + pMemDC->SelectObject(&pOldMemBitmap); + pMemDC->DeleteDC(); + delete pMemDC; + pBkDC->SelectObject(&pOldBkBitmap); + pBkDC->DeleteDC(); + delete pBkDC; +} + +void CComboBoxFx::DrawString(CString title, CDC* drawDC, LPDRAWITEMSTRUCT lpDrawItemStruct, COLORREF textColor) +{ + if (title.IsEmpty()) + { + return; + } + + drawDC->SetBkMode(TRANSPARENT); + CRect rect = (CRect)(lpDrawItemStruct->rcItem); + rect.top += m_Margin.top; + rect.left += m_Margin.left; + rect.bottom -= m_Margin.bottom; + rect.right -= m_Margin.right; + drawDC->SetTextColor(textColor); + + if (m_TextAlign == ES_LEFT) + { + drawDC->DrawText(title, title.GetLength(), rect, DT_LEFT | DT_VCENTER | DT_SINGLELINE); + } + else if (m_TextAlign == ES_RIGHT) + { + drawDC->DrawText(title, title.GetLength(), rect, DT_RIGHT | DT_VCENTER | DT_SINGLELINE); + } + else + { + drawDC->DrawText(title, title.GetLength(), rect, DT_CENTER | DT_VCENTER | DT_SINGLELINE); + } +} + +//------------------------------------------------ +// Image +//------------------------------------------------ + +BOOL CComboBoxFx::LoadBitmap(LPCTSTR fileName) +{ + if (m_bHighContrast) { return FALSE; } + if (fileName == NULL) { return FALSE; } + + m_CtrlImage.Destroy(); + m_CtrlImage.Load(fileName); + if (m_CtrlImage.IsNull()) { return FALSE; } + + return LoadBitmap((HBITMAP)m_CtrlImage); +} + +BOOL CComboBoxFx::LoadBitmap(HBITMAP hBitmap) +{ + if (m_bHighContrast) { return FALSE; } + + m_CtrlBitmap.Detach(); + m_CtrlBitmap.Attach(hBitmap); + + return SetBitmap(m_CtrlBitmap); +} + +void CComboBoxFx::SetBkReload(void) +{ + m_bBkBitmapInit = FALSE; + m_bBkLoad = FALSE; +} + +BOOL CComboBoxFx::SetBitmap(CBitmap& bitmap) +{ + if (m_bHighContrast) { return FALSE; } + + BITMAP bitmapinfo; + bitmap.GetBitmap(&bitmapinfo); + + if (m_CtrlSize.cx != bitmapinfo.bmWidth + || m_CtrlSize.cy != bitmapinfo.bmHeight / m_ImageCount) + { + return FALSE; + } + else + { + return TRUE; + } +} + +void CComboBoxFx::LoadCtrlBk(CDC* drawDC) +{ + if (m_bHighContrast) { SetBkReload(); return; } + + if (m_BkBitmap.m_hObject != NULL) + { + BITMAP bitmapInfo; + m_BkBitmap.GetBitmap(&bitmapInfo); + if (bitmapInfo.bmBitsPixel != drawDC->GetDeviceCaps(BITSPIXEL)) + { + SetBkReload(); + } + } + + if (&m_CtrlBitmap != NULL) + { + if (!m_bBkBitmapInit) + { + m_BkBitmap.DeleteObject(); + m_BkBitmap.CreateCompatibleBitmap(drawDC, m_CtrlSize.cx, m_CtrlSize.cy); + m_bBkBitmapInit = TRUE; + } + + if (!m_bBkLoad) + { + CBitmap* pOldBitmap; + CDC* pMemDC = new CDC; + pMemDC->CreateCompatibleDC(drawDC); + pOldBitmap = pMemDC->SelectObject(&m_BkBitmap); + pMemDC->BitBlt(0, 0, m_CtrlSize.cx, m_CtrlSize.cy, m_BkDC, m_X, m_Y, SRCCOPY); + pMemDC->SelectObject(pOldBitmap); + pMemDC->DeleteDC(); + delete pMemDC; + m_bBkLoad = TRUE; + } + } +} + +//------------------------------------------------ +// Font +//------------------------------------------------ + +void CComboBoxFx::SetFontEx(CString face, int size, int sizeToolTip, double zoomRatio, double fontRatio, + COLORREF textColor, COLORREF textColorSelected, LONG fontWeight, BYTE fontRender) +{ + LOGFONT logFont = { 0 }; + logFont.lfCharSet = DEFAULT_CHARSET; + logFont.lfHeight = (LONG)(-1 * size * zoomRatio * fontRatio); + logFont.lfQuality = fontRender; + logFont.lfWeight = fontWeight; + m_FontRender = fontRender; + + if (face.GetLength() < 32) + { + wsprintf(logFont.lfFaceName, _T("%s"), (LPCTSTR)face); + } + else + { + wsprintf(logFont.lfFaceName, _T("")); + } + + m_Font.DeleteObject(); + m_Font.CreateFontIndirect(&logFont); + SetFont(&m_Font); + + logFont.lfHeight = (LONG)(-1 * sizeToolTip * zoomRatio); + m_FontToolTip.DeleteObject(); + m_FontToolTip.CreateFontIndirect(&logFont); + + if (! m_bHighContrast) + { + m_TextColor = textColor; + m_TextColorSelected = textColorSelected; + } + + if (m_ToolTip.m_hWnd != NULL) + { + m_ToolTip.SetFont(&m_FontToolTip); + } +} + +//------------------------------------------------ +// Mouse +//------------------------------------------------ + +void CComboBoxFx::SetHandCursor(BOOL bHandCuror) +{ + m_bHandCursor = bHandCuror; +} + +void CComboBoxFx::OnMouseMove(UINT nFlags, CPoint point) +{ +#if _MSC_VER <= 1310 + typedef BOOL(WINAPI* Func_TrackMouseEvent)(LPTRACKMOUSEEVENT); + static Func_TrackMouseEvent p_TrackMouseEvent = NULL; + static BOOL bInit_TrackMouseEvent = FALSE; + + if (bInit_TrackMouseEvent && p_TrackMouseEvent == NULL) + { + return; // TrackMouseEvent is not available + } + else + { + HMODULE hModule = GetModuleHandle(_T("user32.dll")); + if (hModule) + { + p_TrackMouseEvent = (Func_TrackMouseEvent)GetProcAddress(hModule, "TrackMouseEvent"); + } + } + + if (p_TrackMouseEvent != NULL) + { + TRACKMOUSEEVENT tme = { sizeof(TRACKMOUSEEVENT) }; + tme.hwndTrack = m_hWnd; + tme.dwFlags = TME_LEAVE | TME_HOVER; + tme.dwHoverTime = 1; + m_bTrackingNow = p_TrackMouseEvent(&tme); + } + bInit_TrackMouseEvent = TRUE; +#else + if (!m_bTrackingNow) + { + TRACKMOUSEEVENT tme = { sizeof(TRACKMOUSEEVENT) }; + tme.hwndTrack = m_hWnd; + tme.dwFlags = TME_LEAVE | TME_HOVER; + tme.dwHoverTime = 1; + m_bTrackingNow = _TrackMouseEvent(&tme); + } +#endif + + CComboBox::OnMouseMove(nFlags, point); +} + +void CComboBoxFx::OnMouseHover(UINT nFlags, CPoint point) +{ +#if _MSC_VER > 1310 + CComboBox::OnMouseHover(nFlags, point); +#endif + m_bHover = TRUE; + Invalidate(); +} + +void CComboBoxFx::OnMouseLeave() +{ +#if _MSC_VER > 1310 + CComboBox::OnMouseLeave(); +#endif + m_bTrackingNow = FALSE; + m_bHover = FALSE; + Invalidate(); +} + +void CComboBoxFx::OnSetfocus() +{ + m_bFocas = TRUE; + Invalidate(); +} + +void CComboBoxFx::OnKillfocus() +{ + m_bFocas = FALSE; + Invalidate(); +} + +BOOL CComboBoxFx::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message) +{ + HCURSOR hCursor = NULL; + if (m_bHandCursor) + { + hCursor = AfxGetApp()->LoadStandardCursor(IDC_HAND); + if (hCursor) + { + ::SetCursor(hCursor); + } + } + else + { + hCursor = AfxGetApp()->LoadStandardCursor(IDC_ARROW); + if (hCursor) + { + ::SetCursor(hCursor); + } + } + + return TRUE; +} + +//------------------------------------------------ +// ToolTip +//------------------------------------------------ + +void CComboBoxFx::SetToolTipText(LPCTSTR text) +{ + if (text == NULL) { return; } + + InitToolTip(); + m_ToolTipText = text; + + if (m_ToolTip.GetToolCount() == 0) + { + CRect rect; + GetClientRect(rect); + m_ToolTip.AddTool(this, m_ToolTipText, rect, 1); + } + else + { + m_ToolTip.UpdateTipText(m_ToolTipText, this, 1); + } + + SetToolTipActivate(TRUE); +} + +void CComboBoxFx::SetToolTipActivate(BOOL bActivate) +{ + if (m_ToolTip.GetToolCount() == 0) { return; } + m_ToolTip.Activate(bActivate); +} + +void CComboBoxFx::SetToolTipWindowText(LPCTSTR pText) +{ + SetToolTipText(pText); + SetWindowText(pText); +} + +CString CComboBoxFx::GetToolTipText() +{ + return m_ToolTipText; +} + +void CComboBoxFx::InitToolTip() +{ + if (m_ToolTip.m_hWnd == NULL) + { + m_ToolTip.Create(this, TTS_ALWAYSTIP | TTS_BALLOON | TTS_NOANIMATE | TTS_NOFADE); + m_ToolTip.Activate(FALSE); + m_ToolTip.SetFont(&m_FontToolTip); + m_ToolTip.SendMessage(TTM_SETMAXTIPWIDTH, 0, 1024); + m_ToolTip.SetDelayTime(TTDT_AUTOPOP, 8000); + m_ToolTip.SetDelayTime(TTDT_INITIAL, 500); + m_ToolTip.SetDelayTime(TTDT_RESHOW, 100); + } +} + +BOOL CComboBoxFx::PreTranslateMessage(MSG* pMsg) +{ + InitToolTip(); + m_ToolTip.RelayEvent(pMsg); + + return CComboBox::PreTranslateMessage(pMsg); +} \ No newline at end of file diff --git a/CristalDiskMark/source/CrystalDiskMark/Priscilla/ComboBoxFx.h b/CristalDiskMark/source/CrystalDiskMark/Priscilla/ComboBoxFx.h new file mode 100644 index 0000000..fb14ddd --- /dev/null +++ b/CristalDiskMark/source/CrystalDiskMark/Priscilla/ComboBoxFx.h @@ -0,0 +1,130 @@ +/*---------------------------------------------------------------------------*/ +// Author : hiyohiyo +// Mail : hiyohiyo@crystalmark.info +// Web : https://crystalmark.info/ +// License : MIT License +/*---------------------------------------------------------------------------*/ + +#pragma once + +#include "ImageFx.h" + +class CComboBoxFx : public CComboBox +{ + DECLARE_DYNAMIC(CComboBoxFx); + +// Constructors +public: + CComboBoxFx(); + virtual ~CComboBoxFx(); + +// Control +public: + BOOL InitControl(int x, int y, int width, int height, double zoomRatio, CDC* bkDC, + LPCWSTR imagePath, int imageCount, DWORD textAlign, int renderMode, BOOL bHighContrast, BOOL m_bDarkMode, + COLORREF bkColor, COLORREF bkColorSelected, COLORREF glassColor, BYTE glassAlpha + ); + void SetFontHeight(int height, double zoomRatio, double fontRatio = 1.0); + void SetItemHeightEx(int nIndex, int height, double zoomRatio, double fontRatio = 1.0); + void SetItemHeightAll(int height, double zoomRatio, double fontRatio = 1.0); + void SetMargin(int top, int left, int bottom, int right, double zoomRatio); + CSize GetSize(void); + void SetGlassColor(COLORREF glassColor, BYTE glassAlpha); + void SetAlpha(BYTE alpha); + HWND GetListHwnd(); + + // Font + void SetFontEx(CString face, int size, int sizeToolTip, double zoomRatio, double fontRatio = 1.0, + COLORREF textColor = RGB(0, 0, 0), COLORREF textColorSelected = RGB(0, 0, 0), LONG fontWeight = FW_NORMAL, BYTE fontRender = CLEARTYPE_NATURAL_QUALITY); + + // ToolTip + void SetToolTipText(LPCTSTR pText); + void SetToolTipActivate(BOOL bActivate = TRUE); + void SetToolTipWindowText(LPCTSTR pText); + CString GetToolTipText(); + + // Mouse + void SetHandCursor(BOOL bHandCuror = TRUE); + +protected: + // Draw Control + virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct); + virtual void MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct); + virtual void DrawControl(CString title, CDC* drawDC, LPDRAWITEMSTRUCT lpDrawItemStruct, CBitmap& ctrlBitmap, CBitmap& bkBitmap, int no); + virtual void DrawString(CString title, CDC* drawDC, LPDRAWITEMSTRUCT lpDrawItemStruct, COLORREF textColor); + + // Image + BOOL LoadBitmap(LPCTSTR fileName); + BOOL LoadBitmap(HBITMAP hBitmap); + void SetBkReload(void); + BOOL SetBitmap(CBitmap& bitmap); + void LoadCtrlBk(CDC* drawDC); + + // ToolTip + void InitToolTip(); + virtual BOOL PreTranslateMessage(MSG* pMsg); + + // Message Map + DECLARE_MESSAGE_MAP() + afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor); + afx_msg void OnMouseMove(UINT nFlags, CPoint point); + afx_msg void OnMouseHover(UINT nFlags, CPoint point); + afx_msg void OnMouseLeave(); + afx_msg void OnKillfocus(); + afx_msg void OnSetfocus(); + afx_msg BOOL OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message); + +protected: + // Control + int m_X; + int m_Y; + double m_ZoomRatio; + CSize m_CtrlSize; + CRect m_Margin; + int m_RenderMode; + BOOL m_bHighContrast; + BOOL m_bDarkMode; + BYTE m_FontRender; // For FontComboBoxFx + + // Alpha/Glass + BYTE m_Alpha; + COLORREF m_GlassColor; + BYTE m_GlassAlpha; + + // Image + CString m_ImagePath; + int m_ImageCount; + CDC* m_BkDC; + CBitmap m_BkBitmap; + BOOL m_bBkBitmapInit; + BOOL m_bBkLoad; + CBitmap m_CtrlBitmap; + CImage m_CtrlImage; + + // Font + DWORD m_TextAlign; + CFont m_Font; + CFont m_FontToolTip; + COLORREF m_TextColor; + COLORREF m_TextColorSelected; + COLORREF m_BkColor; + COLORREF m_BkColorSelected; + COLORREF m_TextColorHc; + COLORREF m_TextColorSelectedHc; + COLORREF m_BkColorHc; + COLORREF m_BkColorSelectedHc; + LONG m_FontHeight; + + // ToolTip + CToolTipCtrl m_ToolTip; + CString m_ToolTipText; + + // Mouse + BOOL m_bHover; + BOOL m_bFocas; + BOOL m_bTrackingNow; + BOOL m_bHandCursor; + + // Brush + CBrush m_BkBrush; +}; diff --git a/CristalDiskMark/source/CrystalDiskMark/Priscilla/CommonFx.h b/CristalDiskMark/source/CrystalDiskMark/Priscilla/CommonFx.h new file mode 100644 index 0000000..0dd11f3 --- /dev/null +++ b/CristalDiskMark/source/CrystalDiskMark/Priscilla/CommonFx.h @@ -0,0 +1,89 @@ +/*---------------------------------------------------------------------------*/ +// Author : hiyohiyo +// Mail : hiyohiyo@crystalmark.info +// Web : https://crystalmark.info/ +// License : MIT License +/*---------------------------------------------------------------------------*/ + +#pragma once + +//------------------------------------------------ +// Naming Conventions +//------------------------------------------------ +// BOOL bXxxxYyyy +// HANDLE hXxxxYyyy +// Pointer pXxxxYyyy +// Function SampleFunction +// Variable sampleVariable +// Const Value ConstVaiable +// Member Variable m_XxxxYyyy + +//------------------------------------------------ +// Order for C*****Fx Control +//------------------------------------------------ +// Control > Draw Control > Image > Font > Mouse > ToolTip +// + +//------------------------------------------------ +// Utility Macros +//------------------------------------------------ + +#define SAFE_DELETE(p) {if(p){delete (p);(p)=NULL;}} + +#if _MSC_VER > 1310 +#define MENU_MODIFY_MENU menu->ModifyMenu +#define SUBMENU_MODIFY_MENU subMenu.ModifyMenu +#else +#define MENU_MODIFY_MENU if(!IsNT3())menu->ModifyMenu +#define SUBMENU_MODIFY_MENU if(!IsNT3())subMenu.ModifyMenu +#endif + +//------------------------------------------------ +// WM_APP +//------------------------------------------------ +// WM_APP + 0x0000-0x0BFF: User Application +// WM_APP + 0x0C00-0x0FFF: Project Priscilla + // WM_APP + 0x0C00-0x0CFF: Theme + // WM_APP + 0x0D00-0x0DFF: Language + // WP_APP + 0x0E00-0x0FFF: Reserved +// WM_APP + 0x1000-0x3FFF: User Application + +#define WM_THEME_ID (WM_APP + 0x0C00) +#define WM_LANGUAGE_ID (WM_APP + 0x0D00) + +//------------------------------------------------ +// TIMER ID +//------------------------------------------------ +// 0x0000 - 0x0FFF: Project Priscilla +// 0x1000 - : User Application + +static const int TimerUpdateDialogSizeDpiChanged = 0x0001; +static const int TimerUpdateDialogSizeDisplayChange = 0x0002; +static const int TimerUpdateDialogSizeSysColorChange = 0x0003; +static const int TimerUpdateDialogSizeSettingChange = 0x0004; + +//------------------------------------------------ +// Const Values +//------------------------------------------------ + +static const int ControlImageNormal = 0x0000; +static const int ControlImageHover = 0x0001; +static const int ControlImageFocus = 0x0002; +static const int ControlImageSelected = 0x0003; +static const int ControlImageDisabled = 0x0004; + +static const int SystemDraw = 0x0001; +static const int OwnerDrawImage = 0x0002; +static const int OwnerDrawGlass = 0x0004; +static const int OwnerDrawTransparent = 0x0008; + +static const int ZoomTypeAuto = 0; +static const int ZoomType050 = 50; +static const int ZoomType064 = 64; +static const int ZoomType075 = 75; +static const int ZoomType100 = 100; +static const int ZoomType125 = 125; +static const int ZoomType150 = 150; +static const int ZoomType200 = 200; +static const int ZoomType250 = 250; +static const int ZoomType300 = 300; \ No newline at end of file diff --git a/CristalDiskMark/source/CrystalDiskMark/Priscilla/DarkMode.cpp b/CristalDiskMark/source/CrystalDiskMark/Priscilla/DarkMode.cpp new file mode 100644 index 0000000..aca5b2c --- /dev/null +++ b/CristalDiskMark/source/CrystalDiskMark/Priscilla/DarkMode.cpp @@ -0,0 +1,261 @@ +/*---------------------------------------------------------------------------*/ +// Author : Richard Yu +// Web : https://github.com/ysc3839/win32-darkmode +// License : MIT License +// https://github.com/ysc3839/win32-darkmode/blob/master/LICENSE +/*---------------------------------------------------------------------------*/ + +#include "stdafx.h" +#include "OsInfoFx.h" +#include "IatHook.h" + +enum IMMERSIVE_HC_CACHE_MODE +{ + IHCM_USE_CACHED_VALUE, + IHCM_REFRESH +}; + +// 1903 18362 +enum class PreferredAppMode +{ + Default, + AllowDark, + ForceDark, + ForceLight, + Max +}; + +enum WINDOWCOMPOSITIONATTRIB +{ + WCA_UNDEFINED = 0, + WCA_NCRENDERING_ENABLED = 1, + WCA_NCRENDERING_POLICY = 2, + WCA_TRANSITIONS_FORCEDISABLED = 3, + WCA_ALLOW_NCPAINT = 4, + WCA_CAPTION_BUTTON_BOUNDS = 5, + WCA_NONCLIENT_RTL_LAYOUT = 6, + WCA_FORCE_ICONIC_REPRESENTATION = 7, + WCA_EXTENDED_FRAME_BOUNDS = 8, + WCA_HAS_ICONIC_BITMAP = 9, + WCA_THEME_ATTRIBUTES = 10, + WCA_NCRENDERING_EXILED = 11, + WCA_NCADORNMENTINFO = 12, + WCA_EXCLUDED_FROM_LIVEPREVIEW = 13, + WCA_VIDEO_OVERLAY_ACTIVE = 14, + WCA_FORCE_ACTIVEWINDOW_APPEARANCE = 15, + WCA_DISALLOW_PEEK = 16, + WCA_CLOAK = 17, + WCA_CLOAKED = 18, + WCA_ACCENT_POLICY = 19, + WCA_FREEZE_REPRESENTATION = 20, + WCA_EVER_UNCLOAKED = 21, + WCA_VISUAL_OWNER = 22, + WCA_HOLOGRAPHIC = 23, + WCA_EXCLUDED_FROM_DDA = 24, + WCA_PASSIVEUPDATEMODE = 25, + WCA_USEDARKMODECOLORS = 26, + WCA_LAST = 27 +}; + +struct WINDOWCOMPOSITIONATTRIBDATA +{ + WINDOWCOMPOSITIONATTRIB Attrib; + PVOID pvData; + SIZE_T cbData; +}; + +using fnRtlGetNtVersionNumbers = void (WINAPI*)(LPDWORD major, LPDWORD minor, LPDWORD build); +using fnSetWindowCompositionAttribute = BOOL(WINAPI*)(HWND hWnd, WINDOWCOMPOSITIONATTRIBDATA*); +// 1809 17763 +using fnShouldAppsUseDarkMode = bool (WINAPI*)(); // ordinal 132 +using fnAllowDarkModeForWindow = bool (WINAPI*)(HWND hWnd, bool allow); // ordinal 133 +using fnAllowDarkModeForApp = bool (WINAPI*)(bool allow); // ordinal 135, in 1809 +using fnFlushMenuThemes = void (WINAPI*)(); // ordinal 136 +using fnRefreshImmersiveColorPolicyState = void (WINAPI*)(); // ordinal 104 +using fnIsDarkModeAllowedForWindow = bool (WINAPI*)(HWND hWnd); // ordinal 137 +using fnGetIsImmersiveColorUsingHighContrast = bool (WINAPI*)(IMMERSIVE_HC_CACHE_MODE mode); // ordinal 106 +using fnOpenNcThemeData = HTHEME(WINAPI*)(HWND hWnd, LPCWSTR pszClassList); // ordinal 49 +// 1903 18362 +using fnShouldSystemUseDarkMode = bool (WINAPI*)(); // ordinal 138 +using fnSetPreferredAppMode = PreferredAppMode(WINAPI*)(PreferredAppMode appMode); // ordinal 135, in 1903 +using fnIsDarkModeAllowedForApp = bool (WINAPI*)(); // ordinal 139 + +fnSetWindowCompositionAttribute _SetWindowCompositionAttribute = nullptr; +fnShouldAppsUseDarkMode _ShouldAppsUseDarkMode = nullptr; +fnAllowDarkModeForWindow _AllowDarkModeForWindow = nullptr; +fnAllowDarkModeForApp _AllowDarkModeForApp = nullptr; +fnFlushMenuThemes _FlushMenuThemes = nullptr; +fnRefreshImmersiveColorPolicyState _RefreshImmersiveColorPolicyState = nullptr; +fnIsDarkModeAllowedForWindow _IsDarkModeAllowedForWindow = nullptr; +fnGetIsImmersiveColorUsingHighContrast _GetIsImmersiveColorUsingHighContrast = nullptr; +fnOpenNcThemeData _OpenNcThemeData = nullptr; +// 1903 18362 +fnShouldSystemUseDarkMode _ShouldSystemUseDarkMode = nullptr; +fnSetPreferredAppMode _SetPreferredAppMode = nullptr; + +bool g_darkModeSupported = false; +bool g_darkModeEnabled = false; +DWORD g_buildNumber = 0; + +bool AllowDarkModeForWindow(HWND hWnd, bool allow) +{ + if (g_darkModeSupported) + return _AllowDarkModeForWindow(hWnd, allow); + return false; +} + +bool IsHighContrast() +{ + HIGHCONTRASTW highContrast = { sizeof(highContrast) }; + if (SystemParametersInfoW(SPI_GETHIGHCONTRAST, sizeof(highContrast), &highContrast, FALSE)) + return highContrast.dwFlags & HCF_HIGHCONTRASTON; + return false; +} + +void AllowDarkModeForApp(bool allow) +{ + if (_AllowDarkModeForApp) + _AllowDarkModeForApp(allow); + else if (_SetPreferredAppMode) + _SetPreferredAppMode(allow ? PreferredAppMode::AllowDark : PreferredAppMode::Default); +} + +void RefreshTitleBarThemeColor(HWND hWnd) +{ + BOOL dark = FALSE; + if (_IsDarkModeAllowedForWindow(hWnd) && + _ShouldAppsUseDarkMode() && + !IsHighContrast()) + { + dark = TRUE; + } + if (g_buildNumber < 18362) + SetPropW(hWnd, L"UseImmersiveDarkModeColors", reinterpret_cast(static_cast(dark))); + else if (_SetWindowCompositionAttribute) + { + WINDOWCOMPOSITIONATTRIBDATA data = { WCA_USEDARKMODECOLORS, &dark, sizeof(dark) }; + _SetWindowCompositionAttribute(hWnd, &data); + } +} + +constexpr bool CheckBuildNumber(DWORD buildNumber) +{ + return (buildNumber >= 17763); +} + +void FixDarkScrollBar() +{ + HMODULE hComctl = LoadLibraryExW(L"comctl32.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32); + if (hComctl) + { + auto addr = FindDelayLoadThunkInModule(hComctl, "uxtheme.dll", 49); // OpenNcThemeData + if (addr) + { + DWORD oldProtect; + if (VirtualProtect(addr, sizeof(IMAGE_THUNK_DATA), PAGE_READWRITE, &oldProtect)) + { + auto MyOpenThemeData = [](HWND hWnd, LPCWSTR classList) -> HTHEME { + if (wcscmp(classList, L"ScrollBar") == 0) + { + hWnd = nullptr; + classList = L"Explorer::ScrollBar"; + } + return _OpenNcThemeData(hWnd, classList); + }; + + addr->u1.Function = reinterpret_cast(static_cast(MyOpenThemeData)); + VirtualProtect(addr, sizeof(IMAGE_THUNK_DATA), oldProtect, &oldProtect); + } + } + } +} + +BOOL InitDarkMode() +{ + HMODULE ntdll = GetModuleHandleW(L"ntdll.dll"); + HMODULE user32 = GetModuleHandleW(L"user32.dll"); + if (!ntdll || !user32) return FALSE; + auto RtlGetNtVersionNumbers = reinterpret_cast(GetProcAddress(ntdll, "RtlGetNtVersionNumbers")); + if (RtlGetNtVersionNumbers) + { + DWORD major, minor; + RtlGetNtVersionNumbers(&major, &minor, &g_buildNumber); + g_buildNumber &= ~0xF0000000; + if (major == 10 && minor == 0 && CheckBuildNumber(g_buildNumber)) + { + HMODULE hUxtheme = LoadLibraryExW(L"uxtheme.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32); + if (hUxtheme) + { + _OpenNcThemeData = reinterpret_cast(GetProcAddress(hUxtheme, MAKEINTRESOURCEA(49))); + _RefreshImmersiveColorPolicyState = reinterpret_cast(GetProcAddress(hUxtheme, MAKEINTRESOURCEA(104))); + _GetIsImmersiveColorUsingHighContrast = reinterpret_cast(GetProcAddress(hUxtheme, MAKEINTRESOURCEA(106))); + _ShouldAppsUseDarkMode = reinterpret_cast(GetProcAddress(hUxtheme, MAKEINTRESOURCEA(132))); + _AllowDarkModeForWindow = reinterpret_cast(GetProcAddress(hUxtheme, MAKEINTRESOURCEA(133))); + + auto ord135 = GetProcAddress(hUxtheme, MAKEINTRESOURCEA(135)); + if (g_buildNumber < 18362) + _AllowDarkModeForApp = reinterpret_cast(ord135); + else + _SetPreferredAppMode = reinterpret_cast(ord135); + + //_FlushMenuThemes = reinterpret_cast(GetProcAddress(hUxtheme, MAKEINTRESOURCEA(136))); + _IsDarkModeAllowedForWindow = reinterpret_cast(GetProcAddress(hUxtheme, MAKEINTRESOURCEA(137))); + + _SetWindowCompositionAttribute = reinterpret_cast(GetProcAddress(user32, "SetWindowCompositionAttribute")); + + if (_OpenNcThemeData && + _RefreshImmersiveColorPolicyState && + _ShouldAppsUseDarkMode && + _AllowDarkModeForWindow && + (_AllowDarkModeForApp || _SetPreferredAppMode) && + //_FlushMenuThemes && + _IsDarkModeAllowedForWindow) + { + g_darkModeSupported = true; + + AllowDarkModeForApp(true); + _RefreshImmersiveColorPolicyState(); + + g_darkModeEnabled = _ShouldAppsUseDarkMode() && !IsHighContrast(); + + // FixDarkScrollBar(); + } + } + } + } + + return (BOOL)g_darkModeEnabled; +} + +BOOL SetDarkMode(HWND hWnd) +{ + BOOL bDarkMode = FALSE; + if (IsDarkModeSupport()) + { + bDarkMode = InitDarkMode(); + AllowDarkModeForWindow(hWnd, bDarkMode); + RefreshTitleBarThemeColor(hWnd); + } + + return bDarkMode; +} + +void UnsetDarkMode(HWND hWnd) +{ + if (IsDarkModeSupport()) + { + InitDarkMode(); + AllowDarkModeForWindow(hWnd, FALSE); + RefreshTitleBarThemeColor(hWnd); + } +} + +void SetDarkModeControl(HWND hWnd, BOOL bDarkMode) +{ + if (IsDarkModeSupport()) + { + SetWindowTheme(hWnd, L"Explorer", nullptr); + AllowDarkModeForWindow(hWnd, bDarkMode); + SendMessageW(hWnd, WM_THEMECHANGED, 0, 0); + } +} \ No newline at end of file diff --git a/CristalDiskMark/source/CrystalDiskMark/Priscilla/DarkMode.h b/CristalDiskMark/source/CrystalDiskMark/Priscilla/DarkMode.h new file mode 100644 index 0000000..46d8daf --- /dev/null +++ b/CristalDiskMark/source/CrystalDiskMark/Priscilla/DarkMode.h @@ -0,0 +1,18 @@ +/*---------------------------------------------------------------------------*/ +// Author : Richard Yu +// Web : https://github.com/ysc3839/win32-darkmode +// License : MIT License +// https://github.com/ysc3839/win32-darkmode/blob/master/LICENSE +/*---------------------------------------------------------------------------*/ + +#pragma once + +BOOL SetDarkMode(HWND hWnd); +void UnsetDarkMode(HWND hWnd); +void SetDarkModeControl(HWND hWnd, BOOL bDarkMode); + +void FixDarkScrollBar(); +bool AllowDarkModeForWindow(HWND hWnd, bool allow); + +// BOOL InitDarkMode(); +// void RefreshTitleBarThemeColor(HWND hWnd); diff --git a/CristalDiskMark/source/CrystalDiskMark/Priscilla/DialogFx.cpp b/CristalDiskMark/source/CrystalDiskMark/Priscilla/DialogFx.cpp new file mode 100644 index 0000000..72add00 --- /dev/null +++ b/CristalDiskMark/source/CrystalDiskMark/Priscilla/DialogFx.cpp @@ -0,0 +1,738 @@ +/*---------------------------------------------------------------------------*/ +// Author : hiyohiyo +// Mail : hiyohiyo@crystalmark.info +// Web : https://crystalmark.info/ +// License : MIT License +/*---------------------------------------------------------------------------*/ + +#include "stdafx.h" +#include "Resource.h" +#include "DialogFx.h" +#include "UtilityFx.h" +#include "OsInfoFx.h" +#include +#include "DarkMode.h" + +// defined by Windows 8.1/Windows 2012 R2 +#ifndef WM_DPICHANGED +#define WM_DPICHANGED 0x02E0 +#endif + +////------------------------------------------------ +// CDialogFx +////------------------------------------------------ + +CDialogFx::CDialogFx(UINT dlgResouce, CWnd* pParent) + :CDialog(dlgResouce, pParent) +{ + // Dialog + m_bInitializing = TRUE; + m_bDpiChanging = FALSE; + m_bShowWindow = FALSE; + m_bModelessDlg = FALSE; + m_bHighContrast = FALSE; + m_bDarkMode = FALSE; + m_bDisableDarkMode = FALSE; + m_bBkImage = FALSE; + m_MenuId = 0; + m_ParentWnd = NULL; + m_DlgWnd = NULL; + m_hAccelerator = NULL; + m_bDrag = FALSE; + m_FontScale = 100; + m_FontRatio = 1.0; + m_FontRender = CLEARTYPE_NATURAL_QUALITY; + m_hPal = NULL; + + m_SizeX = 0; + m_MaxSizeX = 65535; + m_MinSizeX = 0; + m_SizeY = 0; + m_MaxSizeY = 65535; + m_MinSizeY = 0; + + // Zoom + m_Dpi = 96; + m_ZoomRatio = 1.0; + m_ZoomType = ZoomTypeAuto; + + // Color for SubClass + m_LabelText = 0x00000000; + m_MeterText = 0x00000000; + m_ComboText = 0x00000000; + m_ComboTextSelected = 0x00808080; + m_ComboBk = 0x00FFFFFF; + m_ComboBkSelected = 0x00808080; + m_ButtonText = 0x00000000; + m_EditText = 0x00000000; + m_EditBk = 0x00FFFFFF; + m_ListText1 = 0x00000000; + m_ListText2 = 0x00000000; + m_ListTextSelected = 0x00000000; + m_ListBk1 = 0x00FFFFFF; + m_ListBk2 = 0x00FFFFFF; + m_ListBkSelected = 0x00808080; + m_ListLine1 = 0x00000000; + m_ListLine2 = 0x00000000; + m_Glass = 0x00808080; + m_Frame = 0x00808080; + m_Background = 0xFFFFFFFF; // Disabled + + m_ComboAlpha = 0; + m_EditAlpha = 0; + m_GlassAlpha = 0; + + m_CharacterPosition = 0; + + // Theme for SubClass + m_OffsetX = 0; + + // Voice for SubClass + m_VoiceVolume = 0; +} + +CDialogFx::~CDialogFx() +{ + if(m_hPal) DeleteObject(m_hPal); +} + +BEGIN_MESSAGE_MAP(CDialogFx, CDialog) + ON_WM_SIZE() + ON_WM_TIMER() + ON_WM_ERASEBKGND() + ON_MESSAGE(WM_DPICHANGED, &CDialogFx::OnDpiChanged) + ON_MESSAGE(WM_DISPLAYCHANGE, &CDialogFx::OnDisplayChange) + ON_MESSAGE(WM_SYSCOLORCHANGE, &CDialogFx::OnSysColorChange) + ON_MESSAGE(WM_SETTINGCHANGE, &CDialogFx::OnSettingChange) + ON_MESSAGE(WM_ENTERSIZEMOVE, &CDialogFx::OnEnterSizeMove) + ON_MESSAGE(WM_EXITSIZEMOVE, &CDialogFx::OnExitSizeMove) +END_MESSAGE_MAP() + +//------------------------------------------------ +// Dialog +//------------------------------------------------ + +BOOL CDialogFx::Create(UINT nIDTemplate, CWnd* pDlgWnd, UINT menuId, CWnd* pParentWnd) +{ + m_bModelessDlg = TRUE; + m_ParentWnd = pParentWnd; + m_DlgWnd = pDlgWnd; + m_MenuId = menuId; + + if (m_MenuId != 0 && m_ParentWnd != NULL) + { + CMenu* menu = m_ParentWnd->GetMenu(); + menu->EnableMenuItem(m_MenuId, MF_GRAYED); + m_ParentWnd->SetMenu(menu); + m_ParentWnd->DrawMenuBar(); + } + + return CDialog::Create(nIDTemplate, pParentWnd); +} + +int CDialogFx::GetDpi() +{ + INT dpi = 96; + CDC* pDC = GetDC(); + dpi = GetDeviceCaps(pDC->m_hDC, LOGPIXELSY); + ReleaseDC(pDC); + + HMODULE hModule = GetModuleHandle(_T("Shcore.dll")); + if (hModule) + { + typedef HRESULT(WINAPI* FuncGetDpiForMonitor) (HMONITOR hmonitor, UINT dpiType, UINT* dpiX, UINT* dpiY); + typedef HMONITOR(WINAPI* FuncMonitorFromWindow) (HWND hwnd, DWORD dwFlags); + + FuncGetDpiForMonitor pGetDpiForMonitor = (FuncGetDpiForMonitor)GetProcAddress(hModule, "GetDpiForMonitor"); + FuncMonitorFromWindow pMonitorFromWindow = (FuncMonitorFromWindow)GetProcAddress(hModule, "MonitorFromWindow"); + + if (pGetDpiForMonitor && pMonitorFromWindow) + { + UINT dpiX, dpiY; + pGetDpiForMonitor(pMonitorFromWindow(m_hWnd, MONITOR_DEFAULTTONEAREST), 0, &dpiX, &dpiY); + dpi = dpiY; + } + } + + return dpi; +} + +BOOL CDialogFx::OnInitDialog() +{ + CDialog::OnInitDialog(); + + m_bHighContrast = IsHighContrast(); + m_Dpi = GetDpi(); + m_hAccelerator = ::LoadAccelerators(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDR_ACCELERATOR)); + + // m_bInitializing = FALSE; + + return TRUE; +} + +void CDialogFx::OnSize(UINT nType, int cx, int cy) +{ + CDialog::OnSize(nType, cx, cy); + + if (nType == SIZE_RESTORED) + { + UpdateBackground(TRUE, FALSE); + Invalidate(); + } +} + +BOOL CDialogFx::PreTranslateMessage(MSG* pMsg) +{ + if(m_hAccelerator != NULL) + { + if(::TranslateAccelerator(m_hWnd, m_hAccelerator, pMsg) != 0) + { + return TRUE; + } + } + + return CDialog::PreTranslateMessage(pMsg); +} + +void CDialogFx::PostNcDestroy() +{ + if (m_bModelessDlg) + { + m_DlgWnd = NULL; + delete this; + } + else + { + CDialog::PostNcDestroy(); + } +} + +void CDialogFx::UpdateDialogSize() +{ +#if _MSC_VER > 1310 + if (! m_bDisableDarkMode) + { + m_bDarkMode = SetDarkMode(m_hWnd); + } + else + { + UnsetDarkMode(m_hWnd); + m_bDarkMode = FALSE; + } +#endif +} + +void CDialogFx::SetClientSize(int sizeX, int sizeY, double zoomRatio) +{ + RECT rw, rc; + GetWindowRect(&rw); + GetClientRect(&rc); + + if (rc.right != 0) + { + int ncaWidth = (rw.right - rw.left) - (rc.right - rc.left); + int ncaHeight = (rw.bottom - rw.top) - (rc.bottom - rc.top); + + SetWindowPos(NULL, 0, 0, (int)(sizeX * zoomRatio) + ncaWidth, (int)(sizeY * zoomRatio) + ncaHeight, SWP_NOMOVE | SWP_NOZORDER); + + GetWindowRect(&rw); + GetClientRect(&rc); + + int ncaHeightMenu = (rw.bottom - rw.top) - (rc.bottom - rc.top); + + if (ncaHeight != ncaHeightMenu) + { + SetWindowPos(NULL, 0, 0, (int)(sizeX * zoomRatio) + ncaWidth, (int)(sizeY * zoomRatio) + ncaHeightMenu, SWP_NOMOVE | SWP_NOZORDER); + } + } +} + +void CDialogFx::UpdateBackground(BOOL resize, BOOL bDarkMode) +{ + BOOL result = FALSE; + CImage srcBitmap; + double ratio = m_ZoomRatio; + m_bBkImage = FALSE; + +#if _MSC_VER > 1310 + if (resize) { m_ZoomRatio = 3.0; } + result = srcBitmap.Load(IP(m_BackgroundName)); + if (resize) { m_ZoomRatio = ratio; } +#else + if (resize) { m_ZoomRatio = 1.0; } + result = srcBitmap.Load(IP(m_BackgroundName)); + if (resize) { m_ZoomRatio = ratio; } +#endif + + HDC hScreenDC = ::GetDC(NULL); // get desktop DC + if(!m_hPal && GetDeviceCaps(hScreenDC, RASTERCAPS) & RC_PALETTE) + { + m_hPal = CreateHalftonePalette(hScreenDC); + } + DeleteDC(hScreenDC); // delete it after use + + if (result) + { + m_bBkImage = TRUE; + CBitmap baseBitmap; + CDC baseDC; + CDC* pWndDC = GetDC(); + +#if _MSC_VER > 1310 + int w = (int)(m_ZoomRatio / 3.0 * srcBitmap.GetWidth()); + int h = (int)(m_ZoomRatio / 3.0 * srcBitmap.GetHeight()); +#else + int w = (int)(m_ZoomRatio * srcBitmap.GetWidth()); + int h = (int)(m_ZoomRatio * srcBitmap.GetHeight()); +#endif + int orgw = srcBitmap.GetWidth(); + int orgh = srcBitmap.GetHeight(); + if(m_hPal && pWndDC->GetDeviceCaps(RASTERCAPS) & RC_PALETTE) + { + SelectPalette( pWndDC->GetSafeHdc(), m_hPal, TRUE ); + pWndDC->RealizePalette(); + pWndDC->SetStretchBltMode(HALFTONE); + } + baseBitmap.CreateCompatibleBitmap(pWndDC, orgw, orgh); + baseDC.CreateCompatibleDC(pWndDC); + if(m_hPal && baseDC.GetDeviceCaps(RASTERCAPS) & RC_PALETTE) + { + SelectPalette( baseDC.GetSafeHdc(), m_hPal, FALSE ); + baseDC.RealizePalette(); + baseDC.SetStretchBltMode(HALFTONE); + } + + m_BkBitmap.DeleteObject(); + m_BkDC.DeleteDC(); + m_BkBitmap.CreateCompatibleBitmap(pWndDC, w, h); + m_BkDC.CreateCompatibleDC(pWndDC); + if(m_hPal && baseDC.GetDeviceCaps(RASTERCAPS) & RC_PALETTE) + { + SelectPalette( m_BkDC.GetSafeHdc(), m_hPal, FALSE ); + m_BkDC.RealizePalette(); + m_BkDC.SetStretchBltMode(HALFTONE); + } + + ReleaseDC(pWndDC); + + baseDC.SelectObject(&baseBitmap); + m_BkDC.SelectObject(&m_BkBitmap); + + srcBitmap.BitBlt(baseDC.GetSafeHdc(), 0, 0, SRCCOPY); + srcBitmap.Destroy(); + + m_BkDC.SetStretchBltMode(HALFTONE); + SetBrushOrgEx(m_BkDC, 0, 0, NULL); + m_BkDC.StretchBlt(0, 0, w, h, &baseDC, 0, 0, orgw, orgh, SRCCOPY); + + baseBitmap.DeleteObject(); + baseDC.DeleteDC(); + + m_BrushDlg.DeleteObject(); + m_BrushDlg.CreatePatternBrush(&m_BkBitmap); + + return; + } + else if (m_bHighContrast) + { + m_BrushDlg.DeleteObject(); + m_BrushDlg.CreateSolidBrush(RGB(0, 0, 0)); + } + else + { + CBitmap baseBitmap; + CDC baseDC; + CDC* pWndDC = GetDC(); + + CRect rect; + GetClientRect(&rect); + int w = rect.Width(); + int h = rect.Height(); + + m_BkBitmap.DeleteObject(); + m_BkBitmap.CreateCompatibleBitmap(pWndDC, w, h); + m_BkDC.DeleteDC(); + m_BkDC.CreateCompatibleDC(pWndDC); + m_BkDC.SelectObject(&m_BkBitmap); + + m_BrushDlg.DeleteObject(); + COLORREF bkColor; + + if (m_Background != 0xFFFFFFFF) + { + bkColor = m_Background; + } + else if (bDarkMode) + { + bkColor = RGB(32, 32, 32); + } + else + { + bkColor = RGB(255, 255, 255); + } + m_BrushDlg.CreateSolidBrush(bkColor); + + m_BkDC.FillRect(&rect, &m_BrushDlg); + + ReleaseDC(pWndDC); + } +} + +void CDialogFx::SetWindowTitle(CString title) +{ + SetWindowText(_T(" ") + title + _T(" ")); +} + +void CDialogFx::OnOK() +{ +} + +void CDialogFx::OnCancel() +{ + if (m_bModelessDlg) + { + if (m_MenuId != 0 && m_ParentWnd != NULL) + { + CMenu* menu = m_ParentWnd->GetMenu(); + menu->EnableMenuItem(m_MenuId, MF_ENABLED); + m_ParentWnd->SetMenu(menu); + m_ParentWnd->DrawMenuBar(); + } + CDialog::DestroyWindow(); + } + else + { + CDialog::OnCancel(); + } +} + +//------------------------------------------------ +// Font +//------------------------------------------------ + +int CDialogFx::GetFontScale() +{ + return m_FontScale; +} + +BYTE CDialogFx::GetFontRender() +{ + return m_FontRender; +} + +double CDialogFx::GetFontRatio() +{ + return m_FontRatio; +} + +CString CDialogFx::GetFontFace() +{ + return m_FontFace; +} + +//------------------------------------------------ +// Zoom +//------------------------------------------------ + +DWORD CDialogFx::ChangeZoomType(DWORD zoomType) +{ + DWORD current = (DWORD)ceil(m_Dpi / 96.0 * 100); + int width = GetSystemMetrics(SM_CXSCREEN); + + if(zoomType == ZoomTypeAuto) + { +#if _MSC_VER > 1310 + if (current >= 300) + { + zoomType = ZoomType300; + } + else if (current >= 250) + { + zoomType = ZoomType250; + } + else +#endif + if(current >= 200) + { + zoomType = ZoomType200; + } + else if(current >= 150) + { + zoomType = ZoomType150; + } + else if(current >= 125) + { + zoomType = ZoomType125; + } +#ifdef CRYSTALMARK_RETRO +#ifdef SUISHO_SHIZUKU_SUPPORT + else if (width < 900) { zoomType = ZoomType050; } + else if (width < 1200){ zoomType = ZoomType075; } +#else +// else if (width < 732) { zoomType = ZoomType050; } + else if (width < 732) { zoomType = ZoomType064; } + else if (width < 976) { zoomType = ZoomType075; } +#endif +#endif + else + { + zoomType = ZoomType100; + } + } + + m_ZoomRatio = zoomType / 100.0; + + return zoomType; +} + +//------------------------------------------------ +// Theme +//------------------------------------------------ + +BOOL CDialogFx::IsHighContrast() +{ + HIGHCONTRAST hc = { sizeof(HIGHCONTRAST) }; + SystemParametersInfoW(SPI_GETHIGHCONTRAST, sizeof(HIGHCONTRAST), &hc, 0); + + return hc.dwFlags & HCF_HIGHCONTRASTON; +} + +BOOL CDialogFx::IsDisableDarkMode() +{ + return m_bDisableDarkMode; +} + +//------------------------------------------------ +// Utility +//------------------------------------------------ + +CString CDialogFx::IP(CString imageName) /// ImagePath +{ + CString imagePath; + imagePath.Format(_T("%s%s\\%s-%03d.png"), (LPCTSTR)m_ThemeDir, (LPCTSTR)m_CurrentTheme, (LPCTSTR)imageName, (DWORD)(m_ZoomRatio * 100)); + if (IsFileExist(imagePath)) + { + return imagePath; + } + imagePath.Format(_T("%s%s\\%s-%03d.png"), (LPCTSTR)m_ThemeDir, (LPCTSTR)m_ParentTheme1, (LPCTSTR)imageName, (DWORD)(m_ZoomRatio * 100)); + if (IsFileExist(imagePath)) + { + return imagePath; + } + imagePath.Format(_T("%s%s\\%s-%03d.png"), (LPCTSTR)m_ThemeDir, (LPCTSTR)m_ParentTheme2, (LPCTSTR)imageName, (DWORD)(m_ZoomRatio * 100)); + if (IsFileExist(imagePath)) + { + return imagePath; + } + imagePath.Format(_T("%s%s\\%s-%03d.png"), (LPCTSTR)m_ThemeDir, (LPCTSTR)m_DefaultTheme, (LPCTSTR)imageName, (DWORD)(m_ZoomRatio * 100)); + if (IsFileExist(imagePath)) + { + return imagePath; + } + + return _T(""); +} + +CString CDialogFx::i18n(CString section, CString key, BOOL inEnglish) +{ + TCHAR str[256]; + CString cstr; + + if(inEnglish) + { + GetPrivateProfileStringFx(section, key, _T(""), str, 256, m_DefaultLangPath); + cstr = str; + } + else + { + GetPrivateProfileStringFx(section, key, _T(""), str, 256, m_CurrentLangPath); + cstr = str; + if(cstr.IsEmpty()) + { + GetPrivateProfileStringFx(section, key, _T(""), str, 256, m_DefaultLangPath); + cstr = str; + } + } + + return cstr; +} + +void CDialogFx::OpenUrl(CString url) +{ + INT_PTR result = 0; + result = (INT_PTR)(ShellExecute(NULL, _T("open"), (LPCTSTR)url, NULL, NULL, SW_SHOWNORMAL)); + if(result <= 32) + { + CString args; + args.Format(_T("url.dll,FileProtocolHandler %s"), (LPCTSTR)url); + ShellExecute(NULL, _T("open"), _T("rundll32.exe"), args, NULL, SW_SHOWNORMAL); + } +} + +void CDialogFx::SetLayeredWindow(HWND hWnd, BYTE alpha) +{ +#if _MSC_VER > 1310 + if (IsWin2k()) { return; } + + ::SetWindowLong(hWnd, GWL_EXSTYLE, ::GetWindowLong(hWnd, GWL_EXSTYLE) ^ WS_EX_LAYERED); + ::SetWindowLong(hWnd, GWL_EXSTYLE, ::GetWindowLong(hWnd, GWL_EXSTYLE) | WS_EX_LAYERED); + if (m_bHighContrast) + { + ::SetLayeredWindowAttributes(hWnd, 0, 255, LWA_ALPHA); + } + else + { + ::SetLayeredWindowAttributes(hWnd, 0, alpha, LWA_ALPHA); + } +#endif +} + +//------------------------------------------------ +// MessageMap +//------------------------------------------------ + +void CDialogFx::OnTimer(UINT_PTR nIDEvent) +{ + switch (nIDEvent) + { + case TimerUpdateDialogSizeDpiChanged: + if (m_bDrag) + { + KillTimer(TimerUpdateDialogSizeDpiChanged); + SetTimer(TimerUpdateDialogSizeDpiChanged, TIMER_UPDATE_DIALOG, NULL); + } + else + { + m_bDpiChanging = FALSE; + KillTimer(TimerUpdateDialogSizeDpiChanged); + UpdateDialogSize(); + } + break; + case TimerUpdateDialogSizeDisplayChange: + KillTimer(TimerUpdateDialogSizeDisplayChange); + UpdateDialogSize(); + break; + case TimerUpdateDialogSizeSysColorChange: + KillTimer(TimerUpdateDialogSizeSysColorChange); + UpdateDialogSize(); + break; + case TimerUpdateDialogSizeSettingChange: + KillTimer(TimerUpdateDialogSizeSettingChange); + UpdateDialogSize(); + break; + } +} + +BOOL CDialogFx::OnEraseBkgnd(CDC* pDC) +{ + if (m_bHighContrast) + { + return CDialog::OnEraseBkgnd(pDC); + } + + if(m_hPal && pDC->GetDeviceCaps(RASTERCAPS) & RC_PALETTE) + { + SelectPalette( pDC->GetSafeHdc(), m_hPal, TRUE ); + pDC->RealizePalette(); + pDC->SetStretchBltMode(HALFTONE); + } + + CRect rect; + GetClientRect(&rect); + + return pDC->StretchBlt(0, 0, rect.Width(), rect.Height(), &m_BkDC, 0, 0, rect.Width(), rect.Height(), SRCCOPY); +} + +afx_msg LRESULT CDialogFx::OnDpiChanged(WPARAM wParam, LPARAM lParam) +{ + if (m_bInitializing) { return 0; } + + static ULONGLONG preTime = 0; + ULONGLONG currentTime = GetTickCountFx(); + if (currentTime - preTime < 1000) + { + return 0; + } + else + { + preTime = currentTime; + } + + m_Dpi = (INT)HIWORD(wParam); + +#if _MSC_VER > 1310 + if (IsWindowsBuildOrGreater(16299)) // DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 + { + ChangeZoomType(m_ZoomType); + m_bDpiChanging = TRUE; + SetTimer(TimerUpdateDialogSizeDpiChanged, TIMER_UPDATE_DIALOG, NULL); + } + else +#endif + if(m_ZoomType == ZoomTypeAuto) + { + DWORD oldZoomRatio = (DWORD)(m_ZoomRatio * 100); + if (ChangeZoomType(m_ZoomType) != oldZoomRatio) + { + m_bDpiChanging = TRUE; + SetTimer(TimerUpdateDialogSizeDpiChanged, TIMER_UPDATE_DIALOG, NULL); + } + } + + return 0; +} + +afx_msg LRESULT CDialogFx::OnDisplayChange(WPARAM wParam, LPARAM lParam) +{ + if (m_bInitializing) { return 0; } + + CDC* cdc = GetDC(); + if (cdc) + { + int color = cdc->GetDeviceCaps(BITSPIXEL) * cdc->GetDeviceCaps(PLANES); + if (color != wParam) + { + SetTimer(TimerUpdateDialogSizeDisplayChange, TIMER_UPDATE_DIALOG, NULL); + } + ReleaseDC(cdc); + } + + return 0; +} + +afx_msg LRESULT CDialogFx::OnSysColorChange(WPARAM wParam, LPARAM lParam) +{ + if (m_bInitializing) { return 0; } + + m_bHighContrast = IsHighContrast(); + + SetTimer(TimerUpdateDialogSizeSysColorChange, TIMER_UPDATE_DIALOG, NULL); + + return 0; +} + +afx_msg LRESULT CDialogFx::OnSettingChange(WPARAM wParam, LPARAM lParam) +{ + if (m_bInitializing) { return 0; } + + if (!lstrcmp(LPCTSTR(lParam), _T("ImmersiveColorSet"))) + { + SetTimer(TimerUpdateDialogSizeSettingChange, TIMER_UPDATE_DIALOG, NULL); + } + + return 0; +} + +afx_msg LRESULT CDialogFx::OnEnterSizeMove(WPARAM wParam, LPARAM lParam) +{ + m_bDrag = TRUE; + + return TRUE; +} + +afx_msg LRESULT CDialogFx::OnExitSizeMove(WPARAM wParam, LPARAM lParam) +{ + m_bDrag = FALSE; + + return TRUE; +} \ No newline at end of file diff --git a/CristalDiskMark/source/CrystalDiskMark/Priscilla/DialogFx.h b/CristalDiskMark/source/CrystalDiskMark/Priscilla/DialogFx.h new file mode 100644 index 0000000..3b369d0 --- /dev/null +++ b/CristalDiskMark/source/CrystalDiskMark/Priscilla/DialogFx.h @@ -0,0 +1,156 @@ +/*---------------------------------------------------------------------------*/ +// Author : hiyohiyo +// Mail : hiyohiyo@crystalmark.info +// Web : https://crystalmark.info/ +// License : MIT License +/*---------------------------------------------------------------------------*/ + +#pragma once + +#include "ImageFx.h" + +class CDialogFx : public CDialog +{ +public: + CDialogFx(UINT dlgResouce, CWnd* pParent = NULL); + virtual ~CDialogFx(); + + // Dialog + virtual BOOL Create(UINT nIDTemplate, CWnd* dlgWnd, UINT menuId, CWnd* pParentWnd = NULL); + + // Font + int GetFontScale(); + BYTE GetFontRender(); + double GetFontRatio(); + CString GetFontFace(); + + // Theme + BOOL IsDisableDarkMode(); + +protected: + // Dialog + virtual BOOL OnInitDialog(); + virtual BOOL PreTranslateMessage(MSG* pMsg); + virtual void PostNcDestroy(); + virtual void UpdateDialogSize(); + virtual void SetClientSize(int sizeX, int sizeY, double zoomRatio); + virtual void UpdateBackground(BOOL resize, BOOL darkMode); + virtual void SetWindowTitle(CString title); + virtual void OnOK(); + virtual void OnCancel(); + + // Zoom + DWORD ChangeZoomType(DWORD zoomType); + + // Theme + BOOL IsHighContrast(); + + // Utility + virtual CString IP(CString imageName); + CString i18n(CString section, CString key, BOOL inEnglish = FALSE); + void OpenUrl(CString url); + void SetLayeredWindow(HWND hWnd, BYTE alpha); + int GetDpi(); + + // MessageMap + DECLARE_MESSAGE_MAP() + afx_msg void OnSize(UINT nType, int cx, int cy); + afx_msg void OnTimer(UINT_PTR nIDEvent); + afx_msg BOOL OnEraseBkgnd(CDC* pDC); + afx_msg LRESULT OnDpiChanged(WPARAM wParam, LPARAM lParam); + afx_msg LRESULT OnDisplayChange(WPARAM wParam, LPARAM lParam); + afx_msg LRESULT OnSysColorChange(WPARAM wParam, LPARAM lParam); + afx_msg LRESULT OnSettingChange(WPARAM wParam, LPARAM lParam); + afx_msg LRESULT OnEnterSizeMove(WPARAM wParam, LPARAM lParam); + afx_msg LRESULT OnExitSizeMove(WPARAM wParam, LPARAM lParam); + +protected: + // Dialog + BOOL m_bInitializing; + BOOL m_bDpiChanging; + BOOL m_bShowWindow; + BOOL m_bModelessDlg; + BOOL m_bHighContrast; + BOOL m_bDarkMode; + BOOL m_bDisableDarkMode; + BOOL m_bBkImage; + UINT m_MenuId; + CWnd* m_ParentWnd; + CWnd* m_DlgWnd; + CString m_Ini; + HACCEL m_hAccelerator; + BOOL m_bDrag; + CString m_FontFace; + int m_FontScale; + double m_FontRatio; + BYTE m_FontRender; + HPALETTE m_hPal; + + int m_SizeX; + int m_MaxSizeX; + int m_MinSizeX; + int m_SizeY; + int m_MaxSizeY; + int m_MinSizeY; + + // Zoom + int m_Dpi; + DWORD m_ZoomType; + double m_ZoomRatio; + + // Color for SubClass + COLORREF m_LabelText; + COLORREF m_MeterText; + COLORREF m_ComboText; + COLORREF m_ComboTextSelected; + COLORREF m_ComboBk; + COLORREF m_ComboBkSelected; + COLORREF m_ButtonText; + COLORREF m_EditText; + COLORREF m_EditBk; + COLORREF m_ListText1; + COLORREF m_ListText2; + COLORREF m_ListTextSelected; + COLORREF m_ListBk1; + COLORREF m_ListBk2; + COLORREF m_ListBkSelected; + COLORREF m_ListLine1; + COLORREF m_ListLine2; + COLORREF m_Glass; + COLORREF m_Frame; + COLORREF m_Background; + + BYTE m_ComboAlpha; + BYTE m_EditAlpha; + BYTE m_GlassAlpha; + + BYTE m_CharacterPosition; + + // Theme for SubClass + int m_OffsetX; + CString m_ThemeDir; + CString m_CurrentTheme; + CString m_DefaultTheme; + CString m_ParentTheme1; + CString m_ParentTheme2; + CString m_RandomThemeLabel; + CString m_RandomThemeName; + + // Language for SubClass + CString m_LangDir; + CString m_CurrentLang; + CString m_CurrentLangPath; + CString m_DefaultLangPath; + CString m_BackgroundName; + + // Voice for SubClass + CString m_VoiceDir; + CString m_CurrentVoice; + INT m_VoiceVolume; + + // Class + CBitmap m_BkBitmap; + CDC m_BkDC; + CImage m_BkImage; + CBrush m_BrushDlg; +}; diff --git a/CristalDiskMark/source/CrystalDiskMark/Priscilla/EditFx.cpp b/CristalDiskMark/source/CrystalDiskMark/Priscilla/EditFx.cpp new file mode 100644 index 0000000..8d1c968 --- /dev/null +++ b/CristalDiskMark/source/CrystalDiskMark/Priscilla/EditFx.cpp @@ -0,0 +1,629 @@ +/*---------------------------------------------------------------------------*/ +// Author : hiyohiyo +// Mail : hiyohiyo@crystalmark.info +// Web : https://crystalmark.info/ +// License : MIT License +/*---------------------------------------------------------------------------*/ + +#include "stdafx.h" +#include "EditFx.h" + +////------------------------------------------------ +// CEditFx +////------------------------------------------------ + +CEditFx::CEditFx() +{ + // Control + m_X = 0; + m_Y = 0; + m_bHighContrast = FALSE; + m_bDarkMode = FALSE; + m_bDrawFrame = FALSE; + m_FrameColor = RGB(128, 128, 128); + m_RenderMode = OwnerDrawImage; + m_bMultiLine = FALSE; + m_BkColor = RGB(255, 255, 255); + + // Glass + m_GlassColor = RGB(255, 255, 255); + m_GlassAlpha = 128; + + // Image + m_ImageCount = 0; + m_BkDC = NULL; + m_bBkBitmapInit = FALSE; + m_bBkLoad = FALSE; + + // Font + m_TextAlign = SS_LEFT; + m_TextColor = RGB(0, 0, 0); + + // Margin + m_Margin.top = 0; + m_Margin.left = 0; + m_Margin.bottom = 0; + m_Margin.right = 0; +} + +CEditFx::~CEditFx() +{ +} + +IMPLEMENT_DYNAMIC(CEditFx, CEdit) + +BEGIN_MESSAGE_MAP(CEditFx, CEdit) + //{{AFX_MSG_MAP(CEditFx) + ON_WM_CTLCOLOR_REFLECT() + ON_CONTROL_REFLECT(EN_CHANGE, OnEnChange) + ON_WM_KEYDOWN() + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +//------------------------------------------------ +// Control +//------------------------------------------------ + +BOOL CEditFx::InitControl(int x, int y, int width, int height, double zoomRatio, CDC* bkDC, + LPCTSTR imagePath, int imageCount, DWORD textAlign, int renderMode, BOOL bHighContrast, BOOL bDarkMode, BOOL bDrawFrame, BOOL bMultiLine) +{ + m_X = (int)(x * zoomRatio); + m_Y = (int)(y * zoomRatio); + m_CtrlSize.cx = (int)(width * zoomRatio); + m_CtrlSize.cy = (int)(height * zoomRatio); + MoveWindow(m_X, m_Y, m_CtrlSize.cx, m_CtrlSize.cy); + m_bMultiLine = bMultiLine; + + m_BkDC = bkDC; + m_ImagePath = imagePath; + m_ImageCount = imageCount; + m_RenderMode = renderMode; + + if (ES_LEFT <= textAlign && textAlign <= ES_RIGHT) + { + m_TextAlign = textAlign; + ModifyStyle(0, m_TextAlign); + } + + if (m_ToolTip.m_hWnd != NULL) + { + if (m_ToolTip.GetToolCount() != 0) + { + m_ToolTip.DelTool(this, 1); + } + CRect rect; + GetClientRect(rect); + m_ToolTip.AddTool(this, m_ToolTipText, rect, 1); + } + + m_bHighContrast = bHighContrast; + m_bDarkMode = bDarkMode; + m_bDrawFrame = bDrawFrame; + + if (m_bHighContrast) + { + return TRUE; + } + else if (renderMode & SystemDraw) + { + return TRUE; + } + else + { + SetBkReload(); + LoadCtrlBk(m_BkDC); + } + + if (renderMode & OwnerDrawImage) + { + if (!LoadBitmap(imagePath)) + { + } + } + else + { + m_ImageCount = 1; + m_CtrlImage.Destroy(); + m_CtrlImage.Create(m_CtrlSize.cx, m_CtrlSize.cy * m_ImageCount, 32); + m_CtrlBitmap.Detach(); + m_CtrlBitmap.Attach((HBITMAP)m_CtrlImage); + DWORD length = m_CtrlSize.cx * m_CtrlSize.cy * m_ImageCount * 4; + BYTE* bitmapBits = new BYTE[length]; + m_CtrlBitmap.GetBitmapBits(length, bitmapBits); + + BYTE r, g, b, a; + if (renderMode & OwnerDrawGlass) + { + r = (BYTE)GetRValue(m_GlassColor); + g = (BYTE)GetGValue(m_GlassColor); + b = (BYTE)GetBValue(m_GlassColor); + a = m_GlassAlpha; + } + else // OwnerDrawTransparent + { + r = 0; + g = 0; + b = 0; + a = 0; + } + + for (int y = 0; y < (int)(m_CtrlSize.cy * m_ImageCount); y++) + { + for (int x = 0; x < m_CtrlSize.cx; x++) + { + DWORD p = (y * m_CtrlSize.cx + x) * 4; +#if _MSC_VER > 1310 +#pragma warning( disable : 6386 ) +#endif + bitmapBits[p + 0] = b; + bitmapBits[p + 1] = g; + bitmapBits[p + 2] = r; + bitmapBits[p + 3] = a; +#if _MSC_VER > 1310 +#pragma warning( default : 6386 ) +#endif + } + } + + m_CtrlBitmap.SetBitmapBits(length, bitmapBits); + delete[] bitmapBits; + } + + SetupControlImage(m_BkBitmap, m_CtrlBitmap); + + m_BkBrush.DeleteObject(); + m_BkBrush.CreatePatternBrush(&m_CtrlBitmap); + + Invalidate(); + + return TRUE; +} + +void CEditFx::SetMargin(int top, int left, int bottom, int right, double zoomRatio) +{ + m_Margin.top = (int)(top * zoomRatio); + m_Margin.left = (int)(left * zoomRatio); + m_Margin.bottom = (int)(bottom * zoomRatio); + m_Margin.right = (int)(right * zoomRatio); + + if (GetWindowLongPtr(m_hWnd, GWL_STYLE) & ES_MULTILINE) + { + CRect rectGet, rectSet; + GetRect(rectGet); + + rectSet.top = m_Margin.top; + rectSet.bottom = rectGet.bottom - m_Margin.bottom - m_Margin.top; + rectSet.left = m_Margin.left; + rectSet.right = rectGet.right - m_Margin.right - m_Margin.left; + + SetRect(rectSet); + } + else + { + SetMargins(m_Margin.left, m_Margin.right); + } +} + +CSize CEditFx::GetSize(void) +{ + return m_CtrlSize; +} + +void CEditFx::SetDrawFrame(BOOL bDrawFrame) +{ +#if _MSC_VER > 1310 + if (bDrawFrame) + { + ModifyStyleEx(0, WS_EX_STATICEDGE, SWP_DRAWFRAME); + } + else + { + ModifyStyleEx(WS_EX_STATICEDGE, 0, SWP_DRAWFRAME); + } +#else + if (bDrawFrame) + { + if (IsNT3()) + { + ModifyStyle(0, WS_BORDER, SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_FRAMECHANGED); + } + else + { + ModifyStyleEx(0, WS_EX_STATICEDGE, SWP_DRAWFRAME); + } + } + else + { + if (IsNT3()) + { + ModifyStyle(WS_BORDER, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_FRAMECHANGED); + } + else + { + ModifyStyleEx(WS_EX_STATICEDGE, 0, SWP_DRAWFRAME); + } + } +#endif + m_bDrawFrame = bDrawFrame; +} + +void CEditFx::SetGlassColor(COLORREF glassColor, BYTE glassAlpha) +{ + m_GlassColor = glassColor; + m_GlassAlpha = glassAlpha; +} + +void CEditFx::SetBkColor(COLORREF bkColor) +{ + m_BkColor = bkColor; +} + +void CEditFx::Adjust() +{ + CRect rectGet, rectSet; + GetRect(rectGet); + + CClientDC dc(this); + HGDIOBJ oldFont = dc.SelectObject(&m_Font); +#ifdef UNICODE + CSize size = dc.GetTextExtent(L"ÁAaPpQqYy8!"); +#else + CSize size = dc.GetTextExtent("AaPpQqYy8!"); +#endif + + dc.SelectObject(oldFont); + + rectSet.top = (m_CtrlSize.cy - size.cy) / 2; + rectSet.bottom = rectSet.top + size.cy; + rectSet.left = rectGet.left; + rectSet.right = rectGet.right; + + SetRect(rectSet); +} + +HBRUSH CEditFx::CtlColor(CDC* pDC, UINT nCtlColor) +{ + if (m_bHighContrast) + { + pDC->SetBkMode(TRANSPARENT); + return NULL; + } + else + { +#ifdef UNICODE + pDC->SetTextColor(m_TextColor); + pDC->SetBkMode(TRANSPARENT); + return m_BkBrush; +#else + pDC->SetTextColor(m_TextColor); + pDC->SetBkColor(m_BkColor); + pDC->SetBkMode(OPAQUE); + + return CreateSolidBrush(m_BkColor); +#endif + } +} + +//------------------------------------------------ +// Image +//------------------------------------------------ + +BOOL CEditFx::LoadBitmap(LPCTSTR fileName) +{ + if (m_bHighContrast) { return FALSE; } + if (fileName == NULL) { return FALSE; } + + m_CtrlImage.Destroy(); + m_CtrlImage.Load(fileName); + if (m_CtrlImage.IsNull()) { return FALSE; } + + return LoadBitmap((HBITMAP)m_CtrlImage); +} + +BOOL CEditFx::LoadBitmap(HBITMAP hBitmap) +{ + if (m_bHighContrast) { return FALSE; } + + m_CtrlBitmap.Detach(); + m_CtrlBitmap.Attach(hBitmap); + + return SetBitmap(m_CtrlBitmap); +} + +void CEditFx::SetBkReload(void) +{ + m_bBkBitmapInit = FALSE; + m_bBkLoad = FALSE; +} + +BOOL CEditFx::SetBitmap(CBitmap& bitmap) +{ + if (m_bHighContrast) { return FALSE; } + + BITMAP bitmapInfo; + bitmap.GetBitmap(&bitmapInfo); + + if (m_CtrlSize.cx != bitmapInfo.bmWidth + || m_CtrlSize.cy != bitmapInfo.bmHeight / m_ImageCount) + { + return FALSE; + } + else + { + return TRUE; + } +} + +void CEditFx::LoadCtrlBk(CDC* drawDC) +{ + if (m_bHighContrast) { SetBkReload(); return; } + + if (m_BkBitmap.m_hObject != NULL) + { + BITMAP bitmapInfo; + m_BkBitmap.GetBitmap(&bitmapInfo); + if (bitmapInfo.bmBitsPixel != drawDC->GetDeviceCaps(BITSPIXEL)) + { + SetBkReload(); + } + } + + if (&m_CtrlBitmap != NULL) + { + if (!m_bBkBitmapInit) + { + m_BkBitmap.DeleteObject(); + m_BkBitmap.CreateCompatibleBitmap(drawDC, m_CtrlSize.cx, m_CtrlSize.cy); + m_bBkBitmapInit = TRUE; + } + + if (!m_bBkLoad) + { + CBitmap* pOldBitmap; + CDC* pMemDC = new CDC; + pMemDC->CreateCompatibleDC(drawDC); + pOldBitmap = pMemDC->SelectObject(&m_BkBitmap); + pMemDC->BitBlt(0, 0, m_CtrlSize.cx, m_CtrlSize.cy, m_BkDC, m_X, m_Y, SRCCOPY); + pMemDC->SelectObject(pOldBitmap); + pMemDC->DeleteDC(); + delete pMemDC; + m_bBkLoad = TRUE; + } + } +} + +void CEditFx::SetupControlImage(CBitmap& bkBitmap, CBitmap& ctrlBitmap) +{ + int color = m_BkDC->GetDeviceCaps(BITSPIXEL) * m_BkDC->GetDeviceCaps(PLANES); + + if (!m_CtrlImage.IsNull()) + { + if (m_CtrlImage.GetBPP() == 32) + { + CBitmap* bk32Bitmap; + CImage bk32Image; + if (color == 32) + { + bk32Bitmap = &bkBitmap; + } + else + { + bk32Image.Create(m_CtrlSize.cx, m_CtrlSize.cy, 32); + ::BitBlt(bk32Image.GetDC(), 0, 0, m_CtrlSize.cx, m_CtrlSize.cy, *m_BkDC, m_X, m_Y, SRCCOPY); + bk32Bitmap = CBitmap::FromHandle((HBITMAP)bk32Image); + bk32Image.ReleaseDC(); + } + + BITMAP CtlBmpInfo, DstBmpInfo; + bk32Bitmap->GetBitmap(&DstBmpInfo); + DWORD DstLineBytes = DstBmpInfo.bmWidthBytes; + DWORD DstMemSize = DstLineBytes * DstBmpInfo.bmHeight; + ctrlBitmap.GetBitmap(&CtlBmpInfo); + DWORD CtlLineBytes = CtlBmpInfo.bmWidthBytes; + DWORD CtlMemSize = CtlLineBytes * CtlBmpInfo.bmHeight; + + if ((DstBmpInfo.bmWidthBytes != CtlBmpInfo.bmWidthBytes) + || (DstBmpInfo.bmHeight != CtlBmpInfo.bmHeight / m_ImageCount)) + { + // Error Check // + } + else + { + BYTE* DstBuffer = new BYTE[DstMemSize]; + bk32Bitmap->GetBitmapBits(DstMemSize, DstBuffer); + BYTE* CtlBuffer = new BYTE[CtlMemSize]; + ctrlBitmap.GetBitmapBits(CtlMemSize, CtlBuffer); + + int baseY = 0; + for (LONG py = 0; py < DstBmpInfo.bmHeight; py++) + { + int dn = py * DstLineBytes; + int cn = (baseY + py) * CtlLineBytes; + for (LONG px = 0; px < DstBmpInfo.bmWidth; px++) + { +#if _MSC_VER > 1310 +#pragma warning( disable : 6385 ) +#pragma warning( disable : 6386 ) +#endif + BYTE a = CtlBuffer[cn + 3]; + BYTE na = 255 - a; + CtlBuffer[dn + 0] = (BYTE)((CtlBuffer[cn + 0] * a + DstBuffer[dn + 0] * na) / 255); + CtlBuffer[dn + 1] = (BYTE)((CtlBuffer[cn + 1] * a + DstBuffer[dn + 1] * na) / 255); + CtlBuffer[dn + 2] = (BYTE)((CtlBuffer[cn + 2] * a + DstBuffer[dn + 2] * na) / 255); + dn += (DstBmpInfo.bmBitsPixel / 8); + cn += (CtlBmpInfo.bmBitsPixel / 8); +#if _MSC_VER > 1310 +#pragma warning( default : 6386 ) +#pragma warning( default : 6385 ) +#endif + } + } + + if (color == 32) + { + ctrlBitmap.SetBitmapBits(CtlMemSize, CtlBuffer); + } + else + { + bk32Bitmap->SetBitmapBits(CtlMemSize, CtlBuffer); + m_CtrlImage.Detach(); + m_CtrlImage.Attach(ctrlBitmap); + ::BitBlt(m_CtrlImage.GetDC(), 0, 0, m_CtrlSize.cx, m_CtrlSize.cy, bk32Image.GetDC(), 0, 0, SRCCOPY); + m_CtrlImage.ReleaseDC(); + bk32Image.ReleaseDC(); + + ctrlBitmap.SetBitmapBits(CtlMemSize, CtlBuffer); + } + + if (m_bDrawFrame) + { + HGDIOBJ oldPen; + POINT point; + CPen pen1; pen1.CreatePen(PS_SOLID, 1, RGB(0xF8, 0xF8, 0xF8)); + CPen pen2; pen2.CreatePen(PS_SOLID, 1, RGB(0x98, 0x98, 0x98)); + + HDC hDC = m_CtrlImage.GetDC(); + + oldPen = SelectObject(hDC, pen1); + MoveToEx(hDC, 0, m_CtrlSize.cy - 1, &point); + LineTo(hDC, m_CtrlSize.cx - 1, m_CtrlSize.cy - 1); + LineTo(hDC, m_CtrlSize.cx - 1, 0); + LineTo(hDC, m_CtrlSize.cx - 1, m_CtrlSize.cy - 1); + SelectObject(hDC, pen2); + MoveToEx(hDC, 0, m_CtrlSize.cy - 2, &point); + LineTo(hDC, 0, 0); + LineTo(hDC, m_CtrlSize.cx - 1, 0); + SelectObject(hDC, oldPen); + + pen1.DeleteObject(); + pen2.DeleteObject(); + m_CtrlImage.ReleaseDC(); + } + + delete[] DstBuffer; + delete[] CtlBuffer; + } + } + } +} + +//------------------------------------------------ +// Font +//------------------------------------------------ + +void CEditFx::SetFontEx(CString face, int size, int sizeToolTip, double zoomRatio, double fontRatio, + COLORREF textColor, LONG fontWeight, BYTE fontRender) +{ + LOGFONT logFont = { 0 }; + logFont.lfCharSet = DEFAULT_CHARSET; + logFont.lfHeight = (LONG)(-1 * size * zoomRatio * fontRatio); + logFont.lfQuality = fontRender; + logFont.lfWeight = fontWeight; + if (face.GetLength() < 32) + { + wsprintf(logFont.lfFaceName, _T("%s"), (LPCTSTR)face); + } + else + { + wsprintf(logFont.lfFaceName, _T("")); + } + + m_Font.DeleteObject(); + m_Font.CreateFontIndirect(&logFont); + SetFont(&m_Font); + + logFont.lfHeight = (LONG)(-1 * sizeToolTip * zoomRatio); + m_FontToolTip.DeleteObject(); + m_FontToolTip.CreateFontIndirect(&logFont); + + m_TextColor = textColor; + + if (m_ToolTip.m_hWnd != NULL) + { + m_ToolTip.SetFont(&m_FontToolTip); + } +} + +//------------------------------------------------ +// Message Map +//------------------------------------------------ + +void CEditFx::OnEnChange() +{ + Invalidate(); +} + +void CEditFx::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) +{ + if (nChar == VK_RETURN && m_bMultiLine == FALSE) + { + return ; + } + else + { + CEdit::OnKeyDown(nChar, nRepCnt, nFlags); + } +} + +//------------------------------------------------ +// ToolTip +//------------------------------------------------ + +void CEditFx::SetToolTipText(LPCTSTR text) +{ + if (text == NULL) { return; } + + InitToolTip(); + m_ToolTipText = text; + if (m_ToolTip.GetToolCount() == 0) + { + CRect rect; + GetClientRect(rect); + m_ToolTip.AddTool(this, m_ToolTipText, rect, 1); + } + else + { + m_ToolTip.UpdateTipText(m_ToolTipText, this, 1); + } + + SetToolTipActivate(TRUE); +} + +void CEditFx::SetToolTipActivate(BOOL bActivate) +{ + if (m_ToolTip.GetToolCount() == 0) { return; } + m_ToolTip.Activate(bActivate); +} + +void CEditFx::SetToolTipWindowText(LPCTSTR text) +{ + SetToolTipText(text); + SetWindowText(text); +} + +CString CEditFx::GetToolTipText() +{ + return m_ToolTipText; +} + +void CEditFx::InitToolTip() +{ + if (m_ToolTip.m_hWnd == NULL) + { + m_ToolTip.Create(this, TTS_ALWAYSTIP | TTS_BALLOON | TTS_NOANIMATE | TTS_NOFADE); + m_ToolTip.Activate(FALSE); + m_ToolTip.SetFont(&m_FontToolTip); + m_ToolTip.SendMessage(TTM_SETMAXTIPWIDTH, 0, 1024); + m_ToolTip.SetDelayTime(TTDT_AUTOPOP, 8000); + m_ToolTip.SetDelayTime(TTDT_INITIAL, 500); + m_ToolTip.SetDelayTime(TTDT_RESHOW, 100); + } +} + +BOOL CEditFx::PreTranslateMessage(MSG* pMsg) +{ + InitToolTip(); + m_ToolTip.RelayEvent(pMsg); + + return CEdit::PreTranslateMessage(pMsg); +} \ No newline at end of file diff --git a/CristalDiskMark/source/CrystalDiskMark/Priscilla/EditFx.h b/CristalDiskMark/source/CrystalDiskMark/Priscilla/EditFx.h new file mode 100644 index 0000000..8019299 --- /dev/null +++ b/CristalDiskMark/source/CrystalDiskMark/Priscilla/EditFx.h @@ -0,0 +1,98 @@ +/*---------------------------------------------------------------------------*/ +// Author : hiyohiyo +// Mail : hiyohiyo@crystalmark.info +// Web : https://crystalmark.info/ +// License : MIT License +/*---------------------------------------------------------------------------*/ + +#pragma once + +#include "ImageFx.h" + +class CEditFx : public CEdit +{ + DECLARE_DYNAMIC(CEditFx); + +public: + // Constructors + CEditFx(); + virtual ~CEditFx(); + + // Control + BOOL InitControl(int x, int y, int width, int height, double zoomRatio, CDC* bkDC, LPCTSTR imagePath, + int imageCount, DWORD textAlign, int renderMode, BOOL bHighContrast, BOOL bDarkMode, BOOL bDrawFrame, BOOL bMultiLine = FALSE); + void SetMargin(int top, int left, int bottom, int right, double zoomRatio); + CSize GetSize(void); + void SetDrawFrame(BOOL bDrawFrame); + void SetGlassColor(COLORREF glassColor, BYTE glassAlpha); + void SetBkColor(COLORREF bkColor); + void Adjust(); + + // Font + void SetFontEx(CString face, int size, int sizeToolTip, double zoomRatio, double fontRatio = 1.0, + COLORREF textColor = RGB(0, 0, 0), LONG fontWeight = FW_NORMAL, BYTE fontRender = CLEARTYPE_NATURAL_QUALITY); + + // ToolTip + void SetToolTipText(LPCTSTR text); + void SetToolTipActivate(BOOL bActivate = TRUE); + void SetToolTipWindowText(LPCTSTR text); + CString GetToolTipText(); + +protected: + // Image + BOOL LoadBitmap(LPCTSTR fileName); + BOOL LoadBitmap(HBITMAP hBitmap); + void SetBkReload(void); + BOOL SetBitmap(CBitmap& bitmap); + void LoadCtrlBk(CDC* drawDC); + void SetupControlImage(CBitmap& bkBitmap, CBitmap& ctrlBitmap); + + // ToolTip + void InitToolTip(); + virtual BOOL PreTranslateMessage(MSG* pMsg); + + // MessageMap + DECLARE_MESSAGE_MAP() + afx_msg HBRUSH CtlColor(CDC* pDC, UINT nCtlColor); + afx_msg void OnEnChange(); + afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags); + +protected: + // Control + int m_X; + int m_Y; + CSize m_CtrlSize; + CRect m_Margin; + int m_RenderMode; + BOOL m_bHighContrast; + BOOL m_bDarkMode; + BOOL m_bDrawFrame; + COLORREF m_FrameColor; + BOOL m_bMultiLine; + COLORREF m_BkColor; + + // Glass + COLORREF m_GlassColor; + BYTE m_GlassAlpha; + + // Image + CString m_ImagePath; + int m_ImageCount; + CDC* m_BkDC; + CBitmap m_BkBitmap; + CBrush m_BkBrush; + BOOL m_bBkBitmapInit; + BOOL m_bBkLoad; + CBitmap m_CtrlBitmap; + CImage m_CtrlImage; + + // Font + DWORD m_TextAlign; + CFont m_Font; + CFont m_FontToolTip; + COLORREF m_TextColor; + + // ToolTip + CToolTipCtrl m_ToolTip; + CString m_ToolTipText; +}; diff --git a/CristalDiskMark/source/CrystalDiskMark/Priscilla/FontComboBoxFx.cpp b/CristalDiskMark/source/CrystalDiskMark/Priscilla/FontComboBoxFx.cpp new file mode 100644 index 0000000..1583362 --- /dev/null +++ b/CristalDiskMark/source/CrystalDiskMark/Priscilla/FontComboBoxFx.cpp @@ -0,0 +1,134 @@ +/*---------------------------------------------------------------------------*/ +// Author : hiyohiyo +// Mail : hiyohiyo@crystalmark.info +// Web : https://crystalmark.info/ +// License : MIT License +/*---------------------------------------------------------------------------*/ + +#include "stdafx.h" +#include "FontComboBoxFx.h" + +////------------------------------------------------ +// CFontComboBox +////------------------------------------------------ + +IMPLEMENT_DYNAMIC(CFontComboBox, CComboBoxFx) + +CFontComboBox::CFontComboBox() +{ + m_Brush = NULL; +} + +CFontComboBox::~CFontComboBox() +{ + m_BkBrush.DeleteObject(); +} + +BEGIN_MESSAGE_MAP(CFontComboBox, CComboBoxFx) +END_MESSAGE_MAP() + +void CFontComboBox::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) +{ + if (lpDrawItemStruct->itemID == -1) { return; } + + static COLORREF textColor; + static COLORREF textColorSelected; + static COLORREF bkColor; + static COLORREF bkColorSelected; + + if (m_bHighContrast) + { + textColor = GetTextColor(lpDrawItemStruct->hDC); + textColorSelected = RGB(0, 0, 0); + bkColor = GetBkColor(lpDrawItemStruct->hDC); + bkColorSelected = RGB(0, 255, 255); + + if (bkColor <= RGB(0x80, 0x80, 0x80)) { textColor = RGB(255, 255, 255); } + else { textColor = RGB(0, 0, 0); } + } + else if (m_bDarkMode) + { + textColor = RGB(255, 255, 255); + textColorSelected = RGB(255, 255, 255); + bkColor = RGB(32, 32, 32); + bkColorSelected = RGB(77, 77, 77); + } + else + { + textColor = m_TextColor; + textColorSelected = m_TextColorSelected; + bkColor = m_BkColor; + bkColorSelected = m_BkColorSelected; + } + + CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC); + LoadCtrlBk(pDC); + CString title; + GetLBText(lpDrawItemStruct->itemID, title); + + CFont font; + LOGFONT logfont; + memset(&logfont, 0, sizeof(logfont)); + logfont.lfHeight = m_FontHeight; + logfont.lfWidth = 0; + logfont.lfWeight = FW_NORMAL; + logfont.lfQuality = m_FontRender; + logfont.lfCharSet = DEFAULT_CHARSET; + +#if _MSC_VER <= 1310 + _tcscpy(logfont.lfFaceName, (LPCTSTR)title); +#else + _tcscpy_s(logfont.lfFaceName, 32, (LPCTSTR)title); +#endif + font.CreateFontIndirect(&logfont); + HGDIOBJ oldFont = pDC->SelectObject(&font); + + CBrush Brush; + CBrush* pOldBrush; + if (lpDrawItemStruct->rcItem.left != 0 && !m_bHighContrast) + { + DrawControl(title, pDC, lpDrawItemStruct, m_CtrlBitmap, m_BkBitmap, ControlImageNormal); + Brush.CreateSolidBrush(bkColorSelected); + pOldBrush = pDC->SelectObject(&Brush); + if (lpDrawItemStruct->itemState & ODS_SELECTED) + { + RECT rc = lpDrawItemStruct->rcItem; + // rc.top = (LONG)(rc.bottom - 2 * m_ZoomRatio); + rc.right = (LONG)(rc.left + 3 * m_ZoomRatio); + FillRect(lpDrawItemStruct->hDC, &rc, (HBRUSH)Brush); + } + DrawString(title, pDC, lpDrawItemStruct, textColor); + +#if _MSC_VER <= 1310 + if (IsNT3() && IsWindowEnabled()) + { + DWORD oldTextAlign = m_TextAlign; + HGDIOBJ myoldFont = pDC->SelectStockObject(SYSTEM_FONT); + m_TextAlign = ES_RIGHT; + DrawString(_T("v"), pDC, lpDrawItemStruct, textColor); + m_TextAlign = oldTextAlign; + pDC->SelectObject(myoldFont); + } +#endif + } + else + { + if (lpDrawItemStruct->itemState & ODS_SELECTED) + { + Brush.CreateSolidBrush(bkColorSelected); + pOldBrush = pDC->SelectObject(&Brush); + FillRect(lpDrawItemStruct->hDC, &lpDrawItemStruct->rcItem, (HBRUSH)Brush); + DrawString(title, pDC, lpDrawItemStruct, textColorSelected); + } + else + { + Brush.CreateSolidBrush(bkColor); + pOldBrush = pDC->SelectObject(&Brush); + FillRect(lpDrawItemStruct->hDC, &lpDrawItemStruct->rcItem, (HBRUSH)Brush); + DrawString(title, pDC, lpDrawItemStruct, textColor); + } + } + pDC->SelectObject(pOldBrush); + Brush.DeleteObject(); + pDC->SelectObject(oldFont); +} diff --git a/CristalDiskMark/source/CrystalDiskMark/Priscilla/FontComboBoxFx.h b/CristalDiskMark/source/CrystalDiskMark/Priscilla/FontComboBoxFx.h new file mode 100644 index 0000000..56f1125 --- /dev/null +++ b/CristalDiskMark/source/CrystalDiskMark/Priscilla/FontComboBoxFx.h @@ -0,0 +1,27 @@ +/*---------------------------------------------------------------------------*/ +// Author : hiyohiyo +// Mail : hiyohiyo@crystalmark.info +// Web : https://crystalmark.info/ +// License : MIT License +/*---------------------------------------------------------------------------*/ + +#pragma once + +#include "ComboBoxFx.h" + +class CFontComboBox : public CComboBoxFx +{ + DECLARE_DYNAMIC(CFontComboBox) + +public: + CFontComboBox(); + virtual ~CFontComboBox(); + +protected: + DECLARE_MESSAGE_MAP() + virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct); + + HBRUSH m_Brush; +}; + + diff --git a/CristalDiskMark/source/CrystalDiskMark/Priscilla/HeaderCtrlFx.cpp b/CristalDiskMark/source/CrystalDiskMark/Priscilla/HeaderCtrlFx.cpp new file mode 100644 index 0000000..444c425 --- /dev/null +++ b/CristalDiskMark/source/CrystalDiskMark/Priscilla/HeaderCtrlFx.cpp @@ -0,0 +1,203 @@ +/*---------------------------------------------------------------------------*/ +// Author : hiyohiyo +// Mail : hiyohiyo@crystalmark.info +// Web : https://crystalmark.info/ +// License : MIT License +/*---------------------------------------------------------------------------*/ + +#include "stdafx.h" +#include "HeaderCtrlFx.h" +#include "OsInfoFx.h" + +IMPLEMENT_DYNAMIC(CHeaderCtrlFx, CHeaderCtrl) + +CHeaderCtrlFx::CHeaderCtrlFx() +{ + m_X = 0; + m_Y = 0; + + m_TextColor = RGB(0, 0, 0); + m_LineColor = RGB(224, 224, 224); + m_BkColor = RGB(255, 255, 255); + m_ZoomRatio = 1.0; + m_FontRatio = 1.0; + m_FontSize = 12; + m_BkDC = NULL; + m_CtrlBitmap = NULL; + m_bHighContrast = FALSE; + m_bDarkMode = FALSE; + m_RenderMode = SystemDraw; +} + +CHeaderCtrlFx::~CHeaderCtrlFx() +{ +} + +BEGIN_MESSAGE_MAP(CHeaderCtrlFx, CHeaderCtrl) + ON_WM_PAINT() + ON_MESSAGE(HDM_LAYOUT, OnLayout) +END_MESSAGE_MAP() + +void CHeaderCtrlFx::InitControl(int x, int y, double zoomRatio, CDC* bkDC, CBitmap* ctrlBitmap, COLORREF textColor, COLORREF bkColor, COLORREF lineColor, int renderMode, BOOL bHighContrast, BOOL bDarkMode) +{ + m_X = (int)(x * zoomRatio); + m_Y = (int)(y * zoomRatio); + m_ZoomRatio = zoomRatio; + m_BkDC = bkDC; + m_TextColor = textColor; + m_LineColor = lineColor; + m_BkColor = bkColor; + + m_CtrlBitmap = ctrlBitmap; + m_RenderMode = renderMode; + m_bHighContrast = bHighContrast; + m_bDarkMode = bDarkMode; +} + +void CHeaderCtrlFx::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) +{ + if (m_bHighContrast || m_RenderMode & SystemDraw) + { + return CHeaderCtrl::DrawItem(lpDrawItemStruct); + } + + CDC* drawDC = CDC::FromHandle(lpDrawItemStruct->hDC); + + drawDC->SetBkMode(TRANSPARENT); + drawDC->SetTextColor(m_TextColor); + + CRect clientRect; + GetClientRect(&clientRect); + + CDC BkDC; + BkDC.CreateCompatibleDC(m_BkDC); + BkDC.SelectObject(m_CtrlBitmap); + CRect rc = lpDrawItemStruct->rcItem; + CBrush br; + + if (m_CtrlBitmap != NULL) + { + drawDC->BitBlt(rc.left, rc.top, rc.right, rc.bottom, &BkDC, rc.left, rc.top, SRCCOPY); + } + else + { + br.CreateSolidBrush(m_BkColor); + drawDC->FillRect(&rc, &br); + } + + br.DeleteObject(); + br.CreateSolidBrush(m_LineColor); + + CRect rect = lpDrawItemStruct->rcItem; + rect.left = rect.right - 1; + drawDC->FillRect(&rect, &br); + + rect = lpDrawItemStruct->rcItem; + rect.top = rect.bottom - 1; + drawDC->FillRect(&rect, &br); + + HDITEM hi{}; + TCHAR str[256]{}; + hi.mask = HDI_TEXT | HDI_FORMAT; + hi.pszText = str; + hi.cchTextMax = 256; + GetItem(lpDrawItemStruct->itemID, &hi); + + rect = (CRect)(lpDrawItemStruct->rcItem); + + if (hi.fmt & HDF_CENTER) + { + drawDC->DrawText(hi.pszText, lstrlen(hi.pszText), rect, DT_CENTER | DT_VCENTER | DT_SINGLELINE); + } + else if (hi.fmt & HDF_RIGHT) + { + rect.right -= 6; + drawDC->DrawText(hi.pszText, lstrlen(hi.pszText), rect, DT_RIGHT | DT_VCENTER | DT_SINGLELINE); + } + else + { + rect.left += 6; + drawDC->DrawText(hi.pszText, lstrlen(hi.pszText), rect, DT_LEFT | DT_VCENTER | DT_SINGLELINE); + } +} + +void CHeaderCtrlFx::OnPaint() +{ + if (m_bHighContrast || m_RenderMode & SystemDraw) + { + return CHeaderCtrl::OnPaint(); + } + + CHeaderCtrl::OnPaint(); + + RECT rectRightItem; + int iItemCount = Header_GetItemCount(this->m_hWnd); + if (iItemCount > 0) + { + Header_GetItemRect(this->m_hWnd, (WPARAM)iItemCount - 1, &rectRightItem); + RECT rectClient; + GetClientRect(&rectClient); + if (rectRightItem.right < rectClient.right) + { + CDC* drawDC = GetDC(); + if (m_CtrlBitmap != NULL) + { + CDC BkDC; + BkDC.CreateCompatibleDC(m_BkDC); + BkDC.SelectObject(m_CtrlBitmap); + drawDC->BitBlt(rectRightItem.right, rectClient.top, rectClient.right, rectClient.bottom, &BkDC, rectRightItem.right, rectRightItem.top, SRCCOPY); + } + else + { + CBrush br; + br.CreateSolidBrush(m_BkColor); + rectClient.left = rectRightItem.right; + drawDC->FillRect(&rectClient, &br); + } + } + } +} + +LRESULT CHeaderCtrlFx::OnLayout(WPARAM wParam, LPARAM lParam) +{ + LRESULT lResult = CHeaderCtrl::DefWindowProc(HDM_LAYOUT, 0, lParam); + + if (IsWinXpLuna()) + { + HD_LAYOUT& hdl = *(HD_LAYOUT*)lParam; + RECT* prc = hdl.prc; + WINDOWPOS* pwpos = hdl.pwpos; + + int nHeight = (int)(pwpos->cy * (m_ZoomRatio * m_FontRatio)); + + pwpos->cy = nHeight; + prc->top = nHeight; + } + + return lResult; +} + +void CHeaderCtrlFx::SetFontEx(CString face, int size, double zoomRatio, double fontRatio, LONG fontWeight, BYTE fontRender) +{ + m_FontSize = size; + m_ZoomRatio = zoomRatio; + m_FontRatio = fontRatio; + + LOGFONT logFont = { 0 }; + logFont.lfCharSet = DEFAULT_CHARSET; + logFont.lfHeight = (LONG)(-1 * size * zoomRatio * fontRatio); + logFont.lfQuality = fontRender; + logFont.lfWeight = fontWeight; + if (face.GetLength() < 32) + { + wsprintf(logFont.lfFaceName, _T("%s"), (LPCTSTR)face); + } + else + { + wsprintf(logFont.lfFaceName, _T("")); + } + + m_Font.DeleteObject(); + m_Font.CreateFontIndirect(&logFont); + SetFont(&m_Font); +} \ No newline at end of file diff --git a/CristalDiskMark/source/CrystalDiskMark/Priscilla/HeaderCtrlFx.h b/CristalDiskMark/source/CrystalDiskMark/Priscilla/HeaderCtrlFx.h new file mode 100644 index 0000000..e36bfed --- /dev/null +++ b/CristalDiskMark/source/CrystalDiskMark/Priscilla/HeaderCtrlFx.h @@ -0,0 +1,45 @@ +/*---------------------------------------------------------------------------*/ +// Author : hiyohiyo +// Mail : hiyohiyo@crystalmark.info +// Web : https://crystalmark.info/ +// License : MIT License +/*---------------------------------------------------------------------------*/ + +#pragma once + +class CHeaderCtrlFx : public CHeaderCtrl +{ + DECLARE_DYNAMIC(CHeaderCtrlFx) + +public: + CHeaderCtrlFx(); + virtual ~CHeaderCtrlFx(); + void InitControl(int x, int y, double zoomRatio, CDC* bkDC, CBitmap* ctrlBitmap, COLORREF textColor, COLORREF bkColor, COLORREF lineColor, int renderMode, BOOL bHighContrast, BOOL bDarkMode); + void SetFontEx(CString face, int size, double zoomRatio, double fontRatio, LONG fontWeight, BYTE fontRender); + +protected: + // Draw Control + virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct); + + DECLARE_MESSAGE_MAP() + afx_msg void OnPaint(); + afx_msg LRESULT OnLayout(WPARAM wParam, LPARAM lParam); + + int m_X; + int m_Y; + COLORREF m_TextColor; + COLORREF m_BkColor; + COLORREF m_LineColor; + double m_ZoomRatio; + double m_FontRatio; + int m_RenderMode; + BOOL m_bHighContrast; + BOOL m_bDarkMode; + + CFont m_Font; + int m_FontSize; + CDC* m_BkDC; + CBitmap* m_CtrlBitmap; +}; + + diff --git a/CristalDiskMark/source/CrystalDiskMark/Priscilla/IatHook.h b/CristalDiskMark/source/CrystalDiskMark/Priscilla/IatHook.h new file mode 100644 index 0000000..b1406a3 --- /dev/null +++ b/CristalDiskMark/source/CrystalDiskMark/Priscilla/IatHook.h @@ -0,0 +1,99 @@ +/*---------------------------------------------------------------------------*/ +// Author : Richard Yu +// Web : https://github.com/ysc3839/win32-darkmode +// License : The MIT License +// https://github.com/ysc3839/win32-darkmode/blob/master/LICENSE +/*---------------------------------------------------------------------------*/ +// This file contains code from +// https://github.com/stevemk14ebr/PolyHook_2_0/blob/master/sources/IatHook.cpp +// which is licensed under the MIT License. +// See PolyHook_2_0-LICENSE for more information. + +#pragma once + +#include + +template +constexpr T RVA2VA(T1 base, T2 rva) +{ + return reinterpret_cast(reinterpret_cast(base) + rva); +} + +template +constexpr T DataDirectoryFromModuleBase(void *moduleBase, size_t entryID) +{ + auto dosHdr = reinterpret_cast(moduleBase); + auto ntHdr = RVA2VA(moduleBase, dosHdr->e_lfanew); + auto dataDir = ntHdr->OptionalHeader.DataDirectory; + return RVA2VA(moduleBase, dataDir[entryID].VirtualAddress); +} + +PIMAGE_THUNK_DATA FindAddressByName(void *moduleBase, PIMAGE_THUNK_DATA impName, PIMAGE_THUNK_DATA impAddr, const char *funcName) +{ + for (; impName->u1.Ordinal; ++impName, ++impAddr) + { + if (IMAGE_SNAP_BY_ORDINAL(impName->u1.Ordinal)) + continue; + + auto import = RVA2VA(moduleBase, impName->u1.AddressOfData); + if (strcmp(import->Name, funcName) != 0) + continue; + return impAddr; + } + return nullptr; +} + +PIMAGE_THUNK_DATA FindAddressByOrdinal(void *moduleBase, PIMAGE_THUNK_DATA impName, PIMAGE_THUNK_DATA impAddr, uint16_t ordinal) +{ + for (; impName->u1.Ordinal; ++impName, ++impAddr) + { + if (IMAGE_SNAP_BY_ORDINAL(impName->u1.Ordinal) && IMAGE_ORDINAL(impName->u1.Ordinal) == ordinal) + return impAddr; + } + return nullptr; +} + +PIMAGE_THUNK_DATA FindIatThunkInModule(void *moduleBase, const char *dllName, const char *funcName) +{ + auto imports = DataDirectoryFromModuleBase(moduleBase, IMAGE_DIRECTORY_ENTRY_IMPORT); + for (; imports->Name; ++imports) + { + if (_stricmp(RVA2VA(moduleBase, imports->Name), dllName) != 0) + continue; + + auto origThunk = RVA2VA(moduleBase, imports->OriginalFirstThunk); + auto thunk = RVA2VA(moduleBase, imports->FirstThunk); + return FindAddressByName(moduleBase, origThunk, thunk, funcName); + } + return nullptr; +} + +PIMAGE_THUNK_DATA FindDelayLoadThunkInModule(void *moduleBase, const char *dllName, const char *funcName) +{ + auto imports = DataDirectoryFromModuleBase(moduleBase, IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT); + for (; imports->DllNameRVA; ++imports) + { + if (_stricmp(RVA2VA(moduleBase, imports->DllNameRVA), dllName) != 0) + continue; + + auto impName = RVA2VA(moduleBase, imports->ImportNameTableRVA); + auto impAddr = RVA2VA(moduleBase, imports->ImportAddressTableRVA); + return FindAddressByName(moduleBase, impName, impAddr, funcName); + } + return nullptr; +} + +PIMAGE_THUNK_DATA FindDelayLoadThunkInModule(void *moduleBase, const char *dllName, uint16_t ordinal) +{ + auto imports = DataDirectoryFromModuleBase(moduleBase, IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT); + for (; imports->DllNameRVA; ++imports) + { + if (_stricmp(RVA2VA(moduleBase, imports->DllNameRVA), dllName) != 0) + continue; + + auto impName = RVA2VA(moduleBase, imports->ImportNameTableRVA); + auto impAddr = RVA2VA(moduleBase, imports->ImportAddressTableRVA); + return FindAddressByOrdinal(moduleBase, impName, impAddr, ordinal); + } + return nullptr; +} diff --git a/CristalDiskMark/source/CrystalDiskMark/Priscilla/ImageFx.h b/CristalDiskMark/source/CrystalDiskMark/Priscilla/ImageFx.h new file mode 100644 index 0000000..19a3c1f --- /dev/null +++ b/CristalDiskMark/source/CrystalDiskMark/Priscilla/ImageFx.h @@ -0,0 +1,420 @@ +#pragma once +#include +#include + +#include "stb_image.h" +#include "stb_image_write.h" + +class CImage +{ +public: + enum + { + createAlphaChannel = 0x01 + }; + + CImage() + { + Init(); + } + + ~CImage() + { + Destroy(); + } + + operator HBITMAP() const { return m_hBitmap; } + BOOL IsNull() const { return m_hBitmap == NULL; } + + int GetWidth() const { return m_width; } + int GetHeight() const { return m_height; } + int GetPitch() const { return m_pitch; } + int GetBPP() const { return 32; } + void* GetBits() const { return m_bits; } + + BOOL Create(int w, int h, int bpp, DWORD flags = 0) + { + Destroy(); + + if (bpp != 32) return FALSE; + + BITMAPINFO bmi = {}; + bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bmi.bmiHeader.biWidth = w; + bmi.bmiHeader.biHeight = -h; + bmi.bmiHeader.biPlanes = 1; + bmi.bmiHeader.biBitCount = 32; + bmi.bmiHeader.biCompression = BI_RGB; + + void* bits = NULL; + + m_hBitmap = CreateDIBSection(NULL, &bmi, DIB_RGB_COLORS, &bits, NULL, 0); + if (!m_hBitmap) return FALSE; + + m_bits = (BYTE*)bits; + m_width = w; + m_height = h; + m_pitch = w * 4; + + m_hasAlpha = (flags & createAlphaChannel) != 0; + + memset(m_bits, 0, w * h * 4); + + return TRUE; + } + + void Destroy() + { + ReleaseDC(); + + if (m_hBitmap) + { + DeleteObject(m_hBitmap); + m_hBitmap = NULL; + } + + Init(); + } + + BOOL Load(LPCTSTR fileName) + { + Destroy(); + + HANDLE hFile = CreateFile(fileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); + if (hFile == INVALID_HANDLE_VALUE) + { + return FALSE; + } + + DWORD size = GetFileSize(hFile, NULL); + BYTE* buf = (BYTE*)malloc(size); + + DWORD read = 0; + if (ReadFile(hFile, buf, size, &read, NULL) == FALSE || read != size) + { + free(buf); + CloseHandle(hFile); + return FALSE; + } + + BOOL result = FALSE; + + if (IsPNG(buf)) + { + result = LoadPNG(buf, size); + } + else if (IsBMP(buf)) + { + result = LoadBMP(buf, size); + } + + free(buf); + return result; + } + + static void png_write_func(void* context, void* data, int size) + { + HANDLE hFile = (HANDLE)context; + DWORD written = 0; + WriteFile(hFile, data, size, &written, NULL); + } + + BOOL Save(LPCTSTR fileName) + { + if (!m_bits || !fileName) + return FALSE; + + if (IsPNGFileName(fileName)) + return SavePNG(fileName); + + if (IsBMPFileName(fileName)) + return SaveBMP(fileName); + + return FALSE; + } + + BOOL IsPNGFileName(LPCTSTR fileName) + { + LPCTSTR ext = _tcsrchr(fileName, _T('.')); + if (!ext) return FALSE; + return _tcsicmp(ext, _T(".png")) == 0; + } + + BOOL IsBMPFileName(LPCTSTR fileName) + { + LPCTSTR ext = _tcsrchr(fileName, _T('.')); + if (!ext) return FALSE; + return _tcsicmp(ext, _T(".bmp")) == 0; + } + + BOOL SavePNG(LPCTSTR fileName) + { + HANDLE hFile = CreateFile( + fileName, + GENERIC_WRITE, + 0, + NULL, + CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, + NULL); + + if (hFile == INVALID_HANDLE_VALUE) + return FALSE; + + size_t size = (size_t)m_width * m_height * 4; + BYTE* tmp = (BYTE*)malloc(size); + if (!tmp) { + CloseHandle(hFile); + return FALSE; + } + + for (int y = 0; y < m_height; y++) + { + BYTE* src = m_bits + y * m_pitch; + BYTE* dst = tmp + y * m_width * 4; + + for (int x = 0; x < m_width; x++) + { + dst[x * 4 + 0] = src[x * 4 + 2]; + dst[x * 4 + 1] = src[x * 4 + 1]; + dst[x * 4 + 2] = src[x * 4 + 0]; + dst[x * 4 + 3] = 255; + } + } + + int result = stbi_write_png_to_func( + png_write_func, + (void*)hFile, + m_width, + m_height, + 4, + tmp, + m_width * 4); + + free(tmp); + CloseHandle(hFile); + + return result != 0; + } + + BOOL SaveBMP(LPCTSTR fileName) + { + HANDLE hFile = CreateFile( + fileName, + GENERIC_WRITE, + 0, + NULL, + CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, + NULL); + + if (hFile == INVALID_HANDLE_VALUE) + return FALSE; + + int rowSize = ((m_width * 3 + 3) / 4) * 4; + int dataSize = rowSize * m_height; + + BITMAPFILEHEADER bf = {}; + bf.bfType = 0x4D42; // 'BM' + bf.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER); + bf.bfSize = bf.bfOffBits + dataSize; + + BITMAPINFOHEADER bi = {}; + bi.biSize = sizeof(BITMAPINFOHEADER); + bi.biWidth = m_width; + bi.biHeight = m_height; // bottom-up + bi.biPlanes = 1; + bi.biBitCount = 24; + bi.biCompression = BI_RGB; + + DWORD written = 0; + + WriteFile(hFile, &bf, sizeof(bf), &written, NULL); + WriteFile(hFile, &bi, sizeof(bi), &written, NULL); + + BYTE* line = (BYTE*)malloc(rowSize); + if (!line) + { + CloseHandle(hFile); + return FALSE; + } + + for (int y = m_height - 1; y >= 0; y--) + { + BYTE* src = m_bits + y * m_pitch; + BYTE* dst = line; + + memset(line, 0, rowSize); + + for (int x = 0; x < m_width; x++) + { + dst[0] = src[0]; // B + dst[1] = src[1]; // G + dst[2] = src[2]; // R + + src += 4; + dst += 3; + } + + if (!WriteFile(hFile, line, rowSize, &written, NULL) || written != (DWORD)rowSize) + { + free(line); + CloseHandle(hFile); + return FALSE; + } + } + + free(line); + CloseHandle(hFile); + return TRUE; + } + + BOOL BitBlt(HDC hDest, int x, int y, DWORD rop = SRCCOPY) const + { + return BitBlt(hDest, x, y, m_width, m_height, 0, 0, rop); + } + + BOOL BitBlt(HDC hDest, int x, int y, int w, int h, int sx, int sy, DWORD rop) const + { + HDC hSrc = GetDC(); + + BOOL r = ::BitBlt(hDest, x, y, w, h, hSrc, sx, sy, rop); + + ReleaseDC(); + return r; + } + + COLORREF GetPixel(int x, int y) const + { + BYTE* p = m_bits + y * m_pitch + x * 4; + return RGB(p[2], p[1], p[0]); + } + + HDC GetDC() const + { + if (!m_hDC) + { + m_hDC = CreateCompatibleDC(NULL); + m_hOldBitmap = (HBITMAP)SelectObject(m_hDC, m_hBitmap); + } + return m_hDC; + } + + void ReleaseDC() const + { + if (m_hDC) + { + SelectObject(m_hDC, m_hOldBitmap); + DeleteDC(m_hDC); + m_hDC = NULL; + m_hOldBitmap = NULL; + } + } + + void Attach(HBITMAP hBitmap) + { + Destroy(); + + m_hBitmap = hBitmap; + + BITMAP bm; + GetObject(hBitmap, sizeof(bm), &bm); + + m_width = bm.bmWidth; + m_height = bm.bmHeight; + m_pitch = bm.bmWidthBytes; + m_bits = (BYTE*)bm.bmBits; + + m_hasAlpha = (bm.bmBitsPixel == 32); + } + + HBITMAP Detach() + { + HBITMAP h = m_hBitmap; + Init(); + return h; + } + +private: + void Init() + { + m_hBitmap = NULL; + m_bits = NULL; + m_width = m_height = m_pitch = 0; + m_hDC = NULL; + m_hOldBitmap = NULL; + m_hasAlpha = false; + } + + BOOL IsPNG(BYTE* p) + { + static BYTE sig[8] = { 137,80,78,71,13,10,26,10 }; + return memcmp(p, sig, 8) == 0; + } + + BOOL IsBMP(BYTE* p) + { + return p[0] == 'B' && p[1] == 'M'; + } + + BOOL LoadPNG(BYTE* data, int size) + { + int w, h, c; + unsigned char* img = stbi_load_from_memory(data, size, &w, &h, &c, 4); + if (!img) return FALSE; + + Create(w, h, 32, createAlphaChannel); + + for (int i = 0; i < w * h; i++) + { + BYTE r = img[i * 4 + 0]; + BYTE g = img[i * 4 + 1]; + BYTE b = img[i * 4 + 2]; + BYTE a = img[i * 4 + 3]; + + m_bits[i * 4 + 0] = b; + m_bits[i * 4 + 1] = g; + m_bits[i * 4 + 2] = r; + m_bits[i * 4 + 3] = a; + } + + stbi_image_free(img); + return TRUE; + } + + BOOL LoadBMP(BYTE* data, int) + { + BITMAPFILEHEADER* bf = (BITMAPFILEHEADER*)data; + BITMAPINFOHEADER* bi = (BITMAPINFOHEADER*)(data + sizeof(BITMAPFILEHEADER)); + + BYTE* src = data + bf->bfOffBits; + + Create(bi->biWidth, abs(bi->biHeight), 32); + + for (int y = 0; y < m_height; y++) + { + BYTE* d = m_bits + y * m_pitch; + BYTE* s = src + (m_height - 1 - y) * ((m_width * 3 + 3) & ~3); + + for (int x = 0; x < m_width; x++) + { + d[0] = s[0]; + d[1] = s[1]; + d[2] = s[2]; + d[3] = 255; + d += 4; s += 3; + } + } + return TRUE; + } + +private: + HBITMAP m_hBitmap; + BYTE* m_bits; + int m_width, m_height, m_pitch; + + mutable HDC m_hDC; + mutable HBITMAP m_hOldBitmap; + + bool m_hasAlpha; +}; \ No newline at end of file diff --git a/CristalDiskMark/source/CrystalDiskMark/Priscilla/ImageToast.cpp b/CristalDiskMark/source/CrystalDiskMark/Priscilla/ImageToast.cpp new file mode 100644 index 0000000..1670ebf --- /dev/null +++ b/CristalDiskMark/source/CrystalDiskMark/Priscilla/ImageToast.cpp @@ -0,0 +1,269 @@ +/*---------------------------------------------------------------------------*/ +// Author : hiyohiyo +// Mail : hiyohiyo@crystalmark.info +// Web : https://crystalmark.info/ +// License : MIT License +/*---------------------------------------------------------------------------*/ + +#include "stdafx.h" +#include "ImageToast.h" + +#ifndef CMK_MIN +#define CMK_MIN(a,b) (( (a) < (b) ) ? (a) : (b)) +#endif +#ifndef CMK_MAX +#define CMK_MAX(a,b) (( (a) > (b) ) ? (a) : (b)) +#endif + +using namespace Gdiplus; + +static const UINT IDT_CLOSE = 1; +static const UINT IDT_FADE = 2; + +BEGIN_MESSAGE_MAP(CImageToast, CWnd) + ON_WM_CREATE() + ON_WM_TIMER() + ON_WM_LBUTTONDOWN() + ON_WM_RBUTTONDOWN() + ON_WM_ERASEBKGND() + ON_WM_KEYDOWN() +END_MESSAGE_MAP() + +CImageToast::CImageToast() {} +CImageToast::~CImageToast() { + if (m_hDib) { ::DeleteObject(m_hDib); m_hDib = nullptr; } +} + +int CImageToast::OnCreate(LPCREATESTRUCT lpCreateStruct) +{ + if (CWnd::OnCreate(lpCreateStruct) == -1) + return -1; + return 0; +} + +BOOL CImageToast::OnEraseBkgnd(CDC* /*pDC*/) { return TRUE; } + +void CImageToast::OnLButtonDown(UINT, CPoint) +{ + OpenUrlIfAny(); + BeginClose(FALSE); +} + +void CImageToast::OnRButtonDown(UINT, CPoint) +{ + BeginClose(FALSE); +} + +void CImageToast::OnKeyDown(UINT, UINT, UINT) +{ + BeginClose(FALSE); +} + +BOOL CImageToast::EnsureWindowCreated() +{ + if (m_hWnd && ::IsWindow(m_hWnd)) return TRUE; + + CString cls = AfxRegisterWndClass(0, ::LoadCursor(nullptr, IDC_HAND), 0, 0); + DWORD ex = WS_EX_TOPMOST | WS_EX_TOOLWINDOW | WS_EX_LAYERED; + DWORD st = WS_POPUP; + + if (!CreateEx(ex, cls, _T(""), st, CRect(0,0,0,0), nullptr, 0)) + return FALSE; + + ShowWindow(SW_SHOWNOACTIVATE); + return TRUE; +} + +static BOOL CreateARGBDIB(HDC hdc, int w, int h, HBITMAP& outBmp, void** outBits) +{ + BITMAPINFO bi{}; + bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bi.bmiHeader.biWidth = w; + bi.bmiHeader.biHeight = -h; // top-down + bi.bmiHeader.biPlanes = 1; + bi.bmiHeader.biBitCount = 32; + bi.bmiHeader.biCompression = BI_RGB; + + void* bits = nullptr; + HBITMAP hbmp = CreateDIBSection(hdc, &bi, DIB_RGB_COLORS, &bits, nullptr, 0); + if (!hbmp || !bits) return FALSE; + outBmp = hbmp; *outBits = bits; return TRUE; +} + +BOOL CImageToast::LoadPngToDIB(LPCWSTR path) +{ + Gdiplus::Bitmap bmp(path); + if (bmp.GetLastStatus() != Gdiplus::Ok) return FALSE; + + const int w = (int)bmp.GetWidth(); + const int h = (int)bmp.GetHeight(); + if (w <= 0 || h <= 0) return FALSE; + + HDC hdcScreen = ::GetDC(nullptr); + + HBITMAP hbmp = nullptr; + void* bits = nullptr; + if (!CreateARGBDIB(hdcScreen, w, h, hbmp, &bits)) { + ::ReleaseDC(nullptr, hdcScreen); + return FALSE; + } + + HDC hdcMem = ::CreateCompatibleDC(hdcScreen); + HGDIOBJ oldBmp = ::SelectObject(hdcMem, hbmp); + + { + Gdiplus::Graphics g(hdcMem); + g.SetCompositingMode(Gdiplus::CompositingModeSourceCopy); + Gdiplus::SolidBrush clearBrush(Gdiplus::Color(0, 0, 0, 0)); + g.FillRectangle(&clearBrush, 0, 0, w, h); + g.DrawImage(&bmp, 0, 0, w, h); + } + + ::SelectObject(hdcMem, oldBmp); + ::DeleteDC(hdcMem); + ::ReleaseDC(nullptr, hdcScreen); + + if (m_hDib) ::DeleteObject(m_hDib); + m_hDib = hbmp; + m_bmpSize.cx = w; m_bmpSize.cy = h; + return TRUE; +} + +void CImageToast::UpdateLayered() +{ + if (!m_hWnd || !::IsWindow(m_hWnd) || !m_hDib) return; + + HDC hdcScreen = ::GetDC(nullptr); + HDC hdcMem = ::CreateCompatibleDC(hdcScreen); + HBITMAP hOld = (HBITMAP)::SelectObject(hdcMem, m_hDib); + + POINT ptSrc{ 0,0 }; + SIZE sz{ m_bmpSize.cx, m_bmpSize.cy }; + BLENDFUNCTION bf{}; + bf.BlendOp = AC_SRC_OVER; + bf.SourceConstantAlpha = m_curAlpha; + bf.AlphaFormat = AC_SRC_ALPHA; + + POINT cursor{}; ::GetCursorPos(&cursor); + HMONITOR mon = ::MonitorFromPoint(cursor, MONITOR_DEFAULTTONEAREST); + MONITORINFO mi{ sizeof(mi) }; ::GetMonitorInfo(mon, &mi); + RECT wa = mi.rcWork; + + POINT ptDst{}; + ptDst.x = wa.right - sz.cx - m_margin; + ptDst.y = wa.bottom - sz.cy - m_margin; + + ::UpdateLayeredWindow(m_hWnd, hdcScreen, &ptDst, &sz, hdcMem, &ptSrc, 0, &bf, ULW_ALPHA); + + ::SelectObject(hdcMem, hOld); + ::DeleteDC(hdcMem); + ::ReleaseDC(nullptr, hdcScreen); +} + +void CImageToast::StartFadeTimer(BOOL fadeIn) +{ + if (!m_enableFade) return; + m_closing = !fadeIn; + SetTimer(IDT_FADE, 16, nullptr); +} + +void CImageToast::BeginClose(BOOL force) +{ + if (!m_hWnd) return; + + if (force || !m_enableFade) { + KillTimer(IDT_FADE); + KillTimer(IDT_CLOSE); + DestroyWindow(); + return; + } + if (!m_closing) { + m_closing = TRUE; + SetTimer(IDT_FADE, 16, nullptr); + } +} + +void CImageToast::OnTimer(UINT_PTR id) +{ + if (id == IDT_CLOSE) { + KillTimer(IDT_CLOSE); + BeginClose(FALSE); + return; + } + if (id == IDT_FADE) { + int stepIn = CMK_MAX(1, (int)m_maxAlpha * 16 / CMK_MAX(1, m_fadeInMs)); + int stepOut = CMK_MAX(1, (int)m_maxAlpha * 16 / CMK_MAX(1, m_fadeOutMs)); + + if (!m_closing) { + if (m_curAlpha < m_maxAlpha) { + m_curAlpha = (BYTE)CMK_MIN((int)m_maxAlpha, (int)m_curAlpha + stepIn); + UpdateLayered(); + } + else { + KillTimer(IDT_FADE); + } + } + else { + if (m_curAlpha > 0) { + m_curAlpha = (BYTE)CMK_MAX(0, (int)m_curAlpha - stepOut); + UpdateLayered(); + } + else { + KillTimer(IDT_FADE); + DestroyWindow(); + } + } + return; + } + CWnd::OnTimer(id); +} + +BOOL CImageToast::Show(LPCWSTR pngPath, UINT showMillis, BOOL enableFade, BYTE maxAlpha, + int margin, int fadeInMs, int fadeOutMs, LPCWSTR urlToOpen) +{ + m_pngPath = pngPath; + m_showMillis = showMillis; + m_enableFade = enableFade; + m_maxAlpha = maxAlpha; + m_margin = margin; + m_fadeInMs = fadeInMs; + m_fadeOutMs = fadeOutMs; + m_curAlpha = enableFade ? 0 : maxAlpha; + m_closing = FALSE; + m_opened = FALSE; + m_url = (urlToOpen ? urlToOpen : L""); + + if (!EnsureWindowCreated()) return FALSE; + if (!LoadPngToDIB(m_pngPath)) { + BeginClose(TRUE); + return FALSE; + } + + UpdateLayered(); + ShowWindow(SW_SHOWNOACTIVATE); + + SetTimer(IDT_CLOSE, m_showMillis, nullptr); + if (m_enableFade) StartFadeTimer(TRUE); + + return TRUE; +} + +void CImageToast::SetLink(LPCWSTR urlToOpen) +{ + m_url = (urlToOpen ? urlToOpen : L""); +} + +void CImageToast::CloseNow() +{ + BeginClose(FALSE); +} + +void CImageToast::OpenUrlIfAny() +{ + if (m_opened) return; + if (m_url.IsEmpty()) return; + + m_opened = TRUE; + + ::ShellExecuteW(nullptr, _T("open"), m_url, nullptr, nullptr, SW_SHOWNORMAL); +} diff --git a/CristalDiskMark/source/CrystalDiskMark/Priscilla/ImageToast.h b/CristalDiskMark/source/CrystalDiskMark/Priscilla/ImageToast.h new file mode 100644 index 0000000..a568300 --- /dev/null +++ b/CristalDiskMark/source/CrystalDiskMark/Priscilla/ImageToast.h @@ -0,0 +1,60 @@ +/*---------------------------------------------------------------------------*/ +// Author : hiyohiyo +// Mail : hiyohiyo@crystalmark.info +// Web : https://crystalmark.info/ +// License : MIT License +/*---------------------------------------------------------------------------*/ + +#pragma once +#include +#pragma comment(lib, "gdiplus.lib") +#pragma comment(lib, "Shcore.lib") + +class CImageToast : public CWnd +{ +public: + CImageToast(); + virtual ~CImageToast(); + + BOOL Show(LPCWSTR pngPath, UINT showMillis = 30000, + BOOL enableFade = TRUE, BYTE maxAlpha = 255, + int margin = 16, int fadeInMs = 200, int fadeOutMs = 250, + LPCWSTR urlToOpen = nullptr); + + void SetLink(LPCWSTR urlToOpen); + + void CloseNow(); + +protected: + afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); + afx_msg void OnTimer(UINT_PTR nIDEvent); + afx_msg void OnLButtonDown(UINT nFlags, CPoint point); + afx_msg void OnRButtonDown(UINT nFlags, CPoint point); + afx_msg BOOL OnEraseBkgnd(CDC* pDC); + afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags); + DECLARE_MESSAGE_MAP() + + BOOL EnsureWindowCreated(); + BOOL LoadPngToDIB(LPCWSTR path); + void UpdateLayered(); + void BeginClose(BOOL force = FALSE); + void StartFadeTimer(BOOL fadeIn); + + void OpenUrlIfAny(); + +private: + CString m_pngPath; + UINT m_showMillis{ 30000 }; + BOOL m_enableFade{ TRUE }; + BYTE m_maxAlpha{ 255 }; + int m_margin{ 16 }; + int m_fadeInMs{ 200 }; + int m_fadeOutMs{ 250 }; + CString m_url; + + HBITMAP m_hDib{ nullptr }; + SIZE m_bmpSize{ 0,0 }; + BYTE m_curAlpha{ 0 }; + BOOL m_closing{ FALSE }; + BOOL m_opened{ FALSE }; +}; diff --git a/CristalDiskMark/source/CrystalDiskMark/Priscilla/ListCtrlFx.cpp b/CristalDiskMark/source/CrystalDiskMark/Priscilla/ListCtrlFx.cpp new file mode 100644 index 0000000..e4f81e6 --- /dev/null +++ b/CristalDiskMark/source/CrystalDiskMark/Priscilla/ListCtrlFx.cpp @@ -0,0 +1,372 @@ +/*---------------------------------------------------------------------------*/ +// Author : hiyohiyo +// Mail : hiyohiyo@crystalmark.info +// Web : https://crystalmark.info/ +// License : MIT License +/*---------------------------------------------------------------------------*/ + +#include "stdafx.h" +#include "ListCtrlFx.h" +#include "OsInfoFx.h" + +IMPLEMENT_DYNAMIC(CListCtrlFx, CListCtrl) + +CListCtrlFx::CListCtrlFx() +{ + m_X = 0; + m_Y = 0; + m_bNT6orLater = IsNT6orLater(); + m_BkDC = NULL; + m_bHighContrast = FALSE; + m_RenderMode = SystemDraw; + m_bDarkMode = FALSE; + + // Color + m_TextColor1 = RGB(0, 0, 0); + m_TextColor2 = RGB(0, 0, 0); + m_TextSelected = RGB(0, 0, 0); + m_BkColor1 = RGB(255, 255, 255); + m_BkColor2 = RGB(248, 248, 248); + m_BkSelected = RGB(248, 248, 255); + m_LineColor1 = RGB(224, 224, 224); + m_LineColor2 = RGB(240, 240, 240); + + // Glass + m_GlassColor = RGB(255, 255, 255); + m_GlassAlpha = 128; +} + +CListCtrlFx::~CListCtrlFx() +{ +} + +#pragma warning( disable : 26454 ) +BEGIN_MESSAGE_MAP(CListCtrlFx, CListCtrl) + ON_NOTIFY_REFLECT(NM_CUSTOMDRAW, &CListCtrlFx::OnCustomdraw) +END_MESSAGE_MAP() +#pragma warning( default : 26454 ) + +BOOL CListCtrlFx::InitControl(int x, int y, int width, int height, int maxWidth, int maxHeight, double zoomRatio, CDC* bkDC, int renderMode, BOOL bHighContrast, BOOL bDarkMode) +{ + m_X = (int)(x * zoomRatio); + m_Y = (int)(y * zoomRatio); + m_CtrlSize.cx = (int)(width * zoomRatio); + m_CtrlSize.cy = (int)(height * zoomRatio); + MoveWindow(m_X, m_Y, m_CtrlSize.cx, m_CtrlSize.cy); + maxWidth = (int)(maxWidth * zoomRatio); + maxHeight = (int)(maxHeight * zoomRatio); + + m_BkDC = bkDC; + m_RenderMode = renderMode; + m_bHighContrast = bHighContrast; + m_bDarkMode = bDarkMode; + + if (m_bHighContrast) + { + SetBkImage((LPTSTR)_T("")); + } + else if (renderMode & OwnerDrawGlass || renderMode & OwnerDrawTransparent) + { + m_BkBitmap.DeleteObject(); + m_BkBitmap.CreateCompatibleBitmap(m_BkDC, maxWidth, maxHeight); + CDC BkDC; + BkDC.CreateCompatibleDC(m_BkDC); + BkDC.SelectObject(m_BkBitmap); + BkDC.BitBlt(0, 0, maxWidth, maxHeight, m_BkDC, m_X + 2, m_Y + 2, SRCCOPY); + + m_CtrlImage.Destroy(); + m_CtrlImage.Create(maxWidth, maxHeight, 32); + + RECT rect{}; + rect.top = 0; + rect.left = 0; + rect.right = maxWidth; + rect.bottom = maxHeight; + + m_CtrlBitmap.Detach(); + m_CtrlBitmap.Attach((HBITMAP)m_CtrlImage); + + DWORD length = maxWidth * maxHeight * 4; + BYTE* bitmapBits = new BYTE[length]; + m_CtrlBitmap.GetBitmapBits(length, bitmapBits); + + BYTE r, g, b, a; + if (renderMode & OwnerDrawGlass) + { + r = (BYTE)GetRValue(m_GlassColor); + g = (BYTE)GetGValue(m_GlassColor); + b = (BYTE)GetBValue(m_GlassColor); + a = m_GlassAlpha; + } + else // OwnerDrawTransparent + { + r = 0; + g = 0; + b = 0; + a = 0; + } + + for (int y = 0; y < maxHeight; y++) + { + for (int x = 0; x < maxWidth; x++) + { + DWORD p = (y * maxWidth + x) * 4; +#pragma warning( disable : 6386 ) + bitmapBits[p + 0] = b; + bitmapBits[p + 1] = g; + bitmapBits[p + 2] = r; + bitmapBits[p + 3] = a; +#pragma warning( default : 6386 ) + } + } + + m_CtrlBitmap.SetBitmapBits(length, bitmapBits); + delete[] bitmapBits; + + SetupControlImage(m_BkBitmap, m_CtrlBitmap); + if(m_bNT6orLater) + { + SetBkImage((HBITMAP)m_CtrlBitmap); + m_Header.InitControl(x, y, zoomRatio, bkDC, &m_CtrlBitmap, m_TextColor1, m_BkColor1, m_LineColor1, m_RenderMode, m_bHighContrast, m_bDarkMode); + } + else + { + SetBkColor(m_BkColor1); + m_Header.InitControl(x, y, zoomRatio, bkDC, NULL, m_TextColor1, m_BkColor1, m_LineColor1, m_RenderMode, m_bHighContrast, m_bDarkMode); + } + } + else + { + if(m_bNT6orLater) + { + SetBkImage((LPTSTR)_T("")); + SetBkColor(m_BkColor1); + m_Header.InitControl(x, y, zoomRatio, bkDC, NULL, m_TextColor1, m_BkColor1, m_LineColor1, m_RenderMode, m_bHighContrast, m_bDarkMode); + } + else + { + SetBkColor(m_BkColor1); + m_Header.InitControl(x, y, zoomRatio, bkDC, NULL, m_TextColor1, m_BkColor1, m_LineColor1, m_RenderMode, m_bHighContrast, m_bDarkMode); + } + } + + return TRUE; +} + +void CListCtrlFx::SetupControlImage(CBitmap& bkBitmap, CBitmap& ctrlBitmap) +{ + int color = m_BkDC->GetDeviceCaps(BITSPIXEL) * m_BkDC->GetDeviceCaps(PLANES); + + CBitmap* bk32Bitmap; + CImage bk32Image; + if (color == 32) + { + bk32Bitmap = &bkBitmap; + } + else + { + bk32Image.Create(m_CtrlSize.cx, m_CtrlSize.cy, 32); + ::BitBlt(bk32Image.GetDC(), 0, 0, m_CtrlSize.cx, m_CtrlSize.cy, *m_BkDC, m_X, m_Y, SRCCOPY); + bk32Bitmap = CBitmap::FromHandle((HBITMAP)bk32Image); + bk32Image.ReleaseDC(); + } + + BITMAP CtlBmpInfo, DstBmpInfo; + bk32Bitmap->GetBitmap(&DstBmpInfo); + DWORD DstLineBytes = DstBmpInfo.bmWidthBytes; + DWORD DstMemSize = DstLineBytes * DstBmpInfo.bmHeight; + ctrlBitmap.GetBitmap(&CtlBmpInfo); + DWORD CtlLineBytes = CtlBmpInfo.bmWidthBytes; + DWORD CtlMemSize = CtlLineBytes * CtlBmpInfo.bmHeight; + BYTE* DstBuffer = new BYTE[DstMemSize]; + bk32Bitmap->GetBitmapBits(DstMemSize, DstBuffer); + BYTE* CtlBuffer = new BYTE[CtlMemSize]; + ctrlBitmap.GetBitmapBits(CtlMemSize, CtlBuffer); + + int baseY = 0; + for (LONG py = 0; py < DstBmpInfo.bmHeight; py++) + { + int dn = py * DstLineBytes; + int cn = (baseY + py) * CtlLineBytes; + for (LONG px = 0; px < DstBmpInfo.bmWidth; px++) + { +#pragma warning( disable : 6385 ) +#pragma warning( disable : 6386 ) + BYTE a = CtlBuffer[cn + 3]; + BYTE na = 255 - a; + CtlBuffer[dn + 0] = (BYTE)((CtlBuffer[cn + 0] * a + DstBuffer[dn + 0] * na) / 255); + CtlBuffer[dn + 1] = (BYTE)((CtlBuffer[cn + 1] * a + DstBuffer[dn + 1] * na) / 255); + CtlBuffer[dn + 2] = (BYTE)((CtlBuffer[cn + 2] * a + DstBuffer[dn + 2] * na) / 255); + dn += (DstBmpInfo.bmBitsPixel / 8); + cn += (CtlBmpInfo.bmBitsPixel / 8); +#pragma warning( default : 6386 ) +#pragma warning( default : 6385 ) + } + } + + if (color == 32) + { + ctrlBitmap.SetBitmapBits(CtlMemSize, CtlBuffer); + } + else + { + bk32Bitmap->SetBitmapBits(CtlMemSize, CtlBuffer); + m_CtrlImage.Detach(); + m_CtrlImage.Attach(ctrlBitmap); + ::BitBlt(m_CtrlImage.GetDC(), 0, 0, m_CtrlSize.cx - 1, m_CtrlSize.cy - 1, bk32Image.GetDC(), 1, 1, SRCCOPY); + m_CtrlImage.ReleaseDC(); + bk32Image.ReleaseDC(); + } + + delete[] DstBuffer; + delete[] CtlBuffer; +} + +void CListCtrlFx::OnCustomdraw(NMHDR *pNMHDR, LRESULT *pResult) +{ + LPNMLVCUSTOMDRAW lpLVCustomDraw = reinterpret_cast(pNMHDR); + + switch(lpLVCustomDraw->nmcd.dwDrawStage) + { + case CDDS_ITEMPREPAINT: + case CDDS_ITEMPREPAINT | CDDS_SUBITEM: + if(! m_bHighContrast) + { + if(lpLVCustomDraw->nmcd.dwItemSpec % 2 == 0) + { + lpLVCustomDraw->clrText = m_TextColor1; + lpLVCustomDraw->clrTextBk = m_BkColor1; + } + else + { + lpLVCustomDraw->clrText = m_TextColor2; + lpLVCustomDraw->clrTextBk = m_BkColor2; + } + } + break; + case CDDS_ITEMPOSTPAINT | CDDS_SUBITEM: + { + RECT rc{}; + CBrush br1(m_LineColor1); + CBrush br2(m_LineColor2); + + CHeaderCtrl* header = this->GetHeaderCtrl(); + if(header != NULL) + { + int count = header->GetItemCount(); + for(int i = 0; i < count; i++) + { + ListView_GetSubItemRect(m_hWnd, lpLVCustomDraw->nmcd.dwItemSpec, i, LVIR_LABEL, &rc); + LONG left = rc.left; + rc.left = rc.right - 1; + FillRect(lpLVCustomDraw->nmcd.hdc, &rc, (HBRUSH)br1.GetSafeHandle()); + rc.left = left; + rc.top = rc.bottom - 1; + FillRect(lpLVCustomDraw->nmcd.hdc, &rc, (HBRUSH)br2.GetSafeHandle()); + } + } + } + break; + default: + break; + } + + *pResult = 0; + *pResult |= CDRF_NOTIFYPOSTPAINT; + *pResult |= CDRF_NOTIFYITEMDRAW; + *pResult |= CDRF_NOTIFYSUBITEMDRAW; +} + +void CListCtrlFx::SetTextColor1(COLORREF color){m_TextColor1 = color;} +void CListCtrlFx::SetTextColor2(COLORREF color){m_TextColor2 = color;} +void CListCtrlFx::SetTextSelected(COLORREF color){m_TextSelected = color;} +void CListCtrlFx::SetBkColor1(COLORREF color){m_BkColor1 = color;} +void CListCtrlFx::SetBkColor2(COLORREF color){m_BkColor2 = color;} +void CListCtrlFx::SetBkSelected(COLORREF color){m_BkSelected = color;} +void CListCtrlFx::SetLineColor1(COLORREF color){m_LineColor1 = color;} +void CListCtrlFx::SetLineColor2(COLORREF color){m_LineColor2 = color;} + +void CListCtrlFx::SetGlassColor(COLORREF glassColor, BYTE glassAlpha) +{ + m_GlassColor = glassColor; + m_GlassAlpha = glassAlpha; +} + +COLORREF CListCtrlFx::GetTextColor1(){return m_TextColor1;} +COLORREF CListCtrlFx::GetTextColor2(){return m_TextColor2;} +COLORREF CListCtrlFx::GetTextSelected(){return m_TextSelected;} +COLORREF CListCtrlFx::GetBkColor1(){return m_BkColor1;} +COLORREF CListCtrlFx::GetBkColor2(){return m_BkColor2;} +COLORREF CListCtrlFx::GetBkSelected(){return m_BkSelected;} +COLORREF CListCtrlFx::GetLineColor1(){return m_LineColor1;} +COLORREF CListCtrlFx::GetLineColor2(){return m_LineColor2;} + +void CListCtrlFx::SetFontEx(CString face, int size, double zoomRatio, double fontRatio, LONG fontWeight, BYTE fontRender) +{ + LOGFONT logFont = { 0 }; + logFont.lfCharSet = DEFAULT_CHARSET; + logFont.lfHeight = (LONG)(-1 * size * zoomRatio * fontRatio); + logFont.lfQuality = fontRender; + logFont.lfWeight = fontWeight; + if (face.GetLength() < 32) + { + wsprintf(logFont.lfFaceName, _T("%s"), (LPCTSTR)face); + } + else + { + wsprintf(logFont.lfFaceName, _T("")); + } + + m_Font.DeleteObject(); + m_Font.CreateFontIndirect(&logFont); + SetFont(&m_Font); + + m_Header.SetFontEx(face, size, zoomRatio, fontRatio, fontWeight, fontRender); +} + +void CListCtrlFx::PreSubclassWindow() +{ + CListCtrl::PreSubclassWindow(); + + CHeaderCtrlFx* pHeader = (CHeaderCtrlFx*)GetHeaderCtrl(); + m_Header.SubclassWindow(pHeader->GetSafeHwnd()); +} + +void CListCtrlFx::EnableHeaderOwnerDraw(BOOL bOwnerDraw) +{ + if (m_bHighContrast) + { + HDITEM hi = { 0 }; + hi.mask = HDI_FORMAT; + for (int i = 0; i < m_Header.GetItemCount(); i++) + { + m_Header.GetItem(i, &hi); + hi.fmt &= ~HDF_OWNERDRAW; + m_Header.SetItem(i, &hi); + } + return; + } + else if (m_RenderMode & OwnerDrawGlass) + { + HDITEM hi = {0}; + hi.mask = HDI_FORMAT; + if (bOwnerDraw) + { + for (int i = 0; i < m_Header.GetItemCount(); i++) + { + m_Header.GetItem(i, &hi); + hi.fmt |= HDF_OWNERDRAW; + m_Header.SetItem(i, &hi); + } + } + else + { + for (int i = 0; i < m_Header.GetItemCount(); i++) + { + m_Header.GetItem(i, &hi); + hi.fmt &= ~HDF_OWNERDRAW; + m_Header.SetItem(i, &hi); + } + } + } +} diff --git a/CristalDiskMark/source/CrystalDiskMark/Priscilla/ListCtrlFx.h b/CristalDiskMark/source/CrystalDiskMark/Priscilla/ListCtrlFx.h new file mode 100644 index 0000000..315f420 --- /dev/null +++ b/CristalDiskMark/source/CrystalDiskMark/Priscilla/ListCtrlFx.h @@ -0,0 +1,85 @@ +/*---------------------------------------------------------------------------*/ +// Author : hiyohiyo +// Mail : hiyohiyo@crystalmark.info +// Web : https://crystalmark.info/ +// License : MIT License +/*---------------------------------------------------------------------------*/ + +#pragma once + +#include "HeaderCtrlFx.h" +#include "ImageFx.h" + +class CListCtrlFx : public CListCtrl +{ + DECLARE_DYNAMIC(CListCtrlFx) + +public: + CListCtrlFx(); + virtual ~CListCtrlFx(); + + void SetTextColor1(COLORREF color); + void SetTextColor2(COLORREF color); + void SetTextSelected(COLORREF color); + void SetBkColor1(COLORREF color); + void SetBkColor2(COLORREF color); + void SetBkSelected(COLORREF color); + void SetLineColor1(COLORREF color); + void SetLineColor2(COLORREF color); + void SetGlassColor(COLORREF glassColor, BYTE glassAlpha); + + COLORREF GetTextColor1(); + COLORREF GetTextColor2(); + COLORREF GetTextSelected(); + COLORREF GetBkColor1(); + COLORREF GetBkColor2(); + COLORREF GetBkSelected(); + COLORREF GetLineColor1(); + COLORREF GetLineColor2(); + + BOOL InitControl(int x, int y, int width, int height, int maxWidth, int maxHeight, double zoomRatio, CDC* bkDC, int renderMode, BOOL bHighContrast, BOOL bDarkMode); + void SetFontEx(CString face, int size, double zoomRatio, double fontRatio, LONG fontWeight, BYTE fontRender); + void EnableHeaderOwnerDraw(BOOL bOwnerDraw); + +protected: + virtual void PreSubclassWindow(); + + void SetupControlImage(CBitmap& bkBitmap, CBitmap& ctrlBitmap); + + DECLARE_MESSAGE_MAP() + afx_msg void OnCustomdraw(NMHDR* pNMHDR, LRESULT* pResult); + + int m_X; + int m_Y; + BOOL m_bNT6orLater; + CSize m_CtrlSize; + CRect m_Margin; + int m_RenderMode; + BOOL m_bHighContrast; + BOOL m_bDarkMode; + CHeaderCtrlFx m_Header; + + COLORREF m_TextColor1; + COLORREF m_TextColor2; + COLORREF m_TextSelected; + COLORREF m_BkColor1; + COLORREF m_BkColor2; + COLORREF m_BkSelected; + COLORREF m_LineColor1; + COLORREF m_LineColor2; + + CFont m_Font; + CImageList m_Image; + CDC* m_BkDC; + + // Glass + COLORREF m_GlassColor; + BYTE m_GlassAlpha; + + // Image + CBitmap m_BkBitmap; + CBitmap m_CtrlBitmap; + CImage m_CtrlImage; +}; + + diff --git a/CristalDiskMark/source/CrystalDiskMark/Priscilla/MainDialogFx.cpp b/CristalDiskMark/source/CrystalDiskMark/Priscilla/MainDialogFx.cpp new file mode 100644 index 0000000..bbf780d --- /dev/null +++ b/CristalDiskMark/source/CrystalDiskMark/Priscilla/MainDialogFx.cpp @@ -0,0 +1,1070 @@ +/*---------------------------------------------------------------------------*/ +// Author : hiyohiyo +// Mail : hiyohiyo@crystalmark.info +// Web : https://crystalmark.info/ +// License : MIT License +/*---------------------------------------------------------------------------*/ + +#include "stdafx.h" +#include "MainDialogFx.h" +#include +#include +#include "UtilityFx.h" +#include "OsInfoFx.h" +using namespace std; + +CMainDialogFx::CMainDialogFx(UINT dlgResouce, CWnd* pParent) + :CDialogFx(dlgResouce, pParent) +{ + // Common + m_bStartup = FALSE; + m_bWindowMinimizeOnce = TRUE; + m_bResident = FALSE; + m_bResidentMinimize = FALSE; + + // Theme + m_ThemeKeyName = _T("Theme"); + + TCHAR* ptrEnd; + TCHAR ini[MAX_PATH]; + TCHAR tmp[MAX_PATH]; + CString directry; + + + GetModuleFileName(NULL, ini, MAX_PATH); + if ((ptrEnd = _tcsrchr(ini, '.')) != NULL) + { + *ptrEnd = '\0'; +#if _MSC_VER > 1310 + _tcscat_s(ini, MAX_PATH, _T(".ini")); +#else + _tcscat(ini, _T(".ini")); +#endif + m_Ini = ini; + } + +#if _MSC_VER > 1310 + CString tmpPath; + tmpPath = m_Ini; + tmpPath.Replace(_T(".ini"), _T(".tmp")); + + if (! CanWriteFile(tmpPath)) + { + TCHAR drive[_MAX_DRIVE]; + TCHAR ext[_MAX_EXT]; + TCHAR appData[MAX_PATH]; + TCHAR dir[_MAX_DIR]; + TCHAR fileName[_MAX_FNAME]; + GetModuleFileName(NULL, ini, MAX_PATH); + _tsplitpath(ini, drive, dir, fileName, ext); + SHGetSpecialFolderPath(NULL, appData, CSIDL_APPDATA, 0); + directry.Format(_T("%s\\%s"), appData, PRODUCT_FILENAME); + CreateDirectory(directry, NULL); + m_Ini.Format(_T("%s\\%s\\%s.ini"), appData, PRODUCT_FILENAME, fileName); + } +#endif + + GetModuleFileName(NULL, tmp, MAX_PATH); + if ((ptrEnd = _tcsrchr(tmp, '\\')) != NULL) { *ptrEnd = '\0'; } + m_ThemeDir.Format(_T("%s\\%s"), tmp, THEME_DIR); + m_LangDir.Format(_T("%s\\%s"), tmp, LANGUAGE_DIR); + m_VoiceDir.Format(_T("%s\\%s"), tmp, VOICE_DIR); +} + +CMainDialogFx::~CMainDialogFx() +{ +} + +BEGIN_MESSAGE_MAP(CMainDialogFx, CDialogFx) + ON_WM_WINDOWPOSCHANGING() + ON_WM_GETMINMAXINFO() +END_MESSAGE_MAP() + + +LRESULT CMainDialogFx::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) +{ +#if _MSC_VER > 1310 + LRESULT lr = 0; + if (UAHWndProc(m_hWnd, message, wParam, lParam, &lr)) { + return lr; + } +#endif + + return CDialogFx::WindowProc(message, wParam, lParam); +} + +int CALLBACK HasFontProc(ENUMLOGFONTEX* lpelfe, NEWTEXTMETRICEX* lpntme, int FontType, LPARAM lParam) +{ + *(BOOL*)lParam = TRUE; + return 0; +} + +CString CMainDialogFx::GetDefaultFont() +{ +#if _MSC_VER <= 1310 + int stockFont = DEFAULT_GUI_FONT; + if (IsNT3()) + { + return _T("MS Shell Dlg"); + } + HFONT hFont = (HFONT)GetStockObject(stockFont); + LOGFONT lf = { 0 }; + + if (GetObject(hFont, sizeof(LOGFONT), &lf)) + { + return lf.lfFaceName; + } +#endif + + CClientDC dc(this); + LOGFONT logfont; + BOOL hasFont = FALSE; + ZeroMemory(&logfont, sizeof(LOGFONT)); + lstrcpy(logfont.lfFaceName, DEFAULT_FONT_FACE_1); + logfont.lfCharSet = DEFAULT_CHARSET; + ::EnumFontFamiliesEx(dc.m_hDC, &logfont, (FONTENUMPROC)HasFontProc, (LPARAM)(&hasFont), 0); + + if (hasFont) + { + return DEFAULT_FONT_FACE_1; + } + else + { + return DEFAULT_FONT_FACE_2; + } +} + +CString CMainDialogFx::GetCurrentLangPath() +{ + return m_CurrentLangPath; +} + +CString CMainDialogFx::GetDefaultLangPath() +{ + return m_DefaultLangPath; +} + +CString CMainDialogFx::GetThemeDir() +{ + return m_ThemeDir; +} + +CString CMainDialogFx::GetCurrentTheme() +{ + return m_CurrentTheme; +} + +CString CMainDialogFx::GetDefaultTheme() +{ + return m_DefaultTheme; +} + +CString CMainDialogFx::GetParentTheme1() +{ + return m_ParentTheme1; +} + +CString CMainDialogFx::GetParentTheme2() +{ + return m_ParentTheme2; +} + +CString CMainDialogFx::GetIniPath() +{ + return m_Ini; +} + +void CMainDialogFx::SetWindowTitle(CString message) +{ + CString title; + + if(! message.IsEmpty()) + { + title.Format(_T(" %s - %s"), PRODUCT_SHORT_NAME, (LPCTSTR)message); + } + else + { + title.Format(_T(" %s %s %s"), PRODUCT_NAME, PRODUCT_VERSION, PRODUCT_EDITION); + } + + SetWindowText(title); +} + +void CMainDialogFx::InitThemeLang() +{ + TCHAR str[256]; + TCHAR *ptrEnd; + + WIN32_FIND_DATA findData; + HANDLE hFind; + CString langPath; + int i = 0; + WORD PrimaryLangID; + CString PrimaryLang; + +// Set Theme + if(m_CurrentTheme.IsEmpty()) + { + CString defaultTheme = m_DefaultTheme; +#if _MSC_VER > 1310 + if (IsFileExist(m_ThemeDir + m_RecommendTheme + _T("\\") + m_BackgroundName + _T("-300.png"))) + { + defaultTheme = m_RecommendTheme; + } +#else + if (IsFileExist(m_ThemeDir + m_RecommendTheme + _T("\\") + m_BackgroundName + _T("-100.png"))) + { + defaultTheme = m_RecommendTheme; + } +#endif + + GetPrivateProfileStringFx(_T("Setting"), m_ThemeKeyName, defaultTheme, str, 256, m_Ini); + m_CurrentTheme = str; + } + +// Set Language + GetPrivateProfileStringFx(_T("Setting"), _T("Language"), _T(""), str, 256, m_Ini); + + langPath.Format(_T("%s\\%s.lang"), (LPCTSTR)m_LangDir, str); +#ifdef UNICODE + m_DefaultLangPath.Format(_T("%s\\%s.lang"), (LPCTSTR)m_LangDir, DEFAULT_LANGUAGE); +#else + m_DefaultLangPath.Format(_T("%s\\%s9x.lang"), (LPCTSTR)m_LangDir, DEFAULT_LANGUAGE); +#endif + if(_tcscmp(str, _T("")) != 0 && IsFileExist((LPCTSTR)langPath)) + { + m_CurrentLang = str; + m_CurrentLang.Replace(_T("9x"), _T("")); +#ifdef UNICODE + m_CurrentLangPath.Format(_T("%s\\%s.lang"), (LPCTSTR)m_LangDir, (LPCTSTR)m_CurrentLang); +#else + m_CurrentLangPath.Format(_T("%s\\%s9x.lang"), (LPCTSTR)m_LangDir, (LPCTSTR)m_CurrentLang); +#endif + } + else + { + CString currentLocalID; + currentLocalID.Format(_T("0x%04X"), GetUserDefaultLCID()); + PrimaryLangID = PRIMARYLANGID(GetUserDefaultLCID()); + + + langPath.Format(_T("%s\\*.lang"), (LPCTSTR)m_LangDir); + + hFind = ::FindFirstFile(langPath, &findData); + if(hFind != INVALID_HANDLE_VALUE) + { + do{ + if(findData.dwFileAttributes != FILE_ATTRIBUTE_DIRECTORY) + { + + CString cstr; + cstr = findData.cFileName; + +#ifdef UNICODE + if (cstr.Find(_T("9x.lang")) >= 0) + { + continue; + } +#else + if (cstr.Find(_T("9x.lang")) == -1) + { + continue; + } +#endif + i++; + + cstr.Format(_T("%s\\%s"), (LPCTSTR)m_LangDir, findData.cFileName); + GetPrivateProfileStringFx(_T("Language"), _T("LOCALE_ID"), _T(""), str, 256, cstr); + if((ptrEnd = _tcsrchr(findData.cFileName, '.')) != NULL){*ptrEnd = '\0';} + + if(_tcsstr(str, currentLocalID) != NULL) + { + m_CurrentLang = findData.cFileName; + m_CurrentLang.Replace(_T("9x"), _T("")); +#ifdef UNICODE + m_CurrentLangPath.Format(_T("%s\\%s.lang"), (LPCTSTR)m_LangDir, findData.cFileName); +#else + m_CurrentLangPath.Format(_T("%s\\%s9x.lang"), (LPCTSTR)m_LangDir, findData.cFileName); +#endif + } + if(PrimaryLangID == PRIMARYLANGID(_tcstol(str, NULL, 16))) + { + PrimaryLang = findData.cFileName; + PrimaryLang.Replace(_T("9x"), _T("")); + } + } + }while(::FindNextFile(hFind, &findData) && i <= 0xFF); + } + FindClose(hFind); + + if(m_CurrentLang.IsEmpty()) + { + if(PrimaryLang.IsEmpty()) + { + m_CurrentLang = DEFAULT_LANGUAGE; +#ifdef UNICODE + m_CurrentLangPath.Format(_T("%s\\%s.lang"), (LPCTSTR)m_LangDir, (LPCTSTR)m_CurrentLang); +#else + m_CurrentLangPath.Format(_T("%s\\%s9x.lang"), (LPCTSTR)m_LangDir, (LPCTSTR)m_CurrentLang); +#endif + } + else + { + m_CurrentLang = PrimaryLang; +#ifdef UNICODE + m_CurrentLangPath.Format(_T("%s\\%s.lang"), (LPCTSTR)m_LangDir, (LPCTSTR)PrimaryLang); +#else + m_CurrentLangPath.Format(_T("%s\\%s9x.lang"), (LPCTSTR)m_LangDir, (LPCTSTR)PrimaryLang); +#endif + } + } + } + + UpdateThemeInfo(); +} + +void CMainDialogFx::InitMenu() +{ + CMenu menu; + CMenu subMenu; + BOOL FlagHitTheme = FALSE; + BOOL FlagHitLang = FALSE; + UINT newItemID = 0; + UINT currentItemID = 0; + UINT defaultStyleItemID = 0; + WIN32_FIND_DATA findData; + + HANDLE hFind; + CString themePath; + CString themeCssPath; + CString langPath; + int i = 0; + TCHAR *ptrEnd = NULL; + TCHAR str[256]; + + srand((unsigned int)std::time(NULL)); + + menu.Attach(GetMenu()->GetSafeHmenu()); + subMenu.Attach(menu.GetSubMenu(MENU_THEME_INDEX)->GetSafeHmenu()); + + themePath.Format(_T("%s\\*.*"), (LPCTSTR)m_ThemeDir); + + // Add Random as first choice. + subMenu.AppendMenu(MF_STRING, (UINT_PTR)WM_THEME_ID + i, m_RandomThemeLabel + m_RandomThemeName); + i++; + m_MenuArrayTheme.Add(m_RandomThemeLabel); + + hFind = ::FindFirstFile(themePath, &findData); + if(hFind != INVALID_HANDLE_VALUE) + { + while(::FindNextFile(hFind, &findData) && i <= 0xFF) + { + if(findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + { + CString name = findData.cFileName; + if(CheckThemeEdition(name)) + { + // Add Theme + newItemID = WM_THEME_ID + i; + i++; + subMenu.AppendMenu(MF_STRING, (UINT_PTR)newItemID, findData.cFileName); + m_MenuArrayTheme.Add(findData.cFileName); + if(m_CurrentTheme.Compare(findData.cFileName) == 0) + { + currentItemID = newItemID; + FlagHitTheme = TRUE; + } + + if(_tcsstr(findData.cFileName, m_DefaultTheme) != NULL) + { + defaultStyleItemID = newItemID; + } + } + } + } + } + FindClose(hFind); + + if(m_CurrentTheme.Compare(m_RandomThemeLabel) == 0) + { + m_CurrentTheme = GetRandomTheme(); + m_RandomThemeName = _T(" (") + m_CurrentTheme + _T(")"); + // Keep currentItemID the same as the first item if "Random". + currentItemID = WM_THEME_ID; + + SUBMENU_MODIFY_MENU(WM_THEME_ID, MF_STRING, WM_THEME_ID, m_RandomThemeLabel + m_RandomThemeName); + } + else if(! FlagHitTheme) + { + currentItemID = defaultStyleItemID; + m_CurrentTheme = m_DefaultTheme; + } + + CMenu subMenuAN; + CMenu subMenuOZ; + subMenu.CheckMenuRadioItem(WM_THEME_ID, WM_THEME_ID + (UINT)m_MenuArrayTheme.GetSize(), + currentItemID, MF_BYCOMMAND); + subMenu.Detach(); + subMenu.Attach(menu.GetSubMenu(MENU_LANG_INDEX)->GetSafeHmenu()); + subMenuAN.Attach(subMenu.GetSubMenu(0)->GetSafeHmenu()); // 1st is "A~N" + subMenuAN.RemoveMenu(0, MF_BYPOSITION); + subMenuOZ.Attach(subMenu.GetSubMenu(1)->GetSafeHmenu()); // 2nd is "O~Z" + subMenuOZ.RemoveMenu(0, MF_BYPOSITION); + langPath.Format(_T("%s\\*.lang"), (LPCTSTR)m_LangDir); + i = 0; + hFind = ::FindFirstFile(langPath, &findData); + if(hFind != INVALID_HANDLE_VALUE) + { + do{ + if(findData.dwFileAttributes != FILE_ATTRIBUTE_DIRECTORY) + { + // Add Language + CString cstr; + cstr = findData.cFileName; +#ifdef UNICODE + if (cstr.Find(_T("9x.lang")) >= 0) + { + continue; + } +#else + if (cstr.Find(_T("9x.lang")) == -1) + { + continue; + } +#endif + newItemID = WM_LANGUAGE_ID + i; + i++; + + cstr.Format(_T("%s\\%s"), (LPCTSTR)m_LangDir, findData.cFileName); + GetPrivateProfileStringFx(_T("Language"), _T("LANGUAGE"), _T(""), str, 256, cstr); + if((ptrEnd = _tcsrchr(findData.cFileName, L'.')) != NULL) + { + *ptrEnd = '\0'; + } + + cstr.Format(_T("%s, [%s]"), str, findData.cFileName); + if(L'A' <= findData.cFileName[0] && findData.cFileName[0] <= L'N') + { + subMenuAN.AppendMenu(MF_STRING, (UINT_PTR)newItemID, cstr); + } + else + { + subMenuOZ.AppendMenu(MF_STRING, (UINT_PTR)newItemID, cstr); + } + m_MenuArrayLang.Add(findData.cFileName); + + cstr = findData.cFileName; +#ifndef UNICODE + cstr.Replace(_T("9x"), _T("")); +#endif + if(m_CurrentLang.Compare(cstr) == 0) + { + currentItemID = newItemID; + FlagHitLang = TRUE; + } + } + }while(::FindNextFile(hFind, &findData) && i <= 0xFF); + } + FindClose(hFind); + + subMenuAN.CheckMenuRadioItem(WM_LANGUAGE_ID, WM_LANGUAGE_ID + (UINT)m_MenuArrayLang.GetSize(), + currentItemID, MF_BYCOMMAND); + subMenuOZ.CheckMenuRadioItem(WM_LANGUAGE_ID, WM_LANGUAGE_ID + (UINT)m_MenuArrayLang.GetSize(), + currentItemID, MF_BYCOMMAND); + + subMenuOZ.Detach(); + subMenuAN.Detach(); + subMenu.Detach(); + menu.Detach(); + + if(! FlagHitLang) + { + AfxMessageBox(_T("FATAL ERROR: Missing Language File!!")); + } +} + +BOOL CMainDialogFx::CheckThemeEdition(CString name) +{ + if (name.Find(_T(".")) != 0) { return TRUE; } + + return FALSE; +} + +BOOL CMainDialogFx::OnInitDialog() +{ + return CDialogFx::OnInitDialog(); +} + +void CMainDialogFx::ChangeTheme(CString themeName) +{ + WritePrivateProfileStringFx(_T("Setting"), m_ThemeKeyName, themeName, m_Ini); +} + +BOOL CMainDialogFx::OnCommand(WPARAM wParam, LPARAM lParam) +{ + // Select Theme + if(WM_THEME_ID <= wParam && wParam < WM_THEME_ID + (WPARAM)m_MenuArrayTheme.GetSize()) + { + CMenu menu; + CMenu subMenu; + menu.Attach(GetMenu()->GetSafeHmenu()); + subMenu.Attach(menu.GetSubMenu(MENU_THEME_INDEX)->GetSafeHmenu()); + + m_CurrentTheme = m_MenuArrayTheme.GetAt(wParam - WM_THEME_ID); + if (m_CurrentTheme.Compare(m_RandomThemeLabel) == 0) + { + m_CurrentTheme = GetRandomTheme(); + m_RandomThemeLabel = _T("Random"); + m_RandomThemeName = _T(" (") + m_CurrentTheme + _T(")"); + + // ChangeTheme save the theme configuration to profile; so if we are on + // Random, then save Random to profile. + ChangeTheme(m_RandomThemeLabel); + } + else + { + ChangeTheme(m_MenuArrayTheme.GetAt(wParam - WM_THEME_ID)); + m_RandomThemeName = _T(""); + } + + SUBMENU_MODIFY_MENU(WM_THEME_ID, MF_STRING, WM_THEME_ID, m_RandomThemeLabel + m_RandomThemeName); + subMenu.CheckMenuRadioItem(WM_THEME_ID, WM_THEME_ID + (UINT)m_MenuArrayTheme.GetSize(), + (UINT)wParam, MF_BYCOMMAND); + subMenu.Detach(); + menu.Detach(); + + UpdateThemeInfo(); + UpdateDialogSize(); + } + + return CDialogFx::OnCommand(wParam, lParam); +} + +void CMainDialogFx::OnWindowPosChanging(WINDOWPOS * lpwndpos) +{ + if(! m_bShowWindow) + { + lpwndpos->flags &= ~SWP_SHOWWINDOW; + } + + if(m_bWindowMinimizeOnce && ! m_bInitializing) + { + m_bWindowMinimizeOnce = FALSE; + if(m_bResident && m_bResidentMinimize) + { + ShowWindow(SW_MINIMIZE); + } + } + + CDialogFx::OnWindowPosChanging(lpwndpos); +} + +void CMainDialogFx::OnGetMinMaxInfo(MINMAXINFO* lpMMI) +{ + lpMMI->ptMinTrackSize.x = m_MinSizeX; + lpMMI->ptMinTrackSize.y = m_MinSizeY; + + lpMMI->ptMaxTrackSize.x = m_MaxSizeX; + lpMMI->ptMaxTrackSize.y = m_MaxSizeY; + + CDialogFx::OnGetMinMaxInfo(lpMMI); +} + +void CMainDialogFx::SaveWindowPosition() +{ + WINDOWPLACEMENT place = { sizeof(WINDOWPLACEMENT) }; + GetWindowPlacement(&place); + + CString x, y; + x.Format(_T("%d"), place.rcNormalPosition.left); + y.Format(_T("%d"), place.rcNormalPosition.top); + WritePrivateProfileStringFx(_T("Setting"), _T("X"), x, m_Ini); + WritePrivateProfileStringFx(_T("Setting"), _T("Y"), y, m_Ini); +} + +void CMainDialogFx::RestoreWindowPosition() +{ + const int x = GetPrivateProfileInt(_T("Setting"), _T("X"), INT_MIN, m_Ini); + const int y = GetPrivateProfileInt(_T("Setting"), _T("Y"), INT_MIN, m_Ini); + + RECT rw, rc; + GetWindowRect(&rw); + + rc.left = x; + rc.top = y; + rc.right = x + rw.right - rw.left; + rc.bottom = y + rw.bottom - rw.top; + +#if _MSC_VER > 1310 + HMONITOR hMonitor = MonitorFromRect(&rc, MONITOR_DEFAULTTONULL); + if (hMonitor == NULL) + { + CenterWindow(); + } + else + { + // Get Taskbar Size + APPBARDATA taskbarInfo = { 0 }; + taskbarInfo.cbSize = sizeof(APPBARDATA); + taskbarInfo.hWnd = m_hWnd; + SHAppBarMessage(ABM_GETTASKBARPOS, &taskbarInfo); + CRect taskbarRect = taskbarInfo.rc; + + if (taskbarInfo.rc.top <= 0 && taskbarInfo.rc.left <= 0) // Top Side or Left Side + { + if (taskbarRect.Height() > taskbarRect.Width()) // Left Side + { + if (x < taskbarRect.Width()) // Overlap + { + SetWindowPos(NULL, taskbarRect.Width(), y, 0, 0, SWP_NOSIZE | SWP_NOZORDER); + } + else + { + SetWindowPos(NULL, x, y, 0, 0, SWP_NOSIZE | SWP_NOZORDER); + } + } + else // Top Side + { + if (y < taskbarRect.Height()) // Overlap + { + SetWindowPos(NULL, x, taskbarRect.Height(), 0, 0, SWP_NOSIZE | SWP_NOZORDER); + } + else + { + SetWindowPos(NULL, x, y, 0, 0, SWP_NOSIZE | SWP_NOZORDER); + } + } + } + else + { + SetWindowPos(NULL, x, y, 0, 0, SWP_NOSIZE | SWP_NOZORDER); + } + } +#else + CenterWindow(); +#endif +} + +DWORD CMainDialogFx::GetZoomType() +{ + return GetPrivateProfileInt(_T("Setting"), _T("ZoomType"), ZoomTypeAuto, m_Ini); +} + +void CMainDialogFx::SetZoomType(DWORD zoomType) +{ + CString cstr; + cstr.Format(_T("%d"), m_ZoomType); + WritePrivateProfileStringFx(_T("Setting"), _T("ZoomType"), cstr, m_Ini); +} + +void CMainDialogFx::UpdateThemeInfo() +{ + CString theme = m_ThemeDir + m_CurrentTheme + _T("\\theme.ini"); + + m_LabelText = GetControlColor(_T("LabelText"), 0, theme); + m_MeterText = GetControlColor(_T("MeterText"), 0, theme); + m_ComboText = GetControlColor(_T("ComboText"), 0, theme); + m_ComboTextSelected = GetControlColor(_T("ComboTextSelected"), 0, theme); + m_ComboBk = GetControlColor(_T("ComboBk"), 255, theme); + m_ComboBkSelected = GetControlColor(_T("ComboBkSelected"), 192, theme); + m_ButtonText= GetControlColor(_T("ButtonText"), 0, theme); + m_EditText = GetControlColor(_T("EditText"), 0, theme); + m_EditBk = GetControlColor(_T("EditBk"), 255, theme); + m_ListText1 = GetControlColor(_T("ListText1"), 0, theme); + m_ListText2 = GetControlColor(_T("ListText2"), 0, theme); + m_ListTextSelected = GetControlColor(_T("ListTextSelected"), 0, theme); + m_ListBk1 = GetControlColor(_T("ListBk1"), 255, theme); + m_ListBk2 = GetControlColor(_T("ListBk2"), 255, theme); + m_ListBkSelected = GetControlColor(_T("ListBkSelected"), 0, theme); + m_ListLine1 = GetControlColor(_T("ListLine1"), 0, theme); + m_ListLine2 = GetControlColor(_T("ListLine2"), 0, theme); + m_Glass = GetControlColor(_T("Glass"), 255, theme); + m_Frame = GetControlColor(_T("Frame"), 128, theme); + m_Background = GetBackgroundColor(_T("Background"), theme); + + m_ComboAlpha = GetControlAlpha(_T("ComboAlpha"), 255, theme); + m_EditAlpha = GetControlAlpha(_T("EditAlpha"), 255, theme); + m_GlassAlpha = GetControlAlpha(_T("GlassAlpha"), 128, theme); + + m_CharacterPosition = GetCharacterPosition(theme); + + m_ParentTheme1 = GetParentTheme(1, theme); + m_ParentTheme2 = GetParentTheme(2, theme); +} + +COLORREF CMainDialogFx::GetControlColor(CString name, BYTE defaultColor, CString theme) +{ + COLORREF reverseColor; + + reverseColor = GetPrivateProfileInt(_T("Color"), name, RGB(defaultColor, defaultColor, defaultColor), theme); + + COLORREF color = RGB(GetBValue(reverseColor), GetGValue(reverseColor), GetRValue(reverseColor)); + + return color; +} + +COLORREF CMainDialogFx::GetBackgroundColor(CString name, CString theme) +{ + COLORREF reverseColor; + + reverseColor = GetPrivateProfileInt(_T("Color"), name, 0xFFFFFFFF, theme); + + if (reverseColor == 0xFFFFFFFF) + { + return 0xFFFFFFFF; // 0xFFFFFFF = Disabled + } + else + { + COLORREF color = RGB(GetBValue(reverseColor), GetGValue(reverseColor), GetRValue(reverseColor)); + return color; + } +} + +BYTE CMainDialogFx::GetControlAlpha(CString name, BYTE defaultAlpha, CString theme) +{ + BYTE alpha = (BYTE)GetPrivateProfileInt(_T("Alpha"), name, defaultAlpha, theme); + + return alpha; +} + +BYTE CMainDialogFx::GetCharacterPosition(CString theme) +{ + BYTE position = (BYTE)GetPrivateProfileInt(_T("Character"), _T("Position"), 0, theme); + + return position; +} + +CString CMainDialogFx::GetParentTheme(int i, CString theme) +{ + CString cstr; + cstr.Format(_T("ParentTheme%d"), i); + TCHAR str[256]; + GetPrivateProfileStringFx(_T("Info"), cstr, _T(""), str, 256, theme); + cstr = str; + + return cstr; +} + +CString CMainDialogFx::GetRandomTheme() { + // We need to add/subtract one to exclude first item ("Random"). + UINT i = 1 + rand() % ((UINT)m_MenuArrayTheme.GetSize() - 1); + return m_MenuArrayTheme.GetAt(i); +} + +void CMainDialogFx::SaveImage() +{ +#if _MSC_VER > 1310 + BOOL bDwmEnabled = FALSE; + + HMODULE hModule = LoadLibraryEx(_T("dwmapi.dll"), NULL, LOAD_LIBRARY_SEARCH_SYSTEM32); + typedef HRESULT(WINAPI* FuncDwmGetWindowAttribute) (HWND hwnd, DWORD dwAttribute, PVOID pvAttribute, DWORD cbAttribute); + typedef HRESULT(WINAPI* FuncDwmIsCompositionEnabled)(BOOL* pfEnabled); + FuncDwmGetWindowAttribute pDwmGetWindowAttribute = NULL; + FuncDwmIsCompositionEnabled pDwmIsCompositionEnabled = NULL; + if (hModule) + { + pDwmGetWindowAttribute = (FuncDwmGetWindowAttribute)GetProcAddress(hModule, "DwmGetWindowAttribute"); + pDwmIsCompositionEnabled = (FuncDwmIsCompositionEnabled)GetProcAddress(hModule, "DwmIsCompositionEnabled"); + } + + if (pDwmGetWindowAttribute && pDwmIsCompositionEnabled) + { + pDwmIsCompositionEnabled(&bDwmEnabled); + } + + CRect rc1; + CRect rc2; + CRect rc3; + + CImage* image1 = new CImage(); + CImage* image2 = new CImage(); + CImage* image3 = new CImage(); + + if (bDwmEnabled) + { + GetWindowRect(&rc1); + if (image1->Create(rc1.Width(), rc1.Height(), 32)) + { + HDC hImage1DC = image1->GetDC(); + if (IsWin81orLater()) + { + ::PrintWindow(m_hWnd, hImage1DC, 2); // PW_RENDERFULLCONTENT, Windows 8.1 or later + + GetClientRect(&rc3); + if (image3->Create(rc3.Width(), rc3.Height(), 32)) + { + HDC hImage3DC = image3->GetDC(); + ::PrintWindow(m_hWnd, hImage3DC, 1); // PW_CLIENTONLY + int targetY = 0; + int offsetX = (rc1.Width() - rc3.Width()) / 2; + int offsetY = (rc1.Height() - rc3.Height()) / 2; + + // Compare Screenshot + for (int y = offsetY; y < rc1.Height() - rc3.Height(); y++) + { + for (int x = 0; x < rc3.Width(); x++) + { + if (image1->GetPixel(offsetX + x, y) == image3->GetPixel(x, 0)) + { + if (x == rc3.Width() / 2) + { + for (int yy = 0; yy < rc3.Height(); yy++) + { + if (image1->GetPixel(offsetX, y + yy) == image3->GetPixel(0, yy)) + { + if (yy == rc3.Height() / 2) + { + targetY = y; + goto loopEnd; + } + } + else + { + break; + } + } + } + } + else + { + break; + } + } + } + + loopEnd: + if (targetY > 0) + { + ::BitBlt(hImage1DC, (rc1.Width() - rc3.Width()) / 2, targetY, rc3.Width(), rc3.Height(), hImage3DC, 0, 0, SRCCOPY); + } + image3->ReleaseDC(); + } + } + else + { + ::PrintWindow(m_hWnd, hImage1DC, 0); + } + + pDwmGetWindowAttribute(m_hWnd, DWMWA_EXTENDED_FRAME_BOUNDS, &rc2, sizeof(rc2)); + // cstr.Format(_T("Width=%d/%d, Height=%d/%d"), rc1.Width(), rc2.Width(), rc1.Height(), rc2.Height()); + // AfxMessageBox(cstr); + if (rc1.Width() > rc2.Width()) + { + if (image2->Create(rc2.Width(), rc2.Height(), 32)) + { + HDC hImage2DC = image2->GetDC(); + ::BitBlt(hImage2DC, 0, 0, rc2.Width(), rc2.Height(), hImage1DC, (rc1.Width() - rc2.Width()) / 2, 0, SRCCOPY); + image2->ReleaseDC(); + SaveImageDlg(image2); + } + else + { + SaveImageDlg(image1); + } + } + else + { + SaveImageDlg(image1); + } + image1->ReleaseDC(); + } + } + else + { + GetWindowRect(&rc1); + if (image1->Create(rc1.Width(), rc1.Height(), 32)) + { + HDC hImage1DC = image1->GetDC(); + ::PrintWindow(m_hWnd, hImage1DC, 0); + SaveImageDlg(image1); + image1->ReleaseDC(); + } + } + SAFE_DELETE(image1); + SAFE_DELETE(image2); + SAFE_DELETE(image3); +#endif +} + +void CMainDialogFx::SaveImageDlg(CImage* image) +{ + CString path; + SYSTEMTIME st; + GetLocalTime(&st); + path.Format(_T("%s_%04d%02d%02d%02d%02d%02d"), PRODUCT_FILENAME, st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond); + + CString filter = _T("PNG (*.png)|*.png|BMP (*.bmp)|*.bmp||"); + CFileDialog save(FALSE, _T(""), path, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT | OFN_EXPLORER, filter); + + if (save.DoModal() == IDOK) + { + image->Save(save.GetPathName().GetString()); + } +} + +///////////////////////////////////////////////////////////////////////////////////////////////// +// +// Task Tray +// +///////////////////////////////////////////////////////////////////////////////////////////////// + +#ifdef OPTION_TASK_TRAY + +UINT CMainDialogFx::wmTaskbarCreated = ::RegisterWindowMessage(_T("TaskbarCreated")); + +// Add TaskTray +BOOL CMainDialogFx::AddTaskTray(UINT id, UINT callback, HICON icon, CString tip) +{ + if(m_bResident) + { + NOTIFYICONDATA nidata = {0}; + nidata.cbSize = sizeof(NOTIFYICONDATA); + nidata.hWnd = m_hWnd; + nidata.uID = id; + nidata.uFlags = NIF_TIP | NIF_ICON | NIF_MESSAGE; + nidata.hIcon = icon; + nidata.uVersion = NOTIFYICON_VERSION; + nidata.uCallbackMessage = callback; + _tcscpy_s(nidata.szTip, 128, tip.Left(127)); + + ::Shell_NotifyIcon(NIM_SETVERSION, &nidata); + int waitCount = 10; + if(m_bStartup) + { + waitCount = 20; + } + for(int i = 0; i < waitCount; i++) + { + if(::Shell_NotifyIcon(NIM_ADD, &nidata)) + { + return TRUE; + } + Sleep(100 * i); + } + } + return FALSE; +} + +// Update TaskTray Icon +BOOL CMainDialogFx::ModifyTaskTrayIcon(UINT id, HICON icon) +{ + if(m_bResident) + { + NOTIFYICONDATA nidata = { 0 }; + nidata.cbSize = sizeof(NOTIFYICONDATA); + nidata.hWnd = m_hWnd; + nidata.uID = id; + nidata.uFlags = NIF_ICON; + nidata.hIcon = icon; + for(int i = 0; i < 3; i++) + { + if(::Shell_NotifyIcon(NIM_MODIFY, &nidata)) + { + return TRUE; + } + Sleep(100 * i); + } + } + return FALSE; +} + +// Update TaskTray Tips +BOOL CMainDialogFx::ModifyTaskTrayTip(UINT id, CString tip) +{ + if(m_bResident) + { + NOTIFYICONDATA nidata = { 0 }; + nidata.cbSize = sizeof(NOTIFYICONDATA); + nidata.hWnd = m_hWnd; + nidata.uID = id; + nidata.uFlags = NIF_TIP; + + _tcscpy_s(nidata.szTip, 128, tip.Left(127)); + + for(int i = 0; i < 3; i++) + { + if(::Shell_NotifyIcon(NIM_MODIFY, &nidata)) + { + return TRUE; + } + Sleep(100 * i); + } + } + return FALSE; +} + +// Update TaskTray +BOOL CMainDialogFx::ModifyTaskTray(UINT id, HICON icon, CString tip) +{ + if(m_bResident) + { + NOTIFYICONDATA nidata = { 0 }; + nidata.cbSize = sizeof(NOTIFYICONDATA); + nidata.hWnd = m_hWnd; + nidata.uID = id; + nidata.uFlags = NIF_TIP|NIF_ICON; + nidata.hIcon = icon; + _tcscpy_s(nidata.szTip, 128, tip.Left(127)); + + for(int i = 0; i < 3; i++) + { + if(::Shell_NotifyIcon(NIM_MODIFY, &nidata)) + { + return TRUE; + } + Sleep(100 * i); + } + } + return FALSE; +} + +// Show Balloon +BOOL CMainDialogFx::ShowBalloon(UINT id, DWORD infoFlag, CString infoTitle, CString info) +{ + if(m_bResident) + { + NOTIFYICONDATA nidata = { 0 }; + nidata.cbSize = sizeof(NOTIFYICONDATA); + nidata.hWnd = m_hWnd; + nidata.uID = id; + nidata.uFlags = NIF_INFO; + nidata.dwInfoFlags = infoFlag; + + _tcscpy_s(nidata.szInfo, 256, info.Left(255)); + _tcscpy_s(nidata.szInfoTitle, 64, infoTitle.Left(63)); + + for(int i = 0; i < 3; i++) + { + if(::Shell_NotifyIcon(NIM_MODIFY, &nidata)) + { + return TRUE; + } + Sleep(100 * i); + } + } + return FALSE; +} + +// Remove TaskTray +BOOL CMainDialogFx::RemoveTaskTray(UINT id) +{ + if(m_bResident) + { + NOTIFYICONDATA nidata = { 0 }; + nidata.cbSize = sizeof(NOTIFYICONDATA); + nidata.hWnd = m_hWnd; + nidata.uID = id; + + for(int i = 0; i < 3; i++) + { + if(::Shell_NotifyIcon(NIM_DELETE, &nidata)) + { + return TRUE; + } + Sleep(100 * i); + } + } + return FALSE; +} + +#endif \ No newline at end of file diff --git a/CristalDiskMark/source/CrystalDiskMark/Priscilla/MainDialogFx.h b/CristalDiskMark/source/CrystalDiskMark/Priscilla/MainDialogFx.h new file mode 100644 index 0000000..012f8a3 --- /dev/null +++ b/CristalDiskMark/source/CrystalDiskMark/Priscilla/MainDialogFx.h @@ -0,0 +1,85 @@ +/*---------------------------------------------------------------------------*/ +// Author : hiyohiyo +// Mail : hiyohiyo@crystalmark.info +// Web : https://crystalmark.info/ +// License : MIT License +/*---------------------------------------------------------------------------*/ + +#pragma once +#include "DialogFx.h" + +class CMainDialogFx : public CDialogFx +{ +public: + CMainDialogFx(UINT dlgResouce, CWnd* pParent = NULL); + virtual ~CMainDialogFx(); + + // Zoom + DWORD GetZoomType(); + void SetZoomType(DWORD zoomType); + + // Getter + CString GetCurrentLangPath(); + CString GetDefaultLangPath(); + CString GetThemeDir(); + CString GetCurrentTheme(); + CString GetDefaultTheme(); + CString GetParentTheme1(); + CString GetParentTheme2(); + CString GetIniPath(); + + void SaveImage(); + +protected: + void InitMenu(); + void InitThemeLang(); + void ChangeTheme(CString themeName); + void SetWindowTitle(CString message); + void UpdateThemeInfo(); + COLORREF GetControlColor(CString name, BYTE defaultColor, CString theme); + COLORREF GetBackgroundColor(CString name, CString theme); + BYTE GetControlAlpha(CString name, BYTE defaultAlpha, CString theme); + BYTE GetCharacterPosition(CString theme); + CString GetParentTheme(int i, CString theme); + CString GetRandomTheme(); + void SaveImageDlg(CImage* image); + + virtual LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam); + virtual BOOL OnInitDialog(); + virtual BOOL OnCommand(WPARAM wParam, LPARAM lParam); + virtual BOOL CheckThemeEdition(CString name); + virtual CString GetDefaultFont(); + + virtual void SaveWindowPosition(); + virtual void RestoreWindowPosition(); + + DECLARE_MESSAGE_MAP() + afx_msg void OnWindowPosChanging(WINDOWPOS* lpwndpos); + afx_msg void OnGetMinMaxInfo(MINMAXINFO* lpMMI); + + // Common + BOOL m_bStartup; + BOOL m_bWindowMinimizeOnce; + BOOL m_bResident; + BOOL m_bResidentMinimize; + + // Theme + CString m_ThemeKeyName; + CString m_RecommendTheme; + CStringArray m_MenuArrayTheme; + + // Language + CStringArray m_MenuArrayLang; + +#ifdef OPTION_TASK_TRAY + // Task Tray + static UINT wmTaskbarCreated; + BOOL AddTaskTray(UINT id, UINT callback, HICON icon, CString tip); + BOOL RemoveTaskTray(UINT id); + BOOL ModifyTaskTray(UINT id, HICON icon, CString tip); + BOOL ModifyTaskTrayIcon(UINT id, HICON icon); + BOOL ModifyTaskTrayTip(UINT id, CString tip); + BOOL ShowBalloon(UINT id, DWORD infoFlag, CString infoTitle, CString info); +#endif + +}; \ No newline at end of file diff --git a/CristalDiskMark/source/CrystalDiskMark/Priscilla/OsInfoFx.cpp b/CristalDiskMark/source/CrystalDiskMark/Priscilla/OsInfoFx.cpp new file mode 100644 index 0000000..b409068 --- /dev/null +++ b/CristalDiskMark/source/CrystalDiskMark/Priscilla/OsInfoFx.cpp @@ -0,0 +1,1558 @@ +/*---------------------------------------------------------------------------*/ +// Author : hiyohiyo +// Mail : hiyohiyo@crystalmark.info +// Web : https://crystalmark.info/ +// License : MIT License +/*---------------------------------------------------------------------------*/ + +#include "stdafx.h" +#include "OsInfoFx.h" +#include "UtilityFx.h" + +typedef BOOL (WINAPI* FuncGetProductInfo)(DWORD, DWORD, DWORD, DWORD, PDWORD); +typedef BOOL (WINAPI* FuncGetNativeSystemInfo)(LPSYSTEM_INFO); +typedef BOOL (WINAPI* FuncIsWow64Process)(HANDLE hProcess,PBOOL Wow64Process); +typedef LONG (WINAPI* FuncRtlGetVersion)(POSVERSIONINFOEXW osvi); + +#if _MSC_VER > 1310 +BOOL IsWindowsVersionOrGreaterFx(WORD wMajorVersion, WORD wMinorVersion, WORD wServicePackMajor) +{ + OSVERSIONINFOEXW osvi = { sizeof(osvi), 0, 0, 0, 0, {0}, 0, 0 }; + DWORDLONG const dwlConditionMask = VerSetConditionMask( + VerSetConditionMask( + VerSetConditionMask( + 0, VER_MAJORVERSION, VER_GREATER_EQUAL), + VER_MINORVERSION, VER_GREATER_EQUAL), + VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL); + + osvi.dwMajorVersion = wMajorVersion; + osvi.dwMinorVersion = wMinorVersion; + osvi.wServicePackMajor = wServicePackMajor; + + return VerifyVersionInfoW(&osvi, VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR, dwlConditionMask) != FALSE; +} + +BOOL IsWindowsBuildOrGreater(DWORD build) +{ + OSVERSIONINFOEXW osvi = { sizeof(osvi), 0, 0, 0, 0, {0}, 0, 0 }; + osvi.dwBuildNumber = build; + return (VerifyVersionInfoW(&osvi, VER_BUILDNUMBER, VerSetConditionMask(0, VER_BUILDNUMBER, VER_GREATER_EQUAL)) == TRUE); +} +#endif + +BOOL GetVersionFx(POSVERSIONINFOEXW osvi) +{ + static FuncRtlGetVersion pRtlGetVersion = NULL; + if (pRtlGetVersion == NULL) + { + HMODULE hModule = GetModuleHandle(_T("ntdll.dll")); + if (hModule) + { + pRtlGetVersion = (FuncRtlGetVersion)GetProcAddress(hModule, "RtlGetVersion"); + } + } + + if (pRtlGetVersion) + { + if (pRtlGetVersion(osvi) >= 0) // NT_SUCCESS(pRtlGetVersion(osvi) + { + return TRUE; + } + } + return FALSE; +} + +#if _MSC_VER > 1310 +BOOL IsX64() +{ + static BOOL b = -1; + if (b == -1) + { + b = FALSE; + HMODULE hModule = GetModuleHandle(_T("kernel32.dll")); + if (hModule) + { + FuncGetNativeSystemInfo pGetNativeSystemInfo = (FuncGetNativeSystemInfo)GetProcAddress(hModule, "GetNativeSystemInfo"); + if (pGetNativeSystemInfo != NULL) + { + SYSTEM_INFO si = { 0 }; + pGetNativeSystemInfo(&si); + if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64) + { + b = TRUE; + } + } + } + } + return b; +} + +BOOL IsIa64() +{ + static BOOL b = -1; + if (b == -1) + { + b = FALSE; + HMODULE hModule = GetModuleHandle(_T("kernel32.dll")); + if (hModule) + { + FuncGetNativeSystemInfo pGetNativeSystemInfo = (FuncGetNativeSystemInfo)GetProcAddress(hModule, "GetNativeSystemInfo"); + if (pGetNativeSystemInfo != NULL) + { + SYSTEM_INFO si = { 0 }; + pGetNativeSystemInfo(&si); + if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_IA64) + { + b = TRUE; + } + } + } + } + return b; +} + +BOOL IsArm32() +{ + static BOOL b = -1; + if (b == -1) + { + b = FALSE; + HMODULE hModule = GetModuleHandle(_T("kernel32.dll")); + if (hModule) + { + FuncGetNativeSystemInfo pGetNativeSystemInfo = (FuncGetNativeSystemInfo)GetProcAddress(hModule, "GetNativeSystemInfo"); + if (pGetNativeSystemInfo != NULL) + { + SYSTEM_INFO si = { 0 }; + pGetNativeSystemInfo(&si); + if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_ARM) + { + b = TRUE; + } + } + } + } + return b; +} + +BOOL IsArm64() +{ + static BOOL b = -1; + if (b == -1) + { + b = FALSE; + HMODULE hModule = GetModuleHandle(_T("kernel32.dll")); + if (hModule) + { + FuncGetNativeSystemInfo pGetNativeSystemInfo = (FuncGetNativeSystemInfo)GetProcAddress(hModule, "GetNativeSystemInfo"); + if (pGetNativeSystemInfo != NULL) + { + SYSTEM_INFO si = { 0 }; + pGetNativeSystemInfo(&si); + if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_ARM64) + { + b = TRUE; + } + } + } + } + return b; +} + +BOOL IsWow64() +{ + static BOOL b = -1; + if (b == -1) + { + b = FALSE; + HMODULE hModule = GetModuleHandle(_T("kernel32.dll")); + if (hModule) + { + FuncIsWow64Process pIsWow64Process = (FuncIsWow64Process)GetProcAddress(hModule, "IsWow64Process"); + if (pIsWow64Process != NULL) + { + pIsWow64Process(GetCurrentProcess(), &b); + } + } + } + return b; +} + +BOOL IsIe556() +{ + switch (GetIeVersion()) + { + case 550: + case 600: + return TRUE; + break; + default: + return FALSE; + break; + } +} + +BOOL IsDotNet2() +{ + static BOOL b = -1; + + if (b == -1) + { + b = FALSE; + DWORD type = REG_DWORD; + ULONG size = sizeof(DWORD); + HKEY hKey = NULL; + DWORD buf = 0; + + if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("SOFTWARE\\Microsoft\\NET Framework Setup\\NDP\\v2.0.50727"), 0, KEY_READ, &hKey) == ERROR_SUCCESS + || RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("SOFTWARE\\Wow6432Node\\Microsoft\\NET Framework Setup\\NDP\\v2.0.50727"), 0, KEY_READ, &hKey) == ERROR_SUCCESS) + { + if (RegQueryValueEx(hKey, _T("Install"), NULL, &type, (LPBYTE)&buf, &size) == ERROR_SUCCESS) + { + if (buf == 1) + { + b = TRUE; + } + } + RegCloseKey(hKey); + } + } + + return (BOOL)b; +} + +BOOL IsDotNet4() +{ + static BOOL b = -1; + + if (b == -1) + { + b = FALSE; + DWORD type = REG_DWORD; + ULONG size = sizeof(DWORD); + HKEY hKey = NULL; + DWORD buf = 0; + + if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("SOFTWARE\\Microsoft\\NET Framework Setup\\NDP\\v4\\Client"), 0, KEY_READ, &hKey) == ERROR_SUCCESS + || RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("SOFTWARE\\Microsoft\\NET Framework Setup\\NDP\\v4\\Full"), 0, KEY_READ, &hKey) == ERROR_SUCCESS + || RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("SOFTWARE\\WOW6432Node\\Microsoft\\NET Framework Setup\\NDP\\v4\\Client"), 0, KEY_READ, &hKey) == ERROR_SUCCESS + || RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("SOFTWARE\\WOW6432Node\\Microsoft\\NET Framework Setup\\NDP\\v4\\Full"), 0, KEY_READ, &hKey) == ERROR_SUCCESS + ) + { + if (RegQueryValueEx(hKey, _T("Install"), NULL, &type, (LPBYTE)&buf, &size) == ERROR_SUCCESS) + { + if (buf == 1) + { + b = TRUE; + } + } + RegCloseKey(hKey); + } + } + + return b; +} + +BOOL IsDotNet48() +{ + static BOOL b = -1; + + if (b == -1) + { + b = FALSE; + DWORD type = REG_DWORD; + ULONG size = sizeof(DWORD); + HKEY hKey = NULL; + DWORD buf = 0; + + if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("SOFTWARE\\Microsoft\\NET Framework Setup\\NDP\\v4\\Client"), 0, KEY_READ, &hKey) == ERROR_SUCCESS + || RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("SOFTWARE\\Microsoft\\NET Framework Setup\\NDP\\v4\\Full"), 0, KEY_READ, &hKey) == ERROR_SUCCESS) + { + if (RegQueryValueEx(hKey, _T("Install"), NULL, &type, (LPBYTE)&buf, &size) == ERROR_SUCCESS) + { + if (buf == 1) + { + if (RegQueryValueEx(hKey, _T("Release"), NULL, &type, (LPBYTE)&buf, &size) == ERROR_SUCCESS) + { + if (buf >= 528040) + { + b = TRUE; + } + } + } + } + RegCloseKey(hKey); + } + } + + return b; +} + +BOOL IsNT5() +{ + static BOOL b = -1; + if (b == -1) + { + b = !IsWindowsVersionOrGreaterFx(6, 0) && IsWindowsVersionOrGreaterFx(5, 0) ? TRUE : FALSE; + } + return b; +} + +BOOL IsNT6orLater() +{ + static BOOL b = -1; + if (b == -1) + { + b = IsWindowsVersionOrGreaterFx(6, 0) ? TRUE : FALSE; + } + return b; +} + +BOOL IsWin2k() +{ + static BOOL b = -1; + if (b == -1) + { + b = IsWindowsVersionOrGreaterFx(5, 0) && !IsWindowsVersionOrGreaterFx(5, 1) ? TRUE : FALSE; + } + return b; +} + +BOOL IsWinXpOrLater() +{ + static BOOL b = -1; + if (b == -1) + { + b = IsWindowsVersionOrGreaterFx(5, 1) ? TRUE : FALSE; + } + return b; +} + +BOOL IsWinXpLuna() +{ + static BOOL xp = -1; + BOOL b = FALSE; + if (xp == -1) + { + xp = IsWindowsVersionOrGreaterFx(5, 1) && !IsWindowsVersionOrGreaterFx(6, 0) ? TRUE : FALSE; + } + if (xp == FALSE) + { + return FALSE; + } + + // Luna Check + DWORD type = REG_DWORD; + ULONG size = 256; + HKEY hKey = NULL; + BYTE buf[256] = {0}; + CString cstr; + + if (RegOpenKeyEx(HKEY_CURRENT_USER, _T("Software\\Microsoft\\Windows\\CurrentVersion\\ThemeManager\\"), 0, KEY_READ, &hKey) == ERROR_SUCCESS) + { + if (RegQueryValueEx(hKey, _T("ThemeActive"), NULL, &type, buf, &size) == ERROR_SUCCESS) + { + cstr = (TCHAR*)buf; + if (cstr.Find(_T("1")) == 0) + { + b = TRUE; + } + } + RegCloseKey(hKey); + } + return b; +} + +BOOL IsWin8orLater() +{ + static BOOL b = -1; + if (b == -1) + { + b = IsWindowsVersionOrGreaterFx(6, 2) ? TRUE : FALSE; + } + return b; +} + +BOOL IsWin81orLater() +{ + static BOOL b = -1; + if (b == -1) + { + b = IsWindowsVersionOrGreaterFx(6, 3) ? TRUE : FALSE; + } + return b; +} + +BOOL IsDarkModeSupport() +{ + static BOOL b = -1; + if (b == -1) + { + b = IsWindowsBuildOrGreater(17763) ? TRUE : FALSE; + } + return b; +} + +BOOL HasSidebar() +{ + static BOOL b = -1; + if (b == -1) + { + b = FALSE; + OSVERSIONINFOEXW osvi; + GetVersionFx(&osvi); + + if (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion < 2 && osvi.wProductType == VER_NT_WORKSTATION) + { + b = TRUE; + } + } + return b; +} + +DWORD GetIeVersion() +{ + static INT ieVersion = -1; + + if (ieVersion != -1) + { + return ieVersion; + } + + DWORD type = REG_SZ; + ULONG size = 256; + HKEY hKey = NULL; + BYTE buf[256] = {0}; + CString cstr; + + switch (GetFileVersion(_T("Shdocvw.dll"))) + { + case 470: ieVersion = 300; break; + case 471: ieVersion = 400; break; + case 472: ieVersion = 401; break; + case 500: ieVersion = 500; break; + case 550: ieVersion = 550; break; + case 600: + default: + ieVersion = 600; + if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("SOFTWARE\\Microsoft\\Internet Explorer"), 0, KEY_READ, &hKey) == ERROR_SUCCESS) + { + if (RegQueryValueEx(hKey, _T("Version"), NULL, &type, buf, &size) == ERROR_SUCCESS) + { + cstr = (TCHAR*)buf; + ieVersion = _tstoi(cstr) * 100; + if (ieVersion == 900 && RegQueryValueEx(hKey, _T("svcVersion"), NULL, &type, buf, &size) == ERROR_SUCCESS) + { + cstr = (TCHAR*)buf; + if (_tstoi(cstr) * 100 > 900) + { + ieVersion = _tstoi(cstr) * 100; + } + } + } + RegCloseKey(hKey); + } + break; + } + + return ieVersion; +} +#endif + +BOOL IsNT3() +{ + static BOOL b = -1; + if (b == -1) + { + b = FALSE; + + OSVERSIONINFO osvi = { 0 }; + osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + GetVersionEx((OSVERSIONINFO*)&osvi); + + if ((osvi.dwPlatformId == VER_PLATFORM_WIN32_NT) + && (osvi.dwMajorVersion == 3)) + { + b = TRUE; + } + } + return b; +} + +BOOL IsNT4() +{ + static BOOL b = -1; + if (b == -1) + { + b = FALSE; + + OSVERSIONINFO osvi = { 0 }; + osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + GetVersionEx((OSVERSIONINFO*)&osvi); + + if ((osvi.dwPlatformId == VER_PLATFORM_WIN32_NT) + && (osvi.dwMajorVersion == 4)) + { + b = TRUE; + } + } + return b; +} + +BOOL IsWin9x() +{ + static BOOL b = -1; + + if (b == -1) + { + b = FALSE; + + OSVERSIONINFO osvi = { 0 }; + osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + GetVersionEx((OSVERSIONINFO*)&osvi); + + if (osvi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) + { + b = TRUE; + } + } + + return b; +} + +BOOL IsWin95() +{ + static BOOL b = -1; + + if (b == -1) + { + b = FALSE; + + OSVERSIONINFO osvi = { 0 }; + osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + GetVersionEx((OSVERSIONINFO*)&osvi); + + if (osvi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS + && osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 0) + { + b = TRUE; + } + } + + return b; +} + +BOOL IsWin95First() +{ + static BOOL b = -1; + + if (b == -1) + { + b = FALSE; + + OSVERSIONINFO osvi = { 0 }; + osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + GetVersionEx((OSVERSIONINFO*)&osvi); + + if (osvi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS + && osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 0 && osvi.dwBuildNumber <= 950) + { + b = TRUE; + } + } + + return b; +} + +BOOL IsPC98() +{ + static BOOL b = -1; + + DWORD type = REG_SZ; + ULONG size = 256; + HKEY hKey = NULL; + BYTE buf[256] = {0}; + CString cstr; + + if (b == -1) + { + b = FALSE; + if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("HARDWARE\\DESCRIPTION\\System"), 0, KEY_READ, &hKey) == ERROR_SUCCESS) + { + if (RegQueryValueEx(hKey, _T("Identifier"), NULL, &type, buf, &size) == ERROR_SUCCESS) + { + cstr = (TCHAR*)buf; + if (cstr.Find(_T("NEC PC-98")) == 0) + { + b = TRUE; + } + } + RegCloseKey(hKey); + } + + if ((GetKeyboardType(1) & 0xFF00) == 0x0D00) + { + b = TRUE; + } + +#ifndef UNICODE +/// PC-98 機種判定 det98 Programmed by K.Takata +/// http://k-takata.o.oo7.jp/mysoft/det98.html +#define MK_FP(seg, off) ((void *) (((seg) << 4) + (off))) +#define MACHINE_ID_SEG 0xf8e8 +#define MACHINE_ID_SEG_HIGHRESO 0xffe8 +#define PC98_ID_OFF 0x0000 +#define PC98_ID 0x2198 /* 9821 */ + + if(IsWin9x()) + { + unsigned short* pc98_id = NULL; + pc98_id = (unsigned short*)MK_FP(MACHINE_ID_SEG, PC98_ID_OFF); + if(*pc98_id == PC98_ID) + { + b = TRUE; + } + + if((GetSystemMetrics(SM_CXSCREEN) == 1120) && (GetSystemMetrics(SM_CYSCREEN) == 750)) // High Resolution + { + pc98_id = (unsigned short*)MK_FP(MACHINE_ID_SEG_HIGHRESO, PC98_ID_OFF); + if (*pc98_id == PC98_ID) + { + b = TRUE; + } + } + } +#endif + } + + return b; +} + +BOOL IsNT51orlater() +{ + static BOOL b = -1; + if (b == -1) + { + b = FALSE; + + OSVERSIONINFO osvi = { 0 }; + osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + GetVersionEx((OSVERSIONINFO*)&osvi); + + if ((osvi.dwPlatformId == VER_PLATFORM_WIN32_NT) + && + ((osvi.dwMajorVersion == 5 && osvi.dwMinorVersion >= 1) || (osvi.dwMajorVersion > 5))) + { + b = TRUE; + } + } + return b; +} + +BOOL IsRunningOnWine() +{ + HMODULE hModule = LoadLibraryA("ntdll.dll"); + if (hModule) + { + void* pWineGetVersion = (void*)GetProcAddress(hModule, "wine_get_version"); + FreeLibrary(hModule); + return pWineGetVersion != NULL; + } + return FALSE; +} + +void GetOsName(CString& osFullName, CString& name, CString& version, CString& architecture) +{ + CString osName, osType, osCsd, osVersion, osBuild, osArchitecture, osDisplayVersion; + CString osNameWmi; + CString cstr; + +#if _MSC_VER <= 1310 + // For Win9x + OSVERSIONINFO osv = { 0 }; + osv.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + GetVersionEx((OSVERSIONINFO*)&osv); + + if (osv.dwPlatformId == VER_PLATFORM_WIN32s) + { + osFullName = _T("Windows 3.x + Win32s"); + name = osFullName; + return; + } + else if (osv.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) + { + switch (osv.dwMinorVersion) + { + case 0: // Windows 95 + if (LOWORD(osv.dwBuildNumber) >= 1214) + { + osName = _T("Windows 95 OSR2.5"); + } + else if (LOWORD(osv.dwBuildNumber) >= 1212) + { + osName = _T("Windows 95 OSR2.1"); + } + else if (LOWORD(osv.dwBuildNumber) >= 1111) + { + osName = _T("Windows 95 OSR2"); + } + else + { + osName = _T("Windows 95"); + } + break; + case 10: // Windows 98 + if (LOWORD(osv.dwBuildNumber) >= 2222) + { + osName = _T("Windows 98 Second Edition"); + } + else if (LOWORD(osv.dwBuildNumber) >= 2000) + { + osName = _T("Windows 98 SP1"); + } + else + { + osName = _T("Windows 98"); + } + break; + case 90: + osName = _T("Windows Me"); + break; + default: + osName = _T("Windows 9x"); + break; + } + osVersion.Format(_T("%d.%d"), osv.dwMajorVersion, osv.dwMinorVersion); + osBuild.Format(_T("%d"), LOWORD(osv.dwBuildNumber)); + osFullName.Format(_T("%s [%s Build %s]"), (LPCTSTR)osName, (LPCTSTR)osVersion, (LPCTSTR)osBuild); + + name = osName; + version.Format(_T("%s Build %s"), (LPCTSTR)osVersion, (LPCTSTR)osBuild); + architecture = _T("x86"); + + return; + } +#endif + +#if _MSC_VER > 1310 + #ifdef UNICODE + OSVERSIONINFOEXW osvi = { sizeof(osvi), 0, 0, 0, 0, {0}, 0, 0 }; + GetVersionFx((OSVERSIONINFOEXW*)&osvi); + #else + OSVERSIONINFOEX osvi = { sizeof(osvi), 0, 0, 0, 0, {0}, 0, 0 }; + GetVersionEx((OSVERSIONINFO*)&osvi); + #endif +#else + OSVERSIONINFOEXW osviw = { sizeof(osviw), 0, 0, 0, 0, {0}, 0, 0 }; + OSVERSIONINFOEX osvi = { sizeof(osvi), 0, 0, 0, 0, {0}, 0, 0 }; + + GetVersionEx((OSVERSIONINFO*)&osvi); + if (osvi.dwMajorVersion == 0) // Windows NT 3.51, NT 4.0 SP4 or earlier + { + osvi.dwMajorVersion = osv.dwMajorVersion; + osvi.dwMinorVersion = osv.dwMinorVersion; + osvi.dwBuildNumber = osv.dwBuildNumber; + osvi.dwPlatformId = osv.dwPlatformId; + wsprintf(osvi.szCSDVersion, osv.szCSDVersion); + } + + if (osvi.dwMajorVersion >= 6 && GetVersionFx((OSVERSIONINFOEXW*)&osviw)) + { + osvi.dwMajorVersion = osviw.dwMajorVersion; + osvi.dwMinorVersion = osviw.dwMinorVersion; + osvi.dwBuildNumber = osviw.dwBuildNumber; + osvi.wServicePackMajor = osviw.wServicePackMajor; + osvi.wServicePackMinor = osviw.wServicePackMinor; + osvi.wSuiteMask = osviw.wSuiteMask; + osvi.wProductType = osviw.wProductType; + } +#endif + + GetOsNameWmi(osNameWmi); + + // Windows 11/Server 2025 + CString osNameWmiBackup = osNameWmi; + CString osNameWmiMajorVersion = osNameWmi; + osNameWmiMajorVersion.Replace(_T("(R)"), _T("")); + osNameWmiMajorVersion.Replace(_T("Microsoft "), _T("")); + osNameWmiMajorVersion.Replace(_T("Windows "), _T("")); + osNameWmiMajorVersion.Replace(_T("Server "), _T("")); + + int majorVersion = _ttoi(osNameWmiMajorVersion); + + if ((3 <= majorVersion && majorVersion <= 11) || (2000 <= majorVersion && majorVersion <= 2025)) + { + osNameWmi = _T(""); + } + + if (osNameWmi.IsEmpty()) + { + switch (osvi.dwPlatformId) + { + case VER_PLATFORM_WIN32_NT: + if (osvi.dwMajorVersion == 3) + { + osName.Format(_T("Windows NT 3.%d"), osvi.dwMinorVersion); + } + else if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 0) + { + osName = _T("Windows NT 4.0"); + } + else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0) + { + osName = _T("Windows 2000"); + } + else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1) + { + osName = _T("Windows XP"); + } + else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2) + { + if (GetSystemMetrics(SM_SERVERR2)) + { + osName = _T("Windows Server 2003 R2"); + } + else if (osvi.wSuiteMask == 0x00002000 /*VER_SUITE_STORAGE_SERVER*/) + { + osName = _T("Windows Storage Server 2003"); + } + else if (osvi.wProductType == VER_NT_WORKSTATION) + { + osName = _T("Windows XP"); + } + else + { + osName = _T("Windows Server 2003"); + } + } + else if (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 0) + { + if (osvi.wProductType != VER_NT_WORKSTATION) + { + osName = _T("Windows Server 2008"); + } + else + { + osName = _T("Windows Vista"); + } + } + else if (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 1) + { + if (osvi.wProductType != VER_NT_WORKSTATION) + { + osName = _T("Windows Server 2008 R2"); + } + else + { + osName = _T("Windows 7"); + } + } + else if (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 2) + { + if (osvi.wProductType != VER_NT_WORKSTATION) + { + osName = _T("Windows Server 2012"); + } + else + { + osName = _T("Windows 8"); + } + } + else if (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 3) + { + if (osvi.wProductType != VER_NT_WORKSTATION) + { + osName = _T("Windows Server 2012 R2"); + } + else + { + osName = _T("Windows 8.1"); + } + } + else if ((osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 4) + || (osvi.dwMajorVersion >= 10 && osvi.dwMinorVersion >= 0)) + { + if (osvi.wProductType != VER_NT_WORKSTATION) + { + if (osvi.dwBuildNumber >= 26040) + { + osName = _T("Windows Server 2025"); + } + else if (osvi.dwBuildNumber >= 20344) + { + osName = _T("Windows Server 2022"); + } + else if (osvi.dwBuildNumber >= 17763) + { + osName = _T("Windows Server 2019"); + } + else + { + osName = _T("Windows Server 2016"); + } + } + else + { + if (osvi.dwBuildNumber >= 21996) + { + osName = _T("Windows 11"); + } + else + { + osName = _T("Windows 10"); + } + } + } + else + { + osName.Format(_T("Windows NT %d.%d"), osvi.dwMajorVersion, osvi.dwMinorVersion); + } + + if (osvi.dwMajorVersion >= 6) + { + HMODULE hModule = GetModuleHandle(_T("kernel32.dll")); + FuncGetProductInfo pGetProductInfo = NULL; + if (hModule) + { + pGetProductInfo = (FuncGetProductInfo)GetProcAddress(hModule, "GetProductInfo"); + } + + if (pGetProductInfo) + { + DWORD productType = 0; + pGetProductInfo(osvi.dwMajorVersion, osvi.dwMinorVersion, 0, 0, &productType); + + switch (productType) + { + case PRODUCT_UNLICENSED: + osType = _T("Unlicensed"); + break; + case PRODUCT_CORE_ARM: + case PRODUCT_CORE_COUNTRYSPECIFIC: + case PRODUCT_CORE_SINGLELANGUAGE: + case PRODUCT_CORE: + osType = L"Home"; + break; + case PRODUCT_CORE_N: + osType = L"Home N"; + break; + case PRODUCT_EDUCATION: + osType = L"Education"; + break; + case PRODUCT_EDUCATION_N: + osType = L"Education N"; + break; + case PRODUCT_BUSINESS: + osType = _T("Business"); + break; + case PRODUCT_BUSINESS_N: + osType = _T("Business N"); + break; + case PRODUCT_CLUSTER_SERVER: + osType = _T("Cluster Server"); + break; + case PRODUCT_DATACENTER_SERVER: + osType = _T("Datacenter"); + break; + case PRODUCT_DATACENTER_SERVER_CORE: + osType = _T("Datacenter"); + break; + case PRODUCT_ENTERPRISE: + osType = _T("Enterprise"); + break; + case PRODUCT_ENTERPRISE_N: + osType = _T("Enterprise N"); + break; + case PRODUCT_ENTERPRISE_G: + osType = _T("Enterprise G"); + break; + case PRODUCT_ENTERPRISE_SERVER: + osType = _T("Enterprise"); + break; + case PRODUCT_ENTERPRISE_SERVER_CORE: + osType = _T("Enterprise"); + break; + case PRODUCT_ENTERPRISE_SERVER_IA64: + osType = _T("Datacenter Enterprise for Itanium-based Systems"); + break; + case PRODUCT_HOME_BASIC: + osType = _T("Home Basic"); + break; + case PRODUCT_HOME_BASIC_N: + osType = _T("Home Basic N"); + break; + case PRODUCT_HOME_PREMIUM: + osType = _T("Home Premium"); + break; + case PRODUCT_HOME_PREMIUM_N: + osType = _T("Home Premium N"); + break; + case PRODUCT_HOME_SERVER: + osType = _T("Home Server"); + break; + case PRODUCT_SERVER_FOR_SMALLBUSINESS: + osType = _T("Server for Small Business"); + break; + case PRODUCT_SMALLBUSINESS_SERVER: + osType = _T("Small Business Server"); + break; + case PRODUCT_SMALLBUSINESS_SERVER_PREMIUM: + osType = _T("Small Business Server Premium"); + break; + case PRODUCT_STANDARD_SERVER: + osType = _T("Server Standard"); + break; + case PRODUCT_STANDARD_SERVER_CORE: + osType = _T("Server Standard"); + break; + case PRODUCT_STARTER: + osType = _T("Starter"); + break; + case PRODUCT_STARTER_N: + osType = _T("Starter N"); + break; + case PRODUCT_STARTER_E: + osType = _T("Starter E"); + break; + case PRODUCT_STORAGE_ENTERPRISE_SERVER: + osType = _T("Storage Server Enterprise"); + break; + case PRODUCT_STORAGE_EXPRESS_SERVER: + osType = _T("Storage Server Express"); + break; + case PRODUCT_STORAGE_STANDARD_SERVER: + osType = _T("Storage Server Standard"); + break; + case PRODUCT_STORAGE_WORKGROUP_SERVER: + osType = _T("Storage Server Workgroup"); + break; + case PRODUCT_ULTIMATE: + osType = _T("Ultimate"); + break; + case PRODUCT_ULTIMATE_N: + osType = _T("Ultimate N"); + break; + case PRODUCT_WEB_SERVER: + osType = _T("Web Server"); + break; + case PRODUCT_PROFESSIONAL: + if (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion <= 2) + { + osType = _T("Professional"); + } + else + { + osType = _T("Pro"); + } + break; + case PRODUCT_PROFESSIONAL_N: + if (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion <= 2) + { + osType = _T("Professional N"); + } + else + { + osType = _T("Pro N"); + } + break; + case PRODUCT_PRO_WORKSTATION: + case PRODUCT_PROFESSIONAL_WORKSTATION: + osType = _T("Pro for Workstation"); + break; + case PRODUCT_PRO_WORKSTATION_N: + case PRODUCT_PROFESSIONAL_WORKSTATION_N: + osType = _T("Pro for Workstation N"); + break; + case PRODUCT_PRO_FOR_EDUCATION: + osType = _T("Pro for Education"); + break; + case PRODUCT_PRO_FOR_EDUCATION_N: + osType = _T("Pro for Education N"); + break; + case PRODUCT_ESSENTIALBUSINESS_SERVER_ADDL: + case PRODUCT_ESSENTIALBUSINESS_SERVER_MGMTSVC: + case PRODUCT_ESSENTIALBUSINESS_SERVER_ADDLSVC: + osType = _T("Essentials Server"); + break; + } + } + } + else if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 0) + { + if (osvi.wProductType == VER_NT_WORKSTATION) + { + osType = _T("Workstation"); + } + else if (osvi.wProductType == VER_NT_SERVER || osvi.wProductType == VER_NT_DOMAIN_CONTROLLER) + { + if (osvi.wSuiteMask & VER_SUITE_ENTERPRISE) + { + osType = _T("Server Enterprise Edition"); + } + else + { + osType = _T("Server"); + } + } + } + else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0) + { + if (osvi.wProductType == VER_NT_WORKSTATION) + { + osType = _T("Professional"); + } + else if (osvi.wProductType == VER_NT_SERVER || osvi.wProductType == VER_NT_DOMAIN_CONTROLLER) + { + if (osvi.wSuiteMask & VER_SUITE_ENTERPRISE) + { + osType = _T("Advanced Server"); + } + else if (osvi.wSuiteMask & VER_SUITE_DATACENTER) + { + osType = _T("Datacenter Server"); + } + else + { + osType = _T("Server"); + } + } + } + else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion >= 1) + { + if (osvi.wSuiteMask & VER_SUITE_PERSONAL) + { + osType = _T("Home Edition"); + } + else if (osvi.wSuiteMask & VER_SUITE_DATACENTER) + { + osType = _T("Datacenter Edition"); + } + else if (osvi.wSuiteMask & VER_SUITE_ENTERPRISE) + { + osType = _T("Enterprise Edition"); + } + else if (osvi.wSuiteMask & VER_SUITE_BLADE) + { + osType = _T("Web Edition"); + } + else if (osvi.wProductType == VER_NT_WORKSTATION) + { + osType = _T("Professional"); + } + + // Meida Center & Tablet + if (GetSystemMetrics(SM_MEDIACENTER)) + { + TCHAR path[MAX_PATH] = {0}; + TCHAR str[256] = {0}; + UINT length = GetWindowsDirectory(path, MAX_PATH); + +#if _MSC_VER <= 1310 + _tcscat(path, _T("\\ehome\\ehshell.exe")); +#else + _tcscat_s(path, MAX_PATH, _T("\\ehome\\ehshell.exe")); +#endif + + if (length != 0 && GetFileVersion(path, str)) + { + cstr = str; + if (cstr.Find(_T("5.1")) == 0) + { + osType = _T("Media Center "); + cstr.Replace(_T("5.1."), _T("")); + double num = _tstof(cstr); + if (num <= 2600.1200) + { + osType += _T("2002"); + } + else if (num <= 2600.2500) + { + osType += _T("2004"); + } + else + { + osType += _T("2005"); + } + } + } + } + else if (GetSystemMetrics(SM_TABLETPC)) + { + osType = _T("Tablet PC"); + } + } + } + } + + osCsd = osvi.szCSDVersion; + osCsd.Replace(_T("Service Pack "), _T("SP")); + + if (osvi.dwMajorVersion >= 10) + { + DWORD value = 0; + DWORD type = REG_SZ; + TCHAR str[256]; + ULONG size = 256 * sizeof(TCHAR); + HKEY hKey = NULL; + + if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion"), 0, KEY_READ, &hKey) == ERROR_SUCCESS) + { + if (RegQueryValueEx(hKey, _T("DisplayVersion"), NULL, &type, (LPBYTE)str, &size) == ERROR_SUCCESS) + { + osDisplayVersion = str; + } + + if (osDisplayVersion.IsEmpty() && RegQueryValueEx(hKey, _T("ReleaseId"), NULL, &type, (LPBYTE)str, &size) == ERROR_SUCCESS) + { + osDisplayVersion = str; + } + } + } + + osVersion.Format(_T("%d.%d"), osvi.dwMajorVersion, osvi.dwMinorVersion); + osBuild.Format(_T("%d"), osvi.dwBuildNumber); + +#if _MSC_VER > 1310 + if(IsX64()) + { + osArchitecture = _T("x64"); + } + else if (IsArm32()) + { + osArchitecture = _T("ARM32"); + } + else if (IsArm64()) + { + osArchitecture = _T("ARM64"); + } + else if(IsIa64()) + { + osArchitecture = _T("IA64"); + } + else + { + osArchitecture = _T("x86"); + } +#else + osArchitecture = _T("x86"); +#endif + + // for Unknown Edition + if (osType.IsEmpty()) + { + osNameWmi = osNameWmiBackup; + } + + if (!osNameWmi.IsEmpty()) + { + if (!osDisplayVersion.IsEmpty()) + { + osFullName.Format(_T("%s %s [%s Build %s] (%s)"), (LPCTSTR)osNameWmi, (LPCTSTR)osDisplayVersion, (LPCTSTR)osVersion, (LPCTSTR)osBuild, (LPCTSTR)osArchitecture); + name.Format(_T("%s %s"), (LPCTSTR)osNameWmi, (LPCTSTR)osDisplayVersion); + version.Format(_T("%s Build %s"), (LPCTSTR)osVersion, (LPCTSTR)osBuild); + architecture = osArchitecture; + } + else if (!osCsd.IsEmpty()) + { + osFullName.Format(_T("%s %s [%s Build %s] (%s)"), (LPCTSTR)osNameWmi, (LPCTSTR)osCsd, (LPCTSTR)osVersion, (LPCTSTR)osBuild, (LPCTSTR)osArchitecture); + name.Format(_T("%s %s"), (LPCTSTR)osNameWmi, (LPCTSTR)osCsd); + version.Format(_T("%s Build %s"), (LPCTSTR)osVersion, (LPCTSTR)osBuild); + architecture = osArchitecture; + } + else + { + osFullName.Format(_T("%s [%s Build %s] (%s)"), (LPCTSTR)osNameWmi, (LPCTSTR)osVersion, (LPCTSTR)osBuild, (LPCTSTR)osArchitecture); + name.Format(_T("%s"), (LPCTSTR)osNameWmi); + version.Format(_T("%s Build %s"), (LPCTSTR)osVersion, (LPCTSTR)osBuild); + architecture = osArchitecture; + } + } + else + { + if (!osDisplayVersion.IsEmpty()) + { + osFullName.Format(_T("%s %s %s [%s Build %s] (%s)"), (LPCTSTR)osName, (LPCTSTR)osType, (LPCTSTR)osDisplayVersion, (LPCTSTR)osVersion, (LPCTSTR)osBuild, (LPCTSTR)osArchitecture); + name.Format(_T("%s %s %s"), (LPCTSTR)osName, (LPCTSTR)osType, (LPCTSTR)osDisplayVersion); + version.Format(_T("%s Build %s"), (LPCTSTR)osVersion, (LPCTSTR)osBuild); + architecture = osArchitecture; + } + else if (!osCsd.IsEmpty()) + { + osFullName.Format(_T("%s %s %s [%s Build %s] (%s)"), (LPCTSTR)osName, (LPCTSTR)osType, (LPCTSTR)osCsd, (LPCTSTR)osVersion, (LPCTSTR)osBuild, (LPCTSTR)osArchitecture); + name.Format(_T("%s %s %s"), (LPCTSTR)osName, (LPCTSTR)osType, (LPCTSTR)osCsd); + version.Format(_T("%s Build %s"), (LPCTSTR)osVersion, (LPCTSTR)osBuild); + architecture = osArchitecture; + } + else if (!osType.IsEmpty()) + { + osFullName.Format(_T("%s %s [%s Build %s] (%s)"), (LPCTSTR)osName, (LPCTSTR)osType, (LPCTSTR)osVersion, (LPCTSTR)osBuild, (LPCTSTR)osArchitecture); + name.Format(_T("%s %s"), (LPCTSTR)osName, (LPCTSTR)osType); + version.Format(_T("%s Build %s"), (LPCTSTR)osVersion, (LPCTSTR)osBuild); + architecture = osArchitecture; + } + else + { + osFullName.Format(_T("%s [%s Build %s] (%s)"), (LPCTSTR)osName, (LPCTSTR)osVersion, (LPCTSTR)osBuild, (LPCTSTR)osArchitecture); + name.Format(_T("%s"), (LPCTSTR)osName); + version.Format(_T("%s Build %s"), (LPCTSTR)osVersion, (LPCTSTR)osBuild); + architecture = osArchitecture; + } + } + + osFullName.Replace(_T(" "), _T(" ")); +} + +//------------------------------------------------ +// Get OS Information by WMI +//------------------------------------------------ + +//warning : enum3, enum class +#if _MSC_VER > 1310 +#pragma warning(disable : 26812) +#endif + +#include +#include +#include +#pragma comment(lib, "oleaut32.lib") +#pragma comment(lib, "wbemuuid.lib") + +#define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } } +#ifndef safeCloseHandle +#define safeCloseHandle(h) { if( h != NULL ) { ::CloseHandle(h); h = NULL; } } +#endif +#ifndef safeVirtualFree +#define safeVirtualFree(h,b,c) { if( h != NULL ) { ::VirtualFree(h, b, c); h = NULL; } } +#endif + +void GetOsNameWmi(CString& osName) +{ + CString query = _T("Select * from Win32_OperatingSystem"); + + IWbemLocator* pIWbemLocator = NULL; + IWbemServices* pIWbemServices = NULL; + IEnumWbemClassObject* pEnumCOMDevs = NULL; + IWbemClassObject* pCOMDev = NULL; + ULONG uReturned = 0; + BOOL flag = FALSE; + + try + { + if (SUCCEEDED(CoCreateInstance(CLSID_WbemLocator, NULL, CLSCTX_INPROC_SERVER, + IID_IWbemLocator, (LPVOID*)&pIWbemLocator))) + { + long securityFlag = 0; +#if _MSC_VER > 1310 + if (IsWindowsVersionOrGreaterFx(6, 0)) { securityFlag = WBEM_FLAG_CONNECT_USE_MAX_WAIT; } +#endif + if (SUCCEEDED(pIWbemLocator->ConnectServer(_bstr_t(_T("root\\cimv2")), + NULL, NULL, 0L, securityFlag, NULL, NULL, &pIWbemServices))) + { +#if _MSC_VER > 1310 + if (SUCCEEDED(CoSetProxyBlanket(pIWbemServices, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, + NULL, RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE))) +#endif + { + if (SUCCEEDED(pIWbemServices->ExecQuery(_bstr_t(_T("WQL")), + _bstr_t(query), WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, NULL, &pEnumCOMDevs))) + { + while (pEnumCOMDevs && SUCCEEDED(pEnumCOMDevs->Next(10000, 1, &pCOMDev, &uReturned)) && uReturned == 1) + { + CString name; + VARIANT pVal; + VariantInit(&pVal); + + if (pCOMDev->Get(L"Caption", 0L, &pVal, NULL, NULL) == WBEM_S_NO_ERROR && pVal.vt > VT_NULL) + { + name = pVal.bstrVal; + VariantClear(&pVal); +#ifdef UNICODE + name.Replace(_T("™"), _T("")); + name.Replace(_T("®"), _T("")); +#endif + name.Replace(_T("(R)"), _T("")); + name.Replace(_T("Microsoft "), _T("")); + + name.Trim(); + } + VariantInit(&pVal); + + osName = name; + } + } + } + } + } + } + catch (...) + { + + } + + SAFE_RELEASE(pCOMDev); + SAFE_RELEASE(pEnumCOMDevs); + SAFE_RELEASE(pIWbemServices); + SAFE_RELEASE(pIWbemLocator); +} + +#if _MSC_VER <= 1310 +#ifdef UNICODE + +/// https://web.archive.org/web/20050906124319/http://support.microsoft.com/kb/q118626/ +BOOL IsCurrentUserLocalAdministrator(void) +{ + BOOL fReturn = FALSE; + DWORD dwStatus; + DWORD dwAccessMask; + DWORD dwAccessDesired; + DWORD dwACLSize; + DWORD dwStructureSize = sizeof(PRIVILEGE_SET); + PACL pACL = NULL; + PSID psidAdmin = NULL; + + HANDLE hToken = NULL; + HANDLE hImpersonationToken = NULL; + + PRIVILEGE_SET ps; + GENERIC_MAPPING GenericMapping; + + PSECURITY_DESCRIPTOR psdAdmin = NULL; + SID_IDENTIFIER_AUTHORITY SystemSidAuthority = SECURITY_NT_AUTHORITY; + + const DWORD ACCESS_READ = 1; + const DWORD ACCESS_WRITE = 2; + + __try + { + if (!OpenThreadToken(GetCurrentThread(), TOKEN_DUPLICATE | TOKEN_QUERY, + + TRUE, &hToken)) + { + if (GetLastError() != ERROR_NO_TOKEN) + __leave; + + if (!OpenProcessToken(GetCurrentProcess(), + + TOKEN_DUPLICATE | TOKEN_QUERY, &hToken)) + __leave; + } + + if (!DuplicateToken(hToken, SecurityImpersonation, + + &hImpersonationToken)) + __leave; + + if (!AllocateAndInitializeSid(&SystemSidAuthority, 2, + SECURITY_BUILTIN_DOMAIN_RID, + DOMAIN_ALIAS_RID_ADMINS, + 0, 0, 0, 0, 0, 0, &psidAdmin)) + __leave; + + psdAdmin = LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH); + if (psdAdmin == NULL) + __leave; + + if (!InitializeSecurityDescriptor(psdAdmin, + + SECURITY_DESCRIPTOR_REVISION)) + __leave; + + dwACLSize = sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE) + + GetLengthSid(psidAdmin) - sizeof(DWORD); + + pACL = (PACL)LocalAlloc(LPTR, dwACLSize); + if (pACL == NULL) + __leave; + + if (!InitializeAcl(pACL, dwACLSize, ACL_REVISION2)) + __leave; + + dwAccessMask = ACCESS_READ | ACCESS_WRITE; + + if (!AddAccessAllowedAce(pACL, ACL_REVISION2, dwAccessMask, + + psidAdmin)) + __leave; + + if (!SetSecurityDescriptorDacl(psdAdmin, TRUE, pACL, FALSE)) + __leave; + + SetSecurityDescriptorGroup(psdAdmin, psidAdmin, FALSE); + SetSecurityDescriptorOwner(psdAdmin, psidAdmin, FALSE); + + if (!IsValidSecurityDescriptor(psdAdmin)) + __leave; + + dwAccessDesired = ACCESS_READ; + + GenericMapping.GenericRead = ACCESS_READ; + GenericMapping.GenericWrite = ACCESS_WRITE; + GenericMapping.GenericExecute = 0; + GenericMapping.GenericAll = ACCESS_READ | ACCESS_WRITE; + + if (!AccessCheck(psdAdmin, hImpersonationToken, dwAccessDesired, + &GenericMapping, &ps, &dwStructureSize, &dwStatus, + &fReturn)) + { + fReturn = FALSE; + __leave; + } + } + __finally + { + if (pACL) LocalFree(pACL); + if (psdAdmin) LocalFree(psdAdmin); + if (psidAdmin) FreeSid(psidAdmin); + if (hImpersonationToken) CloseHandle(hImpersonationToken); + if (hToken) CloseHandle(hToken); + } + + return fReturn; +} + +/// https://learn.microsoft.com/en-us/windows/win32/api/securitybaseapi/nf-securitybaseapi-checktokenmembership +BOOL IsUserAdmin(VOID) +{ + BOOL b = FALSE; + SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY; + PSID AdministratorsGroup; + b = AllocateAndInitializeSid( + &NtAuthority, + 2, + SECURITY_BUILTIN_DOMAIN_RID, + DOMAIN_ALIAS_RID_ADMINS, + 0, 0, 0, 0, 0, 0, + &AdministratorsGroup); + + if (b) + { + typedef BOOL(WINAPI* FuncCheckTokenMembership)(HANDLE, PSID, PBOOL); + FuncCheckTokenMembership pCheckTokenMembership = NULL; + HMODULE hModule = GetModuleHandle(_T("Advapi32.dll")); + if (hModule) + { + pCheckTokenMembership = (FuncCheckTokenMembership)GetProcAddress(hModule, "CheckTokenMembership"); + } + + if (pCheckTokenMembership != NULL) + { + if (!pCheckTokenMembership(NULL, AdministratorsGroup, &b)) + { + b = FALSE; + } + } + else if (IsCurrentUserLocalAdministrator()) // for NT4 + { + b = TRUE; + } + else + { + b = FALSE; + } + FreeSid(AdministratorsGroup); + } + + return(b); +} +#endif +#endif \ No newline at end of file diff --git a/CristalDiskMark/source/CrystalDiskMark/Priscilla/OsInfoFx.h b/CristalDiskMark/source/CrystalDiskMark/Priscilla/OsInfoFx.h new file mode 100644 index 0000000..72f4e42 --- /dev/null +++ b/CristalDiskMark/source/CrystalDiskMark/Priscilla/OsInfoFx.h @@ -0,0 +1,242 @@ +/*---------------------------------------------------------------------------*/ +// Author : hiyohiyo +// Mail : hiyohiyo@crystalmark.info +// Web : https://crystalmark.info/ +// License : MIT License +/*---------------------------------------------------------------------------*/ + +#pragma once + +////------------------------------------------------ +// OS Info +////------------------------------------------------ + +#if _MSC_VER > 1310 +BOOL IsWindowsVersionOrGreaterFx(WORD wMajorVersion, WORD wMinorVersion, WORD wServicePackMajor = 0); +BOOL IsWindowsBuildOrGreater(DWORD build); +BOOL IsX64(); +BOOL IsIa64(); +BOOL IsArm32(); +BOOL IsArm64(); +BOOL IsWow64(); +BOOL IsIe556(); +BOOL IsDotNet2(); +BOOL IsDotNet4(); +BOOL IsDotNet48(); +BOOL IsNT5(); +BOOL IsNT6orLater(); +BOOL IsWin2k(); +BOOL IsWinXpOrLater(); +BOOL IsWinXpLuna(); +BOOL IsWin8orLater(); +BOOL IsWin81orLater(); +BOOL IsDarkModeSupport(); +BOOL HasSidebar(); +#endif + +#if _MSC_VER <= 1310 +#ifdef UNICODE +BOOL IsCurrentUserLocalAdministrator(void); +BOOL IsUserAdmin(VOID); +#endif +#endif + +BOOL IsNT3(); +BOOL IsNT4(); +BOOL IsWin9x(); +BOOL IsWin95(); +BOOL IsWin95First(); +BOOL IsPC98(); +BOOL IsNT51orlater(); +BOOL IsRunningOnWine(); + +DWORD GetIeVersion(); +// DWORD GetWin10Version(); +void GetOsName(CString& osFullName, CString& osName, CString& osVersion, CString& osArchitecture); +void GetOsNameWmi(CString& osFullName); + +////------------------------------------------------ +// Define +////------------------------------------------------ + +#define PRODUCT_UNDEFINED 0x00000000 + +#define PRODUCT_ULTIMATE 0x00000001 +#define PRODUCT_HOME_BASIC 0x00000002 +#define PRODUCT_HOME_PREMIUM 0x00000003 +#define PRODUCT_ENTERPRISE 0x00000004 +#define PRODUCT_HOME_BASIC_N 0x00000005 +#define PRODUCT_BUSINESS 0x00000006 +#define PRODUCT_STANDARD_SERVER 0x00000007 +#define PRODUCT_DATACENTER_SERVER 0x00000008 +#define PRODUCT_SMALLBUSINESS_SERVER 0x00000009 +#define PRODUCT_ENTERPRISE_SERVER 0x0000000A +#define PRODUCT_STARTER 0x0000000B +#define PRODUCT_DATACENTER_SERVER_CORE 0x0000000C +#define PRODUCT_STANDARD_SERVER_CORE 0x0000000D +#define PRODUCT_ENTERPRISE_SERVER_CORE 0x0000000E +#define PRODUCT_ENTERPRISE_SERVER_IA64 0x0000000F +#define PRODUCT_BUSINESS_N 0x00000010 +#define PRODUCT_WEB_SERVER 0x00000011 +#define PRODUCT_CLUSTER_SERVER 0x00000012 +#define PRODUCT_HOME_SERVER 0x00000013 +#define PRODUCT_STORAGE_EXPRESS_SERVER 0x00000014 +#define PRODUCT_STORAGE_STANDARD_SERVER 0x00000015 +#define PRODUCT_STORAGE_WORKGROUP_SERVER 0x00000016 +#define PRODUCT_STORAGE_ENTERPRISE_SERVER 0x00000017 +#define PRODUCT_SERVER_FOR_SMALLBUSINESS 0x00000018 +#define PRODUCT_SMALLBUSINESS_SERVER_PREMIUM 0x00000019 +#define PRODUCT_HOME_PREMIUM_N 0x0000001A +#define PRODUCT_ENTERPRISE_N 0x0000001B +#define PRODUCT_ULTIMATE_N 0x0000001C +#define PRODUCT_WEB_SERVER_CORE 0x0000001D +#define PRODUCT_MEDIUMBUSINESS_SERVER_MANAGEMENT 0x0000001E +#define PRODUCT_MEDIUMBUSINESS_SERVER_SECURITY 0x0000001F +#define PRODUCT_MEDIUMBUSINESS_SERVER_MESSAGING 0x00000020 +#define PRODUCT_SERVER_FOUNDATION 0x00000021 +#define PRODUCT_HOME_PREMIUM_SERVER 0x00000022 +#define PRODUCT_SERVER_FOR_SMALLBUSINESS_V 0x00000023 +#define PRODUCT_STANDARD_SERVER_V 0x00000024 +#define PRODUCT_DATACENTER_SERVER_V 0x00000025 +#define PRODUCT_ENTERPRISE_SERVER_V 0x00000026 +#define PRODUCT_DATACENTER_SERVER_CORE_V 0x00000027 +#define PRODUCT_STANDARD_SERVER_CORE_V 0x00000028 +#define PRODUCT_ENTERPRISE_SERVER_CORE_V 0x00000029 +#define PRODUCT_HYPERV 0x0000002A +#define PRODUCT_STORAGE_EXPRESS_SERVER_CORE 0x0000002B +#define PRODUCT_STORAGE_STANDARD_SERVER_CORE 0x0000002C +#define PRODUCT_STORAGE_WORKGROUP_SERVER_CORE 0x0000002D +#define PRODUCT_STORAGE_ENTERPRISE_SERVER_CORE 0x0000002E +#define PRODUCT_STARTER_N 0x0000002F +#define PRODUCT_PROFESSIONAL 0x00000030 +#define PRODUCT_PROFESSIONAL_N 0x00000031 +#define PRODUCT_SB_SOLUTION_SERVER 0x00000032 +#define PRODUCT_SERVER_FOR_SB_SOLUTIONS 0x00000033 +#define PRODUCT_STANDARD_SERVER_SOLUTIONS 0x00000034 +#define PRODUCT_STANDARD_SERVER_SOLUTIONS_CORE 0x00000035 +#define PRODUCT_SB_SOLUTION_SERVER_EM 0x00000036 +#define PRODUCT_SERVER_FOR_SB_SOLUTIONS_EM 0x00000037 +#define PRODUCT_SOLUTION_EMBEDDEDSERVER 0x00000038 +#define PRODUCT_SOLUTION_EMBEDDEDSERVER_CORE 0x00000039 +#define PRODUCT_PROFESSIONAL_EMBEDDED 0x0000003A +#define PRODUCT_ESSENTIALBUSINESS_SERVER_MGMT 0x0000003B +#define PRODUCT_ESSENTIALBUSINESS_SERVER_ADDL 0x0000003C +#define PRODUCT_ESSENTIALBUSINESS_SERVER_MGMTSVC 0x0000003D +#define PRODUCT_ESSENTIALBUSINESS_SERVER_ADDLSVC 0x0000003E +#define PRODUCT_SMALLBUSINESS_SERVER_PREMIUM_CORE 0x0000003F +#define PRODUCT_CLUSTER_SERVER_V 0x00000040 +#define PRODUCT_EMBEDDED 0x00000041 +#define PRODUCT_STARTER_E 0x00000042 +#define PRODUCT_HOME_BASIC_E 0x00000043 +#define PRODUCT_HOME_PREMIUM_E 0x00000044 +#define PRODUCT_PROFESSIONAL_E 0x00000045 +#define PRODUCT_ENTERPRISE_E 0x00000046 +#define PRODUCT_ULTIMATE_E 0x00000047 +#define PRODUCT_ENTERPRISE_EVALUATION 0x00000048 +#define PRODUCT_MULTIPOINT_STANDARD_SERVER 0x0000004C +#define PRODUCT_MULTIPOINT_PREMIUM_SERVER 0x0000004D +#define PRODUCT_STANDARD_EVALUATION_SERVER 0x0000004F +#define PRODUCT_DATACENTER_EVALUATION_SERVER 0x00000050 +#define PRODUCT_ENTERPRISE_N_EVALUATION 0x00000054 +#define PRODUCT_EMBEDDED_AUTOMOTIVE 0x00000055 +#define PRODUCT_EMBEDDED_INDUSTRY_A 0x00000056 +#define PRODUCT_THINPC 0x00000057 +#define PRODUCT_EMBEDDED_A 0x00000058 +#define PRODUCT_EMBEDDED_INDUSTRY 0x00000059 +#define PRODUCT_EMBEDDED_E 0x0000005A +#define PRODUCT_EMBEDDED_INDUSTRY_E 0x0000005B +#define PRODUCT_EMBEDDED_INDUSTRY_A_E 0x0000005C +#define PRODUCT_STORAGE_WORKGROUP_EVALUATION_SERVER 0x0000005F +#define PRODUCT_STORAGE_STANDARD_EVALUATION_SERVER 0x00000060 +#define PRODUCT_CORE_ARM 0x00000061 +#define PRODUCT_CORE_N 0x00000062 +#define PRODUCT_CORE_COUNTRYSPECIFIC 0x00000063 +#define PRODUCT_CORE_SINGLELANGUAGE 0x00000064 +#define PRODUCT_CORE 0x00000065 +#define PRODUCT_PROFESSIONAL_WMC 0x00000067 +#define PRODUCT_EMBEDDED_INDUSTRY_EVAL 0x00000069 +#define PRODUCT_EMBEDDED_INDUSTRY_E_EVAL 0x0000006A +#define PRODUCT_EMBEDDED_EVAL 0x0000006B +#define PRODUCT_EMBEDDED_E_EVAL 0x0000006C +#define PRODUCT_NANO_SERVER 0x0000006D +#define PRODUCT_CLOUD_STORAGE_SERVER 0x0000006E +#define PRODUCT_CORE_CONNECTED 0x0000006F +#define PRODUCT_PROFESSIONAL_STUDENT 0x00000070 +#define PRODUCT_CORE_CONNECTED_N 0x00000071 +#define PRODUCT_PROFESSIONAL_STUDENT_N 0x00000072 +#define PRODUCT_CORE_CONNECTED_SINGLELANGUAGE 0x00000073 +#define PRODUCT_CORE_CONNECTED_COUNTRYSPECIFIC 0x00000074 +#define PRODUCT_CONNECTED_CAR 0x00000075 +#define PRODUCT_INDUSTRY_HANDHELD 0x00000076 +#define PRODUCT_PPI_PRO 0x00000077 +#define PRODUCT_ARM64_SERVER 0x00000078 +#define PRODUCT_EDUCATION 0x00000079 +#define PRODUCT_EDUCATION_N 0x0000007A +#define PRODUCT_IOTUAP 0x0000007B +#define PRODUCT_CLOUD_HOST_INFRASTRUCTURE_SERVER 0x0000007C +#define PRODUCT_ENTERPRISE_S 0x0000007D +#define PRODUCT_ENTERPRISE_S_N 0x0000007E +#define PRODUCT_PROFESSIONAL_S 0x0000007F +#define PRODUCT_PROFESSIONAL_S_N 0x00000080 +#define PRODUCT_ENTERPRISE_S_EVALUATION 0x00000081 +#define PRODUCT_ENTERPRISE_S_N_EVALUATION 0x00000082 +#define PRODUCT_HOLOGRAPHIC 0x00000087 +#define PRODUCT_HOLOGRAPHIC_BUSINESS 0x00000088 +#define PRODUCT_PRO_SINGLE_LANGUAGE 0x0000008A +#define PRODUCT_PRO_CHINA 0x0000008B +#define PRODUCT_ENTERPRISE_SUBSCRIPTION 0x0000008C +#define PRODUCT_ENTERPRISE_SUBSCRIPTION_N 0x0000008D +#define PRODUCT_DATACENTER_NANO_SERVER 0x0000008F +#define PRODUCT_STANDARD_NANO_SERVER 0x00000090 +#define PRODUCT_DATACENTER_A_SERVER_CORE 0x00000091 +#define PRODUCT_STANDARD_A_SERVER_CORE 0x00000092 +#define PRODUCT_DATACENTER_WS_SERVER_CORE 0x00000093 +#define PRODUCT_STANDARD_WS_SERVER_CORE 0x00000094 +#define PRODUCT_UTILITY_VM 0x00000095 +#define PRODUCT_DATACENTER_EVALUATION_SERVER_CORE 0x0000009F +#define PRODUCT_STANDARD_EVALUATION_SERVER_CORE 0x000000A0 +#define PRODUCT_PRO_WORKSTATION 0x000000A1 +#define PRODUCT_PRO_WORKSTATION_N 0x000000A2 +#define PRODUCT_PRO_FOR_EDUCATION 0x000000A4 +#define PRODUCT_PRO_FOR_EDUCATION_N 0x000000A5 +#define PRODUCT_AZURE_SERVER_CORE 0x000000A8 +#define PRODUCT_AZURE_NANO_SERVER 0x000000A9 +#define PRODUCT_ENTERPRISEG 0x000000AB +#define PRODUCT_ENTERPRISEGN 0x000000AC +#define PRODUCT_SERVERRDSH 0x000000AF +#define PRODUCT_CLOUD 0x000000B2 +#define PRODUCT_CLOUDN 0x000000B3 +#define PRODUCT_HUBOS 0x000000B4 +#define PRODUCT_ONECOREUPDATEOS 0x000000B6 +#define PRODUCT_CLOUDE 0x000000B7 +#define PRODUCT_IOTOS 0x000000B9 +#define PRODUCT_CLOUDEN 0x000000BA +#define PRODUCT_IOTEDGEOS 0x000000BB +#define PRODUCT_IOTENTERPRISE 0x000000BC +#define PRODUCT_LITE 0x000000BD +#define PRODUCT_IOTENTERPRISES 0x000000BF +#define PRODUCT_XBOX_SYSTEMOS 0x000000C0 +#define PRODUCT_XBOX_GAMEOS 0x000000C2 +#define PRODUCT_XBOX_ERAOS 0x000000C3 +#define PRODUCT_XBOX_DURANGOHOSTOS 0x000000C4 +#define PRODUCT_XBOX_SCARLETTHOSTOS 0x000000C5 +#define PRODUCT_XBOX_KEYSTONE 0x000000C6 +#define PRODUCT_AZURE_SERVER_CLOUDHOST 0x000000C7 +#define PRODUCT_AZURE_SERVER_CLOUDMOS 0x000000C8 +#define PRODUCT_CLOUDEDITIONN 0x000000CA +#define PRODUCT_CLOUDEDITION 0x000000CB +#define PRODUCT_AZURESTACKHCI_SERVER_CORE 0x00000196 +#define PRODUCT_DATACENTER_SERVER_AZURE_EDITION 0x00000197 +#define PRODUCT_DATACENTER_SERVER_CORE_AZURE_EDITION 0x00000198 + +#define PRODUCT_UNLICENSED 0xABCDABCD + +// ChatGPT... +#define PRODUCT_ENTERPRISE_G 0x00000067 +#define PRODUCT_PROFESSIONAL_WORKSTATION 0x000000B5 +#define PRODUCT_PROFESSIONAL_WORKSTATION_N 0x000000B6 + +#define SM_TABLETPC 86 +#define SM_MEDIACENTER 87 +#define SM_STARTER 88 +#define SM_SERVERR2 89 diff --git a/CristalDiskMark/source/CrystalDiskMark/Priscilla/ScrollBarFx.cpp b/CristalDiskMark/source/CrystalDiskMark/Priscilla/ScrollBarFx.cpp new file mode 100644 index 0000000..86ec12c --- /dev/null +++ b/CristalDiskMark/source/CrystalDiskMark/Priscilla/ScrollBarFx.cpp @@ -0,0 +1,93 @@ +/*---------------------------------------------------------------------------*/ +// Author : hiyohiyo +// Mail : hiyohiyo@crystalmark.info +// Web : https://crystalmark.info/ +// License : The MIT License +/*---------------------------------------------------------------------------*/ + +#include "../stdafx.h" +#include "ScrollBarFx.h" +#include "OsInfoFx.h" + +CScrollBarFx::CScrollBarFx() +{ + m_X = 0; + m_Y = 0; + m_BkDC = NULL; + m_RenderMode = SystemDraw; + m_bHighContrast = FALSE; + m_bDarkMode = FALSE; +} + +CScrollBarFx::~CScrollBarFx() +{ + m_BkBrush.DeleteObject(); +} + +IMPLEMENT_DYNAMIC(CScrollBarFx, CScrollBar) + +BEGIN_MESSAGE_MAP(CScrollBarFx, CScrollBar) + //{{AFX_MSG_MAP(CScrollBarFx) + ON_WM_HSCROLL_REFLECT() + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +BOOL CScrollBarFx::InitControl(int x, int y, int width, int height, double zoomRatio, CDC* bkDC, int renderMode, BOOL bHighContrast, BOOL bDarkMode, int min, int max, int pos) +{ + m_X = (int)(x * zoomRatio); + m_Y = (int)(y * zoomRatio); + m_CtrlSize.cx = (int)(width * zoomRatio); + m_CtrlSize.cy = (int)(height * zoomRatio); + MoveWindow(m_X, m_Y, m_CtrlSize.cx, m_CtrlSize.cy); + + m_BkDC = bkDC; + m_RenderMode = renderMode; + m_bHighContrast = bHighContrast; + m_bDarkMode = bDarkMode; + + // BkBrush + m_BkBrush.DeleteObject(); + if (bDarkMode) + { + m_BkBrush.CreateSolidBrush(RGB(32, 32, 32)); + } + else + { + m_BkBrush.CreateSolidBrush(RGB(255, 255, 255)); + } + + SetScrollRange(min, max, TRUE); + SetScrollPos(pos); + + Invalidate(); + + return TRUE; +} + +void CScrollBarFx::HScroll(UINT nSBCode, UINT nPos) +{ + int position = GetScrollPos(); + switch (nSBCode) + { + case SB_LINELEFT: + position -= 1; + break; + case SB_LINERIGHT: + position += 1; + break; + case SB_PAGELEFT: + position -= 5; + break; + case SB_PAGERIGHT: + position += 5; + break; + case SB_LEFT: + break; + case SB_RIGHT: + break; + case SB_THUMBTRACK: + position = nPos; + break; + } + SetScrollPos(position); +} \ No newline at end of file diff --git a/CristalDiskMark/source/CrystalDiskMark/Priscilla/ScrollBarFx.h b/CristalDiskMark/source/CrystalDiskMark/Priscilla/ScrollBarFx.h new file mode 100644 index 0000000..bfa2a2a --- /dev/null +++ b/CristalDiskMark/source/CrystalDiskMark/Priscilla/ScrollBarFx.h @@ -0,0 +1,40 @@ +/*---------------------------------------------------------------------------*/ +// Author : hiyohiyo +// Mail : hiyohiyo@crystalmark.info +// Web : https://crystalmark.info/ +// License : The MIT License +/*---------------------------------------------------------------------------*/ + +#pragma once + +#include "CommonFx.h" +#include +#include +#pragma comment(lib, "Gdiplus.lib") +using namespace Gdiplus; + +class CScrollBarFx : public CScrollBar +{ + DECLARE_DYNAMIC(CScrollBarFx) + +public: + CScrollBarFx(); + virtual ~CScrollBarFx(); + BOOL InitControl(int x, int y, int width, int height, double zoomRatio, CDC* bkDC, int renderMode, BOOL bHighContrast, BOOL bDarkMode, int min, int max, int pos); + + BOOL m_bHighContrast; + CBrush m_BkBrush; + +protected: + DECLARE_MESSAGE_MAP() + afx_msg void HScroll(UINT nSBCode, UINT nPos); + + int m_X; + int m_Y; + CSize m_CtrlSize; + CRect m_Margin; + int m_RenderMode; + BOOL m_bDarkMode; + CDC* m_BkDC; +}; + diff --git a/CristalDiskMark/source/CrystalDiskMark/Priscilla/SliderCtrlFx.cpp b/CristalDiskMark/source/CrystalDiskMark/Priscilla/SliderCtrlFx.cpp new file mode 100644 index 0000000..003eab9 --- /dev/null +++ b/CristalDiskMark/source/CrystalDiskMark/Priscilla/SliderCtrlFx.cpp @@ -0,0 +1,129 @@ +/*---------------------------------------------------------------------------*/ +// Author : hiyohiyo +// Mail : hiyohiyo@crystalmark.info +// Web : https://crystalmark.info/ +// License : MIT License +/*---------------------------------------------------------------------------*/ + +#include "stdafx.h" +#include "SliderCtrlFx.h" +#include "OsInfoFx.h" + +IMPLEMENT_DYNAMIC(CSliderCtrlFx, CSliderCtrl) + +CSliderCtrlFx::CSliderCtrlFx() +{ + m_X = 0; + m_Y = 0; + m_BkDC = NULL; + m_RenderMode = SystemDraw; + m_bHighContrast = FALSE; + m_bDarkMode = FALSE; + m_bBkBitmapInit = FALSE; +} + +CSliderCtrlFx::~CSliderCtrlFx() +{ + m_BkBrush.DeleteObject(); +} + +BEGIN_MESSAGE_MAP(CSliderCtrlFx, CSliderCtrl) + ON_WM_KEYDOWN() +END_MESSAGE_MAP() + +BOOL CSliderCtrlFx::InitControl(int x, int y, int width, int height, double zoomRatio, CDC* bkDC, int renderMode, BOOL bHighContrast, BOOL bDarkMode, int min, int max, int pos) +{ + m_X = (int)(x * zoomRatio); + m_Y = (int)(y * zoomRatio); + m_CtrlSize.cx = (int)(width * zoomRatio); + m_CtrlSize.cy = (int)(height * zoomRatio); + MoveWindow(m_X, m_Y, m_CtrlSize.cx, m_CtrlSize.cy); + SendMessage(TBM_SETTHUMBLENGTH, m_CtrlSize.cy, 0); + + m_BkDC = bkDC; + m_RenderMode = renderMode; + m_bHighContrast = bHighContrast; + m_bDarkMode = bDarkMode; + + SetBkReload(); + LoadCtrlBk(bkDC); + m_BkBrush.DeleteObject(); + if (bDarkMode) + { + // m_BkBrush.CreateSolidBrush(RGB(32, 32, 32)); + m_BkBrush.CreatePatternBrush(&m_BkBitmap); + } + else + { + // m_BkBrush.CreateSolidBrush(RGB(255, 255, 255)); + m_BkBrush.CreatePatternBrush(&m_BkBitmap); + } + + // Range, Pos + SetRange(min, max, TRUE); + SetPos(pos); + + Invalidate(); + + return TRUE; +} + +void CSliderCtrlFx::SetBkReload(void) +{ + m_bBkBitmapInit = FALSE; + m_bBkLoad = FALSE; +} + +void CSliderCtrlFx::LoadCtrlBk(CDC* drawDC) +{ + if (m_bHighContrast) { SetBkReload(); return; } + + if (m_BkBitmap.m_hObject != NULL) + { + BITMAP bitmapInfo; + m_BkBitmap.GetBitmap(&bitmapInfo); + if (bitmapInfo.bmBitsPixel != drawDC->GetDeviceCaps(BITSPIXEL)) + { + SetBkReload(); + } + } + + if (&m_CtrlBitmap != NULL) + { + if (!m_bBkBitmapInit) + { + m_BkBitmap.DeleteObject(); + m_BkBitmap.CreateCompatibleBitmap(drawDC, m_CtrlSize.cx, m_CtrlSize.cy); + m_bBkBitmapInit = TRUE; + } + + if (!m_bBkLoad) + { + CBitmap* pOldBitmap; + CDC* pMemDC = new CDC; + pMemDC->CreateCompatibleDC(drawDC); + pOldBitmap = pMemDC->SelectObject(&m_BkBitmap); + pMemDC->BitBlt(0, 0, m_CtrlSize.cx, m_CtrlSize.cy, m_BkDC, m_X, m_Y, SRCCOPY); + pMemDC->SelectObject(pOldBitmap); + pMemDC->DeleteDC(); + delete pMemDC; + m_bBkLoad = TRUE; + } + } +} + +void CSliderCtrlFx::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) +{ + if (nChar == VK_UP) + { + PostMessage(WM_KEYDOWN, VK_RIGHT, nFlags); + return; + } + else if (nChar == VK_DOWN) + { + PostMessage(WM_KEYDOWN, VK_LEFT, nFlags); + return; + } + + CSliderCtrl::OnKeyDown(nChar, nRepCnt, nFlags); +} \ No newline at end of file diff --git a/CristalDiskMark/source/CrystalDiskMark/Priscilla/SliderCtrlFx.h b/CristalDiskMark/source/CrystalDiskMark/Priscilla/SliderCtrlFx.h new file mode 100644 index 0000000..d0dfa43 --- /dev/null +++ b/CristalDiskMark/source/CrystalDiskMark/Priscilla/SliderCtrlFx.h @@ -0,0 +1,48 @@ +/*---------------------------------------------------------------------------*/ +// Author : hiyohiyo +// Mail : hiyohiyo@crystalmark.info +// Web : https://crystalmark.info/ +// License : MIT License +/*---------------------------------------------------------------------------*/ + +#pragma once + +#include "ImageFx.h" + +class CSliderCtrlFx : public CSliderCtrl +{ + DECLARE_DYNAMIC(CSliderCtrlFx) + +public: + CSliderCtrlFx(); + virtual ~CSliderCtrlFx(); + BOOL InitControl(int x, int y, int width, int height, double zoomRatio, CDC* bkDC, int renderMode, BOOL bHighContrast, BOOL bDarkMode, int min, int max, int pos); + + BOOL m_bHighContrast{}; + CBrush m_BkBrush; + +protected: + // Message Map + DECLARE_MESSAGE_MAP() + afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags); + + // Image + void SetBkReload(void); + void LoadCtrlBk(CDC* drawDC); + + int m_X{}; + int m_Y{}; + CSize m_CtrlSize; + CRect m_Margin; + int m_RenderMode{}; + BOOL m_bDarkMode{}; + + // Image + CDC* m_BkDC; + CBitmap m_BkBitmap; + BOOL m_bBkBitmapInit{}; + BOOL m_bBkLoad{}; + CBitmap m_CtrlBitmap; + CImage m_CtrlImage; +}; + diff --git a/CristalDiskMark/source/CrystalDiskMark/Priscilla/StaticFx.cpp b/CristalDiskMark/source/CrystalDiskMark/Priscilla/StaticFx.cpp new file mode 100644 index 0000000..e7c8881 --- /dev/null +++ b/CristalDiskMark/source/CrystalDiskMark/Priscilla/StaticFx.cpp @@ -0,0 +1,917 @@ +/*---------------------------------------------------------------------------*/ +// Author : hiyohiyo +// Mail : hiyohiyo@crystalmark.info +// Web : https://crystalmark.info/ +// License : MIT License +/*---------------------------------------------------------------------------*/ + +#include "stdafx.h" +#include "StaticFx.h" + +#if _MSC_VER <= 1310 +#define ON_WM_MOUSEHOVER() \ + { 0x2A1 /*WM_MOUSEHOVER*/, 0, 0, 0, AfxSig_vwp, \ + (AFX_PMSG)(AFX_PMSGW) \ + (static_cast< void (AFX_MSG_CALL CWnd::*)(UINT, CPoint) > (OnMouseHover)) }, + +#define ON_WM_MOUSELEAVE() \ + { 0x2A3 /*WM_MOUSELEAVE*/, 0, 0, 0, AfxSig_vv, \ + (AFX_PMSG)(AFX_PMSGW) \ + (static_cast< void (AFX_MSG_CALL CWnd::*)(void) > (OnMouseLeave)) }, +#endif + +////------------------------------------------------ +// CStaticFx +////------------------------------------------------ + +CStaticFx::CStaticFx() +{ + // Control + m_X = 0; + m_Y = 0; + m_RenderMode = SystemDraw; + m_bHighContrast = FALSE; + m_bDarkMode = FALSE; + m_DrawFrame = FALSE; + m_bDrawFrameEx = FALSE; + m_FrameColor = RGB(128, 128, 128); + m_hPal = NULL; + + // Glass + m_GlassColor = RGB(255, 255, 255); + m_GlassAlpha = 255; + + // Meter + m_bMeter = FALSE; + m_MeterRatio = 0.0; + + // Image + m_ImageCount = 0; + m_BkDC = NULL; + m_bBkBitmapInit = FALSE; + m_bBkLoad = FALSE; + + // Font + m_TextAlign = SS_LEFT; + m_TextColor = RGB(0, 0, 0); + + // Mouse + m_bHover = FALSE; + m_bFocas = FALSE; + m_bTrackingNow = FALSE; + m_bHandCursor = FALSE; + + // Text Format + m_TextFormat = 0; + m_LabelFormat = DT_LEFT | DT_TOP | DT_SINGLELINE; + m_UnitFormat = DT_RIGHT | DT_BOTTOM | DT_SINGLELINE; + + // Margin + m_Margin.top = 0; + m_Margin.left = 0; + m_Margin.bottom = 0; + m_Margin.right = 0; +} + +CStaticFx::~CStaticFx() +{ +} + +IMPLEMENT_DYNAMIC(CStaticFx, CStatic) + +BEGIN_MESSAGE_MAP(CStaticFx, CStatic) + //{{AFX_MSG_MAP(CStaticFx) + ON_WM_ERASEBKGND() + ON_WM_MOUSEMOVE() + ON_WM_MOUSEHOVER() + ON_WM_MOUSELEAVE() + ON_WM_KILLFOCUS() + ON_WM_SETFOCUS() + ON_WM_SETCURSOR() + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +//------------------------------------------------ +// Control +//------------------------------------------------ + +BOOL CStaticFx::InitControl(int x, int y, int width, int height, double zoomRatio, HPALETTE hPal, CDC* bkDC, + LPCTSTR imagePath, int imageCount, DWORD textAlign, int renderMode, BOOL bHighContrast, BOOL bDarkMode, DWORD drawFrame) +{ + m_X = (int)(x * zoomRatio); + m_Y = (int)(y * zoomRatio); + m_CtrlSize.cx = (int)(width * zoomRatio); + m_CtrlSize.cy = (int)(height * zoomRatio); + MoveWindow(m_X, m_Y, m_CtrlSize.cx, m_CtrlSize.cy); + + m_hPal = hPal; + m_BkDC = bkDC; + m_ImagePath = imagePath; + m_ImageCount = imageCount; + m_RenderMode = renderMode; + + if (SS_LEFT <= textAlign && textAlign <= SS_RIGHT) + { + m_TextAlign = textAlign; + } + + if (m_ToolTip.m_hWnd != NULL) + { + if (m_ToolTip.GetToolCount() != 0) + { + m_ToolTip.DelTool(this, 1); + } + CRect rect; + GetClientRect(rect); + m_ToolTip.AddTool(this, m_ToolTipText, rect, 1); + } + + m_bHighContrast = bHighContrast; + m_bDarkMode = bDarkMode; + m_DrawFrame = drawFrame; + + if (m_bHighContrast) + { + ModifyStyle(SS_OWNERDRAW, m_TextAlign | SS_CENTERIMAGE); + + return TRUE; + } + else if (renderMode & SystemDraw) + { + ModifyStyle(SS_OWNERDRAW, m_TextAlign | SS_CENTERIMAGE); + + return TRUE; + } + else + { + SetBkReload(); + ModifyStyle(m_TextAlign | SS_CENTERIMAGE, SS_OWNERDRAW); + } + + if (renderMode & OwnerDrawImage) + { + if (!LoadBitmap(imagePath)) + { + ModifyStyle(SS_OWNERDRAW, m_TextAlign); + } + } + else + { + m_ImageCount = 1; + m_CtrlImage.Destroy(); + m_CtrlImage.Create(m_CtrlSize.cx, m_CtrlSize.cy * m_ImageCount, 32); + m_CtrlBitmap.Detach(); + m_CtrlBitmap.Attach((HBITMAP)m_CtrlImage); + DWORD length = m_CtrlSize.cx * m_CtrlSize.cy * m_ImageCount * 4; + BYTE* bitmapBits = new BYTE[length]; + m_CtrlBitmap.GetBitmapBits(length, bitmapBits); + + BYTE r, g, b, a; + if (renderMode & OwnerDrawGlass) + { + r = (BYTE)GetRValue(m_GlassColor); + g = (BYTE)GetGValue(m_GlassColor); + b = (BYTE)GetBValue(m_GlassColor); + a = m_GlassAlpha; + } + else // OwnerDrawTransparent + { + r = 0; + g = 0; + b = 0; + a = 0; + } + + for (int y = 0; y < (int)(m_CtrlSize.cy * m_ImageCount); y++) + { + for (int x = 0; x < m_CtrlSize.cx; x++) + { + DWORD p = (y * m_CtrlSize.cx + x) * 4; +#if _MSC_VER > 1310 +#pragma warning( disable : 6386 ) +#endif + bitmapBits[p + 0] = b; + bitmapBits[p + 1] = g; + bitmapBits[p + 2] = r; + bitmapBits[p + 3] = a; +#if _MSC_VER > 1310 +#pragma warning( default : 6386 ) +#endif + } + } + + m_CtrlBitmap.SetBitmapBits(length, bitmapBits); + delete[] bitmapBits; + } + + Invalidate(); + + return TRUE; +} + +void CStaticFx::SetMargin(int top, int left, int bottom, int right, double zoomRatio) +{ + m_Margin.top = (int)(top * zoomRatio); + m_Margin.left = (int)(left * zoomRatio); + m_Margin.bottom = (int)(bottom * zoomRatio); + m_Margin.right = (int)(right * zoomRatio); +} + +CSize CStaticFx::GetSize(void) +{ + return m_CtrlSize; +} + +void CStaticFx::SetDrawFrame(BOOL drawFrame) +{ + if (drawFrame && m_bHighContrast) + { + ModifyStyleEx(0, WS_EX_STATICEDGE, SWP_DRAWFRAME); + } + else + { + ModifyStyleEx(WS_EX_STATICEDGE, 0, SWP_DRAWFRAME); + } + m_DrawFrame = drawFrame; +} + +void CStaticFx::SetDrawFrameEx(BOOL bDrawFrameEx, COLORREF frameColor) +{ + m_bDrawFrameEx = bDrawFrameEx; + m_FrameColor = frameColor; +} + +void CStaticFx::SetGlassColor(COLORREF glassColor, BYTE glassAlpha) +{ + m_GlassColor = glassColor; + m_GlassAlpha = glassAlpha; +} + +void CStaticFx::SetMeter(BOOL bMeter, double meterRatio) +{ + m_bMeter = bMeter; + if (meterRatio > 1.0) + { + m_MeterRatio = 1.0; + } + else if (meterRatio > 0) + { + m_MeterRatio = meterRatio; + } + else + { + m_MeterRatio = 0.0; + } + + Invalidate(); +} + +void CStaticFx::SetLabelUnit(CString label, CString unit) +{ + m_Label = label; + m_Unit = unit; +} + +void CStaticFx::SetLabelUnitFormat(UINT labelFormat, UINT unitFormat) +{ + m_LabelFormat = labelFormat; + m_UnitFormat = unitFormat; +} + +void CStaticFx::SetTextFormat(UINT format) +{ + m_TextFormat = format; +} + +//------------------------------------------------ +// Draw Control +//------------------------------------------------ + +void CStaticFx::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) +{ + CDC* drawDC = CDC::FromHandle(lpDrawItemStruct->hDC); + LoadCtrlBk(drawDC); + + DrawControl(drawDC, lpDrawItemStruct, m_CtrlBitmap, m_BkBitmap, ControlImageNormal); +} + +void CStaticFx::DrawControl(CDC* drawDC, LPDRAWITEMSTRUCT lpDrawItemStruct, CBitmap& ctrlBitmap, CBitmap& bkBitmap, int no) +{ + CDC* pMemDC = new CDC; + CBitmap* pOldMemBitmap; + if(m_hPal && drawDC->GetDeviceCaps(RASTERCAPS) & RC_PALETTE) + { + SelectPalette( drawDC->GetSafeHdc(), m_hPal, FALSE ); + drawDC->RealizePalette(); + drawDC->SetStretchBltMode(HALFTONE); + } + pMemDC->CreateCompatibleDC(drawDC); + if(m_hPal && pMemDC->GetDeviceCaps(RASTERCAPS) & RC_PALETTE) + { + SelectPalette( pMemDC->GetSafeHdc(), m_hPal, FALSE ); + pMemDC->RealizePalette(); + pMemDC->SetStretchBltMode(HALFTONE); + } + pOldMemBitmap = pMemDC->SelectObject(&ctrlBitmap); + CDC* pBkDC = new CDC; + CBitmap* pOldBkBitmap; + pBkDC->CreateCompatibleDC(drawDC); + if(m_hPal && pBkDC->GetDeviceCaps(RASTERCAPS) & RC_PALETTE) + { + SelectPalette( pBkDC->GetSafeHdc(), m_hPal, FALSE ); + pBkDC->RealizePalette(); + pBkDC->SetStretchBltMode(HALFTONE); + } + pOldBkBitmap = pBkDC->SelectObject(&bkBitmap); + + CBitmap DrawBmp; + DrawBmp.CreateCompatibleBitmap(drawDC, m_CtrlSize.cx, m_CtrlSize.cy); + CDC* pDrawBmpDC = new CDC; + CBitmap* pOldDrawBitmap; + pDrawBmpDC->CreateCompatibleDC(drawDC); + if(m_hPal && pDrawBmpDC->GetDeviceCaps(RASTERCAPS) & RC_PALETTE) + { + SelectPalette( pDrawBmpDC->GetSafeHdc(), m_hPal, FALSE ); + pDrawBmpDC->RealizePalette(); + pDrawBmpDC->SetStretchBltMode(HALFTONE); + } + pOldDrawBitmap = pDrawBmpDC->SelectObject(&DrawBmp); + + int color = drawDC->GetDeviceCaps(BITSPIXEL) * drawDC->GetDeviceCaps(PLANES); + + if (!m_CtrlImage.IsNull()) + { + if (m_CtrlImage.GetBPP() == 32) + { + CBitmap* bk32Bitmap; + CImage bk32Image; + if (color == 32) + { + bk32Bitmap = &bkBitmap; + } + else + { + bk32Image.Create(m_CtrlSize.cx, m_CtrlSize.cy, 32); + ::StretchBlt(bk32Image.GetDC(), 0, 0, m_CtrlSize.cx, m_CtrlSize.cy, *pBkDC, 0, 0, m_CtrlSize.cx, m_CtrlSize.cy, SRCCOPY); + bk32Bitmap = CBitmap::FromHandle((HBITMAP)bk32Image); + } + + BITMAP CtlBmpInfo, DstBmpInfo; + bk32Bitmap->GetBitmap(&DstBmpInfo); + DWORD DstLineBytes = DstBmpInfo.bmWidthBytes; + DWORD DstMemSize = DstLineBytes * DstBmpInfo.bmHeight; + ctrlBitmap.GetBitmap(&CtlBmpInfo); + DWORD CtlLineBytes = CtlBmpInfo.bmWidthBytes; + DWORD CtlMemSize = CtlLineBytes * CtlBmpInfo.bmHeight; + + if ((DstBmpInfo.bmWidthBytes != CtlBmpInfo.bmWidthBytes) + || (DstBmpInfo.bmHeight != CtlBmpInfo.bmHeight / m_ImageCount)) + { + // Error Check // + } + else + { + BYTE* DstBuffer = new BYTE[DstMemSize]; + bk32Bitmap->GetBitmapBits(DstMemSize, DstBuffer); + BYTE* CtlBuffer = new BYTE[CtlMemSize]; + ctrlBitmap.GetBitmapBits(CtlMemSize, CtlBuffer); + + if (m_bMeter) + { + int meter = (int)(m_CtrlSize.cx * m_MeterRatio); + int baseY; + baseY = m_CtrlSize.cy; + for (LONG py = 0; py < DstBmpInfo.bmHeight; py++) + { + int dn = py * DstLineBytes; + int cn = (baseY + py) * CtlLineBytes; + for (LONG px = 0; px < meter; px++) + { + BYTE a = CtlBuffer[cn + 3]; + BYTE na = 255 - a; + DstBuffer[dn + 0] = (BYTE)((CtlBuffer[cn + 0] * a + DstBuffer[dn + 0] * na) / 255); + DstBuffer[dn + 1] = (BYTE)((CtlBuffer[cn + 1] * a + DstBuffer[dn + 1] * na) / 255); + DstBuffer[dn + 2] = (BYTE)((CtlBuffer[cn + 2] * a + DstBuffer[dn + 2] * na) / 255); + DstBuffer[dn + 3] = 255; + dn += (DstBmpInfo.bmBitsPixel / 8); + cn += (CtlBmpInfo.bmBitsPixel / 8); + } + cn -= baseY * CtlLineBytes; + for (LONG px = meter; px < DstBmpInfo.bmWidth; px++) + { + BYTE a = CtlBuffer[cn + 3]; + BYTE na = 255 - a; + DstBuffer[dn + 0] = (BYTE)((CtlBuffer[cn + 0] * a + DstBuffer[dn + 0] * na) / 255); + DstBuffer[dn + 1] = (BYTE)((CtlBuffer[cn + 1] * a + DstBuffer[dn + 1] * na) / 255); + DstBuffer[dn + 2] = (BYTE)((CtlBuffer[cn + 2] * a + DstBuffer[dn + 2] * na) / 255); + DstBuffer[dn + 3] = 255; + dn += (DstBmpInfo.bmBitsPixel / 8); + cn += (CtlBmpInfo.bmBitsPixel / 8); + } + } + } + else + { + int baseY = m_CtrlSize.cy * no; + for (LONG py = 0; py < DstBmpInfo.bmHeight; py++) + { + int dn = py * DstLineBytes; + int cn = (baseY + py) * CtlLineBytes; + for (LONG px = 0; px < DstBmpInfo.bmWidth; px++) + { +#if _MSC_VER > 1310 +#pragma warning( disable : 6385 ) +#pragma warning( disable : 6386 ) +#endif + BYTE a = CtlBuffer[cn + 3]; + BYTE na = 255 - a; + DstBuffer[dn + 0] = (BYTE)((CtlBuffer[cn + 0] * a + DstBuffer[dn + 0] * na) / 255); + DstBuffer[dn + 1] = (BYTE)((CtlBuffer[cn + 1] * a + DstBuffer[dn + 1] * na) / 255); + DstBuffer[dn + 2] = (BYTE)((CtlBuffer[cn + 2] * a + DstBuffer[dn + 2] * na) / 255); + DstBuffer[dn + 3] = 255; + dn += (DstBmpInfo.bmBitsPixel / 8); + cn += (CtlBmpInfo.bmBitsPixel / 8); +#if _MSC_VER > 1310 +#pragma warning( default : 6386 ) +#pragma warning( default : 6385 ) +#endif + } + } + } + + if (color == 32) + { + DrawBmp.SetBitmapBits(DstMemSize, DstBuffer); + } + else + { + bk32Bitmap->SetBitmapBits(DstMemSize, DstBuffer); + ::StretchBlt(pDrawBmpDC->GetSafeHdc(), 0, 0, m_CtrlSize.cx, m_CtrlSize.cy, bk32Image.GetDC(), 0, 0, m_CtrlSize.cx, m_CtrlSize.cy, SRCCOPY); + bk32Image.ReleaseDC(); + } + DrawString(pDrawBmpDC, lpDrawItemStruct); + drawDC->StretchBlt(0, 0, m_CtrlSize.cx, m_CtrlSize.cy, pDrawBmpDC, 0, 0, m_CtrlSize.cx, m_CtrlSize.cy, SRCCOPY); + + delete[] DstBuffer; + delete[] CtlBuffer; + } + } + else + { + if (m_bMeter) + { + int meter = (int)(m_CtrlSize.cx * (m_MeterRatio)); + pDrawBmpDC->StretchBlt(meter, 0, m_CtrlSize.cx - meter, m_CtrlSize.cy, pMemDC, meter, m_CtrlSize.cy * 0, m_CtrlSize.cx - meter, m_CtrlSize.cy, SRCCOPY); + pDrawBmpDC->StretchBlt(0, 0, meter, m_CtrlSize.cy, pMemDC, 0, m_CtrlSize.cy * 1, meter, m_CtrlSize.cy, SRCCOPY); + DrawString(pDrawBmpDC, lpDrawItemStruct); + drawDC->StretchBlt(0, 0, m_CtrlSize.cx, m_CtrlSize.cy, pDrawBmpDC, 0, 0, m_CtrlSize.cx, m_CtrlSize.cy, SRCCOPY); + } + else + { + pDrawBmpDC->StretchBlt(0, 0, m_CtrlSize.cx, m_CtrlSize.cy, pMemDC, 0, m_CtrlSize.cy* no, m_CtrlSize.cx, m_CtrlSize.cy, SRCCOPY); + DrawString(pDrawBmpDC, lpDrawItemStruct); + drawDC->StretchBlt(0, 0, m_CtrlSize.cx, m_CtrlSize.cy, pDrawBmpDC, 0, 0, m_CtrlSize.cx, m_CtrlSize.cy, SRCCOPY); + } + } + } + else + { + pDrawBmpDC->StretchBlt(0, 0, m_CtrlSize.cx, m_CtrlSize.cy, pBkDC, 0, m_CtrlSize.cy* no, m_CtrlSize.cx, m_CtrlSize.cy, SRCCOPY); + DrawString(pDrawBmpDC, lpDrawItemStruct); + drawDC->StretchBlt(0, 0, m_CtrlSize.cx, m_CtrlSize.cy, pDrawBmpDC, 0, 0, m_CtrlSize.cx, m_CtrlSize.cy, SRCCOPY); + } + + + if (m_DrawFrame == Border::UNDERLINE) + { + HGDIOBJ oldPen; + POINT point; + CPen pen1; + COLORREF frameColor; + if (m_bDarkMode){frameColor = RGB(0x29, 0x2B, 0x2F);} // Windows 11 color + else{ frameColor = RGB(0xCC, 0xCC, 0xCC);} + pen1.CreatePen(PS_SOLID, 1, frameColor); + + oldPen = SelectObject(drawDC->m_hDC, pen1); + MoveToEx(drawDC->m_hDC, 0, m_CtrlSize.cy - 1, &point); + LineTo(drawDC->m_hDC, m_CtrlSize.cx - 1, m_CtrlSize.cy - 1); + LineTo(drawDC->m_hDC, 0, m_CtrlSize.cy - 1); + SelectObject(drawDC->m_hDC, oldPen); + + pen1.DeleteObject(); + } + else if (m_DrawFrame) + { + HGDIOBJ oldPen; + POINT point; + CPen pen1; pen1.CreatePen(PS_SOLID, 1, RGB(0xF8, 0xF8, 0xF8)); + CPen pen2; pen2.CreatePen(PS_SOLID, 1, RGB(0x98, 0x98, 0x98)); + + oldPen = SelectObject(drawDC->m_hDC, pen1); + MoveToEx(drawDC->m_hDC, 0, m_CtrlSize.cy - 1, &point); + LineTo(drawDC->m_hDC, m_CtrlSize.cx - 1, m_CtrlSize.cy - 1); + LineTo(drawDC->m_hDC, m_CtrlSize.cx - 1, 0); + LineTo(drawDC->m_hDC, m_CtrlSize.cx - 1, m_CtrlSize.cy - 1); + SelectObject(drawDC->m_hDC, pen2); + MoveToEx(drawDC->m_hDC, 0, m_CtrlSize.cy - 2, &point); + LineTo(drawDC->m_hDC, 0, 0); + LineTo(drawDC->m_hDC, m_CtrlSize.cx - 1, 0); + SelectObject(drawDC->m_hDC, oldPen); + + pen1.DeleteObject(); + pen2.DeleteObject(); + } + + pDrawBmpDC->SelectObject(&pOldDrawBitmap); + pDrawBmpDC->DeleteDC(); + delete pDrawBmpDC; + pMemDC->SelectObject(&pOldMemBitmap); + pMemDC->DeleteDC(); + delete pMemDC; + pBkDC->SelectObject(&pOldBkBitmap); + pBkDC->DeleteDC(); + delete pBkDC; + + if (m_bDrawFrameEx) + { + CBrush brush; + brush.CreateSolidBrush(m_FrameColor); + drawDC->FrameRect(&(lpDrawItemStruct->rcItem), &brush); + brush.DeleteObject(); + } +} + +void CStaticFx::DrawString(CDC* drawDC, LPDRAWITEMSTRUCT lpDrawItemStruct) +{ + CString title; + GetWindowText(title); + + if (title.IsEmpty()) + { + return; + } + + drawDC->SetBkMode(TRANSPARENT); + CRect rect = (CRect)(lpDrawItemStruct->rcItem); + CRect rectControl = (CRect)(lpDrawItemStruct->rcItem); + rect.top += m_Margin.top; + rect.left += m_Margin.left; + rect.bottom -= m_Margin.bottom; + rect.right -= m_Margin.right; + + CRect rectI; + CSize extent; + HGDIOBJ oldFont = drawDC->SelectObject(m_Font); + if ((m_RenderMode & OwnerDrawTransparent) && m_bDarkMode) + { + SetTextColor(drawDC->m_hDC, RGB(255, 255, 255)); + } + else + { + SetTextColor(drawDC->m_hDC, m_TextColor); + } + extent = drawDC->GetTextExtent(title); + + if (m_bMeter && rect.Width() < extent.cx) + { + title.Replace(_T(","), _T(".")); + int score = _tstoi((LPCTSTR)title); + title.Format(_T("%d"), score); + extent = drawDC->GetTextExtent(title); + } + + if (m_TextFormat != 0) + { + drawDC->DrawText(title, title.GetLength(), rect, m_TextFormat); + drawDC->SelectObject(oldFont); + + oldFont = drawDC->SelectObject(m_FontToolTip); + drawDC->DrawText(m_Label, m_Label.GetLength(), rect, m_LabelFormat); + drawDC->DrawText(m_Unit, m_Unit.GetLength(), rect, m_UnitFormat); + } + else if (!m_Label.IsEmpty()) + { + drawDC->DrawText(title, title.GetLength(), rect, DT_CENTER | DT_VCENTER | DT_SINGLELINE); + drawDC->SelectObject(oldFont); + + oldFont = drawDC->SelectObject(m_FontToolTip); + drawDC->DrawText(m_Label, m_Label.GetLength(), rect, m_LabelFormat); + drawDC->DrawText(m_Unit, m_Unit.GetLength(), rect, m_UnitFormat); + } + else if (m_TextAlign == SS_LEFT) + { + drawDC->DrawText(title, title.GetLength(), rect, DT_LEFT | DT_VCENTER | DT_SINGLELINE); + } + else if (m_TextAlign == SS_RIGHT) + { + drawDC->DrawText(title, title.GetLength(), rect, DT_RIGHT | DT_VCENTER | DT_SINGLELINE); + } + else + { + drawDC->DrawText(title, title.GetLength(), rect, DT_CENTER | DT_VCENTER | DT_SINGLELINE); + } + + drawDC->SelectObject(oldFont); +} + +//------------------------------------------------ +// Image +//------------------------------------------------ + +BOOL CStaticFx::LoadBitmap(LPCTSTR fileName) +{ + if (m_bHighContrast) { return FALSE; } + if (fileName == NULL) { return FALSE; } + + m_CtrlImage.Destroy(); + m_CtrlImage.Load(fileName); + if (m_CtrlImage.IsNull()) { return FALSE; } + + return LoadBitmap((HBITMAP)m_CtrlImage); +} + +BOOL CStaticFx::LoadBitmap(HBITMAP hBitmap) +{ + if (m_bHighContrast) { return FALSE; } + + m_CtrlBitmap.Detach(); + m_CtrlBitmap.Attach(hBitmap); + + return SetBitmap(m_CtrlBitmap); +} + +void CStaticFx::SetBkReload(void) +{ + m_bBkBitmapInit = FALSE; + m_bBkLoad = FALSE; +} + +BOOL CStaticFx::SetBitmap(CBitmap& bitmap) +{ + if (m_bHighContrast) { return FALSE; } + + BITMAP bitmapInfo; + bitmap.GetBitmap(&bitmapInfo); + if (m_CtrlSize.cx != bitmapInfo.bmWidth + || m_CtrlSize.cy != bitmapInfo.bmHeight / m_ImageCount) + { + ModifyStyle(SS_OWNERDRAW, 0); + return FALSE; + } + else + { + ModifyStyle(0, SS_OWNERDRAW); + return TRUE; + } +} + +void CStaticFx::LoadCtrlBk(CDC* drawDC) +{ + if (m_bHighContrast) { SetBkReload(); return; } + + if (m_BkBitmap.m_hObject != NULL) + { + BITMAP bitmapInfo; + m_BkBitmap.GetBitmap(&bitmapInfo); + if (bitmapInfo.bmBitsPixel != drawDC->GetDeviceCaps(BITSPIXEL)) + { + SetBkReload(); + } + } + + if (&m_CtrlBitmap != NULL) + { + if (!m_bBkBitmapInit) + { + m_BkBitmap.DeleteObject(); + m_BkBitmap.CreateCompatibleBitmap(drawDC, m_CtrlSize.cx, m_CtrlSize.cy); + m_bBkBitmapInit = TRUE; + } + + if (!m_bBkLoad) + { + CBitmap* pOldBitmap; + CDC* pMemDC = new CDC; + pMemDC->CreateCompatibleDC(drawDC); + pOldBitmap = pMemDC->SelectObject(&m_BkBitmap); + pMemDC->StretchBlt(0, 0, m_CtrlSize.cx, m_CtrlSize.cy, m_BkDC, m_X, m_Y, m_CtrlSize.cx, m_CtrlSize.cy, SRCCOPY); + pMemDC->SelectObject(pOldBitmap); + pMemDC->DeleteDC(); + delete pMemDC; + m_bBkLoad = TRUE; + } + } +} + +//------------------------------------------------ +// Font +//------------------------------------------------ + +void CStaticFx::SetFontEx(CString face, int size, int sizeToolTip, double zoomRatio, double fontRatio, + COLORREF textColor, LONG fontWeight, BYTE fontRender) +{ + LOGFONT logFont = { 0 }; + logFont.lfCharSet = DEFAULT_CHARSET; + logFont.lfHeight = (LONG)(-1 * size * zoomRatio * fontRatio); + logFont.lfQuality = fontRender; + logFont.lfWeight = fontWeight; + if (face.GetLength() < 32) + { + wsprintf(logFont.lfFaceName, _T("%s"), (LPCTSTR)face); + } + else + { + wsprintf(logFont.lfFaceName, _T("")); + } + + m_Font.DeleteObject(); + m_Font.CreateFontIndirect(&logFont); + SetFont(&m_Font); + + logFont.lfHeight = (LONG)(-1 * sizeToolTip * zoomRatio * fontRatio); + m_FontToolTip.DeleteObject(); + m_FontToolTip.CreateFontIndirect(&logFont); + + m_TextColor = textColor; + + if (m_ToolTip.m_hWnd != NULL) + { + m_ToolTip.SetFont(&m_FontToolTip); + } +} + +//------------------------------------------------ +// Mouse +//------------------------------------------------ + +void CStaticFx::SetHandCursor(BOOL bHandCuror) +{ + m_bHandCursor = bHandCuror; +} + +void CStaticFx::OnMouseMove(UINT nFlags, CPoint point) +{ +#if _MSC_VER <= 1310 + typedef BOOL(WINAPI* Func_TrackMouseEvent)(LPTRACKMOUSEEVENT); + static Func_TrackMouseEvent p_TrackMouseEvent = NULL; + static BOOL bInit_TrackMouseEvent = FALSE; + + if (bInit_TrackMouseEvent && p_TrackMouseEvent == NULL) + { + return; // TrackMouseEvent is not available + } + else + { + HMODULE hModule = GetModuleHandle(_T("user32.dll")); + if (hModule) + { + p_TrackMouseEvent = (Func_TrackMouseEvent)GetProcAddress(hModule, "TrackMouseEvent"); + } + } + + if (p_TrackMouseEvent != NULL) + { + TRACKMOUSEEVENT tme = { sizeof(TRACKMOUSEEVENT) }; + tme.hwndTrack = m_hWnd; + tme.dwFlags = TME_LEAVE | TME_HOVER; + tme.dwHoverTime = 1; + m_bTrackingNow = p_TrackMouseEvent(&tme); + } + bInit_TrackMouseEvent = TRUE; +#else + if (!m_bTrackingNow) + { + TRACKMOUSEEVENT tme = { sizeof(TRACKMOUSEEVENT) }; + tme.hwndTrack = m_hWnd; + tme.dwFlags = TME_LEAVE | TME_HOVER; + tme.dwHoverTime = 1; + m_bTrackingNow = _TrackMouseEvent(&tme); + } +#endif + + CStatic::OnMouseMove(nFlags, point); +} + +void CStaticFx::OnMouseHover(UINT nFlags, CPoint point) +{ +#if _MSC_VER > 1310 + CStatic::OnMouseHover(nFlags, point); +#endif + + m_bHover = TRUE; + Invalidate(); +} + +void CStaticFx::OnMouseLeave() +{ +#if _MSC_VER > 1310 + CStatic::OnMouseLeave(); +#endif + + m_bTrackingNow = FALSE; + m_bHover = FALSE; + Invalidate(); +} + +void CStaticFx::OnSetfocus() +{ + m_bFocas = TRUE; + Invalidate(); +} + +void CStaticFx::OnKillfocus() +{ + m_bFocas = FALSE; + Invalidate(); +} + +BOOL CStaticFx::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message) +{ + HCURSOR hCursor = NULL; + if (m_bHandCursor) + { + hCursor = AfxGetApp()->LoadStandardCursor(IDC_HAND); + if (hCursor) + { + ::SetCursor(hCursor); + } + } + else + { + hCursor = AfxGetApp()->LoadStandardCursor(IDC_ARROW); + if (hCursor) + { + ::SetCursor(hCursor); + } + } + + return TRUE; +} + +//------------------------------------------------ +// ToolTip +//------------------------------------------------ + +void CStaticFx::SetToolTipText(LPCTSTR text) +{ + if (text == NULL) { return; } + + InitToolTip(); + m_ToolTipText = text; + if (m_ToolTip.GetToolCount() == 0) + { + CRect rect; + GetClientRect(rect); + m_ToolTip.AddTool(this, m_ToolTipText, rect, 1); + } + else + { + m_ToolTip.UpdateTipText(m_ToolTipText, this, 1); + } + + SetToolTipActivate(TRUE); +} + +void CStaticFx::SetToolTipActivate(BOOL bActivate) +{ + if (m_ToolTip.GetToolCount() == 0) { return; } + m_ToolTip.Activate(bActivate); +} + +void CStaticFx::SetToolTipWindowText(LPCTSTR pText) +{ + SetToolTipText(pText); + SetWindowText(pText); +} + +CString CStaticFx::GetToolTipText() +{ + return m_ToolTipText; +} + +void CStaticFx::InitToolTip() +{ + if (m_ToolTip.m_hWnd == NULL) + { + m_ToolTip.Create(this, TTS_ALWAYSTIP | TTS_BALLOON | TTS_NOANIMATE | TTS_NOFADE); + m_ToolTip.Activate(FALSE); + m_ToolTip.SetFont(&m_FontToolTip); + m_ToolTip.SendMessage(TTM_SETMAXTIPWIDTH, 0, 1024); + m_ToolTip.SetDelayTime(TTDT_AUTOPOP, 8000); + m_ToolTip.SetDelayTime(TTDT_INITIAL, 500); + m_ToolTip.SetDelayTime(TTDT_RESHOW, 100); + } +} + +BOOL CStaticFx::PreTranslateMessage(MSG* pMsg) +{ + InitToolTip(); + m_ToolTip.RelayEvent(pMsg); + + return CStatic::PreTranslateMessage(pMsg); +} + +BOOL CStaticFx::OnEraseBkgnd(CDC* pDC) +{ + return TRUE; +} \ No newline at end of file diff --git a/CristalDiskMark/source/CrystalDiskMark/Priscilla/StaticFx.h b/CristalDiskMark/source/CrystalDiskMark/Priscilla/StaticFx.h new file mode 100644 index 0000000..a339646 --- /dev/null +++ b/CristalDiskMark/source/CrystalDiskMark/Priscilla/StaticFx.h @@ -0,0 +1,135 @@ +/*---------------------------------------------------------------------------*/ +// Author : hiyohiyo +// Mail : hiyohiyo@crystalmark.info +// Web : https://crystalmark.info/ +// License : MIT License +/*---------------------------------------------------------------------------*/ + +#pragma once + +#include "ImageFx.h" + +class CStaticFx : public CStatic +{ + DECLARE_DYNAMIC(CStaticFx); + + enum Border + { + NO_BORDER = 0, // FALSE + SYSTEM_BORDER = 1, // TRUE + UNDERLINE = 2, + }; + +public: + // Constructors + CStaticFx(); + virtual ~CStaticFx(); + + // Control + BOOL InitControl(int x, int y, int width, int height, double zoomRatio, HPALETTE hPal, CDC* bkDC, + LPCTSTR imagePath, int imageCount, DWORD textAlign, int renderMode, BOOL bHighContrast, BOOL bDarkMode, DWORD drawFrame); + void SetMargin(int top, int left, int bottom, int right, double zoomRatio); + CSize GetSize(void); + void SetDrawFrame(BOOL bDrawFrame); + void SetDrawFrameEx(BOOL bDrawFrame, COLORREF frameColor = RGB(128, 128, 128)); + void SetGlassColor(COLORREF glassColor, BYTE glassAlpha); + void SetMeter(BOOL bMeter, double meterRatio); + void SetLabelUnit(CString label, CString unit); + void SetLabelUnitFormat(UINT labelFormat, UINT unitFormat); + void SetTextFormat(UINT format); + + // Font + void SetFontEx(CString face, int size, int sizeToolTip, double zoomRatio, double fontRatio = 1.0, + COLORREF textColor = RGB(0, 0, 0), LONG fontWeight = FW_NORMAL, BYTE fontRender = CLEARTYPE_NATURAL_QUALITY); + + // ToolTip + void SetToolTipText(LPCTSTR pText); + void SetToolTipActivate(BOOL bActivate = TRUE); + void SetToolTipWindowText(LPCTSTR pText); + CString GetToolTipText(); + + // Mouse + void SetHandCursor(BOOL bHandCuror = TRUE); + +protected: + // Draw Control + virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct); + virtual void DrawControl(CDC* drawDC, LPDRAWITEMSTRUCT lpDrawItemStruct, CBitmap& ctrlBitmap, CBitmap& bkBitmap, int no); + virtual void DrawString(CDC* drawDC, LPDRAWITEMSTRUCT lpDrawItemStruct); + + // Image + BOOL LoadBitmap(LPCTSTR fileName); + BOOL LoadBitmap(HBITMAP hBitmap); + void SetBkReload(void); + BOOL SetBitmap(CBitmap& bitmap); + void LoadCtrlBk(CDC* drawDC); + + // ToolTip + void InitToolTip(); + virtual BOOL PreTranslateMessage(MSG* pMsg); + + // Message Map + DECLARE_MESSAGE_MAP() + afx_msg BOOL OnEraseBkgnd(CDC* pDC); + afx_msg void OnMouseMove(UINT nFlags, CPoint point); + afx_msg void OnMouseHover(UINT nFlags, CPoint point); + afx_msg void OnMouseLeave(); + afx_msg void OnKillfocus(); + afx_msg void OnSetfocus(); + afx_msg BOOL OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message); + +protected: + // Control + int m_X; + int m_Y; + CSize m_CtrlSize; + CRect m_Margin; + int m_RenderMode; + BOOL m_bHighContrast; + BOOL m_bDarkMode; + DWORD m_DrawFrame; + BOOL m_bDrawFrameEx; + COLORREF m_FrameColor; + HPALETTE m_hPal; + + CString m_Label; + CString m_Unit; + + UINT m_TextFormat; + UINT m_LabelFormat; + UINT m_UnitFormat; + + // Glass + COLORREF m_GlassColor; + BYTE m_GlassAlpha; + + // Meter + BOOL m_bMeter; + double m_MeterRatio; + + // Image + CString m_ImagePath; + int m_ImageCount; + CDC* m_BkDC; + CBitmap m_BkBitmap; + BOOL m_bBkBitmapInit; + BOOL m_bBkLoad; + CBitmap m_CtrlBitmap; + CImage m_CtrlImage; + + // Font + DWORD m_TextAlign; + CFont m_Font; + CFont m_FontToolTip; + COLORREF m_TextColor; + + // ToolTip + CToolTipCtrl m_ToolTip; + CString m_ToolTipText; + + // Mouse + BOOL m_bHover; + BOOL m_bFocas; + BOOL m_bTrackingNow; + BOOL m_bHandCursor; +}; diff --git a/CristalDiskMark/source/CrystalDiskMark/Priscilla/SystemInfoFx.cpp b/CristalDiskMark/source/CrystalDiskMark/Priscilla/SystemInfoFx.cpp new file mode 100644 index 0000000..483e445 --- /dev/null +++ b/CristalDiskMark/source/CrystalDiskMark/Priscilla/SystemInfoFx.cpp @@ -0,0 +1,1887 @@ +/*---------------------------------------------------------------------------*/ +// Author : hiyohiyo +// Mail : hiyohiyo@crystalmark.info +// Web : https://crystalmark.info/ +// License : MIT License +/*---------------------------------------------------------------------------*/ + +#include "stdafx.h" +#include "OsInfoFx.h" +#include "SystemInfoFx.h" +#include "UtilityFx.h" + + +//------------------------------------------------ +// Get System Information by WMI +//------------------------------------------------ + +//warning : enum3, enum class +#if _MSC_VER > 1310 +#pragma warning(disable : 26812) +#endif + +#include +#include +#include +#pragma comment(lib, "oleaut32.lib") +#pragma comment(lib, "wbemuuid.lib") + +#define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } } +#ifndef safeCloseHandle +#define safeCloseHandle(h) { if( h != NULL ) { ::CloseHandle(h); h = NULL; } } +#endif +#ifndef safeVirtualFree +#define safeVirtualFree(h,b,c) { if( h != NULL ) { ::VirtualFree(h, b, c); h = NULL; } } +#endif + +#if _MSC_VER > 1310 +DWORD CountSetBits(ULONG_PTR bitMask) { + DWORD LSHIFT = sizeof(ULONG_PTR) * 8 - 1; + DWORD bitSetCount = 0; + ULONG_PTR bitTest = (ULONG_PTR)1 << LSHIFT; + for (DWORD i = 0; i <= LSHIFT; ++i) { + bitSetCount += ((bitMask & bitTest) ? 1 : 0); + bitTest >>= 1; + } + return bitSetCount; +} + +typedef ULONGLONG(WINAPI* FuncGetLogicalProcessorInformationEx)(LOGICAL_PROCESSOR_RELATIONSHIP, PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX, PDWORD); +typedef BOOL(WINAPI* FuncGetLogicalProcessorInformation)(PSYSTEM_LOGICAL_PROCESSOR_INFORMATION, PDWORD); + +#endif + +void GetProcessorInfo(int* cores, int* threads) +{ + *cores = 0; + *threads = 0; + +#if _MSC_VER > 1310 + HMODULE hModule = GetModuleHandle(_T("kernel32.dll")); + FuncGetLogicalProcessorInformationEx pGetLogicalProcessorInformationEx = NULL; + FuncGetLogicalProcessorInformation pGetLogicalProcessorInformation = NULL; + + if (hModule) + { + pGetLogicalProcessorInformationEx = (FuncGetLogicalProcessorInformationEx)GetProcAddress(hModule, "GetLogicalProcessorInformationEx"); + pGetLogicalProcessorInformation = (FuncGetLogicalProcessorInformation)GetProcAddress(hModule, "GetLogicalProcessorInformation"); + + } + + // for Windows 7 or later + if (pGetLogicalProcessorInformationEx != NULL) + { + DWORD length = 0; + pGetLogicalProcessorInformationEx(RelationAll, nullptr, &length); + + BYTE* buffer = new BYTE[length]; + if (pGetLogicalProcessorInformationEx(RelationAll, reinterpret_cast(buffer), &length)) { + DWORD offset = 0; + while (offset < length) { + PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX info = reinterpret_cast(buffer + offset); + + if (info->Relationship == RelationProcessorCore) { + *cores += 1; + for (int group = 0; group < info->Processor.GroupCount; ++group) { + *threads += CountSetBits(info->Processor.GroupMask[group].Mask); + } + } + + offset += info->Size; + } + } + delete[] buffer; + } + // for Windows XP SP3/Vista + else if(pGetLogicalProcessorInformation != NULL) + { + DWORD length = 0; + pGetLogicalProcessorInformation(NULL, &length); + + SYSTEM_LOGICAL_PROCESSOR_INFORMATION* buffer = new SYSTEM_LOGICAL_PROCESSOR_INFORMATION[length / sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION)]; + pGetLogicalProcessorInformation(&buffer[0], &length); + + for (DWORD i = 0; i != length / sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION); ++i) { + if (buffer[i].Relationship == RelationProcessorCore) { + *cores += 1; + ULONG_PTR mask = buffer[i].ProcessorMask; + while (mask) { + if (mask & 1) { + *threads += 1; + } + mask >>= 1; + } + } + } + delete[] buffer; + } + else // - Windows XP SP2 + { + SYSTEM_INFO si = { 0 }; + GetSystemInfo(&si); + + *cores = si.dwNumberOfProcessors; + *threads = si.dwNumberOfProcessors; + } +#else + SYSTEM_INFO si = {0}; + GetSystemInfo(&si); + + *cores = si.dwNumberOfProcessors; + *threads = si.dwNumberOfProcessors; +#endif +} + +#if defined(_M_IX86) || defined(_M_X64) + +void getProcessorBrandString(char* brandString); +void getCpuName(char* cpuName); +unsigned int getCacheInfoIntel(int test); +CStringA getCpuModelName(CStringA vendor, unsigned int family, unsigned int model, unsigned int stepping, unsigned int type, unsigned int L2Cashe, unsigned int fpu); + +#if _MSC_VER > 1310 +#include // for __cpuid + +void GetCpuid(unsigned int param, unsigned int* _eax, unsigned int* _ebx, unsigned int* _ecx, unsigned int* _edx) +{ + int cpuInfo[4] = { 0 }; + __cpuid(cpuInfo, param); + + *_eax = cpuInfo[0]; + *_ebx = cpuInfo[1]; + *_ecx = cpuInfo[2]; + *_edx = cpuInfo[3]; +} +#else +BOOL IsCpuidSupported() +{ + bool supported = false; + __asm { + pushfd + pop eax + mov ebx, eax + xor eax, 0x200000 + push eax + popfd + pushfd + pop eax + xor eax, ebx + test eax, 0x200000 + jz not_supported + mov supported, 1 + not_supported: + push ebx + popfd + } + + return supported; +} + +void GetCpuid(unsigned int param, unsigned int* _eax, unsigned int* _ebx, unsigned int* _ecx, unsigned int* _edx) +{ + static BOOL bIsCpuid = IsCpuidSupported(); + if (!bIsCpuid) { return; } + + unsigned int a, b, c, d; + __asm { + MOV EAX, param + CPUID + MOV a, EAX + MOV b, EBX + MOV c, ECX + MOV d, EDX + } + *_eax = a; + *_ebx = b; + *_ecx = c; + *_edx = d; +} +#endif + +void getProcessorBrandString(char* brandString) +{ + unsigned int eax = 0; + unsigned int ebx = 0; + unsigned int ecx = 0; + unsigned int edx = 0; + + __try + { + // Check if CPUID supports brand string + GetCpuid(0x80000000, &eax, &ebx, &ecx, &edx); + if (eax < 0x80000004) { + strcpy(brandString, ""); + return; + } + + // Get brand string + for (int i = 0x80000002; i <= 0x80000004; ++i) { + GetCpuid(i, &eax, &ebx, &ecx, &edx); + memcpy(brandString + (i - 0x80000002) * 16, &eax, 4); + memcpy(brandString + (i - 0x80000002) * 16 + 4, &ebx, 4); + memcpy(brandString + (i - 0x80000002) * 16 + 8, &ecx, 4); + memcpy(brandString + (i - 0x80000002) * 16 + 12, &edx, 4); + } + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + strcpy(brandString, ""); + } +} + +void GetHypervisorVendorString(char* vendorString) +{ + unsigned int eax = 0; + unsigned int ebx = 0; + unsigned int ecx = 0; + unsigned int edx = 0; + + __try + { + GetCpuid(0x40000000, &eax, &ebx, &ecx, &edx); + memcpy(vendorString, &ebx, 4); + memcpy(vendorString + 4, &ecx, 4); + memcpy(vendorString + 8, &edx, 4); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + strcpy(vendorString, ""); + } +} + +#if _MSC_VER <= 1310 + +BOOL Is486orAbove(); +BOOL IsCyrixCPU(); +BOOL IsAmd486(); +BOOL readCcr(BYTE addr, BYTE* value); +CStringA getCyrixModelName(); + +inline unsigned char inpb(unsigned short port) +{ + unsigned char val; + __asm { + mov dx, port + in al, dx + mov val, al + } + return val; +} + +inline void outpb(unsigned short port, unsigned char data) +{ + __asm { + mov dx, port + mov al, data + out dx, al + } +} + +// https://github.com/captainys/TOWNSEMU/issues/147#issuecomment-2764633838 +BOOL IsFMTOWNS() +{ + static BOOL b = -1; + if (b == -1) + { + b = FALSE; + + if (IsPC98()) + { + return FALSE; + } + + if (! IsWin95First()) + { + return FALSE; + } + + if (GetUserDefaultLCID() != 0x0411) // Japanese + { + return FALSE; + } + + __try + { + BYTE in30 = (BYTE)inpb(0x30); + BYTE in31 = (BYTE)inpb(0x31); + if (in30 && in30 != 0xFF && in31 && in31 != 0xFF) + { + b = TRUE; + return TRUE; + } + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + return FALSE; + } + } + + return b; +} + +BOOL Is486orAbove() +{ + BOOL result = FALSE; + + __asm { + pushfd + pop eax + mov ecx, eax + xor eax, 0x40000 + push eax + popfd + + pushfd + pop eax + cmp eax, ecx + jz is_not_80486 + + mov result, 1 + jmp end + + is_not_80486 : + mov result, 0 + end : + } + + return result; +} + +BOOL IsCyrixCPU() +{ + BOOL result = FALSE; + + __asm { + xor ax, ax + sahf + mov ax, 5 + mov bx, 2 + div bl + lahf + cmp ah, 2 + jne not_cyrix + + mov result, 1 + jmp end + + not_cyrix: + mov result, 0 + end: + } + + return result; +} + +BOOL IsAmd486() +{ + __try + { + outpb(0xC0, 0x55); + BYTE val = (BYTE)inpb(0xC0); + if (val == 0x55) + { + return TRUE; + } + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + return FALSE; + } + + return FALSE; +} + +BOOL readCcr(BYTE addr, BYTE* value) +{ + __try + { + outpb(0x22, addr); + *value = inpb(0x23); + return TRUE; + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + return FALSE; + } +} + +// http://www.bitsavers.org/components/cyrix/appnotes/Cyrix_CPU_Detection_Guide_1997.pdf +CStringA getCyrixModelName() +{ + BYTE dir0 = 0; + + if(! readCcr(0xFE, &dir0)) + { + return "Cyrix Unknown CPU"; + } + if (0x00 <= dir0 && dir0 <= 0x1F) { return "Cyrix Cx486"; } + else if (0x20 <= dir0 && dir0 <= 0x2F) { return "Cyrix 5x86"; } + else if (0x30 <= dir0 && dir0 <= 0x3F) { return "Cyrix 6x86"; } + else if (0x40 <= dir0 && dir0 <= 0x4F) { return "Cyrix MediaGX"; } + else if (0x50 <= dir0 && dir0 <= 0x5F) { return "Cyrix 6x86MX/MII"; } + else + { + return "Cyrix Unknown CPU"; + } +} + +#endif + +void getCpuName(char* cpuName) +{ + unsigned int eax = 0; + unsigned int ebx = 0; + unsigned int ecx = 0; + unsigned int edx = 0; + unsigned int maxCpuId = 0; + +#if _MSC_VER <= 1310 + if(! IsCpuidSupported()) + { + CStringA modelName = ""; + + if (! Is486orAbove()) + { + modelName = "386 Generation Processor"; + } + else if (IsFMTOWNS()) + { + + } + else if (IsCyrixCPU()) + { + modelName = "Cyrix Unknown CPU"; + if (IsWin9x() && !IsPC98() && !IsFMTOWNS()) // PC-98 and FM TOWNS are not supported. + { + modelName = getCyrixModelName(); + } + } + else if (IsWin9x()) + { + if (IsAmd486()) + { + modelName = "AMD Am486/Am5x86"; + } + } + + if (modelName.IsEmpty()) + { + SYSTEM_INFO si = { 0 }; + GetSystemInfo(&si); + + switch (si.dwProcessorType) + { + case PROCESSOR_INTEL_386: + modelName = "386 Generation Processor"; + break; + case PROCESSOR_INTEL_486: + modelName = "486 Generation Processor"; + break; + case PROCESSOR_INTEL_PENTIUM: + modelName = "586 Generation Processor"; + break; + case PROCESSOR_ARCHITECTURE_UNKNOWN: + default: + modelName = "Unknown Processor"; + break; + } + } + + sprintf(cpuName, "%s", modelName.GetString()); + return; + } +#endif + + char vendorString[13] = {0}; + GetCpuid(0x00, &eax, &ebx, &ecx, &edx); + memcpy(vendorString, &ebx, 4); + memcpy(vendorString + 4, &edx, 4); + memcpy(vendorString + 8, &ecx, 4); + + GetCpuid(0x80000000, &eax, &ebx, &ecx, &edx); + maxCpuId = eax; + + if (maxCpuId >= 0x80000004) + { + getProcessorBrandString(cpuName); + } + else + { + CStringA vendor = vendorString; + GetCpuid(0x1, &eax, &ebx, &ecx, &edx); + + unsigned int version = eax; + unsigned int family = (version >> 8) & 0xF; + unsigned int model = (version >> 4) & 0xF; + unsigned int stepping = version & 0xF; + unsigned int type = (version >> 12) & 0x3; + + unsigned int fpu = 1; // Under Construction + + unsigned int cacheL2 = 0; + unsigned int temp = 0; + if (vendor.Find("GenuineIntel") == 0) + { + GetCpuid(0x2, &eax, &ebx, &ecx, &edx); + temp = getCacheInfoIntel((eax & 0xFF000000) >> 24); if (temp > 0) { cacheL2 = temp; } + temp = getCacheInfoIntel((eax & 0x00FF0000) >> 16); if (temp > 0) { cacheL2 = temp; } + temp = getCacheInfoIntel((eax & 0x0000FF00) >> 8); if (temp > 0) { cacheL2 = temp; } + temp = getCacheInfoIntel((eax & 0x000000FF) >> 0); if (temp > 0) { cacheL2 = temp; } + temp = getCacheInfoIntel((ebx & 0xFF000000) >> 24); if (temp > 0) { cacheL2 = temp; } + temp = getCacheInfoIntel((ebx & 0x00FF0000) >> 16); if (temp > 0) { cacheL2 = temp; } + temp = getCacheInfoIntel((ebx & 0x0000FF00) >> 8); if (temp > 0) { cacheL2 = temp; } + temp = getCacheInfoIntel((ebx & 0x000000FF) >> 0); if (temp > 0) { cacheL2 = temp; } + temp = getCacheInfoIntel((ecx & 0xFF000000) >> 24); if (temp > 0) { cacheL2 = temp; } + temp = getCacheInfoIntel((ecx & 0x00FF0000) >> 16); if (temp > 0) { cacheL2 = temp; } + temp = getCacheInfoIntel((ecx & 0x0000FF00) >> 8); if (temp > 0) { cacheL2 = temp; } + temp = getCacheInfoIntel((ecx & 0x000000FF) >> 0); if (temp > 0) { cacheL2 = temp; } + temp = getCacheInfoIntel((edx & 0xFF000000) >> 24); if (temp > 0) { cacheL2 = temp; } + temp = getCacheInfoIntel((edx & 0x00FF0000) >> 16); if (temp > 0) { cacheL2 = temp; } + temp = getCacheInfoIntel((edx & 0x0000FF00) >> 8); if (temp > 0) { cacheL2 = temp; } + temp = getCacheInfoIntel((edx & 0x000000FF) >> 0); if (temp > 0) { cacheL2 = temp; } + } + + if(maxCpuId >= 0x80000006) + { + GetCpuid(0x80000006, &eax, &ebx, &ecx, &edx); + cacheL2 = ((ebx >> 12) & 0xF) * 256; + } + + CStringA modelName = getCpuModelName(vendor, family, model, stepping, type, cacheL2, fpu); + + sprintf(cpuName, "%s", modelName.GetString()); + } +} + +unsigned int getCacheInfoIntel(int test) +{ + unsigned int CacheL2 = 0; + switch (test) + { + case 0x39:CacheL2 = 128;break; + case 0x3A:CacheL2 = 192;break; + case 0x3B:CacheL2 = 128;break; + case 0x3C:CacheL2 = 256;break; + case 0x3D:CacheL2 = 384;break; + case 0x3E:CacheL2 = 512;break; + case 0x41:CacheL2 = 128;break; + case 0x42:CacheL2 = 256;break; + case 0x43:CacheL2 = 512;break; + case 0x44:CacheL2 = 1024;break; + case 0x45:CacheL2 = 2048;break; + case 0x48:CacheL2 = 3072;break; + case 0x49:CacheL2 = 4096;break; + case 0x4E:CacheL2 = 6144;break; + case 0x78:CacheL2 = 1024;break; + case 0x79:CacheL2 = 128;break; + case 0x7A:CacheL2 = 256;break; + case 0x7B:CacheL2 = 512;break; + case 0x7C:CacheL2 = 1024;break; + case 0x7D:CacheL2 = 2048;break; + case 0x7E:CacheL2 = 256;break; + case 0x7F:CacheL2 = 512;break; + case 0x81:CacheL2 = 128;break; + case 0x82:CacheL2 = 256;break; + case 0x83:CacheL2 = 512;break; + case 0x84:CacheL2 = 1024;break; + case 0x85:CacheL2 = 2048;break; + case 0x86:CacheL2 = 512;break; + case 0x87:CacheL2 = 1024;break; + default:; + } + + return CacheL2; +} + +CStringA getCpuModelName(CStringA vendor, unsigned int family, unsigned int model, unsigned int stepping, unsigned int type, unsigned int cacheL2, unsigned int fpu) +{ + CStringA modelName; + int F = family; + int M = model; + int S = stepping; + int CacheL2 = cacheL2; + char* n = NULL; + char* v = NULL; + + if (vendor.Find("GenuineIntel") == 0) + { + v = "Intel"; + switch (family) + { + case 0x06: + switch (model) + { + ///////////// + // Cascades + ///////////// + case 0xA: + n = "Pentium III Xeon"; + break; + /////////// + // Banias + /////////// + case 9: + if (CacheL2 == 1024) { + n = "Pentium M"; + } else { + n = "Celeron M"; + } + break; + /////////////// + // Coppermine + /////////////// + case 8: + if (CacheL2 >= 256) { + n = "Pentium III"; + } else if (CacheL2 <= 128) { + n = "Celeron"; + } + break; + /////////// + // Katmai + /////////// + case 7: + if (CacheL2 == 1024) { + n = "Pentium III Xeon"; + } else { + n = "Pentium III"; + } + break; + ////////////////////// + // Dixon & Mendocino + ////////////////////// + case 6: + if ((S == 0xA || S == 0xD) && CacheL2 == 256) { + n = "Mobile Pentium II"; + } else if ((S == 0xA || S == 0xD) && CacheL2 == 128) { + n = "Mobile Celeron"; + } else { + n = "Celeron"; + } + break; + ////////////// + // Deschutes + ////////////// + case 5: + if (CacheL2 > 512) { + n = "Pentium II Xeon"; + } else if (CacheL2 == 512 && type == 0x1) { + n = "Pentium II OverDrive"; + } else if (CacheL2 == 512) { + n = "Pentium II"; + } else if (CacheL2 == 0) { + n = "Celeron"; + } + break; + case 4: + n = "OverDrive"; + break; + case 3: + if (type == 0x1) { + n = "Pentium II OverDrive"; + } else { + n = "Pentium II"; + } + break; + /////// + // P6 + /////// + case 2: + n = "Pentium Pro"; + break; + case 1: + n = "Pentium Pro"; + break; + case 0: + n = "Pentium Pro"; + break; + } + break; + //////////// + // Pentium + //////////// + case 5: + switch (model) { + case 8: + n = "Pentium MMX"; + break; + case 7: + n = "Pentium"; + break; + case 6: + n = "Pentium OverDrive"; + break; + case 5: + n = "Pentium OverDrive"; + break; + case 4: + if (type == 1) { + n = "Pentium MMX OverDrive"; + } else { + n = "Pentium MMX"; + } + break; + case 3: + n = "Pentium OverDrive"; + break; + case 2: + if (type == 1) { + n = "Pentium OverDrive"; + } else { + n = "Pentium"; + } + break; + case 1: + case 0: + if (type == 1) { + n = "Pentium OverDrive"; + } else { + n = "Pentium"; + } + break; + default: + n = "Pentium"; + break; + } + break; + //////// + // 486 + //////// + case 4: + switch (model) { + case 9: + n = "486DX4 WB"; + break; + case 8: + n = "486DX4"; + break; + case 7: + n = "486DX2 WB"; + break; + case 5: + n = "486SX2"; + break; + case 4: + n = "486SL"; + break; + case 3: + n = "486DX2"; + break; + case 2: + n = "486SX"; + break; + case 1: + case 0: + n = "486DX"; + break; + default: + n = "486"; + break; + } + break; + case 3: + n = "386"; + break; + default: + n = "Unknown CPU"; + break; + } + } + else if (vendor.Find("AuthenticAMD") == 0) + { + v = "AMD"; + switch (family) + { + case 5: + switch (model) { + case 0xD: + case 0xC: + if (CacheL2 == 256) { + n = "K6-III+"; + } else { + n = "K6-2+"; + } + break; + case 0xA: + n = "Geode LX"; + break; + case 9: + n = "K6-III"; + break; + case 8: + n = "K6-2"; + break; + case 7: + n = "K6"; + break; + case 3: + case 2: + case 1: + case 0: + n = "K5"; + break; + default: + n = "Unknown CPU"; + break; + } + break; + case 4: + switch (model) { + case 0xF: + case 0xE: + n = "Am5x86"; + break; + case 9: + case 8: + n = "Am486DX4/Am5x86"; + break; + case 7: + case 3: + if (fpu) + { + n = "Am486DX2"; + } + else + { + n = "Am486SX2"; + } + break; + default: + n = "Unknown CPU"; + break; + } + break; + default: + n = "Unknown CPU"; + break; + } + } + else if (vendor.Find("CentaurHauls") == 0 || vendor.Find("VIA VIA VIA") == 0) + { + v = ""; + switch (family) + { + case 6: + switch (model) + { + case 0xF: + n = "VIA Nano"; + break; + case 0xD: + case 0xC: + case 0xB: + case 0xA: + n = "VIA C7"; + break; + case 9: + case 8: + case 7: + n = "VIA C3"; + break; + case 6: + n = "VIA Cyrix III"; + break; + case 5: + if (stepping == 0) + { + n = "VIA 6x86MX"; + } + else + { + n = "VIA Cyrix III"; + } + break; + case 4: + n = "VIA Cyrix III"; + break; + case 3: + n = "VIA 6x86MX"; + break; + case 2: + n = "VIA Cyrix III"; + break; + case 0: + n = "VIA 6x86MX"; + break; + default: + n = "VIA Unknown CPU"; + break; + } + break; + case 5: + switch (model) + { + case 9: + n = "IDT WinChip 3"; + break; + case 8: + n = "IDT WinChip 2"; + break; + case 4: + n = "IDT WinChip C6"; + break; + default: + n = "VIA Unknown CPU"; + break; + } + break; + default: + n = "VIA Unknown CPU"; + break; + } + } + else if (vendor.Find("CyrixInstead") == 0) + { + v = "Cyrix"; + switch (family) + { + case 6: + switch (model) + { + case 0: + n = "MII"; + break; + default: + n = "Unknown CPU"; + break; + } + break; + case 5: + switch (model) + { + case 9: + n = "Geode"; + break; + case 4: + n = "MediaGX"; + break; + case 2: + n = "6x86"; + break; + default: + n = "Unknown CPU"; + break; + } + break; + case 4: + switch (model) + { + case 4: + n = "MediaGX"; + break; + default: + n = "Unknown CPU"; + break; + } + break; + default: + n = "Unknown CPU"; + break; + } + } + else if (vendor.Find("SiS SiS SiS") == 0) + { + v = "SiS"; + n = "55x"; + } + else if (vendor.Find("Geode by NSC") == 0) + { + v = "NSC"; + n = "Geode"; + } + else if (vendor.Find("NexGenDriven") == 0) + { + v = "NexGen"; + n = "Nx586"; + } + else if (vendor.Find("RiseRiseRise") == 0) + { + v = "Rise"; + n = "mP6"; + } + else if (vendor.Find("UMC UMC UMC") == 0) + { + v = "UMC"; + n = "Green CPU"; + } + else + { + v = NULL; + n = NULL; + } + + if (v != NULL && n != NULL) + { + modelName.Format("%s %s", v, n); + return modelName; + } + else + { + return ""; + } +} +#endif + +void GetCpuInfo(CString& cpuInfo, CString& cpuName, int* clock, int* cores, int* threads) +{ + CString query = _T("Select * from Win32_Processor"); + + IWbemLocator* pIWbemLocator = NULL; + IWbemServices* pIWbemServices = NULL; + IEnumWbemClassObject* pEnumCOMDevs = NULL; + IWbemClassObject* pCOMDev = NULL; + ULONG uReturned = 0; + BOOL flag = FALSE; + + try + { + if (SUCCEEDED(CoCreateInstance(CLSID_WbemLocator, NULL, CLSCTX_INPROC_SERVER, + IID_IWbemLocator, (LPVOID*)&pIWbemLocator))) + { + long securityFlag = 0; +#if _MSC_VER > 1310 + if (IsWindowsVersionOrGreaterFx(6, 0)) { securityFlag = WBEM_FLAG_CONNECT_USE_MAX_WAIT; } +#endif + if (SUCCEEDED(pIWbemLocator->ConnectServer(_bstr_t(_T("root\\cimv2")), + NULL, NULL, 0L, securityFlag, NULL, NULL, &pIWbemServices))) + { +#if _MSC_VER > 1310 + if (SUCCEEDED(CoSetProxyBlanket(pIWbemServices, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, + NULL, RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE))) +#endif + { + if (SUCCEEDED(pIWbemServices->ExecQuery(_bstr_t(_T("WQL")), + _bstr_t(query), WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, NULL, &pEnumCOMDevs))) + { + while (pEnumCOMDevs && SUCCEEDED(pEnumCOMDevs->Next(10000, 1, &pCOMDev, &uReturned)) && uReturned == 1) + { + CString name; + UINT32 speed = 0; + // UINT32 cores = 0; + // UINT32 threads = 0; + +#if defined(_M_IX86) || defined(_M_X64) + char brandString[49] = { 0 }; + getCpuName(brandString); + //getProcessorBrandString(brandString); + name = brandString; + name.TrimLeft(); + name.TrimRight(); + cpuName = name; +#endif + VARIANT pVal; + VariantInit(&pVal); + if (name.IsEmpty() && pCOMDev->Get(L"Name", 0L, &pVal, NULL, NULL) == WBEM_S_NO_ERROR && pVal.vt > VT_NULL) + { + name = pVal.bstrVal; + name.TrimLeft(); + name.TrimRight(); + cpuName = name; + VariantClear(&pVal); + } + if (pCOMDev->Get(L"MaxClockSpeed", 0L, &pVal, NULL, NULL) == WBEM_S_NO_ERROR && pVal.vt > VT_NULL) + { + speed = pVal.intVal; + if(clock != NULL) { *clock = (int)speed; } + VariantClear(&pVal); + } + + /* + if (pCOMDev->Get(L"NumberOfCores", 0L, &pVal, NULL, NULL) == WBEM_S_NO_ERROR && pVal.vt > VT_NULL) + { + *cores = pVal.intVal; + VariantClear(&pVal); + } + if (pCOMDev->Get(L"NumberOfLogicalProcessors", 0L, &pVal, NULL, NULL) == WBEM_S_NO_ERROR && pVal.vt > VT_NULL) + { + *threads = pVal.intVal; + VariantClear(&pVal); + } + */ + + GetProcessorInfo(cores, threads); + + if (speed > 0 && *cores > 0 && *threads > 0) + { + if (*cores > 1 && *threads > 1) + { + cpuInfo.Format(_T("%s %dMHz (%dcores/%dthreads)"), (LPCTSTR)name, speed, *cores, *threads); + } + else if (*cores == 1 && *threads == 1) + { + cpuInfo.Format(_T("%s %dMHz (%dcore/%dthread)"), (LPCTSTR)name, speed, *cores, *threads); + } + else if (*cores == 1) + { + cpuInfo.Format(_T("%s %dMHz (%dcore/%dthreads)"), (LPCTSTR)name, speed, *cores, *threads); + } + } + else if (*cores > 0 && *threads > 0) + { + if (*cores > 1 && *threads > 1) + { + cpuInfo.Format(_T("%s (%dcores/%dthreads)"), (LPCTSTR)name, *cores, *threads); + } + else if (*cores == 1 && *threads == 1) + { + cpuInfo.Format(_T("%s (%dcore/%dthread)"), (LPCTSTR)name, *cores, *threads); + } + else if (*cores == 1) + { + cpuInfo.Format(_T("%s (%dcore/%dthreads)"), (LPCTSTR)name, *cores, *threads); + } + } + else + { + cpuInfo = name; + } + + break; + } + } + } + } + } + } + catch (...) + { + + } + + SAFE_RELEASE(pCOMDev); + SAFE_RELEASE(pEnumCOMDevs); + SAFE_RELEASE(pIWbemServices); + SAFE_RELEASE(pIWbemLocator); + + if (cpuInfo.IsEmpty()) + { + TCHAR str[256] = {}; + DWORD value = 0; + DWORD type = REG_SZ; + ULONG size = 256 * sizeof(TCHAR); + HKEY hKey = NULL; + +#if defined(_M_IX86) || defined(_M_X64) + char brandString[49] = { 0 }; + getCpuName(brandString); + //getProcessorBrandString(brandString); + cpuInfo = brandString; + cpuInfo.TrimLeft(); + cpuInfo.TrimRight(); +#endif + + if (cpuInfo.IsEmpty() && !IsWin9x()) + { + if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0"), 0, KEY_READ, &hKey) == ERROR_SUCCESS) + { + if (RegQueryValueEx(hKey, _T("ProcessorNameString"), NULL, &type, (LPBYTE)str, &size) == ERROR_SUCCESS) + { + cpuInfo = str; + cpuInfo.TrimLeft(); + cpuInfo.TrimRight(); + } + } + } + +#ifdef _M_IX86 + +#endif + cpuName = cpuInfo; + + if (!IsWin9x()) + { + if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0"), 0, KEY_READ, &hKey) == ERROR_SUCCESS) + { + type = REG_DWORD; + size = sizeof(DWORD); + if (RegQueryValueEx(hKey, _T("~MHz"), NULL, &type, (LPBYTE)&value, &size) == ERROR_SUCCESS) + { + cpuInfo.Format(_T("%s %dMHz"), (LPCTSTR)cpuInfo, value); + if (clock != NULL) { *clock = (int)value; } + } + RegCloseKey(hKey); + } + } + + GetProcessorInfo(cores, threads); + if (*cores > 0 && *threads > 0) + { + CString cstr; + if (*cores > 1 && *threads > 1) + { + cstr.Format(_T(" (%dcores/%dthreads)"), *cores, *threads); + } + else if(*cores == 1 && *threads == 1) + { + cstr.Format(_T(" (%dcore/%dthread)"), *cores, *threads); + } + else if (*cores == 1) + { + cstr.Format(_T(" (%dcore/%dthreads)"), *cores, *threads); + } + + cpuInfo += cstr; + } + } + + cpuName.Replace(_T("(R)"), _T("")); + cpuName.Replace(_T("(r)"), _T("")); + cpuName.Replace(_T("(TM)"), _T("")); + cpuName.Replace(_T("(tm)"), _T("")); + cpuInfo.Replace(_T("(R)"), _T("")); + cpuInfo.Replace(_T("(TM)"), _T("")); + cpuInfo.Replace(_T("(t)"), _T("")); + cpuInfo.Replace(_T("(tm)"), _T("")); +} + +void GetGpuInfo(CString& gpuInfo) +{ +#if _MSC_VER > 1310 + #pragma comment(lib, "dxgi.lib") + + HMODULE hModule = LoadLibraryEx(_T("dxgi.dll"), NULL, LOAD_LIBRARY_SEARCH_SYSTEM32); + typedef HRESULT(WINAPI* FuncCreateDXGIFactory)(REFIID, void**); + FuncCreateDXGIFactory pCreateDXGIFactory = NULL; + + if (hModule != NULL) + { + pCreateDXGIFactory = (FuncCreateDXGIFactory)GetProcAddress(hModule, "CreateDXGIFactory"); + } + + if (pCreateDXGIFactory != NULL) + { + IDXGIFactory* pFactory = nullptr; + if (SUCCEEDED(pCreateDXGIFactory(__uuidof(IDXGIFactory), (void**)&pFactory))) + { + IDXGIAdapter* pAdapter = nullptr; + DXGI_ADAPTER_DESC adapterDesc; + + for (UINT i = 0; pFactory->EnumAdapters(i, &pAdapter) != DXGI_ERROR_NOT_FOUND; ++i) + { + pAdapter->GetDesc(&adapterDesc); + + CString cstr; + cstr.Format(L"%s [%dMB]", adapterDesc.Description, (int)(adapterDesc.DedicatedVideoMemory / (1024 * 1024))); + + if (cstr.Find(L"Microsoft Basic Render Driver") == 0) + { + pAdapter->Release(); + continue; + } + + if (gpuInfo.IsEmpty()) + { + gpuInfo = cstr; + } + else if (gpuInfo.Find(cstr) >= 0) + { + // Duplication + } + else + { + gpuInfo += _T(" | ") + cstr; + } + pAdapter->Release(); + } + pFactory->Release(); + } + } + + if (! gpuInfo.IsEmpty()) + { + gpuInfo.Replace(_T("(R)"), _T("")); + gpuInfo.Replace(_T("(TM)"), _T("")); + return; + } +#endif + + CString query = _T("Select * from Win32_VideoController"); + + IWbemLocator* pIWbemLocator = NULL; + IWbemServices* pIWbemServices = NULL; + IEnumWbemClassObject* pEnumCOMDevs = NULL; + IWbemClassObject* pCOMDev = NULL; + ULONG uReturned = 0; + BOOL flag = FALSE; + + try + { + if (SUCCEEDED(CoCreateInstance(CLSID_WbemLocator, NULL, CLSCTX_INPROC_SERVER, + IID_IWbemLocator, (LPVOID*)&pIWbemLocator))) + { + long securityFlag = 0; +#if _MSC_VER > 1310 + if (IsWindowsVersionOrGreaterFx(6, 0)) { securityFlag = WBEM_FLAG_CONNECT_USE_MAX_WAIT; } +#endif + if (SUCCEEDED(pIWbemLocator->ConnectServer(_bstr_t(_T("root\\cimv2")), + NULL, NULL, 0L, securityFlag, NULL, NULL, &pIWbemServices))) + { +#if _MSC_VER > 1310 + if (SUCCEEDED(CoSetProxyBlanket(pIWbemServices, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, + NULL, RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE))) +#endif + { + if (SUCCEEDED(pIWbemServices->ExecQuery(_bstr_t(_T("WQL")), + _bstr_t(query), WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, NULL, &pEnumCOMDevs))) + { + while (pEnumCOMDevs && SUCCEEDED(pEnumCOMDevs->Next(10000, 1, &pCOMDev, &uReturned)) && uReturned == 1) + { + CString name; + + VARIANT pVal; + VariantInit(&pVal); + if (pCOMDev->Get(L"Name", 0L, &pVal, NULL, NULL) == WBEM_S_NO_ERROR && pVal.vt > VT_NULL) + { + name = pVal.bstrVal; + name.TrimLeft(); + name.TrimRight(); + VariantClear(&pVal); + } + + // exclusion + // if (name.Find(_T("Virtual")) >= 0 || name.Find(_T("Remote")) >= 0 || name.Find(_T("ASPEED")) == 0) + if (gpuInfo.IsEmpty()) + { + gpuInfo = name; + } + else + { + gpuInfo += _T(" | ") + name; + } + } + } + } + } + } + } + catch (...) + { + + } + + SAFE_RELEASE(pCOMDev); + SAFE_RELEASE(pEnumCOMDevs); + SAFE_RELEASE(pIWbemServices); + SAFE_RELEASE(pIWbemLocator); + +#ifndef UNICODE + if (IsWin9x()) + { + TCHAR str[256] = { 0 }; + GetPrivateProfileStringFx(_T("boot.description"), _T("display.drv"), _T(""), str, 256, _T("system.ini")); + gpuInfo = str; + } +#endif + + if (gpuInfo.IsEmpty()) + { + TCHAR str[256] = {}; + DWORD value = 0; + DWORD type = REG_SZ; + ULONG size = 256 * sizeof(TCHAR); + HKEY hKey = NULL; + + // GPU + if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("SYSTEM\\CurrentControlSet\\Control\\Class\\{4d36e968-e325-11ce-bfc1-08002be10318}\\0000"), 0, KEY_READ, &hKey) == ERROR_SUCCESS) + { + type = REG_SZ; + size = 256 * sizeof(TCHAR); + if (RegQueryValueEx(hKey, _T("DriverDesc"), NULL, &type, (LPBYTE)str, &size) == ERROR_SUCCESS) + { + gpuInfo = str; + gpuInfo.TrimLeft(); + gpuInfo.TrimRight(); + } + RegCloseKey(hKey); + } + if (gpuInfo.IsEmpty()) + { + if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("SYSTEM\\CurrentControlSet\\Control\\Class\\{4d36e968-e325-11ce-bfc1-08002be10318}\\0001"), 0, KEY_READ, &hKey) == ERROR_SUCCESS) + { + type = REG_SZ; + size = 256 * sizeof(TCHAR); + if (RegQueryValueEx(hKey, _T("DriverDesc"), NULL, &type, (LPBYTE)str, &size) == ERROR_SUCCESS) + { + gpuInfo = str; + gpuInfo.TrimLeft(); + gpuInfo.TrimRight(); + } + RegCloseKey(hKey); + } + } + if (gpuInfo.IsEmpty()) + { + TCHAR str[256] = {}; + DWORD value = 0; + DWORD type = REG_SZ; + ULONG size = 256 * sizeof(TCHAR); + HKEY hKey = NULL; + HKEY hKey2 = NULL; + type = REG_SZ; + size = 256 * sizeof(TCHAR); + CString videoKey, key; + if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("HARDWARE\\DEVICEMAP\\VIDEO"), 0, KEY_READ, &hKey) == ERROR_SUCCESS) + { + for (int i = 0; i < 10; i++) + { + videoKey.Format(_T("\\Device\\Video%d"), i); + key = _T(""); + if (RegQueryValueEx(hKey, videoKey, NULL, &type, (LPBYTE)str, &size) == ERROR_SUCCESS) + { + key = str; + } + + if (!key.IsEmpty()) + { + key.MakeLower().Replace(_T("\\registry\\machine\\"), _T("")); + if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, key, 0, KEY_READ, &hKey2) == ERROR_SUCCESS) + { + type = REG_SZ; + size = 256 * sizeof(TCHAR); + if (RegQueryValueEx(hKey2, _T("DriverDesc"), NULL, &type, (LPBYTE)str, &size) == ERROR_SUCCESS) + { + CString cstr = str; + cstr.TrimLeft(); + cstr.TrimRight(); + + if (gpuInfo.IsEmpty()) + { + gpuInfo = cstr; + } + else + { + gpuInfo += _T(" | ") + cstr; + } + RegCloseKey(hKey2); + break; + } + + type = REG_BINARY; + if (RegQueryValueEx(hKey2, _T("HardwareInformation.AdapterString"), NULL, &type, (LPBYTE)str, &size) == ERROR_SUCCESS) + { + #ifndef UNICODE + char buf[256] = {}; + WideCharToMultiByte(CP_ACP, 0, (WCHAR*)str, size, buf, 256, 0, 0); + CString cstr = buf; + #else + CString cstr = str; + #endif + cstr.TrimLeft(); + cstr.TrimRight(); + + if (gpuInfo.IsEmpty()) + { + gpuInfo = cstr; + } + else + { + gpuInfo += _T(" | ") + cstr; + } + RegCloseKey(hKey2); + break; + } + else + { + _tcscpy(str, key); + #if _MSC_VER > 1310 + PathRemoveFileSpec(str); + CString cstr = PathFindFileName(str); + #else + PathRemoveFileSpecFx(str); + CString cstr = PathFindFileNameFx(str); + #endif + cstr += _T(" compatible device"); + if (gpuInfo.IsEmpty()) + { + gpuInfo = cstr; + } + else + { + gpuInfo += _T(" | ") + cstr; + } + RegCloseKey(hKey2); + break; + } + } + } + } + RegCloseKey(hKey); + } + } + } + + gpuInfo.Replace(_T("(R)"), _T("")); + gpuInfo.Replace(_T("(TM)"), _T("")); +} + +void GetBaseBoardInfo(CString& baseBoardInfo) +{ + CString query = _T("Select * from Win32_BaseBoard"); + + IWbemLocator* pIWbemLocator = NULL; + IWbemServices* pIWbemServices = NULL; + IEnumWbemClassObject* pEnumCOMDevs = NULL; + IWbemClassObject* pCOMDev = NULL; + ULONG uReturned = 0; + BOOL flag = FALSE; + + try + { + if (SUCCEEDED(CoCreateInstance(CLSID_WbemLocator, NULL, CLSCTX_INPROC_SERVER, + IID_IWbemLocator, (LPVOID*)&pIWbemLocator))) + { + long securityFlag = 0; +#if _MSC_VER > 1310 + if (IsWindowsVersionOrGreaterFx(6, 0)) { securityFlag = WBEM_FLAG_CONNECT_USE_MAX_WAIT; } +#endif + if (SUCCEEDED(pIWbemLocator->ConnectServer(_bstr_t(_T("root\\cimv2")), + NULL, NULL, 0L, securityFlag, NULL, NULL, &pIWbemServices))) + { +#if _MSC_VER > 1310 + if (SUCCEEDED(CoSetProxyBlanket(pIWbemServices, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, + NULL, RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE))) +#endif + { + if (SUCCEEDED(pIWbemServices->ExecQuery(_bstr_t(_T("WQL")), + _bstr_t(query), WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, NULL, &pEnumCOMDevs))) + { + while (pEnumCOMDevs && SUCCEEDED(pEnumCOMDevs->Next(10000, 1, &pCOMDev, &uReturned)) && uReturned == 1) + { + CString manufacturer; + CString product; + + VARIANT pVal; + VariantInit(&pVal); + if (pCOMDev->Get(L"Manufacturer", 0L, &pVal, NULL, NULL) == WBEM_S_NO_ERROR && pVal.vt > VT_NULL) + { + manufacturer = pVal.bstrVal; + manufacturer.TrimLeft(); + manufacturer.TrimRight(); + VariantClear(&pVal); + } + if (pCOMDev->Get(L"Product", 0L, &pVal, NULL, NULL) == WBEM_S_NO_ERROR && pVal.vt > VT_NULL) + { + product = pVal.bstrVal; + product.TrimLeft(); + product.TrimRight(); + VariantClear(&pVal); + } + baseBoardInfo = manufacturer + _T(" ") + product; + + baseBoardInfo.Replace(_T("To Be Filled By O.E.M."), _T("")); + baseBoardInfo.Replace(_T("To be filled by O.E.M."), _T("")); + baseBoardInfo.Replace(_T("Not Available"), _T("")); + baseBoardInfo.TrimLeft(); + baseBoardInfo.TrimRight(); + } + } + } + } + } + } + catch (...) + { + + } + + SAFE_RELEASE(pCOMDev); + SAFE_RELEASE(pEnumCOMDevs); + SAFE_RELEASE(pIWbemServices); + SAFE_RELEASE(pIWbemLocator); + + if (baseBoardInfo.IsEmpty()) + { + TCHAR str[256] = {}; + DWORD value = 0; + DWORD type = REG_SZ; + ULONG size = 256 * sizeof(TCHAR); + HKEY hKey = NULL; + + // BaseBoard/System + if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("HARDWARE\\DESCRIPTION\\System\\BIOS"), 0, KEY_READ, &hKey) == ERROR_SUCCESS) + { + size = 256 * sizeof(TCHAR); + if (RegQueryValueEx(hKey, _T("BaseBoardManufacturer"), NULL, &type, (LPBYTE)str, &size) == ERROR_SUCCESS) + { + baseBoardInfo = str; + + } + size = 256 * sizeof(TCHAR); + if (RegQueryValueEx(hKey, _T("BaseBoardProduct"), NULL, &type, (LPBYTE)str, &size) == ERROR_SUCCESS) + { + baseBoardInfo += _T(" "); + baseBoardInfo += str; + } + + baseBoardInfo.Replace(_T("To Be Filled By O.E.M."), _T("")); + baseBoardInfo.Replace(_T("To be filled by O.E.M."), _T("")); + baseBoardInfo.Replace(_T("Not Available"), _T("")); + baseBoardInfo.TrimLeft(); + baseBoardInfo.TrimRight(); + + RegCloseKey(hKey); + } + } +} + +void GetComputerSystemInfo(CString& computerSystemInfo) +{ + CString query = _T("Select * from Win32_ComputerSystem"); + + IWbemLocator* pIWbemLocator = NULL; + IWbemServices* pIWbemServices = NULL; + IEnumWbemClassObject* pEnumCOMDevs = NULL; + IWbemClassObject* pCOMDev = NULL; + ULONG uReturned = 0; + BOOL flag = FALSE; + + try + { + if (SUCCEEDED(CoCreateInstance(CLSID_WbemLocator, NULL, CLSCTX_INPROC_SERVER, + IID_IWbemLocator, (LPVOID*)&pIWbemLocator))) + { + long securityFlag = 0; +#if _MSC_VER > 1310 + if (IsWindowsVersionOrGreaterFx(6, 0)) { securityFlag = WBEM_FLAG_CONNECT_USE_MAX_WAIT; } +#endif + if (SUCCEEDED(pIWbemLocator->ConnectServer(_bstr_t(_T("root\\cimv2")), + NULL, NULL, 0L, securityFlag, NULL, NULL, &pIWbemServices))) + { +#if _MSC_VER > 1310 + if (SUCCEEDED(CoSetProxyBlanket(pIWbemServices, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, + NULL, RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE))) +#endif + { + if (SUCCEEDED(pIWbemServices->ExecQuery(_bstr_t(_T("WQL")), + _bstr_t(query), WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, NULL, &pEnumCOMDevs))) + { + while (pEnumCOMDevs && SUCCEEDED(pEnumCOMDevs->Next(10000, 1, &pCOMDev, &uReturned)) && uReturned == 1) + { + CString manufacturer; + CString model; + + VARIANT pVal; + VariantInit(&pVal); + if (pCOMDev->Get(L"Manufacturer", 0L, &pVal, NULL, NULL) == WBEM_S_NO_ERROR && pVal.vt > VT_NULL) + { + manufacturer = pVal.bstrVal; + manufacturer.TrimLeft(); + manufacturer.TrimRight(); + VariantClear(&pVal); + } + if (pCOMDev->Get(L"Model", 0L, &pVal, NULL, NULL) == WBEM_S_NO_ERROR && pVal.vt > VT_NULL) + { + model = pVal.bstrVal; + model.TrimLeft(); + model.TrimRight(); + VariantClear(&pVal); + } + computerSystemInfo = manufacturer + _T(" ") + model; + + computerSystemInfo.Replace(_T("To Be Filled By O.E.M."), _T("")); + computerSystemInfo.Replace(_T("To be filled by O.E.M."), _T("")); + computerSystemInfo.Replace(_T("System manufacturer"), _T("")); + computerSystemInfo.Replace(_T("System Product Name"), _T("")); + computerSystemInfo.Replace(_T("Not Available"), _T("")); + computerSystemInfo.TrimLeft(); + computerSystemInfo.TrimRight(); + } + } + } + } + } + } + catch (...) + { + + } + + SAFE_RELEASE(pCOMDev); + SAFE_RELEASE(pEnumCOMDevs); + SAFE_RELEASE(pIWbemServices); + SAFE_RELEASE(pIWbemLocator); + + if (computerSystemInfo.IsEmpty()) + { + TCHAR str[256] = {}; + DWORD value = 0; + DWORD type = REG_SZ; + ULONG size = 256 * sizeof(TCHAR); + HKEY hKey = NULL; + + // BaseBoard/System + if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("HARDWARE\\DESCRIPTION\\System\\BIOS"), 0, KEY_READ, &hKey) == ERROR_SUCCESS) + { + size = 256 * sizeof(TCHAR); + if (RegQueryValueEx(hKey, _T("SystemManufacturer"), NULL, &type, (LPBYTE)str, &size) == ERROR_SUCCESS) + { + computerSystemInfo = str; + } + size = 256 * sizeof(TCHAR); + if (RegQueryValueEx(hKey, _T("SystemProductName"), NULL, &type, (LPBYTE)str, &size) == ERROR_SUCCESS) + { + computerSystemInfo += _T(" "); + computerSystemInfo += str; + } + + computerSystemInfo.Replace(_T("To Be Filled By O.E.M."), _T("")); + computerSystemInfo.Replace(_T("To be filled by O.E.M."), _T("")); + computerSystemInfo.Replace(_T("Not Available"), _T("")); + computerSystemInfo.Replace(_T("System Product Name"), _T("")); + computerSystemInfo.Replace(_T("System manufacturer"), _T("")); + computerSystemInfo.TrimLeft(); + computerSystemInfo.TrimRight(); + + RegCloseKey(hKey); + } + } + +#if _MSC_VER <= 1310 + if (IsPC98()) + { + computerSystemInfo = _T("[PC-98] ") + computerSystemInfo; + } + else if (IsFMTOWNS()) + { + computerSystemInfo = _T("[FM TOWNS] ") + computerSystemInfo; + } +#endif +} + +void GetScreenInfo(CString& screenInfo, int* width, int* height, int* color, CString& smoothing) +{ + int screenWidth = GetSystemMetrics(SM_CXSCREEN); + int screenHeight = GetSystemMetrics(SM_CYSCREEN); + if(width != NULL){*width = screenWidth;} + if(height != NULL){*height = screenHeight;} + + HDC hDC = ::GetDC(NULL); + int bitsPerPixel = ::GetDeviceCaps(hDC, BITSPIXEL); + int planes = ::GetDeviceCaps(hDC, PLANES); + int colorDepth = bitsPerPixel * planes; + if(color != NULL){*color = colorDepth;} + ::ReleaseDC(NULL, hDC); + + DWORD fontSmoothingType = 0; + SystemParametersInfoW(SPI_GETFONTSMOOTHINGTYPE, 0, &fontSmoothingType, 0); + screenInfo.Format(_T("%dx%d %dbit"), screenWidth, screenHeight, colorDepth); + + if (fontSmoothingType == FE_FONTSMOOTHINGSTANDARD) + { + screenInfo += _T(" (Smoothing)"); + smoothing = _T("Smoothing"); + } + else if (fontSmoothingType == FE_FONTSMOOTHINGCLEARTYPE) + { + screenInfo += _T(" (ClearType)"); + smoothing = _T("ClearType"); + } +} + +void GetMemoryInfo(CString& memoryInfo, int* size) +{ +#if _MSC_VER > 1310 + MEMORYSTATUSEX memory = {}; + memory.dwLength = sizeof(memory); + GlobalMemoryStatusEx(&memory); + + if ((int)(memory.ullTotalPhys / 1024 / 1024 / 1024 + 1) > 1) + { + memoryInfo.Format(_T("%.1fGB"), (memory.ullTotalPhys / 1024.0 / 1024 / 1024)); + + } + else + { + memoryInfo.Format(_T("%dMB"), (int)(memory.ullTotalPhys / 1024.0 / 1024 + 1)); + } + if(size != NULL){*size = (int)(memory.ullTotalPhys / 1024.0 / 1024 + 1);} +#else + + // for Windows 2000 + typedef BOOL(WINAPI* FuncGlobalMemoryStatusEx)(LPMEMORYSTATUSEX); + HMODULE hModule = GetModuleHandle(_T("kernel32.dll")); + FuncGlobalMemoryStatusEx pGlobalMemoryStatusEx = NULL; + if (hModule) + { + pGlobalMemoryStatusEx = (FuncGlobalMemoryStatusEx)GetProcAddress(hModule, "GlobalMemoryStatusEx"); + } + + if (pGlobalMemoryStatusEx != NULL) // for Windows 2000 + { + MEMORYSTATUSEX memory; + memory.dwLength = sizeof(memory); + pGlobalMemoryStatusEx(&memory); + + if ((int)(memory.ullTotalPhys / 1024 / 1024 / 1024 + 1) > 1) + { + memoryInfo.Format(_T("%.1fGB"), (memory.ullTotalPhys / 1024.0 / 1024 / 1024)); + + } + else + { + memoryInfo.Format(_T("%dMB"), (int)(memory.ullTotalPhys / 1024.0 / 1024 + 1)); + } + if (size != NULL) { *size = (int)(memory.ullTotalPhys / 1024.0 / 1024 + 1); } + } + else + { + MEMORYSTATUS memory; + memory.dwLength = sizeof(memory); + GlobalMemoryStatus(&memory); + + if ((int)(memory.dwTotalPhys / 1024 / 1024 / 1024 + 1) > 1) + { + memoryInfo.Format(_T("%.1fGB"), (memory.dwTotalPhys / 1024.0 / 1024 / 1024)); + + } + else + { + memoryInfo.Format(_T("%dMB"), (int)(memory.dwTotalPhys / 1024.0 / 1024 + 1)); +} + if (size != NULL) { *size = (int)(memory.dwTotalPhys / 1024.0 / 1024 + 1); } + } +#endif +} + +#if _MSC_VER <= 1310 +/// https://www.betaarchive.com/wiki/index.php/Microsoft_KB_Archive/124207 +BOOL IsCoProcessorPresent() +{ +#define MY_ERROR_WRONG_OS 0x20000000 + HKEY hKey; + SYSTEM_INFO SystemInfo; + + // return FALSE if we are not running under Windows NT + // this should be expanded to cover alternative Win32 platforms + + if (!(GetVersion() & 0x7FFFFFFF)) + { + SetLastError(MY_ERROR_WRONG_OS); + return(FALSE); + } + + // we return TRUE if we're not running on x86 + // other CPUs have built in floating-point, with no registry entry + + GetSystemInfo(&SystemInfo); + + if ((SystemInfo.dwProcessorType != PROCESSOR_INTEL_386) && + (SystemInfo.dwProcessorType != PROCESSOR_INTEL_486) && + (SystemInfo.dwProcessorType != PROCESSOR_INTEL_PENTIUM)) + { + return(TRUE); + } + + if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("HARDWARE\\DESCRIPTION\\System\\FloatingPointProcessor"), + 0, KEY_EXECUTE, &hKey) != ERROR_SUCCESS) + { + // GetLastError() will indicate ERROR_RESOURCE_DATA_NOT_FOUND + // if we can't find the key. This indicates no coprocessor present + return(FALSE); + } + + RegCloseKey(hKey); + return(TRUE); +} +#endif + diff --git a/CristalDiskMark/source/CrystalDiskMark/Priscilla/SystemInfoFx.h b/CristalDiskMark/source/CrystalDiskMark/Priscilla/SystemInfoFx.h new file mode 100644 index 0000000..81d3572 --- /dev/null +++ b/CristalDiskMark/source/CrystalDiskMark/Priscilla/SystemInfoFx.h @@ -0,0 +1,30 @@ +/*---------------------------------------------------------------------------*/ +// Author : hiyohiyo +// Mail : hiyohiyo@crystalmark.info +// Web : https://crystalmark.info/ +// License : MIT License +/*---------------------------------------------------------------------------*/ + +#pragma once + +//------------------------------------------------ +// System Info +//------------------------------------------------ + +void GetCpuInfo(CString& cpuInfo, CString& cpuName, int* clock, int* cores, int* threads); +void GetGpuInfo(CString& gpuInfo); +void GetBaseBoardInfo(CString& baseBoardInfo); +void GetComputerSystemInfo(CString& computerSystemInfo); +void GetScreenInfo(CString& screenInfo, int* width, int* height, int* color, CString& smoothing); +void GetMemoryInfo(CString& screenInfo, int* size = NULL); + +#if defined(_M_IX86) || defined(_M_X64) +void GetCpuid(unsigned int param, unsigned int* _eax, unsigned int* _ebx, unsigned int* _ecx, unsigned int* _edx); +void GetHypervisorVendorString(char* vendorString); +#endif + +#if _MSC_VER <= 1310 +/// https://www.betaarchive.com/wiki/index.php/Microsoft_KB_Archive/124207 +BOOL IsCoProcessorPresent(); +BOOL IsFMTOWNS(); +#endif \ No newline at end of file diff --git a/CristalDiskMark/source/CrystalDiskMark/Priscilla/UAHMenuBar.cpp b/CristalDiskMark/source/CrystalDiskMark/Priscilla/UAHMenuBar.cpp new file mode 100644 index 0000000..abf129d --- /dev/null +++ b/CristalDiskMark/source/CrystalDiskMark/Priscilla/UAHMenuBar.cpp @@ -0,0 +1,205 @@ +/*---------------------------------------------------------------------------*/ +// Author : adzm +// Web : https://github.com/adzm/win32-custom-menubar-aero-theme +// License : MIT License +// https://github.com/adzm/win32-custom-menubar-aero-theme/blob/main/LICENSE +/*---------------------------------------------------------------------------*/ + +#include "stdafx.h" +#include +#include +#include "UAHMenuBar.h" + +#pragma comment(lib, "uxtheme.lib") + +static HTHEME g_menuTheme = nullptr; +extern bool g_darkModeEnabled; + +// ugly colors for illustration purposes +static HBRUSH g_brBarBackground = CreateSolidBrush(RGB(0x2C, 0x2C, 0x2C)); + +void UAHDrawMenuNCBottomLine(HWND hWnd) +{ + MENUBARINFO mbi = { sizeof(mbi) }; + if (!GetMenuBarInfo(hWnd, OBJID_MENU, 0, &mbi)) + { + return; + } + + RECT rcClient = { 0 }; + GetClientRect(hWnd, &rcClient); + MapWindowPoints(hWnd, nullptr, (POINT*)&rcClient, 2); + + RECT rcWindow = { 0 }; + GetWindowRect(hWnd, &rcWindow); + + OffsetRect(&rcClient, -rcWindow.left, -rcWindow.top); + + // the rcBar is offset by the window rect + RECT rcAnnoyingLine = rcClient; + rcAnnoyingLine.bottom = rcAnnoyingLine.top; + rcAnnoyingLine.top--; + + + HDC hdc = GetWindowDC(hWnd); + FillRect(hdc, &rcAnnoyingLine, g_brBarBackground); + ReleaseDC(hWnd, hdc); +} + +// processes messages related to UAH / custom menubar drawing. +// return true if handled, false to continue with normal processing in your wndproc +bool UAHWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, LRESULT* lr) +{ + if (! g_darkModeEnabled) + { + return false; + } + + switch (message) + { + case WM_UAHDRAWMENU: + { + UAHMENU* pUDM = (UAHMENU*)lParam; + RECT rc = { 0 }; + + // get the menubar rect + { + MENUBARINFO mbi = { sizeof(mbi) }; + GetMenuBarInfo(hWnd, OBJID_MENU, 0, &mbi); + + RECT rcWindow; + GetWindowRect(hWnd, &rcWindow); + + // the rcBar is offset by the window rect + rc = mbi.rcBar; + OffsetRect(&rc, -rcWindow.left, -rcWindow.top); + } + + FillRect(pUDM->hdc, &rc, g_brBarBackground); + + return true; + } + case WM_UAHDRAWMENUITEM: + { + typedef HRESULT(WINAPI* FuncDrawThemeTextEx)(HTHEME hTheme, HDC hdc, + int iPartId, int iStateId, LPCWSTR pszText, int iCharCount, DWORD dwTextFlags, + LPRECT pRect, const DTTOPTS* pOptions); + + static bool bInitialized = false; + static FuncDrawThemeTextEx pDrawThemeTextEx = NULL; + + if (bInitialized == false) + { + HMODULE hModule = GetModuleHandle(_T("UxTheme.dll")); + if (hModule) + { + pDrawThemeTextEx = (FuncDrawThemeTextEx)GetProcAddress(hModule, "DrawThemeTextEx"); + } + bInitialized = true; + } + + if (pDrawThemeTextEx == NULL) + { + return false; + } + + UAHDRAWMENUITEM* pUDMI = (UAHDRAWMENUITEM*)lParam; + + // ugly colors for illustration purposes + static HBRUSH g_brItemBackground = CreateSolidBrush(RGB(0x2C, 0x2C, 0x2C)); + static HBRUSH g_brItemBackgroundHot = CreateSolidBrush(RGB(0x35, 0x35, 0x35)); + static HBRUSH g_brItemBackgroundSelected = CreateSolidBrush(RGB(0x35, 0x35, 0x35)); + + HBRUSH* pbrBackground = &g_brItemBackground; + + // get the menu item string + wchar_t menuString[256] = { 0 }; + MENUITEMINFO mii = { sizeof(mii), MIIM_STRING }; + { + mii.dwTypeData = menuString; + mii.cch = (sizeof(menuString) / 2) - 1; + + GetMenuItemInfo(pUDMI->um.hmenu, pUDMI->umi.iPosition, TRUE, &mii); + } + + // get the item state for drawing + + DWORD dwFlags = DT_CENTER | DT_SINGLELINE | DT_VCENTER; + + int iTextStateID = 0; + int iBackgroundStateID = 0; + { + if ((pUDMI->dis.itemState & ODS_INACTIVE) | (pUDMI->dis.itemState & ODS_DEFAULT)) { + // normal display + iTextStateID = MPI_NORMAL; + iBackgroundStateID = MPI_NORMAL; + } + if (pUDMI->dis.itemState & ODS_HOTLIGHT) { + // hot tracking + iTextStateID = MPI_HOT; + iBackgroundStateID = MPI_HOT; + + pbrBackground = &g_brItemBackgroundHot; + } + if (pUDMI->dis.itemState & ODS_SELECTED) { + // clicked -- MENU_POPUPITEM has no state for this, though MENU_BARITEM does + iTextStateID = MPI_HOT; + iBackgroundStateID = MPI_HOT; + + pbrBackground = &g_brItemBackgroundSelected; + } + if ((pUDMI->dis.itemState & ODS_GRAYED) || (pUDMI->dis.itemState & ODS_DISABLED)) { + // disabled / grey text + iTextStateID = MPI_DISABLED; + iBackgroundStateID = MPI_DISABLED; + } + if (pUDMI->dis.itemState & ODS_NOACCEL) { + dwFlags |= DT_HIDEPREFIX; + } + } + + if (!g_menuTheme) { + g_menuTheme = OpenThemeData(hWnd, L"Menu"); + } + + DTTOPTS opts = { sizeof(opts), DTT_TEXTCOLOR | DTT_COMPOSITED | DTT_GLOWSIZE, RGB(0xFF, 0xFF, 0xFF), iTextStateID != MPI_DISABLED ? RGB(0xFF, 0xFF, 0xFF) : RGB(0xC0, 0xC0, 0xC0) }; + //opts.dwFlags = ; + + FillRect(pUDMI->um.hdc, &pUDMI->dis.rcItem, *pbrBackground); + pDrawThemeTextEx(g_menuTheme, pUDMI->um.hdc, MENU_BARITEM, MBI_NORMAL, menuString, mii.cch, dwFlags, &pUDMI->dis.rcItem, &opts); + + return true; + } + case WM_UAHMEASUREMENUITEM: + { + UAHMEASUREMENUITEM* pMmi = (UAHMEASUREMENUITEM*)lParam; + + // allow the default window procedure to handle the message + // since we don't really care about changing the width + *lr = DefWindowProc(hWnd, message, wParam, lParam); + + // but we can modify it here to make it 1/3rd wider for example + //pMmi->mis.itemWidth = (pMmi->mis.itemWidth * 5) / 4; + + return true; + } + case WM_THEMECHANGED: + { + if (g_menuTheme) { + CloseThemeData(g_menuTheme); + g_menuTheme = nullptr; + } + // continue processing in main wndproc + return false; + } + case WM_NCPAINT: + case WM_NCACTIVATE: + *lr = DefWindowProc(hWnd, message, wParam, lParam); + UAHDrawMenuNCBottomLine(hWnd); + return true; + break; + default: + return false; + } +} + diff --git a/CristalDiskMark/source/CrystalDiskMark/Priscilla/UAHMenuBar.h b/CristalDiskMark/source/CrystalDiskMark/Priscilla/UAHMenuBar.h new file mode 100644 index 0000000..2420066 --- /dev/null +++ b/CristalDiskMark/source/CrystalDiskMark/Priscilla/UAHMenuBar.h @@ -0,0 +1,78 @@ +/*---------------------------------------------------------------------------*/ +// Author : adzm +// Web : https://github.com/adzm/win32-custom-menubar-aero-theme +// License : MIT License +// https://github.com/adzm/win32-custom-menubar-aero-theme/blob/main/LICENSE +/*---------------------------------------------------------------------------*/ + +#pragma once + +// processes messages related to UAH / custom menubar drawing. +// return true if handled, false to continue with normal processing in your wndproc +bool UAHWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, LRESULT* lr); + +// window messages related to menu bar drawing +#define WM_UAHDESTROYWINDOW 0x0090 // handled by DefWindowProc +#define WM_UAHDRAWMENU 0x0091 // lParam is UAHMENU +#define WM_UAHDRAWMENUITEM 0x0092 // lParam is UAHDRAWMENUITEM +#define WM_UAHINITMENU 0x0093 // handled by DefWindowProc +#define WM_UAHMEASUREMENUITEM 0x0094 // lParam is UAHMEASUREMENUITEM +#define WM_UAHNCPAINTMENUPOPUP 0x0095 // handled by DefWindowProc + +// describes the sizes of the menu bar or menu item +typedef union tagUAHMENUITEMMETRICS +{ + // cx appears to be 14 / 0xE less than rcItem's width! + // cy 0x14 seems stable, i wonder if it is 4 less than rcItem's height which is always 24 atm + struct { + DWORD cx; + DWORD cy; + } rgsizeBar[2]; + struct { + DWORD cx; + DWORD cy; + } rgsizePopup[4]; +} UAHMENUITEMMETRICS; + +// not really used in our case but part of the other structures +typedef struct tagUAHMENUPOPUPMETRICS +{ + DWORD rgcx[4]; + DWORD fUpdateMaxWidths : 2; // from kernel symbols, padded to full dword +} UAHMENUPOPUPMETRICS; + +// hmenu is the main window menu; hdc is the context to draw in +typedef struct tagUAHMENU +{ + HMENU hmenu; + HDC hdc; + DWORD dwFlags; // no idea what these mean, in my testing it's either 0x00000a00 or sometimes 0x00000a10 +} UAHMENU; + +// menu items are always referred to by iPosition here +typedef struct tagUAHMENUITEM +{ + int iPosition; // 0-based position of menu item in menubar + UAHMENUITEMMETRICS umim; + UAHMENUPOPUPMETRICS umpm; +} UAHMENUITEM; + +// the DRAWITEMSTRUCT contains the states of the menu items, as well as +// the position index of the item in the menu, which is duplicated in +// the UAHMENUITEM's iPosition as well +typedef struct UAHDRAWMENUITEM +{ + DRAWITEMSTRUCT dis; // itemID looks uninitialized + UAHMENU um; + UAHMENUITEM umi; +} UAHDRAWMENUITEM; + +// the MEASUREITEMSTRUCT is intended to be filled with the size of the item +// height appears to be ignored, but width can be modified +typedef struct tagUAHMEASUREMENUITEM +{ + MEASUREITEMSTRUCT mis; + UAHMENU um; + UAHMENUITEM umi; +} UAHMEASUREMENUITEM; + diff --git a/CristalDiskMark/source/CrystalDiskMark/Priscilla/UtilityFx.cpp b/CristalDiskMark/source/CrystalDiskMark/Priscilla/UtilityFx.cpp new file mode 100644 index 0000000..e2f0a5d --- /dev/null +++ b/CristalDiskMark/source/CrystalDiskMark/Priscilla/UtilityFx.cpp @@ -0,0 +1,1038 @@ +/*---------------------------------------------------------------------------*/ +// Author : hiyohiyo +// Mail : hiyohiyo@crystalmark.info +// Web : https://crystalmark.info/ +// License : MIT License +/*---------------------------------------------------------------------------*/ + +#include "stdafx.h" +#include "UtilityFx.h" + +#include +#pragma comment(lib,"version.lib") + +////------------------------------------------------ +// Debug +////------------------------------------------------ + +static const DWORD DEBUG_MODE_NONE = 0; +static const DWORD DEBUG_MODE_LOG = 1; +static const DWORD DEBUG_MODE_MESSAGE = 2; + +static DWORD debugMode = DEBUG_MODE_NONE; + +void SetDebugMode(DWORD mode) +{ + if (mode <= DEBUG_MODE_MESSAGE) + { + debugMode = mode; + } + else + { + debugMode = DEBUG_MODE_NONE; + } +} + +void DebugPrint(CString cstr) +{ + static BOOL flag = TRUE; + static TCHAR file[MAX_PATH] = _T(""); + static DWORD first = (DWORD)GetTickCountFx(); + CString output; + + output.Format(_T("%08d "), (DWORD)GetTickCountFx() - first); + output += cstr; + output.Append(_T("\n")); + output.Replace(_T("\r"), _T("")); + + if (flag) + { + TCHAR* ptrEnd; + ::GetModuleFileName(NULL, file, MAX_PATH); + if ((ptrEnd = _tcsrchr(file, '.')) != NULL) + { + *ptrEnd = '\0'; +#if _MSC_VER <= 1310 + _tcscat(file, _T(".log")); +#else + _tcscat_s(file, MAX_PATH, _T(".log")); +#endif + } + DeleteFile(file); + flag = FALSE; + } + + if (debugMode == DEBUG_MODE_NONE) + { + return; + } + + FILE* fp = NULL; +#if _MSC_VER <= 1310 + fp = _tfopen(file, _T("ac")); +#else + _tfopen_s(&fp, file, _T("ac")); +#endif + + if (fp != NULL) + { + _ftprintf(fp, _T("%s"), (LPCTSTR)output); + fflush(fp); + fclose(fp); + } + + if (debugMode == DEBUG_MODE_MESSAGE) + { + AfxMessageBox(output); + } +} + +////------------------------------------------------ +// File Information +////------------------------------------------------ + +int GetFileVersion(const TCHAR* file, TCHAR* version) +{ + ULONG reserved = 0; + VS_FIXEDFILEINFO vffi = { 0 }; + TCHAR* buf = NULL; + int Locale = 0; + TCHAR str[256] = { 0 }; + + UINT size = GetFileVersionInfoSize((TCHAR*)file, &reserved); + TCHAR* vbuf = new TCHAR[size]; + if (GetFileVersionInfo((TCHAR*)file, 0, size, vbuf)) + { + VerQueryValue(vbuf, _T("\\"), (void**)&buf, &size); + CopyMemory(&vffi, buf, sizeof(VS_FIXEDFILEINFO)); + + VerQueryValue(vbuf, _T("\\VarFileInfo\\Translation"), (void**)&buf, &size); + CopyMemory(&Locale, buf, sizeof(int)); + wsprintf(str, _T("\\StringFileInfo\\%04X%04X\\%s"), + LOWORD(Locale), HIWORD(Locale), _T("FileVersion")); + VerQueryValue(vbuf, str, (void**)&buf, &size); + +#if _MSC_VER <= 1310 + _tcscpy(str, buf); +#else + _tcscpy_s(str, 256, buf); +#endif + + if (version != NULL) + { +#if _MSC_VER <= 1310 + _tcscpy(version,buf); +#else + _tcscpy_s(version, 256, buf); +#endif + } + } + delete[] vbuf; + + if (_tcscmp(str, _T("")) != 0) + { + return int(_tstof(str) * 100); + } + else + { + return 0; + } +} + +void GetFileVersionEx(const TCHAR* file, CString& version) +{ + ULONG reserved = 0; + VS_FIXEDFILEINFO vffi = { 0 }; + TCHAR* buf = NULL; + int Locale = 0; + TCHAR str[256] = { 0 }; + + UINT size = GetFileVersionInfoSize((TCHAR*)file, &reserved); + TCHAR* vbuf = new TCHAR[size]; + if (GetFileVersionInfo((TCHAR*)file, 0, size, vbuf)) + { + VerQueryValue(vbuf, _T("\\"), (void**)&buf, &size); + CopyMemory(&vffi, buf, sizeof(VS_FIXEDFILEINFO)); + + if (vffi.dwSignature == 0xfeef04bd) + { + version.Format(_T("%d.%d.%d.%d"), + HIWORD(vffi.dwFileVersionMS), + LOWORD(vffi.dwFileVersionMS), + HIWORD(vffi.dwFileVersionLS), + LOWORD(vffi.dwFileVersionLS)); + } + } + delete[] vbuf; +} + +BOOL IsFileExist(const TCHAR* path) +{ + FILE* fp = NULL; + +#if _MSC_VER <= 1310 + fp = _tfopen(path, _T("rb")); + if (fp == NULL) +#else + errno_t err = 0; + err = _tfopen_s(&fp, path, _T("rb")); + if (err != 0 || fp == NULL) +#endif + { + return FALSE; + } + fclose(fp); + return TRUE; +} + +BOOL CanWriteFile(const TCHAR* path) +{ + HANDLE hFile = CreateFile(path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, NULL); + + if (hFile == INVALID_HANDLE_VALUE) { return FALSE; } + const char* testData = "1"; + DWORD bytesWritten; + BOOL writeResult = WriteFile(hFile, testData, (DWORD)strlen(testData), &bytesWritten, NULL); + CloseHandle(hFile); + + return writeResult; +} + + +////------------------------------------------------ +// Utility +////------------------------------------------------ + +typedef ULONGLONG(WINAPI* FuncGetTickCount64)(); + +ULONGLONG GetTickCountFx() +{ + HMODULE hModule = GetModuleHandle(_T("kernel32.dll")); + FuncGetTickCount64 pGetTickCount64 = NULL; + if (hModule) + { + pGetTickCount64 = (FuncGetTickCount64)GetProcAddress(hModule, "GetTickCount64"); + } + + if (pGetTickCount64) + { + return (ULONGLONG)pGetTickCount64(); + } + else + { +#if _MSC_VER <= 1310 + return (ULONGLONG)GetTickCount(); +#else + return _Pragma("warning(suppress: 28159)") (ULONGLONG)GetTickCount(); +#endif + } +} + +ULONG64 B8toB64(BYTE b0, BYTE b1, BYTE b2, BYTE b3, BYTE b4, BYTE b5, BYTE b6, BYTE b7) +{ + ULONG64 data = + ((ULONG64)b7 << 56) + + ((ULONG64)b6 << 48) + + ((ULONG64)b5 << 40) + + ((ULONG64)b4 << 32) + + ((ULONG64)b3 << 24) + + ((ULONG64)b2 << 16) + + ((ULONG64)b1 << 8) + + ((ULONG64)b0 << 0); + + return data; +} + +DWORD B8toB32(BYTE b0, BYTE b1, BYTE b2, BYTE b3) +{ + DWORD data = + ((DWORD)b3 << 24) + + ((DWORD)b2 << 16) + + ((DWORD)b1 << 8) + + ((DWORD)b0 << 0); + + return data; +} + +void SplitCString(const CString& str, const CString& delimiter, CStringArray& arr) +{ + int startPos = 0; + while (startPos >= 0) + { + int endPos = str.Find(delimiter, startPos); + if (endPos == -1) + { + arr.Add(str.Mid(startPos)); + break; + } + arr.Add(str.Mid(startPos, endPos - startPos)); + startPos = endPos + lstrlen(delimiter); + } +} + + + +#if _MSC_VER > 1310 +// --------------------------------------------------------- +// 20260123: Safe for unaligned/page-boundary (Using memcpy for atomic-like MOV) >>> + +// Environment Validation (Compile-time) > +static_assert(sizeof(USHORT) == 2, "! (sizeof(USHORT) == 2)"); +static_assert(sizeof(INT) == 4, "! (sizeof(INT) == 4)"); +static_assert(sizeof(DWORD) == 4, "! (sizeof(DWORD) == 4)"); +static_assert(sizeof(ULONG64) == 8, "! (sizeof(ULONG64) == 8)"); + +// Boundary-Safe Loaders > + +NODISCARD ULONG64 B8toB64le_ptr(_In_reads_(8) const BYTE* v) noexcept { + ULONG64 u64; + ::memcpy(&u64, v, sizeof(u64)); + return u64; +} +NODISCARD DWORD B8toB32le_ptr(_In_reads_(4) const BYTE* v) noexcept { + return ((static_cast(v[0])) + | (static_cast(v[1]) << 8) + | (static_cast(v[2]) << 16) + | (static_cast(v[3]) << 24)); +} +NODISCARD INT B8toINTle_ptr(_In_reads_(4) const BYTE* v) noexcept { + return static_cast((static_cast(v[0])) + | (static_cast(v[1]) << 8) + | (static_cast(v[2]) << 16) + | (static_cast(v[3]) << 24)); +} +NODISCARD USHORT B8toB16le_ptr(_In_reads_(2) const BYTE* v) noexcept { + return static_cast((static_cast(v[0])) + | (static_cast(v[1]) << 8)); +} +NODISCARD SHORT B8toSHORTle_ptr(_In_reads_(2) const BYTE* v) noexcept { + return static_cast((static_cast(v[0])) + | (static_cast(v[1]) << 8)); +} +NODISCARD ULONG64 B8toB64le(const BYTE(&v)[6]) noexcept { + return ((static_cast(v[0])) + | (static_cast(v[1]) << 8) + | (static_cast(v[2]) << 16) + | (static_cast(v[3]) << 24) + | (static_cast(v[4]) << 32) + | (static_cast(v[5]) << 40)); +} +NODISCARD DWORD B8toB32le(const BYTE(&v)[6]) noexcept { + return ((static_cast(v[0])) + | (static_cast(v[1]) << 8) + | (static_cast(v[2]) << 16) + | (static_cast(v[3]) << 24)); +} +NODISCARD INT B8toINTle(const BYTE(&v)[6]) noexcept { + return static_cast((static_cast(v[0])) + | (static_cast(v[1]) << 8) + | (static_cast(v[2]) << 16) + | (static_cast(v[3]) << 24)); +} +NODISCARD USHORT B8toB16le(const BYTE(&v)[6]) noexcept { + return ((static_cast(v[0])) + | (static_cast(v[1]) << 8)); +} + +// 20260123: Safe for unaligned/page-boundary <<< +// --------------------------------------------------------- +#endif + + +////------------------------------------------------ +// .ini support function +////------------------------------------------------ + +DWORD GetPrivateProfileStringFx(LPCTSTR lpAppName, LPCTSTR lpKeyName, LPCTSTR lpDefault, LPTSTR lpReturnedString, DWORD nSize, LPCTSTR lpFileName) +{ + DWORD result = 0; + CString key = lpKeyName; + key.Replace(_T("="), _T("%#3D")); + key.Replace(_T("\""), _T("%#22")); + result = GetPrivateProfileString(lpAppName, key, lpDefault, lpReturnedString, nSize, lpFileName); + + CString value = lpReturnedString; + value.Replace(_T("%#3D"), _T("=")); + value.Replace(_T("%#22"), _T("\"")); + +#if _MSC_VER <= 1310 + _tcscpy(lpReturnedString, (LPCTSTR)value); +#else + _tcscpy_s(lpReturnedString, nSize, (LPCTSTR)value); +#endif + + return result; +} + +UINT GetPrivateProfileIntFx(LPCTSTR lpAppName, LPCTSTR lpKeyName, INT nDefault, LPCTSTR lpFileName) +{ + CString key = lpKeyName; + key.Replace(_T("="), _T("%#3D")); + key.Replace(_T("\""), _T("%#22")); + + return GetPrivateProfileInt(lpAppName, key, nDefault, lpFileName); +} + +BOOL WritePrivateProfileStringFx(LPCTSTR lpAppName, LPCTSTR lpKeyName, LPCTSTR lpString, LPCTSTR lpFileName) +{ + CString key = lpKeyName; + key.Replace(_T("="), _T("%#3D")); + key.Replace(_T("\""), _T("%#22")); + + CString value = lpString; + value.Replace(_T("="), _T("%#3D")); + value.Replace(_T("\""), _T("%#22")); + + value = _T("\"" + value + _T("\"")); + + return WritePrivateProfileString(lpAppName, key, value, lpFileName); +} + +////------------------------------------------------ +// Check CodeSign +////------------------------------------------------ +#if _MSC_VER > 1310 +#include +#pragma comment(lib, "Wintrust.lib") +#pragma comment(lib, "Crypt32.lib") + +BOOL CheckCodeSign(LPCWSTR certName, LPCWSTR filePath) +{ +#ifdef _DEBUG + return TRUE; +#endif + + // check sign + + WINTRUST_FILE_INFO FileData = { sizeof(WINTRUST_FILE_INFO) }; + FileData.pcwszFilePath = filePath; + + GUID WVTPolicyGUID = WINTRUST_ACTION_GENERIC_VERIFY_V2; + WINTRUST_DATA WinTrustData = { sizeof(WinTrustData) }; + WinTrustData.dwUIChoice = WTD_UI_NONE; + WinTrustData.fdwRevocationChecks = WTD_REVOKE_NONE; + WinTrustData.dwUnionChoice = WTD_CHOICE_FILE; + WinTrustData.dwStateAction = WTD_STATEACTION_VERIFY; + WinTrustData.pFile = &FileData; + + const LONG ret = WinVerifyTrust(NULL, &WVTPolicyGUID, &WinTrustData); + + bool cert_chk = false; + + if (ret == ERROR_SUCCESS) { + // retreive the signer certificate and display its information + CRYPT_PROVIDER_DATA const* psProvData = NULL; + CRYPT_PROVIDER_SGNR* psProvSigner = NULL; + CRYPT_PROVIDER_CERT* psProvCert = NULL; + + psProvData = WTHelperProvDataFromStateData(WinTrustData.hWVTStateData); + if (psProvData) { + psProvSigner = WTHelperGetProvSignerFromChain((PCRYPT_PROVIDER_DATA)psProvData, 0, FALSE, 0); + if (psProvSigner) { + psProvCert = WTHelperGetProvCertFromChain(psProvSigner, 0); + if (psProvCert) { + wchar_t szCertName[200] = {0}; + DWORD dwStrType = CERT_X500_NAME_STR; + CertGetNameStringW(psProvCert->pCert, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, &dwStrType, szCertName, 200); + cert_chk = !(szCertName[0] == '\0' || wcscmp(szCertName, certName) != 0); + } + } + } + } + WinTrustData.dwStateAction = WTD_STATEACTION_CLOSE; + (void)WinVerifyTrust(NULL, &WVTPolicyGUID, &WinTrustData); + if (!cert_chk) return FALSE; + + return TRUE; +} +#endif + +////------------------------------------------------ +// Play Sound +////------------------------------------------------ + +#include +#include "digitalv.h" + +#pragma comment(lib, "winmm.lib") + +/* +void ShowMciError(DWORD error) +{ + TCHAR errorBuf[MAXERRORLENGTH]; + + if (mciGetErrorString(error, (LPTSTR)errorBuf, MAXERRORLENGTH)) + { + AfxMessageBox(errorBuf); + } + else + { + AfxMessageBox(_T("Unknown Error"); + } +} +*/ + +BOOL AlertSound(const CString& alertSoundPath, int volume) +{ +#if _MSC_VER <= 1310 + PlaySound(alertSoundPath, NULL, SND_SYNC); +#else + + static MCI_OPEN_PARMS mop = { 0 }; + static MCI_PLAY_PARMS mpp = { 0 }; + static MCI_GENERIC_PARMS mgp = { 0 }; + MCIERROR error = 0; + + if (mop.wDeviceID != 0) + { + // Stop and close + error = mciSendCommandW(mop.wDeviceID, MCI_STOP, 0, 0); + error = mciSendCommandW(mop.wDeviceID, MCI_CLOSE, 0, 0); + mop.wDeviceID = 0; + ZeroMemory(&mop, sizeof(MCI_OPEN_PARMS)); + if (error) + { + // ShowMciError(error); + return FALSE; + } + } + + if (alertSoundPath.Compare(_T("")) == 0) { + // Close + error = mciSendCommandW(mop.wDeviceID, MCI_CLOSE, 0, 0); + if (error) + { + // ShowMciError(error); + return FALSE; + } + return TRUE; + } + + // Open + mop.lpstrElementName = (LPCTSTR)alertSoundPath; + mop.lpstrDeviceType = _T("MPEGVideo"); + error = mciSendCommandW(NULL, MCI_OPEN, MCI_OPEN_TYPE | MCI_OPEN_ELEMENT, (DWORD_PTR)(&mop)); + + if (error) + { + // ShowMciError(error); + return FALSE; + } + + // Set volume + if (volume < 0 || volume > 100) { volume = 80; } + + MCI_DGV_SETAUDIO_PARMS parms = { 0 }; + parms.dwItem = MCI_DGV_SETAUDIO_VOLUME; + parms.dwValue = volume * 10; // 0-1000 + error = mciSendCommand(mop.wDeviceID, MCI_SETAUDIO, MCI_DGV_SETAUDIO_ITEM | MCI_DGV_SETAUDIO_VALUE, (DWORD_PTR)&parms); + if (error) + { + // ShowMciError(error); + return FALSE; + } + // Seek + error = mciSendCommand(mop.wDeviceID, MCI_SEEK, MCI_SEEK_TO_START, reinterpret_cast(&mgp)); + if (error) + { + // ShowMciError(error); + return FALSE; + } + + // Play + error = mciSendCommandW(mop.wDeviceID, MCI_PLAY, 0, reinterpret_cast(&mpp)); + if (error) + { + // ShowMciError(error); + return FALSE; + } +#endif + + return TRUE; +} + + +////------------------------------------------------ +// Hash +////------------------------------------------------ + +#if _MSC_VER > 1310 +#include +#include +#include +#include +#include +CStringA MD5(const CStringA& str) +{ + HCRYPTPROV hProv = 0; + HCRYPTHASH hHash = 0; + BYTE hash[16]; + DWORD hashLen = 16; + CStringA hashStr; + + if (!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) { + return ""; + } + + if (!CryptCreateHash(hProv, CALG_MD5, 0, 0, &hHash)) { + CryptReleaseContext(hProv, 0); + return ""; + } + + std::string utf8Str(str); + + if (!CryptHashData(hHash, reinterpret_cast(utf8Str.c_str()), (DWORD)utf8Str.size(), 0)) { + CryptDestroyHash(hHash); + CryptReleaseContext(hProv, 0); + return ""; + } + + if (!CryptGetHashParam(hHash, HP_HASHVAL, hash, &hashLen, 0)) { + CryptDestroyHash(hHash); + CryptReleaseContext(hProv, 0); + return ""; + } + + for (DWORD i = 0; i < hashLen; ++i) { + CString temp; + temp.Format(_T("%02x"), hash[i]); + hashStr += temp; + } + + CryptDestroyHash(hHash); + CryptReleaseContext(hProv, 0); + + return hashStr; +} +#else +#include "md5.h" +CStringA MD5(const CStringA& str) +{ + char* input = (char*)(LPCSTR)str; + uint8_t result[16] = { 0 }; + md5String(input, result); + + CStringA hashStr; + for (int i = 0; i < 16; ++i) + { + CStringA byteStr; + byteStr.Format("%02x", result[i]); + hashStr += byteStr; + } + + return hashStr; +} +#endif + +////------------------------------------------------ +// Character Converter +////------------------------------------------------ + +CStringA URLEncode(const CStringA& str) +{ + CStringA encoded; + for (int i = 0; i < str.GetLength(); i++) + { + if (isalnum((BYTE)str[i]) || str[i] == '-' || str[i] == '_' || str[i] == '.' || str[i] == '~') + { + encoded += str[i]; + } + else + { + encoded.AppendFormat("%%%02X", (BYTE)str[i]); + } + } + return encoded; +} + +#if _MSC_VER <= 1310 + +// https://github.com/roytam1/RetroZilla/commit/e44dd98dbf2effeff3305430835e889d76ec73b4#diff-065242b491de972d8519dbbae0c4c8dfb6a1a3c3eb8b9936d56a4c1ad63ec7abR126-R282 +/*** UTF16<-->UTF8 functions minicking MultiByteToWideChar/WideCharToMultiByte ***/ +int utf8GetMaskIndex(unsigned char n) { + if ((unsigned char)(n + 2) < 0xc2) return 1; // 00~10111111, fe, ff + if (n < 0xe0) return 2; // 110xxxxx + if (n < 0xf0) return 3; // 1110xxxx + if (n < 0xf8) return 4; // 11110xxx + if (n < 0xfc) return 5; // 111110xx + return 6; // 1111110x +} + +int wc2Utf8Len(wchar_t** n, int* len) { + wchar_t* ch = *n, ch2; + int qch; + if ((0xD800 <= *ch && *ch <= 0xDBFF) && *len) { + ch2 = *(ch + 1); + if (0xDC00 <= ch2 && ch2 <= 0xDFFF) { + qch = 0x10000 + (((*ch - 0xD800) & 0x3ff) << 10) + ((ch2 - 0xDC00) & 0x3ff); + (*n)++; + (*len)--; + } + } + else + qch = (int)*ch; + + if (qch <= 0x7f) return 1; + else if (qch <= 0x7ff) return 2; + else if (qch <= 0xffff) return 3; + else if (qch <= 0x1fffff) return 4; + else if (qch <= 0x3ffffff) return 5; + else return 6; +} + +int Utf8ToWideChar(unsigned int unused1, unsigned long unused2, char* sb, int ss, wchar_t* wb, int ws) { + static const unsigned char utf8mask[] = { 0, 0xff, 0x1f, 0x0f, 0x07, 0x03, 0x01 }; + char* p = (char*)(sb); + char* e = (char*)(sb + ss); + wchar_t* w = wb; + int cnt = 0, t, qch; + + if (ss < 1) { + ss = lstrlenA(sb); + e = (char*)(sb + ss); + } + + if (wb && ws) { + for (; p < e; ++w) { + t = utf8GetMaskIndex(*p); + qch = (*p++ & utf8mask[t]); + while (p < e && --t) + qch <<= 6, qch |= (*p++) & 0x3f; + if (qch < 0x10000) { + if (cnt <= ws) + *w = (wchar_t)qch; + cnt++; + } + else { + if (cnt + 2 <= ws) { + *w++ = (wchar_t)(0xD800 + (((qch - 0x10000) >> 10) & 0x3ff)), + *w = (wchar_t)(0xDC00 + (((qch - 0x10000)) & 0x3ff)); + } + cnt += 2; + } + } + if (cnt < ws) { + *(wb + cnt) = 0; + return cnt; + } + else { + *(wb + ws) = 0; + return ws; + } + } + else { + for (t; p < e;) { + t = utf8GetMaskIndex(*p); + qch = (*p++ & utf8mask[t]); + while (p < e && --t) + qch <<= 6, qch |= (*p++) & 0x3f; + if (qch < 0x10000) + cnt++; + else + cnt += 2; + } + return cnt + 1; + } +} + +int WideCharToUtf8(unsigned int unused1, unsigned long unused2, wchar_t* wb, int ws, char* sb, int ss) { + wchar_t* p = (wchar_t*)(wb); + wchar_t* e = (wchar_t*)(wb + ws); + wchar_t* oldp; + char* s = sb; + int cnt = 0, qch, t; + + if (ws < 1) { + ws = lstrlenW(wb); + e = (wchar_t*)(wb + ws); + } + + if (sb && ss) { + for (t; p < e; ++p) { + oldp = p; + t = wc2Utf8Len(&p, &ws); + + if (p != oldp) { /* unicode surrogates encountered */ + qch = 0x10000 + (((*oldp - 0xD800) & 0x3ff) << 10) + ((*p - 0xDC00) & 0x3ff); + } + else + qch = *p; + + if (qch <= 0x7f) + *s++ = (char)(qch), + cnt++; + else if (qch <= 0x7ff) + *s++ = 0xc0 | (char)(qch >> 6), + *s++ = 0x80 | (char)(qch & 0x3f), + cnt += 2; + else if (qch <= 0xffff) + *s++ = 0xe0 | (char)(qch >> 12), + *s++ = 0x80 | (char)((qch >> 6) & 0x3f), + *s++ = 0x80 | (char)(qch & 0x3f), + cnt += 3; + else if (qch <= 0x1fffff) + *s++ = 0xf0 | (char)(qch >> 18), + *s++ = 0x80 | (char)((qch >> 12) & 0x3f), + *s++ = 0x80 | (char)((qch >> 6) & 0x3f), + *s++ = 0x80 | (char)(qch & 0x3f), + cnt += 4; + else if (qch <= 0x3ffffff) + *s++ = 0xf8 | (char)(qch >> 24), + *s++ = 0x80 | (char)((qch >> 18) & 0x3f), + *s++ = 0x80 | (char)((qch >> 12) & 0x3f), + *s++ = 0x80 | (char)((qch >> 6) & 0x3f), + *s++ = 0x80 | (char)(qch & 0x3f), + cnt += 5; + else + *s++ = 0xfc | (char)(qch >> 30), + *s++ = 0x80 | (char)((qch >> 24) & 0x3f), + *s++ = 0x80 | (char)((qch >> 18) & 0x3f), + *s++ = 0x80 | (char)((qch >> 12) & 0x3f), + *s++ = 0x80 | (char)((qch >> 6) & 0x3f), + *s++ = 0x80 | (char)(qch & 0x3f), + cnt += 6; + } + if (cnt < ss) { + *(sb + cnt) = 0; + return cnt; + } + else { + *(sb + ss) = 0; + return ss; + } + } + else { + for (t; p < e; ++p) { + t = wc2Utf8Len(&p, &ws); + cnt += t; + } + return cnt + 1; + } +} +/*** Ends ***/ + +#ifdef UNICODE +CStringA UTF16toUTF8(const CStringW& utf16str) +{ + if (IsNT3() || IsNT4()) + { + CStringA utf8str; + WCHAR* utf16string = new WCHAR[(utf16str.GetLength() + 1) * 2]; + wsprintf(utf16string, L"%s", utf16str); + int utf16Length = utf16str.GetLength(); + int utf8Length = WideCharToUtf8(CP_UTF8, 0, utf16string, -1, NULL, 0); + if (utf8Length <= 0) { return ""; } + WideCharToUtf8(CP_UTF8, 0, utf16string, -1, utf8str.GetBuffer(utf8Length), utf8Length); + utf8str.ReleaseBuffer(); + delete utf16string; + return utf8str; + } + else + { + CStringA utf8str; + int utf8Length = WideCharToMultiByte(CP_UTF8, 0, utf16str, -1, NULL, 0, NULL, NULL); + if (utf8Length <= 0) { return ""; } + WideCharToMultiByte(CP_UTF8, 0, utf16str, -1, utf8str.GetBuffer(utf8Length), utf8Length, NULL, NULL); + utf8str.ReleaseBuffer(); + return utf8str; + } +} + +CStringW UTF8toUTF16(const CStringA& utf8str) +{ + CStringW utf16str; + CHAR* utf8string = new CHAR[(utf8str.GetLength() + 1) * 2]; + sprintf(utf8string, "%s", utf8str); + int utf8Length = utf8str.GetLength(); + int utf16Length = Utf8ToWideChar(1200, 0, utf8string, -1, NULL, 0); + if (utf16Length <= 0) { return L""; } + Utf8ToWideChar(1200, 0, utf8string, -1, utf16str.GetBuffer(utf16Length), utf16Length); + utf16str.ReleaseBuffer(); + delete utf8string; + return utf16str; +} + +#else +CStringA ANSItoUTF8(const CStringA& ansiStr) +{ + int utf16Length = MultiByteToWideChar(CP_ACP, 0, ansiStr, -1, NULL, 0); + if (utf16Length <= 0) { return ""; } + CStringW utf16str; + MultiByteToWideChar(CP_ACP, 0, ansiStr, -1, utf16str.GetBuffer(utf16Length), utf16Length); + utf16str.ReleaseBuffer(); + + CStringA utf8str; + int utf8Length = WideCharToUtf8(CP_UTF8, 0, utf16str.GetBuffer(utf16Length), -1, NULL, 0); + if (utf8Length <= 0) { return ""; } + WideCharToUtf8(CP_UTF8, 0, utf16str.GetBuffer(utf16Length), -1, utf8str.GetBuffer(utf8Length), utf8Length); + utf8str.ReleaseBuffer(); + return utf8str; +} +#endif +#else + +CStringA UTF16toUTF8(const CStringW& utf16str) +{ + CStringA utf8str(CW2A(utf16str, CP_UTF8)); + return utf8str; +} + +CStringW UTF8toUTF16(const CStringA& utf8str) +{ + CStringW utf16str; + utf16str = CA2W(utf8str); + return utf16str; +} +#endif + +#ifdef UNICODE +CStringA UE(const CStringW& utf16str) +{ + return URLEncode(UTF16toUTF8(utf16str)); +} +#else +CStringA UE(const CStringA& ansiStr) +{ + return URLEncode(ANSItoUTF8(ansiStr)); +} +#endif +////------------------------------------------------ +// Clipboard +////------------------------------------------------ + +void SetClipboardText(CString clip) +{ + if (OpenClipboard(NULL)) + { + HGLOBAL clipbuffer; + TCHAR* buffer = NULL; + EmptyClipboard(); + clipbuffer = GlobalAlloc(GMEM_DDESHARE, sizeof(TCHAR) * (clip.GetLength() + 1)); + if (clipbuffer != NULL) + { + buffer = (TCHAR*)GlobalLock(clipbuffer); + if (buffer != NULL) + { +#if _MSC_VER <= 1310 + _tcscpy(buffer, LPCTSTR(clip)); +#else + _tcscpy_s(buffer, clip.GetLength() + 1, LPCTSTR(clip)); +#endif + } + GlobalUnlock(clipbuffer); +#ifdef UNICODE + SetClipboardData(CF_UNICODETEXT, clipbuffer); +#else + SetClipboardData(CF_TEXT, clipbuffer); +#endif + } + CloseClipboard(); + } +} + +////------------------------------------------------ +// SHLWAPI.DLL compatible functions +////------------------------------------------------ +#if _MSC_VER <= 1310 +BOOL PathRemoveFileSpecFxA(char* path) +{ + char* filespec = path; + BOOL modified = FALSE; + + if (!path || !*path) { return FALSE; } + if (*path == '\\') { filespec = ++path; } + if (*path == '\\') { filespec = ++path; } + + while (*path) + { + if (*path == '\\') + { + filespec = path; + } + else if (*path == ':') + { + filespec = ++path; + if (*path == '\\') { filespec++; } + } + path = CharNextA(path); + } + + if (*filespec) + { + *filespec = '\0'; + modified = TRUE; + } + + return modified; +} + +BOOL PathRemoveFileSpecFxW(WCHAR* path) +{ + WCHAR* filespec = path; + BOOL modified = FALSE; + + if (!path || !*path) { return FALSE; } + if (*path == '\\') { filespec = ++path; } + if (*path == '\\') { filespec = ++path; } + + while (*path) + { + if (*path == '\\') + { + filespec = path; + } + else if (*path == ':') + { + filespec = ++path; + if (*path == '\\') { filespec++; } + } + path++; + } + + if (*filespec) + { + *filespec = '\0'; + modified = TRUE; + } + + return modified; +} + +char* PathFindFileNameFxA(const char* path) +{ + const char* p = path; + const char* name = NULL; + while (*p) + { + if (*p == '\\' || *p == '/') + { + name = p + 1; + } + p = CharNextA(p); + } + if (name) + { + return (char*)name; + } + return (char*)path; +} + +WCHAR* PathFindFileNameFxW(const WCHAR* path) +{ + const WCHAR* p = path; + const WCHAR* name = NULL; + while (*p) + { + if (*p == '\\' || *p == '/') + { + name = p + 1; + } + p++; + } + if (name) + { + return (WCHAR*)name; + } + return (WCHAR*)path; +} +#endif \ No newline at end of file diff --git a/CristalDiskMark/source/CrystalDiskMark/Priscilla/UtilityFx.h b/CristalDiskMark/source/CrystalDiskMark/Priscilla/UtilityFx.h new file mode 100644 index 0000000..cc9bf07 --- /dev/null +++ b/CristalDiskMark/source/CrystalDiskMark/Priscilla/UtilityFx.h @@ -0,0 +1,143 @@ +/*---------------------------------------------------------------------------*/ +// Author : hiyohiyo +// Mail : hiyohiyo@crystalmark.info +// Web : https://crystalmark.info/ +// License : MIT License +/*---------------------------------------------------------------------------*/ + +#pragma once + +////------------------------------------------------ +// Debug +////------------------------------------------------ + +void SetDebugMode(DWORD mode); +void DebugPrint(CString cstr); + +////------------------------------------------------ +// File Information +////------------------------------------------------ + +int GetFileVersion(const TCHAR* fileName, TCHAR* version = NULL); +void GetFileVersionEx(const TCHAR* file, CString& version); +BOOL IsFileExist(const TCHAR* fileName); +BOOL CanWriteFile(const TCHAR* fileName); + +////------------------------------------------------ +// Utility +////------------------------------------------------ + +ULONGLONG GetTickCountFx(); + +ULONG64 B8toB64(BYTE b0, BYTE b1 = 0, BYTE b2 = 0, BYTE b3 = 0, BYTE b4 = 0, BYTE b5 = 0, BYTE b6 = 0, BYTE b7 = 0); +DWORD B8toB32(BYTE b0, BYTE b1 = 0, BYTE b2 = 0, BYTE b3 = 0); +void SplitCString(const CString& str, const CString& delimiter, CStringArray& arr); + +#if _MSC_VER > 1310 +// --------------------------------------------------------- +// 20260123: Safe for unaligned/page-boundary (Using memcpy for atomic-like MOV) >>> +#ifndef NODISCARD + #if (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) + #define NODISCARD [[nodiscard]] + #elif defined(_MSC_VER) && (_MSC_VER >= 1700) + #define NODISCARD _Check_return_ + #else + #define NODISCARD + #endif +#endif + +// SAL annotation support +#ifndef _In_reads_ + #ifdef _MSC_VER + #include + #endif + //without SAL + #ifndef _In_reads_ + #define _In_reads_(s) + #endif +#endif + +/* 8byte(le) to ULONG64 (Safe for unaligned/page-boundary) */ +NODISCARD ULONG64 B8toB64le_ptr(_In_reads_(8) const BYTE* v) noexcept; +/* 4byte(le) to DWORD (Safe for unaligned/page-boundary) */ +NODISCARD DWORD B8toB32le_ptr(_In_reads_(4) const BYTE* v) noexcept; +/* 4byte(le) to INT (Controlled sign extension) */ +NODISCARD INT B8toINTle_ptr(_In_reads_(4) const BYTE* v) noexcept; +/* 2byte(le) to USHORT (Safe for unaligned/page-boundary) */ +NODISCARD USHORT B8toB16le_ptr(_In_reads_(2) const BYTE* v) noexcept; +/* 2byte(le) to signed SHORT (Controlled sign extension) */ +NODISCARD SHORT B8toSHORTle_ptr(_In_reads_(2) const BYTE* v) noexcept; +/* 6byte(le) to ULONG64 (Safe for page-boundary) */ +NODISCARD ULONG64 B8toB64le(const BYTE(&v)[6]) noexcept; +/* 6byte(le) to DWORD (Safe for page-boundary) */ +NODISCARD DWORD B8toB32le(const BYTE(&v)[6]) noexcept; +/* 6byte(le) to INT (Controlled sign extension) */ +NODISCARD INT B8toINTle(const BYTE(&v)[6]) noexcept; +/* 6byte(le) to USHORT (Safe for page-boundary) */ +NODISCARD USHORT B8toB16le(const BYTE(&v)[6]) noexcept; + +// 20260123: Safe for unaligned/page-boundary <<< +// --------------------------------------------------------- +#endif + +////------------------------------------------------ +// .ini support function +////------------------------------------------------ + +DWORD GetPrivateProfileStringFx(LPCTSTR lpAppName, LPCTSTR lpKeyName, LPCTSTR lpDefault, LPTSTR lpReturnedString,DWORD nSize,LPCTSTR lpFileName); +UINT GetPrivateProfileIntFx(LPCTSTR lpAppName, LPCTSTR lpKeyName, INT nDefault, LPCTSTR lpFileName); +BOOL WritePrivateProfileStringFx(LPCTSTR lpAppName, LPCTSTR lpKeyName, LPCTSTR lpString, LPCTSTR lpFileName); + +////------------------------------------------------ +// Check CodeSign +////------------------------------------------------ + +#if _MSC_VER > 1310 +BOOL CheckCodeSign(LPCWSTR certName, LPCWSTR filePath); +#endif + +////------------------------------------------------ +// Play Sound +////------------------------------------------------ + +BOOL AlertSound(const CString& alertSoundPath, int volume); + +////------------------------------------------------ +// Hash +////------------------------------------------------ + +CStringA MD5(const CStringA& str); + +////------------------------------------------------ +// Character Converter +////------------------------------------------------ + +CStringW UTF8toUTF16(const CStringA& utf8str); +CStringA UTF16toUTF8(const CStringW& utf16str); +CStringA URLEncode(const CStringA& str); +CStringA UE(const CStringW& utf16str); +CStringA UE(const CStringA& ansiStr); + +////------------------------------------------------ +// Clipboard +////------------------------------------------------ + +void SetClipboardText(CString clip); + +////------------------------------------------------ +// SHLWAPI.DLL compatible functions +////------------------------------------------------ +#if _MSC_VER <= 1310 +#ifdef UNICODE +#define PathRemoveFileSpecFx PathRemoveFileSpecFxW +#define PathFindFileNameFx PathFindFileNameFxW +#else +#define PathRemoveFileSpecFx PathRemoveFileSpecFxA +#define PathFindFileNameFx PathFindFileNameFxA +#endif + +BOOL PathRemoveFileSpecFxA(char* path); +BOOL PathRemoveFileSpecFxW(WCHAR* path); +char* PathFindFileNameFxA(const char* path); +WCHAR* PathFindFileNameFxW(const WCHAR* path); +#endif diff --git a/CristalDiskMark/source/CrystalDiskMark/Priscilla/md5.cpp b/CristalDiskMark/source/CrystalDiskMark/Priscilla/md5.cpp new file mode 100644 index 0000000..645a075 --- /dev/null +++ b/CristalDiskMark/source/CrystalDiskMark/Priscilla/md5.cpp @@ -0,0 +1,226 @@ +/* + * Derived from the RSA Data Security, Inc. MD5 Message-Digest Algorithm + * and modified slightly to be functionally identical but condensed into control structures. + */ + +#include "stdafx.h" +#include "md5.h" + +/* + * Constants defined by the MD5 algorithm + */ +#define A 0x67452301 +#define B 0xefcdab89 +#define C 0x98badcfe +#define D 0x10325476 + +static uint32_t S[] = {7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, + 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, + 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, + 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21}; + +static uint32_t K[] = {0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, + 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, + 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, + 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, + 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, + 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8, + 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, + 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, + 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, + 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, + 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, + 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, + 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, + 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, + 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, + 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391}; + +/* + * Padding used to make the size (in bits) of the input congruent to 448 mod 512 + */ +static uint8_t PADDING[] = {0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + +/* + * Bit-manipulation functions defined by the MD5 algorithm + */ +#define F(X, Y, Z) ((X & Y) | (~X & Z)) +#define G(X, Y, Z) ((X & Z) | (Y & ~Z)) +#define H(X, Y, Z) (X ^ Y ^ Z) +#define I(X, Y, Z) (Y ^ (X | ~Z)) + +/* + * Rotates a 32-bit word left by n bits + */ +uint32_t rotateLeft(uint32_t x, uint32_t n){ + return (x << n) | (x >> (32 - n)); +} + + +/* + * Initialize a context + */ +void md5Init(MD5Context *ctx){ + ctx->size = (uint64_t)0; + + ctx->buffer[0] = (uint32_t)A; + ctx->buffer[1] = (uint32_t)B; + ctx->buffer[2] = (uint32_t)C; + ctx->buffer[3] = (uint32_t)D; +} + +/* + * Add some amount of input to the context + * + * If the input fills out a block of 512 bits, apply the algorithm (md5Step) + * and save the result in the buffer. Also updates the overall size. + */ +void md5Update(MD5Context *ctx, uint8_t *input_buffer, size_t input_len){ + uint32_t input[16]; + unsigned int offset = (unsigned int)(ctx->size % 64); + ctx->size += (uint64_t)input_len; + + // Copy each byte in input_buffer into the next space in our context input + for(unsigned int i = 0; i < input_len; ++i){ + ctx->input[offset++] = (uint8_t)*(input_buffer + i); + + // If we've filled our context input, copy it into our local array input + // then reset the offset to 0 and fill in a new buffer. + // Every time we fill out a chunk, we run it through the algorithm + // to enable some back and forth between cpu and i/o + if(offset % 64 == 0){ + for(unsigned int j = 0; j < 16; ++j){ + // Convert to little-endian + // The local variable `input` our 512-bit chunk separated into 32-bit words + // we can use in calculations + input[j] = (uint32_t)(ctx->input[(j * 4) + 3]) << 24 | + (uint32_t)(ctx->input[(j * 4) + 2]) << 16 | + (uint32_t)(ctx->input[(j * 4) + 1]) << 8 | + (uint32_t)(ctx->input[(j * 4)]); + } + md5Step(ctx->buffer, input); + offset = 0; + } + } +} + +/* + * Pad the current input to get to 448 bytes, append the size in bits to the very end, + * and save the result of the final iteration into digest. + */ +void md5Finalize(MD5Context *ctx){ + uint32_t input[16]; + unsigned int offset = (unsigned int)(ctx->size % 64); + unsigned int padding_length = offset < 56 ? 56 - offset : (56 + 64) - offset; + + // Fill in the padding and undo the changes to size that resulted from the update + md5Update(ctx, PADDING, padding_length); + ctx->size -= (uint64_t)padding_length; + + // Do a final update (internal to this function) + // Last two 32-bit words are the two halves of the size (converted from bytes to bits) + for(unsigned int j = 0; j < 14; ++j){ + input[j] = (uint32_t)(ctx->input[(j * 4) + 3]) << 24 | + (uint32_t)(ctx->input[(j * 4) + 2]) << 16 | + (uint32_t)(ctx->input[(j * 4) + 1]) << 8 | + (uint32_t)(ctx->input[(j * 4)]); + } + input[14] = (uint32_t)(ctx->size * 8); + input[15] = (uint32_t)((ctx->size * 8) >> 32); + + md5Step(ctx->buffer, input); + + // Move the result into digest (convert from little-endian) + for(unsigned int i = 0; i < 4; ++i){ + ctx->digest[(i * 4) + 0] = (uint8_t)((ctx->buffer[i] & 0x000000FF)); + ctx->digest[(i * 4) + 1] = (uint8_t)((ctx->buffer[i] & 0x0000FF00) >> 8); + ctx->digest[(i * 4) + 2] = (uint8_t)((ctx->buffer[i] & 0x00FF0000) >> 16); + ctx->digest[(i * 4) + 3] = (uint8_t)((ctx->buffer[i] & 0xFF000000) >> 24); + } +} + +/* + * Step on 512 bits of input with the main MD5 algorithm. + */ +void md5Step(uint32_t *buffer, uint32_t *input){ + uint32_t AA = buffer[0]; + uint32_t BB = buffer[1]; + uint32_t CC = buffer[2]; + uint32_t DD = buffer[3]; + + uint32_t E; + + unsigned int j; + + for(unsigned int i = 0; i < 64; ++i){ + switch(i / 16){ + case 0: + E = F(BB, CC, DD); + j = i; + break; + case 1: + E = G(BB, CC, DD); + j = ((i * 5) + 1) % 16; + break; + case 2: + E = H(BB, CC, DD); + j = ((i * 3) + 5) % 16; + break; + default: + E = I(BB, CC, DD); + j = (i * 7) % 16; + break; + } + + uint32_t temp = DD; + DD = CC; + CC = BB; + BB = BB + rotateLeft(AA + E + K[i] + input[j], S[i]); + AA = temp; + } + + buffer[0] += AA; + buffer[1] += BB; + buffer[2] += CC; + buffer[3] += DD; +} + +/* + * Functions that run the algorithm on the provided input and put the digest into result. + * result should be able to store 16 bytes. + */ +void md5String(char *input, uint8_t *result){ + MD5Context ctx = {0}; + md5Init(&ctx); + md5Update(&ctx, (uint8_t *)input, strlen(input)); + md5Finalize(&ctx); + + memcpy(result, ctx.digest, 16); +} + +/* +void md5File(FILE *file, uint8_t *result){ + char *input_buffer = malloc(1024); + size_t input_size = 0; + + MD5Context ctx; + md5Init(&ctx); + + while((input_size = fread(input_buffer, 1, 1024, file)) > 0){ + md5Update(&ctx, (uint8_t *)input_buffer, input_size); + } + + md5Finalize(&ctx); + + free(input_buffer); + + memcpy(result, ctx.digest, 16); +} +*/ diff --git a/CristalDiskMark/source/CrystalDiskMark/Priscilla/md5.h b/CristalDiskMark/source/CrystalDiskMark/Priscilla/md5.h new file mode 100644 index 0000000..73e3b55 --- /dev/null +++ b/CristalDiskMark/source/CrystalDiskMark/Priscilla/md5.h @@ -0,0 +1,29 @@ +#ifndef MD5_H +#define MD5_H + +typedef signed char int8_t; +typedef short int16_t; +typedef int int32_t; +typedef long long int64_t; + +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; +typedef unsigned long long uint64_t; + +typedef struct{ + uint64_t size; // Size of input in bytes + uint32_t buffer[4]; // Current accumulation of hash + uint8_t input[64]; // Input to be used in the next step + uint8_t digest[16]; // Result of algorithm +}MD5Context; + +void md5Init(MD5Context *ctx); +void md5Update(MD5Context *ctx, uint8_t *input, size_t input_len); +void md5Finalize(MD5Context *ctx); +void md5Step(uint32_t *buffer, uint32_t *input); + +void md5String(char *input, uint8_t *result); +// void md5File(FILE *file, uint8_t *result); + +#endif diff --git a/CristalDiskMark/source/CrystalDiskMark/Priscilla/stb_image.h b/CristalDiskMark/source/CrystalDiskMark/Priscilla/stb_image.h new file mode 100644 index 0000000..9eedabe --- /dev/null +++ b/CristalDiskMark/source/CrystalDiskMark/Priscilla/stb_image.h @@ -0,0 +1,7988 @@ +/* stb_image - v2.30 - public domain image loader - http://nothings.org/stb + no warranty implied; use at your own risk + + Do this: + #define STB_IMAGE_IMPLEMENTATION + before you include this file in *one* C or C++ file to create the implementation. + + // i.e. it should look like this: + #include ... + #include ... + #include ... + #define STB_IMAGE_IMPLEMENTATION + #include "stb_image.h" + + You can #define STBI_ASSERT(x) before the #include to avoid using assert.h. + And #define STBI_MALLOC, STBI_REALLOC, and STBI_FREE to avoid using malloc,realloc,free + + + QUICK NOTES: + Primarily of interest to game developers and other people who can + avoid problematic images and only need the trivial interface + + JPEG baseline & progressive (12 bpc/arithmetic not supported, same as stock IJG lib) + PNG 1/2/4/8/16-bit-per-channel + + TGA (not sure what subset, if a subset) + BMP non-1bpp, non-RLE + PSD (composited view only, no extra channels, 8/16 bit-per-channel) + + GIF (*comp always reports as 4-channel) + HDR (radiance rgbE format) + PIC (Softimage PIC) + PNM (PPM and PGM binary only) + + Animated GIF still needs a proper API, but here's one way to do it: + http://gist.github.com/urraka/685d9a6340b26b830d49 + + - decode from memory or through FILE (define STBI_NO_STDIO to remove code) + - decode from arbitrary I/O callbacks + - SIMD acceleration on x86/x64 (SSE2) and ARM (NEON) + + Full documentation under "DOCUMENTATION" below. + + +LICENSE + + See end of file for license information. + +RECENT REVISION HISTORY: + + 2.30 (2024-05-31) avoid erroneous gcc warning + 2.29 (2023-05-xx) optimizations + 2.28 (2023-01-29) many error fixes, security errors, just tons of stuff + 2.27 (2021-07-11) document stbi_info better, 16-bit PNM support, bug fixes + 2.26 (2020-07-13) many minor fixes + 2.25 (2020-02-02) fix warnings + 2.24 (2020-02-02) fix warnings; thread-local failure_reason and flip_vertically + 2.23 (2019-08-11) fix clang static analysis warning + 2.22 (2019-03-04) gif fixes, fix warnings + 2.21 (2019-02-25) fix typo in comment + 2.20 (2019-02-07) support utf8 filenames in Windows; fix warnings and platform ifdefs + 2.19 (2018-02-11) fix warning + 2.18 (2018-01-30) fix warnings + 2.17 (2018-01-29) bugfix, 1-bit BMP, 16-bitness query, fix warnings + 2.16 (2017-07-23) all functions have 16-bit variants; optimizations; bugfixes + 2.15 (2017-03-18) fix png-1,2,4; all Imagenet JPGs; no runtime SSE detection on GCC + 2.14 (2017-03-03) remove deprecated STBI_JPEG_OLD; fixes for Imagenet JPGs + 2.13 (2016-12-04) experimental 16-bit API, only for PNG so far; fixes + 2.12 (2016-04-02) fix typo in 2.11 PSD fix that caused crashes + 2.11 (2016-04-02) 16-bit PNGS; enable SSE2 in non-gcc x64 + RGB-format JPEG; remove white matting in PSD; + allocate large structures on the stack; + correct channel count for PNG & BMP + 2.10 (2016-01-22) avoid warning introduced in 2.09 + 2.09 (2016-01-16) 16-bit TGA; comments in PNM files; STBI_REALLOC_SIZED + + See end of file for full revision history. + + + ============================ Contributors ========================= + + Image formats Extensions, features + Sean Barrett (jpeg, png, bmp) Jetro Lauha (stbi_info) + Nicolas Schulz (hdr, psd) Martin "SpartanJ" Golini (stbi_info) + Jonathan Dummer (tga) James "moose2000" Brown (iPhone PNG) + Jean-Marc Lienher (gif) Ben "Disch" Wenger (io callbacks) + Tom Seddon (pic) Omar Cornut (1/2/4-bit PNG) + Thatcher Ulrich (psd) Nicolas Guillemot (vertical flip) + Ken Miller (pgm, ppm) Richard Mitton (16-bit PSD) + github:urraka (animated gif) Junggon Kim (PNM comments) + Christopher Forseth (animated gif) Daniel Gibson (16-bit TGA) + socks-the-fox (16-bit PNG) + Jeremy Sawicki (handle all ImageNet JPGs) + Optimizations & bugfixes Mikhail Morozov (1-bit BMP) + Fabian "ryg" Giesen Anael Seghezzi (is-16-bit query) + Arseny Kapoulkine Simon Breuss (16-bit PNM) + John-Mark Allen + Carmelo J Fdez-Aguera + + Bug & warning fixes + Marc LeBlanc David Woo Guillaume George Martins Mozeiko + Christpher Lloyd Jerry Jansson Joseph Thomson Blazej Dariusz Roszkowski + Phil Jordan Dave Moore Roy Eltham + Hayaki Saito Nathan Reed Won Chun + Luke Graham Johan Duparc Nick Verigakis the Horde3D community + Thomas Ruf Ronny Chevalier github:rlyeh + Janez Zemva John Bartholomew Michal Cichon github:romigrou + Jonathan Blow Ken Hamada Tero Hanninen github:svdijk + Eugene Golushkov Laurent Gomila Cort Stratton github:snagar + Aruelien Pocheville Sergio Gonzalez Thibault Reuille github:Zelex + Cass Everitt Ryamond Barbiero github:grim210 + Paul Du Bois Engin Manap Aldo Culquicondor github:sammyhw + Philipp Wiesemann Dale Weiler Oriol Ferrer Mesia github:phprus + Josh Tobin Neil Bickford Matthew Gregan github:poppolopoppo + Julian Raschke Gregory Mullen Christian Floisand github:darealshinji + Baldur Karlsson Kevin Schmidt JR Smith github:Michaelangel007 + Brad Weinberger Matvey Cherevko github:mosra + Luca Sas Alexander Veselov Zack Middleton [reserved] + Ryan C. Gordon [reserved] [reserved] + DO NOT ADD YOUR NAME HERE + + Jacko Dirks + + To add your name to the credits, pick a random blank space in the middle and fill it. + 80% of merge conflicts on stb PRs are due to people adding their name at the end + of the credits. +*/ + +#ifndef STBI_INCLUDE_STB_IMAGE_H +#define STBI_INCLUDE_STB_IMAGE_H + +// DOCUMENTATION +// +// Limitations: +// - no 12-bit-per-channel JPEG +// - no JPEGs with arithmetic coding +// - GIF always returns *comp=4 +// +// Basic usage (see HDR discussion below for HDR usage): +// int x,y,n; +// unsigned char *data = stbi_load(filename, &x, &y, &n, 0); +// // ... process data if not NULL ... +// // ... x = width, y = height, n = # 8-bit components per pixel ... +// // ... replace '0' with '1'..'4' to force that many components per pixel +// // ... but 'n' will always be the number that it would have been if you said 0 +// stbi_image_free(data); +// +// Standard parameters: +// int *x -- outputs image width in pixels +// int *y -- outputs image height in pixels +// int *channels_in_file -- outputs # of image components in image file +// int desired_channels -- if non-zero, # of image components requested in result +// +// The return value from an image loader is an 'unsigned char *' which points +// to the pixel data, or NULL on an allocation failure or if the image is +// corrupt or invalid. The pixel data consists of *y scanlines of *x pixels, +// with each pixel consisting of N interleaved 8-bit components; the first +// pixel pointed to is top-left-most in the image. There is no padding between +// image scanlines or between pixels, regardless of format. The number of +// components N is 'desired_channels' if desired_channels is non-zero, or +// *channels_in_file otherwise. If desired_channels is non-zero, +// *channels_in_file has the number of components that _would_ have been +// output otherwise. E.g. if you set desired_channels to 4, you will always +// get RGBA output, but you can check *channels_in_file to see if it's trivially +// opaque because e.g. there were only 3 channels in the source image. +// +// An output image with N components has the following components interleaved +// in this order in each pixel: +// +// N=#comp components +// 1 grey +// 2 grey, alpha +// 3 red, green, blue +// 4 red, green, blue, alpha +// +// If image loading fails for any reason, the return value will be NULL, +// and *x, *y, *channels_in_file will be unchanged. The function +// stbi_failure_reason() can be queried for an extremely brief, end-user +// unfriendly explanation of why the load failed. Define STBI_NO_FAILURE_STRINGS +// to avoid compiling these strings at all, and STBI_FAILURE_USERMSG to get slightly +// more user-friendly ones. +// +// Paletted PNG, BMP, GIF, and PIC images are automatically depalettized. +// +// To query the width, height and component count of an image without having to +// decode the full file, you can use the stbi_info family of functions: +// +// int x,y,n,ok; +// ok = stbi_info(filename, &x, &y, &n); +// // returns ok=1 and sets x, y, n if image is a supported format, +// // 0 otherwise. +// +// Note that stb_image pervasively uses ints in its public API for sizes, +// including sizes of memory buffers. This is now part of the API and thus +// hard to change without causing breakage. As a result, the various image +// loaders all have certain limits on image size; these differ somewhat +// by format but generally boil down to either just under 2GB or just under +// 1GB. When the decoded image would be larger than this, stb_image decoding +// will fail. +// +// Additionally, stb_image will reject image files that have any of their +// dimensions set to a larger value than the configurable STBI_MAX_DIMENSIONS, +// which defaults to 2**24 = 16777216 pixels. Due to the above memory limit, +// the only way to have an image with such dimensions load correctly +// is for it to have a rather extreme aspect ratio. Either way, the +// assumption here is that such larger images are likely to be malformed +// or malicious. If you do need to load an image with individual dimensions +// larger than that, and it still fits in the overall size limit, you can +// #define STBI_MAX_DIMENSIONS on your own to be something larger. +// +// =========================================================================== +// +// UNICODE: +// +// If compiling for Windows and you wish to use Unicode filenames, compile +// with +// #define STBI_WINDOWS_UTF8 +// and pass utf8-encoded filenames. Call stbi_convert_wchar_to_utf8 to convert +// Windows wchar_t filenames to utf8. +// +// =========================================================================== +// +// Philosophy +// +// stb libraries are designed with the following priorities: +// +// 1. easy to use +// 2. easy to maintain +// 3. good performance +// +// Sometimes I let "good performance" creep up in priority over "easy to maintain", +// and for best performance I may provide less-easy-to-use APIs that give higher +// performance, in addition to the easy-to-use ones. Nevertheless, it's important +// to keep in mind that from the standpoint of you, a client of this library, +// all you care about is #1 and #3, and stb libraries DO NOT emphasize #3 above all. +// +// Some secondary priorities arise directly from the first two, some of which +// provide more explicit reasons why performance can't be emphasized. +// +// - Portable ("ease of use") +// - Small source code footprint ("easy to maintain") +// - No dependencies ("ease of use") +// +// =========================================================================== +// +// I/O callbacks +// +// I/O callbacks allow you to read from arbitrary sources, like packaged +// files or some other source. Data read from callbacks are processed +// through a small internal buffer (currently 128 bytes) to try to reduce +// overhead. +// +// The three functions you must define are "read" (reads some bytes of data), +// "skip" (skips some bytes of data), "eof" (reports if the stream is at the end). +// +// =========================================================================== +// +// SIMD support +// +// The JPEG decoder will try to automatically use SIMD kernels on x86 when +// supported by the compiler. For ARM Neon support, you must explicitly +// request it. +// +// (The old do-it-yourself SIMD API is no longer supported in the current +// code.) +// +// On x86, SSE2 will automatically be used when available based on a run-time +// test; if not, the generic C versions are used as a fall-back. On ARM targets, +// the typical path is to have separate builds for NEON and non-NEON devices +// (at least this is true for iOS and Android). Therefore, the NEON support is +// toggled by a build flag: define STBI_NEON to get NEON loops. +// +// If for some reason you do not want to use any of SIMD code, or if +// you have issues compiling it, you can disable it entirely by +// defining STBI_NO_SIMD. +// +// =========================================================================== +// +// HDR image support (disable by defining STBI_NO_HDR) +// +// stb_image supports loading HDR images in general, and currently the Radiance +// .HDR file format specifically. You can still load any file through the existing +// interface; if you attempt to load an HDR file, it will be automatically remapped +// to LDR, assuming gamma 2.2 and an arbitrary scale factor defaulting to 1; +// both of these constants can be reconfigured through this interface: +// +// stbi_hdr_to_ldr_gamma(2.2f); +// stbi_hdr_to_ldr_scale(1.0f); +// +// (note, do not use _inverse_ constants; stbi_image will invert them +// appropriately). +// +// Additionally, there is a new, parallel interface for loading files as +// (linear) floats to preserve the full dynamic range: +// +// float *data = stbi_loadf(filename, &x, &y, &n, 0); +// +// If you load LDR images through this interface, those images will +// be promoted to floating point values, run through the inverse of +// constants corresponding to the above: +// +// stbi_ldr_to_hdr_scale(1.0f); +// stbi_ldr_to_hdr_gamma(2.2f); +// +// Finally, given a filename (or an open file or memory block--see header +// file for details) containing image data, you can query for the "most +// appropriate" interface to use (that is, whether the image is HDR or +// not), using: +// +// stbi_is_hdr(char *filename); +// +// =========================================================================== +// +// iPhone PNG support: +// +// We optionally support converting iPhone-formatted PNGs (which store +// premultiplied BGRA) back to RGB, even though they're internally encoded +// differently. To enable this conversion, call +// stbi_convert_iphone_png_to_rgb(1). +// +// Call stbi_set_unpremultiply_on_load(1) as well to force a divide per +// pixel to remove any premultiplied alpha *only* if the image file explicitly +// says there's premultiplied data (currently only happens in iPhone images, +// and only if iPhone convert-to-rgb processing is on). +// +// =========================================================================== +// +// ADDITIONAL CONFIGURATION +// +// - You can suppress implementation of any of the decoders to reduce +// your code footprint by #defining one or more of the following +// symbols before creating the implementation. +// +// STBI_NO_JPEG +// STBI_NO_PNG +// STBI_NO_BMP +// STBI_NO_PSD +// STBI_NO_TGA +// STBI_NO_GIF +// STBI_NO_HDR +// STBI_NO_PIC +// STBI_NO_PNM (.ppm and .pgm) +// +// - You can request *only* certain decoders and suppress all other ones +// (this will be more forward-compatible, as addition of new decoders +// doesn't require you to disable them explicitly): +// +// STBI_ONLY_JPEG +// STBI_ONLY_PNG +// STBI_ONLY_BMP +// STBI_ONLY_PSD +// STBI_ONLY_TGA +// STBI_ONLY_GIF +// STBI_ONLY_HDR +// STBI_ONLY_PIC +// STBI_ONLY_PNM (.ppm and .pgm) +// +// - If you use STBI_NO_PNG (or _ONLY_ without PNG), and you still +// want the zlib decoder to be available, #define STBI_SUPPORT_ZLIB +// +// - If you define STBI_MAX_DIMENSIONS, stb_image will reject images greater +// than that size (in either width or height) without further processing. +// This is to let programs in the wild set an upper bound to prevent +// denial-of-service attacks on untrusted data, as one could generate a +// valid image of gigantic dimensions and force stb_image to allocate a +// huge block of memory and spend disproportionate time decoding it. By +// default this is set to (1 << 24), which is 16777216, but that's still +// very big. + +#ifndef STBI_NO_STDIO +#include +#endif // STBI_NO_STDIO + +#define STBI_VERSION 1 + +enum +{ + STBI_default = 0, // only used for desired_channels + + STBI_grey = 1, + STBI_grey_alpha = 2, + STBI_rgb = 3, + STBI_rgb_alpha = 4 +}; + +#include +typedef unsigned char stbi_uc; +typedef unsigned short stbi_us; + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef STBIDEF +#ifdef STB_IMAGE_STATIC +#define STBIDEF static +#else +#define STBIDEF extern +#endif +#endif + +////////////////////////////////////////////////////////////////////////////// +// +// PRIMARY API - works on images of any type +// + +// +// load image by filename, open file, or memory buffer +// + +typedef struct +{ + int (*read) (void *user,char *data,int size); // fill 'data' with 'size' bytes. return number of bytes actually read + void (*skip) (void *user,int n); // skip the next 'n' bytes, or 'unget' the last -n bytes if negative + int (*eof) (void *user); // returns nonzero if we are at end of file/data +} stbi_io_callbacks; + +//////////////////////////////////// +// +// 8-bits-per-channel interface +// + +STBIDEF stbi_uc *stbi_load_from_memory (stbi_uc const *buffer, int len , int *x, int *y, int *channels_in_file, int desired_channels); +STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk , void *user, int *x, int *y, int *channels_in_file, int desired_channels); + +#ifndef STBI_NO_STDIO +STBIDEF stbi_uc *stbi_load (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels); +STBIDEF stbi_uc *stbi_load_from_file (FILE *f, int *x, int *y, int *channels_in_file, int desired_channels); +// for stbi_load_from_file, file pointer is left pointing immediately after image +#endif + +#ifndef STBI_NO_GIF +STBIDEF stbi_uc *stbi_load_gif_from_memory(stbi_uc const *buffer, int len, int **delays, int *x, int *y, int *z, int *comp, int req_comp); +#endif + +#ifdef STBI_WINDOWS_UTF8 +STBIDEF int stbi_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input); +#endif + +//////////////////////////////////// +// +// 16-bits-per-channel interface +// + +STBIDEF stbi_us *stbi_load_16_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels); +STBIDEF stbi_us *stbi_load_16_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels); + +#ifndef STBI_NO_STDIO +STBIDEF stbi_us *stbi_load_16 (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels); +STBIDEF stbi_us *stbi_load_from_file_16(FILE *f, int *x, int *y, int *channels_in_file, int desired_channels); +#endif + +//////////////////////////////////// +// +// float-per-channel interface +// +#ifndef STBI_NO_LINEAR + STBIDEF float *stbi_loadf_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels); + STBIDEF float *stbi_loadf_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels); + + #ifndef STBI_NO_STDIO + STBIDEF float *stbi_loadf (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels); + STBIDEF float *stbi_loadf_from_file (FILE *f, int *x, int *y, int *channels_in_file, int desired_channels); + #endif +#endif + +#ifndef STBI_NO_HDR + STBIDEF void stbi_hdr_to_ldr_gamma(float gamma); + STBIDEF void stbi_hdr_to_ldr_scale(float scale); +#endif // STBI_NO_HDR + +#ifndef STBI_NO_LINEAR + STBIDEF void stbi_ldr_to_hdr_gamma(float gamma); + STBIDEF void stbi_ldr_to_hdr_scale(float scale); +#endif // STBI_NO_LINEAR + +// stbi_is_hdr is always defined, but always returns false if STBI_NO_HDR +STBIDEF int stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user); +STBIDEF int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len); +#ifndef STBI_NO_STDIO +STBIDEF int stbi_is_hdr (char const *filename); +STBIDEF int stbi_is_hdr_from_file(FILE *f); +#endif // STBI_NO_STDIO + + +// get a VERY brief reason for failure +// on most compilers (and ALL modern mainstream compilers) this is threadsafe +STBIDEF const char *stbi_failure_reason (void); + +// free the loaded image -- this is just free() +STBIDEF void stbi_image_free (void *retval_from_stbi_load); + +// get image dimensions & components without fully decoding +STBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp); +STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp); +STBIDEF int stbi_is_16_bit_from_memory(stbi_uc const *buffer, int len); +STBIDEF int stbi_is_16_bit_from_callbacks(stbi_io_callbacks const *clbk, void *user); + +#ifndef STBI_NO_STDIO +STBIDEF int stbi_info (char const *filename, int *x, int *y, int *comp); +STBIDEF int stbi_info_from_file (FILE *f, int *x, int *y, int *comp); +STBIDEF int stbi_is_16_bit (char const *filename); +STBIDEF int stbi_is_16_bit_from_file(FILE *f); +#endif + + + +// for image formats that explicitly notate that they have premultiplied alpha, +// we just return the colors as stored in the file. set this flag to force +// unpremultiplication. results are undefined if the unpremultiply overflow. +STBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply); + +// indicate whether we should process iphone images back to canonical format, +// or just pass them through "as-is" +STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert); + +// flip the image vertically, so the first pixel in the output array is the bottom left +STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip); + +// as above, but only applies to images loaded on the thread that calls the function +// this function is only available if your compiler supports thread-local variables; +// calling it will fail to link if your compiler doesn't +STBIDEF void stbi_set_unpremultiply_on_load_thread(int flag_true_if_should_unpremultiply); +STBIDEF void stbi_convert_iphone_png_to_rgb_thread(int flag_true_if_should_convert); +STBIDEF void stbi_set_flip_vertically_on_load_thread(int flag_true_if_should_flip); + +// ZLIB client - used by PNG, available for other purposes + +STBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen); +STBIDEF char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header); +STBIDEF char *stbi_zlib_decode_malloc(const char *buffer, int len, int *outlen); +STBIDEF int stbi_zlib_decode_buffer(char *obuffer, int olen, const char *ibuffer, int ilen); + +STBIDEF char *stbi_zlib_decode_noheader_malloc(const char *buffer, int len, int *outlen); +STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen); + + +#ifdef __cplusplus +} +#endif + +// +// +//// end header file ///////////////////////////////////////////////////// +#endif // STBI_INCLUDE_STB_IMAGE_H + +#ifdef STB_IMAGE_IMPLEMENTATION + +#if defined(STBI_ONLY_JPEG) || defined(STBI_ONLY_PNG) || defined(STBI_ONLY_BMP) \ + || defined(STBI_ONLY_TGA) || defined(STBI_ONLY_GIF) || defined(STBI_ONLY_PSD) \ + || defined(STBI_ONLY_HDR) || defined(STBI_ONLY_PIC) || defined(STBI_ONLY_PNM) \ + || defined(STBI_ONLY_ZLIB) + #ifndef STBI_ONLY_JPEG + #define STBI_NO_JPEG + #endif + #ifndef STBI_ONLY_PNG + #define STBI_NO_PNG + #endif + #ifndef STBI_ONLY_BMP + #define STBI_NO_BMP + #endif + #ifndef STBI_ONLY_PSD + #define STBI_NO_PSD + #endif + #ifndef STBI_ONLY_TGA + #define STBI_NO_TGA + #endif + #ifndef STBI_ONLY_GIF + #define STBI_NO_GIF + #endif + #ifndef STBI_ONLY_HDR + #define STBI_NO_HDR + #endif + #ifndef STBI_ONLY_PIC + #define STBI_NO_PIC + #endif + #ifndef STBI_ONLY_PNM + #define STBI_NO_PNM + #endif +#endif + +#if defined(STBI_NO_PNG) && !defined(STBI_SUPPORT_ZLIB) && !defined(STBI_NO_ZLIB) +#define STBI_NO_ZLIB +#endif + + +#include +#include // ptrdiff_t on osx +#include +#include +#include + +#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) +#include // ldexp, pow +#endif + +#ifndef STBI_NO_STDIO +#include +#endif + +#ifndef STBI_ASSERT +#include +#define STBI_ASSERT(x) assert(x) +#endif + +#ifdef __cplusplus +#define STBI_EXTERN extern "C" +#else +#define STBI_EXTERN extern +#endif + + +#ifndef _MSC_VER + #ifdef __cplusplus + #define stbi_inline inline + #else + #define stbi_inline + #endif +#else + #define stbi_inline __forceinline +#endif + +#ifndef STBI_NO_THREAD_LOCALS + #if defined(__cplusplus) && __cplusplus >= 201103L + #define STBI_THREAD_LOCAL thread_local + #elif defined(__GNUC__) && __GNUC__ < 5 + #define STBI_THREAD_LOCAL __thread + #elif defined(_MSC_VER) + #define STBI_THREAD_LOCAL __declspec(thread) + #elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 201112L && !defined(__STDC_NO_THREADS__) + #define STBI_THREAD_LOCAL _Thread_local + #endif + + #ifndef STBI_THREAD_LOCAL + #if defined(__GNUC__) + #define STBI_THREAD_LOCAL __thread + #endif + #endif +#endif + +#if defined(_MSC_VER) || defined(__SYMBIAN32__) +typedef unsigned short stbi__uint16; +typedef signed short stbi__int16; +typedef unsigned int stbi__uint32; +typedef signed int stbi__int32; +#else +#include +typedef uint16_t stbi__uint16; +typedef int16_t stbi__int16; +typedef uint32_t stbi__uint32; +typedef int32_t stbi__int32; +#endif + +// should produce compiler error if size is wrong +typedef unsigned char validate_uint32[sizeof(stbi__uint32)==4 ? 1 : -1]; + +#ifdef _MSC_VER +#define STBI_NOTUSED(v) (void)(v) +#else +#define STBI_NOTUSED(v) (void)sizeof(v) +#endif + +#ifdef _MSC_VER +#define STBI_HAS_LROTL +#endif + +#ifdef STBI_HAS_LROTL + #define stbi_lrot(x,y) _lrotl(x,y) +#else + #define stbi_lrot(x,y) (((x) << (y)) | ((x) >> (-(y) & 31))) +#endif + +#if defined(STBI_MALLOC) && defined(STBI_FREE) && (defined(STBI_REALLOC) || defined(STBI_REALLOC_SIZED)) +// ok +#elif !defined(STBI_MALLOC) && !defined(STBI_FREE) && !defined(STBI_REALLOC) && !defined(STBI_REALLOC_SIZED) +// ok +#else +#error "Must define all or none of STBI_MALLOC, STBI_FREE, and STBI_REALLOC (or STBI_REALLOC_SIZED)." +#endif + +#ifndef STBI_MALLOC +#define STBI_MALLOC(sz) malloc(sz) +#define STBI_REALLOC(p,newsz) realloc(p,newsz) +#define STBI_FREE(p) free(p) +#endif + +#ifndef STBI_REALLOC_SIZED +#define STBI_REALLOC_SIZED(p,oldsz,newsz) STBI_REALLOC(p,newsz) +#endif + +// x86/x64 detection +#if defined(__x86_64__) || defined(_M_X64) +#define STBI__X64_TARGET +#elif defined(__i386) || defined(_M_IX86) +#define STBI__X86_TARGET +#endif + +#if defined(__GNUC__) && defined(STBI__X86_TARGET) && !defined(__SSE2__) && !defined(STBI_NO_SIMD) +// gcc doesn't support sse2 intrinsics unless you compile with -msse2, +// which in turn means it gets to use SSE2 everywhere. This is unfortunate, +// but previous attempts to provide the SSE2 functions with runtime +// detection caused numerous issues. The way architecture extensions are +// exposed in GCC/Clang is, sadly, not really suited for one-file libs. +// New behavior: if compiled with -msse2, we use SSE2 without any +// detection; if not, we don't use it at all. +#define STBI_NO_SIMD +#endif + +#if defined(__MINGW32__) && defined(STBI__X86_TARGET) && !defined(STBI_MINGW_ENABLE_SSE2) && !defined(STBI_NO_SIMD) +// Note that __MINGW32__ doesn't actually mean 32-bit, so we have to avoid STBI__X64_TARGET +// +// 32-bit MinGW wants ESP to be 16-byte aligned, but this is not in the +// Windows ABI and VC++ as well as Windows DLLs don't maintain that invariant. +// As a result, enabling SSE2 on 32-bit MinGW is dangerous when not +// simultaneously enabling "-mstackrealign". +// +// See https://github.com/nothings/stb/issues/81 for more information. +// +// So default to no SSE2 on 32-bit MinGW. If you've read this far and added +// -mstackrealign to your build settings, feel free to #define STBI_MINGW_ENABLE_SSE2. +#define STBI_NO_SIMD +#endif + +#if !defined(STBI_NO_SIMD) && (defined(STBI__X86_TARGET) || defined(STBI__X64_TARGET)) +#define STBI_SSE2 +#include + +#ifdef _MSC_VER + +#if _MSC_VER >= 1400 // not VC6 +#include // __cpuid +static int stbi__cpuid3(void) +{ + int info[4]; + __cpuid(info,1); + return info[3]; +} +#else +static int stbi__cpuid3(void) +{ + int res; + __asm { + mov eax,1 + cpuid + mov res,edx + } + return res; +} +#endif + +#define STBI_SIMD_ALIGN(type, name) __declspec(align(16)) type name + +#if !defined(STBI_NO_JPEG) && defined(STBI_SSE2) +static int stbi__sse2_available(void) +{ + int info3 = stbi__cpuid3(); + return ((info3 >> 26) & 1) != 0; +} +#endif + +#else // assume GCC-style if not VC++ +#define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16))) + +#if !defined(STBI_NO_JPEG) && defined(STBI_SSE2) +static int stbi__sse2_available(void) +{ + // If we're even attempting to compile this on GCC/Clang, that means + // -msse2 is on, which means the compiler is allowed to use SSE2 + // instructions at will, and so are we. + return 1; +} +#endif + +#endif +#endif + +// ARM NEON +#if defined(STBI_NO_SIMD) && defined(STBI_NEON) +#undef STBI_NEON +#endif + +#ifdef STBI_NEON +#include +#ifdef _MSC_VER +#define STBI_SIMD_ALIGN(type, name) __declspec(align(16)) type name +#else +#define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16))) +#endif +#endif + +#ifndef STBI_SIMD_ALIGN +#define STBI_SIMD_ALIGN(type, name) type name +#endif + +#ifndef STBI_MAX_DIMENSIONS +#define STBI_MAX_DIMENSIONS (1 << 24) +#endif + +/////////////////////////////////////////////// +// +// stbi__context struct and start_xxx functions + +// stbi__context structure is our basic context used by all images, so it +// contains all the IO context, plus some basic image information +typedef struct +{ + stbi__uint32 img_x, img_y; + int img_n, img_out_n; + + stbi_io_callbacks io; + void *io_user_data; + + int read_from_callbacks; + int buflen; + stbi_uc buffer_start[128]; + int callback_already_read; + + stbi_uc *img_buffer, *img_buffer_end; + stbi_uc *img_buffer_original, *img_buffer_original_end; +} stbi__context; + + +static void stbi__refill_buffer(stbi__context *s); + +// initialize a memory-decode context +static void stbi__start_mem(stbi__context *s, stbi_uc const *buffer, int len) +{ + s->io.read = NULL; + s->read_from_callbacks = 0; + s->callback_already_read = 0; + s->img_buffer = s->img_buffer_original = (stbi_uc *) buffer; + s->img_buffer_end = s->img_buffer_original_end = (stbi_uc *) buffer+len; +} + +// initialize a callback-based context +static void stbi__start_callbacks(stbi__context *s, stbi_io_callbacks *c, void *user) +{ + s->io = *c; + s->io_user_data = user; + s->buflen = sizeof(s->buffer_start); + s->read_from_callbacks = 1; + s->callback_already_read = 0; + s->img_buffer = s->img_buffer_original = s->buffer_start; + stbi__refill_buffer(s); + s->img_buffer_original_end = s->img_buffer_end; +} + +#ifndef STBI_NO_STDIO + +static int stbi__stdio_read(void *user, char *data, int size) +{ + return (int) fread(data,1,size,(FILE*) user); +} + +static void stbi__stdio_skip(void *user, int n) +{ + int ch; + fseek((FILE*) user, n, SEEK_CUR); + ch = fgetc((FILE*) user); /* have to read a byte to reset feof()'s flag */ + if (ch != EOF) { + ungetc(ch, (FILE *) user); /* push byte back onto stream if valid. */ + } +} + +static int stbi__stdio_eof(void *user) +{ + return feof((FILE*) user) || ferror((FILE *) user); +} + +static stbi_io_callbacks stbi__stdio_callbacks = +{ + stbi__stdio_read, + stbi__stdio_skip, + stbi__stdio_eof, +}; + +static void stbi__start_file(stbi__context *s, FILE *f) +{ + stbi__start_callbacks(s, &stbi__stdio_callbacks, (void *) f); +} + +//static void stop_file(stbi__context *s) { } + +#endif // !STBI_NO_STDIO + +static void stbi__rewind(stbi__context *s) +{ + // conceptually rewind SHOULD rewind to the beginning of the stream, + // but we just rewind to the beginning of the initial buffer, because + // we only use it after doing 'test', which only ever looks at at most 92 bytes + s->img_buffer = s->img_buffer_original; + s->img_buffer_end = s->img_buffer_original_end; +} + +enum +{ + STBI_ORDER_RGB, + STBI_ORDER_BGR +}; + +typedef struct +{ + int bits_per_channel; + int num_channels; + int channel_order; +} stbi__result_info; + +#ifndef STBI_NO_JPEG +static int stbi__jpeg_test(stbi__context *s); +static void *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_PNG +static int stbi__png_test(stbi__context *s); +static void *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__png_info(stbi__context *s, int *x, int *y, int *comp); +static int stbi__png_is16(stbi__context *s); +#endif + +#ifndef STBI_NO_BMP +static int stbi__bmp_test(stbi__context *s); +static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_TGA +static int stbi__tga_test(stbi__context *s); +static void *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_PSD +static int stbi__psd_test(stbi__context *s); +static void *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc); +static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp); +static int stbi__psd_is16(stbi__context *s); +#endif + +#ifndef STBI_NO_HDR +static int stbi__hdr_test(stbi__context *s); +static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_PIC +static int stbi__pic_test(stbi__context *s); +static void *stbi__pic_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_GIF +static int stbi__gif_test(stbi__context *s); +static void *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, int *z, int *comp, int req_comp); +static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_PNM +static int stbi__pnm_test(stbi__context *s); +static void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp); +static int stbi__pnm_is16(stbi__context *s); +#endif + +static +#ifdef STBI_THREAD_LOCAL +STBI_THREAD_LOCAL +#endif +const char *stbi__g_failure_reason; + +STBIDEF const char *stbi_failure_reason(void) +{ + return stbi__g_failure_reason; +} + +#ifndef STBI_NO_FAILURE_STRINGS +static int stbi__err(const char *str) +{ + stbi__g_failure_reason = str; + return 0; +} +#endif + +static void *stbi__malloc(size_t size) +{ + return STBI_MALLOC(size); +} + +// stb_image uses ints pervasively, including for offset calculations. +// therefore the largest decoded image size we can support with the +// current code, even on 64-bit targets, is INT_MAX. this is not a +// significant limitation for the intended use case. +// +// we do, however, need to make sure our size calculations don't +// overflow. hence a few helper functions for size calculations that +// multiply integers together, making sure that they're non-negative +// and no overflow occurs. + +// return 1 if the sum is valid, 0 on overflow. +// negative terms are considered invalid. +static int stbi__addsizes_valid(int a, int b) +{ + if (b < 0) return 0; + // now 0 <= b <= INT_MAX, hence also + // 0 <= INT_MAX - b <= INTMAX. + // And "a + b <= INT_MAX" (which might overflow) is the + // same as a <= INT_MAX - b (no overflow) + return a <= INT_MAX - b; +} + +// returns 1 if the product is valid, 0 on overflow. +// negative factors are considered invalid. +static int stbi__mul2sizes_valid(int a, int b) +{ + if (a < 0 || b < 0) return 0; + if (b == 0) return 1; // mul-by-0 is always safe + // portable way to check for no overflows in a*b + return a <= INT_MAX/b; +} + +#if !defined(STBI_NO_JPEG) || !defined(STBI_NO_PNG) || !defined(STBI_NO_TGA) || !defined(STBI_NO_HDR) +// returns 1 if "a*b + add" has no negative terms/factors and doesn't overflow +static int stbi__mad2sizes_valid(int a, int b, int add) +{ + return stbi__mul2sizes_valid(a, b) && stbi__addsizes_valid(a*b, add); +} +#endif + +// returns 1 if "a*b*c + add" has no negative terms/factors and doesn't overflow +static int stbi__mad3sizes_valid(int a, int b, int c, int add) +{ + return stbi__mul2sizes_valid(a, b) && stbi__mul2sizes_valid(a*b, c) && + stbi__addsizes_valid(a*b*c, add); +} + +// returns 1 if "a*b*c*d + add" has no negative terms/factors and doesn't overflow +#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) || !defined(STBI_NO_PNM) +static int stbi__mad4sizes_valid(int a, int b, int c, int d, int add) +{ + return stbi__mul2sizes_valid(a, b) && stbi__mul2sizes_valid(a*b, c) && + stbi__mul2sizes_valid(a*b*c, d) && stbi__addsizes_valid(a*b*c*d, add); +} +#endif + +#if !defined(STBI_NO_JPEG) || !defined(STBI_NO_PNG) || !defined(STBI_NO_TGA) || !defined(STBI_NO_HDR) +// mallocs with size overflow checking +static void *stbi__malloc_mad2(int a, int b, int add) +{ + if (!stbi__mad2sizes_valid(a, b, add)) return NULL; + return stbi__malloc(a*b + add); +} +#endif + +static void *stbi__malloc_mad3(int a, int b, int c, int add) +{ + if (!stbi__mad3sizes_valid(a, b, c, add)) return NULL; + return stbi__malloc(a*b*c + add); +} + +#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) || !defined(STBI_NO_PNM) +static void *stbi__malloc_mad4(int a, int b, int c, int d, int add) +{ + if (!stbi__mad4sizes_valid(a, b, c, d, add)) return NULL; + return stbi__malloc(a*b*c*d + add); +} +#endif + +// returns 1 if the sum of two signed ints is valid (between -2^31 and 2^31-1 inclusive), 0 on overflow. +static int stbi__addints_valid(int a, int b) +{ + if ((a >= 0) != (b >= 0)) return 1; // a and b have different signs, so no overflow + if (a < 0 && b < 0) return a >= INT_MIN - b; // same as a + b >= INT_MIN; INT_MIN - b cannot overflow since b < 0. + return a <= INT_MAX - b; +} + +// returns 1 if the product of two ints fits in a signed short, 0 on overflow. +static int stbi__mul2shorts_valid(int a, int b) +{ + if (b == 0 || b == -1) return 1; // multiplication by 0 is always 0; check for -1 so SHRT_MIN/b doesn't overflow + if ((a >= 0) == (b >= 0)) return a <= SHRT_MAX/b; // product is positive, so similar to mul2sizes_valid + if (b < 0) return a <= SHRT_MIN / b; // same as a * b >= SHRT_MIN + return a >= SHRT_MIN / b; +} + +// stbi__err - error +// stbi__errpf - error returning pointer to float +// stbi__errpuc - error returning pointer to unsigned char + +#ifdef STBI_NO_FAILURE_STRINGS + #define stbi__err(x,y) 0 +#elif defined(STBI_FAILURE_USERMSG) + #define stbi__err(x,y) stbi__err(y) +#else + #define stbi__err(x,y) stbi__err(x) +#endif + +#define stbi__errpf(x,y) ((float *)(size_t) (stbi__err(x,y)?NULL:NULL)) +#define stbi__errpuc(x,y) ((unsigned char *)(size_t) (stbi__err(x,y)?NULL:NULL)) + +STBIDEF void stbi_image_free(void *retval_from_stbi_load) +{ + STBI_FREE(retval_from_stbi_load); +} + +#ifndef STBI_NO_LINEAR +static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp); +#endif + +#ifndef STBI_NO_HDR +static stbi_uc *stbi__hdr_to_ldr(float *data, int x, int y, int comp); +#endif + +static int stbi__vertically_flip_on_load_global = 0; + +STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip) +{ + stbi__vertically_flip_on_load_global = flag_true_if_should_flip; +} + +#ifndef STBI_THREAD_LOCAL +#define stbi__vertically_flip_on_load stbi__vertically_flip_on_load_global +#else +static STBI_THREAD_LOCAL int stbi__vertically_flip_on_load_local, stbi__vertically_flip_on_load_set; + +STBIDEF void stbi_set_flip_vertically_on_load_thread(int flag_true_if_should_flip) +{ + stbi__vertically_flip_on_load_local = flag_true_if_should_flip; + stbi__vertically_flip_on_load_set = 1; +} + +#define stbi__vertically_flip_on_load (stbi__vertically_flip_on_load_set \ + ? stbi__vertically_flip_on_load_local \ + : stbi__vertically_flip_on_load_global) +#endif // STBI_THREAD_LOCAL + +static void *stbi__load_main(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc) +{ + memset(ri, 0, sizeof(*ri)); // make sure it's initialized if we add new fields + ri->bits_per_channel = 8; // default is 8 so most paths don't have to be changed + ri->channel_order = STBI_ORDER_RGB; // all current input & output are this, but this is here so we can add BGR order + ri->num_channels = 0; + + // test the formats with a very explicit header first (at least a FOURCC + // or distinctive magic number first) + #ifndef STBI_NO_PNG + if (stbi__png_test(s)) return stbi__png_load(s,x,y,comp,req_comp, ri); + #endif + #ifndef STBI_NO_BMP + if (stbi__bmp_test(s)) return stbi__bmp_load(s,x,y,comp,req_comp, ri); + #endif + #ifndef STBI_NO_GIF + if (stbi__gif_test(s)) return stbi__gif_load(s,x,y,comp,req_comp, ri); + #endif + #ifndef STBI_NO_PSD + if (stbi__psd_test(s)) return stbi__psd_load(s,x,y,comp,req_comp, ri, bpc); + #else + STBI_NOTUSED(bpc); + #endif + #ifndef STBI_NO_PIC + if (stbi__pic_test(s)) return stbi__pic_load(s,x,y,comp,req_comp, ri); + #endif + + // then the formats that can end up attempting to load with just 1 or 2 + // bytes matching expectations; these are prone to false positives, so + // try them later + #ifndef STBI_NO_JPEG + if (stbi__jpeg_test(s)) return stbi__jpeg_load(s,x,y,comp,req_comp, ri); + #endif + #ifndef STBI_NO_PNM + if (stbi__pnm_test(s)) return stbi__pnm_load(s,x,y,comp,req_comp, ri); + #endif + + #ifndef STBI_NO_HDR + if (stbi__hdr_test(s)) { + float *hdr = stbi__hdr_load(s, x,y,comp,req_comp, ri); + return stbi__hdr_to_ldr(hdr, *x, *y, req_comp ? req_comp : *comp); + } + #endif + + #ifndef STBI_NO_TGA + // test tga last because it's a crappy test! + if (stbi__tga_test(s)) + return stbi__tga_load(s,x,y,comp,req_comp, ri); + #endif + + return stbi__errpuc("unknown image type", "Image not of any known type, or corrupt"); +} + +static stbi_uc *stbi__convert_16_to_8(stbi__uint16 *orig, int w, int h, int channels) +{ + int i; + int img_len = w * h * channels; + stbi_uc *reduced; + + reduced = (stbi_uc *) stbi__malloc(img_len); + if (reduced == NULL) return stbi__errpuc("outofmem", "Out of memory"); + + for (i = 0; i < img_len; ++i) + reduced[i] = (stbi_uc)((orig[i] >> 8) & 0xFF); // top half of each byte is sufficient approx of 16->8 bit scaling + + STBI_FREE(orig); + return reduced; +} + +static stbi__uint16 *stbi__convert_8_to_16(stbi_uc *orig, int w, int h, int channels) +{ + int i; + int img_len = w * h * channels; + stbi__uint16 *enlarged; + + enlarged = (stbi__uint16 *) stbi__malloc(img_len*2); + if (enlarged == NULL) return (stbi__uint16 *) stbi__errpuc("outofmem", "Out of memory"); + + for (i = 0; i < img_len; ++i) + enlarged[i] = (stbi__uint16)((orig[i] << 8) + orig[i]); // replicate to high and low byte, maps 0->0, 255->0xffff + + STBI_FREE(orig); + return enlarged; +} + +static void stbi__vertical_flip(void *image, int w, int h, int bytes_per_pixel) +{ + int row; + size_t bytes_per_row = (size_t)w * bytes_per_pixel; + stbi_uc temp[2048]; + stbi_uc *bytes = (stbi_uc *)image; + + for (row = 0; row < (h>>1); row++) { + stbi_uc *row0 = bytes + row*bytes_per_row; + stbi_uc *row1 = bytes + (h - row - 1)*bytes_per_row; + // swap row0 with row1 + size_t bytes_left = bytes_per_row; + while (bytes_left) { + size_t bytes_copy = (bytes_left < sizeof(temp)) ? bytes_left : sizeof(temp); + memcpy(temp, row0, bytes_copy); + memcpy(row0, row1, bytes_copy); + memcpy(row1, temp, bytes_copy); + row0 += bytes_copy; + row1 += bytes_copy; + bytes_left -= bytes_copy; + } + } +} + +#ifndef STBI_NO_GIF +static void stbi__vertical_flip_slices(void *image, int w, int h, int z, int bytes_per_pixel) +{ + int slice; + int slice_size = w * h * bytes_per_pixel; + + stbi_uc *bytes = (stbi_uc *)image; + for (slice = 0; slice < z; ++slice) { + stbi__vertical_flip(bytes, w, h, bytes_per_pixel); + bytes += slice_size; + } +} +#endif + +static unsigned char *stbi__load_and_postprocess_8bit(stbi__context *s, int *x, int *y, int *comp, int req_comp) +{ + stbi__result_info ri; + void *result = stbi__load_main(s, x, y, comp, req_comp, &ri, 8); + + if (result == NULL) + return NULL; + + // it is the responsibility of the loaders to make sure we get either 8 or 16 bit. + STBI_ASSERT(ri.bits_per_channel == 8 || ri.bits_per_channel == 16); + + if (ri.bits_per_channel != 8) { + result = stbi__convert_16_to_8((stbi__uint16 *) result, *x, *y, req_comp == 0 ? *comp : req_comp); + ri.bits_per_channel = 8; + } + + // @TODO: move stbi__convert_format to here + + if (stbi__vertically_flip_on_load) { + int channels = req_comp ? req_comp : *comp; + stbi__vertical_flip(result, *x, *y, channels * sizeof(stbi_uc)); + } + + return (unsigned char *) result; +} + +static stbi__uint16 *stbi__load_and_postprocess_16bit(stbi__context *s, int *x, int *y, int *comp, int req_comp) +{ + stbi__result_info ri; + void *result = stbi__load_main(s, x, y, comp, req_comp, &ri, 16); + + if (result == NULL) + return NULL; + + // it is the responsibility of the loaders to make sure we get either 8 or 16 bit. + STBI_ASSERT(ri.bits_per_channel == 8 || ri.bits_per_channel == 16); + + if (ri.bits_per_channel != 16) { + result = stbi__convert_8_to_16((stbi_uc *) result, *x, *y, req_comp == 0 ? *comp : req_comp); + ri.bits_per_channel = 16; + } + + // @TODO: move stbi__convert_format16 to here + // @TODO: special case RGB-to-Y (and RGBA-to-YA) for 8-bit-to-16-bit case to keep more precision + + if (stbi__vertically_flip_on_load) { + int channels = req_comp ? req_comp : *comp; + stbi__vertical_flip(result, *x, *y, channels * sizeof(stbi__uint16)); + } + + return (stbi__uint16 *) result; +} + +#if !defined(STBI_NO_HDR) && !defined(STBI_NO_LINEAR) +static void stbi__float_postprocess(float *result, int *x, int *y, int *comp, int req_comp) +{ + if (stbi__vertically_flip_on_load && result != NULL) { + int channels = req_comp ? req_comp : *comp; + stbi__vertical_flip(result, *x, *y, channels * sizeof(float)); + } +} +#endif + +#ifndef STBI_NO_STDIO + +#if defined(_WIN32) && defined(STBI_WINDOWS_UTF8) +STBI_EXTERN __declspec(dllimport) int __stdcall MultiByteToWideChar(unsigned int cp, unsigned long flags, const char *str, int cbmb, wchar_t *widestr, int cchwide); +STBI_EXTERN __declspec(dllimport) int __stdcall WideCharToMultiByte(unsigned int cp, unsigned long flags, const wchar_t *widestr, int cchwide, char *str, int cbmb, const char *defchar, int *used_default); +#endif + +#if defined(_WIN32) && defined(STBI_WINDOWS_UTF8) +STBIDEF int stbi_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input) +{ + return WideCharToMultiByte(65001 /* UTF8 */, 0, input, -1, buffer, (int) bufferlen, NULL, NULL); +} +#endif + +static FILE *stbi__fopen(char const *filename, char const *mode) +{ + FILE *f; +#if defined(_WIN32) && defined(STBI_WINDOWS_UTF8) + wchar_t wMode[64]; + wchar_t wFilename[1024]; + if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, filename, -1, wFilename, sizeof(wFilename)/sizeof(*wFilename))) + return 0; + + if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, mode, -1, wMode, sizeof(wMode)/sizeof(*wMode))) + return 0; + +#if defined(_MSC_VER) && _MSC_VER >= 1400 + if (0 != _wfopen_s(&f, wFilename, wMode)) + f = 0; +#else + f = _wfopen(wFilename, wMode); +#endif + +#elif defined(_MSC_VER) && _MSC_VER >= 1400 + if (0 != fopen_s(&f, filename, mode)) + f=0; +#else + f = fopen(filename, mode); +#endif + return f; +} + + +STBIDEF stbi_uc *stbi_load(char const *filename, int *x, int *y, int *comp, int req_comp) +{ + FILE *f = stbi__fopen(filename, "rb"); + unsigned char *result; + if (!f) return stbi__errpuc("can't fopen", "Unable to open file"); + result = stbi_load_from_file(f,x,y,comp,req_comp); + fclose(f); + return result; +} + +STBIDEF stbi_uc *stbi_load_from_file(FILE *f, int *x, int *y, int *comp, int req_comp) +{ + unsigned char *result; + stbi__context s; + stbi__start_file(&s,f); + result = stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp); + if (result) { + // need to 'unget' all the characters in the IO buffer + fseek(f, - (int) (s.img_buffer_end - s.img_buffer), SEEK_CUR); + } + return result; +} + +STBIDEF stbi__uint16 *stbi_load_from_file_16(FILE *f, int *x, int *y, int *comp, int req_comp) +{ + stbi__uint16 *result; + stbi__context s; + stbi__start_file(&s,f); + result = stbi__load_and_postprocess_16bit(&s,x,y,comp,req_comp); + if (result) { + // need to 'unget' all the characters in the IO buffer + fseek(f, - (int) (s.img_buffer_end - s.img_buffer), SEEK_CUR); + } + return result; +} + +STBIDEF stbi_us *stbi_load_16(char const *filename, int *x, int *y, int *comp, int req_comp) +{ + FILE *f = stbi__fopen(filename, "rb"); + stbi__uint16 *result; + if (!f) return (stbi_us *) stbi__errpuc("can't fopen", "Unable to open file"); + result = stbi_load_from_file_16(f,x,y,comp,req_comp); + fclose(f); + return result; +} + + +#endif //!STBI_NO_STDIO + +STBIDEF stbi_us *stbi_load_16_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels) +{ + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__load_and_postprocess_16bit(&s,x,y,channels_in_file,desired_channels); +} + +STBIDEF stbi_us *stbi_load_16_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *)clbk, user); + return stbi__load_and_postprocess_16bit(&s,x,y,channels_in_file,desired_channels); +} + +STBIDEF stbi_uc *stbi_load_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp); +} + +STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); + return stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp); +} + +#ifndef STBI_NO_GIF +STBIDEF stbi_uc *stbi_load_gif_from_memory(stbi_uc const *buffer, int len, int **delays, int *x, int *y, int *z, int *comp, int req_comp) +{ + unsigned char *result; + stbi__context s; + stbi__start_mem(&s,buffer,len); + + result = (unsigned char*) stbi__load_gif_main(&s, delays, x, y, z, comp, req_comp); + if (stbi__vertically_flip_on_load) { + stbi__vertical_flip_slices( result, *x, *y, *z, *comp ); + } + + return result; +} +#endif + +#ifndef STBI_NO_LINEAR +static float *stbi__loadf_main(stbi__context *s, int *x, int *y, int *comp, int req_comp) +{ + unsigned char *data; + #ifndef STBI_NO_HDR + if (stbi__hdr_test(s)) { + stbi__result_info ri; + float *hdr_data = stbi__hdr_load(s,x,y,comp,req_comp, &ri); + if (hdr_data) + stbi__float_postprocess(hdr_data,x,y,comp,req_comp); + return hdr_data; + } + #endif + data = stbi__load_and_postprocess_8bit(s, x, y, comp, req_comp); + if (data) + return stbi__ldr_to_hdr(data, *x, *y, req_comp ? req_comp : *comp); + return stbi__errpf("unknown image type", "Image not of any known type, or corrupt"); +} + +STBIDEF float *stbi_loadf_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__loadf_main(&s,x,y,comp,req_comp); +} + +STBIDEF float *stbi_loadf_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); + return stbi__loadf_main(&s,x,y,comp,req_comp); +} + +#ifndef STBI_NO_STDIO +STBIDEF float *stbi_loadf(char const *filename, int *x, int *y, int *comp, int req_comp) +{ + float *result; + FILE *f = stbi__fopen(filename, "rb"); + if (!f) return stbi__errpf("can't fopen", "Unable to open file"); + result = stbi_loadf_from_file(f,x,y,comp,req_comp); + fclose(f); + return result; +} + +STBIDEF float *stbi_loadf_from_file(FILE *f, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_file(&s,f); + return stbi__loadf_main(&s,x,y,comp,req_comp); +} +#endif // !STBI_NO_STDIO + +#endif // !STBI_NO_LINEAR + +// these is-hdr-or-not is defined independent of whether STBI_NO_LINEAR is +// defined, for API simplicity; if STBI_NO_LINEAR is defined, it always +// reports false! + +STBIDEF int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len) +{ + #ifndef STBI_NO_HDR + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__hdr_test(&s); + #else + STBI_NOTUSED(buffer); + STBI_NOTUSED(len); + return 0; + #endif +} + +#ifndef STBI_NO_STDIO +STBIDEF int stbi_is_hdr (char const *filename) +{ + FILE *f = stbi__fopen(filename, "rb"); + int result=0; + if (f) { + result = stbi_is_hdr_from_file(f); + fclose(f); + } + return result; +} + +STBIDEF int stbi_is_hdr_from_file(FILE *f) +{ + #ifndef STBI_NO_HDR + long pos = ftell(f); + int res; + stbi__context s; + stbi__start_file(&s,f); + res = stbi__hdr_test(&s); + fseek(f, pos, SEEK_SET); + return res; + #else + STBI_NOTUSED(f); + return 0; + #endif +} +#endif // !STBI_NO_STDIO + +STBIDEF int stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user) +{ + #ifndef STBI_NO_HDR + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); + return stbi__hdr_test(&s); + #else + STBI_NOTUSED(clbk); + STBI_NOTUSED(user); + return 0; + #endif +} + +#ifndef STBI_NO_LINEAR +static float stbi__l2h_gamma=2.2f, stbi__l2h_scale=1.0f; + +STBIDEF void stbi_ldr_to_hdr_gamma(float gamma) { stbi__l2h_gamma = gamma; } +STBIDEF void stbi_ldr_to_hdr_scale(float scale) { stbi__l2h_scale = scale; } +#endif + +static float stbi__h2l_gamma_i=1.0f/2.2f, stbi__h2l_scale_i=1.0f; + +STBIDEF void stbi_hdr_to_ldr_gamma(float gamma) { stbi__h2l_gamma_i = 1/gamma; } +STBIDEF void stbi_hdr_to_ldr_scale(float scale) { stbi__h2l_scale_i = 1/scale; } + + +////////////////////////////////////////////////////////////////////////////// +// +// Common code used by all image loaders +// + +enum +{ + STBI__SCAN_load=0, + STBI__SCAN_type, + STBI__SCAN_header +}; + +static void stbi__refill_buffer(stbi__context *s) +{ + int n = (s->io.read)(s->io_user_data,(char*)s->buffer_start,s->buflen); + s->callback_already_read += (int) (s->img_buffer - s->img_buffer_original); + if (n == 0) { + // at end of file, treat same as if from memory, but need to handle case + // where s->img_buffer isn't pointing to safe memory, e.g. 0-byte file + s->read_from_callbacks = 0; + s->img_buffer = s->buffer_start; + s->img_buffer_end = s->buffer_start+1; + *s->img_buffer = 0; + } else { + s->img_buffer = s->buffer_start; + s->img_buffer_end = s->buffer_start + n; + } +} + +stbi_inline static stbi_uc stbi__get8(stbi__context *s) +{ + if (s->img_buffer < s->img_buffer_end) + return *s->img_buffer++; + if (s->read_from_callbacks) { + stbi__refill_buffer(s); + return *s->img_buffer++; + } + return 0; +} + +#if defined(STBI_NO_JPEG) && defined(STBI_NO_HDR) && defined(STBI_NO_PIC) && defined(STBI_NO_PNM) +// nothing +#else +stbi_inline static int stbi__at_eof(stbi__context *s) +{ + if (s->io.read) { + if (!(s->io.eof)(s->io_user_data)) return 0; + // if feof() is true, check if buffer = end + // special case: we've only got the special 0 character at the end + if (s->read_from_callbacks == 0) return 1; + } + + return s->img_buffer >= s->img_buffer_end; +} +#endif + +#if defined(STBI_NO_JPEG) && defined(STBI_NO_PNG) && defined(STBI_NO_BMP) && defined(STBI_NO_PSD) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) && defined(STBI_NO_PIC) +// nothing +#else +static void stbi__skip(stbi__context *s, int n) +{ + if (n == 0) return; // already there! + if (n < 0) { + s->img_buffer = s->img_buffer_end; + return; + } + if (s->io.read) { + int blen = (int) (s->img_buffer_end - s->img_buffer); + if (blen < n) { + s->img_buffer = s->img_buffer_end; + (s->io.skip)(s->io_user_data, n - blen); + return; + } + } + s->img_buffer += n; +} +#endif + +#if defined(STBI_NO_PNG) && defined(STBI_NO_TGA) && defined(STBI_NO_HDR) && defined(STBI_NO_PNM) +// nothing +#else +static int stbi__getn(stbi__context *s, stbi_uc *buffer, int n) +{ + if (s->io.read) { + int blen = (int) (s->img_buffer_end - s->img_buffer); + if (blen < n) { + int res, count; + + memcpy(buffer, s->img_buffer, blen); + + count = (s->io.read)(s->io_user_data, (char*) buffer + blen, n - blen); + res = (count == (n-blen)); + s->img_buffer = s->img_buffer_end; + return res; + } + } + + if (s->img_buffer+n <= s->img_buffer_end) { + memcpy(buffer, s->img_buffer, n); + s->img_buffer += n; + return 1; + } else + return 0; +} +#endif + +#if defined(STBI_NO_JPEG) && defined(STBI_NO_PNG) && defined(STBI_NO_PSD) && defined(STBI_NO_PIC) +// nothing +#else +static int stbi__get16be(stbi__context *s) +{ + int z = stbi__get8(s); + return (z << 8) + stbi__get8(s); +} +#endif + +#if defined(STBI_NO_PNG) && defined(STBI_NO_PSD) && defined(STBI_NO_PIC) +// nothing +#else +static stbi__uint32 stbi__get32be(stbi__context *s) +{ + stbi__uint32 z = stbi__get16be(s); + return (z << 16) + stbi__get16be(s); +} +#endif + +#if defined(STBI_NO_BMP) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) +// nothing +#else +static int stbi__get16le(stbi__context *s) +{ + int z = stbi__get8(s); + return z + (stbi__get8(s) << 8); +} +#endif + +#ifndef STBI_NO_BMP +static stbi__uint32 stbi__get32le(stbi__context *s) +{ + stbi__uint32 z = stbi__get16le(s); + z += (stbi__uint32)stbi__get16le(s) << 16; + return z; +} +#endif + +#define STBI__BYTECAST(x) ((stbi_uc) ((x) & 255)) // truncate int to byte without warnings + +#if defined(STBI_NO_JPEG) && defined(STBI_NO_PNG) && defined(STBI_NO_BMP) && defined(STBI_NO_PSD) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) && defined(STBI_NO_PIC) && defined(STBI_NO_PNM) +// nothing +#else +////////////////////////////////////////////////////////////////////////////// +// +// generic converter from built-in img_n to req_comp +// individual types do this automatically as much as possible (e.g. jpeg +// does all cases internally since it needs to colorspace convert anyway, +// and it never has alpha, so very few cases ). png can automatically +// interleave an alpha=255 channel, but falls back to this for other cases +// +// assume data buffer is malloced, so malloc a new one and free that one +// only failure mode is malloc failing + +static stbi_uc stbi__compute_y(int r, int g, int b) +{ + return (stbi_uc) (((r*77) + (g*150) + (29*b)) >> 8); +} +#endif + +#if defined(STBI_NO_PNG) && defined(STBI_NO_BMP) && defined(STBI_NO_PSD) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) && defined(STBI_NO_PIC) && defined(STBI_NO_PNM) +// nothing +#else +static unsigned char *stbi__convert_format(unsigned char *data, int img_n, int req_comp, unsigned int x, unsigned int y) +{ + int i,j; + unsigned char *good; + + if (req_comp == img_n) return data; + STBI_ASSERT(req_comp >= 1 && req_comp <= 4); + + good = (unsigned char *) stbi__malloc_mad3(req_comp, x, y, 0); + if (good == NULL) { + STBI_FREE(data); + return stbi__errpuc("outofmem", "Out of memory"); + } + + for (j=0; j < (int) y; ++j) { + unsigned char *src = data + j * x * img_n ; + unsigned char *dest = good + j * x * req_comp; + + #define STBI__COMBO(a,b) ((a)*8+(b)) + #define STBI__CASE(a,b) case STBI__COMBO(a,b): for(i=x-1; i >= 0; --i, src += a, dest += b) + // convert source image with img_n components to one with req_comp components; + // avoid switch per pixel, so use switch per scanline and massive macros + switch (STBI__COMBO(img_n, req_comp)) { + STBI__CASE(1,2) { dest[0]=src[0]; dest[1]=255; } break; + STBI__CASE(1,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; + STBI__CASE(1,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=255; } break; + STBI__CASE(2,1) { dest[0]=src[0]; } break; + STBI__CASE(2,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; + STBI__CASE(2,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=src[1]; } break; + STBI__CASE(3,4) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2];dest[3]=255; } break; + STBI__CASE(3,1) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); } break; + STBI__CASE(3,2) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); dest[1] = 255; } break; + STBI__CASE(4,1) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); } break; + STBI__CASE(4,2) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); dest[1] = src[3]; } break; + STBI__CASE(4,3) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2]; } break; + default: STBI_ASSERT(0); STBI_FREE(data); STBI_FREE(good); return stbi__errpuc("unsupported", "Unsupported format conversion"); + } + #undef STBI__CASE + } + + STBI_FREE(data); + return good; +} +#endif + +#if defined(STBI_NO_PNG) && defined(STBI_NO_PSD) +// nothing +#else +static stbi__uint16 stbi__compute_y_16(int r, int g, int b) +{ + return (stbi__uint16) (((r*77) + (g*150) + (29*b)) >> 8); +} +#endif + +#if defined(STBI_NO_PNG) && defined(STBI_NO_PSD) +// nothing +#else +static stbi__uint16 *stbi__convert_format16(stbi__uint16 *data, int img_n, int req_comp, unsigned int x, unsigned int y) +{ + int i,j; + stbi__uint16 *good; + + if (req_comp == img_n) return data; + STBI_ASSERT(req_comp >= 1 && req_comp <= 4); + + good = (stbi__uint16 *) stbi__malloc(req_comp * x * y * 2); + if (good == NULL) { + STBI_FREE(data); + return (stbi__uint16 *) stbi__errpuc("outofmem", "Out of memory"); + } + + for (j=0; j < (int) y; ++j) { + stbi__uint16 *src = data + j * x * img_n ; + stbi__uint16 *dest = good + j * x * req_comp; + + #define STBI__COMBO(a,b) ((a)*8+(b)) + #define STBI__CASE(a,b) case STBI__COMBO(a,b): for(i=x-1; i >= 0; --i, src += a, dest += b) + // convert source image with img_n components to one with req_comp components; + // avoid switch per pixel, so use switch per scanline and massive macros + switch (STBI__COMBO(img_n, req_comp)) { + STBI__CASE(1,2) { dest[0]=src[0]; dest[1]=0xffff; } break; + STBI__CASE(1,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; + STBI__CASE(1,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=0xffff; } break; + STBI__CASE(2,1) { dest[0]=src[0]; } break; + STBI__CASE(2,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; + STBI__CASE(2,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=src[1]; } break; + STBI__CASE(3,4) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2];dest[3]=0xffff; } break; + STBI__CASE(3,1) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); } break; + STBI__CASE(3,2) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); dest[1] = 0xffff; } break; + STBI__CASE(4,1) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); } break; + STBI__CASE(4,2) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); dest[1] = src[3]; } break; + STBI__CASE(4,3) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2]; } break; + default: STBI_ASSERT(0); STBI_FREE(data); STBI_FREE(good); return (stbi__uint16*) stbi__errpuc("unsupported", "Unsupported format conversion"); + } + #undef STBI__CASE + } + + STBI_FREE(data); + return good; +} +#endif + +#ifndef STBI_NO_LINEAR +static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp) +{ + int i,k,n; + float *output; + if (!data) return NULL; + output = (float *) stbi__malloc_mad4(x, y, comp, sizeof(float), 0); + if (output == NULL) { STBI_FREE(data); return stbi__errpf("outofmem", "Out of memory"); } + // compute number of non-alpha components + if (comp & 1) n = comp; else n = comp-1; + for (i=0; i < x*y; ++i) { + for (k=0; k < n; ++k) { + output[i*comp + k] = (float) (pow(data[i*comp+k]/255.0f, stbi__l2h_gamma) * stbi__l2h_scale); + } + } + if (n < comp) { + for (i=0; i < x*y; ++i) { + output[i*comp + n] = data[i*comp + n]/255.0f; + } + } + STBI_FREE(data); + return output; +} +#endif + +#ifndef STBI_NO_HDR +#define stbi__float2int(x) ((int) (x)) +static stbi_uc *stbi__hdr_to_ldr(float *data, int x, int y, int comp) +{ + int i,k,n; + stbi_uc *output; + if (!data) return NULL; + output = (stbi_uc *) stbi__malloc_mad3(x, y, comp, 0); + if (output == NULL) { STBI_FREE(data); return stbi__errpuc("outofmem", "Out of memory"); } + // compute number of non-alpha components + if (comp & 1) n = comp; else n = comp-1; + for (i=0; i < x*y; ++i) { + for (k=0; k < n; ++k) { + float z = (float) pow(data[i*comp+k]*stbi__h2l_scale_i, stbi__h2l_gamma_i) * 255 + 0.5f; + if (z < 0) z = 0; + if (z > 255) z = 255; + output[i*comp + k] = (stbi_uc) stbi__float2int(z); + } + if (k < comp) { + float z = data[i*comp+k] * 255 + 0.5f; + if (z < 0) z = 0; + if (z > 255) z = 255; + output[i*comp + k] = (stbi_uc) stbi__float2int(z); + } + } + STBI_FREE(data); + return output; +} +#endif + +////////////////////////////////////////////////////////////////////////////// +// +// "baseline" JPEG/JFIF decoder +// +// simple implementation +// - doesn't support delayed output of y-dimension +// - simple interface (only one output format: 8-bit interleaved RGB) +// - doesn't try to recover corrupt jpegs +// - doesn't allow partial loading, loading multiple at once +// - still fast on x86 (copying globals into locals doesn't help x86) +// - allocates lots of intermediate memory (full size of all components) +// - non-interleaved case requires this anyway +// - allows good upsampling (see next) +// high-quality +// - upsampled channels are bilinearly interpolated, even across blocks +// - quality integer IDCT derived from IJG's 'slow' +// performance +// - fast huffman; reasonable integer IDCT +// - some SIMD kernels for common paths on targets with SSE2/NEON +// - uses a lot of intermediate memory, could cache poorly + +#ifndef STBI_NO_JPEG + +// huffman decoding acceleration +#define FAST_BITS 9 // larger handles more cases; smaller stomps less cache + +typedef struct +{ + stbi_uc fast[1 << FAST_BITS]; + // weirdly, repacking this into AoS is a 10% speed loss, instead of a win + stbi__uint16 code[256]; + stbi_uc values[256]; + stbi_uc size[257]; + unsigned int maxcode[18]; + int delta[17]; // old 'firstsymbol' - old 'firstcode' +} stbi__huffman; + +typedef struct +{ + stbi__context *s; + stbi__huffman huff_dc[4]; + stbi__huffman huff_ac[4]; + stbi__uint16 dequant[4][64]; + stbi__int16 fast_ac[4][1 << FAST_BITS]; + +// sizes for components, interleaved MCUs + int img_h_max, img_v_max; + int img_mcu_x, img_mcu_y; + int img_mcu_w, img_mcu_h; + +// definition of jpeg image component + struct + { + int id; + int h,v; + int tq; + int hd,ha; + int dc_pred; + + int x,y,w2,h2; + stbi_uc *data; + void *raw_data, *raw_coeff; + stbi_uc *linebuf; + short *coeff; // progressive only + int coeff_w, coeff_h; // number of 8x8 coefficient blocks + } img_comp[4]; + + stbi__uint32 code_buffer; // jpeg entropy-coded buffer + int code_bits; // number of valid bits + unsigned char marker; // marker seen while filling entropy buffer + int nomore; // flag if we saw a marker so must stop + + int progressive; + int spec_start; + int spec_end; + int succ_high; + int succ_low; + int eob_run; + int jfif; + int app14_color_transform; // Adobe APP14 tag + int rgb; + + int scan_n, order[4]; + int restart_interval, todo; + +// kernels + void (*idct_block_kernel)(stbi_uc *out, int out_stride, short data[64]); + void (*YCbCr_to_RGB_kernel)(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step); + stbi_uc *(*resample_row_hv_2_kernel)(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs); +} stbi__jpeg; + +static int stbi__build_huffman(stbi__huffman *h, int *count) +{ + int i,j,k=0; + unsigned int code; + // build size list for each symbol (from JPEG spec) + for (i=0; i < 16; ++i) { + for (j=0; j < count[i]; ++j) { + h->size[k++] = (stbi_uc) (i+1); + if(k >= 257) return stbi__err("bad size list","Corrupt JPEG"); + } + } + h->size[k] = 0; + + // compute actual symbols (from jpeg spec) + code = 0; + k = 0; + for(j=1; j <= 16; ++j) { + // compute delta to add to code to compute symbol id + h->delta[j] = k - code; + if (h->size[k] == j) { + while (h->size[k] == j) + h->code[k++] = (stbi__uint16) (code++); + if (code-1 >= (1u << j)) return stbi__err("bad code lengths","Corrupt JPEG"); + } + // compute largest code + 1 for this size, preshifted as needed later + h->maxcode[j] = code << (16-j); + code <<= 1; + } + h->maxcode[j] = 0xffffffff; + + // build non-spec acceleration table; 255 is flag for not-accelerated + memset(h->fast, 255, 1 << FAST_BITS); + for (i=0; i < k; ++i) { + int s = h->size[i]; + if (s <= FAST_BITS) { + int c = h->code[i] << (FAST_BITS-s); + int m = 1 << (FAST_BITS-s); + for (j=0; j < m; ++j) { + h->fast[c+j] = (stbi_uc) i; + } + } + } + return 1; +} + +// build a table that decodes both magnitude and value of small ACs in +// one go. +static void stbi__build_fast_ac(stbi__int16 *fast_ac, stbi__huffman *h) +{ + int i; + for (i=0; i < (1 << FAST_BITS); ++i) { + stbi_uc fast = h->fast[i]; + fast_ac[i] = 0; + if (fast < 255) { + int rs = h->values[fast]; + int run = (rs >> 4) & 15; + int magbits = rs & 15; + int len = h->size[fast]; + + if (magbits && len + magbits <= FAST_BITS) { + // magnitude code followed by receive_extend code + int k = ((i << len) & ((1 << FAST_BITS) - 1)) >> (FAST_BITS - magbits); + int m = 1 << (magbits - 1); + if (k < m) k += (~0U << magbits) + 1; + // if the result is small enough, we can fit it in fast_ac table + if (k >= -128 && k <= 127) + fast_ac[i] = (stbi__int16) ((k * 256) + (run * 16) + (len + magbits)); + } + } + } +} + +static void stbi__grow_buffer_unsafe(stbi__jpeg *j) +{ + do { + unsigned int b = j->nomore ? 0 : stbi__get8(j->s); + if (b == 0xff) { + int c = stbi__get8(j->s); + while (c == 0xff) c = stbi__get8(j->s); // consume fill bytes + if (c != 0) { + j->marker = (unsigned char) c; + j->nomore = 1; + return; + } + } + j->code_buffer |= b << (24 - j->code_bits); + j->code_bits += 8; + } while (j->code_bits <= 24); +} + +// (1 << n) - 1 +static const stbi__uint32 stbi__bmask[17]={0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535}; + +// decode a jpeg huffman value from the bitstream +stbi_inline static int stbi__jpeg_huff_decode(stbi__jpeg *j, stbi__huffman *h) +{ + unsigned int temp; + int c,k; + + if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + + // look at the top FAST_BITS and determine what symbol ID it is, + // if the code is <= FAST_BITS + c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1); + k = h->fast[c]; + if (k < 255) { + int s = h->size[k]; + if (s > j->code_bits) + return -1; + j->code_buffer <<= s; + j->code_bits -= s; + return h->values[k]; + } + + // naive test is to shift the code_buffer down so k bits are + // valid, then test against maxcode. To speed this up, we've + // preshifted maxcode left so that it has (16-k) 0s at the + // end; in other words, regardless of the number of bits, it + // wants to be compared against something shifted to have 16; + // that way we don't need to shift inside the loop. + temp = j->code_buffer >> 16; + for (k=FAST_BITS+1 ; ; ++k) + if (temp < h->maxcode[k]) + break; + if (k == 17) { + // error! code not found + j->code_bits -= 16; + return -1; + } + + if (k > j->code_bits) + return -1; + + // convert the huffman code to the symbol id + c = ((j->code_buffer >> (32 - k)) & stbi__bmask[k]) + h->delta[k]; + if(c < 0 || c >= 256) // symbol id out of bounds! + return -1; + STBI_ASSERT((((j->code_buffer) >> (32 - h->size[c])) & stbi__bmask[h->size[c]]) == h->code[c]); + + // convert the id to a symbol + j->code_bits -= k; + j->code_buffer <<= k; + return h->values[c]; +} + +// bias[n] = (-1<code_bits < n) stbi__grow_buffer_unsafe(j); + if (j->code_bits < n) return 0; // ran out of bits from stream, return 0s intead of continuing + + sgn = j->code_buffer >> 31; // sign bit always in MSB; 0 if MSB clear (positive), 1 if MSB set (negative) + k = stbi_lrot(j->code_buffer, n); + j->code_buffer = k & ~stbi__bmask[n]; + k &= stbi__bmask[n]; + j->code_bits -= n; + return k + (stbi__jbias[n] & (sgn - 1)); +} + +// get some unsigned bits +stbi_inline static int stbi__jpeg_get_bits(stbi__jpeg *j, int n) +{ + unsigned int k; + if (j->code_bits < n) stbi__grow_buffer_unsafe(j); + if (j->code_bits < n) return 0; // ran out of bits from stream, return 0s intead of continuing + k = stbi_lrot(j->code_buffer, n); + j->code_buffer = k & ~stbi__bmask[n]; + k &= stbi__bmask[n]; + j->code_bits -= n; + return k; +} + +stbi_inline static int stbi__jpeg_get_bit(stbi__jpeg *j) +{ + unsigned int k; + if (j->code_bits < 1) stbi__grow_buffer_unsafe(j); + if (j->code_bits < 1) return 0; // ran out of bits from stream, return 0s intead of continuing + k = j->code_buffer; + j->code_buffer <<= 1; + --j->code_bits; + return k & 0x80000000; +} + +// given a value that's at position X in the zigzag stream, +// where does it appear in the 8x8 matrix coded as row-major? +static const stbi_uc stbi__jpeg_dezigzag[64+15] = +{ + 0, 1, 8, 16, 9, 2, 3, 10, + 17, 24, 32, 25, 18, 11, 4, 5, + 12, 19, 26, 33, 40, 48, 41, 34, + 27, 20, 13, 6, 7, 14, 21, 28, + 35, 42, 49, 56, 57, 50, 43, 36, + 29, 22, 15, 23, 30, 37, 44, 51, + 58, 59, 52, 45, 38, 31, 39, 46, + 53, 60, 61, 54, 47, 55, 62, 63, + // let corrupt input sample past end + 63, 63, 63, 63, 63, 63, 63, 63, + 63, 63, 63, 63, 63, 63, 63 +}; + +// decode one 64-entry block-- +static int stbi__jpeg_decode_block(stbi__jpeg *j, short data[64], stbi__huffman *hdc, stbi__huffman *hac, stbi__int16 *fac, int b, stbi__uint16 *dequant) +{ + int diff,dc,k; + int t; + + if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + t = stbi__jpeg_huff_decode(j, hdc); + if (t < 0 || t > 15) return stbi__err("bad huffman code","Corrupt JPEG"); + + // 0 all the ac values now so we can do it 32-bits at a time + memset(data,0,64*sizeof(data[0])); + + diff = t ? stbi__extend_receive(j, t) : 0; + if (!stbi__addints_valid(j->img_comp[b].dc_pred, diff)) return stbi__err("bad delta","Corrupt JPEG"); + dc = j->img_comp[b].dc_pred + diff; + j->img_comp[b].dc_pred = dc; + if (!stbi__mul2shorts_valid(dc, dequant[0])) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); + data[0] = (short) (dc * dequant[0]); + + // decode AC components, see JPEG spec + k = 1; + do { + unsigned int zig; + int c,r,s; + if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1); + r = fac[c]; + if (r) { // fast-AC path + k += (r >> 4) & 15; // run + s = r & 15; // combined length + if (s > j->code_bits) return stbi__err("bad huffman code", "Combined length longer than code bits available"); + j->code_buffer <<= s; + j->code_bits -= s; + // decode into unzigzag'd location + zig = stbi__jpeg_dezigzag[k++]; + data[zig] = (short) ((r >> 8) * dequant[zig]); + } else { + int rs = stbi__jpeg_huff_decode(j, hac); + if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG"); + s = rs & 15; + r = rs >> 4; + if (s == 0) { + if (rs != 0xf0) break; // end block + k += 16; + } else { + k += r; + // decode into unzigzag'd location + zig = stbi__jpeg_dezigzag[k++]; + data[zig] = (short) (stbi__extend_receive(j,s) * dequant[zig]); + } + } + } while (k < 64); + return 1; +} + +static int stbi__jpeg_decode_block_prog_dc(stbi__jpeg *j, short data[64], stbi__huffman *hdc, int b) +{ + int diff,dc; + int t; + if (j->spec_end != 0) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); + + if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + + if (j->succ_high == 0) { + // first scan for DC coefficient, must be first + memset(data,0,64*sizeof(data[0])); // 0 all the ac values now + t = stbi__jpeg_huff_decode(j, hdc); + if (t < 0 || t > 15) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); + diff = t ? stbi__extend_receive(j, t) : 0; + + if (!stbi__addints_valid(j->img_comp[b].dc_pred, diff)) return stbi__err("bad delta", "Corrupt JPEG"); + dc = j->img_comp[b].dc_pred + diff; + j->img_comp[b].dc_pred = dc; + if (!stbi__mul2shorts_valid(dc, 1 << j->succ_low)) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); + data[0] = (short) (dc * (1 << j->succ_low)); + } else { + // refinement scan for DC coefficient + if (stbi__jpeg_get_bit(j)) + data[0] += (short) (1 << j->succ_low); + } + return 1; +} + +// @OPTIMIZE: store non-zigzagged during the decode passes, +// and only de-zigzag when dequantizing +static int stbi__jpeg_decode_block_prog_ac(stbi__jpeg *j, short data[64], stbi__huffman *hac, stbi__int16 *fac) +{ + int k; + if (j->spec_start == 0) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); + + if (j->succ_high == 0) { + int shift = j->succ_low; + + if (j->eob_run) { + --j->eob_run; + return 1; + } + + k = j->spec_start; + do { + unsigned int zig; + int c,r,s; + if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1); + r = fac[c]; + if (r) { // fast-AC path + k += (r >> 4) & 15; // run + s = r & 15; // combined length + if (s > j->code_bits) return stbi__err("bad huffman code", "Combined length longer than code bits available"); + j->code_buffer <<= s; + j->code_bits -= s; + zig = stbi__jpeg_dezigzag[k++]; + data[zig] = (short) ((r >> 8) * (1 << shift)); + } else { + int rs = stbi__jpeg_huff_decode(j, hac); + if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG"); + s = rs & 15; + r = rs >> 4; + if (s == 0) { + if (r < 15) { + j->eob_run = (1 << r); + if (r) + j->eob_run += stbi__jpeg_get_bits(j, r); + --j->eob_run; + break; + } + k += 16; + } else { + k += r; + zig = stbi__jpeg_dezigzag[k++]; + data[zig] = (short) (stbi__extend_receive(j,s) * (1 << shift)); + } + } + } while (k <= j->spec_end); + } else { + // refinement scan for these AC coefficients + + short bit = (short) (1 << j->succ_low); + + if (j->eob_run) { + --j->eob_run; + for (k = j->spec_start; k <= j->spec_end; ++k) { + short *p = &data[stbi__jpeg_dezigzag[k]]; + if (*p != 0) + if (stbi__jpeg_get_bit(j)) + if ((*p & bit)==0) { + if (*p > 0) + *p += bit; + else + *p -= bit; + } + } + } else { + k = j->spec_start; + do { + int r,s; + int rs = stbi__jpeg_huff_decode(j, hac); // @OPTIMIZE see if we can use the fast path here, advance-by-r is so slow, eh + if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG"); + s = rs & 15; + r = rs >> 4; + if (s == 0) { + if (r < 15) { + j->eob_run = (1 << r) - 1; + if (r) + j->eob_run += stbi__jpeg_get_bits(j, r); + r = 64; // force end of block + } else { + // r=15 s=0 should write 16 0s, so we just do + // a run of 15 0s and then write s (which is 0), + // so we don't have to do anything special here + } + } else { + if (s != 1) return stbi__err("bad huffman code", "Corrupt JPEG"); + // sign bit + if (stbi__jpeg_get_bit(j)) + s = bit; + else + s = -bit; + } + + // advance by r + while (k <= j->spec_end) { + short *p = &data[stbi__jpeg_dezigzag[k++]]; + if (*p != 0) { + if (stbi__jpeg_get_bit(j)) + if ((*p & bit)==0) { + if (*p > 0) + *p += bit; + else + *p -= bit; + } + } else { + if (r == 0) { + *p = (short) s; + break; + } + --r; + } + } + } while (k <= j->spec_end); + } + } + return 1; +} + +// take a -128..127 value and stbi__clamp it and convert to 0..255 +stbi_inline static stbi_uc stbi__clamp(int x) +{ + // trick to use a single test to catch both cases + if ((unsigned int) x > 255) { + if (x < 0) return 0; + if (x > 255) return 255; + } + return (stbi_uc) x; +} + +#define stbi__f2f(x) ((int) (((x) * 4096 + 0.5))) +#define stbi__fsh(x) ((x) * 4096) + +// derived from jidctint -- DCT_ISLOW +#define STBI__IDCT_1D(s0,s1,s2,s3,s4,s5,s6,s7) \ + int t0,t1,t2,t3,p1,p2,p3,p4,p5,x0,x1,x2,x3; \ + p2 = s2; \ + p3 = s6; \ + p1 = (p2+p3) * stbi__f2f(0.5411961f); \ + t2 = p1 + p3*stbi__f2f(-1.847759065f); \ + t3 = p1 + p2*stbi__f2f( 0.765366865f); \ + p2 = s0; \ + p3 = s4; \ + t0 = stbi__fsh(p2+p3); \ + t1 = stbi__fsh(p2-p3); \ + x0 = t0+t3; \ + x3 = t0-t3; \ + x1 = t1+t2; \ + x2 = t1-t2; \ + t0 = s7; \ + t1 = s5; \ + t2 = s3; \ + t3 = s1; \ + p3 = t0+t2; \ + p4 = t1+t3; \ + p1 = t0+t3; \ + p2 = t1+t2; \ + p5 = (p3+p4)*stbi__f2f( 1.175875602f); \ + t0 = t0*stbi__f2f( 0.298631336f); \ + t1 = t1*stbi__f2f( 2.053119869f); \ + t2 = t2*stbi__f2f( 3.072711026f); \ + t3 = t3*stbi__f2f( 1.501321110f); \ + p1 = p5 + p1*stbi__f2f(-0.899976223f); \ + p2 = p5 + p2*stbi__f2f(-2.562915447f); \ + p3 = p3*stbi__f2f(-1.961570560f); \ + p4 = p4*stbi__f2f(-0.390180644f); \ + t3 += p1+p4; \ + t2 += p2+p3; \ + t1 += p2+p4; \ + t0 += p1+p3; + +static void stbi__idct_block(stbi_uc *out, int out_stride, short data[64]) +{ + int i,val[64],*v=val; + stbi_uc *o; + short *d = data; + + // columns + for (i=0; i < 8; ++i,++d, ++v) { + // if all zeroes, shortcut -- this avoids dequantizing 0s and IDCTing + if (d[ 8]==0 && d[16]==0 && d[24]==0 && d[32]==0 + && d[40]==0 && d[48]==0 && d[56]==0) { + // no shortcut 0 seconds + // (1|2|3|4|5|6|7)==0 0 seconds + // all separate -0.047 seconds + // 1 && 2|3 && 4|5 && 6|7: -0.047 seconds + int dcterm = d[0]*4; + v[0] = v[8] = v[16] = v[24] = v[32] = v[40] = v[48] = v[56] = dcterm; + } else { + STBI__IDCT_1D(d[ 0],d[ 8],d[16],d[24],d[32],d[40],d[48],d[56]) + // constants scaled things up by 1<<12; let's bring them back + // down, but keep 2 extra bits of precision + x0 += 512; x1 += 512; x2 += 512; x3 += 512; + v[ 0] = (x0+t3) >> 10; + v[56] = (x0-t3) >> 10; + v[ 8] = (x1+t2) >> 10; + v[48] = (x1-t2) >> 10; + v[16] = (x2+t1) >> 10; + v[40] = (x2-t1) >> 10; + v[24] = (x3+t0) >> 10; + v[32] = (x3-t0) >> 10; + } + } + + for (i=0, v=val, o=out; i < 8; ++i,v+=8,o+=out_stride) { + // no fast case since the first 1D IDCT spread components out + STBI__IDCT_1D(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7]) + // constants scaled things up by 1<<12, plus we had 1<<2 from first + // loop, plus horizontal and vertical each scale by sqrt(8) so together + // we've got an extra 1<<3, so 1<<17 total we need to remove. + // so we want to round that, which means adding 0.5 * 1<<17, + // aka 65536. Also, we'll end up with -128 to 127 that we want + // to encode as 0..255 by adding 128, so we'll add that before the shift + x0 += 65536 + (128<<17); + x1 += 65536 + (128<<17); + x2 += 65536 + (128<<17); + x3 += 65536 + (128<<17); + // tried computing the shifts into temps, or'ing the temps to see + // if any were out of range, but that was slower + o[0] = stbi__clamp((x0+t3) >> 17); + o[7] = stbi__clamp((x0-t3) >> 17); + o[1] = stbi__clamp((x1+t2) >> 17); + o[6] = stbi__clamp((x1-t2) >> 17); + o[2] = stbi__clamp((x2+t1) >> 17); + o[5] = stbi__clamp((x2-t1) >> 17); + o[3] = stbi__clamp((x3+t0) >> 17); + o[4] = stbi__clamp((x3-t0) >> 17); + } +} + +#ifdef STBI_SSE2 +// sse2 integer IDCT. not the fastest possible implementation but it +// produces bit-identical results to the generic C version so it's +// fully "transparent". +static void stbi__idct_simd(stbi_uc *out, int out_stride, short data[64]) +{ + // This is constructed to match our regular (generic) integer IDCT exactly. + __m128i row0, row1, row2, row3, row4, row5, row6, row7; + __m128i tmp; + + // dot product constant: even elems=x, odd elems=y + #define dct_const(x,y) _mm_setr_epi16((x),(y),(x),(y),(x),(y),(x),(y)) + + // out(0) = c0[even]*x + c0[odd]*y (c0, x, y 16-bit, out 32-bit) + // out(1) = c1[even]*x + c1[odd]*y + #define dct_rot(out0,out1, x,y,c0,c1) \ + __m128i c0##lo = _mm_unpacklo_epi16((x),(y)); \ + __m128i c0##hi = _mm_unpackhi_epi16((x),(y)); \ + __m128i out0##_l = _mm_madd_epi16(c0##lo, c0); \ + __m128i out0##_h = _mm_madd_epi16(c0##hi, c0); \ + __m128i out1##_l = _mm_madd_epi16(c0##lo, c1); \ + __m128i out1##_h = _mm_madd_epi16(c0##hi, c1) + + // out = in << 12 (in 16-bit, out 32-bit) + #define dct_widen(out, in) \ + __m128i out##_l = _mm_srai_epi32(_mm_unpacklo_epi16(_mm_setzero_si128(), (in)), 4); \ + __m128i out##_h = _mm_srai_epi32(_mm_unpackhi_epi16(_mm_setzero_si128(), (in)), 4) + + // wide add + #define dct_wadd(out, a, b) \ + __m128i out##_l = _mm_add_epi32(a##_l, b##_l); \ + __m128i out##_h = _mm_add_epi32(a##_h, b##_h) + + // wide sub + #define dct_wsub(out, a, b) \ + __m128i out##_l = _mm_sub_epi32(a##_l, b##_l); \ + __m128i out##_h = _mm_sub_epi32(a##_h, b##_h) + + // butterfly a/b, add bias, then shift by "s" and pack + #define dct_bfly32o(out0, out1, a,b,bias,s) \ + { \ + __m128i abiased_l = _mm_add_epi32(a##_l, bias); \ + __m128i abiased_h = _mm_add_epi32(a##_h, bias); \ + dct_wadd(sum, abiased, b); \ + dct_wsub(dif, abiased, b); \ + out0 = _mm_packs_epi32(_mm_srai_epi32(sum_l, s), _mm_srai_epi32(sum_h, s)); \ + out1 = _mm_packs_epi32(_mm_srai_epi32(dif_l, s), _mm_srai_epi32(dif_h, s)); \ + } + + // 8-bit interleave step (for transposes) + #define dct_interleave8(a, b) \ + tmp = a; \ + a = _mm_unpacklo_epi8(a, b); \ + b = _mm_unpackhi_epi8(tmp, b) + + // 16-bit interleave step (for transposes) + #define dct_interleave16(a, b) \ + tmp = a; \ + a = _mm_unpacklo_epi16(a, b); \ + b = _mm_unpackhi_epi16(tmp, b) + + #define dct_pass(bias,shift) \ + { \ + /* even part */ \ + dct_rot(t2e,t3e, row2,row6, rot0_0,rot0_1); \ + __m128i sum04 = _mm_add_epi16(row0, row4); \ + __m128i dif04 = _mm_sub_epi16(row0, row4); \ + dct_widen(t0e, sum04); \ + dct_widen(t1e, dif04); \ + dct_wadd(x0, t0e, t3e); \ + dct_wsub(x3, t0e, t3e); \ + dct_wadd(x1, t1e, t2e); \ + dct_wsub(x2, t1e, t2e); \ + /* odd part */ \ + dct_rot(y0o,y2o, row7,row3, rot2_0,rot2_1); \ + dct_rot(y1o,y3o, row5,row1, rot3_0,rot3_1); \ + __m128i sum17 = _mm_add_epi16(row1, row7); \ + __m128i sum35 = _mm_add_epi16(row3, row5); \ + dct_rot(y4o,y5o, sum17,sum35, rot1_0,rot1_1); \ + dct_wadd(x4, y0o, y4o); \ + dct_wadd(x5, y1o, y5o); \ + dct_wadd(x6, y2o, y5o); \ + dct_wadd(x7, y3o, y4o); \ + dct_bfly32o(row0,row7, x0,x7,bias,shift); \ + dct_bfly32o(row1,row6, x1,x6,bias,shift); \ + dct_bfly32o(row2,row5, x2,x5,bias,shift); \ + dct_bfly32o(row3,row4, x3,x4,bias,shift); \ + } + + __m128i rot0_0 = dct_const(stbi__f2f(0.5411961f), stbi__f2f(0.5411961f) + stbi__f2f(-1.847759065f)); + __m128i rot0_1 = dct_const(stbi__f2f(0.5411961f) + stbi__f2f( 0.765366865f), stbi__f2f(0.5411961f)); + __m128i rot1_0 = dct_const(stbi__f2f(1.175875602f) + stbi__f2f(-0.899976223f), stbi__f2f(1.175875602f)); + __m128i rot1_1 = dct_const(stbi__f2f(1.175875602f), stbi__f2f(1.175875602f) + stbi__f2f(-2.562915447f)); + __m128i rot2_0 = dct_const(stbi__f2f(-1.961570560f) + stbi__f2f( 0.298631336f), stbi__f2f(-1.961570560f)); + __m128i rot2_1 = dct_const(stbi__f2f(-1.961570560f), stbi__f2f(-1.961570560f) + stbi__f2f( 3.072711026f)); + __m128i rot3_0 = dct_const(stbi__f2f(-0.390180644f) + stbi__f2f( 2.053119869f), stbi__f2f(-0.390180644f)); + __m128i rot3_1 = dct_const(stbi__f2f(-0.390180644f), stbi__f2f(-0.390180644f) + stbi__f2f( 1.501321110f)); + + // rounding biases in column/row passes, see stbi__idct_block for explanation. + __m128i bias_0 = _mm_set1_epi32(512); + __m128i bias_1 = _mm_set1_epi32(65536 + (128<<17)); + + // load + row0 = _mm_load_si128((const __m128i *) (data + 0*8)); + row1 = _mm_load_si128((const __m128i *) (data + 1*8)); + row2 = _mm_load_si128((const __m128i *) (data + 2*8)); + row3 = _mm_load_si128((const __m128i *) (data + 3*8)); + row4 = _mm_load_si128((const __m128i *) (data + 4*8)); + row5 = _mm_load_si128((const __m128i *) (data + 5*8)); + row6 = _mm_load_si128((const __m128i *) (data + 6*8)); + row7 = _mm_load_si128((const __m128i *) (data + 7*8)); + + // column pass + dct_pass(bias_0, 10); + + { + // 16bit 8x8 transpose pass 1 + dct_interleave16(row0, row4); + dct_interleave16(row1, row5); + dct_interleave16(row2, row6); + dct_interleave16(row3, row7); + + // transpose pass 2 + dct_interleave16(row0, row2); + dct_interleave16(row1, row3); + dct_interleave16(row4, row6); + dct_interleave16(row5, row7); + + // transpose pass 3 + dct_interleave16(row0, row1); + dct_interleave16(row2, row3); + dct_interleave16(row4, row5); + dct_interleave16(row6, row7); + } + + // row pass + dct_pass(bias_1, 17); + + { + // pack + __m128i p0 = _mm_packus_epi16(row0, row1); // a0a1a2a3...a7b0b1b2b3...b7 + __m128i p1 = _mm_packus_epi16(row2, row3); + __m128i p2 = _mm_packus_epi16(row4, row5); + __m128i p3 = _mm_packus_epi16(row6, row7); + + // 8bit 8x8 transpose pass 1 + dct_interleave8(p0, p2); // a0e0a1e1... + dct_interleave8(p1, p3); // c0g0c1g1... + + // transpose pass 2 + dct_interleave8(p0, p1); // a0c0e0g0... + dct_interleave8(p2, p3); // b0d0f0h0... + + // transpose pass 3 + dct_interleave8(p0, p2); // a0b0c0d0... + dct_interleave8(p1, p3); // a4b4c4d4... + + // store + _mm_storel_epi64((__m128i *) out, p0); out += out_stride; + _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p0, 0x4e)); out += out_stride; + _mm_storel_epi64((__m128i *) out, p2); out += out_stride; + _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p2, 0x4e)); out += out_stride; + _mm_storel_epi64((__m128i *) out, p1); out += out_stride; + _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p1, 0x4e)); out += out_stride; + _mm_storel_epi64((__m128i *) out, p3); out += out_stride; + _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p3, 0x4e)); + } + +#undef dct_const +#undef dct_rot +#undef dct_widen +#undef dct_wadd +#undef dct_wsub +#undef dct_bfly32o +#undef dct_interleave8 +#undef dct_interleave16 +#undef dct_pass +} + +#endif // STBI_SSE2 + +#ifdef STBI_NEON + +// NEON integer IDCT. should produce bit-identical +// results to the generic C version. +static void stbi__idct_simd(stbi_uc *out, int out_stride, short data[64]) +{ + int16x8_t row0, row1, row2, row3, row4, row5, row6, row7; + + int16x4_t rot0_0 = vdup_n_s16(stbi__f2f(0.5411961f)); + int16x4_t rot0_1 = vdup_n_s16(stbi__f2f(-1.847759065f)); + int16x4_t rot0_2 = vdup_n_s16(stbi__f2f( 0.765366865f)); + int16x4_t rot1_0 = vdup_n_s16(stbi__f2f( 1.175875602f)); + int16x4_t rot1_1 = vdup_n_s16(stbi__f2f(-0.899976223f)); + int16x4_t rot1_2 = vdup_n_s16(stbi__f2f(-2.562915447f)); + int16x4_t rot2_0 = vdup_n_s16(stbi__f2f(-1.961570560f)); + int16x4_t rot2_1 = vdup_n_s16(stbi__f2f(-0.390180644f)); + int16x4_t rot3_0 = vdup_n_s16(stbi__f2f( 0.298631336f)); + int16x4_t rot3_1 = vdup_n_s16(stbi__f2f( 2.053119869f)); + int16x4_t rot3_2 = vdup_n_s16(stbi__f2f( 3.072711026f)); + int16x4_t rot3_3 = vdup_n_s16(stbi__f2f( 1.501321110f)); + +#define dct_long_mul(out, inq, coeff) \ + int32x4_t out##_l = vmull_s16(vget_low_s16(inq), coeff); \ + int32x4_t out##_h = vmull_s16(vget_high_s16(inq), coeff) + +#define dct_long_mac(out, acc, inq, coeff) \ + int32x4_t out##_l = vmlal_s16(acc##_l, vget_low_s16(inq), coeff); \ + int32x4_t out##_h = vmlal_s16(acc##_h, vget_high_s16(inq), coeff) + +#define dct_widen(out, inq) \ + int32x4_t out##_l = vshll_n_s16(vget_low_s16(inq), 12); \ + int32x4_t out##_h = vshll_n_s16(vget_high_s16(inq), 12) + +// wide add +#define dct_wadd(out, a, b) \ + int32x4_t out##_l = vaddq_s32(a##_l, b##_l); \ + int32x4_t out##_h = vaddq_s32(a##_h, b##_h) + +// wide sub +#define dct_wsub(out, a, b) \ + int32x4_t out##_l = vsubq_s32(a##_l, b##_l); \ + int32x4_t out##_h = vsubq_s32(a##_h, b##_h) + +// butterfly a/b, then shift using "shiftop" by "s" and pack +#define dct_bfly32o(out0,out1, a,b,shiftop,s) \ + { \ + dct_wadd(sum, a, b); \ + dct_wsub(dif, a, b); \ + out0 = vcombine_s16(shiftop(sum_l, s), shiftop(sum_h, s)); \ + out1 = vcombine_s16(shiftop(dif_l, s), shiftop(dif_h, s)); \ + } + +#define dct_pass(shiftop, shift) \ + { \ + /* even part */ \ + int16x8_t sum26 = vaddq_s16(row2, row6); \ + dct_long_mul(p1e, sum26, rot0_0); \ + dct_long_mac(t2e, p1e, row6, rot0_1); \ + dct_long_mac(t3e, p1e, row2, rot0_2); \ + int16x8_t sum04 = vaddq_s16(row0, row4); \ + int16x8_t dif04 = vsubq_s16(row0, row4); \ + dct_widen(t0e, sum04); \ + dct_widen(t1e, dif04); \ + dct_wadd(x0, t0e, t3e); \ + dct_wsub(x3, t0e, t3e); \ + dct_wadd(x1, t1e, t2e); \ + dct_wsub(x2, t1e, t2e); \ + /* odd part */ \ + int16x8_t sum15 = vaddq_s16(row1, row5); \ + int16x8_t sum17 = vaddq_s16(row1, row7); \ + int16x8_t sum35 = vaddq_s16(row3, row5); \ + int16x8_t sum37 = vaddq_s16(row3, row7); \ + int16x8_t sumodd = vaddq_s16(sum17, sum35); \ + dct_long_mul(p5o, sumodd, rot1_0); \ + dct_long_mac(p1o, p5o, sum17, rot1_1); \ + dct_long_mac(p2o, p5o, sum35, rot1_2); \ + dct_long_mul(p3o, sum37, rot2_0); \ + dct_long_mul(p4o, sum15, rot2_1); \ + dct_wadd(sump13o, p1o, p3o); \ + dct_wadd(sump24o, p2o, p4o); \ + dct_wadd(sump23o, p2o, p3o); \ + dct_wadd(sump14o, p1o, p4o); \ + dct_long_mac(x4, sump13o, row7, rot3_0); \ + dct_long_mac(x5, sump24o, row5, rot3_1); \ + dct_long_mac(x6, sump23o, row3, rot3_2); \ + dct_long_mac(x7, sump14o, row1, rot3_3); \ + dct_bfly32o(row0,row7, x0,x7,shiftop,shift); \ + dct_bfly32o(row1,row6, x1,x6,shiftop,shift); \ + dct_bfly32o(row2,row5, x2,x5,shiftop,shift); \ + dct_bfly32o(row3,row4, x3,x4,shiftop,shift); \ + } + + // load + row0 = vld1q_s16(data + 0*8); + row1 = vld1q_s16(data + 1*8); + row2 = vld1q_s16(data + 2*8); + row3 = vld1q_s16(data + 3*8); + row4 = vld1q_s16(data + 4*8); + row5 = vld1q_s16(data + 5*8); + row6 = vld1q_s16(data + 6*8); + row7 = vld1q_s16(data + 7*8); + + // add DC bias + row0 = vaddq_s16(row0, vsetq_lane_s16(1024, vdupq_n_s16(0), 0)); + + // column pass + dct_pass(vrshrn_n_s32, 10); + + // 16bit 8x8 transpose + { +// these three map to a single VTRN.16, VTRN.32, and VSWP, respectively. +// whether compilers actually get this is another story, sadly. +#define dct_trn16(x, y) { int16x8x2_t t = vtrnq_s16(x, y); x = t.val[0]; y = t.val[1]; } +#define dct_trn32(x, y) { int32x4x2_t t = vtrnq_s32(vreinterpretq_s32_s16(x), vreinterpretq_s32_s16(y)); x = vreinterpretq_s16_s32(t.val[0]); y = vreinterpretq_s16_s32(t.val[1]); } +#define dct_trn64(x, y) { int16x8_t x0 = x; int16x8_t y0 = y; x = vcombine_s16(vget_low_s16(x0), vget_low_s16(y0)); y = vcombine_s16(vget_high_s16(x0), vget_high_s16(y0)); } + + // pass 1 + dct_trn16(row0, row1); // a0b0a2b2a4b4a6b6 + dct_trn16(row2, row3); + dct_trn16(row4, row5); + dct_trn16(row6, row7); + + // pass 2 + dct_trn32(row0, row2); // a0b0c0d0a4b4c4d4 + dct_trn32(row1, row3); + dct_trn32(row4, row6); + dct_trn32(row5, row7); + + // pass 3 + dct_trn64(row0, row4); // a0b0c0d0e0f0g0h0 + dct_trn64(row1, row5); + dct_trn64(row2, row6); + dct_trn64(row3, row7); + +#undef dct_trn16 +#undef dct_trn32 +#undef dct_trn64 + } + + // row pass + // vrshrn_n_s32 only supports shifts up to 16, we need + // 17. so do a non-rounding shift of 16 first then follow + // up with a rounding shift by 1. + dct_pass(vshrn_n_s32, 16); + + { + // pack and round + uint8x8_t p0 = vqrshrun_n_s16(row0, 1); + uint8x8_t p1 = vqrshrun_n_s16(row1, 1); + uint8x8_t p2 = vqrshrun_n_s16(row2, 1); + uint8x8_t p3 = vqrshrun_n_s16(row3, 1); + uint8x8_t p4 = vqrshrun_n_s16(row4, 1); + uint8x8_t p5 = vqrshrun_n_s16(row5, 1); + uint8x8_t p6 = vqrshrun_n_s16(row6, 1); + uint8x8_t p7 = vqrshrun_n_s16(row7, 1); + + // again, these can translate into one instruction, but often don't. +#define dct_trn8_8(x, y) { uint8x8x2_t t = vtrn_u8(x, y); x = t.val[0]; y = t.val[1]; } +#define dct_trn8_16(x, y) { uint16x4x2_t t = vtrn_u16(vreinterpret_u16_u8(x), vreinterpret_u16_u8(y)); x = vreinterpret_u8_u16(t.val[0]); y = vreinterpret_u8_u16(t.val[1]); } +#define dct_trn8_32(x, y) { uint32x2x2_t t = vtrn_u32(vreinterpret_u32_u8(x), vreinterpret_u32_u8(y)); x = vreinterpret_u8_u32(t.val[0]); y = vreinterpret_u8_u32(t.val[1]); } + + // sadly can't use interleaved stores here since we only write + // 8 bytes to each scan line! + + // 8x8 8-bit transpose pass 1 + dct_trn8_8(p0, p1); + dct_trn8_8(p2, p3); + dct_trn8_8(p4, p5); + dct_trn8_8(p6, p7); + + // pass 2 + dct_trn8_16(p0, p2); + dct_trn8_16(p1, p3); + dct_trn8_16(p4, p6); + dct_trn8_16(p5, p7); + + // pass 3 + dct_trn8_32(p0, p4); + dct_trn8_32(p1, p5); + dct_trn8_32(p2, p6); + dct_trn8_32(p3, p7); + + // store + vst1_u8(out, p0); out += out_stride; + vst1_u8(out, p1); out += out_stride; + vst1_u8(out, p2); out += out_stride; + vst1_u8(out, p3); out += out_stride; + vst1_u8(out, p4); out += out_stride; + vst1_u8(out, p5); out += out_stride; + vst1_u8(out, p6); out += out_stride; + vst1_u8(out, p7); + +#undef dct_trn8_8 +#undef dct_trn8_16 +#undef dct_trn8_32 + } + +#undef dct_long_mul +#undef dct_long_mac +#undef dct_widen +#undef dct_wadd +#undef dct_wsub +#undef dct_bfly32o +#undef dct_pass +} + +#endif // STBI_NEON + +#define STBI__MARKER_none 0xff +// if there's a pending marker from the entropy stream, return that +// otherwise, fetch from the stream and get a marker. if there's no +// marker, return 0xff, which is never a valid marker value +static stbi_uc stbi__get_marker(stbi__jpeg *j) +{ + stbi_uc x; + if (j->marker != STBI__MARKER_none) { x = j->marker; j->marker = STBI__MARKER_none; return x; } + x = stbi__get8(j->s); + if (x != 0xff) return STBI__MARKER_none; + while (x == 0xff) + x = stbi__get8(j->s); // consume repeated 0xff fill bytes + return x; +} + +// in each scan, we'll have scan_n components, and the order +// of the components is specified by order[] +#define STBI__RESTART(x) ((x) >= 0xd0 && (x) <= 0xd7) + +// after a restart interval, stbi__jpeg_reset the entropy decoder and +// the dc prediction +static void stbi__jpeg_reset(stbi__jpeg *j) +{ + j->code_bits = 0; + j->code_buffer = 0; + j->nomore = 0; + j->img_comp[0].dc_pred = j->img_comp[1].dc_pred = j->img_comp[2].dc_pred = j->img_comp[3].dc_pred = 0; + j->marker = STBI__MARKER_none; + j->todo = j->restart_interval ? j->restart_interval : 0x7fffffff; + j->eob_run = 0; + // no more than 1<<31 MCUs if no restart_interal? that's plenty safe, + // since we don't even allow 1<<30 pixels +} + +static int stbi__parse_entropy_coded_data(stbi__jpeg *z) +{ + stbi__jpeg_reset(z); + if (!z->progressive) { + if (z->scan_n == 1) { + int i,j; + STBI_SIMD_ALIGN(short, data[64]); + int n = z->order[0]; + // non-interleaved data, we just need to process one block at a time, + // in trivial scanline order + // number of blocks to do just depends on how many actual "pixels" this + // component has, independent of interleaved MCU blocking and such + int w = (z->img_comp[n].x+7) >> 3; + int h = (z->img_comp[n].y+7) >> 3; + for (j=0; j < h; ++j) { + for (i=0; i < w; ++i) { + int ha = z->img_comp[n].ha; + if (!stbi__jpeg_decode_block(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+ha, z->fast_ac[ha], n, z->dequant[z->img_comp[n].tq])) return 0; + z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8, z->img_comp[n].w2, data); + // every data block is an MCU, so countdown the restart interval + if (--z->todo <= 0) { + if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); + // if it's NOT a restart, then just bail, so we get corrupt data + // rather than no data + if (!STBI__RESTART(z->marker)) return 1; + stbi__jpeg_reset(z); + } + } + } + return 1; + } else { // interleaved + int i,j,k,x,y; + STBI_SIMD_ALIGN(short, data[64]); + for (j=0; j < z->img_mcu_y; ++j) { + for (i=0; i < z->img_mcu_x; ++i) { + // scan an interleaved mcu... process scan_n components in order + for (k=0; k < z->scan_n; ++k) { + int n = z->order[k]; + // scan out an mcu's worth of this component; that's just determined + // by the basic H and V specified for the component + for (y=0; y < z->img_comp[n].v; ++y) { + for (x=0; x < z->img_comp[n].h; ++x) { + int x2 = (i*z->img_comp[n].h + x)*8; + int y2 = (j*z->img_comp[n].v + y)*8; + int ha = z->img_comp[n].ha; + if (!stbi__jpeg_decode_block(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+ha, z->fast_ac[ha], n, z->dequant[z->img_comp[n].tq])) return 0; + z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*y2+x2, z->img_comp[n].w2, data); + } + } + } + // after all interleaved components, that's an interleaved MCU, + // so now count down the restart interval + if (--z->todo <= 0) { + if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); + if (!STBI__RESTART(z->marker)) return 1; + stbi__jpeg_reset(z); + } + } + } + return 1; + } + } else { + if (z->scan_n == 1) { + int i,j; + int n = z->order[0]; + // non-interleaved data, we just need to process one block at a time, + // in trivial scanline order + // number of blocks to do just depends on how many actual "pixels" this + // component has, independent of interleaved MCU blocking and such + int w = (z->img_comp[n].x+7) >> 3; + int h = (z->img_comp[n].y+7) >> 3; + for (j=0; j < h; ++j) { + for (i=0; i < w; ++i) { + short *data = z->img_comp[n].coeff + 64 * (i + j * z->img_comp[n].coeff_w); + if (z->spec_start == 0) { + if (!stbi__jpeg_decode_block_prog_dc(z, data, &z->huff_dc[z->img_comp[n].hd], n)) + return 0; + } else { + int ha = z->img_comp[n].ha; + if (!stbi__jpeg_decode_block_prog_ac(z, data, &z->huff_ac[ha], z->fast_ac[ha])) + return 0; + } + // every data block is an MCU, so countdown the restart interval + if (--z->todo <= 0) { + if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); + if (!STBI__RESTART(z->marker)) return 1; + stbi__jpeg_reset(z); + } + } + } + return 1; + } else { // interleaved + int i,j,k,x,y; + for (j=0; j < z->img_mcu_y; ++j) { + for (i=0; i < z->img_mcu_x; ++i) { + // scan an interleaved mcu... process scan_n components in order + for (k=0; k < z->scan_n; ++k) { + int n = z->order[k]; + // scan out an mcu's worth of this component; that's just determined + // by the basic H and V specified for the component + for (y=0; y < z->img_comp[n].v; ++y) { + for (x=0; x < z->img_comp[n].h; ++x) { + int x2 = (i*z->img_comp[n].h + x); + int y2 = (j*z->img_comp[n].v + y); + short *data = z->img_comp[n].coeff + 64 * (x2 + y2 * z->img_comp[n].coeff_w); + if (!stbi__jpeg_decode_block_prog_dc(z, data, &z->huff_dc[z->img_comp[n].hd], n)) + return 0; + } + } + } + // after all interleaved components, that's an interleaved MCU, + // so now count down the restart interval + if (--z->todo <= 0) { + if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); + if (!STBI__RESTART(z->marker)) return 1; + stbi__jpeg_reset(z); + } + } + } + return 1; + } + } +} + +static void stbi__jpeg_dequantize(short *data, stbi__uint16 *dequant) +{ + int i; + for (i=0; i < 64; ++i) + data[i] *= dequant[i]; +} + +static void stbi__jpeg_finish(stbi__jpeg *z) +{ + if (z->progressive) { + // dequantize and idct the data + int i,j,n; + for (n=0; n < z->s->img_n; ++n) { + int w = (z->img_comp[n].x+7) >> 3; + int h = (z->img_comp[n].y+7) >> 3; + for (j=0; j < h; ++j) { + for (i=0; i < w; ++i) { + short *data = z->img_comp[n].coeff + 64 * (i + j * z->img_comp[n].coeff_w); + stbi__jpeg_dequantize(data, z->dequant[z->img_comp[n].tq]); + z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8, z->img_comp[n].w2, data); + } + } + } + } +} + +static int stbi__process_marker(stbi__jpeg *z, int m) +{ + int L; + switch (m) { + case STBI__MARKER_none: // no marker found + return stbi__err("expected marker","Corrupt JPEG"); + + case 0xDD: // DRI - specify restart interval + if (stbi__get16be(z->s) != 4) return stbi__err("bad DRI len","Corrupt JPEG"); + z->restart_interval = stbi__get16be(z->s); + return 1; + + case 0xDB: // DQT - define quantization table + L = stbi__get16be(z->s)-2; + while (L > 0) { + int q = stbi__get8(z->s); + int p = q >> 4, sixteen = (p != 0); + int t = q & 15,i; + if (p != 0 && p != 1) return stbi__err("bad DQT type","Corrupt JPEG"); + if (t > 3) return stbi__err("bad DQT table","Corrupt JPEG"); + + for (i=0; i < 64; ++i) + z->dequant[t][stbi__jpeg_dezigzag[i]] = (stbi__uint16)(sixteen ? stbi__get16be(z->s) : stbi__get8(z->s)); + L -= (sixteen ? 129 : 65); + } + return L==0; + + case 0xC4: // DHT - define huffman table + L = stbi__get16be(z->s)-2; + while (L > 0) { + stbi_uc *v; + int sizes[16],i,n=0; + int q = stbi__get8(z->s); + int tc = q >> 4; + int th = q & 15; + if (tc > 1 || th > 3) return stbi__err("bad DHT header","Corrupt JPEG"); + for (i=0; i < 16; ++i) { + sizes[i] = stbi__get8(z->s); + n += sizes[i]; + } + if(n > 256) return stbi__err("bad DHT header","Corrupt JPEG"); // Loop over i < n would write past end of values! + L -= 17; + if (tc == 0) { + if (!stbi__build_huffman(z->huff_dc+th, sizes)) return 0; + v = z->huff_dc[th].values; + } else { + if (!stbi__build_huffman(z->huff_ac+th, sizes)) return 0; + v = z->huff_ac[th].values; + } + for (i=0; i < n; ++i) + v[i] = stbi__get8(z->s); + if (tc != 0) + stbi__build_fast_ac(z->fast_ac[th], z->huff_ac + th); + L -= n; + } + return L==0; + } + + // check for comment block or APP blocks + if ((m >= 0xE0 && m <= 0xEF) || m == 0xFE) { + L = stbi__get16be(z->s); + if (L < 2) { + if (m == 0xFE) + return stbi__err("bad COM len","Corrupt JPEG"); + else + return stbi__err("bad APP len","Corrupt JPEG"); + } + L -= 2; + + if (m == 0xE0 && L >= 5) { // JFIF APP0 segment + static const unsigned char tag[5] = {'J','F','I','F','\0'}; + int ok = 1; + int i; + for (i=0; i < 5; ++i) + if (stbi__get8(z->s) != tag[i]) + ok = 0; + L -= 5; + if (ok) + z->jfif = 1; + } else if (m == 0xEE && L >= 12) { // Adobe APP14 segment + static const unsigned char tag[6] = {'A','d','o','b','e','\0'}; + int ok = 1; + int i; + for (i=0; i < 6; ++i) + if (stbi__get8(z->s) != tag[i]) + ok = 0; + L -= 6; + if (ok) { + stbi__get8(z->s); // version + stbi__get16be(z->s); // flags0 + stbi__get16be(z->s); // flags1 + z->app14_color_transform = stbi__get8(z->s); // color transform + L -= 6; + } + } + + stbi__skip(z->s, L); + return 1; + } + + return stbi__err("unknown marker","Corrupt JPEG"); +} + +// after we see SOS +static int stbi__process_scan_header(stbi__jpeg *z) +{ + int i; + int Ls = stbi__get16be(z->s); + z->scan_n = stbi__get8(z->s); + if (z->scan_n < 1 || z->scan_n > 4 || z->scan_n > (int) z->s->img_n) return stbi__err("bad SOS component count","Corrupt JPEG"); + if (Ls != 6+2*z->scan_n) return stbi__err("bad SOS len","Corrupt JPEG"); + for (i=0; i < z->scan_n; ++i) { + int id = stbi__get8(z->s), which; + int q = stbi__get8(z->s); + for (which = 0; which < z->s->img_n; ++which) + if (z->img_comp[which].id == id) + break; + if (which == z->s->img_n) return 0; // no match + z->img_comp[which].hd = q >> 4; if (z->img_comp[which].hd > 3) return stbi__err("bad DC huff","Corrupt JPEG"); + z->img_comp[which].ha = q & 15; if (z->img_comp[which].ha > 3) return stbi__err("bad AC huff","Corrupt JPEG"); + z->order[i] = which; + } + + { + int aa; + z->spec_start = stbi__get8(z->s); + z->spec_end = stbi__get8(z->s); // should be 63, but might be 0 + aa = stbi__get8(z->s); + z->succ_high = (aa >> 4); + z->succ_low = (aa & 15); + if (z->progressive) { + if (z->spec_start > 63 || z->spec_end > 63 || z->spec_start > z->spec_end || z->succ_high > 13 || z->succ_low > 13) + return stbi__err("bad SOS", "Corrupt JPEG"); + } else { + if (z->spec_start != 0) return stbi__err("bad SOS","Corrupt JPEG"); + if (z->succ_high != 0 || z->succ_low != 0) return stbi__err("bad SOS","Corrupt JPEG"); + z->spec_end = 63; + } + } + + return 1; +} + +static int stbi__free_jpeg_components(stbi__jpeg *z, int ncomp, int why) +{ + int i; + for (i=0; i < ncomp; ++i) { + if (z->img_comp[i].raw_data) { + STBI_FREE(z->img_comp[i].raw_data); + z->img_comp[i].raw_data = NULL; + z->img_comp[i].data = NULL; + } + if (z->img_comp[i].raw_coeff) { + STBI_FREE(z->img_comp[i].raw_coeff); + z->img_comp[i].raw_coeff = 0; + z->img_comp[i].coeff = 0; + } + if (z->img_comp[i].linebuf) { + STBI_FREE(z->img_comp[i].linebuf); + z->img_comp[i].linebuf = NULL; + } + } + return why; +} + +static int stbi__process_frame_header(stbi__jpeg *z, int scan) +{ + stbi__context *s = z->s; + int Lf,p,i,q, h_max=1,v_max=1,c; + Lf = stbi__get16be(s); if (Lf < 11) return stbi__err("bad SOF len","Corrupt JPEG"); // JPEG + p = stbi__get8(s); if (p != 8) return stbi__err("only 8-bit","JPEG format not supported: 8-bit only"); // JPEG baseline + s->img_y = stbi__get16be(s); if (s->img_y == 0) return stbi__err("no header height", "JPEG format not supported: delayed height"); // Legal, but we don't handle it--but neither does IJG + s->img_x = stbi__get16be(s); if (s->img_x == 0) return stbi__err("0 width","Corrupt JPEG"); // JPEG requires + if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); + if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); + c = stbi__get8(s); + if (c != 3 && c != 1 && c != 4) return stbi__err("bad component count","Corrupt JPEG"); + s->img_n = c; + for (i=0; i < c; ++i) { + z->img_comp[i].data = NULL; + z->img_comp[i].linebuf = NULL; + } + + if (Lf != 8+3*s->img_n) return stbi__err("bad SOF len","Corrupt JPEG"); + + z->rgb = 0; + for (i=0; i < s->img_n; ++i) { + static const unsigned char rgb[3] = { 'R', 'G', 'B' }; + z->img_comp[i].id = stbi__get8(s); + if (s->img_n == 3 && z->img_comp[i].id == rgb[i]) + ++z->rgb; + q = stbi__get8(s); + z->img_comp[i].h = (q >> 4); if (!z->img_comp[i].h || z->img_comp[i].h > 4) return stbi__err("bad H","Corrupt JPEG"); + z->img_comp[i].v = q & 15; if (!z->img_comp[i].v || z->img_comp[i].v > 4) return stbi__err("bad V","Corrupt JPEG"); + z->img_comp[i].tq = stbi__get8(s); if (z->img_comp[i].tq > 3) return stbi__err("bad TQ","Corrupt JPEG"); + } + + if (scan != STBI__SCAN_load) return 1; + + if (!stbi__mad3sizes_valid(s->img_x, s->img_y, s->img_n, 0)) return stbi__err("too large", "Image too large to decode"); + + for (i=0; i < s->img_n; ++i) { + if (z->img_comp[i].h > h_max) h_max = z->img_comp[i].h; + if (z->img_comp[i].v > v_max) v_max = z->img_comp[i].v; + } + + // check that plane subsampling factors are integer ratios; our resamplers can't deal with fractional ratios + // and I've never seen a non-corrupted JPEG file actually use them + for (i=0; i < s->img_n; ++i) { + if (h_max % z->img_comp[i].h != 0) return stbi__err("bad H","Corrupt JPEG"); + if (v_max % z->img_comp[i].v != 0) return stbi__err("bad V","Corrupt JPEG"); + } + + // compute interleaved mcu info + z->img_h_max = h_max; + z->img_v_max = v_max; + z->img_mcu_w = h_max * 8; + z->img_mcu_h = v_max * 8; + // these sizes can't be more than 17 bits + z->img_mcu_x = (s->img_x + z->img_mcu_w-1) / z->img_mcu_w; + z->img_mcu_y = (s->img_y + z->img_mcu_h-1) / z->img_mcu_h; + + for (i=0; i < s->img_n; ++i) { + // number of effective pixels (e.g. for non-interleaved MCU) + z->img_comp[i].x = (s->img_x * z->img_comp[i].h + h_max-1) / h_max; + z->img_comp[i].y = (s->img_y * z->img_comp[i].v + v_max-1) / v_max; + // to simplify generation, we'll allocate enough memory to decode + // the bogus oversized data from using interleaved MCUs and their + // big blocks (e.g. a 16x16 iMCU on an image of width 33); we won't + // discard the extra data until colorspace conversion + // + // img_mcu_x, img_mcu_y: <=17 bits; comp[i].h and .v are <=4 (checked earlier) + // so these muls can't overflow with 32-bit ints (which we require) + z->img_comp[i].w2 = z->img_mcu_x * z->img_comp[i].h * 8; + z->img_comp[i].h2 = z->img_mcu_y * z->img_comp[i].v * 8; + z->img_comp[i].coeff = 0; + z->img_comp[i].raw_coeff = 0; + z->img_comp[i].linebuf = NULL; + z->img_comp[i].raw_data = stbi__malloc_mad2(z->img_comp[i].w2, z->img_comp[i].h2, 15); + if (z->img_comp[i].raw_data == NULL) + return stbi__free_jpeg_components(z, i+1, stbi__err("outofmem", "Out of memory")); + // align blocks for idct using mmx/sse + z->img_comp[i].data = (stbi_uc*) (((size_t) z->img_comp[i].raw_data + 15) & ~15); + if (z->progressive) { + // w2, h2 are multiples of 8 (see above) + z->img_comp[i].coeff_w = z->img_comp[i].w2 / 8; + z->img_comp[i].coeff_h = z->img_comp[i].h2 / 8; + z->img_comp[i].raw_coeff = stbi__malloc_mad3(z->img_comp[i].w2, z->img_comp[i].h2, sizeof(short), 15); + if (z->img_comp[i].raw_coeff == NULL) + return stbi__free_jpeg_components(z, i+1, stbi__err("outofmem", "Out of memory")); + z->img_comp[i].coeff = (short*) (((size_t) z->img_comp[i].raw_coeff + 15) & ~15); + } + } + + return 1; +} + +// use comparisons since in some cases we handle more than one case (e.g. SOF) +#define stbi__DNL(x) ((x) == 0xdc) +#define stbi__SOI(x) ((x) == 0xd8) +#define stbi__EOI(x) ((x) == 0xd9) +#define stbi__SOF(x) ((x) == 0xc0 || (x) == 0xc1 || (x) == 0xc2) +#define stbi__SOS(x) ((x) == 0xda) + +#define stbi__SOF_progressive(x) ((x) == 0xc2) + +static int stbi__decode_jpeg_header(stbi__jpeg *z, int scan) +{ + int m; + z->jfif = 0; + z->app14_color_transform = -1; // valid values are 0,1,2 + z->marker = STBI__MARKER_none; // initialize cached marker to empty + m = stbi__get_marker(z); + if (!stbi__SOI(m)) return stbi__err("no SOI","Corrupt JPEG"); + if (scan == STBI__SCAN_type) return 1; + m = stbi__get_marker(z); + while (!stbi__SOF(m)) { + if (!stbi__process_marker(z,m)) return 0; + m = stbi__get_marker(z); + while (m == STBI__MARKER_none) { + // some files have extra padding after their blocks, so ok, we'll scan + if (stbi__at_eof(z->s)) return stbi__err("no SOF", "Corrupt JPEG"); + m = stbi__get_marker(z); + } + } + z->progressive = stbi__SOF_progressive(m); + if (!stbi__process_frame_header(z, scan)) return 0; + return 1; +} + +static stbi_uc stbi__skip_jpeg_junk_at_end(stbi__jpeg *j) +{ + // some JPEGs have junk at end, skip over it but if we find what looks + // like a valid marker, resume there + while (!stbi__at_eof(j->s)) { + stbi_uc x = stbi__get8(j->s); + while (x == 0xff) { // might be a marker + if (stbi__at_eof(j->s)) return STBI__MARKER_none; + x = stbi__get8(j->s); + if (x != 0x00 && x != 0xff) { + // not a stuffed zero or lead-in to another marker, looks + // like an actual marker, return it + return x; + } + // stuffed zero has x=0 now which ends the loop, meaning we go + // back to regular scan loop. + // repeated 0xff keeps trying to read the next byte of the marker. + } + } + return STBI__MARKER_none; +} + +// decode image to YCbCr format +static int stbi__decode_jpeg_image(stbi__jpeg *j) +{ + int m; + for (m = 0; m < 4; m++) { + j->img_comp[m].raw_data = NULL; + j->img_comp[m].raw_coeff = NULL; + } + j->restart_interval = 0; + if (!stbi__decode_jpeg_header(j, STBI__SCAN_load)) return 0; + m = stbi__get_marker(j); + while (!stbi__EOI(m)) { + if (stbi__SOS(m)) { + if (!stbi__process_scan_header(j)) return 0; + if (!stbi__parse_entropy_coded_data(j)) return 0; + if (j->marker == STBI__MARKER_none ) { + j->marker = stbi__skip_jpeg_junk_at_end(j); + // if we reach eof without hitting a marker, stbi__get_marker() below will fail and we'll eventually return 0 + } + m = stbi__get_marker(j); + if (STBI__RESTART(m)) + m = stbi__get_marker(j); + } else if (stbi__DNL(m)) { + int Ld = stbi__get16be(j->s); + stbi__uint32 NL = stbi__get16be(j->s); + if (Ld != 4) return stbi__err("bad DNL len", "Corrupt JPEG"); + if (NL != j->s->img_y) return stbi__err("bad DNL height", "Corrupt JPEG"); + m = stbi__get_marker(j); + } else { + if (!stbi__process_marker(j, m)) return 1; + m = stbi__get_marker(j); + } + } + if (j->progressive) + stbi__jpeg_finish(j); + return 1; +} + +// static jfif-centered resampling (across block boundaries) + +typedef stbi_uc *(*resample_row_func)(stbi_uc *out, stbi_uc *in0, stbi_uc *in1, + int w, int hs); + +#define stbi__div4(x) ((stbi_uc) ((x) >> 2)) + +static stbi_uc *resample_row_1(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + STBI_NOTUSED(out); + STBI_NOTUSED(in_far); + STBI_NOTUSED(w); + STBI_NOTUSED(hs); + return in_near; +} + +static stbi_uc* stbi__resample_row_v_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + // need to generate two samples vertically for every one in input + int i; + STBI_NOTUSED(hs); + for (i=0; i < w; ++i) + out[i] = stbi__div4(3*in_near[i] + in_far[i] + 2); + return out; +} + +static stbi_uc* stbi__resample_row_h_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + // need to generate two samples horizontally for every one in input + int i; + stbi_uc *input = in_near; + + if (w == 1) { + // if only one sample, can't do any interpolation + out[0] = out[1] = input[0]; + return out; + } + + out[0] = input[0]; + out[1] = stbi__div4(input[0]*3 + input[1] + 2); + for (i=1; i < w-1; ++i) { + int n = 3*input[i]+2; + out[i*2+0] = stbi__div4(n+input[i-1]); + out[i*2+1] = stbi__div4(n+input[i+1]); + } + out[i*2+0] = stbi__div4(input[w-2]*3 + input[w-1] + 2); + out[i*2+1] = input[w-1]; + + STBI_NOTUSED(in_far); + STBI_NOTUSED(hs); + + return out; +} + +#define stbi__div16(x) ((stbi_uc) ((x) >> 4)) + +static stbi_uc *stbi__resample_row_hv_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + // need to generate 2x2 samples for every one in input + int i,t0,t1; + if (w == 1) { + out[0] = out[1] = stbi__div4(3*in_near[0] + in_far[0] + 2); + return out; + } + + t1 = 3*in_near[0] + in_far[0]; + out[0] = stbi__div4(t1+2); + for (i=1; i < w; ++i) { + t0 = t1; + t1 = 3*in_near[i]+in_far[i]; + out[i*2-1] = stbi__div16(3*t0 + t1 + 8); + out[i*2 ] = stbi__div16(3*t1 + t0 + 8); + } + out[w*2-1] = stbi__div4(t1+2); + + STBI_NOTUSED(hs); + + return out; +} + +#if defined(STBI_SSE2) || defined(STBI_NEON) +static stbi_uc *stbi__resample_row_hv_2_simd(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + // need to generate 2x2 samples for every one in input + int i=0,t0,t1; + + if (w == 1) { + out[0] = out[1] = stbi__div4(3*in_near[0] + in_far[0] + 2); + return out; + } + + t1 = 3*in_near[0] + in_far[0]; + // process groups of 8 pixels for as long as we can. + // note we can't handle the last pixel in a row in this loop + // because we need to handle the filter boundary conditions. + for (; i < ((w-1) & ~7); i += 8) { +#if defined(STBI_SSE2) + // load and perform the vertical filtering pass + // this uses 3*x + y = 4*x + (y - x) + __m128i zero = _mm_setzero_si128(); + __m128i farb = _mm_loadl_epi64((__m128i *) (in_far + i)); + __m128i nearb = _mm_loadl_epi64((__m128i *) (in_near + i)); + __m128i farw = _mm_unpacklo_epi8(farb, zero); + __m128i nearw = _mm_unpacklo_epi8(nearb, zero); + __m128i diff = _mm_sub_epi16(farw, nearw); + __m128i nears = _mm_slli_epi16(nearw, 2); + __m128i curr = _mm_add_epi16(nears, diff); // current row + + // horizontal filter works the same based on shifted vers of current + // row. "prev" is current row shifted right by 1 pixel; we need to + // insert the previous pixel value (from t1). + // "next" is current row shifted left by 1 pixel, with first pixel + // of next block of 8 pixels added in. + __m128i prv0 = _mm_slli_si128(curr, 2); + __m128i nxt0 = _mm_srli_si128(curr, 2); + __m128i prev = _mm_insert_epi16(prv0, t1, 0); + __m128i next = _mm_insert_epi16(nxt0, 3*in_near[i+8] + in_far[i+8], 7); + + // horizontal filter, polyphase implementation since it's convenient: + // even pixels = 3*cur + prev = cur*4 + (prev - cur) + // odd pixels = 3*cur + next = cur*4 + (next - cur) + // note the shared term. + __m128i bias = _mm_set1_epi16(8); + __m128i curs = _mm_slli_epi16(curr, 2); + __m128i prvd = _mm_sub_epi16(prev, curr); + __m128i nxtd = _mm_sub_epi16(next, curr); + __m128i curb = _mm_add_epi16(curs, bias); + __m128i even = _mm_add_epi16(prvd, curb); + __m128i odd = _mm_add_epi16(nxtd, curb); + + // interleave even and odd pixels, then undo scaling. + __m128i int0 = _mm_unpacklo_epi16(even, odd); + __m128i int1 = _mm_unpackhi_epi16(even, odd); + __m128i de0 = _mm_srli_epi16(int0, 4); + __m128i de1 = _mm_srli_epi16(int1, 4); + + // pack and write output + __m128i outv = _mm_packus_epi16(de0, de1); + _mm_storeu_si128((__m128i *) (out + i*2), outv); +#elif defined(STBI_NEON) + // load and perform the vertical filtering pass + // this uses 3*x + y = 4*x + (y - x) + uint8x8_t farb = vld1_u8(in_far + i); + uint8x8_t nearb = vld1_u8(in_near + i); + int16x8_t diff = vreinterpretq_s16_u16(vsubl_u8(farb, nearb)); + int16x8_t nears = vreinterpretq_s16_u16(vshll_n_u8(nearb, 2)); + int16x8_t curr = vaddq_s16(nears, diff); // current row + + // horizontal filter works the same based on shifted vers of current + // row. "prev" is current row shifted right by 1 pixel; we need to + // insert the previous pixel value (from t1). + // "next" is current row shifted left by 1 pixel, with first pixel + // of next block of 8 pixels added in. + int16x8_t prv0 = vextq_s16(curr, curr, 7); + int16x8_t nxt0 = vextq_s16(curr, curr, 1); + int16x8_t prev = vsetq_lane_s16(t1, prv0, 0); + int16x8_t next = vsetq_lane_s16(3*in_near[i+8] + in_far[i+8], nxt0, 7); + + // horizontal filter, polyphase implementation since it's convenient: + // even pixels = 3*cur + prev = cur*4 + (prev - cur) + // odd pixels = 3*cur + next = cur*4 + (next - cur) + // note the shared term. + int16x8_t curs = vshlq_n_s16(curr, 2); + int16x8_t prvd = vsubq_s16(prev, curr); + int16x8_t nxtd = vsubq_s16(next, curr); + int16x8_t even = vaddq_s16(curs, prvd); + int16x8_t odd = vaddq_s16(curs, nxtd); + + // undo scaling and round, then store with even/odd phases interleaved + uint8x8x2_t o; + o.val[0] = vqrshrun_n_s16(even, 4); + o.val[1] = vqrshrun_n_s16(odd, 4); + vst2_u8(out + i*2, o); +#endif + + // "previous" value for next iter + t1 = 3*in_near[i+7] + in_far[i+7]; + } + + t0 = t1; + t1 = 3*in_near[i] + in_far[i]; + out[i*2] = stbi__div16(3*t1 + t0 + 8); + + for (++i; i < w; ++i) { + t0 = t1; + t1 = 3*in_near[i]+in_far[i]; + out[i*2-1] = stbi__div16(3*t0 + t1 + 8); + out[i*2 ] = stbi__div16(3*t1 + t0 + 8); + } + out[w*2-1] = stbi__div4(t1+2); + + STBI_NOTUSED(hs); + + return out; +} +#endif + +static stbi_uc *stbi__resample_row_generic(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + // resample with nearest-neighbor + int i,j; + STBI_NOTUSED(in_far); + for (i=0; i < w; ++i) + for (j=0; j < hs; ++j) + out[i*hs+j] = in_near[i]; + return out; +} + +// this is a reduced-precision calculation of YCbCr-to-RGB introduced +// to make sure the code produces the same results in both SIMD and scalar +#define stbi__float2fixed(x) (((int) ((x) * 4096.0f + 0.5f)) << 8) +static void stbi__YCbCr_to_RGB_row(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step) +{ + int i; + for (i=0; i < count; ++i) { + int y_fixed = (y[i] << 20) + (1<<19); // rounding + int r,g,b; + int cr = pcr[i] - 128; + int cb = pcb[i] - 128; + r = y_fixed + cr* stbi__float2fixed(1.40200f); + g = y_fixed + (cr*-stbi__float2fixed(0.71414f)) + ((cb*-stbi__float2fixed(0.34414f)) & 0xffff0000); + b = y_fixed + cb* stbi__float2fixed(1.77200f); + r >>= 20; + g >>= 20; + b >>= 20; + if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; } + if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; } + if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; } + out[0] = (stbi_uc)r; + out[1] = (stbi_uc)g; + out[2] = (stbi_uc)b; + out[3] = 255; + out += step; + } +} + +#if defined(STBI_SSE2) || defined(STBI_NEON) +static void stbi__YCbCr_to_RGB_simd(stbi_uc *out, stbi_uc const *y, stbi_uc const *pcb, stbi_uc const *pcr, int count, int step) +{ + int i = 0; + +#ifdef STBI_SSE2 + // step == 3 is pretty ugly on the final interleave, and i'm not convinced + // it's useful in practice (you wouldn't use it for textures, for example). + // so just accelerate step == 4 case. + if (step == 4) { + // this is a fairly straightforward implementation and not super-optimized. + __m128i signflip = _mm_set1_epi8(-0x80); + __m128i cr_const0 = _mm_set1_epi16( (short) ( 1.40200f*4096.0f+0.5f)); + __m128i cr_const1 = _mm_set1_epi16( - (short) ( 0.71414f*4096.0f+0.5f)); + __m128i cb_const0 = _mm_set1_epi16( - (short) ( 0.34414f*4096.0f+0.5f)); + __m128i cb_const1 = _mm_set1_epi16( (short) ( 1.77200f*4096.0f+0.5f)); + __m128i y_bias = _mm_set1_epi8((char) (unsigned char) 128); + __m128i xw = _mm_set1_epi16(255); // alpha channel + + for (; i+7 < count; i += 8) { + // load + __m128i y_bytes = _mm_loadl_epi64((__m128i *) (y+i)); + __m128i cr_bytes = _mm_loadl_epi64((__m128i *) (pcr+i)); + __m128i cb_bytes = _mm_loadl_epi64((__m128i *) (pcb+i)); + __m128i cr_biased = _mm_xor_si128(cr_bytes, signflip); // -128 + __m128i cb_biased = _mm_xor_si128(cb_bytes, signflip); // -128 + + // unpack to short (and left-shift cr, cb by 8) + __m128i yw = _mm_unpacklo_epi8(y_bias, y_bytes); + __m128i crw = _mm_unpacklo_epi8(_mm_setzero_si128(), cr_biased); + __m128i cbw = _mm_unpacklo_epi8(_mm_setzero_si128(), cb_biased); + + // color transform + __m128i yws = _mm_srli_epi16(yw, 4); + __m128i cr0 = _mm_mulhi_epi16(cr_const0, crw); + __m128i cb0 = _mm_mulhi_epi16(cb_const0, cbw); + __m128i cb1 = _mm_mulhi_epi16(cbw, cb_const1); + __m128i cr1 = _mm_mulhi_epi16(crw, cr_const1); + __m128i rws = _mm_add_epi16(cr0, yws); + __m128i gwt = _mm_add_epi16(cb0, yws); + __m128i bws = _mm_add_epi16(yws, cb1); + __m128i gws = _mm_add_epi16(gwt, cr1); + + // descale + __m128i rw = _mm_srai_epi16(rws, 4); + __m128i bw = _mm_srai_epi16(bws, 4); + __m128i gw = _mm_srai_epi16(gws, 4); + + // back to byte, set up for transpose + __m128i brb = _mm_packus_epi16(rw, bw); + __m128i gxb = _mm_packus_epi16(gw, xw); + + // transpose to interleave channels + __m128i t0 = _mm_unpacklo_epi8(brb, gxb); + __m128i t1 = _mm_unpackhi_epi8(brb, gxb); + __m128i o0 = _mm_unpacklo_epi16(t0, t1); + __m128i o1 = _mm_unpackhi_epi16(t0, t1); + + // store + _mm_storeu_si128((__m128i *) (out + 0), o0); + _mm_storeu_si128((__m128i *) (out + 16), o1); + out += 32; + } + } +#endif + +#ifdef STBI_NEON + // in this version, step=3 support would be easy to add. but is there demand? + if (step == 4) { + // this is a fairly straightforward implementation and not super-optimized. + uint8x8_t signflip = vdup_n_u8(0x80); + int16x8_t cr_const0 = vdupq_n_s16( (short) ( 1.40200f*4096.0f+0.5f)); + int16x8_t cr_const1 = vdupq_n_s16( - (short) ( 0.71414f*4096.0f+0.5f)); + int16x8_t cb_const0 = vdupq_n_s16( - (short) ( 0.34414f*4096.0f+0.5f)); + int16x8_t cb_const1 = vdupq_n_s16( (short) ( 1.77200f*4096.0f+0.5f)); + + for (; i+7 < count; i += 8) { + // load + uint8x8_t y_bytes = vld1_u8(y + i); + uint8x8_t cr_bytes = vld1_u8(pcr + i); + uint8x8_t cb_bytes = vld1_u8(pcb + i); + int8x8_t cr_biased = vreinterpret_s8_u8(vsub_u8(cr_bytes, signflip)); + int8x8_t cb_biased = vreinterpret_s8_u8(vsub_u8(cb_bytes, signflip)); + + // expand to s16 + int16x8_t yws = vreinterpretq_s16_u16(vshll_n_u8(y_bytes, 4)); + int16x8_t crw = vshll_n_s8(cr_biased, 7); + int16x8_t cbw = vshll_n_s8(cb_biased, 7); + + // color transform + int16x8_t cr0 = vqdmulhq_s16(crw, cr_const0); + int16x8_t cb0 = vqdmulhq_s16(cbw, cb_const0); + int16x8_t cr1 = vqdmulhq_s16(crw, cr_const1); + int16x8_t cb1 = vqdmulhq_s16(cbw, cb_const1); + int16x8_t rws = vaddq_s16(yws, cr0); + int16x8_t gws = vaddq_s16(vaddq_s16(yws, cb0), cr1); + int16x8_t bws = vaddq_s16(yws, cb1); + + // undo scaling, round, convert to byte + uint8x8x4_t o; + o.val[0] = vqrshrun_n_s16(rws, 4); + o.val[1] = vqrshrun_n_s16(gws, 4); + o.val[2] = vqrshrun_n_s16(bws, 4); + o.val[3] = vdup_n_u8(255); + + // store, interleaving r/g/b/a + vst4_u8(out, o); + out += 8*4; + } + } +#endif + + for (; i < count; ++i) { + int y_fixed = (y[i] << 20) + (1<<19); // rounding + int r,g,b; + int cr = pcr[i] - 128; + int cb = pcb[i] - 128; + r = y_fixed + cr* stbi__float2fixed(1.40200f); + g = y_fixed + cr*-stbi__float2fixed(0.71414f) + ((cb*-stbi__float2fixed(0.34414f)) & 0xffff0000); + b = y_fixed + cb* stbi__float2fixed(1.77200f); + r >>= 20; + g >>= 20; + b >>= 20; + if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; } + if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; } + if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; } + out[0] = (stbi_uc)r; + out[1] = (stbi_uc)g; + out[2] = (stbi_uc)b; + out[3] = 255; + out += step; + } +} +#endif + +// set up the kernels +static void stbi__setup_jpeg(stbi__jpeg *j) +{ + j->idct_block_kernel = stbi__idct_block; + j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_row; + j->resample_row_hv_2_kernel = stbi__resample_row_hv_2; + +#ifdef STBI_SSE2 + if (stbi__sse2_available()) { + j->idct_block_kernel = stbi__idct_simd; + j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_simd; + j->resample_row_hv_2_kernel = stbi__resample_row_hv_2_simd; + } +#endif + +#ifdef STBI_NEON + j->idct_block_kernel = stbi__idct_simd; + j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_simd; + j->resample_row_hv_2_kernel = stbi__resample_row_hv_2_simd; +#endif +} + +// clean up the temporary component buffers +static void stbi__cleanup_jpeg(stbi__jpeg *j) +{ + stbi__free_jpeg_components(j, j->s->img_n, 0); +} + +typedef struct +{ + resample_row_func resample; + stbi_uc *line0,*line1; + int hs,vs; // expansion factor in each axis + int w_lores; // horizontal pixels pre-expansion + int ystep; // how far through vertical expansion we are + int ypos; // which pre-expansion row we're on +} stbi__resample; + +// fast 0..255 * 0..255 => 0..255 rounded multiplication +static stbi_uc stbi__blinn_8x8(stbi_uc x, stbi_uc y) +{ + unsigned int t = x*y + 128; + return (stbi_uc) ((t + (t >>8)) >> 8); +} + +static stbi_uc *load_jpeg_image(stbi__jpeg *z, int *out_x, int *out_y, int *comp, int req_comp) +{ + int n, decode_n, is_rgb; + z->s->img_n = 0; // make stbi__cleanup_jpeg safe + + // validate req_comp + if (req_comp < 0 || req_comp > 4) return stbi__errpuc("bad req_comp", "Internal error"); + + // load a jpeg image from whichever source, but leave in YCbCr format + if (!stbi__decode_jpeg_image(z)) { stbi__cleanup_jpeg(z); return NULL; } + + // determine actual number of components to generate + n = req_comp ? req_comp : z->s->img_n >= 3 ? 3 : 1; + + is_rgb = z->s->img_n == 3 && (z->rgb == 3 || (z->app14_color_transform == 0 && !z->jfif)); + + if (z->s->img_n == 3 && n < 3 && !is_rgb) + decode_n = 1; + else + decode_n = z->s->img_n; + + // nothing to do if no components requested; check this now to avoid + // accessing uninitialized coutput[0] later + if (decode_n <= 0) { stbi__cleanup_jpeg(z); return NULL; } + + // resample and color-convert + { + int k; + unsigned int i,j; + stbi_uc *output; + stbi_uc *coutput[4] = { NULL, NULL, NULL, NULL }; + + stbi__resample res_comp[4]; + + for (k=0; k < decode_n; ++k) { + stbi__resample *r = &res_comp[k]; + + // allocate line buffer big enough for upsampling off the edges + // with upsample factor of 4 + z->img_comp[k].linebuf = (stbi_uc *) stbi__malloc(z->s->img_x + 3); + if (!z->img_comp[k].linebuf) { stbi__cleanup_jpeg(z); return stbi__errpuc("outofmem", "Out of memory"); } + + r->hs = z->img_h_max / z->img_comp[k].h; + r->vs = z->img_v_max / z->img_comp[k].v; + r->ystep = r->vs >> 1; + r->w_lores = (z->s->img_x + r->hs-1) / r->hs; + r->ypos = 0; + r->line0 = r->line1 = z->img_comp[k].data; + + if (r->hs == 1 && r->vs == 1) r->resample = resample_row_1; + else if (r->hs == 1 && r->vs == 2) r->resample = stbi__resample_row_v_2; + else if (r->hs == 2 && r->vs == 1) r->resample = stbi__resample_row_h_2; + else if (r->hs == 2 && r->vs == 2) r->resample = z->resample_row_hv_2_kernel; + else r->resample = stbi__resample_row_generic; + } + + // can't error after this so, this is safe + output = (stbi_uc *) stbi__malloc_mad3(n, z->s->img_x, z->s->img_y, 1); + if (!output) { stbi__cleanup_jpeg(z); return stbi__errpuc("outofmem", "Out of memory"); } + + // now go ahead and resample + for (j=0; j < z->s->img_y; ++j) { + stbi_uc *out = output + n * z->s->img_x * j; + for (k=0; k < decode_n; ++k) { + stbi__resample *r = &res_comp[k]; + int y_bot = r->ystep >= (r->vs >> 1); + coutput[k] = r->resample(z->img_comp[k].linebuf, + y_bot ? r->line1 : r->line0, + y_bot ? r->line0 : r->line1, + r->w_lores, r->hs); + if (++r->ystep >= r->vs) { + r->ystep = 0; + r->line0 = r->line1; + if (++r->ypos < z->img_comp[k].y) + r->line1 += z->img_comp[k].w2; + } + } + if (n >= 3) { + stbi_uc *y = coutput[0]; + if (z->s->img_n == 3) { + if (is_rgb) { + for (i=0; i < z->s->img_x; ++i) { + out[0] = y[i]; + out[1] = coutput[1][i]; + out[2] = coutput[2][i]; + out[3] = 255; + out += n; + } + } else { + z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n); + } + } else if (z->s->img_n == 4) { + if (z->app14_color_transform == 0) { // CMYK + for (i=0; i < z->s->img_x; ++i) { + stbi_uc m = coutput[3][i]; + out[0] = stbi__blinn_8x8(coutput[0][i], m); + out[1] = stbi__blinn_8x8(coutput[1][i], m); + out[2] = stbi__blinn_8x8(coutput[2][i], m); + out[3] = 255; + out += n; + } + } else if (z->app14_color_transform == 2) { // YCCK + z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n); + for (i=0; i < z->s->img_x; ++i) { + stbi_uc m = coutput[3][i]; + out[0] = stbi__blinn_8x8(255 - out[0], m); + out[1] = stbi__blinn_8x8(255 - out[1], m); + out[2] = stbi__blinn_8x8(255 - out[2], m); + out += n; + } + } else { // YCbCr + alpha? Ignore the fourth channel for now + z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n); + } + } else + for (i=0; i < z->s->img_x; ++i) { + out[0] = out[1] = out[2] = y[i]; + out[3] = 255; // not used if n==3 + out += n; + } + } else { + if (is_rgb) { + if (n == 1) + for (i=0; i < z->s->img_x; ++i) + *out++ = stbi__compute_y(coutput[0][i], coutput[1][i], coutput[2][i]); + else { + for (i=0; i < z->s->img_x; ++i, out += 2) { + out[0] = stbi__compute_y(coutput[0][i], coutput[1][i], coutput[2][i]); + out[1] = 255; + } + } + } else if (z->s->img_n == 4 && z->app14_color_transform == 0) { + for (i=0; i < z->s->img_x; ++i) { + stbi_uc m = coutput[3][i]; + stbi_uc r = stbi__blinn_8x8(coutput[0][i], m); + stbi_uc g = stbi__blinn_8x8(coutput[1][i], m); + stbi_uc b = stbi__blinn_8x8(coutput[2][i], m); + out[0] = stbi__compute_y(r, g, b); + out[1] = 255; + out += n; + } + } else if (z->s->img_n == 4 && z->app14_color_transform == 2) { + for (i=0; i < z->s->img_x; ++i) { + out[0] = stbi__blinn_8x8(255 - coutput[0][i], coutput[3][i]); + out[1] = 255; + out += n; + } + } else { + stbi_uc *y = coutput[0]; + if (n == 1) + for (i=0; i < z->s->img_x; ++i) out[i] = y[i]; + else + for (i=0; i < z->s->img_x; ++i) { *out++ = y[i]; *out++ = 255; } + } + } + } + stbi__cleanup_jpeg(z); + *out_x = z->s->img_x; + *out_y = z->s->img_y; + if (comp) *comp = z->s->img_n >= 3 ? 3 : 1; // report original components, not output + return output; + } +} + +static void *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + unsigned char* result; + stbi__jpeg* j = (stbi__jpeg*) stbi__malloc(sizeof(stbi__jpeg)); + if (!j) return stbi__errpuc("outofmem", "Out of memory"); + memset(j, 0, sizeof(stbi__jpeg)); + STBI_NOTUSED(ri); + j->s = s; + stbi__setup_jpeg(j); + result = load_jpeg_image(j, x,y,comp,req_comp); + STBI_FREE(j); + return result; +} + +static int stbi__jpeg_test(stbi__context *s) +{ + int r; + stbi__jpeg* j = (stbi__jpeg*)stbi__malloc(sizeof(stbi__jpeg)); + if (!j) return stbi__err("outofmem", "Out of memory"); + memset(j, 0, sizeof(stbi__jpeg)); + j->s = s; + stbi__setup_jpeg(j); + r = stbi__decode_jpeg_header(j, STBI__SCAN_type); + stbi__rewind(s); + STBI_FREE(j); + return r; +} + +static int stbi__jpeg_info_raw(stbi__jpeg *j, int *x, int *y, int *comp) +{ + if (!stbi__decode_jpeg_header(j, STBI__SCAN_header)) { + stbi__rewind( j->s ); + return 0; + } + if (x) *x = j->s->img_x; + if (y) *y = j->s->img_y; + if (comp) *comp = j->s->img_n >= 3 ? 3 : 1; + return 1; +} + +static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp) +{ + int result; + stbi__jpeg* j = (stbi__jpeg*) (stbi__malloc(sizeof(stbi__jpeg))); + if (!j) return stbi__err("outofmem", "Out of memory"); + memset(j, 0, sizeof(stbi__jpeg)); + j->s = s; + result = stbi__jpeg_info_raw(j, x, y, comp); + STBI_FREE(j); + return result; +} +#endif + +// public domain zlib decode v0.2 Sean Barrett 2006-11-18 +// simple implementation +// - all input must be provided in an upfront buffer +// - all output is written to a single output buffer (can malloc/realloc) +// performance +// - fast huffman + +#ifndef STBI_NO_ZLIB + +// fast-way is faster to check than jpeg huffman, but slow way is slower +#define STBI__ZFAST_BITS 9 // accelerate all cases in default tables +#define STBI__ZFAST_MASK ((1 << STBI__ZFAST_BITS) - 1) +#define STBI__ZNSYMS 288 // number of symbols in literal/length alphabet + +// zlib-style huffman encoding +// (jpegs packs from left, zlib from right, so can't share code) +typedef struct +{ + stbi__uint16 fast[1 << STBI__ZFAST_BITS]; + stbi__uint16 firstcode[16]; + int maxcode[17]; + stbi__uint16 firstsymbol[16]; + stbi_uc size[STBI__ZNSYMS]; + stbi__uint16 value[STBI__ZNSYMS]; +} stbi__zhuffman; + +stbi_inline static int stbi__bitreverse16(int n) +{ + n = ((n & 0xAAAA) >> 1) | ((n & 0x5555) << 1); + n = ((n & 0xCCCC) >> 2) | ((n & 0x3333) << 2); + n = ((n & 0xF0F0) >> 4) | ((n & 0x0F0F) << 4); + n = ((n & 0xFF00) >> 8) | ((n & 0x00FF) << 8); + return n; +} + +stbi_inline static int stbi__bit_reverse(int v, int bits) +{ + STBI_ASSERT(bits <= 16); + // to bit reverse n bits, reverse 16 and shift + // e.g. 11 bits, bit reverse and shift away 5 + return stbi__bitreverse16(v) >> (16-bits); +} + +static int stbi__zbuild_huffman(stbi__zhuffman *z, const stbi_uc *sizelist, int num) +{ + int i,k=0; + int code, next_code[16], sizes[17]; + + // DEFLATE spec for generating codes + memset(sizes, 0, sizeof(sizes)); + memset(z->fast, 0, sizeof(z->fast)); + for (i=0; i < num; ++i) + ++sizes[sizelist[i]]; + sizes[0] = 0; + for (i=1; i < 16; ++i) + if (sizes[i] > (1 << i)) + return stbi__err("bad sizes", "Corrupt PNG"); + code = 0; + for (i=1; i < 16; ++i) { + next_code[i] = code; + z->firstcode[i] = (stbi__uint16) code; + z->firstsymbol[i] = (stbi__uint16) k; + code = (code + sizes[i]); + if (sizes[i]) + if (code-1 >= (1 << i)) return stbi__err("bad codelengths","Corrupt PNG"); + z->maxcode[i] = code << (16-i); // preshift for inner loop + code <<= 1; + k += sizes[i]; + } + z->maxcode[16] = 0x10000; // sentinel + for (i=0; i < num; ++i) { + int s = sizelist[i]; + if (s) { + int c = next_code[s] - z->firstcode[s] + z->firstsymbol[s]; + stbi__uint16 fastv = (stbi__uint16) ((s << 9) | i); + z->size [c] = (stbi_uc ) s; + z->value[c] = (stbi__uint16) i; + if (s <= STBI__ZFAST_BITS) { + int j = stbi__bit_reverse(next_code[s],s); + while (j < (1 << STBI__ZFAST_BITS)) { + z->fast[j] = fastv; + j += (1 << s); + } + } + ++next_code[s]; + } + } + return 1; +} + +// zlib-from-memory implementation for PNG reading +// because PNG allows splitting the zlib stream arbitrarily, +// and it's annoying structurally to have PNG call ZLIB call PNG, +// we require PNG read all the IDATs and combine them into a single +// memory buffer + +typedef struct +{ + stbi_uc *zbuffer, *zbuffer_end; + int num_bits; + int hit_zeof_once; + stbi__uint32 code_buffer; + + char *zout; + char *zout_start; + char *zout_end; + int z_expandable; + + stbi__zhuffman z_length, z_distance; +} stbi__zbuf; + +stbi_inline static int stbi__zeof(stbi__zbuf *z) +{ + return (z->zbuffer >= z->zbuffer_end); +} + +stbi_inline static stbi_uc stbi__zget8(stbi__zbuf *z) +{ + return stbi__zeof(z) ? 0 : *z->zbuffer++; +} + +static void stbi__fill_bits(stbi__zbuf *z) +{ + do { + if (z->code_buffer >= (1U << z->num_bits)) { + z->zbuffer = z->zbuffer_end; /* treat this as EOF so we fail. */ + return; + } + z->code_buffer |= (unsigned int) stbi__zget8(z) << z->num_bits; + z->num_bits += 8; + } while (z->num_bits <= 24); +} + +stbi_inline static unsigned int stbi__zreceive(stbi__zbuf *z, int n) +{ + unsigned int k; + if (z->num_bits < n) stbi__fill_bits(z); + k = z->code_buffer & ((1 << n) - 1); + z->code_buffer >>= n; + z->num_bits -= n; + return k; +} + +static int stbi__zhuffman_decode_slowpath(stbi__zbuf *a, stbi__zhuffman *z) +{ + int b,s,k; + // not resolved by fast table, so compute it the slow way + // use jpeg approach, which requires MSbits at top + k = stbi__bit_reverse(a->code_buffer, 16); + for (s=STBI__ZFAST_BITS+1; ; ++s) + if (k < z->maxcode[s]) + break; + if (s >= 16) return -1; // invalid code! + // code size is s, so: + b = (k >> (16-s)) - z->firstcode[s] + z->firstsymbol[s]; + if (b >= STBI__ZNSYMS) return -1; // some data was corrupt somewhere! + if (z->size[b] != s) return -1; // was originally an assert, but report failure instead. + a->code_buffer >>= s; + a->num_bits -= s; + return z->value[b]; +} + +stbi_inline static int stbi__zhuffman_decode(stbi__zbuf *a, stbi__zhuffman *z) +{ + int b,s; + if (a->num_bits < 16) { + if (stbi__zeof(a)) { + if (!a->hit_zeof_once) { + // This is the first time we hit eof, insert 16 extra padding btis + // to allow us to keep going; if we actually consume any of them + // though, that is invalid data. This is caught later. + a->hit_zeof_once = 1; + a->num_bits += 16; // add 16 implicit zero bits + } else { + // We already inserted our extra 16 padding bits and are again + // out, this stream is actually prematurely terminated. + return -1; + } + } else { + stbi__fill_bits(a); + } + } + b = z->fast[a->code_buffer & STBI__ZFAST_MASK]; + if (b) { + s = b >> 9; + a->code_buffer >>= s; + a->num_bits -= s; + return b & 511; + } + return stbi__zhuffman_decode_slowpath(a, z); +} + +static int stbi__zexpand(stbi__zbuf *z, char *zout, int n) // need to make room for n bytes +{ + char *q; + unsigned int cur, limit, old_limit; + z->zout = zout; + if (!z->z_expandable) return stbi__err("output buffer limit","Corrupt PNG"); + cur = (unsigned int) (z->zout - z->zout_start); + limit = old_limit = (unsigned) (z->zout_end - z->zout_start); + if (UINT_MAX - cur < (unsigned) n) return stbi__err("outofmem", "Out of memory"); + while (cur + n > limit) { + if(limit > UINT_MAX / 2) return stbi__err("outofmem", "Out of memory"); + limit *= 2; + } + q = (char *) STBI_REALLOC_SIZED(z->zout_start, old_limit, limit); + STBI_NOTUSED(old_limit); + if (q == NULL) return stbi__err("outofmem", "Out of memory"); + z->zout_start = q; + z->zout = q + cur; + z->zout_end = q + limit; + return 1; +} + +static const int stbi__zlength_base[31] = { + 3,4,5,6,7,8,9,10,11,13, + 15,17,19,23,27,31,35,43,51,59, + 67,83,99,115,131,163,195,227,258,0,0 }; + +static const int stbi__zlength_extra[31]= +{ 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0 }; + +static const int stbi__zdist_base[32] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193, +257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0}; + +static const int stbi__zdist_extra[32] = +{ 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; + +static int stbi__parse_huffman_block(stbi__zbuf *a) +{ + char *zout = a->zout; + for(;;) { + int z = stbi__zhuffman_decode(a, &a->z_length); + if (z < 256) { + if (z < 0) return stbi__err("bad huffman code","Corrupt PNG"); // error in huffman codes + if (zout >= a->zout_end) { + if (!stbi__zexpand(a, zout, 1)) return 0; + zout = a->zout; + } + *zout++ = (char) z; + } else { + stbi_uc *p; + int len,dist; + if (z == 256) { + a->zout = zout; + if (a->hit_zeof_once && a->num_bits < 16) { + // The first time we hit zeof, we inserted 16 extra zero bits into our bit + // buffer so the decoder can just do its speculative decoding. But if we + // actually consumed any of those bits (which is the case when num_bits < 16), + // the stream actually read past the end so it is malformed. + return stbi__err("unexpected end","Corrupt PNG"); + } + return 1; + } + if (z >= 286) return stbi__err("bad huffman code","Corrupt PNG"); // per DEFLATE, length codes 286 and 287 must not appear in compressed data + z -= 257; + len = stbi__zlength_base[z]; + if (stbi__zlength_extra[z]) len += stbi__zreceive(a, stbi__zlength_extra[z]); + z = stbi__zhuffman_decode(a, &a->z_distance); + if (z < 0 || z >= 30) return stbi__err("bad huffman code","Corrupt PNG"); // per DEFLATE, distance codes 30 and 31 must not appear in compressed data + dist = stbi__zdist_base[z]; + if (stbi__zdist_extra[z]) dist += stbi__zreceive(a, stbi__zdist_extra[z]); + if (zout - a->zout_start < dist) return stbi__err("bad dist","Corrupt PNG"); + if (len > a->zout_end - zout) { + if (!stbi__zexpand(a, zout, len)) return 0; + zout = a->zout; + } + p = (stbi_uc *) (zout - dist); + if (dist == 1) { // run of one byte; common in images. + stbi_uc v = *p; + if (len) { do *zout++ = v; while (--len); } + } else { + if (len) { do *zout++ = *p++; while (--len); } + } + } + } +} + +static int stbi__compute_huffman_codes(stbi__zbuf *a) +{ + static const stbi_uc length_dezigzag[19] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 }; + stbi__zhuffman z_codelength; + stbi_uc lencodes[286+32+137];//padding for maximum single op + stbi_uc codelength_sizes[19]; + int i,n; + + int hlit = stbi__zreceive(a,5) + 257; + int hdist = stbi__zreceive(a,5) + 1; + int hclen = stbi__zreceive(a,4) + 4; + int ntot = hlit + hdist; + + memset(codelength_sizes, 0, sizeof(codelength_sizes)); + for (i=0; i < hclen; ++i) { + int s = stbi__zreceive(a,3); + codelength_sizes[length_dezigzag[i]] = (stbi_uc) s; + } + if (!stbi__zbuild_huffman(&z_codelength, codelength_sizes, 19)) return 0; + + n = 0; + while (n < ntot) { + int c = stbi__zhuffman_decode(a, &z_codelength); + if (c < 0 || c >= 19) return stbi__err("bad codelengths", "Corrupt PNG"); + if (c < 16) + lencodes[n++] = (stbi_uc) c; + else { + stbi_uc fill = 0; + if (c == 16) { + c = stbi__zreceive(a,2)+3; + if (n == 0) return stbi__err("bad codelengths", "Corrupt PNG"); + fill = lencodes[n-1]; + } else if (c == 17) { + c = stbi__zreceive(a,3)+3; + } else if (c == 18) { + c = stbi__zreceive(a,7)+11; + } else { + return stbi__err("bad codelengths", "Corrupt PNG"); + } + if (ntot - n < c) return stbi__err("bad codelengths", "Corrupt PNG"); + memset(lencodes+n, fill, c); + n += c; + } + } + if (n != ntot) return stbi__err("bad codelengths","Corrupt PNG"); + if (!stbi__zbuild_huffman(&a->z_length, lencodes, hlit)) return 0; + if (!stbi__zbuild_huffman(&a->z_distance, lencodes+hlit, hdist)) return 0; + return 1; +} + +static int stbi__parse_uncompressed_block(stbi__zbuf *a) +{ + stbi_uc header[4]; + int len,nlen,k; + if (a->num_bits & 7) + stbi__zreceive(a, a->num_bits & 7); // discard + // drain the bit-packed data into header + k = 0; + while (a->num_bits > 0) { + header[k++] = (stbi_uc) (a->code_buffer & 255); // suppress MSVC run-time check + a->code_buffer >>= 8; + a->num_bits -= 8; + } + if (a->num_bits < 0) return stbi__err("zlib corrupt","Corrupt PNG"); + // now fill header the normal way + while (k < 4) + header[k++] = stbi__zget8(a); + len = header[1] * 256 + header[0]; + nlen = header[3] * 256 + header[2]; + if (nlen != (len ^ 0xffff)) return stbi__err("zlib corrupt","Corrupt PNG"); + if (a->zbuffer + len > a->zbuffer_end) return stbi__err("read past buffer","Corrupt PNG"); + if (a->zout + len > a->zout_end) + if (!stbi__zexpand(a, a->zout, len)) return 0; + memcpy(a->zout, a->zbuffer, len); + a->zbuffer += len; + a->zout += len; + return 1; +} + +static int stbi__parse_zlib_header(stbi__zbuf *a) +{ + int cmf = stbi__zget8(a); + int cm = cmf & 15; + /* int cinfo = cmf >> 4; */ + int flg = stbi__zget8(a); + if (stbi__zeof(a)) return stbi__err("bad zlib header","Corrupt PNG"); // zlib spec + if ((cmf*256+flg) % 31 != 0) return stbi__err("bad zlib header","Corrupt PNG"); // zlib spec + if (flg & 32) return stbi__err("no preset dict","Corrupt PNG"); // preset dictionary not allowed in png + if (cm != 8) return stbi__err("bad compression","Corrupt PNG"); // DEFLATE required for png + // window = 1 << (8 + cinfo)... but who cares, we fully buffer output + return 1; +} + +static const stbi_uc stbi__zdefault_length[STBI__ZNSYMS] = +{ + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,8,8,8,8,8,8,8,8 +}; +static const stbi_uc stbi__zdefault_distance[32] = +{ + 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5 +}; +/* +Init algorithm: +{ + int i; // use <= to match clearly with spec + for (i=0; i <= 143; ++i) stbi__zdefault_length[i] = 8; + for ( ; i <= 255; ++i) stbi__zdefault_length[i] = 9; + for ( ; i <= 279; ++i) stbi__zdefault_length[i] = 7; + for ( ; i <= 287; ++i) stbi__zdefault_length[i] = 8; + + for (i=0; i <= 31; ++i) stbi__zdefault_distance[i] = 5; +} +*/ + +static int stbi__parse_zlib(stbi__zbuf *a, int parse_header) +{ + int final, type; + if (parse_header) + if (!stbi__parse_zlib_header(a)) return 0; + a->num_bits = 0; + a->code_buffer = 0; + a->hit_zeof_once = 0; + do { + final = stbi__zreceive(a,1); + type = stbi__zreceive(a,2); + if (type == 0) { + if (!stbi__parse_uncompressed_block(a)) return 0; + } else if (type == 3) { + return 0; + } else { + if (type == 1) { + // use fixed code lengths + if (!stbi__zbuild_huffman(&a->z_length , stbi__zdefault_length , STBI__ZNSYMS)) return 0; + if (!stbi__zbuild_huffman(&a->z_distance, stbi__zdefault_distance, 32)) return 0; + } else { + if (!stbi__compute_huffman_codes(a)) return 0; + } + if (!stbi__parse_huffman_block(a)) return 0; + } + } while (!final); + return 1; +} + +static int stbi__do_zlib(stbi__zbuf *a, char *obuf, int olen, int exp, int parse_header) +{ + a->zout_start = obuf; + a->zout = obuf; + a->zout_end = obuf + olen; + a->z_expandable = exp; + + return stbi__parse_zlib(a, parse_header); +} + +STBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen) +{ + stbi__zbuf a; + char *p = (char *) stbi__malloc(initial_size); + if (p == NULL) return NULL; + a.zbuffer = (stbi_uc *) buffer; + a.zbuffer_end = (stbi_uc *) buffer + len; + if (stbi__do_zlib(&a, p, initial_size, 1, 1)) { + if (outlen) *outlen = (int) (a.zout - a.zout_start); + return a.zout_start; + } else { + STBI_FREE(a.zout_start); + return NULL; + } +} + +STBIDEF char *stbi_zlib_decode_malloc(char const *buffer, int len, int *outlen) +{ + return stbi_zlib_decode_malloc_guesssize(buffer, len, 16384, outlen); +} + +STBIDEF char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header) +{ + stbi__zbuf a; + char *p = (char *) stbi__malloc(initial_size); + if (p == NULL) return NULL; + a.zbuffer = (stbi_uc *) buffer; + a.zbuffer_end = (stbi_uc *) buffer + len; + if (stbi__do_zlib(&a, p, initial_size, 1, parse_header)) { + if (outlen) *outlen = (int) (a.zout - a.zout_start); + return a.zout_start; + } else { + STBI_FREE(a.zout_start); + return NULL; + } +} + +STBIDEF int stbi_zlib_decode_buffer(char *obuffer, int olen, char const *ibuffer, int ilen) +{ + stbi__zbuf a; + a.zbuffer = (stbi_uc *) ibuffer; + a.zbuffer_end = (stbi_uc *) ibuffer + ilen; + if (stbi__do_zlib(&a, obuffer, olen, 0, 1)) + return (int) (a.zout - a.zout_start); + else + return -1; +} + +STBIDEF char *stbi_zlib_decode_noheader_malloc(char const *buffer, int len, int *outlen) +{ + stbi__zbuf a; + char *p = (char *) stbi__malloc(16384); + if (p == NULL) return NULL; + a.zbuffer = (stbi_uc *) buffer; + a.zbuffer_end = (stbi_uc *) buffer+len; + if (stbi__do_zlib(&a, p, 16384, 1, 0)) { + if (outlen) *outlen = (int) (a.zout - a.zout_start); + return a.zout_start; + } else { + STBI_FREE(a.zout_start); + return NULL; + } +} + +STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen) +{ + stbi__zbuf a; + a.zbuffer = (stbi_uc *) ibuffer; + a.zbuffer_end = (stbi_uc *) ibuffer + ilen; + if (stbi__do_zlib(&a, obuffer, olen, 0, 0)) + return (int) (a.zout - a.zout_start); + else + return -1; +} +#endif + +// public domain "baseline" PNG decoder v0.10 Sean Barrett 2006-11-18 +// simple implementation +// - only 8-bit samples +// - no CRC checking +// - allocates lots of intermediate memory +// - avoids problem of streaming data between subsystems +// - avoids explicit window management +// performance +// - uses stb_zlib, a PD zlib implementation with fast huffman decoding + +#ifndef STBI_NO_PNG +typedef struct +{ + stbi__uint32 length; + stbi__uint32 type; +} stbi__pngchunk; + +static stbi__pngchunk stbi__get_chunk_header(stbi__context *s) +{ + stbi__pngchunk c; + c.length = stbi__get32be(s); + c.type = stbi__get32be(s); + return c; +} + +static int stbi__check_png_header(stbi__context *s) +{ + static const stbi_uc png_sig[8] = { 137,80,78,71,13,10,26,10 }; + int i; + for (i=0; i < 8; ++i) + if (stbi__get8(s) != png_sig[i]) return stbi__err("bad png sig","Not a PNG"); + return 1; +} + +typedef struct +{ + stbi__context *s; + stbi_uc *idata, *expanded, *out; + int depth; +} stbi__png; + + +enum { + STBI__F_none=0, + STBI__F_sub=1, + STBI__F_up=2, + STBI__F_avg=3, + STBI__F_paeth=4, + // synthetic filter used for first scanline to avoid needing a dummy row of 0s + STBI__F_avg_first +}; + +static stbi_uc first_row_filter[5] = +{ + STBI__F_none, + STBI__F_sub, + STBI__F_none, + STBI__F_avg_first, + STBI__F_sub // Paeth with b=c=0 turns out to be equivalent to sub +}; + +static int stbi__paeth(int a, int b, int c) +{ + // This formulation looks very different from the reference in the PNG spec, but is + // actually equivalent and has favorable data dependencies and admits straightforward + // generation of branch-free code, which helps performance significantly. + int thresh = c*3 - (a + b); + int lo = a < b ? a : b; + int hi = a < b ? b : a; + int t0 = (hi <= thresh) ? lo : c; + int t1 = (thresh <= lo) ? hi : t0; + return t1; +} + +static const stbi_uc stbi__depth_scale_table[9] = { 0, 0xff, 0x55, 0, 0x11, 0,0,0, 0x01 }; + +// adds an extra all-255 alpha channel +// dest == src is legal +// img_n must be 1 or 3 +static void stbi__create_png_alpha_expand8(stbi_uc *dest, stbi_uc *src, stbi__uint32 x, int img_n) +{ + int i; + // must process data backwards since we allow dest==src + if (img_n == 1) { + for (i=x-1; i >= 0; --i) { + dest[i*2+1] = 255; + dest[i*2+0] = src[i]; + } + } else { + STBI_ASSERT(img_n == 3); + for (i=x-1; i >= 0; --i) { + dest[i*4+3] = 255; + dest[i*4+2] = src[i*3+2]; + dest[i*4+1] = src[i*3+1]; + dest[i*4+0] = src[i*3+0]; + } + } +} + +// create the png data from post-deflated data +static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 raw_len, int out_n, stbi__uint32 x, stbi__uint32 y, int depth, int color) +{ + int bytes = (depth == 16 ? 2 : 1); + stbi__context *s = a->s; + stbi__uint32 i,j,stride = x*out_n*bytes; + stbi__uint32 img_len, img_width_bytes; + stbi_uc *filter_buf; + int all_ok = 1; + int k; + int img_n = s->img_n; // copy it into a local for later + + int output_bytes = out_n*bytes; + int filter_bytes = img_n*bytes; + int width = x; + + STBI_ASSERT(out_n == s->img_n || out_n == s->img_n+1); + a->out = (stbi_uc *) stbi__malloc_mad3(x, y, output_bytes, 0); // extra bytes to write off the end into + if (!a->out) return stbi__err("outofmem", "Out of memory"); + + // note: error exits here don't need to clean up a->out individually, + // stbi__do_png always does on error. + if (!stbi__mad3sizes_valid(img_n, x, depth, 7)) return stbi__err("too large", "Corrupt PNG"); + img_width_bytes = (((img_n * x * depth) + 7) >> 3); + if (!stbi__mad2sizes_valid(img_width_bytes, y, img_width_bytes)) return stbi__err("too large", "Corrupt PNG"); + img_len = (img_width_bytes + 1) * y; + + // we used to check for exact match between raw_len and img_len on non-interlaced PNGs, + // but issue #276 reported a PNG in the wild that had extra data at the end (all zeros), + // so just check for raw_len < img_len always. + if (raw_len < img_len) return stbi__err("not enough pixels","Corrupt PNG"); + + // Allocate two scan lines worth of filter workspace buffer. + filter_buf = (stbi_uc *) stbi__malloc_mad2(img_width_bytes, 2, 0); + if (!filter_buf) return stbi__err("outofmem", "Out of memory"); + + // Filtering for low-bit-depth images + if (depth < 8) { + filter_bytes = 1; + width = img_width_bytes; + } + + for (j=0; j < y; ++j) { + // cur/prior filter buffers alternate + stbi_uc *cur = filter_buf + (j & 1)*img_width_bytes; + stbi_uc *prior = filter_buf + (~j & 1)*img_width_bytes; + stbi_uc *dest = a->out + stride*j; + int nk = width * filter_bytes; + int filter = *raw++; + + // check filter type + if (filter > 4) { + all_ok = stbi__err("invalid filter","Corrupt PNG"); + break; + } + + // if first row, use special filter that doesn't sample previous row + if (j == 0) filter = first_row_filter[filter]; + + // perform actual filtering + switch (filter) { + case STBI__F_none: + memcpy(cur, raw, nk); + break; + case STBI__F_sub: + memcpy(cur, raw, filter_bytes); + for (k = filter_bytes; k < nk; ++k) + cur[k] = STBI__BYTECAST(raw[k] + cur[k-filter_bytes]); + break; + case STBI__F_up: + for (k = 0; k < nk; ++k) + cur[k] = STBI__BYTECAST(raw[k] + prior[k]); + break; + case STBI__F_avg: + for (k = 0; k < filter_bytes; ++k) + cur[k] = STBI__BYTECAST(raw[k] + (prior[k]>>1)); + for (k = filter_bytes; k < nk; ++k) + cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k-filter_bytes])>>1)); + break; + case STBI__F_paeth: + for (k = 0; k < filter_bytes; ++k) + cur[k] = STBI__BYTECAST(raw[k] + prior[k]); // prior[k] == stbi__paeth(0,prior[k],0) + for (k = filter_bytes; k < nk; ++k) + cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes], prior[k], prior[k-filter_bytes])); + break; + case STBI__F_avg_first: + memcpy(cur, raw, filter_bytes); + for (k = filter_bytes; k < nk; ++k) + cur[k] = STBI__BYTECAST(raw[k] + (cur[k-filter_bytes] >> 1)); + break; + } + + raw += nk; + + // expand decoded bits in cur to dest, also adding an extra alpha channel if desired + if (depth < 8) { + stbi_uc scale = (color == 0) ? stbi__depth_scale_table[depth] : 1; // scale grayscale values to 0..255 range + stbi_uc *in = cur; + stbi_uc *out = dest; + stbi_uc inb = 0; + stbi__uint32 nsmp = x*img_n; + + // expand bits to bytes first + if (depth == 4) { + for (i=0; i < nsmp; ++i) { + if ((i & 1) == 0) inb = *in++; + *out++ = scale * (inb >> 4); + inb <<= 4; + } + } else if (depth == 2) { + for (i=0; i < nsmp; ++i) { + if ((i & 3) == 0) inb = *in++; + *out++ = scale * (inb >> 6); + inb <<= 2; + } + } else { + STBI_ASSERT(depth == 1); + for (i=0; i < nsmp; ++i) { + if ((i & 7) == 0) inb = *in++; + *out++ = scale * (inb >> 7); + inb <<= 1; + } + } + + // insert alpha=255 values if desired + if (img_n != out_n) + stbi__create_png_alpha_expand8(dest, dest, x, img_n); + } else if (depth == 8) { + if (img_n == out_n) + memcpy(dest, cur, x*img_n); + else + stbi__create_png_alpha_expand8(dest, cur, x, img_n); + } else if (depth == 16) { + // convert the image data from big-endian to platform-native + stbi__uint16 *dest16 = (stbi__uint16*)dest; + stbi__uint32 nsmp = x*img_n; + + if (img_n == out_n) { + for (i = 0; i < nsmp; ++i, ++dest16, cur += 2) + *dest16 = (cur[0] << 8) | cur[1]; + } else { + STBI_ASSERT(img_n+1 == out_n); + if (img_n == 1) { + for (i = 0; i < x; ++i, dest16 += 2, cur += 2) { + dest16[0] = (cur[0] << 8) | cur[1]; + dest16[1] = 0xffff; + } + } else { + STBI_ASSERT(img_n == 3); + for (i = 0; i < x; ++i, dest16 += 4, cur += 6) { + dest16[0] = (cur[0] << 8) | cur[1]; + dest16[1] = (cur[2] << 8) | cur[3]; + dest16[2] = (cur[4] << 8) | cur[5]; + dest16[3] = 0xffff; + } + } + } + } + } + + STBI_FREE(filter_buf); + if (!all_ok) return 0; + + return 1; +} + +static int stbi__create_png_image(stbi__png *a, stbi_uc *image_data, stbi__uint32 image_data_len, int out_n, int depth, int color, int interlaced) +{ + int bytes = (depth == 16 ? 2 : 1); + int out_bytes = out_n * bytes; + stbi_uc *final; + int p; + if (!interlaced) + return stbi__create_png_image_raw(a, image_data, image_data_len, out_n, a->s->img_x, a->s->img_y, depth, color); + + // de-interlacing + final = (stbi_uc *) stbi__malloc_mad3(a->s->img_x, a->s->img_y, out_bytes, 0); + if (!final) return stbi__err("outofmem", "Out of memory"); + for (p=0; p < 7; ++p) { + int xorig[] = { 0,4,0,2,0,1,0 }; + int yorig[] = { 0,0,4,0,2,0,1 }; + int xspc[] = { 8,8,4,4,2,2,1 }; + int yspc[] = { 8,8,8,4,4,2,2 }; + int i,j,x,y; + // pass1_x[4] = 0, pass1_x[5] = 1, pass1_x[12] = 1 + x = (a->s->img_x - xorig[p] + xspc[p]-1) / xspc[p]; + y = (a->s->img_y - yorig[p] + yspc[p]-1) / yspc[p]; + if (x && y) { + stbi__uint32 img_len = ((((a->s->img_n * x * depth) + 7) >> 3) + 1) * y; + if (!stbi__create_png_image_raw(a, image_data, image_data_len, out_n, x, y, depth, color)) { + STBI_FREE(final); + return 0; + } + for (j=0; j < y; ++j) { + for (i=0; i < x; ++i) { + int out_y = j*yspc[p]+yorig[p]; + int out_x = i*xspc[p]+xorig[p]; + memcpy(final + out_y*a->s->img_x*out_bytes + out_x*out_bytes, + a->out + (j*x+i)*out_bytes, out_bytes); + } + } + STBI_FREE(a->out); + image_data += img_len; + image_data_len -= img_len; + } + } + a->out = final; + + return 1; +} + +static int stbi__compute_transparency(stbi__png *z, stbi_uc tc[3], int out_n) +{ + stbi__context *s = z->s; + stbi__uint32 i, pixel_count = s->img_x * s->img_y; + stbi_uc *p = z->out; + + // compute color-based transparency, assuming we've + // already got 255 as the alpha value in the output + STBI_ASSERT(out_n == 2 || out_n == 4); + + if (out_n == 2) { + for (i=0; i < pixel_count; ++i) { + p[1] = (p[0] == tc[0] ? 0 : 255); + p += 2; + } + } else { + for (i=0; i < pixel_count; ++i) { + if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2]) + p[3] = 0; + p += 4; + } + } + return 1; +} + +static int stbi__compute_transparency16(stbi__png *z, stbi__uint16 tc[3], int out_n) +{ + stbi__context *s = z->s; + stbi__uint32 i, pixel_count = s->img_x * s->img_y; + stbi__uint16 *p = (stbi__uint16*) z->out; + + // compute color-based transparency, assuming we've + // already got 65535 as the alpha value in the output + STBI_ASSERT(out_n == 2 || out_n == 4); + + if (out_n == 2) { + for (i = 0; i < pixel_count; ++i) { + p[1] = (p[0] == tc[0] ? 0 : 65535); + p += 2; + } + } else { + for (i = 0; i < pixel_count; ++i) { + if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2]) + p[3] = 0; + p += 4; + } + } + return 1; +} + +static int stbi__expand_png_palette(stbi__png *a, stbi_uc *palette, int len, int pal_img_n) +{ + stbi__uint32 i, pixel_count = a->s->img_x * a->s->img_y; + stbi_uc *p, *temp_out, *orig = a->out; + + p = (stbi_uc *) stbi__malloc_mad2(pixel_count, pal_img_n, 0); + if (p == NULL) return stbi__err("outofmem", "Out of memory"); + + // between here and free(out) below, exitting would leak + temp_out = p; + + if (pal_img_n == 3) { + for (i=0; i < pixel_count; ++i) { + int n = orig[i]*4; + p[0] = palette[n ]; + p[1] = palette[n+1]; + p[2] = palette[n+2]; + p += 3; + } + } else { + for (i=0; i < pixel_count; ++i) { + int n = orig[i]*4; + p[0] = palette[n ]; + p[1] = palette[n+1]; + p[2] = palette[n+2]; + p[3] = palette[n+3]; + p += 4; + } + } + STBI_FREE(a->out); + a->out = temp_out; + + STBI_NOTUSED(len); + + return 1; +} + +static int stbi__unpremultiply_on_load_global = 0; +static int stbi__de_iphone_flag_global = 0; + +STBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply) +{ + stbi__unpremultiply_on_load_global = flag_true_if_should_unpremultiply; +} + +STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert) +{ + stbi__de_iphone_flag_global = flag_true_if_should_convert; +} + +#ifndef STBI_THREAD_LOCAL +#define stbi__unpremultiply_on_load stbi__unpremultiply_on_load_global +#define stbi__de_iphone_flag stbi__de_iphone_flag_global +#else +static STBI_THREAD_LOCAL int stbi__unpremultiply_on_load_local, stbi__unpremultiply_on_load_set; +static STBI_THREAD_LOCAL int stbi__de_iphone_flag_local, stbi__de_iphone_flag_set; + +STBIDEF void stbi_set_unpremultiply_on_load_thread(int flag_true_if_should_unpremultiply) +{ + stbi__unpremultiply_on_load_local = flag_true_if_should_unpremultiply; + stbi__unpremultiply_on_load_set = 1; +} + +STBIDEF void stbi_convert_iphone_png_to_rgb_thread(int flag_true_if_should_convert) +{ + stbi__de_iphone_flag_local = flag_true_if_should_convert; + stbi__de_iphone_flag_set = 1; +} + +#define stbi__unpremultiply_on_load (stbi__unpremultiply_on_load_set \ + ? stbi__unpremultiply_on_load_local \ + : stbi__unpremultiply_on_load_global) +#define stbi__de_iphone_flag (stbi__de_iphone_flag_set \ + ? stbi__de_iphone_flag_local \ + : stbi__de_iphone_flag_global) +#endif // STBI_THREAD_LOCAL + +static void stbi__de_iphone(stbi__png *z) +{ + stbi__context *s = z->s; + stbi__uint32 i, pixel_count = s->img_x * s->img_y; + stbi_uc *p = z->out; + + if (s->img_out_n == 3) { // convert bgr to rgb + for (i=0; i < pixel_count; ++i) { + stbi_uc t = p[0]; + p[0] = p[2]; + p[2] = t; + p += 3; + } + } else { + STBI_ASSERT(s->img_out_n == 4); + if (stbi__unpremultiply_on_load) { + // convert bgr to rgb and unpremultiply + for (i=0; i < pixel_count; ++i) { + stbi_uc a = p[3]; + stbi_uc t = p[0]; + if (a) { + stbi_uc half = a / 2; + p[0] = (p[2] * 255 + half) / a; + p[1] = (p[1] * 255 + half) / a; + p[2] = ( t * 255 + half) / a; + } else { + p[0] = p[2]; + p[2] = t; + } + p += 4; + } + } else { + // convert bgr to rgb + for (i=0; i < pixel_count; ++i) { + stbi_uc t = p[0]; + p[0] = p[2]; + p[2] = t; + p += 4; + } + } + } +} + +#define STBI__PNG_TYPE(a,b,c,d) (((unsigned) (a) << 24) + ((unsigned) (b) << 16) + ((unsigned) (c) << 8) + (unsigned) (d)) + +static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp) +{ + stbi_uc palette[1024], pal_img_n=0; + stbi_uc has_trans=0, tc[3]={0}; + stbi__uint16 tc16[3]; + stbi__uint32 ioff=0, idata_limit=0, i, pal_len=0; + int first=1,k,interlace=0, color=0, is_iphone=0; + stbi__context *s = z->s; + + z->expanded = NULL; + z->idata = NULL; + z->out = NULL; + + if (!stbi__check_png_header(s)) return 0; + + if (scan == STBI__SCAN_type) return 1; + + for (;;) { + stbi__pngchunk c = stbi__get_chunk_header(s); + switch (c.type) { + case STBI__PNG_TYPE('C','g','B','I'): + is_iphone = 1; + stbi__skip(s, c.length); + break; + case STBI__PNG_TYPE('I','H','D','R'): { + int comp,filter; + if (!first) return stbi__err("multiple IHDR","Corrupt PNG"); + first = 0; + if (c.length != 13) return stbi__err("bad IHDR len","Corrupt PNG"); + s->img_x = stbi__get32be(s); + s->img_y = stbi__get32be(s); + if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); + if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); + z->depth = stbi__get8(s); if (z->depth != 1 && z->depth != 2 && z->depth != 4 && z->depth != 8 && z->depth != 16) return stbi__err("1/2/4/8/16-bit only","PNG not supported: 1/2/4/8/16-bit only"); + color = stbi__get8(s); if (color > 6) return stbi__err("bad ctype","Corrupt PNG"); + if (color == 3 && z->depth == 16) return stbi__err("bad ctype","Corrupt PNG"); + if (color == 3) pal_img_n = 3; else if (color & 1) return stbi__err("bad ctype","Corrupt PNG"); + comp = stbi__get8(s); if (comp) return stbi__err("bad comp method","Corrupt PNG"); + filter= stbi__get8(s); if (filter) return stbi__err("bad filter method","Corrupt PNG"); + interlace = stbi__get8(s); if (interlace>1) return stbi__err("bad interlace method","Corrupt PNG"); + if (!s->img_x || !s->img_y) return stbi__err("0-pixel image","Corrupt PNG"); + if (!pal_img_n) { + s->img_n = (color & 2 ? 3 : 1) + (color & 4 ? 1 : 0); + if ((1 << 30) / s->img_x / s->img_n < s->img_y) return stbi__err("too large", "Image too large to decode"); + } else { + // if paletted, then pal_n is our final components, and + // img_n is # components to decompress/filter. + s->img_n = 1; + if ((1 << 30) / s->img_x / 4 < s->img_y) return stbi__err("too large","Corrupt PNG"); + } + // even with SCAN_header, have to scan to see if we have a tRNS + break; + } + + case STBI__PNG_TYPE('P','L','T','E'): { + if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + if (c.length > 256*3) return stbi__err("invalid PLTE","Corrupt PNG"); + pal_len = c.length / 3; + if (pal_len * 3 != c.length) return stbi__err("invalid PLTE","Corrupt PNG"); + for (i=0; i < pal_len; ++i) { + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + } + break; + } + + case STBI__PNG_TYPE('t','R','N','S'): { + if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + if (z->idata) return stbi__err("tRNS after IDAT","Corrupt PNG"); + if (pal_img_n) { + if (scan == STBI__SCAN_header) { s->img_n = 4; return 1; } + if (pal_len == 0) return stbi__err("tRNS before PLTE","Corrupt PNG"); + if (c.length > pal_len) return stbi__err("bad tRNS len","Corrupt PNG"); + pal_img_n = 4; + for (i=0; i < c.length; ++i) + palette[i*4+3] = stbi__get8(s); + } else { + if (!(s->img_n & 1)) return stbi__err("tRNS with alpha","Corrupt PNG"); + if (c.length != (stbi__uint32) s->img_n*2) return stbi__err("bad tRNS len","Corrupt PNG"); + has_trans = 1; + // non-paletted with tRNS = constant alpha. if header-scanning, we can stop now. + if (scan == STBI__SCAN_header) { ++s->img_n; return 1; } + if (z->depth == 16) { + for (k = 0; k < s->img_n && k < 3; ++k) // extra loop test to suppress false GCC warning + tc16[k] = (stbi__uint16)stbi__get16be(s); // copy the values as-is + } else { + for (k = 0; k < s->img_n && k < 3; ++k) + tc[k] = (stbi_uc)(stbi__get16be(s) & 255) * stbi__depth_scale_table[z->depth]; // non 8-bit images will be larger + } + } + break; + } + + case STBI__PNG_TYPE('I','D','A','T'): { + if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + if (pal_img_n && !pal_len) return stbi__err("no PLTE","Corrupt PNG"); + if (scan == STBI__SCAN_header) { + // header scan definitely stops at first IDAT + if (pal_img_n) + s->img_n = pal_img_n; + return 1; + } + if (c.length > (1u << 30)) return stbi__err("IDAT size limit", "IDAT section larger than 2^30 bytes"); + if ((int)(ioff + c.length) < (int)ioff) return 0; + if (ioff + c.length > idata_limit) { + stbi__uint32 idata_limit_old = idata_limit; + stbi_uc *p; + if (idata_limit == 0) idata_limit = c.length > 4096 ? c.length : 4096; + while (ioff + c.length > idata_limit) + idata_limit *= 2; + STBI_NOTUSED(idata_limit_old); + p = (stbi_uc *) STBI_REALLOC_SIZED(z->idata, idata_limit_old, idata_limit); if (p == NULL) return stbi__err("outofmem", "Out of memory"); + z->idata = p; + } + if (!stbi__getn(s, z->idata+ioff,c.length)) return stbi__err("outofdata","Corrupt PNG"); + ioff += c.length; + break; + } + + case STBI__PNG_TYPE('I','E','N','D'): { + stbi__uint32 raw_len, bpl; + if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + if (scan != STBI__SCAN_load) return 1; + if (z->idata == NULL) return stbi__err("no IDAT","Corrupt PNG"); + // initial guess for decoded data size to avoid unnecessary reallocs + bpl = (s->img_x * z->depth + 7) / 8; // bytes per line, per component + raw_len = bpl * s->img_y * s->img_n /* pixels */ + s->img_y /* filter mode per row */; + z->expanded = (stbi_uc *) stbi_zlib_decode_malloc_guesssize_headerflag((char *) z->idata, ioff, raw_len, (int *) &raw_len, !is_iphone); + if (z->expanded == NULL) return 0; // zlib should set error + STBI_FREE(z->idata); z->idata = NULL; + if ((req_comp == s->img_n+1 && req_comp != 3 && !pal_img_n) || has_trans) + s->img_out_n = s->img_n+1; + else + s->img_out_n = s->img_n; + if (!stbi__create_png_image(z, z->expanded, raw_len, s->img_out_n, z->depth, color, interlace)) return 0; + if (has_trans) { + if (z->depth == 16) { + if (!stbi__compute_transparency16(z, tc16, s->img_out_n)) return 0; + } else { + if (!stbi__compute_transparency(z, tc, s->img_out_n)) return 0; + } + } + if (is_iphone && stbi__de_iphone_flag && s->img_out_n > 2) + stbi__de_iphone(z); + if (pal_img_n) { + // pal_img_n == 3 or 4 + s->img_n = pal_img_n; // record the actual colors we had + s->img_out_n = pal_img_n; + if (req_comp >= 3) s->img_out_n = req_comp; + if (!stbi__expand_png_palette(z, palette, pal_len, s->img_out_n)) + return 0; + } else if (has_trans) { + // non-paletted image with tRNS -> source image has (constant) alpha + ++s->img_n; + } + STBI_FREE(z->expanded); z->expanded = NULL; + // end of PNG chunk, read and skip CRC + stbi__get32be(s); + return 1; + } + + default: + // if critical, fail + if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + if ((c.type & (1 << 29)) == 0) { + #ifndef STBI_NO_FAILURE_STRINGS + // not threadsafe + static char invalid_chunk[] = "XXXX PNG chunk not known"; + invalid_chunk[0] = STBI__BYTECAST(c.type >> 24); + invalid_chunk[1] = STBI__BYTECAST(c.type >> 16); + invalid_chunk[2] = STBI__BYTECAST(c.type >> 8); + invalid_chunk[3] = STBI__BYTECAST(c.type >> 0); + #endif + return stbi__err(invalid_chunk, "PNG not supported: unknown PNG chunk type"); + } + stbi__skip(s, c.length); + break; + } + // end of PNG chunk, read and skip CRC + stbi__get32be(s); + } +} + +static void *stbi__do_png(stbi__png *p, int *x, int *y, int *n, int req_comp, stbi__result_info *ri) +{ + void *result=NULL; + if (req_comp < 0 || req_comp > 4) return stbi__errpuc("bad req_comp", "Internal error"); + if (stbi__parse_png_file(p, STBI__SCAN_load, req_comp)) { + if (p->depth <= 8) + ri->bits_per_channel = 8; + else if (p->depth == 16) + ri->bits_per_channel = 16; + else + return stbi__errpuc("bad bits_per_channel", "PNG not supported: unsupported color depth"); + result = p->out; + p->out = NULL; + if (req_comp && req_comp != p->s->img_out_n) { + if (ri->bits_per_channel == 8) + result = stbi__convert_format((unsigned char *) result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y); + else + result = stbi__convert_format16((stbi__uint16 *) result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y); + p->s->img_out_n = req_comp; + if (result == NULL) return result; + } + *x = p->s->img_x; + *y = p->s->img_y; + if (n) *n = p->s->img_n; + } + STBI_FREE(p->out); p->out = NULL; + STBI_FREE(p->expanded); p->expanded = NULL; + STBI_FREE(p->idata); p->idata = NULL; + + return result; +} + +static void *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + stbi__png p; + p.s = s; + return stbi__do_png(&p, x,y,comp,req_comp, ri); +} + +static int stbi__png_test(stbi__context *s) +{ + int r; + r = stbi__check_png_header(s); + stbi__rewind(s); + return r; +} + +static int stbi__png_info_raw(stbi__png *p, int *x, int *y, int *comp) +{ + if (!stbi__parse_png_file(p, STBI__SCAN_header, 0)) { + stbi__rewind( p->s ); + return 0; + } + if (x) *x = p->s->img_x; + if (y) *y = p->s->img_y; + if (comp) *comp = p->s->img_n; + return 1; +} + +static int stbi__png_info(stbi__context *s, int *x, int *y, int *comp) +{ + stbi__png p; + p.s = s; + return stbi__png_info_raw(&p, x, y, comp); +} + +static int stbi__png_is16(stbi__context *s) +{ + stbi__png p; + p.s = s; + if (!stbi__png_info_raw(&p, NULL, NULL, NULL)) + return 0; + if (p.depth != 16) { + stbi__rewind(p.s); + return 0; + } + return 1; +} +#endif + +// Microsoft/Windows BMP image + +#ifndef STBI_NO_BMP +static int stbi__bmp_test_raw(stbi__context *s) +{ + int r; + int sz; + if (stbi__get8(s) != 'B') return 0; + if (stbi__get8(s) != 'M') return 0; + stbi__get32le(s); // discard filesize + stbi__get16le(s); // discard reserved + stbi__get16le(s); // discard reserved + stbi__get32le(s); // discard data offset + sz = stbi__get32le(s); + r = (sz == 12 || sz == 40 || sz == 56 || sz == 108 || sz == 124); + return r; +} + +static int stbi__bmp_test(stbi__context *s) +{ + int r = stbi__bmp_test_raw(s); + stbi__rewind(s); + return r; +} + + +// returns 0..31 for the highest set bit +static int stbi__high_bit(unsigned int z) +{ + int n=0; + if (z == 0) return -1; + if (z >= 0x10000) { n += 16; z >>= 16; } + if (z >= 0x00100) { n += 8; z >>= 8; } + if (z >= 0x00010) { n += 4; z >>= 4; } + if (z >= 0x00004) { n += 2; z >>= 2; } + if (z >= 0x00002) { n += 1;/* >>= 1;*/ } + return n; +} + +static int stbi__bitcount(unsigned int a) +{ + a = (a & 0x55555555) + ((a >> 1) & 0x55555555); // max 2 + a = (a & 0x33333333) + ((a >> 2) & 0x33333333); // max 4 + a = (a + (a >> 4)) & 0x0f0f0f0f; // max 8 per 4, now 8 bits + a = (a + (a >> 8)); // max 16 per 8 bits + a = (a + (a >> 16)); // max 32 per 8 bits + return a & 0xff; +} + +// extract an arbitrarily-aligned N-bit value (N=bits) +// from v, and then make it 8-bits long and fractionally +// extend it to full full range. +static int stbi__shiftsigned(unsigned int v, int shift, int bits) +{ + static unsigned int mul_table[9] = { + 0, + 0xff/*0b11111111*/, 0x55/*0b01010101*/, 0x49/*0b01001001*/, 0x11/*0b00010001*/, + 0x21/*0b00100001*/, 0x41/*0b01000001*/, 0x81/*0b10000001*/, 0x01/*0b00000001*/, + }; + static unsigned int shift_table[9] = { + 0, 0,0,1,0,2,4,6,0, + }; + if (shift < 0) + v <<= -shift; + else + v >>= shift; + STBI_ASSERT(v < 256); + v >>= (8-bits); + STBI_ASSERT(bits >= 0 && bits <= 8); + return (int) ((unsigned) v * mul_table[bits]) >> shift_table[bits]; +} + +typedef struct +{ + int bpp, offset, hsz; + unsigned int mr,mg,mb,ma, all_a; + int extra_read; +} stbi__bmp_data; + +static int stbi__bmp_set_mask_defaults(stbi__bmp_data *info, int compress) +{ + // BI_BITFIELDS specifies masks explicitly, don't override + if (compress == 3) + return 1; + + if (compress == 0) { + if (info->bpp == 16) { + info->mr = 31u << 10; + info->mg = 31u << 5; + info->mb = 31u << 0; + } else if (info->bpp == 32) { + info->mr = 0xffu << 16; + info->mg = 0xffu << 8; + info->mb = 0xffu << 0; + info->ma = 0xffu << 24; + info->all_a = 0; // if all_a is 0 at end, then we loaded alpha channel but it was all 0 + } else { + // otherwise, use defaults, which is all-0 + info->mr = info->mg = info->mb = info->ma = 0; + } + return 1; + } + return 0; // error +} + +static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info) +{ + int hsz; + if (stbi__get8(s) != 'B' || stbi__get8(s) != 'M') return stbi__errpuc("not BMP", "Corrupt BMP"); + stbi__get32le(s); // discard filesize + stbi__get16le(s); // discard reserved + stbi__get16le(s); // discard reserved + info->offset = stbi__get32le(s); + info->hsz = hsz = stbi__get32le(s); + info->mr = info->mg = info->mb = info->ma = 0; + info->extra_read = 14; + + if (info->offset < 0) return stbi__errpuc("bad BMP", "bad BMP"); + + if (hsz != 12 && hsz != 40 && hsz != 56 && hsz != 108 && hsz != 124) return stbi__errpuc("unknown BMP", "BMP type not supported: unknown"); + if (hsz == 12) { + s->img_x = stbi__get16le(s); + s->img_y = stbi__get16le(s); + } else { + s->img_x = stbi__get32le(s); + s->img_y = stbi__get32le(s); + } + if (stbi__get16le(s) != 1) return stbi__errpuc("bad BMP", "bad BMP"); + info->bpp = stbi__get16le(s); + if (hsz != 12) { + int compress = stbi__get32le(s); + if (compress == 1 || compress == 2) return stbi__errpuc("BMP RLE", "BMP type not supported: RLE"); + if (compress >= 4) return stbi__errpuc("BMP JPEG/PNG", "BMP type not supported: unsupported compression"); // this includes PNG/JPEG modes + if (compress == 3 && info->bpp != 16 && info->bpp != 32) return stbi__errpuc("bad BMP", "bad BMP"); // bitfields requires 16 or 32 bits/pixel + stbi__get32le(s); // discard sizeof + stbi__get32le(s); // discard hres + stbi__get32le(s); // discard vres + stbi__get32le(s); // discard colorsused + stbi__get32le(s); // discard max important + if (hsz == 40 || hsz == 56) { + if (hsz == 56) { + stbi__get32le(s); + stbi__get32le(s); + stbi__get32le(s); + stbi__get32le(s); + } + if (info->bpp == 16 || info->bpp == 32) { + if (compress == 0) { + stbi__bmp_set_mask_defaults(info, compress); + } else if (compress == 3) { + info->mr = stbi__get32le(s); + info->mg = stbi__get32le(s); + info->mb = stbi__get32le(s); + info->extra_read += 12; + // not documented, but generated by photoshop and handled by mspaint + if (info->mr == info->mg && info->mg == info->mb) { + // ?!?!? + return stbi__errpuc("bad BMP", "bad BMP"); + } + } else + return stbi__errpuc("bad BMP", "bad BMP"); + } + } else { + // V4/V5 header + int i; + if (hsz != 108 && hsz != 124) + return stbi__errpuc("bad BMP", "bad BMP"); + info->mr = stbi__get32le(s); + info->mg = stbi__get32le(s); + info->mb = stbi__get32le(s); + info->ma = stbi__get32le(s); + if (compress != 3) // override mr/mg/mb unless in BI_BITFIELDS mode, as per docs + stbi__bmp_set_mask_defaults(info, compress); + stbi__get32le(s); // discard color space + for (i=0; i < 12; ++i) + stbi__get32le(s); // discard color space parameters + if (hsz == 124) { + stbi__get32le(s); // discard rendering intent + stbi__get32le(s); // discard offset of profile data + stbi__get32le(s); // discard size of profile data + stbi__get32le(s); // discard reserved + } + } + } + return (void *) 1; +} + + +static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + stbi_uc *out; + unsigned int mr=0,mg=0,mb=0,ma=0, all_a; + stbi_uc pal[256][4]; + int psize=0,i,j,width; + int flip_vertically, pad, target; + stbi__bmp_data info; + STBI_NOTUSED(ri); + + info.all_a = 255; + if (stbi__bmp_parse_header(s, &info) == NULL) + return NULL; // error code already set + + flip_vertically = ((int) s->img_y) > 0; + s->img_y = abs((int) s->img_y); + + if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + + mr = info.mr; + mg = info.mg; + mb = info.mb; + ma = info.ma; + all_a = info.all_a; + + if (info.hsz == 12) { + if (info.bpp < 24) + psize = (info.offset - info.extra_read - 24) / 3; + } else { + if (info.bpp < 16) + psize = (info.offset - info.extra_read - info.hsz) >> 2; + } + if (psize == 0) { + // accept some number of extra bytes after the header, but if the offset points either to before + // the header ends or implies a large amount of extra data, reject the file as malformed + int bytes_read_so_far = s->callback_already_read + (int)(s->img_buffer - s->img_buffer_original); + int header_limit = 1024; // max we actually read is below 256 bytes currently. + int extra_data_limit = 256*4; // what ordinarily goes here is a palette; 256 entries*4 bytes is its max size. + if (bytes_read_so_far <= 0 || bytes_read_so_far > header_limit) { + return stbi__errpuc("bad header", "Corrupt BMP"); + } + // we established that bytes_read_so_far is positive and sensible. + // the first half of this test rejects offsets that are either too small positives, or + // negative, and guarantees that info.offset >= bytes_read_so_far > 0. this in turn + // ensures the number computed in the second half of the test can't overflow. + if (info.offset < bytes_read_so_far || info.offset - bytes_read_so_far > extra_data_limit) { + return stbi__errpuc("bad offset", "Corrupt BMP"); + } else { + stbi__skip(s, info.offset - bytes_read_so_far); + } + } + + if (info.bpp == 24 && ma == 0xff000000) + s->img_n = 3; + else + s->img_n = ma ? 4 : 3; + if (req_comp && req_comp >= 3) // we can directly decode 3 or 4 + target = req_comp; + else + target = s->img_n; // if they want monochrome, we'll post-convert + + // sanity-check size + if (!stbi__mad3sizes_valid(target, s->img_x, s->img_y, 0)) + return stbi__errpuc("too large", "Corrupt BMP"); + + out = (stbi_uc *) stbi__malloc_mad3(target, s->img_x, s->img_y, 0); + if (!out) return stbi__errpuc("outofmem", "Out of memory"); + if (info.bpp < 16) { + int z=0; + if (psize == 0 || psize > 256) { STBI_FREE(out); return stbi__errpuc("invalid", "Corrupt BMP"); } + for (i=0; i < psize; ++i) { + pal[i][2] = stbi__get8(s); + pal[i][1] = stbi__get8(s); + pal[i][0] = stbi__get8(s); + if (info.hsz != 12) stbi__get8(s); + pal[i][3] = 255; + } + stbi__skip(s, info.offset - info.extra_read - info.hsz - psize * (info.hsz == 12 ? 3 : 4)); + if (info.bpp == 1) width = (s->img_x + 7) >> 3; + else if (info.bpp == 4) width = (s->img_x + 1) >> 1; + else if (info.bpp == 8) width = s->img_x; + else { STBI_FREE(out); return stbi__errpuc("bad bpp", "Corrupt BMP"); } + pad = (-width)&3; + if (info.bpp == 1) { + for (j=0; j < (int) s->img_y; ++j) { + int bit_offset = 7, v = stbi__get8(s); + for (i=0; i < (int) s->img_x; ++i) { + int color = (v>>bit_offset)&0x1; + out[z++] = pal[color][0]; + out[z++] = pal[color][1]; + out[z++] = pal[color][2]; + if (target == 4) out[z++] = 255; + if (i+1 == (int) s->img_x) break; + if((--bit_offset) < 0) { + bit_offset = 7; + v = stbi__get8(s); + } + } + stbi__skip(s, pad); + } + } else { + for (j=0; j < (int) s->img_y; ++j) { + for (i=0; i < (int) s->img_x; i += 2) { + int v=stbi__get8(s),v2=0; + if (info.bpp == 4) { + v2 = v & 15; + v >>= 4; + } + out[z++] = pal[v][0]; + out[z++] = pal[v][1]; + out[z++] = pal[v][2]; + if (target == 4) out[z++] = 255; + if (i+1 == (int) s->img_x) break; + v = (info.bpp == 8) ? stbi__get8(s) : v2; + out[z++] = pal[v][0]; + out[z++] = pal[v][1]; + out[z++] = pal[v][2]; + if (target == 4) out[z++] = 255; + } + stbi__skip(s, pad); + } + } + } else { + int rshift=0,gshift=0,bshift=0,ashift=0,rcount=0,gcount=0,bcount=0,acount=0; + int z = 0; + int easy=0; + stbi__skip(s, info.offset - info.extra_read - info.hsz); + if (info.bpp == 24) width = 3 * s->img_x; + else if (info.bpp == 16) width = 2*s->img_x; + else /* bpp = 32 and pad = 0 */ width=0; + pad = (-width) & 3; + if (info.bpp == 24) { + easy = 1; + } else if (info.bpp == 32) { + if (mb == 0xff && mg == 0xff00 && mr == 0x00ff0000 && ma == 0xff000000) + easy = 2; + } + if (!easy) { + if (!mr || !mg || !mb) { STBI_FREE(out); return stbi__errpuc("bad masks", "Corrupt BMP"); } + // right shift amt to put high bit in position #7 + rshift = stbi__high_bit(mr)-7; rcount = stbi__bitcount(mr); + gshift = stbi__high_bit(mg)-7; gcount = stbi__bitcount(mg); + bshift = stbi__high_bit(mb)-7; bcount = stbi__bitcount(mb); + ashift = stbi__high_bit(ma)-7; acount = stbi__bitcount(ma); + if (rcount > 8 || gcount > 8 || bcount > 8 || acount > 8) { STBI_FREE(out); return stbi__errpuc("bad masks", "Corrupt BMP"); } + } + for (j=0; j < (int) s->img_y; ++j) { + if (easy) { + for (i=0; i < (int) s->img_x; ++i) { + unsigned char a; + out[z+2] = stbi__get8(s); + out[z+1] = stbi__get8(s); + out[z+0] = stbi__get8(s); + z += 3; + a = (easy == 2 ? stbi__get8(s) : 255); + all_a |= a; + if (target == 4) out[z++] = a; + } + } else { + int bpp = info.bpp; + for (i=0; i < (int) s->img_x; ++i) { + stbi__uint32 v = (bpp == 16 ? (stbi__uint32) stbi__get16le(s) : stbi__get32le(s)); + unsigned int a; + out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mr, rshift, rcount)); + out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mg, gshift, gcount)); + out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mb, bshift, bcount)); + a = (ma ? stbi__shiftsigned(v & ma, ashift, acount) : 255); + all_a |= a; + if (target == 4) out[z++] = STBI__BYTECAST(a); + } + } + stbi__skip(s, pad); + } + } + + // if alpha channel is all 0s, replace with all 255s + if (target == 4 && all_a == 0) + for (i=4*s->img_x*s->img_y-1; i >= 0; i -= 4) + out[i] = 255; + + if (flip_vertically) { + stbi_uc t; + for (j=0; j < (int) s->img_y>>1; ++j) { + stbi_uc *p1 = out + j *s->img_x*target; + stbi_uc *p2 = out + (s->img_y-1-j)*s->img_x*target; + for (i=0; i < (int) s->img_x*target; ++i) { + t = p1[i]; p1[i] = p2[i]; p2[i] = t; + } + } + } + + if (req_comp && req_comp != target) { + out = stbi__convert_format(out, target, req_comp, s->img_x, s->img_y); + if (out == NULL) return out; // stbi__convert_format frees input on failure + } + + *x = s->img_x; + *y = s->img_y; + if (comp) *comp = s->img_n; + return out; +} +#endif + +// Targa Truevision - TGA +// by Jonathan Dummer +#ifndef STBI_NO_TGA +// returns STBI_rgb or whatever, 0 on error +static int stbi__tga_get_comp(int bits_per_pixel, int is_grey, int* is_rgb16) +{ + // only RGB or RGBA (incl. 16bit) or grey allowed + if (is_rgb16) *is_rgb16 = 0; + switch(bits_per_pixel) { + case 8: return STBI_grey; + case 16: if(is_grey) return STBI_grey_alpha; + // fallthrough + case 15: if(is_rgb16) *is_rgb16 = 1; + return STBI_rgb; + case 24: // fallthrough + case 32: return bits_per_pixel/8; + default: return 0; + } +} + +static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp) +{ + int tga_w, tga_h, tga_comp, tga_image_type, tga_bits_per_pixel, tga_colormap_bpp; + int sz, tga_colormap_type; + stbi__get8(s); // discard Offset + tga_colormap_type = stbi__get8(s); // colormap type + if( tga_colormap_type > 1 ) { + stbi__rewind(s); + return 0; // only RGB or indexed allowed + } + tga_image_type = stbi__get8(s); // image type + if ( tga_colormap_type == 1 ) { // colormapped (paletted) image + if (tga_image_type != 1 && tga_image_type != 9) { + stbi__rewind(s); + return 0; + } + stbi__skip(s,4); // skip index of first colormap entry and number of entries + sz = stbi__get8(s); // check bits per palette color entry + if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) { + stbi__rewind(s); + return 0; + } + stbi__skip(s,4); // skip image x and y origin + tga_colormap_bpp = sz; + } else { // "normal" image w/o colormap - only RGB or grey allowed, +/- RLE + if ( (tga_image_type != 2) && (tga_image_type != 3) && (tga_image_type != 10) && (tga_image_type != 11) ) { + stbi__rewind(s); + return 0; // only RGB or grey allowed, +/- RLE + } + stbi__skip(s,9); // skip colormap specification and image x/y origin + tga_colormap_bpp = 0; + } + tga_w = stbi__get16le(s); + if( tga_w < 1 ) { + stbi__rewind(s); + return 0; // test width + } + tga_h = stbi__get16le(s); + if( tga_h < 1 ) { + stbi__rewind(s); + return 0; // test height + } + tga_bits_per_pixel = stbi__get8(s); // bits per pixel + stbi__get8(s); // ignore alpha bits + if (tga_colormap_bpp != 0) { + if((tga_bits_per_pixel != 8) && (tga_bits_per_pixel != 16)) { + // when using a colormap, tga_bits_per_pixel is the size of the indexes + // I don't think anything but 8 or 16bit indexes makes sense + stbi__rewind(s); + return 0; + } + tga_comp = stbi__tga_get_comp(tga_colormap_bpp, 0, NULL); + } else { + tga_comp = stbi__tga_get_comp(tga_bits_per_pixel, (tga_image_type == 3) || (tga_image_type == 11), NULL); + } + if(!tga_comp) { + stbi__rewind(s); + return 0; + } + if (x) *x = tga_w; + if (y) *y = tga_h; + if (comp) *comp = tga_comp; + return 1; // seems to have passed everything +} + +static int stbi__tga_test(stbi__context *s) +{ + int res = 0; + int sz, tga_color_type; + stbi__get8(s); // discard Offset + tga_color_type = stbi__get8(s); // color type + if ( tga_color_type > 1 ) goto errorEnd; // only RGB or indexed allowed + sz = stbi__get8(s); // image type + if ( tga_color_type == 1 ) { // colormapped (paletted) image + if (sz != 1 && sz != 9) goto errorEnd; // colortype 1 demands image type 1 or 9 + stbi__skip(s,4); // skip index of first colormap entry and number of entries + sz = stbi__get8(s); // check bits per palette color entry + if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) goto errorEnd; + stbi__skip(s,4); // skip image x and y origin + } else { // "normal" image w/o colormap + if ( (sz != 2) && (sz != 3) && (sz != 10) && (sz != 11) ) goto errorEnd; // only RGB or grey allowed, +/- RLE + stbi__skip(s,9); // skip colormap specification and image x/y origin + } + if ( stbi__get16le(s) < 1 ) goto errorEnd; // test width + if ( stbi__get16le(s) < 1 ) goto errorEnd; // test height + sz = stbi__get8(s); // bits per pixel + if ( (tga_color_type == 1) && (sz != 8) && (sz != 16) ) goto errorEnd; // for colormapped images, bpp is size of an index + if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) goto errorEnd; + + res = 1; // if we got this far, everything's good and we can return 1 instead of 0 + +errorEnd: + stbi__rewind(s); + return res; +} + +// read 16bit value and convert to 24bit RGB +static void stbi__tga_read_rgb16(stbi__context *s, stbi_uc* out) +{ + stbi__uint16 px = (stbi__uint16)stbi__get16le(s); + stbi__uint16 fiveBitMask = 31; + // we have 3 channels with 5bits each + int r = (px >> 10) & fiveBitMask; + int g = (px >> 5) & fiveBitMask; + int b = px & fiveBitMask; + // Note that this saves the data in RGB(A) order, so it doesn't need to be swapped later + out[0] = (stbi_uc)((r * 255)/31); + out[1] = (stbi_uc)((g * 255)/31); + out[2] = (stbi_uc)((b * 255)/31); + + // some people claim that the most significant bit might be used for alpha + // (possibly if an alpha-bit is set in the "image descriptor byte") + // but that only made 16bit test images completely translucent.. + // so let's treat all 15 and 16bit TGAs as RGB with no alpha. +} + +static void *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + // read in the TGA header stuff + int tga_offset = stbi__get8(s); + int tga_indexed = stbi__get8(s); + int tga_image_type = stbi__get8(s); + int tga_is_RLE = 0; + int tga_palette_start = stbi__get16le(s); + int tga_palette_len = stbi__get16le(s); + int tga_palette_bits = stbi__get8(s); + int tga_x_origin = stbi__get16le(s); + int tga_y_origin = stbi__get16le(s); + int tga_width = stbi__get16le(s); + int tga_height = stbi__get16le(s); + int tga_bits_per_pixel = stbi__get8(s); + int tga_comp, tga_rgb16=0; + int tga_inverted = stbi__get8(s); + // int tga_alpha_bits = tga_inverted & 15; // the 4 lowest bits - unused (useless?) + // image data + unsigned char *tga_data; + unsigned char *tga_palette = NULL; + int i, j; + unsigned char raw_data[4] = {0}; + int RLE_count = 0; + int RLE_repeating = 0; + int read_next_pixel = 1; + STBI_NOTUSED(ri); + STBI_NOTUSED(tga_x_origin); // @TODO + STBI_NOTUSED(tga_y_origin); // @TODO + + if (tga_height > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + if (tga_width > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + + // do a tiny bit of precessing + if ( tga_image_type >= 8 ) + { + tga_image_type -= 8; + tga_is_RLE = 1; + } + tga_inverted = 1 - ((tga_inverted >> 5) & 1); + + // If I'm paletted, then I'll use the number of bits from the palette + if ( tga_indexed ) tga_comp = stbi__tga_get_comp(tga_palette_bits, 0, &tga_rgb16); + else tga_comp = stbi__tga_get_comp(tga_bits_per_pixel, (tga_image_type == 3), &tga_rgb16); + + if(!tga_comp) // shouldn't really happen, stbi__tga_test() should have ensured basic consistency + return stbi__errpuc("bad format", "Can't find out TGA pixelformat"); + + // tga info + *x = tga_width; + *y = tga_height; + if (comp) *comp = tga_comp; + + if (!stbi__mad3sizes_valid(tga_width, tga_height, tga_comp, 0)) + return stbi__errpuc("too large", "Corrupt TGA"); + + tga_data = (unsigned char*)stbi__malloc_mad3(tga_width, tga_height, tga_comp, 0); + if (!tga_data) return stbi__errpuc("outofmem", "Out of memory"); + + // skip to the data's starting position (offset usually = 0) + stbi__skip(s, tga_offset ); + + if ( !tga_indexed && !tga_is_RLE && !tga_rgb16 ) { + for (i=0; i < tga_height; ++i) { + int row = tga_inverted ? tga_height -i - 1 : i; + stbi_uc *tga_row = tga_data + row*tga_width*tga_comp; + stbi__getn(s, tga_row, tga_width * tga_comp); + } + } else { + // do I need to load a palette? + if ( tga_indexed) + { + if (tga_palette_len == 0) { /* you have to have at least one entry! */ + STBI_FREE(tga_data); + return stbi__errpuc("bad palette", "Corrupt TGA"); + } + + // any data to skip? (offset usually = 0) + stbi__skip(s, tga_palette_start ); + // load the palette + tga_palette = (unsigned char*)stbi__malloc_mad2(tga_palette_len, tga_comp, 0); + if (!tga_palette) { + STBI_FREE(tga_data); + return stbi__errpuc("outofmem", "Out of memory"); + } + if (tga_rgb16) { + stbi_uc *pal_entry = tga_palette; + STBI_ASSERT(tga_comp == STBI_rgb); + for (i=0; i < tga_palette_len; ++i) { + stbi__tga_read_rgb16(s, pal_entry); + pal_entry += tga_comp; + } + } else if (!stbi__getn(s, tga_palette, tga_palette_len * tga_comp)) { + STBI_FREE(tga_data); + STBI_FREE(tga_palette); + return stbi__errpuc("bad palette", "Corrupt TGA"); + } + } + // load the data + for (i=0; i < tga_width * tga_height; ++i) + { + // if I'm in RLE mode, do I need to get a RLE stbi__pngchunk? + if ( tga_is_RLE ) + { + if ( RLE_count == 0 ) + { + // yep, get the next byte as a RLE command + int RLE_cmd = stbi__get8(s); + RLE_count = 1 + (RLE_cmd & 127); + RLE_repeating = RLE_cmd >> 7; + read_next_pixel = 1; + } else if ( !RLE_repeating ) + { + read_next_pixel = 1; + } + } else + { + read_next_pixel = 1; + } + // OK, if I need to read a pixel, do it now + if ( read_next_pixel ) + { + // load however much data we did have + if ( tga_indexed ) + { + // read in index, then perform the lookup + int pal_idx = (tga_bits_per_pixel == 8) ? stbi__get8(s) : stbi__get16le(s); + if ( pal_idx >= tga_palette_len ) { + // invalid index + pal_idx = 0; + } + pal_idx *= tga_comp; + for (j = 0; j < tga_comp; ++j) { + raw_data[j] = tga_palette[pal_idx+j]; + } + } else if(tga_rgb16) { + STBI_ASSERT(tga_comp == STBI_rgb); + stbi__tga_read_rgb16(s, raw_data); + } else { + // read in the data raw + for (j = 0; j < tga_comp; ++j) { + raw_data[j] = stbi__get8(s); + } + } + // clear the reading flag for the next pixel + read_next_pixel = 0; + } // end of reading a pixel + + // copy data + for (j = 0; j < tga_comp; ++j) + tga_data[i*tga_comp+j] = raw_data[j]; + + // in case we're in RLE mode, keep counting down + --RLE_count; + } + // do I need to invert the image? + if ( tga_inverted ) + { + for (j = 0; j*2 < tga_height; ++j) + { + int index1 = j * tga_width * tga_comp; + int index2 = (tga_height - 1 - j) * tga_width * tga_comp; + for (i = tga_width * tga_comp; i > 0; --i) + { + unsigned char temp = tga_data[index1]; + tga_data[index1] = tga_data[index2]; + tga_data[index2] = temp; + ++index1; + ++index2; + } + } + } + // clear my palette, if I had one + if ( tga_palette != NULL ) + { + STBI_FREE( tga_palette ); + } + } + + // swap RGB - if the source data was RGB16, it already is in the right order + if (tga_comp >= 3 && !tga_rgb16) + { + unsigned char* tga_pixel = tga_data; + for (i=0; i < tga_width * tga_height; ++i) + { + unsigned char temp = tga_pixel[0]; + tga_pixel[0] = tga_pixel[2]; + tga_pixel[2] = temp; + tga_pixel += tga_comp; + } + } + + // convert to target component count + if (req_comp && req_comp != tga_comp) + tga_data = stbi__convert_format(tga_data, tga_comp, req_comp, tga_width, tga_height); + + // the things I do to get rid of an error message, and yet keep + // Microsoft's C compilers happy... [8^( + tga_palette_start = tga_palette_len = tga_palette_bits = + tga_x_origin = tga_y_origin = 0; + STBI_NOTUSED(tga_palette_start); + // OK, done + return tga_data; +} +#endif + +// ************************************************************************************************* +// Photoshop PSD loader -- PD by Thatcher Ulrich, integration by Nicolas Schulz, tweaked by STB + +#ifndef STBI_NO_PSD +static int stbi__psd_test(stbi__context *s) +{ + int r = (stbi__get32be(s) == 0x38425053); + stbi__rewind(s); + return r; +} + +static int stbi__psd_decode_rle(stbi__context *s, stbi_uc *p, int pixelCount) +{ + int count, nleft, len; + + count = 0; + while ((nleft = pixelCount - count) > 0) { + len = stbi__get8(s); + if (len == 128) { + // No-op. + } else if (len < 128) { + // Copy next len+1 bytes literally. + len++; + if (len > nleft) return 0; // corrupt data + count += len; + while (len) { + *p = stbi__get8(s); + p += 4; + len--; + } + } else if (len > 128) { + stbi_uc val; + // Next -len+1 bytes in the dest are replicated from next source byte. + // (Interpret len as a negative 8-bit int.) + len = 257 - len; + if (len > nleft) return 0; // corrupt data + val = stbi__get8(s); + count += len; + while (len) { + *p = val; + p += 4; + len--; + } + } + } + + return 1; +} + +static void *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc) +{ + int pixelCount; + int channelCount, compression; + int channel, i; + int bitdepth; + int w,h; + stbi_uc *out; + STBI_NOTUSED(ri); + + // Check identifier + if (stbi__get32be(s) != 0x38425053) // "8BPS" + return stbi__errpuc("not PSD", "Corrupt PSD image"); + + // Check file type version. + if (stbi__get16be(s) != 1) + return stbi__errpuc("wrong version", "Unsupported version of PSD image"); + + // Skip 6 reserved bytes. + stbi__skip(s, 6 ); + + // Read the number of channels (R, G, B, A, etc). + channelCount = stbi__get16be(s); + if (channelCount < 0 || channelCount > 16) + return stbi__errpuc("wrong channel count", "Unsupported number of channels in PSD image"); + + // Read the rows and columns of the image. + h = stbi__get32be(s); + w = stbi__get32be(s); + + if (h > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + if (w > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + + // Make sure the depth is 8 bits. + bitdepth = stbi__get16be(s); + if (bitdepth != 8 && bitdepth != 16) + return stbi__errpuc("unsupported bit depth", "PSD bit depth is not 8 or 16 bit"); + + // Make sure the color mode is RGB. + // Valid options are: + // 0: Bitmap + // 1: Grayscale + // 2: Indexed color + // 3: RGB color + // 4: CMYK color + // 7: Multichannel + // 8: Duotone + // 9: Lab color + if (stbi__get16be(s) != 3) + return stbi__errpuc("wrong color format", "PSD is not in RGB color format"); + + // Skip the Mode Data. (It's the palette for indexed color; other info for other modes.) + stbi__skip(s,stbi__get32be(s) ); + + // Skip the image resources. (resolution, pen tool paths, etc) + stbi__skip(s, stbi__get32be(s) ); + + // Skip the reserved data. + stbi__skip(s, stbi__get32be(s) ); + + // Find out if the data is compressed. + // Known values: + // 0: no compression + // 1: RLE compressed + compression = stbi__get16be(s); + if (compression > 1) + return stbi__errpuc("bad compression", "PSD has an unknown compression format"); + + // Check size + if (!stbi__mad3sizes_valid(4, w, h, 0)) + return stbi__errpuc("too large", "Corrupt PSD"); + + // Create the destination image. + + if (!compression && bitdepth == 16 && bpc == 16) { + out = (stbi_uc *) stbi__malloc_mad3(8, w, h, 0); + ri->bits_per_channel = 16; + } else + out = (stbi_uc *) stbi__malloc(4 * w*h); + + if (!out) return stbi__errpuc("outofmem", "Out of memory"); + pixelCount = w*h; + + // Initialize the data to zero. + //memset( out, 0, pixelCount * 4 ); + + // Finally, the image data. + if (compression) { + // RLE as used by .PSD and .TIFF + // Loop until you get the number of unpacked bytes you are expecting: + // Read the next source byte into n. + // If n is between 0 and 127 inclusive, copy the next n+1 bytes literally. + // Else if n is between -127 and -1 inclusive, copy the next byte -n+1 times. + // Else if n is 128, noop. + // Endloop + + // The RLE-compressed data is preceded by a 2-byte data count for each row in the data, + // which we're going to just skip. + stbi__skip(s, h * channelCount * 2 ); + + // Read the RLE data by channel. + for (channel = 0; channel < 4; channel++) { + stbi_uc *p; + + p = out+channel; + if (channel >= channelCount) { + // Fill this channel with default data. + for (i = 0; i < pixelCount; i++, p += 4) + *p = (channel == 3 ? 255 : 0); + } else { + // Read the RLE data. + if (!stbi__psd_decode_rle(s, p, pixelCount)) { + STBI_FREE(out); + return stbi__errpuc("corrupt", "bad RLE data"); + } + } + } + + } else { + // We're at the raw image data. It's each channel in order (Red, Green, Blue, Alpha, ...) + // where each channel consists of an 8-bit (or 16-bit) value for each pixel in the image. + + // Read the data by channel. + for (channel = 0; channel < 4; channel++) { + if (channel >= channelCount) { + // Fill this channel with default data. + if (bitdepth == 16 && bpc == 16) { + stbi__uint16 *q = ((stbi__uint16 *) out) + channel; + stbi__uint16 val = channel == 3 ? 65535 : 0; + for (i = 0; i < pixelCount; i++, q += 4) + *q = val; + } else { + stbi_uc *p = out+channel; + stbi_uc val = channel == 3 ? 255 : 0; + for (i = 0; i < pixelCount; i++, p += 4) + *p = val; + } + } else { + if (ri->bits_per_channel == 16) { // output bpc + stbi__uint16 *q = ((stbi__uint16 *) out) + channel; + for (i = 0; i < pixelCount; i++, q += 4) + *q = (stbi__uint16) stbi__get16be(s); + } else { + stbi_uc *p = out+channel; + if (bitdepth == 16) { // input bpc + for (i = 0; i < pixelCount; i++, p += 4) + *p = (stbi_uc) (stbi__get16be(s) >> 8); + } else { + for (i = 0; i < pixelCount; i++, p += 4) + *p = stbi__get8(s); + } + } + } + } + } + + // remove weird white matte from PSD + if (channelCount >= 4) { + if (ri->bits_per_channel == 16) { + for (i=0; i < w*h; ++i) { + stbi__uint16 *pixel = (stbi__uint16 *) out + 4*i; + if (pixel[3] != 0 && pixel[3] != 65535) { + float a = pixel[3] / 65535.0f; + float ra = 1.0f / a; + float inv_a = 65535.0f * (1 - ra); + pixel[0] = (stbi__uint16) (pixel[0]*ra + inv_a); + pixel[1] = (stbi__uint16) (pixel[1]*ra + inv_a); + pixel[2] = (stbi__uint16) (pixel[2]*ra + inv_a); + } + } + } else { + for (i=0; i < w*h; ++i) { + unsigned char *pixel = out + 4*i; + if (pixel[3] != 0 && pixel[3] != 255) { + float a = pixel[3] / 255.0f; + float ra = 1.0f / a; + float inv_a = 255.0f * (1 - ra); + pixel[0] = (unsigned char) (pixel[0]*ra + inv_a); + pixel[1] = (unsigned char) (pixel[1]*ra + inv_a); + pixel[2] = (unsigned char) (pixel[2]*ra + inv_a); + } + } + } + } + + // convert to desired output format + if (req_comp && req_comp != 4) { + if (ri->bits_per_channel == 16) + out = (stbi_uc *) stbi__convert_format16((stbi__uint16 *) out, 4, req_comp, w, h); + else + out = stbi__convert_format(out, 4, req_comp, w, h); + if (out == NULL) return out; // stbi__convert_format frees input on failure + } + + if (comp) *comp = 4; + *y = h; + *x = w; + + return out; +} +#endif + +// ************************************************************************************************* +// Softimage PIC loader +// by Tom Seddon +// +// See http://softimage.wiki.softimage.com/index.php/INFO:_PIC_file_format +// See http://ozviz.wasp.uwa.edu.au/~pbourke/dataformats/softimagepic/ + +#ifndef STBI_NO_PIC +static int stbi__pic_is4(stbi__context *s,const char *str) +{ + int i; + for (i=0; i<4; ++i) + if (stbi__get8(s) != (stbi_uc)str[i]) + return 0; + + return 1; +} + +static int stbi__pic_test_core(stbi__context *s) +{ + int i; + + if (!stbi__pic_is4(s,"\x53\x80\xF6\x34")) + return 0; + + for(i=0;i<84;++i) + stbi__get8(s); + + if (!stbi__pic_is4(s,"PICT")) + return 0; + + return 1; +} + +typedef struct +{ + stbi_uc size,type,channel; +} stbi__pic_packet; + +static stbi_uc *stbi__readval(stbi__context *s, int channel, stbi_uc *dest) +{ + int mask=0x80, i; + + for (i=0; i<4; ++i, mask>>=1) { + if (channel & mask) { + if (stbi__at_eof(s)) return stbi__errpuc("bad file","PIC file too short"); + dest[i]=stbi__get8(s); + } + } + + return dest; +} + +static void stbi__copyval(int channel,stbi_uc *dest,const stbi_uc *src) +{ + int mask=0x80,i; + + for (i=0;i<4; ++i, mask>>=1) + if (channel&mask) + dest[i]=src[i]; +} + +static stbi_uc *stbi__pic_load_core(stbi__context *s,int width,int height,int *comp, stbi_uc *result) +{ + int act_comp=0,num_packets=0,y,chained; + stbi__pic_packet packets[10]; + + // this will (should...) cater for even some bizarre stuff like having data + // for the same channel in multiple packets. + do { + stbi__pic_packet *packet; + + if (num_packets==sizeof(packets)/sizeof(packets[0])) + return stbi__errpuc("bad format","too many packets"); + + packet = &packets[num_packets++]; + + chained = stbi__get8(s); + packet->size = stbi__get8(s); + packet->type = stbi__get8(s); + packet->channel = stbi__get8(s); + + act_comp |= packet->channel; + + if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (reading packets)"); + if (packet->size != 8) return stbi__errpuc("bad format","packet isn't 8bpp"); + } while (chained); + + *comp = (act_comp & 0x10 ? 4 : 3); // has alpha channel? + + for(y=0; ytype) { + default: + return stbi__errpuc("bad format","packet has bad compression type"); + + case 0: {//uncompressed + int x; + + for(x=0;xchannel,dest)) + return 0; + break; + } + + case 1://Pure RLE + { + int left=width, i; + + while (left>0) { + stbi_uc count,value[4]; + + count=stbi__get8(s); + if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (pure read count)"); + + if (count > left) + count = (stbi_uc) left; + + if (!stbi__readval(s,packet->channel,value)) return 0; + + for(i=0; ichannel,dest,value); + left -= count; + } + } + break; + + case 2: {//Mixed RLE + int left=width; + while (left>0) { + int count = stbi__get8(s), i; + if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (mixed read count)"); + + if (count >= 128) { // Repeated + stbi_uc value[4]; + + if (count==128) + count = stbi__get16be(s); + else + count -= 127; + if (count > left) + return stbi__errpuc("bad file","scanline overrun"); + + if (!stbi__readval(s,packet->channel,value)) + return 0; + + for(i=0;ichannel,dest,value); + } else { // Raw + ++count; + if (count>left) return stbi__errpuc("bad file","scanline overrun"); + + for(i=0;ichannel,dest)) + return 0; + } + left-=count; + } + break; + } + } + } + } + + return result; +} + +static void *stbi__pic_load(stbi__context *s,int *px,int *py,int *comp,int req_comp, stbi__result_info *ri) +{ + stbi_uc *result; + int i, x,y, internal_comp; + STBI_NOTUSED(ri); + + if (!comp) comp = &internal_comp; + + for (i=0; i<92; ++i) + stbi__get8(s); + + x = stbi__get16be(s); + y = stbi__get16be(s); + + if (y > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + if (x > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + + if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (pic header)"); + if (!stbi__mad3sizes_valid(x, y, 4, 0)) return stbi__errpuc("too large", "PIC image too large to decode"); + + stbi__get32be(s); //skip `ratio' + stbi__get16be(s); //skip `fields' + stbi__get16be(s); //skip `pad' + + // intermediate buffer is RGBA + result = (stbi_uc *) stbi__malloc_mad3(x, y, 4, 0); + if (!result) return stbi__errpuc("outofmem", "Out of memory"); + memset(result, 0xff, x*y*4); + + if (!stbi__pic_load_core(s,x,y,comp, result)) { + STBI_FREE(result); + result=0; + } + *px = x; + *py = y; + if (req_comp == 0) req_comp = *comp; + result=stbi__convert_format(result,4,req_comp,x,y); + + return result; +} + +static int stbi__pic_test(stbi__context *s) +{ + int r = stbi__pic_test_core(s); + stbi__rewind(s); + return r; +} +#endif + +// ************************************************************************************************* +// GIF loader -- public domain by Jean-Marc Lienher -- simplified/shrunk by stb + +#ifndef STBI_NO_GIF +typedef struct +{ + stbi__int16 prefix; + stbi_uc first; + stbi_uc suffix; +} stbi__gif_lzw; + +typedef struct +{ + int w,h; + stbi_uc *out; // output buffer (always 4 components) + stbi_uc *background; // The current "background" as far as a gif is concerned + stbi_uc *history; + int flags, bgindex, ratio, transparent, eflags; + stbi_uc pal[256][4]; + stbi_uc lpal[256][4]; + stbi__gif_lzw codes[8192]; + stbi_uc *color_table; + int parse, step; + int lflags; + int start_x, start_y; + int max_x, max_y; + int cur_x, cur_y; + int line_size; + int delay; +} stbi__gif; + +static int stbi__gif_test_raw(stbi__context *s) +{ + int sz; + if (stbi__get8(s) != 'G' || stbi__get8(s) != 'I' || stbi__get8(s) != 'F' || stbi__get8(s) != '8') return 0; + sz = stbi__get8(s); + if (sz != '9' && sz != '7') return 0; + if (stbi__get8(s) != 'a') return 0; + return 1; +} + +static int stbi__gif_test(stbi__context *s) +{ + int r = stbi__gif_test_raw(s); + stbi__rewind(s); + return r; +} + +static void stbi__gif_parse_colortable(stbi__context *s, stbi_uc pal[256][4], int num_entries, int transp) +{ + int i; + for (i=0; i < num_entries; ++i) { + pal[i][2] = stbi__get8(s); + pal[i][1] = stbi__get8(s); + pal[i][0] = stbi__get8(s); + pal[i][3] = transp == i ? 0 : 255; + } +} + +static int stbi__gif_header(stbi__context *s, stbi__gif *g, int *comp, int is_info) +{ + stbi_uc version; + if (stbi__get8(s) != 'G' || stbi__get8(s) != 'I' || stbi__get8(s) != 'F' || stbi__get8(s) != '8') + return stbi__err("not GIF", "Corrupt GIF"); + + version = stbi__get8(s); + if (version != '7' && version != '9') return stbi__err("not GIF", "Corrupt GIF"); + if (stbi__get8(s) != 'a') return stbi__err("not GIF", "Corrupt GIF"); + + stbi__g_failure_reason = ""; + g->w = stbi__get16le(s); + g->h = stbi__get16le(s); + g->flags = stbi__get8(s); + g->bgindex = stbi__get8(s); + g->ratio = stbi__get8(s); + g->transparent = -1; + + if (g->w > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); + if (g->h > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); + + if (comp != 0) *comp = 4; // can't actually tell whether it's 3 or 4 until we parse the comments + + if (is_info) return 1; + + if (g->flags & 0x80) + stbi__gif_parse_colortable(s,g->pal, 2 << (g->flags & 7), -1); + + return 1; +} + +static int stbi__gif_info_raw(stbi__context *s, int *x, int *y, int *comp) +{ + stbi__gif* g = (stbi__gif*) stbi__malloc(sizeof(stbi__gif)); + if (!g) return stbi__err("outofmem", "Out of memory"); + if (!stbi__gif_header(s, g, comp, 1)) { + STBI_FREE(g); + stbi__rewind( s ); + return 0; + } + if (x) *x = g->w; + if (y) *y = g->h; + STBI_FREE(g); + return 1; +} + +static void stbi__out_gif_code(stbi__gif *g, stbi__uint16 code) +{ + stbi_uc *p, *c; + int idx; + + // recurse to decode the prefixes, since the linked-list is backwards, + // and working backwards through an interleaved image would be nasty + if (g->codes[code].prefix >= 0) + stbi__out_gif_code(g, g->codes[code].prefix); + + if (g->cur_y >= g->max_y) return; + + idx = g->cur_x + g->cur_y; + p = &g->out[idx]; + g->history[idx / 4] = 1; + + c = &g->color_table[g->codes[code].suffix * 4]; + if (c[3] > 128) { // don't render transparent pixels; + p[0] = c[2]; + p[1] = c[1]; + p[2] = c[0]; + p[3] = c[3]; + } + g->cur_x += 4; + + if (g->cur_x >= g->max_x) { + g->cur_x = g->start_x; + g->cur_y += g->step; + + while (g->cur_y >= g->max_y && g->parse > 0) { + g->step = (1 << g->parse) * g->line_size; + g->cur_y = g->start_y + (g->step >> 1); + --g->parse; + } + } +} + +static stbi_uc *stbi__process_gif_raster(stbi__context *s, stbi__gif *g) +{ + stbi_uc lzw_cs; + stbi__int32 len, init_code; + stbi__uint32 first; + stbi__int32 codesize, codemask, avail, oldcode, bits, valid_bits, clear; + stbi__gif_lzw *p; + + lzw_cs = stbi__get8(s); + if (lzw_cs > 12) return NULL; + clear = 1 << lzw_cs; + first = 1; + codesize = lzw_cs + 1; + codemask = (1 << codesize) - 1; + bits = 0; + valid_bits = 0; + for (init_code = 0; init_code < clear; init_code++) { + g->codes[init_code].prefix = -1; + g->codes[init_code].first = (stbi_uc) init_code; + g->codes[init_code].suffix = (stbi_uc) init_code; + } + + // support no starting clear code + avail = clear+2; + oldcode = -1; + + len = 0; + for(;;) { + if (valid_bits < codesize) { + if (len == 0) { + len = stbi__get8(s); // start new block + if (len == 0) + return g->out; + } + --len; + bits |= (stbi__int32) stbi__get8(s) << valid_bits; + valid_bits += 8; + } else { + stbi__int32 code = bits & codemask; + bits >>= codesize; + valid_bits -= codesize; + // @OPTIMIZE: is there some way we can accelerate the non-clear path? + if (code == clear) { // clear code + codesize = lzw_cs + 1; + codemask = (1 << codesize) - 1; + avail = clear + 2; + oldcode = -1; + first = 0; + } else if (code == clear + 1) { // end of stream code + stbi__skip(s, len); + while ((len = stbi__get8(s)) > 0) + stbi__skip(s,len); + return g->out; + } else if (code <= avail) { + if (first) { + return stbi__errpuc("no clear code", "Corrupt GIF"); + } + + if (oldcode >= 0) { + p = &g->codes[avail++]; + if (avail > 8192) { + return stbi__errpuc("too many codes", "Corrupt GIF"); + } + + p->prefix = (stbi__int16) oldcode; + p->first = g->codes[oldcode].first; + p->suffix = (code == avail) ? p->first : g->codes[code].first; + } else if (code == avail) + return stbi__errpuc("illegal code in raster", "Corrupt GIF"); + + stbi__out_gif_code(g, (stbi__uint16) code); + + if ((avail & codemask) == 0 && avail <= 0x0FFF) { + codesize++; + codemask = (1 << codesize) - 1; + } + + oldcode = code; + } else { + return stbi__errpuc("illegal code in raster", "Corrupt GIF"); + } + } + } +} + +// this function is designed to support animated gifs, although stb_image doesn't support it +// two back is the image from two frames ago, used for a very specific disposal format +static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, int req_comp, stbi_uc *two_back) +{ + int dispose; + int first_frame; + int pi; + int pcount; + STBI_NOTUSED(req_comp); + + // on first frame, any non-written pixels get the background colour (non-transparent) + first_frame = 0; + if (g->out == 0) { + if (!stbi__gif_header(s, g, comp,0)) return 0; // stbi__g_failure_reason set by stbi__gif_header + if (!stbi__mad3sizes_valid(4, g->w, g->h, 0)) + return stbi__errpuc("too large", "GIF image is too large"); + pcount = g->w * g->h; + g->out = (stbi_uc *) stbi__malloc(4 * pcount); + g->background = (stbi_uc *) stbi__malloc(4 * pcount); + g->history = (stbi_uc *) stbi__malloc(pcount); + if (!g->out || !g->background || !g->history) + return stbi__errpuc("outofmem", "Out of memory"); + + // image is treated as "transparent" at the start - ie, nothing overwrites the current background; + // background colour is only used for pixels that are not rendered first frame, after that "background" + // color refers to the color that was there the previous frame. + memset(g->out, 0x00, 4 * pcount); + memset(g->background, 0x00, 4 * pcount); // state of the background (starts transparent) + memset(g->history, 0x00, pcount); // pixels that were affected previous frame + first_frame = 1; + } else { + // second frame - how do we dispose of the previous one? + dispose = (g->eflags & 0x1C) >> 2; + pcount = g->w * g->h; + + if ((dispose == 3) && (two_back == 0)) { + dispose = 2; // if I don't have an image to revert back to, default to the old background + } + + if (dispose == 3) { // use previous graphic + for (pi = 0; pi < pcount; ++pi) { + if (g->history[pi]) { + memcpy( &g->out[pi * 4], &two_back[pi * 4], 4 ); + } + } + } else if (dispose == 2) { + // restore what was changed last frame to background before that frame; + for (pi = 0; pi < pcount; ++pi) { + if (g->history[pi]) { + memcpy( &g->out[pi * 4], &g->background[pi * 4], 4 ); + } + } + } else { + // This is a non-disposal case eithe way, so just + // leave the pixels as is, and they will become the new background + // 1: do not dispose + // 0: not specified. + } + + // background is what out is after the undoing of the previou frame; + memcpy( g->background, g->out, 4 * g->w * g->h ); + } + + // clear my history; + memset( g->history, 0x00, g->w * g->h ); // pixels that were affected previous frame + + for (;;) { + int tag = stbi__get8(s); + switch (tag) { + case 0x2C: /* Image Descriptor */ + { + stbi__int32 x, y, w, h; + stbi_uc *o; + + x = stbi__get16le(s); + y = stbi__get16le(s); + w = stbi__get16le(s); + h = stbi__get16le(s); + if (((x + w) > (g->w)) || ((y + h) > (g->h))) + return stbi__errpuc("bad Image Descriptor", "Corrupt GIF"); + + g->line_size = g->w * 4; + g->start_x = x * 4; + g->start_y = y * g->line_size; + g->max_x = g->start_x + w * 4; + g->max_y = g->start_y + h * g->line_size; + g->cur_x = g->start_x; + g->cur_y = g->start_y; + + // if the width of the specified rectangle is 0, that means + // we may not see *any* pixels or the image is malformed; + // to make sure this is caught, move the current y down to + // max_y (which is what out_gif_code checks). + if (w == 0) + g->cur_y = g->max_y; + + g->lflags = stbi__get8(s); + + if (g->lflags & 0x40) { + g->step = 8 * g->line_size; // first interlaced spacing + g->parse = 3; + } else { + g->step = g->line_size; + g->parse = 0; + } + + if (g->lflags & 0x80) { + stbi__gif_parse_colortable(s,g->lpal, 2 << (g->lflags & 7), g->eflags & 0x01 ? g->transparent : -1); + g->color_table = (stbi_uc *) g->lpal; + } else if (g->flags & 0x80) { + g->color_table = (stbi_uc *) g->pal; + } else + return stbi__errpuc("missing color table", "Corrupt GIF"); + + o = stbi__process_gif_raster(s, g); + if (!o) return NULL; + + // if this was the first frame, + pcount = g->w * g->h; + if (first_frame && (g->bgindex > 0)) { + // if first frame, any pixel not drawn to gets the background color + for (pi = 0; pi < pcount; ++pi) { + if (g->history[pi] == 0) { + g->pal[g->bgindex][3] = 255; // just in case it was made transparent, undo that; It will be reset next frame if need be; + memcpy( &g->out[pi * 4], &g->pal[g->bgindex], 4 ); + } + } + } + + return o; + } + + case 0x21: // Comment Extension. + { + int len; + int ext = stbi__get8(s); + if (ext == 0xF9) { // Graphic Control Extension. + len = stbi__get8(s); + if (len == 4) { + g->eflags = stbi__get8(s); + g->delay = 10 * stbi__get16le(s); // delay - 1/100th of a second, saving as 1/1000ths. + + // unset old transparent + if (g->transparent >= 0) { + g->pal[g->transparent][3] = 255; + } + if (g->eflags & 0x01) { + g->transparent = stbi__get8(s); + if (g->transparent >= 0) { + g->pal[g->transparent][3] = 0; + } + } else { + // don't need transparent + stbi__skip(s, 1); + g->transparent = -1; + } + } else { + stbi__skip(s, len); + break; + } + } + while ((len = stbi__get8(s)) != 0) { + stbi__skip(s, len); + } + break; + } + + case 0x3B: // gif stream termination code + return (stbi_uc *) s; // using '1' causes warning on some compilers + + default: + return stbi__errpuc("unknown code", "Corrupt GIF"); + } + } +} + +static void *stbi__load_gif_main_outofmem(stbi__gif *g, stbi_uc *out, int **delays) +{ + STBI_FREE(g->out); + STBI_FREE(g->history); + STBI_FREE(g->background); + + if (out) STBI_FREE(out); + if (delays && *delays) STBI_FREE(*delays); + return stbi__errpuc("outofmem", "Out of memory"); +} + +static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, int *z, int *comp, int req_comp) +{ + if (stbi__gif_test(s)) { + int layers = 0; + stbi_uc *u = 0; + stbi_uc *out = 0; + stbi_uc *two_back = 0; + stbi__gif g; + int stride; + int out_size = 0; + int delays_size = 0; + + STBI_NOTUSED(out_size); + STBI_NOTUSED(delays_size); + + memset(&g, 0, sizeof(g)); + if (delays) { + *delays = 0; + } + + do { + u = stbi__gif_load_next(s, &g, comp, req_comp, two_back); + if (u == (stbi_uc *) s) u = 0; // end of animated gif marker + + if (u) { + *x = g.w; + *y = g.h; + ++layers; + stride = g.w * g.h * 4; + + if (out) { + void *tmp = (stbi_uc*) STBI_REALLOC_SIZED( out, out_size, layers * stride ); + if (!tmp) + return stbi__load_gif_main_outofmem(&g, out, delays); + else { + out = (stbi_uc*) tmp; + out_size = layers * stride; + } + + if (delays) { + int *new_delays = (int*) STBI_REALLOC_SIZED( *delays, delays_size, sizeof(int) * layers ); + if (!new_delays) + return stbi__load_gif_main_outofmem(&g, out, delays); + *delays = new_delays; + delays_size = layers * sizeof(int); + } + } else { + out = (stbi_uc*)stbi__malloc( layers * stride ); + if (!out) + return stbi__load_gif_main_outofmem(&g, out, delays); + out_size = layers * stride; + if (delays) { + *delays = (int*) stbi__malloc( layers * sizeof(int) ); + if (!*delays) + return stbi__load_gif_main_outofmem(&g, out, delays); + delays_size = layers * sizeof(int); + } + } + memcpy( out + ((layers - 1) * stride), u, stride ); + if (layers >= 2) { + two_back = out - 2 * stride; + } + + if (delays) { + (*delays)[layers - 1U] = g.delay; + } + } + } while (u != 0); + + // free temp buffer; + STBI_FREE(g.out); + STBI_FREE(g.history); + STBI_FREE(g.background); + + // do the final conversion after loading everything; + if (req_comp && req_comp != 4) + out = stbi__convert_format(out, 4, req_comp, layers * g.w, g.h); + + *z = layers; + return out; + } else { + return stbi__errpuc("not GIF", "Image was not as a gif type."); + } +} + +static void *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + stbi_uc *u = 0; + stbi__gif g; + memset(&g, 0, sizeof(g)); + STBI_NOTUSED(ri); + + u = stbi__gif_load_next(s, &g, comp, req_comp, 0); + if (u == (stbi_uc *) s) u = 0; // end of animated gif marker + if (u) { + *x = g.w; + *y = g.h; + + // moved conversion to after successful load so that the same + // can be done for multiple frames. + if (req_comp && req_comp != 4) + u = stbi__convert_format(u, 4, req_comp, g.w, g.h); + } else if (g.out) { + // if there was an error and we allocated an image buffer, free it! + STBI_FREE(g.out); + } + + // free buffers needed for multiple frame loading; + STBI_FREE(g.history); + STBI_FREE(g.background); + + return u; +} + +static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp) +{ + return stbi__gif_info_raw(s,x,y,comp); +} +#endif + +// ************************************************************************************************* +// Radiance RGBE HDR loader +// originally by Nicolas Schulz +#ifndef STBI_NO_HDR +static int stbi__hdr_test_core(stbi__context *s, const char *signature) +{ + int i; + for (i=0; signature[i]; ++i) + if (stbi__get8(s) != signature[i]) + return 0; + stbi__rewind(s); + return 1; +} + +static int stbi__hdr_test(stbi__context* s) +{ + int r = stbi__hdr_test_core(s, "#?RADIANCE\n"); + stbi__rewind(s); + if(!r) { + r = stbi__hdr_test_core(s, "#?RGBE\n"); + stbi__rewind(s); + } + return r; +} + +#define STBI__HDR_BUFLEN 1024 +static char *stbi__hdr_gettoken(stbi__context *z, char *buffer) +{ + int len=0; + char c = '\0'; + + c = (char) stbi__get8(z); + + while (!stbi__at_eof(z) && c != '\n') { + buffer[len++] = c; + if (len == STBI__HDR_BUFLEN-1) { + // flush to end of line + while (!stbi__at_eof(z) && stbi__get8(z) != '\n') + ; + break; + } + c = (char) stbi__get8(z); + } + + buffer[len] = 0; + return buffer; +} + +static void stbi__hdr_convert(float *output, stbi_uc *input, int req_comp) +{ + if ( input[3] != 0 ) { + float f1; + // Exponent + f1 = (float) ldexp(1.0f, input[3] - (int)(128 + 8)); + if (req_comp <= 2) + output[0] = (input[0] + input[1] + input[2]) * f1 / 3; + else { + output[0] = input[0] * f1; + output[1] = input[1] * f1; + output[2] = input[2] * f1; + } + if (req_comp == 2) output[1] = 1; + if (req_comp == 4) output[3] = 1; + } else { + switch (req_comp) { + case 4: output[3] = 1; /* fallthrough */ + case 3: output[0] = output[1] = output[2] = 0; + break; + case 2: output[1] = 1; /* fallthrough */ + case 1: output[0] = 0; + break; + } + } +} + +static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + char buffer[STBI__HDR_BUFLEN]; + char *token; + int valid = 0; + int width, height; + stbi_uc *scanline; + float *hdr_data; + int len; + unsigned char count, value; + int i, j, k, c1,c2, z; + const char *headerToken; + STBI_NOTUSED(ri); + + // Check identifier + headerToken = stbi__hdr_gettoken(s,buffer); + if (strcmp(headerToken, "#?RADIANCE") != 0 && strcmp(headerToken, "#?RGBE") != 0) + return stbi__errpf("not HDR", "Corrupt HDR image"); + + // Parse header + for(;;) { + token = stbi__hdr_gettoken(s,buffer); + if (token[0] == 0) break; + if (strcmp(token, "FORMAT=32-bit_rle_rgbe") == 0) valid = 1; + } + + if (!valid) return stbi__errpf("unsupported format", "Unsupported HDR format"); + + // Parse width and height + // can't use sscanf() if we're not using stdio! + token = stbi__hdr_gettoken(s,buffer); + if (strncmp(token, "-Y ", 3)) return stbi__errpf("unsupported data layout", "Unsupported HDR format"); + token += 3; + height = (int) strtol(token, &token, 10); + while (*token == ' ') ++token; + if (strncmp(token, "+X ", 3)) return stbi__errpf("unsupported data layout", "Unsupported HDR format"); + token += 3; + width = (int) strtol(token, NULL, 10); + + if (height > STBI_MAX_DIMENSIONS) return stbi__errpf("too large","Very large image (corrupt?)"); + if (width > STBI_MAX_DIMENSIONS) return stbi__errpf("too large","Very large image (corrupt?)"); + + *x = width; + *y = height; + + if (comp) *comp = 3; + if (req_comp == 0) req_comp = 3; + + if (!stbi__mad4sizes_valid(width, height, req_comp, sizeof(float), 0)) + return stbi__errpf("too large", "HDR image is too large"); + + // Read data + hdr_data = (float *) stbi__malloc_mad4(width, height, req_comp, sizeof(float), 0); + if (!hdr_data) + return stbi__errpf("outofmem", "Out of memory"); + + // Load image data + // image data is stored as some number of sca + if ( width < 8 || width >= 32768) { + // Read flat data + for (j=0; j < height; ++j) { + for (i=0; i < width; ++i) { + stbi_uc rgbe[4]; + main_decode_loop: + stbi__getn(s, rgbe, 4); + stbi__hdr_convert(hdr_data + j * width * req_comp + i * req_comp, rgbe, req_comp); + } + } + } else { + // Read RLE-encoded data + scanline = NULL; + + for (j = 0; j < height; ++j) { + c1 = stbi__get8(s); + c2 = stbi__get8(s); + len = stbi__get8(s); + if (c1 != 2 || c2 != 2 || (len & 0x80)) { + // not run-length encoded, so we have to actually use THIS data as a decoded + // pixel (note this can't be a valid pixel--one of RGB must be >= 128) + stbi_uc rgbe[4]; + rgbe[0] = (stbi_uc) c1; + rgbe[1] = (stbi_uc) c2; + rgbe[2] = (stbi_uc) len; + rgbe[3] = (stbi_uc) stbi__get8(s); + stbi__hdr_convert(hdr_data, rgbe, req_comp); + i = 1; + j = 0; + STBI_FREE(scanline); + goto main_decode_loop; // yes, this makes no sense + } + len <<= 8; + len |= stbi__get8(s); + if (len != width) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("invalid decoded scanline length", "corrupt HDR"); } + if (scanline == NULL) { + scanline = (stbi_uc *) stbi__malloc_mad2(width, 4, 0); + if (!scanline) { + STBI_FREE(hdr_data); + return stbi__errpf("outofmem", "Out of memory"); + } + } + + for (k = 0; k < 4; ++k) { + int nleft; + i = 0; + while ((nleft = width - i) > 0) { + count = stbi__get8(s); + if (count > 128) { + // Run + value = stbi__get8(s); + count -= 128; + if ((count == 0) || (count > nleft)) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("corrupt", "bad RLE data in HDR"); } + for (z = 0; z < count; ++z) + scanline[i++ * 4 + k] = value; + } else { + // Dump + if ((count == 0) || (count > nleft)) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("corrupt", "bad RLE data in HDR"); } + for (z = 0; z < count; ++z) + scanline[i++ * 4 + k] = stbi__get8(s); + } + } + } + for (i=0; i < width; ++i) + stbi__hdr_convert(hdr_data+(j*width + i)*req_comp, scanline + i*4, req_comp); + } + if (scanline) + STBI_FREE(scanline); + } + + return hdr_data; +} + +static int stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp) +{ + char buffer[STBI__HDR_BUFLEN]; + char *token; + int valid = 0; + int dummy; + + if (!x) x = &dummy; + if (!y) y = &dummy; + if (!comp) comp = &dummy; + + if (stbi__hdr_test(s) == 0) { + stbi__rewind( s ); + return 0; + } + + for(;;) { + token = stbi__hdr_gettoken(s,buffer); + if (token[0] == 0) break; + if (strcmp(token, "FORMAT=32-bit_rle_rgbe") == 0) valid = 1; + } + + if (!valid) { + stbi__rewind( s ); + return 0; + } + token = stbi__hdr_gettoken(s,buffer); + if (strncmp(token, "-Y ", 3)) { + stbi__rewind( s ); + return 0; + } + token += 3; + *y = (int) strtol(token, &token, 10); + while (*token == ' ') ++token; + if (strncmp(token, "+X ", 3)) { + stbi__rewind( s ); + return 0; + } + token += 3; + *x = (int) strtol(token, NULL, 10); + *comp = 3; + return 1; +} +#endif // STBI_NO_HDR + +#ifndef STBI_NO_BMP +static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp) +{ + void *p; + stbi__bmp_data info; + + info.all_a = 255; + p = stbi__bmp_parse_header(s, &info); + if (p == NULL) { + stbi__rewind( s ); + return 0; + } + if (x) *x = s->img_x; + if (y) *y = s->img_y; + if (comp) { + if (info.bpp == 24 && info.ma == 0xff000000) + *comp = 3; + else + *comp = info.ma ? 4 : 3; + } + return 1; +} +#endif + +#ifndef STBI_NO_PSD +static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp) +{ + int channelCount, dummy, depth; + if (!x) x = &dummy; + if (!y) y = &dummy; + if (!comp) comp = &dummy; + if (stbi__get32be(s) != 0x38425053) { + stbi__rewind( s ); + return 0; + } + if (stbi__get16be(s) != 1) { + stbi__rewind( s ); + return 0; + } + stbi__skip(s, 6); + channelCount = stbi__get16be(s); + if (channelCount < 0 || channelCount > 16) { + stbi__rewind( s ); + return 0; + } + *y = stbi__get32be(s); + *x = stbi__get32be(s); + depth = stbi__get16be(s); + if (depth != 8 && depth != 16) { + stbi__rewind( s ); + return 0; + } + if (stbi__get16be(s) != 3) { + stbi__rewind( s ); + return 0; + } + *comp = 4; + return 1; +} + +static int stbi__psd_is16(stbi__context *s) +{ + int channelCount, depth; + if (stbi__get32be(s) != 0x38425053) { + stbi__rewind( s ); + return 0; + } + if (stbi__get16be(s) != 1) { + stbi__rewind( s ); + return 0; + } + stbi__skip(s, 6); + channelCount = stbi__get16be(s); + if (channelCount < 0 || channelCount > 16) { + stbi__rewind( s ); + return 0; + } + STBI_NOTUSED(stbi__get32be(s)); + STBI_NOTUSED(stbi__get32be(s)); + depth = stbi__get16be(s); + if (depth != 16) { + stbi__rewind( s ); + return 0; + } + return 1; +} +#endif + +#ifndef STBI_NO_PIC +static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp) +{ + int act_comp=0,num_packets=0,chained,dummy; + stbi__pic_packet packets[10]; + + if (!x) x = &dummy; + if (!y) y = &dummy; + if (!comp) comp = &dummy; + + if (!stbi__pic_is4(s,"\x53\x80\xF6\x34")) { + stbi__rewind(s); + return 0; + } + + stbi__skip(s, 88); + + *x = stbi__get16be(s); + *y = stbi__get16be(s); + if (stbi__at_eof(s)) { + stbi__rewind( s); + return 0; + } + if ( (*x) != 0 && (1 << 28) / (*x) < (*y)) { + stbi__rewind( s ); + return 0; + } + + stbi__skip(s, 8); + + do { + stbi__pic_packet *packet; + + if (num_packets==sizeof(packets)/sizeof(packets[0])) + return 0; + + packet = &packets[num_packets++]; + chained = stbi__get8(s); + packet->size = stbi__get8(s); + packet->type = stbi__get8(s); + packet->channel = stbi__get8(s); + act_comp |= packet->channel; + + if (stbi__at_eof(s)) { + stbi__rewind( s ); + return 0; + } + if (packet->size != 8) { + stbi__rewind( s ); + return 0; + } + } while (chained); + + *comp = (act_comp & 0x10 ? 4 : 3); + + return 1; +} +#endif + +// ************************************************************************************************* +// Portable Gray Map and Portable Pixel Map loader +// by Ken Miller +// +// PGM: http://netpbm.sourceforge.net/doc/pgm.html +// PPM: http://netpbm.sourceforge.net/doc/ppm.html +// +// Known limitations: +// Does not support comments in the header section +// Does not support ASCII image data (formats P2 and P3) + +#ifndef STBI_NO_PNM + +static int stbi__pnm_test(stbi__context *s) +{ + char p, t; + p = (char) stbi__get8(s); + t = (char) stbi__get8(s); + if (p != 'P' || (t != '5' && t != '6')) { + stbi__rewind( s ); + return 0; + } + return 1; +} + +static void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + stbi_uc *out; + STBI_NOTUSED(ri); + + ri->bits_per_channel = stbi__pnm_info(s, (int *)&s->img_x, (int *)&s->img_y, (int *)&s->img_n); + if (ri->bits_per_channel == 0) + return 0; + + if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + + *x = s->img_x; + *y = s->img_y; + if (comp) *comp = s->img_n; + + if (!stbi__mad4sizes_valid(s->img_n, s->img_x, s->img_y, ri->bits_per_channel / 8, 0)) + return stbi__errpuc("too large", "PNM too large"); + + out = (stbi_uc *) stbi__malloc_mad4(s->img_n, s->img_x, s->img_y, ri->bits_per_channel / 8, 0); + if (!out) return stbi__errpuc("outofmem", "Out of memory"); + if (!stbi__getn(s, out, s->img_n * s->img_x * s->img_y * (ri->bits_per_channel / 8))) { + STBI_FREE(out); + return stbi__errpuc("bad PNM", "PNM file truncated"); + } + + if (req_comp && req_comp != s->img_n) { + if (ri->bits_per_channel == 16) { + out = (stbi_uc *) stbi__convert_format16((stbi__uint16 *) out, s->img_n, req_comp, s->img_x, s->img_y); + } else { + out = stbi__convert_format(out, s->img_n, req_comp, s->img_x, s->img_y); + } + if (out == NULL) return out; // stbi__convert_format frees input on failure + } + return out; +} + +static int stbi__pnm_isspace(char c) +{ + return c == ' ' || c == '\t' || c == '\n' || c == '\v' || c == '\f' || c == '\r'; +} + +static void stbi__pnm_skip_whitespace(stbi__context *s, char *c) +{ + for (;;) { + while (!stbi__at_eof(s) && stbi__pnm_isspace(*c)) + *c = (char) stbi__get8(s); + + if (stbi__at_eof(s) || *c != '#') + break; + + while (!stbi__at_eof(s) && *c != '\n' && *c != '\r' ) + *c = (char) stbi__get8(s); + } +} + +static int stbi__pnm_isdigit(char c) +{ + return c >= '0' && c <= '9'; +} + +static int stbi__pnm_getinteger(stbi__context *s, char *c) +{ + int value = 0; + + while (!stbi__at_eof(s) && stbi__pnm_isdigit(*c)) { + value = value*10 + (*c - '0'); + *c = (char) stbi__get8(s); + if((value > 214748364) || (value == 214748364 && *c > '7')) + return stbi__err("integer parse overflow", "Parsing an integer in the PPM header overflowed a 32-bit int"); + } + + return value; +} + +static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp) +{ + int maxv, dummy; + char c, p, t; + + if (!x) x = &dummy; + if (!y) y = &dummy; + if (!comp) comp = &dummy; + + stbi__rewind(s); + + // Get identifier + p = (char) stbi__get8(s); + t = (char) stbi__get8(s); + if (p != 'P' || (t != '5' && t != '6')) { + stbi__rewind(s); + return 0; + } + + *comp = (t == '6') ? 3 : 1; // '5' is 1-component .pgm; '6' is 3-component .ppm + + c = (char) stbi__get8(s); + stbi__pnm_skip_whitespace(s, &c); + + *x = stbi__pnm_getinteger(s, &c); // read width + if(*x == 0) + return stbi__err("invalid width", "PPM image header had zero or overflowing width"); + stbi__pnm_skip_whitespace(s, &c); + + *y = stbi__pnm_getinteger(s, &c); // read height + if (*y == 0) + return stbi__err("invalid width", "PPM image header had zero or overflowing width"); + stbi__pnm_skip_whitespace(s, &c); + + maxv = stbi__pnm_getinteger(s, &c); // read max value + if (maxv > 65535) + return stbi__err("max value > 65535", "PPM image supports only 8-bit and 16-bit images"); + else if (maxv > 255) + return 16; + else + return 8; +} + +static int stbi__pnm_is16(stbi__context *s) +{ + if (stbi__pnm_info(s, NULL, NULL, NULL) == 16) + return 1; + return 0; +} +#endif + +static int stbi__info_main(stbi__context *s, int *x, int *y, int *comp) +{ + #ifndef STBI_NO_JPEG + if (stbi__jpeg_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_PNG + if (stbi__png_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_GIF + if (stbi__gif_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_BMP + if (stbi__bmp_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_PSD + if (stbi__psd_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_PIC + if (stbi__pic_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_PNM + if (stbi__pnm_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_HDR + if (stbi__hdr_info(s, x, y, comp)) return 1; + #endif + + // test tga last because it's a crappy test! + #ifndef STBI_NO_TGA + if (stbi__tga_info(s, x, y, comp)) + return 1; + #endif + return stbi__err("unknown image type", "Image not of any known type, or corrupt"); +} + +static int stbi__is_16_main(stbi__context *s) +{ + #ifndef STBI_NO_PNG + if (stbi__png_is16(s)) return 1; + #endif + + #ifndef STBI_NO_PSD + if (stbi__psd_is16(s)) return 1; + #endif + + #ifndef STBI_NO_PNM + if (stbi__pnm_is16(s)) return 1; + #endif + return 0; +} + +#ifndef STBI_NO_STDIO +STBIDEF int stbi_info(char const *filename, int *x, int *y, int *comp) +{ + FILE *f = stbi__fopen(filename, "rb"); + int result; + if (!f) return stbi__err("can't fopen", "Unable to open file"); + result = stbi_info_from_file(f, x, y, comp); + fclose(f); + return result; +} + +STBIDEF int stbi_info_from_file(FILE *f, int *x, int *y, int *comp) +{ + int r; + stbi__context s; + long pos = ftell(f); + stbi__start_file(&s, f); + r = stbi__info_main(&s,x,y,comp); + fseek(f,pos,SEEK_SET); + return r; +} + +STBIDEF int stbi_is_16_bit(char const *filename) +{ + FILE *f = stbi__fopen(filename, "rb"); + int result; + if (!f) return stbi__err("can't fopen", "Unable to open file"); + result = stbi_is_16_bit_from_file(f); + fclose(f); + return result; +} + +STBIDEF int stbi_is_16_bit_from_file(FILE *f) +{ + int r; + stbi__context s; + long pos = ftell(f); + stbi__start_file(&s, f); + r = stbi__is_16_main(&s); + fseek(f,pos,SEEK_SET); + return r; +} +#endif // !STBI_NO_STDIO + +STBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp) +{ + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__info_main(&s,x,y,comp); +} + +STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *c, void *user, int *x, int *y, int *comp) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) c, user); + return stbi__info_main(&s,x,y,comp); +} + +STBIDEF int stbi_is_16_bit_from_memory(stbi_uc const *buffer, int len) +{ + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__is_16_main(&s); +} + +STBIDEF int stbi_is_16_bit_from_callbacks(stbi_io_callbacks const *c, void *user) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) c, user); + return stbi__is_16_main(&s); +} + +#endif // STB_IMAGE_IMPLEMENTATION + +/* + revision history: + 2.20 (2019-02-07) support utf8 filenames in Windows; fix warnings and platform ifdefs + 2.19 (2018-02-11) fix warning + 2.18 (2018-01-30) fix warnings + 2.17 (2018-01-29) change sbti__shiftsigned to avoid clang -O2 bug + 1-bit BMP + *_is_16_bit api + avoid warnings + 2.16 (2017-07-23) all functions have 16-bit variants; + STBI_NO_STDIO works again; + compilation fixes; + fix rounding in unpremultiply; + optimize vertical flip; + disable raw_len validation; + documentation fixes + 2.15 (2017-03-18) fix png-1,2,4 bug; now all Imagenet JPGs decode; + warning fixes; disable run-time SSE detection on gcc; + uniform handling of optional "return" values; + thread-safe initialization of zlib tables + 2.14 (2017-03-03) remove deprecated STBI_JPEG_OLD; fixes for Imagenet JPGs + 2.13 (2016-11-29) add 16-bit API, only supported for PNG right now + 2.12 (2016-04-02) fix typo in 2.11 PSD fix that caused crashes + 2.11 (2016-04-02) allocate large structures on the stack + remove white matting for transparent PSD + fix reported channel count for PNG & BMP + re-enable SSE2 in non-gcc 64-bit + support RGB-formatted JPEG + read 16-bit PNGs (only as 8-bit) + 2.10 (2016-01-22) avoid warning introduced in 2.09 by STBI_REALLOC_SIZED + 2.09 (2016-01-16) allow comments in PNM files + 16-bit-per-pixel TGA (not bit-per-component) + info() for TGA could break due to .hdr handling + info() for BMP to shares code instead of sloppy parse + can use STBI_REALLOC_SIZED if allocator doesn't support realloc + code cleanup + 2.08 (2015-09-13) fix to 2.07 cleanup, reading RGB PSD as RGBA + 2.07 (2015-09-13) fix compiler warnings + partial animated GIF support + limited 16-bpc PSD support + #ifdef unused functions + bug with < 92 byte PIC,PNM,HDR,TGA + 2.06 (2015-04-19) fix bug where PSD returns wrong '*comp' value + 2.05 (2015-04-19) fix bug in progressive JPEG handling, fix warning + 2.04 (2015-04-15) try to re-enable SIMD on MinGW 64-bit + 2.03 (2015-04-12) extra corruption checking (mmozeiko) + stbi_set_flip_vertically_on_load (nguillemot) + fix NEON support; fix mingw support + 2.02 (2015-01-19) fix incorrect assert, fix warning + 2.01 (2015-01-17) fix various warnings; suppress SIMD on gcc 32-bit without -msse2 + 2.00b (2014-12-25) fix STBI_MALLOC in progressive JPEG + 2.00 (2014-12-25) optimize JPG, including x86 SSE2 & NEON SIMD (ryg) + progressive JPEG (stb) + PGM/PPM support (Ken Miller) + STBI_MALLOC,STBI_REALLOC,STBI_FREE + GIF bugfix -- seemingly never worked + STBI_NO_*, STBI_ONLY_* + 1.48 (2014-12-14) fix incorrectly-named assert() + 1.47 (2014-12-14) 1/2/4-bit PNG support, both direct and paletted (Omar Cornut & stb) + optimize PNG (ryg) + fix bug in interlaced PNG with user-specified channel count (stb) + 1.46 (2014-08-26) + fix broken tRNS chunk (colorkey-style transparency) in non-paletted PNG + 1.45 (2014-08-16) + fix MSVC-ARM internal compiler error by wrapping malloc + 1.44 (2014-08-07) + various warning fixes from Ronny Chevalier + 1.43 (2014-07-15) + fix MSVC-only compiler problem in code changed in 1.42 + 1.42 (2014-07-09) + don't define _CRT_SECURE_NO_WARNINGS (affects user code) + fixes to stbi__cleanup_jpeg path + added STBI_ASSERT to avoid requiring assert.h + 1.41 (2014-06-25) + fix search&replace from 1.36 that messed up comments/error messages + 1.40 (2014-06-22) + fix gcc struct-initialization warning + 1.39 (2014-06-15) + fix to TGA optimization when req_comp != number of components in TGA; + fix to GIF loading because BMP wasn't rewinding (whoops, no GIFs in my test suite) + add support for BMP version 5 (more ignored fields) + 1.38 (2014-06-06) + suppress MSVC warnings on integer casts truncating values + fix accidental rename of 'skip' field of I/O + 1.37 (2014-06-04) + remove duplicate typedef + 1.36 (2014-06-03) + convert to header file single-file library + if de-iphone isn't set, load iphone images color-swapped instead of returning NULL + 1.35 (2014-05-27) + various warnings + fix broken STBI_SIMD path + fix bug where stbi_load_from_file no longer left file pointer in correct place + fix broken non-easy path for 32-bit BMP (possibly never used) + TGA optimization by Arseny Kapoulkine + 1.34 (unknown) + use STBI_NOTUSED in stbi__resample_row_generic(), fix one more leak in tga failure case + 1.33 (2011-07-14) + make stbi_is_hdr work in STBI_NO_HDR (as specified), minor compiler-friendly improvements + 1.32 (2011-07-13) + support for "info" function for all supported filetypes (SpartanJ) + 1.31 (2011-06-20) + a few more leak fixes, bug in PNG handling (SpartanJ) + 1.30 (2011-06-11) + added ability to load files via callbacks to accomidate custom input streams (Ben Wenger) + removed deprecated format-specific test/load functions + removed support for installable file formats (stbi_loader) -- would have been broken for IO callbacks anyway + error cases in bmp and tga give messages and don't leak (Raymond Barbiero, grisha) + fix inefficiency in decoding 32-bit BMP (David Woo) + 1.29 (2010-08-16) + various warning fixes from Aurelien Pocheville + 1.28 (2010-08-01) + fix bug in GIF palette transparency (SpartanJ) + 1.27 (2010-08-01) + cast-to-stbi_uc to fix warnings + 1.26 (2010-07-24) + fix bug in file buffering for PNG reported by SpartanJ + 1.25 (2010-07-17) + refix trans_data warning (Won Chun) + 1.24 (2010-07-12) + perf improvements reading from files on platforms with lock-heavy fgetc() + minor perf improvements for jpeg + deprecated type-specific functions so we'll get feedback if they're needed + attempt to fix trans_data warning (Won Chun) + 1.23 fixed bug in iPhone support + 1.22 (2010-07-10) + removed image *writing* support + stbi_info support from Jetro Lauha + GIF support from Jean-Marc Lienher + iPhone PNG-extensions from James Brown + warning-fixes from Nicolas Schulz and Janez Zemva (i.stbi__err. Janez (U+017D)emva) + 1.21 fix use of 'stbi_uc' in header (reported by jon blow) + 1.20 added support for Softimage PIC, by Tom Seddon + 1.19 bug in interlaced PNG corruption check (found by ryg) + 1.18 (2008-08-02) + fix a threading bug (local mutable static) + 1.17 support interlaced PNG + 1.16 major bugfix - stbi__convert_format converted one too many pixels + 1.15 initialize some fields for thread safety + 1.14 fix threadsafe conversion bug + header-file-only version (#define STBI_HEADER_FILE_ONLY before including) + 1.13 threadsafe + 1.12 const qualifiers in the API + 1.11 Support installable IDCT, colorspace conversion routines + 1.10 Fixes for 64-bit (don't use "unsigned long") + optimized upsampling by Fabian "ryg" Giesen + 1.09 Fix format-conversion for PSD code (bad global variables!) + 1.08 Thatcher Ulrich's PSD code integrated by Nicolas Schulz + 1.07 attempt to fix C++ warning/errors again + 1.06 attempt to fix C++ warning/errors again + 1.05 fix TGA loading to return correct *comp and use good luminance calc + 1.04 default float alpha is 1, not 255; use 'void *' for stbi_image_free + 1.03 bugfixes to STBI_NO_STDIO, STBI_NO_HDR + 1.02 support for (subset of) HDR files, float interface for preferred access to them + 1.01 fix bug: possible bug in handling right-side up bmps... not sure + fix bug: the stbi__bmp_load() and stbi__tga_load() functions didn't work at all + 1.00 interface to zlib that skips zlib header + 0.99 correct handling of alpha in palette + 0.98 TGA loader by lonesock; dynamically add loaders (untested) + 0.97 jpeg errors on too large a file; also catch another malloc failure + 0.96 fix detection of invalid v value - particleman@mollyrocket forum + 0.95 during header scan, seek to markers in case of padding + 0.94 STBI_NO_STDIO to disable stdio usage; rename all #defines the same + 0.93 handle jpegtran output; verbose errors + 0.92 read 4,8,16,24,32-bit BMP files of several formats + 0.91 output 24-bit Windows 3.0 BMP files + 0.90 fix a few more warnings; bump version number to approach 1.0 + 0.61 bugfixes due to Marc LeBlanc, Christopher Lloyd + 0.60 fix compiling as c++ + 0.59 fix warnings: merge Dave Moore's -Wall fixes + 0.58 fix bug: zlib uncompressed mode len/nlen was wrong endian + 0.57 fix bug: jpg last huffman symbol before marker was >9 bits but less than 16 available + 0.56 fix bug: zlib uncompressed mode len vs. nlen + 0.55 fix bug: restart_interval not initialized to 0 + 0.54 allow NULL for 'int *comp' + 0.53 fix bug in png 3->4; speedup png decoding + 0.52 png handles req_comp=3,4 directly; minor cleanup; jpeg comments + 0.51 obey req_comp requests, 1-component jpegs return as 1-component, + on 'test' only check type, not whether we support this variant + 0.50 (2006-11-19) + first released version +*/ + + +/* +------------------------------------------------------------------------------ +This software is available under 2 licenses -- choose whichever you prefer. +------------------------------------------------------------------------------ +ALTERNATIVE A - MIT License +Copyright (c) 2017 Sean Barrett +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +------------------------------------------------------------------------------ +ALTERNATIVE B - Public Domain (www.unlicense.org) +This is free and unencumbered software released into the public domain. +Anyone is free to copy, modify, publish, use, compile, sell, or distribute this +software, either in source code form or as a compiled binary, for any purpose, +commercial or non-commercial, and by any means. +In jurisdictions that recognize copyright laws, the author or authors of this +software dedicate any and all copyright interest in the software to the public +domain. We make this dedication for the benefit of the public at large and to +the detriment of our heirs and successors. We intend this dedication to be an +overt act of relinquishment in perpetuity of all present and future rights to +this software under copyright law. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +------------------------------------------------------------------------------ +*/ diff --git a/CristalDiskMark/source/CrystalDiskMark/Priscilla/stb_image_impl.cpp b/CristalDiskMark/source/CrystalDiskMark/Priscilla/stb_image_impl.cpp new file mode 100644 index 0000000..0611d54 --- /dev/null +++ b/CristalDiskMark/source/CrystalDiskMark/Priscilla/stb_image_impl.cpp @@ -0,0 +1,17 @@ +/*---------------------------------------------------------------------------*/ +// Author : hiyohiyo +// Mail : hiyohiyo@crystalmark.info +// Web : https://crystalmark.info/ +// License : MIT License +/*---------------------------------------------------------------------------*/ + +#include "stdafx.h" +#define STBI_ONLY_PNG +#define STBI_NO_STDIO +#define STBI_NO_HDR +#define STBI_NO_LINEAR +#define STBI_NO_FAILURE_STRINGS +#define STBI_ASSERT(x) + +#define STB_IMAGE_IMPLEMENTATION +#include "stb_image.h" \ No newline at end of file diff --git a/CristalDiskMark/source/CrystalDiskMark/Priscilla/stb_image_write.h b/CristalDiskMark/source/CrystalDiskMark/Priscilla/stb_image_write.h new file mode 100644 index 0000000..e4b32ed --- /dev/null +++ b/CristalDiskMark/source/CrystalDiskMark/Priscilla/stb_image_write.h @@ -0,0 +1,1724 @@ +/* stb_image_write - v1.16 - public domain - http://nothings.org/stb + writes out PNG/BMP/TGA/JPEG/HDR images to C stdio - Sean Barrett 2010-2015 + no warranty implied; use at your own risk + + Before #including, + + #define STB_IMAGE_WRITE_IMPLEMENTATION + + in the file that you want to have the implementation. + + Will probably not work correctly with strict-aliasing optimizations. + +ABOUT: + + This header file is a library for writing images to C stdio or a callback. + + The PNG output is not optimal; it is 20-50% larger than the file + written by a decent optimizing implementation; though providing a custom + zlib compress function (see STBIW_ZLIB_COMPRESS) can mitigate that. + This library is designed for source code compactness and simplicity, + not optimal image file size or run-time performance. + +BUILDING: + + You can #define STBIW_ASSERT(x) before the #include to avoid using assert.h. + You can #define STBIW_MALLOC(), STBIW_REALLOC(), and STBIW_FREE() to replace + malloc,realloc,free. + You can #define STBIW_MEMMOVE() to replace memmove() + You can #define STBIW_ZLIB_COMPRESS to use a custom zlib-style compress function + for PNG compression (instead of the builtin one), it must have the following signature: + unsigned char * my_compress(unsigned char *data, int data_len, int *out_len, int quality); + The returned data will be freed with STBIW_FREE() (free() by default), + so it must be heap allocated with STBIW_MALLOC() (malloc() by default), + +UNICODE: + + If compiling for Windows and you wish to use Unicode filenames, compile + with + #define STBIW_WINDOWS_UTF8 + and pass utf8-encoded filenames. Call stbiw_convert_wchar_to_utf8 to convert + Windows wchar_t filenames to utf8. + +USAGE: + + There are five functions, one for each image file format: + + int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes); + int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data); + int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data); + int stbi_write_jpg(char const *filename, int w, int h, int comp, const void *data, int quality); + int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data); + + void stbi_flip_vertically_on_write(int flag); // flag is non-zero to flip data vertically + + There are also five equivalent functions that use an arbitrary write function. You are + expected to open/close your file-equivalent before and after calling these: + + int stbi_write_png_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data, int stride_in_bytes); + int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data); + int stbi_write_tga_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data); + int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const float *data); + int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int quality); + + where the callback is: + void stbi_write_func(void *context, void *data, int size); + + You can configure it with these global variables: + int stbi_write_tga_with_rle; // defaults to true; set to 0 to disable RLE + int stbi_write_png_compression_level; // defaults to 8; set to higher for more compression + int stbi_write_force_png_filter; // defaults to -1; set to 0..5 to force a filter mode + + + You can define STBI_WRITE_NO_STDIO to disable the file variant of these + functions, so the library will not use stdio.h at all. However, this will + also disable HDR writing, because it requires stdio for formatted output. + + Each function returns 0 on failure and non-0 on success. + + The functions create an image file defined by the parameters. The image + is a rectangle of pixels stored from left-to-right, top-to-bottom. + Each pixel contains 'comp' channels of data stored interleaved with 8-bits + per channel, in the following order: 1=Y, 2=YA, 3=RGB, 4=RGBA. (Y is + monochrome color.) The rectangle is 'w' pixels wide and 'h' pixels tall. + The *data pointer points to the first byte of the top-left-most pixel. + For PNG, "stride_in_bytes" is the distance in bytes from the first byte of + a row of pixels to the first byte of the next row of pixels. + + PNG creates output files with the same number of components as the input. + The BMP format expands Y to RGB in the file format and does not + output alpha. + + PNG supports writing rectangles of data even when the bytes storing rows of + data are not consecutive in memory (e.g. sub-rectangles of a larger image), + by supplying the stride between the beginning of adjacent rows. The other + formats do not. (Thus you cannot write a native-format BMP through the BMP + writer, both because it is in BGR order and because it may have padding + at the end of the line.) + + PNG allows you to set the deflate compression level by setting the global + variable 'stbi_write_png_compression_level' (it defaults to 8). + + HDR expects linear float data. Since the format is always 32-bit rgb(e) + data, alpha (if provided) is discarded, and for monochrome data it is + replicated across all three channels. + + TGA supports RLE or non-RLE compressed data. To use non-RLE-compressed + data, set the global variable 'stbi_write_tga_with_rle' to 0. + + JPEG does ignore alpha channels in input data; quality is between 1 and 100. + Higher quality looks better but results in a bigger image. + JPEG baseline (no JPEG progressive). + +CREDITS: + + + Sean Barrett - PNG/BMP/TGA + Baldur Karlsson - HDR + Jean-Sebastien Guay - TGA monochrome + Tim Kelsey - misc enhancements + Alan Hickman - TGA RLE + Emmanuel Julien - initial file IO callback implementation + Jon Olick - original jo_jpeg.cpp code + Daniel Gibson - integrate JPEG, allow external zlib + Aarni Koskela - allow choosing PNG filter + + bugfixes: + github:Chribba + Guillaume Chereau + github:jry2 + github:romigrou + Sergio Gonzalez + Jonas Karlsson + Filip Wasil + Thatcher Ulrich + github:poppolopoppo + Patrick Boettcher + github:xeekworx + Cap Petschulat + Simon Rodriguez + Ivan Tikhonov + github:ignotion + Adam Schackart + Andrew Kensler + +LICENSE + + See end of file for license information. + +*/ + +#ifndef INCLUDE_STB_IMAGE_WRITE_H +#define INCLUDE_STB_IMAGE_WRITE_H + +#include + +// if STB_IMAGE_WRITE_STATIC causes problems, try defining STBIWDEF to 'inline' or 'static inline' +#ifndef STBIWDEF +#ifdef STB_IMAGE_WRITE_STATIC +#define STBIWDEF static +#else +#ifdef __cplusplus +#define STBIWDEF extern "C" +#else +#define STBIWDEF extern +#endif +#endif +#endif + +#ifndef STB_IMAGE_WRITE_STATIC // C++ forbids static forward declarations +STBIWDEF int stbi_write_tga_with_rle; +STBIWDEF int stbi_write_png_compression_level; +STBIWDEF int stbi_write_force_png_filter; +#endif + +#ifndef STBI_WRITE_NO_STDIO +STBIWDEF int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes); +STBIWDEF int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data); +STBIWDEF int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data); +STBIWDEF int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data); +STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const void *data, int quality); + +#ifdef STBIW_WINDOWS_UTF8 +STBIWDEF int stbiw_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input); +#endif +#endif + +typedef void stbi_write_func(void *context, void *data, int size); + +STBIWDEF int stbi_write_png_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data, int stride_in_bytes); +STBIWDEF int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data); +STBIWDEF int stbi_write_tga_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data); +STBIWDEF int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const float *data); +STBIWDEF int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int quality); + +STBIWDEF void stbi_flip_vertically_on_write(int flip_boolean); + +#endif//INCLUDE_STB_IMAGE_WRITE_H + +#ifdef STB_IMAGE_WRITE_IMPLEMENTATION + +#ifdef _WIN32 + #ifndef _CRT_SECURE_NO_WARNINGS + #define _CRT_SECURE_NO_WARNINGS + #endif + #ifndef _CRT_NONSTDC_NO_DEPRECATE + #define _CRT_NONSTDC_NO_DEPRECATE + #endif +#endif + +#ifndef STBI_WRITE_NO_STDIO +#include +#endif // STBI_WRITE_NO_STDIO + +#include +#include +#include +#include + +#if defined(STBIW_MALLOC) && defined(STBIW_FREE) && (defined(STBIW_REALLOC) || defined(STBIW_REALLOC_SIZED)) +// ok +#elif !defined(STBIW_MALLOC) && !defined(STBIW_FREE) && !defined(STBIW_REALLOC) && !defined(STBIW_REALLOC_SIZED) +// ok +#else +#error "Must define all or none of STBIW_MALLOC, STBIW_FREE, and STBIW_REALLOC (or STBIW_REALLOC_SIZED)." +#endif + +#ifndef STBIW_MALLOC +#define STBIW_MALLOC(sz) malloc(sz) +#define STBIW_REALLOC(p,newsz) realloc(p,newsz) +#define STBIW_FREE(p) free(p) +#endif + +#ifndef STBIW_REALLOC_SIZED +#define STBIW_REALLOC_SIZED(p,oldsz,newsz) STBIW_REALLOC(p,newsz) +#endif + + +#ifndef STBIW_MEMMOVE +#define STBIW_MEMMOVE(a,b,sz) memmove(a,b,sz) +#endif + + +#ifndef STBIW_ASSERT +#include +#define STBIW_ASSERT(x) assert(x) +#endif + +#define STBIW_UCHAR(x) (unsigned char) ((x) & 0xff) + +#ifdef STB_IMAGE_WRITE_STATIC +static int stbi_write_png_compression_level = 8; +static int stbi_write_tga_with_rle = 1; +static int stbi_write_force_png_filter = -1; +#else +int stbi_write_png_compression_level = 8; +int stbi_write_tga_with_rle = 1; +int stbi_write_force_png_filter = -1; +#endif + +static int stbi__flip_vertically_on_write = 0; + +STBIWDEF void stbi_flip_vertically_on_write(int flag) +{ + stbi__flip_vertically_on_write = flag; +} + +typedef struct +{ + stbi_write_func *func; + void *context; + unsigned char buffer[64]; + int buf_used; +} stbi__write_context; + +// initialize a callback-based context +static void stbi__start_write_callbacks(stbi__write_context *s, stbi_write_func *c, void *context) +{ + s->func = c; + s->context = context; +} + +#ifndef STBI_WRITE_NO_STDIO + +static void stbi__stdio_write(void *context, void *data, int size) +{ + fwrite(data,1,size,(FILE*) context); +} + +#if defined(_WIN32) && defined(STBIW_WINDOWS_UTF8) +#ifdef __cplusplus +#define STBIW_EXTERN extern "C" +#else +#define STBIW_EXTERN extern +#endif +STBIW_EXTERN __declspec(dllimport) int __stdcall MultiByteToWideChar(unsigned int cp, unsigned long flags, const char *str, int cbmb, wchar_t *widestr, int cchwide); +STBIW_EXTERN __declspec(dllimport) int __stdcall WideCharToMultiByte(unsigned int cp, unsigned long flags, const wchar_t *widestr, int cchwide, char *str, int cbmb, const char *defchar, int *used_default); + +STBIWDEF int stbiw_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input) +{ + return WideCharToMultiByte(65001 /* UTF8 */, 0, input, -1, buffer, (int) bufferlen, NULL, NULL); +} +#endif + +static FILE *stbiw__fopen(char const *filename, char const *mode) +{ + FILE *f; +#if defined(_WIN32) && defined(STBIW_WINDOWS_UTF8) + wchar_t wMode[64]; + wchar_t wFilename[1024]; + if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, filename, -1, wFilename, sizeof(wFilename)/sizeof(*wFilename))) + return 0; + + if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, mode, -1, wMode, sizeof(wMode)/sizeof(*wMode))) + return 0; + +#if defined(_MSC_VER) && _MSC_VER >= 1400 + if (0 != _wfopen_s(&f, wFilename, wMode)) + f = 0; +#else + f = _wfopen(wFilename, wMode); +#endif + +#elif defined(_MSC_VER) && _MSC_VER >= 1400 + if (0 != fopen_s(&f, filename, mode)) + f=0; +#else + f = fopen(filename, mode); +#endif + return f; +} + +static int stbi__start_write_file(stbi__write_context *s, const char *filename) +{ + FILE *f = stbiw__fopen(filename, "wb"); + stbi__start_write_callbacks(s, stbi__stdio_write, (void *) f); + return f != NULL; +} + +static void stbi__end_write_file(stbi__write_context *s) +{ + fclose((FILE *)s->context); +} + +#endif // !STBI_WRITE_NO_STDIO + +typedef unsigned int stbiw_uint32; +typedef int stb_image_write_test[sizeof(stbiw_uint32)==4 ? 1 : -1]; + +static void stbiw__writefv(stbi__write_context *s, const char *fmt, va_list v) +{ + while (*fmt) { + switch (*fmt++) { + case ' ': break; + case '1': { unsigned char x = STBIW_UCHAR(va_arg(v, int)); + s->func(s->context,&x,1); + break; } + case '2': { int x = va_arg(v,int); + unsigned char b[2]; + b[0] = STBIW_UCHAR(x); + b[1] = STBIW_UCHAR(x>>8); + s->func(s->context,b,2); + break; } + case '4': { stbiw_uint32 x = va_arg(v,int); + unsigned char b[4]; + b[0]=STBIW_UCHAR(x); + b[1]=STBIW_UCHAR(x>>8); + b[2]=STBIW_UCHAR(x>>16); + b[3]=STBIW_UCHAR(x>>24); + s->func(s->context,b,4); + break; } + default: + STBIW_ASSERT(0); + return; + } + } +} + +static void stbiw__writef(stbi__write_context *s, const char *fmt, ...) +{ + va_list v; + va_start(v, fmt); + stbiw__writefv(s, fmt, v); + va_end(v); +} + +static void stbiw__write_flush(stbi__write_context *s) +{ + if (s->buf_used) { + s->func(s->context, &s->buffer, s->buf_used); + s->buf_used = 0; + } +} + +static void stbiw__putc(stbi__write_context *s, unsigned char c) +{ + s->func(s->context, &c, 1); +} + +static void stbiw__write1(stbi__write_context *s, unsigned char a) +{ + if ((size_t)s->buf_used + 1 > sizeof(s->buffer)) + stbiw__write_flush(s); + s->buffer[s->buf_used++] = a; +} + +static void stbiw__write3(stbi__write_context *s, unsigned char a, unsigned char b, unsigned char c) +{ + int n; + if ((size_t)s->buf_used + 3 > sizeof(s->buffer)) + stbiw__write_flush(s); + n = s->buf_used; + s->buf_used = n+3; + s->buffer[n+0] = a; + s->buffer[n+1] = b; + s->buffer[n+2] = c; +} + +static void stbiw__write_pixel(stbi__write_context *s, int rgb_dir, int comp, int write_alpha, int expand_mono, unsigned char *d) +{ + unsigned char bg[3] = { 255, 0, 255}, px[3]; + int k; + + if (write_alpha < 0) + stbiw__write1(s, d[comp - 1]); + + switch (comp) { + case 2: // 2 pixels = mono + alpha, alpha is written separately, so same as 1-channel case + case 1: + if (expand_mono) + stbiw__write3(s, d[0], d[0], d[0]); // monochrome bmp + else + stbiw__write1(s, d[0]); // monochrome TGA + break; + case 4: + if (!write_alpha) { + // composite against pink background + for (k = 0; k < 3; ++k) + px[k] = bg[k] + ((d[k] - bg[k]) * d[3]) / 255; + stbiw__write3(s, px[1 - rgb_dir], px[1], px[1 + rgb_dir]); + break; + } + /* FALLTHROUGH */ + case 3: + stbiw__write3(s, d[1 - rgb_dir], d[1], d[1 + rgb_dir]); + break; + } + if (write_alpha > 0) + stbiw__write1(s, d[comp - 1]); +} + +static void stbiw__write_pixels(stbi__write_context *s, int rgb_dir, int vdir, int x, int y, int comp, void *data, int write_alpha, int scanline_pad, int expand_mono) +{ + stbiw_uint32 zero = 0; + int i,j, j_end; + + if (y <= 0) + return; + + if (stbi__flip_vertically_on_write) + vdir *= -1; + + if (vdir < 0) { + j_end = -1; j = y-1; + } else { + j_end = y; j = 0; + } + + for (; j != j_end; j += vdir) { + for (i=0; i < x; ++i) { + unsigned char *d = (unsigned char *) data + (j*x+i)*comp; + stbiw__write_pixel(s, rgb_dir, comp, write_alpha, expand_mono, d); + } + stbiw__write_flush(s); + s->func(s->context, &zero, scanline_pad); + } +} + +static int stbiw__outfile(stbi__write_context *s, int rgb_dir, int vdir, int x, int y, int comp, int expand_mono, void *data, int alpha, int pad, const char *fmt, ...) +{ + if (y < 0 || x < 0) { + return 0; + } else { + va_list v; + va_start(v, fmt); + stbiw__writefv(s, fmt, v); + va_end(v); + stbiw__write_pixels(s,rgb_dir,vdir,x,y,comp,data,alpha,pad, expand_mono); + return 1; + } +} + +static int stbi_write_bmp_core(stbi__write_context *s, int x, int y, int comp, const void *data) +{ + if (comp != 4) { + // write RGB bitmap + int pad = (-x*3) & 3; + return stbiw__outfile(s,-1,-1,x,y,comp,1,(void *) data,0,pad, + "11 4 22 4" "4 44 22 444444", + 'B', 'M', 14+40+(x*3+pad)*y, 0,0, 14+40, // file header + 40, x,y, 1,24, 0,0,0,0,0,0); // bitmap header + } else { + // RGBA bitmaps need a v4 header + // use BI_BITFIELDS mode with 32bpp and alpha mask + // (straight BI_RGB with alpha mask doesn't work in most readers) + return stbiw__outfile(s,-1,-1,x,y,comp,1,(void *)data,1,0, + "11 4 22 4" "4 44 22 444444 4444 4 444 444 444 444", + 'B', 'M', 14+108+x*y*4, 0, 0, 14+108, // file header + 108, x,y, 1,32, 3,0,0,0,0,0, 0xff0000,0xff00,0xff,0xff000000u, 0, 0,0,0, 0,0,0, 0,0,0, 0,0,0); // bitmap V4 header + } +} + +STBIWDEF int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data) +{ + stbi__write_context s = { 0 }; + stbi__start_write_callbacks(&s, func, context); + return stbi_write_bmp_core(&s, x, y, comp, data); +} + +#ifndef STBI_WRITE_NO_STDIO +STBIWDEF int stbi_write_bmp(char const *filename, int x, int y, int comp, const void *data) +{ + stbi__write_context s = { 0 }; + if (stbi__start_write_file(&s,filename)) { + int r = stbi_write_bmp_core(&s, x, y, comp, data); + stbi__end_write_file(&s); + return r; + } else + return 0; +} +#endif //!STBI_WRITE_NO_STDIO + +static int stbi_write_tga_core(stbi__write_context *s, int x, int y, int comp, void *data) +{ + int has_alpha = (comp == 2 || comp == 4); + int colorbytes = has_alpha ? comp-1 : comp; + int format = colorbytes < 2 ? 3 : 2; // 3 color channels (RGB/RGBA) = 2, 1 color channel (Y/YA) = 3 + + if (y < 0 || x < 0) + return 0; + + if (!stbi_write_tga_with_rle) { + return stbiw__outfile(s, -1, -1, x, y, comp, 0, (void *) data, has_alpha, 0, + "111 221 2222 11", 0, 0, format, 0, 0, 0, 0, 0, x, y, (colorbytes + has_alpha) * 8, has_alpha * 8); + } else { + int i,j,k; + int jend, jdir; + + stbiw__writef(s, "111 221 2222 11", 0,0,format+8, 0,0,0, 0,0,x,y, (colorbytes + has_alpha) * 8, has_alpha * 8); + + if (stbi__flip_vertically_on_write) { + j = 0; + jend = y; + jdir = 1; + } else { + j = y-1; + jend = -1; + jdir = -1; + } + for (; j != jend; j += jdir) { + unsigned char *row = (unsigned char *) data + j * x * comp; + int len; + + for (i = 0; i < x; i += len) { + unsigned char *begin = row + i * comp; + int diff = 1; + len = 1; + + if (i < x - 1) { + ++len; + diff = memcmp(begin, row + (i + 1) * comp, comp); + if (diff) { + const unsigned char *prev = begin; + for (k = i + 2; k < x && len < 128; ++k) { + if (memcmp(prev, row + k * comp, comp)) { + prev += comp; + ++len; + } else { + --len; + break; + } + } + } else { + for (k = i + 2; k < x && len < 128; ++k) { + if (!memcmp(begin, row + k * comp, comp)) { + ++len; + } else { + break; + } + } + } + } + + if (diff) { + unsigned char header = STBIW_UCHAR(len - 1); + stbiw__write1(s, header); + for (k = 0; k < len; ++k) { + stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin + k * comp); + } + } else { + unsigned char header = STBIW_UCHAR(len - 129); + stbiw__write1(s, header); + stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin); + } + } + } + stbiw__write_flush(s); + } + return 1; +} + +STBIWDEF int stbi_write_tga_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data) +{ + stbi__write_context s = { 0 }; + stbi__start_write_callbacks(&s, func, context); + return stbi_write_tga_core(&s, x, y, comp, (void *) data); +} + +#ifndef STBI_WRITE_NO_STDIO +STBIWDEF int stbi_write_tga(char const *filename, int x, int y, int comp, const void *data) +{ + stbi__write_context s = { 0 }; + if (stbi__start_write_file(&s,filename)) { + int r = stbi_write_tga_core(&s, x, y, comp, (void *) data); + stbi__end_write_file(&s); + return r; + } else + return 0; +} +#endif + +// ************************************************************************************************* +// Radiance RGBE HDR writer +// by Baldur Karlsson + +#define stbiw__max(a, b) ((a) > (b) ? (a) : (b)) + +#ifndef STBI_WRITE_NO_STDIO + +static void stbiw__linear_to_rgbe(unsigned char *rgbe, float *linear) +{ + int exponent; + float maxcomp = stbiw__max(linear[0], stbiw__max(linear[1], linear[2])); + + if (maxcomp < 1e-32f) { + rgbe[0] = rgbe[1] = rgbe[2] = rgbe[3] = 0; + } else { + float normalize = (float) frexp(maxcomp, &exponent) * 256.0f/maxcomp; + + rgbe[0] = (unsigned char)(linear[0] * normalize); + rgbe[1] = (unsigned char)(linear[1] * normalize); + rgbe[2] = (unsigned char)(linear[2] * normalize); + rgbe[3] = (unsigned char)(exponent + 128); + } +} + +static void stbiw__write_run_data(stbi__write_context *s, int length, unsigned char databyte) +{ + unsigned char lengthbyte = STBIW_UCHAR(length+128); + STBIW_ASSERT(length+128 <= 255); + s->func(s->context, &lengthbyte, 1); + s->func(s->context, &databyte, 1); +} + +static void stbiw__write_dump_data(stbi__write_context *s, int length, unsigned char *data) +{ + unsigned char lengthbyte = STBIW_UCHAR(length); + STBIW_ASSERT(length <= 128); // inconsistent with spec but consistent with official code + s->func(s->context, &lengthbyte, 1); + s->func(s->context, data, length); +} + +static void stbiw__write_hdr_scanline(stbi__write_context *s, int width, int ncomp, unsigned char *scratch, float *scanline) +{ + unsigned char scanlineheader[4] = { 2, 2, 0, 0 }; + unsigned char rgbe[4]; + float linear[3]; + int x; + + scanlineheader[2] = (width&0xff00)>>8; + scanlineheader[3] = (width&0x00ff); + + /* skip RLE for images too small or large */ + if (width < 8 || width >= 32768) { + for (x=0; x < width; x++) { + switch (ncomp) { + case 4: /* fallthrough */ + case 3: linear[2] = scanline[x*ncomp + 2]; + linear[1] = scanline[x*ncomp + 1]; + linear[0] = scanline[x*ncomp + 0]; + break; + default: + linear[0] = linear[1] = linear[2] = scanline[x*ncomp + 0]; + break; + } + stbiw__linear_to_rgbe(rgbe, linear); + s->func(s->context, rgbe, 4); + } + } else { + int c,r; + /* encode into scratch buffer */ + for (x=0; x < width; x++) { + switch(ncomp) { + case 4: /* fallthrough */ + case 3: linear[2] = scanline[x*ncomp + 2]; + linear[1] = scanline[x*ncomp + 1]; + linear[0] = scanline[x*ncomp + 0]; + break; + default: + linear[0] = linear[1] = linear[2] = scanline[x*ncomp + 0]; + break; + } + stbiw__linear_to_rgbe(rgbe, linear); + scratch[x + width*0] = rgbe[0]; + scratch[x + width*1] = rgbe[1]; + scratch[x + width*2] = rgbe[2]; + scratch[x + width*3] = rgbe[3]; + } + + s->func(s->context, scanlineheader, 4); + + /* RLE each component separately */ + for (c=0; c < 4; c++) { + unsigned char *comp = &scratch[width*c]; + + x = 0; + while (x < width) { + // find first run + r = x; + while (r+2 < width) { + if (comp[r] == comp[r+1] && comp[r] == comp[r+2]) + break; + ++r; + } + if (r+2 >= width) + r = width; + // dump up to first run + while (x < r) { + int len = r-x; + if (len > 128) len = 128; + stbiw__write_dump_data(s, len, &comp[x]); + x += len; + } + // if there's a run, output it + if (r+2 < width) { // same test as what we break out of in search loop, so only true if we break'd + // find next byte after run + while (r < width && comp[r] == comp[x]) + ++r; + // output run up to r + while (x < r) { + int len = r-x; + if (len > 127) len = 127; + stbiw__write_run_data(s, len, comp[x]); + x += len; + } + } + } + } + } +} + +static int stbi_write_hdr_core(stbi__write_context *s, int x, int y, int comp, float *data) +{ + if (y <= 0 || x <= 0 || data == NULL) + return 0; + else { + // Each component is stored separately. Allocate scratch space for full output scanline. + unsigned char *scratch = (unsigned char *) STBIW_MALLOC(x*4); + int i, len; + char buffer[128]; + char header[] = "#?RADIANCE\n# Written by stb_image_write.h\nFORMAT=32-bit_rle_rgbe\n"; + s->func(s->context, header, sizeof(header)-1); + +#ifdef __STDC_LIB_EXT1__ + len = sprintf_s(buffer, sizeof(buffer), "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x); +#else + len = sprintf(buffer, "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x); +#endif + s->func(s->context, buffer, len); + + for(i=0; i < y; i++) + stbiw__write_hdr_scanline(s, x, comp, scratch, data + comp*x*(stbi__flip_vertically_on_write ? y-1-i : i)); + STBIW_FREE(scratch); + return 1; + } +} + +STBIWDEF int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const float *data) +{ + stbi__write_context s = { 0 }; + stbi__start_write_callbacks(&s, func, context); + return stbi_write_hdr_core(&s, x, y, comp, (float *) data); +} + +STBIWDEF int stbi_write_hdr(char const *filename, int x, int y, int comp, const float *data) +{ + stbi__write_context s = { 0 }; + if (stbi__start_write_file(&s,filename)) { + int r = stbi_write_hdr_core(&s, x, y, comp, (float *) data); + stbi__end_write_file(&s); + return r; + } else + return 0; +} +#endif // STBI_WRITE_NO_STDIO + + +////////////////////////////////////////////////////////////////////////////// +// +// PNG writer +// + +#ifndef STBIW_ZLIB_COMPRESS +// stretchy buffer; stbiw__sbpush() == vector<>::push_back() -- stbiw__sbcount() == vector<>::size() +#define stbiw__sbraw(a) ((int *) (void *) (a) - 2) +#define stbiw__sbm(a) stbiw__sbraw(a)[0] +#define stbiw__sbn(a) stbiw__sbraw(a)[1] + +#define stbiw__sbneedgrow(a,n) ((a)==0 || stbiw__sbn(a)+n >= stbiw__sbm(a)) +#define stbiw__sbmaybegrow(a,n) (stbiw__sbneedgrow(a,(n)) ? stbiw__sbgrow(a,n) : 0) +#define stbiw__sbgrow(a,n) stbiw__sbgrowf((void **) &(a), (n), sizeof(*(a))) + +#define stbiw__sbpush(a, v) (stbiw__sbmaybegrow(a,1), (a)[stbiw__sbn(a)++] = (v)) +#define stbiw__sbcount(a) ((a) ? stbiw__sbn(a) : 0) +#define stbiw__sbfree(a) ((a) ? STBIW_FREE(stbiw__sbraw(a)),0 : 0) + +static void *stbiw__sbgrowf(void **arr, int increment, int itemsize) +{ + int m = *arr ? 2*stbiw__sbm(*arr)+increment : increment+1; + void *p = STBIW_REALLOC_SIZED(*arr ? stbiw__sbraw(*arr) : 0, *arr ? (stbiw__sbm(*arr)*itemsize + sizeof(int)*2) : 0, itemsize * m + sizeof(int)*2); + STBIW_ASSERT(p); + if (p) { + if (!*arr) ((int *) p)[1] = 0; + *arr = (void *) ((int *) p + 2); + stbiw__sbm(*arr) = m; + } + return *arr; +} + +static unsigned char *stbiw__zlib_flushf(unsigned char *data, unsigned int *bitbuffer, int *bitcount) +{ + while (*bitcount >= 8) { + stbiw__sbpush(data, STBIW_UCHAR(*bitbuffer)); + *bitbuffer >>= 8; + *bitcount -= 8; + } + return data; +} + +static int stbiw__zlib_bitrev(int code, int codebits) +{ + int res=0; + while (codebits--) { + res = (res << 1) | (code & 1); + code >>= 1; + } + return res; +} + +static unsigned int stbiw__zlib_countm(unsigned char *a, unsigned char *b, int limit) +{ + int i; + for (i=0; i < limit && i < 258; ++i) + if (a[i] != b[i]) break; + return i; +} + +static unsigned int stbiw__zhash(unsigned char *data) +{ + stbiw_uint32 hash = data[0] + (data[1] << 8) + (data[2] << 16); + hash ^= hash << 3; + hash += hash >> 5; + hash ^= hash << 4; + hash += hash >> 17; + hash ^= hash << 25; + hash += hash >> 6; + return hash; +} + +#define stbiw__zlib_flush() (out = stbiw__zlib_flushf(out, &bitbuf, &bitcount)) +#define stbiw__zlib_add(code,codebits) \ + (bitbuf |= (code) << bitcount, bitcount += (codebits), stbiw__zlib_flush()) +#define stbiw__zlib_huffa(b,c) stbiw__zlib_add(stbiw__zlib_bitrev(b,c),c) +// default huffman tables +#define stbiw__zlib_huff1(n) stbiw__zlib_huffa(0x30 + (n), 8) +#define stbiw__zlib_huff2(n) stbiw__zlib_huffa(0x190 + (n)-144, 9) +#define stbiw__zlib_huff3(n) stbiw__zlib_huffa(0 + (n)-256,7) +#define stbiw__zlib_huff4(n) stbiw__zlib_huffa(0xc0 + (n)-280,8) +#define stbiw__zlib_huff(n) ((n) <= 143 ? stbiw__zlib_huff1(n) : (n) <= 255 ? stbiw__zlib_huff2(n) : (n) <= 279 ? stbiw__zlib_huff3(n) : stbiw__zlib_huff4(n)) +#define stbiw__zlib_huffb(n) ((n) <= 143 ? stbiw__zlib_huff1(n) : stbiw__zlib_huff2(n)) + +#define stbiw__ZHASH 16384 + +#endif // STBIW_ZLIB_COMPRESS + +STBIWDEF unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_len, int quality) +{ +#ifdef STBIW_ZLIB_COMPRESS + // user provided a zlib compress implementation, use that + return STBIW_ZLIB_COMPRESS(data, data_len, out_len, quality); +#else // use builtin + static unsigned short lengthc[] = { 3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258, 259 }; + static unsigned char lengtheb[]= { 0,0,0,0,0,0,0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0 }; + static unsigned short distc[] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577, 32768 }; + static unsigned char disteb[] = { 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13 }; + unsigned int bitbuf=0; + int i,j, bitcount=0; + unsigned char *out = NULL; + unsigned char ***hash_table = (unsigned char***) STBIW_MALLOC(stbiw__ZHASH * sizeof(unsigned char**)); + if (hash_table == NULL) + return NULL; + if (quality < 5) quality = 5; + + stbiw__sbpush(out, 0x78); // DEFLATE 32K window + stbiw__sbpush(out, 0x5e); // FLEVEL = 1 + stbiw__zlib_add(1,1); // BFINAL = 1 + stbiw__zlib_add(1,2); // BTYPE = 1 -- fixed huffman + + for (i=0; i < stbiw__ZHASH; ++i) + hash_table[i] = NULL; + + i=0; + while (i < data_len-3) { + // hash next 3 bytes of data to be compressed + int h = stbiw__zhash(data+i)&(stbiw__ZHASH-1), best=3; + unsigned char *bestloc = 0; + unsigned char **hlist = hash_table[h]; + int n = stbiw__sbcount(hlist); + for (j=0; j < n; ++j) { + if (hlist[j]-data > i-32768) { // if entry lies within window + int d = stbiw__zlib_countm(hlist[j], data+i, data_len-i); + if (d >= best) { best=d; bestloc=hlist[j]; } + } + } + // when hash table entry is too long, delete half the entries + if (hash_table[h] && stbiw__sbn(hash_table[h]) == 2*quality) { + STBIW_MEMMOVE(hash_table[h], hash_table[h]+quality, sizeof(hash_table[h][0])*quality); + stbiw__sbn(hash_table[h]) = quality; + } + stbiw__sbpush(hash_table[h],data+i); + + if (bestloc) { + // "lazy matching" - check match at *next* byte, and if it's better, do cur byte as literal + h = stbiw__zhash(data+i+1)&(stbiw__ZHASH-1); + hlist = hash_table[h]; + n = stbiw__sbcount(hlist); + for (j=0; j < n; ++j) { + if (hlist[j]-data > i-32767) { + int e = stbiw__zlib_countm(hlist[j], data+i+1, data_len-i-1); + if (e > best) { // if next match is better, bail on current match + bestloc = NULL; + break; + } + } + } + } + + if (bestloc) { + int d = (int) (data+i - bestloc); // distance back + STBIW_ASSERT(d <= 32767 && best <= 258); + for (j=0; best > lengthc[j+1]-1; ++j); + stbiw__zlib_huff(j+257); + if (lengtheb[j]) stbiw__zlib_add(best - lengthc[j], lengtheb[j]); + for (j=0; d > distc[j+1]-1; ++j); + stbiw__zlib_add(stbiw__zlib_bitrev(j,5),5); + if (disteb[j]) stbiw__zlib_add(d - distc[j], disteb[j]); + i += best; + } else { + stbiw__zlib_huffb(data[i]); + ++i; + } + } + // write out final bytes + for (;i < data_len; ++i) + stbiw__zlib_huffb(data[i]); + stbiw__zlib_huff(256); // end of block + // pad with 0 bits to byte boundary + while (bitcount) + stbiw__zlib_add(0,1); + + for (i=0; i < stbiw__ZHASH; ++i) + (void) stbiw__sbfree(hash_table[i]); + STBIW_FREE(hash_table); + + // store uncompressed instead if compression was worse + if (stbiw__sbn(out) > data_len + 2 + ((data_len+32766)/32767)*5) { + stbiw__sbn(out) = 2; // truncate to DEFLATE 32K window and FLEVEL = 1 + for (j = 0; j < data_len;) { + int blocklen = data_len - j; + if (blocklen > 32767) blocklen = 32767; + stbiw__sbpush(out, data_len - j == blocklen); // BFINAL = ?, BTYPE = 0 -- no compression + stbiw__sbpush(out, STBIW_UCHAR(blocklen)); // LEN + stbiw__sbpush(out, STBIW_UCHAR(blocklen >> 8)); + stbiw__sbpush(out, STBIW_UCHAR(~blocklen)); // NLEN + stbiw__sbpush(out, STBIW_UCHAR(~blocklen >> 8)); + memcpy(out+stbiw__sbn(out), data+j, blocklen); + stbiw__sbn(out) += blocklen; + j += blocklen; + } + } + + { + // compute adler32 on input + unsigned int s1=1, s2=0; + int blocklen = (int) (data_len % 5552); + j=0; + while (j < data_len) { + for (i=0; i < blocklen; ++i) { s1 += data[j+i]; s2 += s1; } + s1 %= 65521; s2 %= 65521; + j += blocklen; + blocklen = 5552; + } + stbiw__sbpush(out, STBIW_UCHAR(s2 >> 8)); + stbiw__sbpush(out, STBIW_UCHAR(s2)); + stbiw__sbpush(out, STBIW_UCHAR(s1 >> 8)); + stbiw__sbpush(out, STBIW_UCHAR(s1)); + } + *out_len = stbiw__sbn(out); + // make returned pointer freeable + STBIW_MEMMOVE(stbiw__sbraw(out), out, *out_len); + return (unsigned char *) stbiw__sbraw(out); +#endif // STBIW_ZLIB_COMPRESS +} + +static unsigned int stbiw__crc32(unsigned char *buffer, int len) +{ +#ifdef STBIW_CRC32 + return STBIW_CRC32(buffer, len); +#else + static unsigned int crc_table[256] = + { + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, + 0x0eDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, + 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, + 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, + 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, + 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, + 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, + 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, + 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, + 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, + 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, + 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, + 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, + 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, + 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, + 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, + 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, + 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, + 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, + 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, + 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, + 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D + }; + + unsigned int crc = ~0u; + int i; + for (i=0; i < len; ++i) + crc = (crc >> 8) ^ crc_table[buffer[i] ^ (crc & 0xff)]; + return ~crc; +#endif +} + +#define stbiw__wpng4(o,a,b,c,d) ((o)[0]=STBIW_UCHAR(a),(o)[1]=STBIW_UCHAR(b),(o)[2]=STBIW_UCHAR(c),(o)[3]=STBIW_UCHAR(d),(o)+=4) +#define stbiw__wp32(data,v) stbiw__wpng4(data, (v)>>24,(v)>>16,(v)>>8,(v)); +#define stbiw__wptag(data,s) stbiw__wpng4(data, s[0],s[1],s[2],s[3]) + +static void stbiw__wpcrc(unsigned char **data, int len) +{ + unsigned int crc = stbiw__crc32(*data - len - 4, len+4); + stbiw__wp32(*data, crc); +} + +static unsigned char stbiw__paeth(int a, int b, int c) +{ + int p = a + b - c, pa = abs(p-a), pb = abs(p-b), pc = abs(p-c); + if (pa <= pb && pa <= pc) return STBIW_UCHAR(a); + if (pb <= pc) return STBIW_UCHAR(b); + return STBIW_UCHAR(c); +} + +// @OPTIMIZE: provide an option that always forces left-predict or paeth predict +static void stbiw__encode_png_line(unsigned char *pixels, int stride_bytes, int width, int height, int y, int n, int filter_type, signed char *line_buffer) +{ + static int mapping[] = { 0,1,2,3,4 }; + static int firstmap[] = { 0,1,0,5,6 }; + int *mymap = (y != 0) ? mapping : firstmap; + int i; + int type = mymap[filter_type]; + unsigned char *z = pixels + stride_bytes * (stbi__flip_vertically_on_write ? height-1-y : y); + int signed_stride = stbi__flip_vertically_on_write ? -stride_bytes : stride_bytes; + + if (type==0) { + memcpy(line_buffer, z, width*n); + return; + } + + // first loop isn't optimized since it's just one pixel + for (i = 0; i < n; ++i) { + switch (type) { + case 1: line_buffer[i] = z[i]; break; + case 2: line_buffer[i] = z[i] - z[i-signed_stride]; break; + case 3: line_buffer[i] = z[i] - (z[i-signed_stride]>>1); break; + case 4: line_buffer[i] = (signed char) (z[i] - stbiw__paeth(0,z[i-signed_stride],0)); break; + case 5: line_buffer[i] = z[i]; break; + case 6: line_buffer[i] = z[i]; break; + } + } + switch (type) { + case 1: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - z[i-n]; break; + case 2: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - z[i-signed_stride]; break; + case 3: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - ((z[i-n] + z[i-signed_stride])>>1); break; + case 4: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - stbiw__paeth(z[i-n], z[i-signed_stride], z[i-signed_stride-n]); break; + case 5: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - (z[i-n]>>1); break; + case 6: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - stbiw__paeth(z[i-n], 0,0); break; + } +} + +STBIWDEF unsigned char *stbi_write_png_to_mem(const unsigned char *pixels, int stride_bytes, int x, int y, int n, int *out_len) +{ + int force_filter = stbi_write_force_png_filter; + int ctype[5] = { -1, 0, 4, 2, 6 }; + unsigned char sig[8] = { 137,80,78,71,13,10,26,10 }; + unsigned char *out,*o, *filt, *zlib; + signed char *line_buffer; + int j,zlen; + + if (stride_bytes == 0) + stride_bytes = x * n; + + if (force_filter >= 5) { + force_filter = -1; + } + + filt = (unsigned char *) STBIW_MALLOC((x*n+1) * y); if (!filt) return 0; + line_buffer = (signed char *) STBIW_MALLOC(x * n); if (!line_buffer) { STBIW_FREE(filt); return 0; } + for (j=0; j < y; ++j) { + int filter_type; + if (force_filter > -1) { + filter_type = force_filter; + stbiw__encode_png_line((unsigned char*)(pixels), stride_bytes, x, y, j, n, force_filter, line_buffer); + } else { // Estimate the best filter by running through all of them: + int best_filter = 0, best_filter_val = 0x7fffffff, est, i; + for (filter_type = 0; filter_type < 5; filter_type++) { + stbiw__encode_png_line((unsigned char*)(pixels), stride_bytes, x, y, j, n, filter_type, line_buffer); + + // Estimate the entropy of the line using this filter; the less, the better. + est = 0; + for (i = 0; i < x*n; ++i) { + est += abs((signed char) line_buffer[i]); + } + if (est < best_filter_val) { + best_filter_val = est; + best_filter = filter_type; + } + } + if (filter_type != best_filter) { // If the last iteration already got us the best filter, don't redo it + stbiw__encode_png_line((unsigned char*)(pixels), stride_bytes, x, y, j, n, best_filter, line_buffer); + filter_type = best_filter; + } + } + // when we get here, filter_type contains the filter type, and line_buffer contains the data + filt[j*(x*n+1)] = (unsigned char) filter_type; + STBIW_MEMMOVE(filt+j*(x*n+1)+1, line_buffer, x*n); + } + STBIW_FREE(line_buffer); + zlib = stbi_zlib_compress(filt, y*( x*n+1), &zlen, stbi_write_png_compression_level); + STBIW_FREE(filt); + if (!zlib) return 0; + + // each tag requires 12 bytes of overhead + out = (unsigned char *) STBIW_MALLOC(8 + 12+13 + 12+zlen + 12); + if (!out) return 0; + *out_len = 8 + 12+13 + 12+zlen + 12; + + o=out; + STBIW_MEMMOVE(o,sig,8); o+= 8; + stbiw__wp32(o, 13); // header length + stbiw__wptag(o, "IHDR"); + stbiw__wp32(o, x); + stbiw__wp32(o, y); + *o++ = 8; + *o++ = STBIW_UCHAR(ctype[n]); + *o++ = 0; + *o++ = 0; + *o++ = 0; + stbiw__wpcrc(&o,13); + + stbiw__wp32(o, zlen); + stbiw__wptag(o, "IDAT"); + STBIW_MEMMOVE(o, zlib, zlen); + o += zlen; + STBIW_FREE(zlib); + stbiw__wpcrc(&o, zlen); + + stbiw__wp32(o,0); + stbiw__wptag(o, "IEND"); + stbiw__wpcrc(&o,0); + + STBIW_ASSERT(o == out + *out_len); + + return out; +} + +#ifndef STBI_WRITE_NO_STDIO +STBIWDEF int stbi_write_png(char const *filename, int x, int y, int comp, const void *data, int stride_bytes) +{ + FILE *f; + int len; + unsigned char *png = stbi_write_png_to_mem((const unsigned char *) data, stride_bytes, x, y, comp, &len); + if (png == NULL) return 0; + + f = stbiw__fopen(filename, "wb"); + if (!f) { STBIW_FREE(png); return 0; } + fwrite(png, 1, len, f); + fclose(f); + STBIW_FREE(png); + return 1; +} +#endif + +STBIWDEF int stbi_write_png_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int stride_bytes) +{ + int len; + unsigned char *png = stbi_write_png_to_mem((const unsigned char *) data, stride_bytes, x, y, comp, &len); + if (png == NULL) return 0; + func(context, png, len); + STBIW_FREE(png); + return 1; +} + + +/* *************************************************************************** + * + * JPEG writer + * + * This is based on Jon Olick's jo_jpeg.cpp: + * public domain Simple, Minimalistic JPEG writer - http://www.jonolick.com/code.html + */ + +static const unsigned char stbiw__jpg_ZigZag[] = { 0,1,5,6,14,15,27,28,2,4,7,13,16,26,29,42,3,8,12,17,25,30,41,43,9,11,18, + 24,31,40,44,53,10,19,23,32,39,45,52,54,20,22,33,38,46,51,55,60,21,34,37,47,50,56,59,61,35,36,48,49,57,58,62,63 }; + +static void stbiw__jpg_writeBits(stbi__write_context *s, int *bitBufP, int *bitCntP, const unsigned short *bs) { + int bitBuf = *bitBufP, bitCnt = *bitCntP; + bitCnt += bs[1]; + bitBuf |= bs[0] << (24 - bitCnt); + while(bitCnt >= 8) { + unsigned char c = (bitBuf >> 16) & 255; + stbiw__putc(s, c); + if(c == 255) { + stbiw__putc(s, 0); + } + bitBuf <<= 8; + bitCnt -= 8; + } + *bitBufP = bitBuf; + *bitCntP = bitCnt; +} + +static void stbiw__jpg_DCT(float *d0p, float *d1p, float *d2p, float *d3p, float *d4p, float *d5p, float *d6p, float *d7p) { + float d0 = *d0p, d1 = *d1p, d2 = *d2p, d3 = *d3p, d4 = *d4p, d5 = *d5p, d6 = *d6p, d7 = *d7p; + float z1, z2, z3, z4, z5, z11, z13; + + float tmp0 = d0 + d7; + float tmp7 = d0 - d7; + float tmp1 = d1 + d6; + float tmp6 = d1 - d6; + float tmp2 = d2 + d5; + float tmp5 = d2 - d5; + float tmp3 = d3 + d4; + float tmp4 = d3 - d4; + + // Even part + float tmp10 = tmp0 + tmp3; // phase 2 + float tmp13 = tmp0 - tmp3; + float tmp11 = tmp1 + tmp2; + float tmp12 = tmp1 - tmp2; + + d0 = tmp10 + tmp11; // phase 3 + d4 = tmp10 - tmp11; + + z1 = (tmp12 + tmp13) * 0.707106781f; // c4 + d2 = tmp13 + z1; // phase 5 + d6 = tmp13 - z1; + + // Odd part + tmp10 = tmp4 + tmp5; // phase 2 + tmp11 = tmp5 + tmp6; + tmp12 = tmp6 + tmp7; + + // The rotator is modified from fig 4-8 to avoid extra negations. + z5 = (tmp10 - tmp12) * 0.382683433f; // c6 + z2 = tmp10 * 0.541196100f + z5; // c2-c6 + z4 = tmp12 * 1.306562965f + z5; // c2+c6 + z3 = tmp11 * 0.707106781f; // c4 + + z11 = tmp7 + z3; // phase 5 + z13 = tmp7 - z3; + + *d5p = z13 + z2; // phase 6 + *d3p = z13 - z2; + *d1p = z11 + z4; + *d7p = z11 - z4; + + *d0p = d0; *d2p = d2; *d4p = d4; *d6p = d6; +} + +static void stbiw__jpg_calcBits(int val, unsigned short bits[2]) { + int tmp1 = val < 0 ? -val : val; + val = val < 0 ? val-1 : val; + bits[1] = 1; + while(tmp1 >>= 1) { + ++bits[1]; + } + bits[0] = val & ((1<0)&&(DU[end0pos]==0); --end0pos) { + } + // end0pos = first element in reverse order !=0 + if(end0pos == 0) { + stbiw__jpg_writeBits(s, bitBuf, bitCnt, EOB); + return DU[0]; + } + for(i = 1; i <= end0pos; ++i) { + int startpos = i; + int nrzeroes; + unsigned short bits[2]; + for (; DU[i]==0 && i<=end0pos; ++i) { + } + nrzeroes = i-startpos; + if ( nrzeroes >= 16 ) { + int lng = nrzeroes>>4; + int nrmarker; + for (nrmarker=1; nrmarker <= lng; ++nrmarker) + stbiw__jpg_writeBits(s, bitBuf, bitCnt, M16zeroes); + nrzeroes &= 15; + } + stbiw__jpg_calcBits(DU[i], bits); + stbiw__jpg_writeBits(s, bitBuf, bitCnt, HTAC[(nrzeroes<<4)+bits[1]]); + stbiw__jpg_writeBits(s, bitBuf, bitCnt, bits); + } + if(end0pos != 63) { + stbiw__jpg_writeBits(s, bitBuf, bitCnt, EOB); + } + return DU[0]; +} + +static int stbi_write_jpg_core(stbi__write_context *s, int width, int height, int comp, const void* data, int quality) { + // Constants that don't pollute global namespace + static const unsigned char std_dc_luminance_nrcodes[] = {0,0,1,5,1,1,1,1,1,1,0,0,0,0,0,0,0}; + static const unsigned char std_dc_luminance_values[] = {0,1,2,3,4,5,6,7,8,9,10,11}; + static const unsigned char std_ac_luminance_nrcodes[] = {0,0,2,1,3,3,2,4,3,5,5,4,4,0,0,1,0x7d}; + static const unsigned char std_ac_luminance_values[] = { + 0x01,0x02,0x03,0x00,0x04,0x11,0x05,0x12,0x21,0x31,0x41,0x06,0x13,0x51,0x61,0x07,0x22,0x71,0x14,0x32,0x81,0x91,0xa1,0x08, + 0x23,0x42,0xb1,0xc1,0x15,0x52,0xd1,0xf0,0x24,0x33,0x62,0x72,0x82,0x09,0x0a,0x16,0x17,0x18,0x19,0x1a,0x25,0x26,0x27,0x28, + 0x29,0x2a,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x53,0x54,0x55,0x56,0x57,0x58,0x59, + 0x5a,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x83,0x84,0x85,0x86,0x87,0x88,0x89, + 0x8a,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xb2,0xb3,0xb4,0xb5,0xb6, + 0xb7,0xb8,0xb9,0xba,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xe1,0xe2, + 0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa + }; + static const unsigned char std_dc_chrominance_nrcodes[] = {0,0,3,1,1,1,1,1,1,1,1,1,0,0,0,0,0}; + static const unsigned char std_dc_chrominance_values[] = {0,1,2,3,4,5,6,7,8,9,10,11}; + static const unsigned char std_ac_chrominance_nrcodes[] = {0,0,2,1,2,4,4,3,4,7,5,4,4,0,1,2,0x77}; + static const unsigned char std_ac_chrominance_values[] = { + 0x00,0x01,0x02,0x03,0x11,0x04,0x05,0x21,0x31,0x06,0x12,0x41,0x51,0x07,0x61,0x71,0x13,0x22,0x32,0x81,0x08,0x14,0x42,0x91, + 0xa1,0xb1,0xc1,0x09,0x23,0x33,0x52,0xf0,0x15,0x62,0x72,0xd1,0x0a,0x16,0x24,0x34,0xe1,0x25,0xf1,0x17,0x18,0x19,0x1a,0x26, + 0x27,0x28,0x29,0x2a,0x35,0x36,0x37,0x38,0x39,0x3a,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x53,0x54,0x55,0x56,0x57,0x58, + 0x59,0x5a,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x82,0x83,0x84,0x85,0x86,0x87, + 0x88,0x89,0x8a,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xb2,0xb3,0xb4, + 0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda, + 0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa + }; + // Huffman tables + static const unsigned short YDC_HT[256][2] = { {0,2},{2,3},{3,3},{4,3},{5,3},{6,3},{14,4},{30,5},{62,6},{126,7},{254,8},{510,9}}; + static const unsigned short UVDC_HT[256][2] = { {0,2},{1,2},{2,2},{6,3},{14,4},{30,5},{62,6},{126,7},{254,8},{510,9},{1022,10},{2046,11}}; + static const unsigned short YAC_HT[256][2] = { + {10,4},{0,2},{1,2},{4,3},{11,4},{26,5},{120,7},{248,8},{1014,10},{65410,16},{65411,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {12,4},{27,5},{121,7},{502,9},{2038,11},{65412,16},{65413,16},{65414,16},{65415,16},{65416,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {28,5},{249,8},{1015,10},{4084,12},{65417,16},{65418,16},{65419,16},{65420,16},{65421,16},{65422,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {58,6},{503,9},{4085,12},{65423,16},{65424,16},{65425,16},{65426,16},{65427,16},{65428,16},{65429,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {59,6},{1016,10},{65430,16},{65431,16},{65432,16},{65433,16},{65434,16},{65435,16},{65436,16},{65437,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {122,7},{2039,11},{65438,16},{65439,16},{65440,16},{65441,16},{65442,16},{65443,16},{65444,16},{65445,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {123,7},{4086,12},{65446,16},{65447,16},{65448,16},{65449,16},{65450,16},{65451,16},{65452,16},{65453,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {250,8},{4087,12},{65454,16},{65455,16},{65456,16},{65457,16},{65458,16},{65459,16},{65460,16},{65461,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {504,9},{32704,15},{65462,16},{65463,16},{65464,16},{65465,16},{65466,16},{65467,16},{65468,16},{65469,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {505,9},{65470,16},{65471,16},{65472,16},{65473,16},{65474,16},{65475,16},{65476,16},{65477,16},{65478,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {506,9},{65479,16},{65480,16},{65481,16},{65482,16},{65483,16},{65484,16},{65485,16},{65486,16},{65487,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {1017,10},{65488,16},{65489,16},{65490,16},{65491,16},{65492,16},{65493,16},{65494,16},{65495,16},{65496,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {1018,10},{65497,16},{65498,16},{65499,16},{65500,16},{65501,16},{65502,16},{65503,16},{65504,16},{65505,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {2040,11},{65506,16},{65507,16},{65508,16},{65509,16},{65510,16},{65511,16},{65512,16},{65513,16},{65514,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {65515,16},{65516,16},{65517,16},{65518,16},{65519,16},{65520,16},{65521,16},{65522,16},{65523,16},{65524,16},{0,0},{0,0},{0,0},{0,0},{0,0}, + {2041,11},{65525,16},{65526,16},{65527,16},{65528,16},{65529,16},{65530,16},{65531,16},{65532,16},{65533,16},{65534,16},{0,0},{0,0},{0,0},{0,0},{0,0} + }; + static const unsigned short UVAC_HT[256][2] = { + {0,2},{1,2},{4,3},{10,4},{24,5},{25,5},{56,6},{120,7},{500,9},{1014,10},{4084,12},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {11,4},{57,6},{246,8},{501,9},{2038,11},{4085,12},{65416,16},{65417,16},{65418,16},{65419,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {26,5},{247,8},{1015,10},{4086,12},{32706,15},{65420,16},{65421,16},{65422,16},{65423,16},{65424,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {27,5},{248,8},{1016,10},{4087,12},{65425,16},{65426,16},{65427,16},{65428,16},{65429,16},{65430,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {58,6},{502,9},{65431,16},{65432,16},{65433,16},{65434,16},{65435,16},{65436,16},{65437,16},{65438,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {59,6},{1017,10},{65439,16},{65440,16},{65441,16},{65442,16},{65443,16},{65444,16},{65445,16},{65446,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {121,7},{2039,11},{65447,16},{65448,16},{65449,16},{65450,16},{65451,16},{65452,16},{65453,16},{65454,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {122,7},{2040,11},{65455,16},{65456,16},{65457,16},{65458,16},{65459,16},{65460,16},{65461,16},{65462,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {249,8},{65463,16},{65464,16},{65465,16},{65466,16},{65467,16},{65468,16},{65469,16},{65470,16},{65471,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {503,9},{65472,16},{65473,16},{65474,16},{65475,16},{65476,16},{65477,16},{65478,16},{65479,16},{65480,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {504,9},{65481,16},{65482,16},{65483,16},{65484,16},{65485,16},{65486,16},{65487,16},{65488,16},{65489,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {505,9},{65490,16},{65491,16},{65492,16},{65493,16},{65494,16},{65495,16},{65496,16},{65497,16},{65498,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {506,9},{65499,16},{65500,16},{65501,16},{65502,16},{65503,16},{65504,16},{65505,16},{65506,16},{65507,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {2041,11},{65508,16},{65509,16},{65510,16},{65511,16},{65512,16},{65513,16},{65514,16},{65515,16},{65516,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {16352,14},{65517,16},{65518,16},{65519,16},{65520,16},{65521,16},{65522,16},{65523,16},{65524,16},{65525,16},{0,0},{0,0},{0,0},{0,0},{0,0}, + {1018,10},{32707,15},{65526,16},{65527,16},{65528,16},{65529,16},{65530,16},{65531,16},{65532,16},{65533,16},{65534,16},{0,0},{0,0},{0,0},{0,0},{0,0} + }; + static const int YQT[] = {16,11,10,16,24,40,51,61,12,12,14,19,26,58,60,55,14,13,16,24,40,57,69,56,14,17,22,29,51,87,80,62,18,22, + 37,56,68,109,103,77,24,35,55,64,81,104,113,92,49,64,78,87,103,121,120,101,72,92,95,98,112,100,103,99}; + static const int UVQT[] = {17,18,24,47,99,99,99,99,18,21,26,66,99,99,99,99,24,26,56,99,99,99,99,99,47,66,99,99,99,99,99,99, + 99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99}; + static const float aasf[] = { 1.0f * 2.828427125f, 1.387039845f * 2.828427125f, 1.306562965f * 2.828427125f, 1.175875602f * 2.828427125f, + 1.0f * 2.828427125f, 0.785694958f * 2.828427125f, 0.541196100f * 2.828427125f, 0.275899379f * 2.828427125f }; + + int row, col, i, k, subsample; + float fdtbl_Y[64], fdtbl_UV[64]; + unsigned char YTable[64], UVTable[64]; + + if(!data || !width || !height || comp > 4 || comp < 1) { + return 0; + } + + quality = quality ? quality : 90; + subsample = quality <= 90 ? 1 : 0; + quality = quality < 1 ? 1 : quality > 100 ? 100 : quality; + quality = quality < 50 ? 5000 / quality : 200 - quality * 2; + + for(i = 0; i < 64; ++i) { + int uvti, yti = (YQT[i]*quality+50)/100; + YTable[stbiw__jpg_ZigZag[i]] = (unsigned char) (yti < 1 ? 1 : yti > 255 ? 255 : yti); + uvti = (UVQT[i]*quality+50)/100; + UVTable[stbiw__jpg_ZigZag[i]] = (unsigned char) (uvti < 1 ? 1 : uvti > 255 ? 255 : uvti); + } + + for(row = 0, k = 0; row < 8; ++row) { + for(col = 0; col < 8; ++col, ++k) { + fdtbl_Y[k] = 1 / (YTable [stbiw__jpg_ZigZag[k]] * aasf[row] * aasf[col]); + fdtbl_UV[k] = 1 / (UVTable[stbiw__jpg_ZigZag[k]] * aasf[row] * aasf[col]); + } + } + + // Write Headers + { + static const unsigned char head0[] = { 0xFF,0xD8,0xFF,0xE0,0,0x10,'J','F','I','F',0,1,1,0,0,1,0,1,0,0,0xFF,0xDB,0,0x84,0 }; + static const unsigned char head2[] = { 0xFF,0xDA,0,0xC,3,1,0,2,0x11,3,0x11,0,0x3F,0 }; + const unsigned char head1[] = { 0xFF,0xC0,0,0x11,8,(unsigned char)(height>>8),STBIW_UCHAR(height),(unsigned char)(width>>8),STBIW_UCHAR(width), + 3,1,(unsigned char)(subsample?0x22:0x11),0,2,0x11,1,3,0x11,1,0xFF,0xC4,0x01,0xA2,0 }; + s->func(s->context, (void*)head0, sizeof(head0)); + s->func(s->context, (void*)YTable, sizeof(YTable)); + stbiw__putc(s, 1); + s->func(s->context, UVTable, sizeof(UVTable)); + s->func(s->context, (void*)head1, sizeof(head1)); + s->func(s->context, (void*)(std_dc_luminance_nrcodes+1), sizeof(std_dc_luminance_nrcodes)-1); + s->func(s->context, (void*)std_dc_luminance_values, sizeof(std_dc_luminance_values)); + stbiw__putc(s, 0x10); // HTYACinfo + s->func(s->context, (void*)(std_ac_luminance_nrcodes+1), sizeof(std_ac_luminance_nrcodes)-1); + s->func(s->context, (void*)std_ac_luminance_values, sizeof(std_ac_luminance_values)); + stbiw__putc(s, 1); // HTUDCinfo + s->func(s->context, (void*)(std_dc_chrominance_nrcodes+1), sizeof(std_dc_chrominance_nrcodes)-1); + s->func(s->context, (void*)std_dc_chrominance_values, sizeof(std_dc_chrominance_values)); + stbiw__putc(s, 0x11); // HTUACinfo + s->func(s->context, (void*)(std_ac_chrominance_nrcodes+1), sizeof(std_ac_chrominance_nrcodes)-1); + s->func(s->context, (void*)std_ac_chrominance_values, sizeof(std_ac_chrominance_values)); + s->func(s->context, (void*)head2, sizeof(head2)); + } + + // Encode 8x8 macroblocks + { + static const unsigned short fillBits[] = {0x7F, 7}; + int DCY=0, DCU=0, DCV=0; + int bitBuf=0, bitCnt=0; + // comp == 2 is grey+alpha (alpha is ignored) + int ofsG = comp > 2 ? 1 : 0, ofsB = comp > 2 ? 2 : 0; + const unsigned char *dataR = (const unsigned char *)data; + const unsigned char *dataG = dataR + ofsG; + const unsigned char *dataB = dataR + ofsB; + int x, y, pos; + if(subsample) { + for(y = 0; y < height; y += 16) { + for(x = 0; x < width; x += 16) { + float Y[256], U[256], V[256]; + for(row = y, pos = 0; row < y+16; ++row) { + // row >= height => use last input row + int clamped_row = (row < height) ? row : height - 1; + int base_p = (stbi__flip_vertically_on_write ? (height-1-clamped_row) : clamped_row)*width*comp; + for(col = x; col < x+16; ++col, ++pos) { + // if col >= width => use pixel from last input column + int p = base_p + ((col < width) ? col : (width-1))*comp; + float r = dataR[p], g = dataG[p], b = dataB[p]; + Y[pos]= +0.29900f*r + 0.58700f*g + 0.11400f*b - 128; + U[pos]= -0.16874f*r - 0.33126f*g + 0.50000f*b; + V[pos]= +0.50000f*r - 0.41869f*g - 0.08131f*b; + } + } + DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+0, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT); + DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+8, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT); + DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+128, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT); + DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+136, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT); + + // subsample U,V + { + float subU[64], subV[64]; + int yy, xx; + for(yy = 0, pos = 0; yy < 8; ++yy) { + for(xx = 0; xx < 8; ++xx, ++pos) { + int j = yy*32+xx*2; + subU[pos] = (U[j+0] + U[j+1] + U[j+16] + U[j+17]) * 0.25f; + subV[pos] = (V[j+0] + V[j+1] + V[j+16] + V[j+17]) * 0.25f; + } + } + DCU = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, subU, 8, fdtbl_UV, DCU, UVDC_HT, UVAC_HT); + DCV = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, subV, 8, fdtbl_UV, DCV, UVDC_HT, UVAC_HT); + } + } + } + } else { + for(y = 0; y < height; y += 8) { + for(x = 0; x < width; x += 8) { + float Y[64], U[64], V[64]; + for(row = y, pos = 0; row < y+8; ++row) { + // row >= height => use last input row + int clamped_row = (row < height) ? row : height - 1; + int base_p = (stbi__flip_vertically_on_write ? (height-1-clamped_row) : clamped_row)*width*comp; + for(col = x; col < x+8; ++col, ++pos) { + // if col >= width => use pixel from last input column + int p = base_p + ((col < width) ? col : (width-1))*comp; + float r = dataR[p], g = dataG[p], b = dataB[p]; + Y[pos]= +0.29900f*r + 0.58700f*g + 0.11400f*b - 128; + U[pos]= -0.16874f*r - 0.33126f*g + 0.50000f*b; + V[pos]= +0.50000f*r - 0.41869f*g - 0.08131f*b; + } + } + + DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y, 8, fdtbl_Y, DCY, YDC_HT, YAC_HT); + DCU = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, U, 8, fdtbl_UV, DCU, UVDC_HT, UVAC_HT); + DCV = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, V, 8, fdtbl_UV, DCV, UVDC_HT, UVAC_HT); + } + } + } + + // Do the bit alignment of the EOI marker + stbiw__jpg_writeBits(s, &bitBuf, &bitCnt, fillBits); + } + + // EOI + stbiw__putc(s, 0xFF); + stbiw__putc(s, 0xD9); + + return 1; +} + +STBIWDEF int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int quality) +{ + stbi__write_context s = { 0 }; + stbi__start_write_callbacks(&s, func, context); + return stbi_write_jpg_core(&s, x, y, comp, (void *) data, quality); +} + + +#ifndef STBI_WRITE_NO_STDIO +STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const void *data, int quality) +{ + stbi__write_context s = { 0 }; + if (stbi__start_write_file(&s,filename)) { + int r = stbi_write_jpg_core(&s, x, y, comp, data, quality); + stbi__end_write_file(&s); + return r; + } else + return 0; +} +#endif + +#endif // STB_IMAGE_WRITE_IMPLEMENTATION + +/* Revision history + 1.16 (2021-07-11) + make Deflate code emit uncompressed blocks when it would otherwise expand + support writing BMPs with alpha channel + 1.15 (2020-07-13) unknown + 1.14 (2020-02-02) updated JPEG writer to downsample chroma channels + 1.13 + 1.12 + 1.11 (2019-08-11) + + 1.10 (2019-02-07) + support utf8 filenames in Windows; fix warnings and platform ifdefs + 1.09 (2018-02-11) + fix typo in zlib quality API, improve STB_I_W_STATIC in C++ + 1.08 (2018-01-29) + add stbi__flip_vertically_on_write, external zlib, zlib quality, choose PNG filter + 1.07 (2017-07-24) + doc fix + 1.06 (2017-07-23) + writing JPEG (using Jon Olick's code) + 1.05 ??? + 1.04 (2017-03-03) + monochrome BMP expansion + 1.03 ??? + 1.02 (2016-04-02) + avoid allocating large structures on the stack + 1.01 (2016-01-16) + STBIW_REALLOC_SIZED: support allocators with no realloc support + avoid race-condition in crc initialization + minor compile issues + 1.00 (2015-09-14) + installable file IO function + 0.99 (2015-09-13) + warning fixes; TGA rle support + 0.98 (2015-04-08) + added STBIW_MALLOC, STBIW_ASSERT etc + 0.97 (2015-01-18) + fixed HDR asserts, rewrote HDR rle logic + 0.96 (2015-01-17) + add HDR output + fix monochrome BMP + 0.95 (2014-08-17) + add monochrome TGA output + 0.94 (2014-05-31) + rename private functions to avoid conflicts with stb_image.h + 0.93 (2014-05-27) + warning fixes + 0.92 (2010-08-01) + casts to unsigned char to fix warnings + 0.91 (2010-07-17) + first public release + 0.90 first internal release +*/ + +/* +------------------------------------------------------------------------------ +This software is available under 2 licenses -- choose whichever you prefer. +------------------------------------------------------------------------------ +ALTERNATIVE A - MIT License +Copyright (c) 2017 Sean Barrett +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +------------------------------------------------------------------------------ +ALTERNATIVE B - Public Domain (www.unlicense.org) +This is free and unencumbered software released into the public domain. +Anyone is free to copy, modify, publish, use, compile, sell, or distribute this +software, either in source code form or as a compiled binary, for any purpose, +commercial or non-commercial, and by any means. +In jurisdictions that recognize copyright laws, the author or authors of this +software dedicate any and all copyright interest in the software to the public +domain. We make this dedication for the benefit of the public at large and to +the detriment of our heirs and successors. We intend this dedication to be an +overt act of relinquishment in perpetuity of all present and future rights to +this software under copyright law. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +------------------------------------------------------------------------------ +*/ diff --git a/CristalDiskMark/source/CrystalDiskMark/Priscilla/stb_image_write_impl.cpp b/CristalDiskMark/source/CrystalDiskMark/Priscilla/stb_image_write_impl.cpp new file mode 100644 index 0000000..f075420 --- /dev/null +++ b/CristalDiskMark/source/CrystalDiskMark/Priscilla/stb_image_write_impl.cpp @@ -0,0 +1,13 @@ +/*---------------------------------------------------------------------------*/ +// Author : hiyohiyo +// Mail : hiyohiyo@crystalmark.info +// Web : https://crystalmark.info/ +// License : MIT License +/*---------------------------------------------------------------------------*/ + +#include "stdafx.h" +#define STBI_NO_STDIO +#define STBI_WRITE_NO_STDIO +#define STB_IMAGE_WRITE_IMPLEMENTATION +#include "stb_image_write.h" + diff --git a/CristalDiskMark/source/CrystalDiskMark/SettingsDlg.cpp b/CristalDiskMark/source/CrystalDiskMark/SettingsDlg.cpp new file mode 100644 index 0000000..d7e7844 --- /dev/null +++ b/CristalDiskMark/source/CrystalDiskMark/SettingsDlg.cpp @@ -0,0 +1,700 @@ +/*---------------------------------------------------------------------------*/ +// Author : hiyohiyo +// Mail : hiyohiyo@crystalmark.info +// Web : https://crystalmark.info/ +// License : MIT License +/*---------------------------------------------------------------------------*/ + +#include "stdafx.h" +#include "DiskMark.h" +#include "DiskMarkDlg.h" +#include "SettingsDlg.h" + +IMPLEMENT_DYNCREATE(CSettingsDlg, CDialog) + +CSettingsDlg::CSettingsDlg(CWnd* pParent /*=NULL*/) + : CDialogFx(CSettingsDlg::IDD, pParent) +{ + CMainDialogFx* p = (CMainDialogFx*)pParent; + + m_ZoomType = p->GetZoomType(); + m_FontScale = p->GetFontScale(); + m_FontRatio = p->GetFontRatio(); + m_FontFace = p->GetFontFace(); + m_FontRender = p->GetFontRender(); + m_CurrentLangPath = p->GetCurrentLangPath(); + m_DefaultLangPath = p->GetDefaultLangPath(); + m_ThemeDir = p->GetThemeDir(); + m_CurrentTheme = p->GetCurrentTheme(); + m_DefaultTheme = p->GetDefaultTheme(); + m_Ini = p->GetIniPath(); + + m_Profile = ((CDiskMarkDlg*)pParent)->m_Profile; + m_MeasureTime = ((CDiskMarkDlg*)pParent)->m_MeasureTime; + m_IntervalTime = ((CDiskMarkDlg*)pParent)->m_IntervalTime; + m_TestData = ((CDiskMarkDlg*)pParent)->m_TestData; +} + +CSettingsDlg::~CSettingsDlg() +{ +} + +void CSettingsDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialogFx::DoDataExchange(pDX); + + DDX_Control(pDX, IDC_LABEL_TYPE, m_LabelType); + DDX_Control(pDX, IDC_LABEL_SIZE, m_LabelSize); + DDX_Control(pDX, IDC_LABEL_QUEUES, m_LabelQueues); + DDX_Control(pDX, IDC_LABEL_THREADS, m_LabelThreads); + DDX_Control(pDX, IDC_LABEL_DEFAULT, m_LabelDefault); + DDX_Control(pDX, IDC_LABEL_PEAK, m_LabelPeak); + DDX_Control(pDX, IDC_LABEL_DEMO, m_LabelDemo); + + DDX_Control(pDX, IDC_LABEL_MEASURE_TIME, m_LabelMeasureTime); + DDX_Control(pDX, IDC_LABEL_INTERVAL_TIME, m_LabelIntervalTime); +// DDX_Control(pDX, IDC_LABEL_AFFINITY, m_LabelAffinity); +// DDX_Control(pDX, IDC_LABEL_DATA, m_LabelData); + + DDX_Control(pDX, IDC_SET_DEFAULT, m_ButtonSetDefault); + DDX_Control(pDX, IDC_SET_NVME_8, m_ButtonSetNVMe8); + DDX_Control(pDX, IDC_SET_FLASH_MEMORY, m_ButtonSetFlashMemory); + + DDX_Control(pDX, IDC_COMBO_BENCH_TYPE_0, m_ComboBenchType0); + DDX_Control(pDX, IDC_COMBO_BENCH_TYPE_1, m_ComboBenchType1); + DDX_Control(pDX, IDC_COMBO_BENCH_TYPE_2, m_ComboBenchType2); + DDX_Control(pDX, IDC_COMBO_BENCH_TYPE_3, m_ComboBenchType3); + DDX_Control(pDX, IDC_COMBO_BENCH_TYPE_4, m_ComboBenchType4); + DDX_Control(pDX, IDC_COMBO_BENCH_TYPE_5, m_ComboBenchType5); + DDX_Control(pDX, IDC_COMBO_BENCH_TYPE_8, m_ComboBenchType8); + + DDX_Control(pDX, IDC_COMBO_BENCH_SIZE_0, m_ComboBenchSize0); + DDX_Control(pDX, IDC_COMBO_BENCH_SIZE_1, m_ComboBenchSize1); + DDX_Control(pDX, IDC_COMBO_BENCH_SIZE_2, m_ComboBenchSize2); + DDX_Control(pDX, IDC_COMBO_BENCH_SIZE_3, m_ComboBenchSize3); + DDX_Control(pDX, IDC_COMBO_BENCH_SIZE_4, m_ComboBenchSize4); + DDX_Control(pDX, IDC_COMBO_BENCH_SIZE_5, m_ComboBenchSize5); + DDX_Control(pDX, IDC_COMBO_BENCH_SIZE_8, m_ComboBenchSize8); + + DDX_Control(pDX, IDC_COMBO_BENCH_QUEUE_0, m_ComboBenchQueues0); + DDX_Control(pDX, IDC_COMBO_BENCH_QUEUE_1, m_ComboBenchQueues1); + DDX_Control(pDX, IDC_COMBO_BENCH_QUEUE_2, m_ComboBenchQueues2); + DDX_Control(pDX, IDC_COMBO_BENCH_QUEUE_3, m_ComboBenchQueues3); + DDX_Control(pDX, IDC_COMBO_BENCH_QUEUE_4, m_ComboBenchQueues4); + DDX_Control(pDX, IDC_COMBO_BENCH_QUEUE_5, m_ComboBenchQueues5); + DDX_Control(pDX, IDC_COMBO_BENCH_QUEUE_8, m_ComboBenchQueues8); + + DDX_Control(pDX, IDC_COMBO_BENCH_THREAD_0, m_ComboBenchThreads0); + DDX_Control(pDX, IDC_COMBO_BENCH_THREAD_1, m_ComboBenchThreads1); + DDX_Control(pDX, IDC_COMBO_BENCH_THREAD_2, m_ComboBenchThreads2); + DDX_Control(pDX, IDC_COMBO_BENCH_THREAD_3, m_ComboBenchThreads3); + DDX_Control(pDX, IDC_COMBO_BENCH_THREAD_4, m_ComboBenchThreads4); + DDX_Control(pDX, IDC_COMBO_BENCH_THREAD_5, m_ComboBenchThreads5); + DDX_Control(pDX, IDC_COMBO_BENCH_THREAD_8, m_ComboBenchThreads8); + +// DDX_Control(pDX, IDC_COMBO_DATA, m_ComboData); +// DDX_Control(pDX, IDC_COMBO_AFFINITY, m_ComboAffinity); + DDX_Control(pDX, IDC_COMBO_MEASURE_TIME, m_ComboMeasureTime); + DDX_Control(pDX, IDC_COMBO_INTERVAL_TIME, m_ComboIntervalTime); + DDX_Control(pDX, IDC_OK, m_ButtonOk); +} + +BEGIN_MESSAGE_MAP(CSettingsDlg, CDialogFx) + ON_BN_CLICKED(IDC_SET_DEFAULT, &CSettingsDlg::OnSetDefault) + ON_BN_CLICKED(IDC_SET_NVME_8, &CSettingsDlg::OnSetNVMe8) + ON_BN_CLICKED(IDC_SET_FLASH_MEMORY, &CSettingsDlg::OnSetFlashMemory) + ON_BN_CLICKED(IDC_OK, &CSettingsDlg::OnOk) +END_MESSAGE_MAP() + +void CSettingsDlg::OnSetDefault() +{ + int type[9] = { 0, 0, 1, 1, 0, 1, 0, 1, 0 }; + int size[9] = { 1024, 1024, 4, 4, 1024, 4, 1024, 4, 1024 }; + int queues[9] = { 8, 1, 32, 1, 8, 32, 1, 1, 8 }; + int threads[9] = { 1, 1, 1, 1, 1, 1, 1, 1, 1 }; + + for (int i = 0; i < 9; i++) + { + m_BenchType[i] = type[i]; + m_BenchSize[i] = size[i]; + m_BenchQueues[i] = queues[i]; + m_BenchThreads[i] = threads[i]; + } + + m_TestData = 0; + m_MeasureTime = 5; + m_IntervalTime = 5; + InitComboBox(); +} + +void CSettingsDlg::OnSetNVMe8() +{ + int type[9] = { 0, 0, 1, 1, 0, 1, 0, 1, 0 }; + int size[9] = { 1024, 128, 4, 4, 1024, 4, 1024, 4, 1024 }; + int queues[9] = { 8, 32, 32, 1, 8, 32, 1, 1, 8 }; + int threads[9] = { 1, 1, 16, 1, 1, 16, 1, 1, 1 }; + + for (int i = 0; i < 9; i++) + { + m_BenchType[i] = type[i]; + m_BenchSize[i] = size[i]; + m_BenchQueues[i] = queues[i]; + m_BenchThreads[i] = threads[i]; + } + + m_TestData = 0; + m_MeasureTime = 5; + m_IntervalTime = 5; + + InitComboBox(); +} + +void CSettingsDlg::OnSetFlashMemory() +{ + int type[9] = { 0, 0, 1, 1, 0, 1, 0, 1, 0 }; + int size[9] = { 1024, 1024, 4, 4, 1024, 4, 1024, 4, 1024 }; + int queues[9] = { 8, 1, 32, 1, 8, 32, 1, 1, 8 }; + int threads[9] = { 1, 1, 1, 1, 1, 1, 1, 1, 1 }; + + for (int i = 0; i < 9; i++) + { + m_BenchType[i] = type[i]; + m_BenchSize[i] = size[i]; + m_BenchQueues[i] = queues[i]; + m_BenchThreads[i] = threads[i]; + } + + m_TestData = 0; + m_MeasureTime = 1; + m_IntervalTime = 30; + + InitComboBox(); +} + +BOOL CSettingsDlg::OnInitDialog() +{ + CDialogFx::OnInitDialog(); + + CString cstr; + + int type[9] = { 0, 0, 1, 1, 0, 1, 0, 1, 0 }; + int size[9] = { 1024, 1024, 4, 4, 1024, 4, 1024, 4, 1024 }; + int queues[9] = { 8, 1, 32, 1, 8, 32, 1, 1, 8 }; + int threads[9] = { 1, 1, 1, 1, 1, 1, 1, 1, 1 }; + + for (int i = 0; i < 9; i++) + { + cstr.Format(L"BenchType%d", i); + m_BenchType[i] = GetPrivateProfileInt(L"Setting", cstr, type[i], m_Ini); + if (m_BenchType[i] < 0 || m_BenchSize[i] > 1) { m_BenchSize[i] = type[i]; } + + cstr.Format(L"BenchSize%d", i); + m_BenchSize[i] = GetPrivateProfileInt(L"Setting", cstr, size[i], m_Ini); + if (m_BenchSize[i] <= 0 || m_BenchSize[i] > 8192) { m_BenchSize[i] = size[i]; } + + cstr.Format(L"BenchQueues%d", i); + m_BenchQueues[i] = GetPrivateProfileInt(L"Setting", cstr, queues[i], m_Ini); + if (m_BenchQueues[i] <= 0 || m_BenchQueues[i] > MAX_QUEUES) { m_BenchQueues[i] = queues[i]; } + + cstr.Format(L"BenchThreads%d", i); + m_BenchThreads[i] = GetPrivateProfileInt(L"Setting", cstr, threads[i], m_Ini); + if (m_BenchThreads[i] <= 0 || m_BenchThreads[i] > MAX_THREADS) { m_BenchThreads[i] = threads[i]; } + } + + m_TestData = GetPrivateProfileInt(L"Setting", L"TestData", 0, m_Ini); + if (m_TestData < 0 || m_TestData > 1) + { + m_TestData = 0; + } + + InitComboBox(); + + m_LabelType.SetWindowTextW(i18n(L"Dialog", L"TYPE")); + m_LabelSize.SetWindowTextW(i18n(L"Dialog", L"BLOCK_SIZE")); + m_LabelQueues.SetWindowTextW(i18n(L"Dialog", L"QUEUES")); + m_LabelThreads.SetWindowTextW(i18n(L"Dialog", L"THREADS")); + m_LabelDefault.SetWindowTextW(L" " + i18n(L"Dialog", L"PROFILE_DEFAULT")); + m_LabelPeak.SetWindowTextW(L" " + i18n(L"Dialog", L"PROFILE_PEAK_PERFORMANCE")); + m_LabelDemo.SetWindowTextW(L" " + i18n(L"Dialog", L"PROFILE_DEMO")); + m_LabelMeasureTime.SetWindowTextW(L" " + i18n(L"Dialog", L"MEASURE_TIME")); + m_LabelIntervalTime.SetWindowTextW(L" " + i18n(L"Dialog", L"INTERVAL_TIME")); + + m_ButtonSetDefault.SetWindowTextW(i18n(L"Dialog", L"DEFAULT")); + SetWindowTitle(i18n(L"WindowTitle", L"SETTINGS")); + + UpdateDialogSize(); + + return TRUE; +} + +void CSettingsDlg::InitComboBox() +{ + m_ComboBenchType0.ResetContent(); + m_ComboBenchType1.ResetContent(); + m_ComboBenchType2.ResetContent(); + m_ComboBenchType3.ResetContent(); + m_ComboBenchType4.ResetContent(); + m_ComboBenchType5.ResetContent(); + m_ComboBenchType8.ResetContent(); + + for (int i = 0; i < 2; i++) + { + CString cstr; + if (i == 0) + { + cstr.Format(L"SEQ"); + } + else + { + cstr.Format(L"RND"); + } + m_ComboBenchType0.AddString(cstr); if (m_BenchType[0] == i) { m_ComboBenchType0.SetCurSel(i); } + m_ComboBenchType1.AddString(cstr); if (m_BenchType[1] == i) { m_ComboBenchType1.SetCurSel(i); } + m_ComboBenchType2.AddString(cstr); if (m_BenchType[2] == i) { m_ComboBenchType2.SetCurSel(i); } + m_ComboBenchType3.AddString(cstr); if (m_BenchType[3] == i) { m_ComboBenchType3.SetCurSel(i); } + m_ComboBenchType4.AddString(cstr); if (m_BenchType[4] == i) { m_ComboBenchType4.SetCurSel(i); } + m_ComboBenchType5.AddString(cstr); if (m_BenchType[5] == i) { m_ComboBenchType5.SetCurSel(i); } + m_ComboBenchType8.AddString(cstr); if (m_BenchType[8] == i) { m_ComboBenchType8.SetCurSel(i); } + } + + m_ComboBenchSize0.ResetContent(); + m_ComboBenchSize1.ResetContent(); + m_ComboBenchSize2.ResetContent(); + m_ComboBenchSize3.ResetContent(); + m_ComboBenchSize4.ResetContent(); + m_ComboBenchSize5.ResetContent(); + m_ComboBenchSize8.ResetContent(); + + int blockSize[] = { 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192 }; + for (int i = 0; i < 12; i++) + { + CString cstr; + if (blockSize[i] >= 1024) + { + cstr.Format(L"%dMiB", blockSize[i] / 1024); + } + else + { + cstr.Format(L"%dKiB", blockSize[i]); + } + m_ComboBenchSize0.AddString(cstr); if (m_BenchSize[0] == blockSize[i]) { m_ComboBenchSize0.SetCurSel(i); } + m_ComboBenchSize1.AddString(cstr); if (m_BenchSize[1] == blockSize[i]) { m_ComboBenchSize1.SetCurSel(i); } + m_ComboBenchSize2.AddString(cstr); if (m_BenchSize[2] == blockSize[i]) { m_ComboBenchSize2.SetCurSel(i); } + m_ComboBenchSize3.AddString(cstr); if (m_BenchSize[3] == blockSize[i]) { m_ComboBenchSize3.SetCurSel(i); } + m_ComboBenchSize4.AddString(cstr); if (m_BenchSize[4] == blockSize[i]) { m_ComboBenchSize4.SetCurSel(i); } + m_ComboBenchSize5.AddString(cstr); if (m_BenchSize[5] == blockSize[i]) { m_ComboBenchSize5.SetCurSel(i); } + m_ComboBenchSize8.AddString(cstr); if (m_BenchSize[8] == blockSize[i]) { m_ComboBenchSize8.SetCurSel(i); } + } + + // Queues + m_ComboBenchQueues0.ResetContent(); + m_ComboBenchQueues1.ResetContent(); + m_ComboBenchQueues2.ResetContent(); + m_ComboBenchQueues3.ResetContent(); + m_ComboBenchQueues4.ResetContent(); + m_ComboBenchQueues5.ResetContent(); + m_ComboBenchQueues8.ResetContent(); + + int queues[10] = { 1, 2, 4, 8, 16, 32, 64, 128, 256, 512 }; + // Sequential + for (int i = 0; i < 10; i++) + { + CString cstr; + cstr.Format(L"%d", queues[i]); + m_ComboBenchQueues0.AddString(cstr); if (m_BenchQueues[0] == queues[i]) { m_ComboBenchQueues0.SetCurSel(i); } + m_ComboBenchQueues1.AddString(cstr); if (m_BenchQueues[1] == queues[i]) { m_ComboBenchQueues1.SetCurSel(i); } + m_ComboBenchQueues2.AddString(cstr); if (m_BenchQueues[2] == queues[i]) { m_ComboBenchQueues2.SetCurSel(i); } + m_ComboBenchQueues3.AddString(cstr); if (m_BenchQueues[3] == queues[i]) { m_ComboBenchQueues3.SetCurSel(i); } + m_ComboBenchQueues4.AddString(cstr); if (m_BenchQueues[4] == queues[i]) { m_ComboBenchQueues4.SetCurSel(i); } + m_ComboBenchQueues5.AddString(cstr); if (m_BenchQueues[5] == queues[i]) { m_ComboBenchQueues5.SetCurSel(i); } + m_ComboBenchQueues8.AddString(cstr); if (m_BenchQueues[8] == queues[i]) { m_ComboBenchQueues8.SetCurSel(i); } + } + + // Threads + m_ComboBenchThreads0.ResetContent(); + m_ComboBenchThreads1.ResetContent(); + m_ComboBenchThreads2.ResetContent(); + m_ComboBenchThreads3.ResetContent(); + m_ComboBenchThreads4.ResetContent(); + m_ComboBenchThreads5.ResetContent(); + m_ComboBenchThreads8.ResetContent(); + + for (int i = 1; i <= 64; i++) + { + CString cstr; + cstr.Format(L"%d", i); + m_ComboBenchThreads0.AddString(cstr); if (m_BenchThreads[0] == i) { m_ComboBenchThreads0.SetCurSel(i - 1); } + m_ComboBenchThreads1.AddString(cstr); if (m_BenchThreads[1] == i) { m_ComboBenchThreads1.SetCurSel(i - 1); } + m_ComboBenchThreads2.AddString(cstr); if (m_BenchThreads[2] == i) { m_ComboBenchThreads2.SetCurSel(i - 1); } + m_ComboBenchThreads3.AddString(cstr); if (m_BenchThreads[3] == i) { m_ComboBenchThreads3.SetCurSel(i - 1); } + m_ComboBenchThreads4.AddString(cstr); if (m_BenchThreads[4] == i) { m_ComboBenchThreads4.SetCurSel(i - 1); } + m_ComboBenchThreads5.AddString(cstr); if (m_BenchThreads[5] == i) { m_ComboBenchThreads5.SetCurSel(i - 1); } + m_ComboBenchThreads8.AddString(cstr); if (m_BenchThreads[8] == i) { m_ComboBenchThreads8.SetCurSel(i - 1); } + } + + m_ComboMeasureTime.ResetContent(); + int measureTimes[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 20, 30, 60 }; + for (int i = 0; i < 13; i++) + { + CString cstr; + cstr.Format(L"%d", measureTimes[i]); + m_ComboMeasureTime.AddString(cstr); if (m_MeasureTime == measureTimes[i]) { m_ComboMeasureTime.SetCurSel(i); } + } + + m_ComboIntervalTime.ResetContent(); + int intervalTimes[] = { 0, 1, 3, 5, 10, 30, 60, 180, 300, 600 }; + for (int i = 0; i < 10; i++) + { + CString cstr; + cstr.Format(L"%d", intervalTimes[i]); + m_ComboIntervalTime.AddString(cstr); if (m_IntervalTime == intervalTimes[i]) { m_ComboIntervalTime.SetCurSel(i); } + } +} + +int CSettingsDlg::GetType(CString text) +{ + if (text.FindOneOf(L"SEQ") != -1) + { + return 0; + } + else + { + return 1; + } +} + +int CSettingsDlg::GetBlockSize(CString text) +{ + if(text.FindOneOf(L"M") != -1) + { + return _wtoi(text.GetString()) * 1024; + } + else + { + return _wtoi(text.GetString()); + } +} + +void CSettingsDlg::OnOk() +{ + CString cstr; + + m_ComboBenchType0.GetWindowTextW(cstr); cstr.Format(L"%d", GetType(cstr)); WritePrivateProfileString(L"Setting", L"BenchType0", cstr, m_Ini); + m_ComboBenchType1.GetWindowTextW(cstr); cstr.Format(L"%d", GetType(cstr)); WritePrivateProfileString(L"Setting", L"BenchType1", cstr, m_Ini); + m_ComboBenchType2.GetWindowTextW(cstr); cstr.Format(L"%d", GetType(cstr)); WritePrivateProfileString(L"Setting", L"BenchType2", cstr, m_Ini); + m_ComboBenchType3.GetWindowTextW(cstr); cstr.Format(L"%d", GetType(cstr)); WritePrivateProfileString(L"Setting", L"BenchType3", cstr, m_Ini); + m_ComboBenchType4.GetWindowTextW(cstr); cstr.Format(L"%d", GetType(cstr)); WritePrivateProfileString(L"Setting", L"BenchType4", cstr, m_Ini); + m_ComboBenchType5.GetWindowTextW(cstr); cstr.Format(L"%d", GetType(cstr)); WritePrivateProfileString(L"Setting", L"BenchType5", cstr, m_Ini); + m_ComboBenchType8.GetWindowTextW(cstr); cstr.Format(L"%d", GetType(cstr)); WritePrivateProfileString(L"Setting", L"BenchType8", cstr, m_Ini); + + m_ComboBenchSize0.GetWindowTextW(cstr); cstr.Format(L"%d", GetBlockSize(cstr)); WritePrivateProfileString(L"Setting", L"BenchSize0", cstr, m_Ini); + m_ComboBenchSize1.GetWindowTextW(cstr); cstr.Format(L"%d", GetBlockSize(cstr)); WritePrivateProfileString(L"Setting", L"BenchSize1", cstr, m_Ini); + m_ComboBenchSize2.GetWindowTextW(cstr); cstr.Format(L"%d", GetBlockSize(cstr)); WritePrivateProfileString(L"Setting", L"BenchSize2", cstr, m_Ini); + m_ComboBenchSize3.GetWindowTextW(cstr); cstr.Format(L"%d", GetBlockSize(cstr)); WritePrivateProfileString(L"Setting", L"BenchSize3", cstr, m_Ini); + m_ComboBenchSize4.GetWindowTextW(cstr); cstr.Format(L"%d", GetBlockSize(cstr)); WritePrivateProfileString(L"Setting", L"BenchSize4", cstr, m_Ini); + m_ComboBenchSize5.GetWindowTextW(cstr); cstr.Format(L"%d", GetBlockSize(cstr)); WritePrivateProfileString(L"Setting", L"BenchSize5", cstr, m_Ini); + m_ComboBenchSize8.GetWindowTextW(cstr); cstr.Format(L"%d", GetBlockSize(cstr)); WritePrivateProfileString(L"Setting", L"BenchSize8", cstr, m_Ini); + + m_ComboBenchQueues0.GetWindowTextW(cstr); WritePrivateProfileString(L"Setting", L"BenchQueues0", cstr, m_Ini); + m_ComboBenchQueues1.GetWindowTextW(cstr); WritePrivateProfileString(L"Setting", L"BenchQueues1", cstr, m_Ini); + m_ComboBenchQueues2.GetWindowTextW(cstr); WritePrivateProfileString(L"Setting", L"BenchQueues2", cstr, m_Ini); + m_ComboBenchQueues3.GetWindowTextW(cstr); WritePrivateProfileString(L"Setting", L"BenchQueues3", cstr, m_Ini); + m_ComboBenchQueues4.GetWindowTextW(cstr); WritePrivateProfileString(L"Setting", L"BenchQueues4", cstr, m_Ini); + m_ComboBenchQueues5.GetWindowTextW(cstr); WritePrivateProfileString(L"Setting", L"BenchQueues5", cstr, m_Ini); + m_ComboBenchQueues8.GetWindowTextW(cstr); WritePrivateProfileString(L"Setting", L"BenchQueues8", cstr, m_Ini); + + m_ComboBenchThreads0.GetWindowTextW(cstr); WritePrivateProfileString(L"Setting", L"BenchThreads0", cstr, m_Ini); + m_ComboBenchThreads1.GetWindowTextW(cstr); WritePrivateProfileString(L"Setting", L"BenchThreads1", cstr, m_Ini); + m_ComboBenchThreads2.GetWindowTextW(cstr); WritePrivateProfileString(L"Setting", L"BenchThreads2", cstr, m_Ini); + m_ComboBenchThreads3.GetWindowTextW(cstr); WritePrivateProfileString(L"Setting", L"BenchThreads3", cstr, m_Ini); + m_ComboBenchThreads4.GetWindowTextW(cstr); WritePrivateProfileString(L"Setting", L"BenchThreads4", cstr, m_Ini); + m_ComboBenchThreads5.GetWindowTextW(cstr); WritePrivateProfileString(L"Setting", L"BenchThreads5", cstr, m_Ini); + m_ComboBenchThreads8.GetWindowTextW(cstr); WritePrivateProfileString(L"Setting", L"BenchThreads8", cstr, m_Ini); + + m_ComboMeasureTime.GetWindowTextW(cstr); WritePrivateProfileString(L"Setting", L"MeasureTime", cstr, m_Ini); + m_ComboIntervalTime.GetWindowTextW(cstr); WritePrivateProfileString(L"Setting", L"IntervalTime", cstr, m_Ini); + + CDialogFx::OnCancel(); +} + +void CSettingsDlg::OnCancel() +{ + CDialogFx::OnCancel(); +} + +void CSettingsDlg::UpdateDialogSize() +{ + CDialogFx::UpdateDialogSize(); + + ChangeZoomType(m_ZoomType); + SetClientSize(SIZE_X, SIZE_Y, m_ZoomRatio); + UpdateBackground(FALSE, m_bDarkMode); + + COLORREF textColor = RGB(0, 0, 0); + COLORREF textSelectedColor = RGB(0, 0, 0); + +#ifdef SUISHO_SHIZUKU_SUPPORT + int fontSize = 16; + int comboHeight = 24; +#else + int fontSize = 12; + int comboHeight = 20; +#endif + + m_LabelType.SetFontEx(m_FontFace, fontSize, fontSize, m_ZoomRatio, m_FontRatio, RGB(0, 0, 0), FW_NORMAL, m_FontRender); + m_LabelSize.SetFontEx(m_FontFace, fontSize, fontSize, m_ZoomRatio, m_FontRatio, RGB(0, 0, 0), FW_NORMAL, m_FontRender); + m_LabelQueues.SetFontEx(m_FontFace, fontSize, fontSize, m_ZoomRatio, m_FontRatio, RGB(0, 0, 0), FW_NORMAL, m_FontRender); + m_LabelThreads.SetFontEx(m_FontFace, fontSize, fontSize, m_ZoomRatio, m_FontRatio, RGB(0, 0, 0), FW_NORMAL, m_FontRender); + m_LabelDefault.SetFontEx(m_FontFace, fontSize, fontSize, m_ZoomRatio, m_FontRatio, RGB(0, 0, 0), FW_NORMAL, m_FontRender); + m_LabelPeak.SetFontEx(m_FontFace, fontSize, fontSize, m_ZoomRatio, m_FontRatio, RGB(0, 0, 0), FW_NORMAL, m_FontRender); + m_LabelDemo.SetFontEx(m_FontFace, fontSize, fontSize, m_ZoomRatio, m_FontRatio, RGB(0, 0, 0), FW_NORMAL, m_FontRender); + m_LabelMeasureTime.SetFontEx(m_FontFace, fontSize, fontSize, m_ZoomRatio, m_FontRatio, RGB(0, 0, 0), FW_NORMAL, m_FontRender); + m_LabelIntervalTime.SetFontEx(m_FontFace, fontSize, fontSize, m_ZoomRatio, m_FontRatio, RGB(0, 0, 0), FW_NORMAL, m_FontRender); +// m_LabelAffinity.SetFontEx(m_FontFace, fontSize, fontSize, m_ZoomRatio, m_FontRatio, RGB(0, 0, 0), FW_NORMAL, m_FontRender); +// m_LabelData.SetFontEx(m_FontFace, fontSize, fontSize, m_ZoomRatio, m_FontRatio, RGB(0, 0, 0), FW_NORMAL, m_FontRender); + + m_ComboBenchType0.SetFontEx(m_FontFace, fontSize, fontSize, m_ZoomRatio, m_FontRatio, textColor, textSelectedColor, FW_NORMAL, m_FontRender); + m_ComboBenchType1.SetFontEx(m_FontFace, fontSize, fontSize, m_ZoomRatio, m_FontRatio, textColor, textSelectedColor, FW_NORMAL, m_FontRender); + m_ComboBenchType2.SetFontEx(m_FontFace, fontSize, fontSize, m_ZoomRatio, m_FontRatio, textColor, textSelectedColor, FW_NORMAL, m_FontRender); + m_ComboBenchType3.SetFontEx(m_FontFace, fontSize, fontSize, m_ZoomRatio, m_FontRatio, textColor, textSelectedColor, FW_NORMAL, m_FontRender); + m_ComboBenchType4.SetFontEx(m_FontFace, fontSize, fontSize, m_ZoomRatio, m_FontRatio, textColor, textSelectedColor, FW_NORMAL, m_FontRender); + m_ComboBenchType5.SetFontEx(m_FontFace, fontSize, fontSize, m_ZoomRatio, m_FontRatio, textColor, textSelectedColor, FW_NORMAL, m_FontRender); + m_ComboBenchType8.SetFontEx(m_FontFace, fontSize, fontSize, m_ZoomRatio, m_FontRatio, textColor, textSelectedColor, FW_NORMAL, m_FontRender); + + m_ComboBenchSize0.SetFontEx(m_FontFace, fontSize, fontSize, m_ZoomRatio, m_FontRatio, textColor, textSelectedColor, FW_NORMAL, m_FontRender); + m_ComboBenchSize1.SetFontEx(m_FontFace, fontSize, fontSize, m_ZoomRatio, m_FontRatio, textColor, textSelectedColor, FW_NORMAL, m_FontRender); + m_ComboBenchSize2.SetFontEx(m_FontFace, fontSize, fontSize, m_ZoomRatio, m_FontRatio, textColor, textSelectedColor, FW_NORMAL, m_FontRender); + m_ComboBenchSize3.SetFontEx(m_FontFace, fontSize, fontSize, m_ZoomRatio, m_FontRatio, textColor, textSelectedColor, FW_NORMAL, m_FontRender); + m_ComboBenchSize4.SetFontEx(m_FontFace, fontSize, fontSize, m_ZoomRatio, m_FontRatio, textColor, textSelectedColor, FW_NORMAL, m_FontRender); + m_ComboBenchSize5.SetFontEx(m_FontFace, fontSize, fontSize, m_ZoomRatio, m_FontRatio, textColor, textSelectedColor, FW_NORMAL, m_FontRender); + m_ComboBenchSize8.SetFontEx(m_FontFace, fontSize, fontSize, m_ZoomRatio, m_FontRatio, textColor, textSelectedColor, FW_NORMAL, m_FontRender); + + m_ComboBenchQueues0.SetFontEx(m_FontFace, fontSize, fontSize, m_ZoomRatio, m_FontRatio, textColor, textSelectedColor, FW_NORMAL, m_FontRender); + m_ComboBenchQueues1.SetFontEx(m_FontFace, fontSize, fontSize, m_ZoomRatio, m_FontRatio, textColor, textSelectedColor, FW_NORMAL, m_FontRender); + m_ComboBenchQueues2.SetFontEx(m_FontFace, fontSize, fontSize, m_ZoomRatio, m_FontRatio, textColor, textSelectedColor, FW_NORMAL, m_FontRender); + m_ComboBenchQueues3.SetFontEx(m_FontFace, fontSize, fontSize, m_ZoomRatio, m_FontRatio, textColor, textSelectedColor, FW_NORMAL, m_FontRender); + m_ComboBenchQueues4.SetFontEx(m_FontFace, fontSize, fontSize, m_ZoomRatio, m_FontRatio, textColor, textSelectedColor, FW_NORMAL, m_FontRender); + m_ComboBenchQueues5.SetFontEx(m_FontFace, fontSize, fontSize, m_ZoomRatio, m_FontRatio, textColor, textSelectedColor, FW_NORMAL, m_FontRender); + m_ComboBenchQueues8.SetFontEx(m_FontFace, fontSize, fontSize, m_ZoomRatio, m_FontRatio, textColor, textSelectedColor, FW_NORMAL, m_FontRender); + + m_ComboBenchThreads0.SetFontEx(m_FontFace, fontSize, fontSize, m_ZoomRatio, m_FontRatio, textColor, textSelectedColor, FW_NORMAL, m_FontRender); + m_ComboBenchThreads1.SetFontEx(m_FontFace, fontSize, fontSize, m_ZoomRatio, m_FontRatio, textColor, textSelectedColor, FW_NORMAL, m_FontRender); + m_ComboBenchThreads2.SetFontEx(m_FontFace, fontSize, fontSize, m_ZoomRatio, m_FontRatio, textColor, textSelectedColor, FW_NORMAL, m_FontRender); + m_ComboBenchThreads3.SetFontEx(m_FontFace, fontSize, fontSize, m_ZoomRatio, m_FontRatio, textColor, textSelectedColor, FW_NORMAL, m_FontRender); + m_ComboBenchThreads4.SetFontEx(m_FontFace, fontSize, fontSize, m_ZoomRatio, m_FontRatio, textColor, textSelectedColor, FW_NORMAL, m_FontRender); + m_ComboBenchThreads5.SetFontEx(m_FontFace, fontSize, fontSize, m_ZoomRatio, m_FontRatio, textColor, textSelectedColor, FW_NORMAL, m_FontRender); + m_ComboBenchThreads8.SetFontEx(m_FontFace, fontSize, fontSize, m_ZoomRatio, m_FontRatio, textColor, textSelectedColor, FW_NORMAL, m_FontRender); + +// m_ComboData.SetFontEx(m_FontFace, fontSize, fontSize, m_ZoomRatio, m_FontRatio, textColor, textSelectedColor, FW_NORMAL, m_FontRender); +// m_ComboAffinity.SetFontEx(m_FontFace, fontSize, fontSize, m_ZoomRatio, m_FontRatio, textColor, textSelectedColor, FW_NORMAL, m_FontRender); + m_ComboMeasureTime.SetFontEx(m_FontFace, fontSize, fontSize, m_ZoomRatio, m_FontRatio, textColor, textSelectedColor, FW_NORMAL, m_FontRender); + m_ComboIntervalTime.SetFontEx(m_FontFace, fontSize, fontSize, m_ZoomRatio, m_FontRatio, textColor, textSelectedColor, FW_NORMAL, m_FontRender); + m_ButtonSetDefault.SetFontEx(m_FontFace, fontSize, fontSize, m_ZoomRatio, m_FontRatio, m_MeterText, FW_NORMAL, m_FontRender); + m_ButtonSetNVMe8.SetFontEx(m_FontFace, fontSize, fontSize, m_ZoomRatio, m_FontRatio, m_MeterText, FW_NORMAL, m_FontRender); + m_ButtonSetFlashMemory.SetFontEx(m_FontFace, fontSize, fontSize, m_ZoomRatio, m_FontRatio, m_MeterText, FW_NORMAL, m_FontRender); + m_ButtonOk.SetFontEx(m_FontFace, fontSize, fontSize, m_ZoomRatio, m_FontRatio, m_MeterText, FW_NORMAL, m_FontRender); + +#ifdef SUISHO_SHIZUKU_SUPPORT + m_LabelType.InitControl(8, 8, 160, 24, m_ZoomRatio, m_hPal, &m_BkDC, NULL, 0, SS_LEFT, OwnerDrawTransparent, m_bHighContrast, m_bDarkMode, FALSE); + m_LabelSize.InitControl(176, 8, 160, 24, m_ZoomRatio, m_hPal, &m_BkDC, NULL, 0, SS_LEFT, OwnerDrawTransparent, m_bHighContrast, m_bDarkMode, FALSE); + m_LabelQueues.InitControl(344, 8, 160, 24, m_ZoomRatio, m_hPal, &m_BkDC, NULL, 0, SS_LEFT, OwnerDrawTransparent, m_bHighContrast, m_bDarkMode, FALSE); + m_LabelThreads.InitControl(512, 8, 160, 24, m_ZoomRatio, m_hPal, &m_BkDC, NULL, 0, SS_LEFT, OwnerDrawTransparent, m_bHighContrast, m_bDarkMode, FALSE); + m_LabelDefault.InitControl(8, 32, 664, 24, m_ZoomRatio, m_hPal, &m_BkDC, NULL, 0, SS_LEFT, SystemDraw, m_bHighContrast, m_bDarkMode, FALSE); + m_LabelPeak.InitControl(8, 172, 664, 24, m_ZoomRatio, m_hPal, &m_BkDC, NULL, 0, SS_LEFT, SystemDraw, m_bHighContrast, m_bDarkMode, FALSE); + m_LabelDemo.InitControl(8, 256, 664, 24, m_ZoomRatio, m_hPal, &m_BkDC, NULL, 0, SS_LEFT, SystemDraw, m_bHighContrast, m_bDarkMode, FALSE); +// m_LabelData.InitControl(344, 316, 328, 24, m_ZoomRatio, &m_BkDC, NULL, 0, SS_LEFT, SystemDraw, m_bHighContrast, m_bDarkMode, FALSE); +// m_LabelAffinity.InitControl(8, 316, 328, 24, m_ZoomRatio, &m_BkDC, NULL, 0, SS_LEFT, SystemDraw, m_bHighContrast, m_bDarkMode, FALSE); + m_LabelMeasureTime.InitControl(8, 316, 328, 24, m_ZoomRatio, m_hPal, &m_BkDC, NULL, 0, SS_LEFT, SystemDraw, m_bHighContrast, m_bDarkMode, FALSE); + m_LabelIntervalTime.InitControl(344, 316, 328, 24, m_ZoomRatio, m_hPal, &m_BkDC, NULL, 0, SS_LEFT, SystemDraw, m_bHighContrast, m_bDarkMode, FALSE); + + m_ComboBenchType0.InitControl(8, 60, 160, 200, m_ZoomRatio, &m_BkDC, NULL, 0, ES_LEFT, OwnerDrawTransparent, m_bHighContrast, m_bDarkMode, RGB(255, 255, 255), RGB(160, 220, 255), RGB(255, 255, 255), 0); + m_ComboBenchType1.InitControl(8, 88, 160, 200, m_ZoomRatio, &m_BkDC, NULL, 0, ES_LEFT, OwnerDrawTransparent, m_bHighContrast, m_bDarkMode, RGB(255, 255, 255), RGB(160, 220, 255), RGB(255, 255, 255), 0); + m_ComboBenchType2.InitControl(8, 116, 160, 200, m_ZoomRatio, &m_BkDC, NULL, 0, ES_LEFT, OwnerDrawTransparent, m_bHighContrast, m_bDarkMode, RGB(255, 255, 255), RGB(160, 220, 255), RGB(255, 255, 255), 0); + m_ComboBenchType3.InitControl(8, 144, 160, 200, m_ZoomRatio, &m_BkDC, NULL, 0, ES_LEFT, OwnerDrawTransparent, m_bHighContrast, m_bDarkMode, RGB(255, 255, 255), RGB(160, 220, 255), RGB(255, 255, 255), 0); + m_ComboBenchType4.InitControl(8, 200, 160, 200, m_ZoomRatio, &m_BkDC, NULL, 0, ES_LEFT, OwnerDrawTransparent, m_bHighContrast, m_bDarkMode, RGB(255, 255, 255), RGB(160, 220, 255), RGB(255, 255, 255), 0); + m_ComboBenchType5.InitControl(8, 228, 160, 200, m_ZoomRatio, &m_BkDC, NULL, 0, ES_LEFT, OwnerDrawTransparent, m_bHighContrast, m_bDarkMode, RGB(255, 255, 255), RGB(160, 220, 255), RGB(255, 255, 255), 0); + m_ComboBenchType8.InitControl(8, 284, 160, 200, m_ZoomRatio, &m_BkDC, NULL, 0, ES_LEFT, OwnerDrawTransparent, m_bHighContrast, m_bDarkMode, RGB(255, 255, 255), RGB(160, 220, 255), RGB(255, 255, 255), 0); + + m_ComboBenchSize0.InitControl(176, 60, 160, 200, m_ZoomRatio, &m_BkDC, NULL, 0, ES_LEFT, OwnerDrawTransparent, m_bHighContrast, m_bDarkMode, RGB(255, 255, 255), RGB(160, 220, 255), RGB(255, 255, 255), 0); + m_ComboBenchSize1.InitControl(176, 88, 160, 200, m_ZoomRatio, &m_BkDC, NULL, 0, ES_LEFT, OwnerDrawTransparent, m_bHighContrast, m_bDarkMode, RGB(255, 255, 255), RGB(160, 220, 255), RGB(255, 255, 255), 0); + m_ComboBenchSize2.InitControl(176, 116, 160, 200, m_ZoomRatio, &m_BkDC, NULL, 0, ES_LEFT, OwnerDrawTransparent, m_bHighContrast, m_bDarkMode, RGB(255, 255, 255), RGB(160, 220, 255), RGB(255, 255, 255), 0); + m_ComboBenchSize3.InitControl(176, 144, 160, 200, m_ZoomRatio, &m_BkDC, NULL, 0, ES_LEFT, OwnerDrawTransparent, m_bHighContrast, m_bDarkMode, RGB(255, 255, 255), RGB(160, 220, 255), RGB(255, 255, 255), 0); + m_ComboBenchSize4.InitControl(176, 200, 160, 200, m_ZoomRatio, &m_BkDC, NULL, 0, ES_LEFT, OwnerDrawTransparent, m_bHighContrast, m_bDarkMode, RGB(255, 255, 255), RGB(160, 220, 255), RGB(255, 255, 255), 0); + m_ComboBenchSize5.InitControl(176, 228, 160, 200, m_ZoomRatio, &m_BkDC, NULL, 0, ES_LEFT, OwnerDrawTransparent, m_bHighContrast, m_bDarkMode, RGB(255, 255, 255), RGB(160, 220, 255), RGB(255, 255, 255), 0); + m_ComboBenchSize8.InitControl(176, 284, 160, 200, m_ZoomRatio, &m_BkDC, NULL, 0, ES_LEFT, OwnerDrawTransparent, m_bHighContrast, m_bDarkMode, RGB(255, 255, 255), RGB(160, 220, 255), RGB(255, 255, 255), 0); + + m_ComboBenchQueues0.InitControl(344, 60, 160, 200, m_ZoomRatio, &m_BkDC, NULL, 0, ES_LEFT, OwnerDrawTransparent, m_bHighContrast, m_bDarkMode, RGB(255, 255, 255), RGB(160, 220, 255), RGB(255, 255, 255), 0); + m_ComboBenchQueues1.InitControl(344, 88, 160, 200, m_ZoomRatio, &m_BkDC, NULL, 0, ES_LEFT, OwnerDrawTransparent, m_bHighContrast, m_bDarkMode, RGB(255, 255, 255), RGB(160, 220, 255), RGB(255, 255, 255), 0); + m_ComboBenchQueues2.InitControl(344, 116, 160, 200, m_ZoomRatio, &m_BkDC, NULL, 0, ES_LEFT, OwnerDrawTransparent, m_bHighContrast, m_bDarkMode, RGB(255, 255, 255), RGB(160, 220, 255), RGB(255, 255, 255), 0); + m_ComboBenchQueues3.InitControl(344, 144, 160, 200, m_ZoomRatio, &m_BkDC, NULL, 0, ES_LEFT, OwnerDrawTransparent, m_bHighContrast, m_bDarkMode, RGB(255, 255, 255), RGB(160, 220, 255), RGB(255, 255, 255), 0); + m_ComboBenchQueues4.InitControl(344, 200, 160, 200, m_ZoomRatio, &m_BkDC, NULL, 0, ES_LEFT, OwnerDrawTransparent, m_bHighContrast, m_bDarkMode, RGB(255, 255, 255), RGB(160, 220, 255), RGB(255, 255, 255), 0); + m_ComboBenchQueues5.InitControl(344, 228, 160, 200, m_ZoomRatio, &m_BkDC, NULL, 0, ES_LEFT, OwnerDrawTransparent, m_bHighContrast, m_bDarkMode, RGB(255, 255, 255), RGB(160, 220, 255), RGB(255, 255, 255), 0); + m_ComboBenchQueues8.InitControl(344, 284, 160, 200, m_ZoomRatio, &m_BkDC, NULL, 0, ES_LEFT, OwnerDrawTransparent, m_bHighContrast, m_bDarkMode, RGB(255, 255, 255), RGB(160, 220, 255), RGB(255, 255, 255), 0); + + m_ComboBenchThreads0.InitControl(512, 60, 160, 200, m_ZoomRatio, &m_BkDC, NULL, 0, ES_LEFT, OwnerDrawTransparent, m_bHighContrast, m_bDarkMode, RGB(255, 255, 255), RGB(160, 220, 255), RGB(255, 255, 255), 0); + m_ComboBenchThreads1.InitControl(512, 88, 160, 200, m_ZoomRatio, &m_BkDC, NULL, 0, ES_LEFT, OwnerDrawTransparent, m_bHighContrast, m_bDarkMode, RGB(255, 255, 255), RGB(160, 220, 255), RGB(255, 255, 255), 0); + m_ComboBenchThreads2.InitControl(512, 116, 160, 200, m_ZoomRatio, &m_BkDC, NULL, 0, ES_LEFT, OwnerDrawTransparent, m_bHighContrast, m_bDarkMode, RGB(255, 255, 255), RGB(160, 220, 255), RGB(255, 255, 255), 0); + m_ComboBenchThreads3.InitControl(512, 144, 160, 200, m_ZoomRatio, &m_BkDC, NULL, 0, ES_LEFT, OwnerDrawTransparent, m_bHighContrast, m_bDarkMode, RGB(255, 255, 255), RGB(160, 220, 255), RGB(255, 255, 255), 0); + m_ComboBenchThreads4.InitControl(512, 200, 160, 200, m_ZoomRatio, &m_BkDC, NULL, 0, ES_LEFT, OwnerDrawTransparent, m_bHighContrast, m_bDarkMode, RGB(255, 255, 255), RGB(160, 220, 255), RGB(255, 255, 255), 0); + m_ComboBenchThreads5.InitControl(512, 228, 160, 200, m_ZoomRatio, &m_BkDC, NULL, 0, ES_LEFT, OwnerDrawTransparent, m_bHighContrast, m_bDarkMode, RGB(255, 255, 255), RGB(160, 220, 255), RGB(255, 255, 255), 0); + m_ComboBenchThreads8.InitControl(512, 284, 160, 200, m_ZoomRatio, &m_BkDC, NULL, 0, ES_LEFT, OwnerDrawTransparent, m_bHighContrast, m_bDarkMode, RGB(255, 255, 255), RGB(160, 220, 255), RGB(255, 255, 255), 0); + +// m_ComboData.InitControl(352, 344, 320, 200, m_ZoomRatio, &m_BkDC, NULL, 0, ES_LEFT, OwnerDrawTransparent, m_bHighContrast, m_bDarkMode, RGB(255, 255, 255), RGB(160, 220, 255), RGB(255, 255, 255), 0); +// m_ComboAffinity.InitControl(16, 344, 320, 200, m_ZoomRatio, &m_BkDC, NULL, 0, ES_LEFT, OwnerDrawTransparent, m_bHighContrast, m_bDarkMode, RGB(255, 255, 255), RGB(160, 220, 255), RGB(255, 255, 255), 0); + m_ComboMeasureTime.InitControl(8, 344, 328, 200, m_ZoomRatio, &m_BkDC, NULL, 0, ES_LEFT, OwnerDrawTransparent, m_bHighContrast, m_bDarkMode, RGB(255, 255, 255), RGB(160, 220, 255), RGB(255, 255, 255), 0); + m_ComboIntervalTime.InitControl(344, 344, 328, 200, m_ZoomRatio, &m_BkDC, NULL, 0, ES_LEFT, OwnerDrawTransparent, m_bHighContrast, m_bDarkMode, RGB(255, 255, 255), RGB(160, 220, 255), RGB(255, 255, 255), 0); + + m_ButtonSetDefault.InitControl(8, 376, 160, 32, m_ZoomRatio, m_hPal, &m_BkDC, NULL, 0, BS_CENTER, SystemDraw, m_bHighContrast, m_bDarkMode, FALSE); + m_ButtonSetNVMe8.InitControl(176, 376, 160, 32, m_ZoomRatio, m_hPal, &m_BkDC, NULL, 0, BS_CENTER, SystemDraw, m_bHighContrast, m_bDarkMode, FALSE); + m_ButtonSetFlashMemory.InitControl(344, 376, 160, 32, m_ZoomRatio, m_hPal, &m_BkDC, NULL, 0, BS_CENTER, SystemDraw, m_bHighContrast, m_bDarkMode, FALSE); + m_ButtonOk.InitControl(512, 376, 160, 32, m_ZoomRatio, m_hPal, &m_BkDC, NULL, 0, BS_CENTER, SystemDraw, m_bHighContrast, m_bDarkMode, FALSE); +#else + m_LabelType.InitControl(8, 8, 100, 20, m_ZoomRatio, m_hPal, &m_BkDC, NULL, 0, SS_LEFT, OwnerDrawTransparent, m_bHighContrast, m_bDarkMode, FALSE); + m_LabelSize.InitControl(116, 8, 100, 20, m_ZoomRatio, m_hPal, &m_BkDC, NULL, 0, SS_LEFT, OwnerDrawTransparent, m_bHighContrast, m_bDarkMode, FALSE); + m_LabelQueues.InitControl(224, 8, 100, 20, m_ZoomRatio, m_hPal, &m_BkDC, NULL, 0, SS_LEFT, OwnerDrawTransparent, m_bHighContrast, m_bDarkMode, FALSE); + m_LabelThreads.InitControl(332, 8, 100, 20, m_ZoomRatio, m_hPal, &m_BkDC, NULL, 0, SS_LEFT, OwnerDrawTransparent, m_bHighContrast, m_bDarkMode, FALSE); + m_LabelDefault.InitControl(8, 28, 424, 20, m_ZoomRatio, m_hPal, &m_BkDC, NULL, 0, SS_LEFT, SystemDraw, m_bHighContrast, m_bDarkMode, FALSE); + m_LabelPeak.InitControl(8, 148, 424, 20, m_ZoomRatio, m_hPal, &m_BkDC, NULL, 0, SS_LEFT, SystemDraw, m_bHighContrast, m_bDarkMode, FALSE); + m_LabelDemo.InitControl(8, 220, 424, 20, m_ZoomRatio, m_hPal, &m_BkDC, NULL, 0, SS_LEFT, SystemDraw, m_bHighContrast, m_bDarkMode, FALSE); +// m_LabelAffinity.InitControl(8, 272, 208, 20, m_ZoomRatio, &m_BkDC, NULL, 0, SS_LEFT, SystemDraw, m_bHighContrast, m_bDarkMode, FALSE); +// m_LabelData.InitControl(224, 272, 208, 20, m_ZoomRatio, &m_BkDC, NULL, 0, SS_LEFT, SystemDraw, m_bHighContrast, m_bDarkMode, FALSE); + m_LabelMeasureTime.InitControl(8, 272, 208, 20, m_ZoomRatio, m_hPal, &m_BkDC, NULL, 0, SS_LEFT, SystemDraw, m_bHighContrast, m_bDarkMode, FALSE); + m_LabelIntervalTime.InitControl(224, 272, 208, 20, m_ZoomRatio, m_hPal, &m_BkDC, NULL, 0, SS_LEFT, SystemDraw, m_bHighContrast, m_bDarkMode, FALSE); + + m_ComboBenchType0.InitControl(8, 52, 100, 200, m_ZoomRatio, &m_BkDC, NULL, 0, ES_LEFT, OwnerDrawTransparent, m_bHighContrast, m_bDarkMode, RGB(255, 255, 255), RGB(160, 220, 255), RGB(255, 255, 255), 0); + m_ComboBenchType1.InitControl(8, 76, 100, 200, m_ZoomRatio, &m_BkDC, NULL, 0, ES_LEFT, OwnerDrawTransparent, m_bHighContrast, m_bDarkMode, RGB(255, 255, 255), RGB(160, 220, 255), RGB(255, 255, 255), 0); + m_ComboBenchType2.InitControl(8, 100, 100, 200, m_ZoomRatio, &m_BkDC, NULL, 0, ES_LEFT, OwnerDrawTransparent, m_bHighContrast, m_bDarkMode, RGB(255, 255, 255), RGB(160, 220, 255), RGB(255, 255, 255), 0); + m_ComboBenchType3.InitControl(8, 124, 100, 200, m_ZoomRatio, &m_BkDC, NULL, 0, ES_LEFT, OwnerDrawTransparent, m_bHighContrast, m_bDarkMode, RGB(255, 255, 255), RGB(160, 220, 255), RGB(255, 255, 255), 0); + m_ComboBenchType4.InitControl(8, 172, 100, 200, m_ZoomRatio, &m_BkDC, NULL, 0, ES_LEFT, OwnerDrawTransparent, m_bHighContrast, m_bDarkMode, RGB(255, 255, 255), RGB(160, 220, 255), RGB(255, 255, 255), 0); + m_ComboBenchType5.InitControl(8, 196, 100, 200, m_ZoomRatio, &m_BkDC, NULL, 0, ES_LEFT, OwnerDrawTransparent, m_bHighContrast, m_bDarkMode, RGB(255, 255, 255), RGB(160, 220, 255), RGB(255, 255, 255), 0); + m_ComboBenchType8.InitControl(8, 244, 100, 200, m_ZoomRatio, &m_BkDC, NULL, 0, ES_LEFT, OwnerDrawTransparent, m_bHighContrast, m_bDarkMode, RGB(255, 255, 255), RGB(160, 220, 255), RGB(255, 255, 255), 0); + + m_ComboBenchSize0.InitControl(116, 52, 100, 200, m_ZoomRatio, &m_BkDC, NULL, 0, ES_LEFT, OwnerDrawTransparent, m_bHighContrast, m_bDarkMode, RGB(255, 255, 255), RGB(160, 220, 255), RGB(255, 255, 255), 0); + m_ComboBenchSize1.InitControl(116, 76, 100, 200, m_ZoomRatio, &m_BkDC, NULL, 0, ES_LEFT, OwnerDrawTransparent, m_bHighContrast, m_bDarkMode, RGB(255, 255, 255), RGB(160, 220, 255), RGB(255, 255, 255), 0); + m_ComboBenchSize2.InitControl(116, 100, 100, 200, m_ZoomRatio, &m_BkDC, NULL, 0, ES_LEFT, OwnerDrawTransparent, m_bHighContrast, m_bDarkMode, RGB(255, 255, 255), RGB(160, 220, 255), RGB(255, 255, 255), 0); + m_ComboBenchSize3.InitControl(116, 124, 100, 200, m_ZoomRatio, &m_BkDC, NULL, 0, ES_LEFT, OwnerDrawTransparent, m_bHighContrast, m_bDarkMode, RGB(255, 255, 255), RGB(160, 220, 255), RGB(255, 255, 255), 0); + m_ComboBenchSize4.InitControl(116, 172, 100, 200, m_ZoomRatio, &m_BkDC, NULL, 0, ES_LEFT, OwnerDrawTransparent, m_bHighContrast, m_bDarkMode, RGB(255, 255, 255), RGB(160, 220, 255), RGB(255, 255, 255), 0); + m_ComboBenchSize5.InitControl(116, 196, 100, 200, m_ZoomRatio, &m_BkDC, NULL, 0, ES_LEFT, OwnerDrawTransparent, m_bHighContrast, m_bDarkMode, RGB(255, 255, 255), RGB(160, 220, 255), RGB(255, 255, 255), 0); + m_ComboBenchSize8.InitControl(116, 244, 100, 200, m_ZoomRatio, &m_BkDC, NULL, 0, ES_LEFT, OwnerDrawTransparent, m_bHighContrast, m_bDarkMode, RGB(255, 255, 255), RGB(160, 220, 255), RGB(255, 255, 255), 0); + + m_ComboBenchQueues0.InitControl(224, 52, 100, 200, m_ZoomRatio, &m_BkDC, NULL, 0, ES_LEFT, OwnerDrawTransparent, m_bHighContrast, m_bDarkMode, RGB(255, 255, 255), RGB(160, 220, 255), RGB(255, 255, 255), 0); + m_ComboBenchQueues1.InitControl(224, 76, 100, 200, m_ZoomRatio, &m_BkDC, NULL, 0, ES_LEFT, OwnerDrawTransparent, m_bHighContrast, m_bDarkMode, RGB(255, 255, 255), RGB(160, 220, 255), RGB(255, 255, 255), 0); + m_ComboBenchQueues2.InitControl(224, 100, 100, 200, m_ZoomRatio, &m_BkDC, NULL, 0, ES_LEFT, OwnerDrawTransparent, m_bHighContrast, m_bDarkMode, RGB(255, 255, 255), RGB(160, 220, 255), RGB(255, 255, 255), 0); + m_ComboBenchQueues3.InitControl(224, 124, 100, 200, m_ZoomRatio, &m_BkDC, NULL, 0, ES_LEFT, OwnerDrawTransparent, m_bHighContrast, m_bDarkMode, RGB(255, 255, 255), RGB(160, 220, 255), RGB(255, 255, 255), 0); + m_ComboBenchQueues4.InitControl(224, 172, 100, 200, m_ZoomRatio, &m_BkDC, NULL, 0, ES_LEFT, OwnerDrawTransparent, m_bHighContrast, m_bDarkMode, RGB(255, 255, 255), RGB(160, 220, 255), RGB(255, 255, 255), 0); + m_ComboBenchQueues5.InitControl(224, 196, 100, 200, m_ZoomRatio, &m_BkDC, NULL, 0, ES_LEFT, OwnerDrawTransparent, m_bHighContrast, m_bDarkMode, RGB(255, 255, 255), RGB(160, 220, 255), RGB(255, 255, 255), 0); + m_ComboBenchQueues8.InitControl(224, 244, 100, 200, m_ZoomRatio, &m_BkDC, NULL, 0, ES_LEFT, OwnerDrawTransparent, m_bHighContrast, m_bDarkMode, RGB(255, 255, 255), RGB(160, 220, 255), RGB(255, 255, 255), 0); + + m_ComboBenchThreads0.InitControl(332, 52, 100, 200, m_ZoomRatio, &m_BkDC, NULL, 0, ES_LEFT, OwnerDrawTransparent, m_bHighContrast, m_bDarkMode, RGB(255, 255, 255), RGB(160, 220, 255), RGB(255, 255, 255), 0); + m_ComboBenchThreads1.InitControl(332, 76, 100, 200, m_ZoomRatio, &m_BkDC, NULL, 0, ES_LEFT, OwnerDrawTransparent, m_bHighContrast, m_bDarkMode, RGB(255, 255, 255), RGB(160, 220, 255), RGB(255, 255, 255), 0); + m_ComboBenchThreads2.InitControl(332, 100, 100, 200, m_ZoomRatio, &m_BkDC, NULL, 0, ES_LEFT, OwnerDrawTransparent, m_bHighContrast, m_bDarkMode, RGB(255, 255, 255), RGB(160, 220, 255), RGB(255, 255, 255), 0); + m_ComboBenchThreads3.InitControl(332, 124, 100, 200, m_ZoomRatio, &m_BkDC, NULL, 0, ES_LEFT, OwnerDrawTransparent, m_bHighContrast, m_bDarkMode, RGB(255, 255, 255), RGB(160, 220, 255), RGB(255, 255, 255), 0); + m_ComboBenchThreads4.InitControl(332, 172, 100, 200, m_ZoomRatio, &m_BkDC, NULL, 0, ES_LEFT, OwnerDrawTransparent, m_bHighContrast, m_bDarkMode, RGB(255, 255, 255), RGB(160, 220, 255), RGB(255, 255, 255), 0); + m_ComboBenchThreads5.InitControl(332, 196, 100, 200, m_ZoomRatio, &m_BkDC, NULL, 0, ES_LEFT, OwnerDrawTransparent, m_bHighContrast, m_bDarkMode, RGB(255, 255, 255), RGB(160, 220, 255), RGB(255, 255, 255), 0); + m_ComboBenchThreads8.InitControl(332, 244, 100, 200, m_ZoomRatio, &m_BkDC, NULL, 0, ES_LEFT, OwnerDrawTransparent, m_bHighContrast, m_bDarkMode, RGB(255, 255, 255), RGB(160, 220, 255), RGB(255, 255, 255), 0); + +// m_ComboData.InitControl(232, 296, 200, 200, m_ZoomRatio, &m_BkDC, NULL, 0, ES_LEFT, OwnerDrawTransparent, m_bHighContrast, m_bDarkMode, RGB(255, 255, 255), RGB(160, 220, 255), RGB(255, 255, 255), 0); +// m_ComboAffinity.InitControl(16, 296, 200, 200, m_ZoomRatio, &m_BkDC, NULL, 0, ES_LEFT, OwnerDrawTransparent, m_bHighContrast, m_bDarkMode, RGB(255, 255, 255), RGB(160, 220, 255), RGB(255, 255, 255), 0); + m_ComboMeasureTime.InitControl(8, 296, 208, 200, m_ZoomRatio, &m_BkDC, NULL, 0, ES_LEFT, OwnerDrawTransparent, m_bHighContrast, m_bDarkMode, RGB(255, 255, 255), RGB(160, 220, 255), RGB(255, 255, 255), 0); + m_ComboIntervalTime.InitControl(224, 296, 208, 200, m_ZoomRatio, &m_BkDC, NULL, 0, ES_LEFT, OwnerDrawTransparent, m_bHighContrast, m_bDarkMode, RGB(255, 255, 255), RGB(160, 220, 255), RGB(255, 255, 255), 0); + + m_ButtonSetDefault.InitControl(8, 324, 100, 24, m_ZoomRatio, m_hPal, &m_BkDC, NULL, 0, BS_CENTER, SystemDraw, m_bHighContrast, m_bDarkMode, FALSE); + m_ButtonSetNVMe8.InitControl(116, 324, 100, 24, m_ZoomRatio, m_hPal, &m_BkDC, NULL, 0, BS_CENTER, SystemDraw, m_bHighContrast, m_bDarkMode, FALSE); + m_ButtonSetFlashMemory.InitControl(224, 324, 100, 24, m_ZoomRatio, m_hPal,&m_BkDC, NULL, 0, BS_CENTER, SystemDraw, m_bHighContrast, m_bDarkMode, FALSE); + m_ButtonOk.InitControl(332, 324, 100, 24, m_ZoomRatio, m_hPal, &m_BkDC, NULL, 0, BS_CENTER, SystemDraw, m_bHighContrast, m_bDarkMode, FALSE); +#endif + +// m_ButtonSetDefault.SetDrawFrame(TRUE); +// m_ButtonSetNVMe8.SetDrawFrame(TRUE); +// m_ButtonSetNVMe9.SetDrawFrame(TRUE); +// m_ButtonOk.SetDrawFrame(TRUE); + + m_ButtonSetDefault.SetHandCursor(); + m_ButtonSetNVMe8.SetHandCursor(); + m_ButtonSetFlashMemory.SetHandCursor(); + m_ButtonOk.SetHandCursor(); + + SetDarkModeControl(m_ButtonOk.GetSafeHwnd(), m_bDarkMode); + SetDarkModeControl(m_ButtonSetDefault.GetSafeHwnd(), m_bDarkMode); + SetDarkModeControl(m_ButtonSetNVMe8.GetSafeHwnd(), m_bDarkMode); + SetDarkModeControl(m_ButtonSetFlashMemory.GetSafeHwnd(), m_bDarkMode); + + m_ComboBenchType0.SetItemHeightAll(comboHeight, m_ZoomRatio, m_FontRatio); + m_ComboBenchType1.SetItemHeightAll(comboHeight, m_ZoomRatio, m_FontRatio); + m_ComboBenchType2.SetItemHeightAll(comboHeight, m_ZoomRatio, m_FontRatio); + m_ComboBenchType3.SetItemHeightAll(comboHeight, m_ZoomRatio, m_FontRatio); + m_ComboBenchType4.SetItemHeightAll(comboHeight, m_ZoomRatio, m_FontRatio); + m_ComboBenchType5.SetItemHeightAll(comboHeight, m_ZoomRatio, m_FontRatio); + m_ComboBenchType8.SetItemHeightAll(comboHeight, m_ZoomRatio, m_FontRatio); + + m_ComboBenchSize0.SetItemHeightAll(comboHeight, m_ZoomRatio, m_FontRatio); + m_ComboBenchSize1.SetItemHeightAll(comboHeight, m_ZoomRatio, m_FontRatio); + m_ComboBenchSize2.SetItemHeightAll(comboHeight, m_ZoomRatio, m_FontRatio); + m_ComboBenchSize3.SetItemHeightAll(comboHeight, m_ZoomRatio, m_FontRatio); + m_ComboBenchSize4.SetItemHeightAll(comboHeight, m_ZoomRatio, m_FontRatio); + m_ComboBenchSize5.SetItemHeightAll(comboHeight, m_ZoomRatio, m_FontRatio); + m_ComboBenchSize8.SetItemHeightAll(comboHeight, m_ZoomRatio, m_FontRatio); + + m_ComboBenchQueues0.SetItemHeightAll(comboHeight, m_ZoomRatio, m_FontRatio); + m_ComboBenchQueues1.SetItemHeightAll(comboHeight, m_ZoomRatio, m_FontRatio); + m_ComboBenchQueues2.SetItemHeightAll(comboHeight, m_ZoomRatio, m_FontRatio); + m_ComboBenchQueues3.SetItemHeightAll(comboHeight, m_ZoomRatio, m_FontRatio); + m_ComboBenchQueues4.SetItemHeightAll(comboHeight, m_ZoomRatio, m_FontRatio); + m_ComboBenchQueues5.SetItemHeightAll(comboHeight, m_ZoomRatio, m_FontRatio); + m_ComboBenchQueues8.SetItemHeightAll(comboHeight, m_ZoomRatio, m_FontRatio); + + m_ComboBenchThreads0.SetItemHeightAll(comboHeight, m_ZoomRatio, m_FontRatio); + m_ComboBenchThreads1.SetItemHeightAll(comboHeight, m_ZoomRatio, m_FontRatio); + m_ComboBenchThreads2.SetItemHeightAll(comboHeight, m_ZoomRatio, m_FontRatio); + m_ComboBenchThreads3.SetItemHeightAll(comboHeight, m_ZoomRatio, m_FontRatio); + m_ComboBenchThreads4.SetItemHeightAll(comboHeight, m_ZoomRatio, m_FontRatio); + m_ComboBenchThreads5.SetItemHeightAll(comboHeight, m_ZoomRatio, m_FontRatio); + m_ComboBenchThreads8.SetItemHeightAll(comboHeight, m_ZoomRatio, m_FontRatio); + +// m_ComboData.SetItemHeightAll(comboHeight, m_ZoomRatio, m_FontRatio); +// m_ComboAffinity.SetItemHeightAll(comboHeight, m_ZoomRatio, m_FontRatio); + m_ComboMeasureTime.SetItemHeightAll(comboHeight, m_ZoomRatio, m_FontRatio); + m_ComboIntervalTime.SetItemHeightAll(comboHeight, m_ZoomRatio, m_FontRatio); + + m_ComboBenchType0.SetMargin(0, 4, 0, 0, m_ZoomRatio); + m_ComboBenchType1.SetMargin(0, 4, 0, 0, m_ZoomRatio); + m_ComboBenchType2.SetMargin(0, 4, 0, 0, m_ZoomRatio); + m_ComboBenchType3.SetMargin(0, 4, 0, 0, m_ZoomRatio); + m_ComboBenchType4.SetMargin(0, 4, 0, 0, m_ZoomRatio); + m_ComboBenchType5.SetMargin(0, 4, 0, 0, m_ZoomRatio); + m_ComboBenchType8.SetMargin(0, 4, 0, 0, m_ZoomRatio); + + m_ComboBenchSize0.SetMargin(0, 4, 0, 0, m_ZoomRatio); + m_ComboBenchSize1.SetMargin(0, 4, 0, 0, m_ZoomRatio); + m_ComboBenchSize2.SetMargin(0, 4, 0, 0, m_ZoomRatio); + m_ComboBenchSize3.SetMargin(0, 4, 0, 0, m_ZoomRatio); + m_ComboBenchSize4.SetMargin(0, 4, 0, 0, m_ZoomRatio); + m_ComboBenchSize5.SetMargin(0, 4, 0, 0, m_ZoomRatio); + m_ComboBenchSize8.SetMargin(0, 4, 0, 0, m_ZoomRatio); + + m_ComboBenchQueues0.SetMargin(0, 4, 0, 0, m_ZoomRatio); + m_ComboBenchQueues1.SetMargin(0, 4, 0, 0, m_ZoomRatio); + m_ComboBenchQueues2.SetMargin(0, 4, 0, 0, m_ZoomRatio); + m_ComboBenchQueues3.SetMargin(0, 4, 0, 0, m_ZoomRatio); + m_ComboBenchQueues4.SetMargin(0, 4, 0, 0, m_ZoomRatio); + m_ComboBenchQueues5.SetMargin(0, 4, 0, 0, m_ZoomRatio); + m_ComboBenchQueues8.SetMargin(0, 4, 0, 0, m_ZoomRatio); + + m_ComboBenchThreads0.SetMargin(0, 4, 0, 0, m_ZoomRatio); + m_ComboBenchThreads1.SetMargin(0, 4, 0, 0, m_ZoomRatio); + m_ComboBenchThreads2.SetMargin(0, 4, 0, 0, m_ZoomRatio); + m_ComboBenchThreads3.SetMargin(0, 4, 0, 0, m_ZoomRatio); + m_ComboBenchThreads4.SetMargin(0, 4, 0, 0, m_ZoomRatio); + m_ComboBenchThreads5.SetMargin(0, 4, 0, 0, m_ZoomRatio); + m_ComboBenchThreads8.SetMargin(0, 4, 0, 0, m_ZoomRatio); + +// m_ComboData.SetMargin(0, 4, 0, 0, m_ZoomRatio); +// m_ComboAffinity.SetMargin(0, 4, 0, 0, m_ZoomRatio); + m_ComboMeasureTime.SetMargin(0, 4, 0, 0, m_ZoomRatio); + m_ComboIntervalTime.SetMargin(0, 4, 0, 0, m_ZoomRatio); + + m_ComboBenchType4.EnableWindow(FALSE); + m_ComboBenchType5.EnableWindow(FALSE); + + Invalidate(); +} \ No newline at end of file diff --git a/CristalDiskMark/source/CrystalDiskMark/SettingsDlg.h b/CristalDiskMark/source/CrystalDiskMark/SettingsDlg.h new file mode 100644 index 0000000..7c09880 --- /dev/null +++ b/CristalDiskMark/source/CrystalDiskMark/SettingsDlg.h @@ -0,0 +1,108 @@ +/*---------------------------------------------------------------------------*/ +// Author : hiyohiyo +// Mail : hiyohiyo@crystalmark.info +// Web : https://crystalmark.info/ +// License : MIT License +/*---------------------------------------------------------------------------*/ + +#pragma once + +#include "DialogFx.h" +#include "StaticFx.h" +#include "ButtonFx.h" +#include "ComboBoxFx.h" + +class CSettingsDlg : public CDialogFx +{ + DECLARE_DYNCREATE(CSettingsDlg) + +#ifdef SUISHO_SHIZUKU_SUPPORT + static const int SIZE_X = 680; + static const int SIZE_Y = 416; +#else + static const int SIZE_X = 440; + static const int SIZE_Y = 356; +#endif + +public: + CSettingsDlg(CWnd* pParent = NULL); + virtual ~CSettingsDlg(); + + enum { IDD = IDD_SETTINGS }; + +protected: + virtual void DoDataExchange(CDataExchange* pDX); + virtual BOOL OnInitDialog(); + virtual void OnCancel(); + + void UpdateDialogSize(); + int GetBlockSize(CString text); + int GetType(CString text); + + CStaticFx m_LabelType; + CStaticFx m_LabelSize; + CStaticFx m_LabelQueues; + CStaticFx m_LabelThreads; + CStaticFx m_LabelDefault; + CStaticFx m_LabelPeak; + CStaticFx m_LabelDemo; + CStaticFx m_LabelMeasureTime; + CStaticFx m_LabelIntervalTime; + + CComboBoxFx m_ComboBenchType0; + CComboBoxFx m_ComboBenchType1; + CComboBoxFx m_ComboBenchType2; + CComboBoxFx m_ComboBenchType3; + CComboBoxFx m_ComboBenchType4; + CComboBoxFx m_ComboBenchType5; + CComboBoxFx m_ComboBenchType8; + CComboBoxFx m_ComboBenchSize0; + CComboBoxFx m_ComboBenchSize1; + CComboBoxFx m_ComboBenchSize2; + CComboBoxFx m_ComboBenchSize3; + CComboBoxFx m_ComboBenchSize4; + CComboBoxFx m_ComboBenchSize5; + CComboBoxFx m_ComboBenchSize8; + CComboBoxFx m_ComboBenchQueues0; + CComboBoxFx m_ComboBenchQueues1; + CComboBoxFx m_ComboBenchQueues2; + CComboBoxFx m_ComboBenchQueues3; + CComboBoxFx m_ComboBenchQueues4; + CComboBoxFx m_ComboBenchQueues5; + CComboBoxFx m_ComboBenchQueues8; + CComboBoxFx m_ComboBenchThreads0; + CComboBoxFx m_ComboBenchThreads1; + CComboBoxFx m_ComboBenchThreads2; + CComboBoxFx m_ComboBenchThreads3; + CComboBoxFx m_ComboBenchThreads4; + CComboBoxFx m_ComboBenchThreads5; + CComboBoxFx m_ComboBenchThreads8; + +// CComboBoxFx m_ComboAffinity; +// CComboBoxFx m_ComboData; + CComboBoxFx m_ComboMeasureTime; + CComboBoxFx m_ComboIntervalTime; + + CButtonFx m_ButtonSetDefault; + CButtonFx m_ButtonSetNVMe8; + CButtonFx m_ButtonSetFlashMemory; + CButtonFx m_ButtonOk; + + void OnSetDefault(); + void OnSetNVMe8(); + void OnSetFlashMemory(); + void OnOk(); + void InitComboBox(); + + int m_BenchType[9]; + int m_BenchSize[9]; + int m_BenchQueues[9]; + int m_BenchThreads[9]; + + int m_TestData; + int m_MeasureTime; + int m_IntervalTime; + DWORD m_Profile; + + DECLARE_MESSAGE_MAP() +}; diff --git a/CristalDiskMark/source/CrystalDiskMark/res/DiskMark.ico b/CristalDiskMark/source/CrystalDiskMark/res/DiskMark.ico new file mode 100644 index 0000000000000000000000000000000000000000..f9714b85855bf71118dcae7ffbbe95dd8e3a35b1 GIT binary patch literal 103179 zcmeFZWn2~C+xESbRs;bNP*9{xI;0z3F+F;puhUZ z^<3}n`^~*R4to#l_@3vv*36!nV{H|HTL1~r(*x)g8RVk@-~a$1B>ZC^8Gt9~0NlU- zd*28FfKD7p0JU3y5Rh`-0<;9+51tU@lLGKc1?nOE-JcI}7jC!y;0b{dJOEjtw*Upi zLn*-SJj&2vC*LUy310Xl12UKRvfJu)TFdDG|Hp3TyQ=bzsn?bK89Dv3Sis8fp zp4+_ubgnM|g98hocVY!h_UwSujvFw!Z~}HGZoq3S4G0}Y0FON%U~}gKoX&iJUr7K6 zs*3u9D1|5j z6>oJQlA-_(STb*3&b$}t5dRc64s#03~uL)sc=AlfDgB-)jM{8uHQ zGN}Tjx5a_nmK2aU76x+1Qb1)*38)?^fj8?~K>J(+NVmTMufM+mX5E&+s?P%GOz8lV z0cT*(d0zphv2nb7w z08vqqAR#UaL?=dr@1Liwafp2#th#rUoiET+B_Dej7?@k0E!|@>cdmKm~NCCcU zfxzd)A4FV*fY9|=5WSWNLa!n~{AnUcKS~9;eOVx9EFYA8sRVVMwV-~e2_&rNf~2Dy zkiD4=GER#@&RHcWziI+K9SvZpw-L0=Hi1u{KZB2Bt)R7~1@yMJgTCGtXzK+-U)#X& z*FMlc*blyq_JV=IAuuvL1SUsE!1UAz_%{9>jDMei-cN$XnF-K)-2=W|kAsz^DKIlT z59a04T(5xT>viz+U>ofG*aJWI4#4T@3HVe21Cv8A0E5AR z$p33MGa!t9)Bej`NdCv~gdy!CS;K^^H|XfX|IsV?FMzP{qerrD^pi`Bt?XUzt*@pD9 zjX?&t*u!g+qob3P`EdR@3JVMK548(Bd%xvJhkHBgOHe_vTD0lOa~0{y(J?8}{~U#d z#n6Yf_3b}_8~qwoP)=NW`t;Vqhl=zVD22e^DJ-l$EG(_B|E2#`(89uWNlg0r;r`k} zZAnT@a(XoDpA%)_R=c#c_Lu%wLAA+IF*OTw3!8_B+pDuRCCSMtDT05buyCun(Qohk z9>97{a!hi`huOKg>4n+p>DrRysPOP;XxQn=Pzva1Tewv$EkN-P57uhalaouPSJ&27 zmlqc1W@{^=czO8+1^Kzy**OHGQ_=%&=E=gPWEM)9o}OMYy|sUEu)VdpwhA$8bBX*> zi76EypxzWgE;f$vl!{l-!M3m%o?h5LJU_p@UZpr`I)XK>C$S80>QIFrAA%Cg-O9 zn`Y%X1;xKOKRCa<{GBJQG<|-tVR2{g=}9f|cJ1ZZaIr&vG#cL;8OKej$gov-2B^D~rDqKo#AL;q3Avob8wX-vCKT z&83>1osIS132x4;8{iUlS;0iL&h+FPstUC-g+(KbZxL9?~7u@c4pd;V{x^rroFY7Cqe z)i>N^fT)H&=o$dY8;a@z7;nypf3!aVm$QZHn-lvG`mwmTw+_kIR~BP9#QshHSB8PJ z%3l@j9PUj(wLtonl@e&Q|E~WNu-rH*t%p=l9*zIw4Rk&E@0{=WjRwIfRp8w=|vH+HI_^J20nErr*#oJ|Uf@A6*&Q{E_L zi`<>P#_~ewWGGBaD@@c97U?h7{-ysfKqf0xmq|Y~G4pkm<%Nkl>QL#DRX6qDwErA~ zC@BBqp7l%rUw}Ukg+=Z2f84VEi2vU*`~l>aa>)M^_#OX$1e`ZEqSzt* zUlskS{~t=S930eVRfBGde*%B${|DfYvi<^o`y%K;=vVuHum7j#;l`&DLK`2n{ck>% zhnpMVD9{61O=du^#02QoSOBLSHz2oo4rp|l0E+<|U^a#}$ak_szLVOH;g|2Eb9e!0 zUDyGGJquuPg!*rMr!C|=ojHE{PI*4Sq0a|+4W$6D!*B1&1$j?F0RbSOzz+mo3j?v& z;(*^!0Ep>AzRObLm+yRO^AboJ%K;fH1t4b&`7m2mpx~?qG#vDSuDK2{Gt~!{=ElIv z(i9ll>HBVh8@9GJc{1Gd)Yz~0UVIK8z6Hg2}S8S@@;F#Oq%@C_m&urGlXvd{lr+800x)UjeyjH6WNF2}D0g z0)bq4AXKafWOCGjY!2j~vowHMofIMliV!OvnqvO^ij_Q?U2DaeQZ5c}mr#ZQDF zA1Voy*C8Kz4EfM)Eg;vW3$!M5fW=ocpgpGp9A}+?{`zmvX|ZYroR*z{!?6?ae(wfi z{Oy2uv>W6(y@2b52k`dx0{(tJz$4fL1p0e{;NW2373mG4B11rId>9B#2><0RlWsg^ zQX=px^aXyUA>e(p9|)`p0DcYr!2g3kh|Y@xF-5T;DK8nMl&65~tYlDEk_s}jG9VwB z1E9+-s4C5d{A3x(tH=YzRmGsHJP*{DXMw7UV(_W12z>fb2&$_gk6BX#YChG1=Ef>e zTle9Y*X(F2g}i1J`0^3*o6XI@tL;7T?DheE-9f;ABm~5LO#s2;ksxv=5_s(RfbgAA z;Ctc+LKdSy)LJYE+m8ZqXOJiE%mtY}*`Tnm1Z0nAfYSa-(AZT2s`{%z)8|G|`>g`R zujPQG<6Mw+S^_GrOQF{a@Zq`+bhcK5p0--h(bfcdA@AAO^AYlv&EV7ZXVB5w0={&1 zfW9w~_x$n&`h6=H?&||xGwonxunl}4>HuTIz2N(|uV8GlA54Ak2csiHU}|&}%>3a) zXQrpX{Ol-LoSFii*WF-jeGv3t4}sBZ$eYf81Ivq3V10EK%+5i+bafG|tSo@7r6sVm zz6v%rp#8OVu)4kpwsy9`-s&pY{{d|q8{iP~sW%?=@bD)%Jvjj9XGZ{fJpJWU1^;eb z|E>MqEhzZE_5U})fADB%{}Sf!el9LFPDu%Oe`Tb9Dhz%JAcRLjD?T|nm6|n39Rum_ z5C)Kdi&w!tad>=wZluKj_N_o4AIiT&7zn=7O&Oj$K0V%Bf%+ry2%y!J0ClWCLm1c= zjIHb)pWgJ(j}J#P`Xm>``}hP<{}IBVd2DWeYwz^*^rnBLEk0;>X)HU)H^Ad}2!qt| zx%riw{^ON`#Gs(I;gO}Cv4Z%3fZrjY{_**(mGPY9#KhsTv9XbYL>~@T7G^pY&j6o$ zXj}#{*#!mJ`C~gjb{3(vhOK!&@4)QQv9WBA=d6M5Xk11%pMLy=Y|G)?+|usu&SGF- z#?;oy=GFB<0W(W97nhNdfst+d{>9Px6?90C65_v1^lu)VUBM2n=2+Nn`i%^rX4`&r zeSLj3m-cmHVrpUgSHnp`p4Q05A06qK9(f-l@XNs}@+3l_AfjHOn%)&1N z3lq$L_Wu^xPEBs_9vo~=^i51JY;J8&{oVgdV7>e0;HDjIEqt4vo?XcMEB+rvZe=cS zL0<4+>R@YYd15+<>aX~}1(kDI5WaOVwY$8$FrE2=SJ3!oe19|p1Ea0H$%BL4t#6R? zoSpC`7ZkMlSAp$RX7Rwm_Vm_f(Lf+G&rSb71+Tm`21e71CkiLNBn2w#yNC+f*!(ks zEt7#^<;-YaT5OQ7l%QY?#6$i6jBqo}+IoTF(tms~p#J|9==h5K`MJ62{|`ayS6ac} zADo-`H|<|j7#YeyX?}%(9uNMnwwvda`_M)RZU5VI$}3q}prNV?boF$AvyBZvNJIsQ zsb~N>7Ym?#q6SP2oPeuB8;Dd(fS1j3;7zDGc-+GWo_!SoOfABIsY49Vf7Sv#U)2E9 zm?}Wod<6uCw1D8y8zA}31PD)>0ltUDGVcbo7QKPtf-f*x2mnUQ z!N7Vc6j-iC0Eg8W;ItYC9MH!o2koCe zfw;~b;Jc9p0yc9%#7+rF{80_vQ(8cGM?2{6`vR>`jzIT^F)%$j0ahlygPxNKumG(; zZf)&=?d>1GuGc^o7XT|F0K#biC}#y=fDeE@aex6+2MjQ4AP4gU*02;10jmTRupTf3 zoBPc{^Lv{P0C-sd5Ul_}4hP^)IRJMD06^P=<{yR$xM2)H9VQ2ypg8fc2v7s70Hd&> zzxW3bPb3R{|6v6HcQ^o&%@ z0Dui+0N8g10Gp8muw`oi+l&CPy$S$39{Q_(x(5&sO`R1z#PdMB6vRWZ_KYFk2?M|a z82~Ir4#3K+0jwngidg|*D?@+ta1alD4`hW1@hA{~2jWp79{TPHMu-VuJPZK#S`NUR ztpO}90>El30Bm&VZyullS%3qqz%vjIs6jbk1q09%`W_GiFbp*SW3U1+IbQ&?P6n`u zN&u_q2C$*Oj~^ZMDUpR3DIs>46W+o;wLIPYY3>2iBeMC}nQlck#573bB|JuKc2ob;k+;FG} zxM&aXo{~^dkP|(AfR2TP_z(w|;29|sGYbndBPjvWzw142-FWE#+-`pV84d>9Lx=kQ zx&50qKvr7x-knF#84K=-y%dtax!V4^;zH*#cx{t!0B&(?iwW^7I3`y&pOsmts?D9K znxgNzuG)6JI{7xpaxBa3ksuJ?Mrd}QjFlC!qZ30~k7&Z?fpFjh_imZ9yF{vTi1OMaVhogEKe}8mS~4dq}0+WJ<1f>0$g8xX4N4cM@$Kg z0?7;P<^bWCfSH0*g@ucdlPt%ObmC}fb#mujuf$J`g(VpC!&E4vK~SLm~8fuuoQuIjEhumfi%n zNqhQH;dcskvkL+dEaPpzN_{KuxAc1Y9^0EmztNM=Y(;9?Vb8fj0P|c~ zmwPsHJ1HF@LU=ib31O!@1(eI_(>R!AOdC@4Qz9B9_c~-my2=K}jPxzu^ z8J;k^cCLEPeQ6&_ZO?Mtsb>)=6cJi zkBJ^^hmhV95cLkU(oMz>2}Cq7?Fpu_#|yS)O6YWMRg9LH&xlI3Ul=H2)I*%H5$M2J z`6k7(C~QcP{-Vq4TL{tZG`K48kgS^6FG)_E@i~j!oPY?!1^q_2#n(F=(SdzKLhVwO z`Szj0C%wq(59Zt&pT*jHzpB>ATC5q@@7G!oeWa`)5l4WF0 zEz%Sle9{L>!r>Y34FW zN3&%rg-0a4+Y^vv%(keue_qcwQ)y7U(S_1Bj_&$ce`IbR`AG%|w-*!fCfRMQ$_I$F zTr9CC1wQ)~U4ms%9(oUd@n3Is%buJ9=6A|#Uu66Kf>#cd_ zqWX()p-#vRO0c!3E-`zF>h@`wBNAefg{5{VT$?=Wb@CKr^%RYciz01MlW46Uk?#kmqu_>_Iq)l|X^UM_MnQ0Ui zW%{GHTC>a_Ng2FT=6#-JYkkz1i_cb73b(-cf$VpDCstQ7DU?djuJYaGr{S9ZptgR5 zm|dBGTJF5m&hBirEOu>%SzE;AjaFpw+XhLW<2I`kg7*U^qTtC@$!ck*E^QepE-4)qX|Dj-lO9u6Ln;5<(?c7_+bS z41AAmE4DT4>2{z9XZ7Ik&i7e6J@EX5hU;&%b*9?LcbMiS@PR!1#nIypzBObvg$G!+ zM6ZxBKHNne{{GdE{Szob8*s=?SXcQNR5~P{+)nPB8XHQ3PhGGsCC@8-CkYP^`!%;f z4WBbMd^0VJA?1cthKwl|)r$#o^iK)9v#02|8dEyMyA10ml)YYD)ZIT(OR%dZl9!fr zr3Z5HXFm;?@ffluF(gSR4B*f_w2ciS{nFv3s4>KRFW1=du+J^@)7Go}p8C|l4rG++7uyLXFYoFk zkPu~H=sua##P<^~3Vy58bBHGdm*w3g=4L#U!VU=Wu*ypC?ovfJMWimwd8dD3K}BxXySm`EHzJI_Ro?eh7qYmG4Yy>U9*= z?Yumn4zp@aH?J_MN>vw;keylU^v*lzsY| z)V150hx;L#aRaIDh4B~hd_@r?iPw+rZNDW&B`@B(SShzE!^-h#%X!C%m}rruK4OWV z9IXt;^Wf7;L*cbTLygc=K7Q4*LMEI-Gaz9bI8DkR*M8O$ z%w35vWQ9NOTkBRY+lPnJlf_bu0!S{o;@{x7A}G6?t?a(%*|;4lTUQoIAy$p=^^PO_ z<)(wAz@zt1F%Z*G#bU#7K8j@G;S^*pxQO0eauzO>Y--E-7LQtS+5DrtcZ86s8BNsn zdkq^LKe>QGkCzvwT+@hBWgv#ZurQLT=IW;3kqmEowSJEJMW(iUW}6^mFp81x?Y%PM z;w33fr@^hg)fR?a$){wh*tZkKFz9gAImq|o)DWv{Vt!_muxJJy-hRy49d-XL8k5E? z7aV_g1AmtSU32fj#`GQvoC`1Mt9EJssD31QeS55uy|RGNYz3>L?*-i!%kdV^&9{Fb zS@}|*sVsH%%+@vd>StqPCQuaQu9MUT3;9UTiLq~7^4u0#XUU9WQD$kcY+1;%Al(&L z!bHY6M)VQ6bnD3rWPQjeX4pvO6*7&AZQjOjT1m=;M%g?&4v75w+n<%_cEXeT>x(E; z2KTpL3V;nlb{V_suSZUqMx0cNx`rqEqu;e|1N>*S?E5?F zGGQeH!UB6`Y@yjUy6pA|eC#Ur{Yx~__O=j-@newQ<&j5Ln z?M_k!Nhr0k;-bamlgwmHtfVc$2W1(|KO=zlv` zvaYhSk%2D`4?-(rU-(8P&7x$5lU|X5_knJKeV(ysWxW>kjFFfEQz&8mFHmbg4ch4l zF=An%H{BDrvUMSEn26ess-g7ppufqdwj4?Zu8iIX@f41H!ACjbM+UA~4+$1);pKRRuoxuwLmyKHk0J3>vrMazioswkF2-bpiRaXI6E{&AdMge8*Pr>)}$CmGgM9O1C=%VG&T zLfM;g@6WPS=bph6GfZ#WMPb+opQiBgLO?F)O2oG_Lo$jF8y3Kg!^rgP*f>(0NJc`QJ>kOt9sGTvK5>?3s(S`+!tTBpJisLqqA4bV z$5oyCN&J25WxGG?imO+o!Lmn@DZAVj?zBPiOF1t3<*B`+acNzjg_X3%J8w7?n{_Xu ziTj-cBl2ydt*$jjQ4xO}>M{r;_(ci?Nk7NuGNALpv%+f$PL~n76bjDJdPi+P{DU!J zm+eJBJL;Mp#vG;udl%ri8>iDI|9wTjFY#87b-h0h!N=Dk*il}eE$1mvGI&ahB?6X1 zUzSPg%_6Hh%U>~k!@Vs(V;9abOiLc%uij|I*c(mug;_N=LZ4kVwo!@?L0Im^u-X9) z@fXJG{z0`YP!c@@mu^qayPsa>gC#moPZSgN8l{F%jtVb50scC((>uaR_#D{;lby_g zY)2tyF$j*n;3)?yUcuI($N5h{Sh+NH*cc4|jEH5^* zU2DdJXiLIAB);yo`-hL#WEVBS&>IBuR$A|ofF0vm1-Pe zce2!YF@|FNlylgq<~;2N*ZWdhBuOejn?dZTe%dc z+~g-{e04`KNQa=cLA}abi1-WThagLv@f;S!Pj_oVSRckdlwlgwP z|FG$jDT@amaBWfH!VTd)pI&Nfwt){=AiXu?>N}s6^B|@i{Hd>+Xzs>S&_@%0dQ#Kq%l(#vm4RRBcN_iVsF6?)Ptaln=E?m%|gjNwPi{e~SCzcDHJ>~K66 zPV3DpTP6_1#WRD`dxS{D>itqdS^MQYk@g2e4#F}anKdEg03-3(R|WT@@1#daB4ZYc zCP^Qf@GR418yN@*@?gD83K(h#>SG8MvKR6s?e`1fLy_-N;7*|E7{*w|ix!ixBhM6I zjdoV+Y7anCetoEHf$|E?f1rwY7qx#Y=75usnA^d=E$V)VS|H8$MEGNr(KHq7T&4KV zdoio*jb)!&No@n%%SgW1uKr~A^Yfc-bcx%TK#@u1(spJ=C`q_T(Zx^o8)@Ha&$YBl%9FvT z+isS?@uf4H(=X8Dt~nL>-!YA(atL|KLy{vk`8v|;B9(w$JX$3!Mb%KU7Pp&6#tKoE zpzG+Xi?A?0(SGV+x{!6`E@e8#rs_u$fA*!w^fk3`&g)<^4IyVPT#}Rm3hH`;lozi# zM5L;s<2CHgV!pWY`_XQmwkX&*OC5@?3wnsP#w{s6-p11;_LxE-)$Oh(Q)XAq9l|{2 zG=1M!2dyEW&BmnQpcb_XK4;4Ro^fdxS_&r(ek6o-+3lF!Qr18}f zpOJX7xF5}m!q2}EJDz<696LyKhY5wFkh^9#9tI!5*(6GHN4W>kKa=fLIh5(l_2*j+ zV$W6*qasbw=iU=_iPgPEHh8vW4dULUqDW#mMA(xMb&zHgNSxAg_Pc8e9a2fS+(B;i zHTq`R5g((yT-tH4{%TIuhfz(yjj2XJ$WiCaF-!# zUtiMa;KybchkyK_Q8l_M;n)1Ay^R(TD*E!ZkNM%ZNMavFd|Gm4)I5!Dz5AT8(5n@{ z3%)w*V*iRGqW4n63E>W$Jedeu#R>3PN)E!ML}$2TugxSa(&299?C<-;U{i`iY>l6o zqLrEuS25a6=M8d)V+Y=l*5W0Zeic(`*L`wotcSry5-(X*iUA%HA6yuBhjS+KViJVRvZ?ip;82LxZVnTGhLnL@o z=oZO_y^BR$pCi%@Bu(A+%k5vq3pr9Th&pH^W3kW3M1I3-S#l~}jgFgEgQJNQBjgt! z&JA7>e`vtXy~6=>vQur7JX*QOHuEgu8;d9Txc>o~jr7HL0y8zkV6vp`ogd-G9YaG8 zLxv^SYzrH5OCP&P;=(G?G4h#*eD|yEGo-q^JS$O=hi9=Y<<`FBa)wJ}uw#pLaSuzj zHewFF=13(`t2?^9U|X@0zg7QQ?@nl*ULO1{AziG8snc)o6@AxSrf8lY)vE@2I~pl1k~bI5PL0*185VJxakwnarr?2yf)FeM$}0Ogn9V zD6U~8(;;*y@UQJ{2Jv;9WWpvy8mr$okp~9|KPEdCE+-z*ZiH){&1f3C03_t8DXmh} z#UgmsR2xSwsONBqZ5Z~ZFF3igjPHrBJrEXC9Pc}fAb9ltD-*`;mPYTbz9Uc8l%vB_ zF?>u8M#i=7Z^$Wj&p+t~Rho$#L{|_Ul}W45j1?GN6mT!MmT}0j2|qJdSyO4+=^A+R zXpzV6S+xCB)V?TdT&6L+=cv=N&{adIk0^7M+Nd?pg(o7y1B;DE=x2aF56!juYTHMz!5HHDySGy*b!SAJ`NlI=zL$(-&G*dw zyj;{t5n5*9^LN3|1d@4XIM+Jw7$b|zc&cX0z{8r{`J>~Ipkb6MP03+T#o!|{CG^UT zRu2q>CM+M;oEKO^nB2HMNl)h*oD=vz&V0x9Rx=*GlaF2a-Yg-jurIQdMKzVP*)+QH zu}}54bs9lKyuyB2>L~;D+FLIrO#?!sGEkNT-VGUBxl#>$qR5LbzluI;ztsjb*GV)m zV_BC=L!k9!9s-vG4ts!e@;Ey;lGwuMBZt?zv`UBYkP2%+Amgk1<{hf43*r2HL-lZj zBzG5&T`D_NB(;$$;;TcIH5?;yFud-q#*6S^|G>jokR-2p=%s8NW|#K%mW&>XDPGn3 zzz5$~&B$lD1ust|)+IQKRs!DOv+kXKe(HK2p4CLI2erP z?P-=O$F&hbuy%+eSo@Q}cPw6WCQBt|og*uCEScpM5A1Y~VRHJ-=51d*;*gUh|*U~Q|#b!{I4nH1fm!O zF|gQ=Jzb;BA4qK8Kk#_t^{#ZN{51)Yi{s9rAK_x+WAO$7UQKzM>REG{bi={7kA~pp zG?!>yKA+x$&PjALvW=GP6|ZP{JiqAifZV%J)}*vZ@dC@rDzF4Q^$G4gD3Qn={&`6m zQ(zZD{Njfg+v&(#O|9ot*~Quuif1*hgVYG*i9=?6*N3;&e{wqnYKWZqSThL7RHoDA zJg^@rS1VEJTT4z!wQ)U+cX?}B6;GF6h;2Ug;RIf-aoD4ud7>#hIgTRdyDX=Y4qml> zTOqGuO`Tq?ORtS7Ka+(KdC1tSdxgH`n|eZogPISZ&vjq5spt@DJHfjJzE{POLO-{w zSNK_tG~nsUl^0&NxCbjI8quPMTIyZ&+%X56{sOJ1Z8#B?NLh@}^20}8VhlSzSkKks zN81{D8PHHETu)E_{&~wwBIDt-r{2^)BX)6T%O}yZ@DCg06mF-NMI^j<@1db?_lvI(d|<+7L=^dnF|AO|_6XH?<=AU%){8s|JwYRJIGF0h0&rfI zGi^T4wZAmxrQ8&@)2v}d;l0xN?Cj9heWjw)25Niry!zY)A0d0Ic!al(i8A4YI ze8cU{-z2Tv#p<@nTQJiw3SMSjp1Kg-f9t_Fi1oP;&i@ug^WNoBeBEjHW1#{M_9kc8 z$ZM_Uc9-3cZ7H0)`|F&$Q%~FJGcC2@#C%7vd3h4=ew13X%&SZk+%;-%x#W;}UTSN; zWPI-8R;{F`%CEHCzk$7uUt;sP`7VOmQ1PS5+S`nqCc>8W>5mTaXhl)im`-M4*hOQJ z4W$K1zMXV%kFc)Kae}GLSB#VyCd2CoYl9yW7oM0NA7LA4aW3^NV{{>fsk}}eG8=Q4 z9;K*G6GfiKk6u=ymW0QzNWO1QC(iu28Alg~@4?|NIsS#;3M)Vz%7dks3yS-3T#ywhZizQ?@{mw z9PQrtjLVPp(my6LC+U>=T$k_j3#Z2%yrN_xmBZ#^B3|W6MX&YfDVyb@A`K^E*VS(s z`tGVy$s({H@w)w`{hCt-KSN~dl5)ms^Ft-&CzS#dUigMA)vrXl}G+Wa~6X5LlwnTeQkV+tIT9?w7EA@neQsTJs2O1pSFD8pht1aBbDh znX@adFJ=$(`KSqIS1gm!)O6`fGRz-;9z;Wx(#=l{ba;`;_`ImMT&)a0vN7ygw4Va}IA`%JIjZBnLkI0i1TiCpe#oyAQ% zZb&tjOnAWRoA)035BvHw!=EU8qqR+bg|{tPFPi7SN|uW|qxyO&B~#b+<)@usnKq&D zM&gT&Y4J=cTuziMR3s(^I~5GyOLR(-2_ZHcF+WzXRhGd+t5}YP$Q8FQf%G&7y9C?* z`NRc29gZ0d*dg(!4~$dIzOy9o_MFNbUsG}#q>b}9hE!ECNz2IO7Y4SiXe91%0DEPm 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 literal 0 HcmV?d00001 diff --git a/CristalDiskMark/source/CrystalDiskMark/res/DiskMarkA.ico b/CristalDiskMark/source/CrystalDiskMark/res/DiskMarkA.ico new file mode 100644 index 0000000000000000000000000000000000000000..93fed3e5f1b2c0e1842fb8f25e28c67e5736625f GIT binary patch literal 59640 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%0Di!7!fU#rBT0veXVfo*?$_O6P)mJ!SQM(Fwa=< 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 literal 0 HcmV?d00001 diff --git a/CristalDiskMark/source/CrystalDiskMark/res/DiskMarkS.ico b/CristalDiskMark/source/CrystalDiskMark/res/DiskMarkS.ico new file mode 100644 index 0000000000000000000000000000000000000000..0b256ef73d5add6d797cb63a29622f5fb626a93f GIT binary patch literal 60200 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%0De4`43gGqsttZR9E-Kypad;S zkqH^{_;+0%=>Z_jU|9}IrN~$U=+a)TRRm7~3SOWv2kID( zt`OPoGW=7VJw=YR0@Ob!T0vD0joBjZ(F6j3?L?N5@X>g@>0D+okr6V}1Jeqsntc&p zDC1wLlH6?3-0ns!Q=vlV=^_vq_pc!kor7w-8hA#CWaNYbl0Ytl5vm6Dl&LI+)p`|3 zy*!q8p zIk(@csvwMWOB9U}LJ$F?kSK}@RzD2NMzm!AlU4 zTU8pa5~R?UrWe|@0um`u>7nJcw5R8^qyRDUY z5C36{TepnCZ4!GQ!1!?SxXI_R_o)ACAhMJ}GkDx#g@3;(4HfV)N;VfKlKDB2EzRFogo#_cG71S9h}JHk&D64qv- zb>c!>wxW`^1|^P{-4Jy0eRm+149MbFO7eX*%jp5}tn|dr8yPw0l4Jl8Yf-J?%*vG= z6AA50pWcB-bsd^zS;!*7_dz0sW3?Sf;gH?m&yf*KbLUY^3Y~ml3%4g>(qy>-!k%8` z1}!p9@c&>9w3WjCvUUc_@=;T5Tq3y|P&)~Dj;5?-Vb%kmuet5_!T|I#R_ z2U3f#mTBrKFVl5BWN=-U2lz=g>nxuk{mnjnN$j3t z${WuS)60VL;FEq)hB98DlWB)PoN!BM@TC$4#@bxlStfkxQ%flPjF@?nBWbrww!@5Mvs-X8q%b#?^dCeRf~ zp`>@UtE-}$O8Tnvu9i*ft6r>P9tP+xN7BM89GlXnG(nCr^i)1)p1+Fn;D7z6Iz^`_b*A#4>XeAq2B*bhRG}7Pab|G-kKMEj zuF7@Ag5TCGdW;+qTF5P9q?aU$X!1#nPznV?kmJ2t(!|frC7{O^K?>4!*N^31++9(oEKG<}rTIQ9e&NgkTree~IZ#v&yy3sUI@rEgv@ z)4{h@f~|%HIXV1n+dfW~sauJV^r@x4d^JJ1V9bPRXhiTVKhV7@M1tiI0ZrH894`kh zy=4r%4wlXdA(Fq#v1C_Jd!XKqm6$%7?HP0CjkeJ)Q5UpryBATqfAh#xWgg1tK!zjC ztarl*^6HS-X221%p(XhkO-MeFKsPvtyQXVa^c&Dai7EjbPAWn8~sHR zSle5<2)Lw2Nuv-#B@QWlMxqHNlDCYL!~9i1EJoUUVqwR=N85KXTAs=mcqyjCe>moa z^*DgizH>^~!C9G_W&W^2kl>P@G643m@T+LQ?G?N&8tIa z*9#CKhmjon!c3P*xg8S3ba|fDAA<6B#@5d$-KG4zR{>S_4R;V7y#?#uu zROOPk?Gv;+c1gm=%=jmi6~)cQ4m1=ZiZd=9-%M}aBHF_%V4L(q zHR*AD#Ofz%pt)82z&LwdHZwvp+k8pGxpJ{yl7DoeSm|M_;D<%gyXTp^Y zU}Pz^@Z6GQ6gCE=ECn+<_s!t!74aijiU7$k-tBAg&DIYFTa*;&z9|K496|bkgmJ%s z2cpx!nGv<3oDM@jzfZ{umeZRM2?k@n6vl9K>g0>m2CbjmdHv`drLAWEE;(>gVB@1g zFq=$7l6AQ|Rh35th`$oU6zxg@iW3EibpVAx$ORZ9Ko_2;Su{?zwj0NfLLaHlLs+ z@8A6CHF9ngGq?h)qrR18$hJ(_%BJCDtd!mXSNqP%sfu}|LKmgT2O$!B`BSA66MG&~ zLa$$WWygJ#-0eFj31ckDb{~1#vZvvSLnd{p*vhrYKmQR&M`x1D$im#uQ&>!1-m=c> zG-V=428)#q4M-AuraFW3qU3>D*i)-+E*)mi(=_iiqr>K$f+1UR15bI3F?+I)hLqv~ zZbPLoWpL#}ORUJGcH+YLs|ShOc$DFpF7Qc-D2&0)qQucuBsV+vj*HJgtzg?ad>zNO XyjR4UnmN35XX9mgLC3hq!`P^@BA#43tQMHEyZ2uPC2OcoNUr+v}(w0+Ujw|&t+pf6fc zb`+6)QK1-!3xq%zW+s_Q0$POZ2?<$dGHWI-r#(IW{C@X&o*6jD_MD#6dTz#NhUb3o z?|y&V_g>4IU=>)iW?B4yhPD4@%X-eTtQj-R_Z5>ZtDE1ZPBq_uU0_+WZ?~*Dyu%dh z75-%2_x+cNRNA9iANXvp9BW?9$b>6Wjb+K8Hxck8&XyzsMTtPM4o@Obk_?t6L*7)# zmumE-ntbV|G8y6Wbfh8^E@!Siz&FTdp&WjtyevzUCjzAcd)65&C-@%02i)L?^YJS( ztYQxb-&sYBZ&__N6+c}VJ^o@cDAw9b$U@iPm)Z8S1ZKO)4xnwnejS6H79}TA!G62m zpZe8XR@eK}q9+$(t!zP9f~$Ofuw40ZX<-Q$-0&0jWx}O-;Npu|{VNyOTa2&Xw%Rro zL{G30vqT=g@}taSIkWT=a5Ey}N|3+p-Te1>!&q|#OYn}oA6Y$I`!vXx)?1f0SQp>6 zI=0;y_peF{`JRL_Cj2**Wk6`IOgDMcVXqL&SA{h}qWIo#y5Ib6xF!?9@8y8wvUF3$ zQ0-H|8hn<3s4F#(Cqq8P_uvuUAqGZ1d#-2CjE;A2Y=7s5%OCtuNvIN%m1kZckkU<_ zbYqbqD>#NF8-39e3jv28v7d*xt*)KZ2pfZ+YN|*Ei+c9l$sQRO*NFig?@S(RE+1>D zHbKIt9bhKR8hwIHs0c`D;%pI|FcEySMEjOW@iQxULGz-xYx}KWx*NoRo?W+R&sC4L zRJr8vvcZ%GV2ybaA;tVYSo63bIQVTFC&W%Ig(BjxZ~r~^Kj{Wpg|9=kPmZ7esSD17 zZ1$=lv7t#yD9Us9uIUCxhyuTUaXMTXJ-$HpWsr4s-sybrma&LKjwX@fE1IOg$$h5? zoGp&akKWOSl8rl3xRd z9*Wg1B&~%1yvR4ZP<&7CJ_%+wmE3?g+v)%CN3fS_Do^-V5Ik3oJaXYLlC$=BOCE@^ zSltUYS9uf(|60%c4?WzrX%c`8Gm)A}VWDiMLe!0N9tgr%-69HL*Y;a@=c2Psi6xyl zbnJ<&afj<)zxY>{2>M1(FB?4ebpPQw1BV|Ss(ofuQk6Oe=RREAws{g^(|6!r$d5NH z!7117cbzaWTE8eOL`f5o_z`e>Xyg-(WjZKC1b?xVqrj@p_ih%0*I6C!PDv3qt!rX+ z3y3s+%y$`IyLbJ7aCIHwg1Zmeq)gJ0YaSfhfB0d%1C9jk1`FfInyYjdi%n{qrCD8; zTW^tT+1A%x|AH*?z+{=5&U_6>k&pXVwr{!4rUIVVS8mo-`_;KX(`39f1Mc5NF+1Ba|9k$7v zZCQOyx;fxrIsbX*m2J66b zdV%x>O7Z1`_lx~buF+yr!J|IlKOmOmP0~$;Tb$e(*Locn4*1agsRnN9J^s9UR<)%oqVl(3r)}lM_sl?1Ky|#K@bbY~@rI?DmTEli2v-$pMyEMyN}L`+L{vuV)$mwJrfB)&6V!WWA zCW_cNI#5$ASI|uS!<(pX;a`s=Fl;<)^tJ;<=Bl_YOHyfpB17$JLn=835C_MOYH=2< z8s8z0HG?Ect4BUx(7xry{*NBw6re&Ht8zHD;}En4A!kE%_WUoUoSI`x^J;0AYenzT zXQ>-WDNS-9N>MRXkV|K$0y_v|L!@l{!tei)3~7R>25UTiy`r5ZiJDD?kS|v3WMmdc@TvbR8<4rcdz)!4z1!b~;qz_7|t7$%^V| zQ>cr&w%-O64GYaYda4j(dUoGoKxDsbE$ZsH7~}L2W4n()6C zJ+a7bRe-RHbPdz&bYHGs)i6`(h-YZYcr!> zh9c86MLC>Y+<)ki-n}z>_s!%1T?%!?&&crwu-A8BX78SRhHB;}{maMCugO`W#*hVq z6ZBp=@)&xa{`Ee@v+O_>OP&#^QS=Wx~;vF4=upWti7j8<0D+iCw zO9qN;eo#bM3;7!hhHK~L`%CsEN3fEi+GqO?KG3)SK15fvZc#Es^i~cWnFGB;$DX9E zb8^fzPz}ZC=g+BCs;`Xxm!58vmE0!)LNt=C#1E?zId~`Of3@S?8*sYml^DiX^og`} zqw_`Kw>I9uGB7r_m1rArDw}k`= zstNJaOKt6utC z$`zj3l8}O9xb~`|XAB&gJ^a~x^5?3CWN%*l!JA*V{W04rM?r4iqy((9C?AM0(=&i2 zN%#~@3C+s!i+|wAN}uL#LV5r_=6&fgMDu9Tf`< zU?{Stc8{Je&jmrrIt~Jd7oJ@CQ;s6 zEfvjpAC^L1;ZPe%-~O3~a26W;crJX(u3M_E;C82{X5FM0^rvU;ftQr+HJ8 evmE)7%Wa8Xxn$(boD7#I8qvESl868O-@gF0`0z^r literal 0 HcmV?d00001 diff --git a/CristalDiskMark/source/License/COPYRIGHT-ja.txt b/CristalDiskMark/source/License/COPYRIGHT-ja.txt new file mode 100644 index 0000000..0171b56 --- /dev/null +++ b/CristalDiskMark/source/License/COPYRIGHT-ja.txt @@ -0,0 +1,17 @@ +(C) 2007-2026 hiyohiyo + +ȉɒ߂ɏ]A{\tgEFAъ֘Ãt@Ciȉu\tgEF +Avj̕擾邷ׂĂ̐lɑ΂A\tgEFA𖳐ɈƂ𖳏ŋ +‚܂Bɂ́A\tgEFA̕gpAʁAύXAAfځAЕzATu +CZXA/܂͔̔錠Aу\tgEFA񋟂鑊ɓ +Ƃ‚錠Ɋ܂܂܂B + +L̒쌠\і{\A\tgEFÂׂĂ̕܂͏dvȕ +Lڂ̂Ƃ܂B + +\tgEFÁû܂܁vŁAł邩Öقł邩킸A̕ۏ؂ +񋟂܂Błۏ؂Ƃ́AiA̖ړIւ̓KAьN +Qɂ‚Ă̕ۏ؂܂݂܂AɌ肳̂ł͂܂B ҂܂͒ +쌠҂́A_sׁAs@sׁA܂͂ȊOł낤ƁA\tgEFAɋN܂ +֘AA邢̓\tgEFA̎gp܂͂̑̈ɂĐ؂̐A +QȂ̋`ɂ‚ĉ̐ӔCȂ̂Ƃ܂B diff --git a/CristalDiskMark/source/License/COPYRIGHT.txt b/CristalDiskMark/source/License/COPYRIGHT.txt new file mode 100644 index 0000000..b7e2fcd --- /dev/null +++ b/CristalDiskMark/source/License/COPYRIGHT.txt @@ -0,0 +1,19 @@ +(C) 2007-2026 hiyohiyo + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. \ No newline at end of file diff --git a/CristalDiskMark/source/License/DiskSpd-LICENSE.txt b/CristalDiskMark/source/License/DiskSpd-LICENSE.txt new file mode 100644 index 0000000..3cd6750 --- /dev/null +++ b/CristalDiskMark/source/License/DiskSpd-LICENSE.txt @@ -0,0 +1,19 @@ +Copyright (c) 2014 Microsoft + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/CristalDiskMark/source/License/PolyHook_2_0-LICENSE.txt b/CristalDiskMark/source/License/PolyHook_2_0-LICENSE.txt new file mode 100644 index 0000000..f76de84 --- /dev/null +++ b/CristalDiskMark/source/License/PolyHook_2_0-LICENSE.txt @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2018 Stephen Eckels + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/CristalDiskMark/source/License/win32-custom-menubar-aero-theme-LICENSE.txt b/CristalDiskMark/source/License/win32-custom-menubar-aero-theme-LICENSE.txt new file mode 100644 index 0000000..c1f8899 --- /dev/null +++ b/CristalDiskMark/source/License/win32-custom-menubar-aero-theme-LICENSE.txt @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 adzm + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/CristalDiskMark/source/License/win32-darkmode-LICENSE.txt b/CristalDiskMark/source/License/win32-darkmode-LICENSE.txt new file mode 100644 index 0000000..13bdb53 --- /dev/null +++ b/CristalDiskMark/source/License/win32-darkmode-LICENSE.txt @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2019 Richard Yu + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/CristalDiskMark/source/diskspd22/.gitattributes b/CristalDiskMark/source/diskspd22/.gitattributes new file mode 100644 index 0000000..df1344f --- /dev/null +++ b/CristalDiskMark/source/diskspd22/.gitattributes @@ -0,0 +1,26 @@ +# Set the default behavior, in case people don't have core.autocrlf set. +* text=auto + +# Use text conventions for commonly used text extensions. +*.csv text +*.ini text +*.json text +*.txt text +*.xml text +*.ps1 text +*.ps1xml text +*.psd1 text + + +# Denote all files that are truly binary and should not be modified. +*.dll binary +*.exe binary +*.gz binary +*.ico binary +*.jpg binary +*.lib binary +*.pdb binary +*.pdf binary +*.png binary +*.wim binary +*.zip binary diff --git a/CristalDiskMark/source/diskspd22/.gitignore b/CristalDiskMark/source/diskspd22/.gitignore new file mode 100644 index 0000000..f7af6c1 --- /dev/null +++ b/CristalDiskMark/source/diskspd22/.gitignore @@ -0,0 +1,184 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.sln.docstates + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +build/ +bld/ +[Bb]in/ +[Oo]bj/ + +# Roslyn cache directories +*.ide/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +#NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +.vs/ +ipch/ +*.aps +*.ncb +*.opensdf +*.sdf +*.cachefile + +# Visual Studio profiler +*.psess +*.vsp +*.vspx + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding addin-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +_NCrunch_* +.*crunch*.local.xml + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# TODO: Comment the next line if you want to checkin your web deploy settings +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/packages/* +# except build/, which is used as an MSBuild target. +!**/packages/build/ +# If using the old MSBuild-Integrated Package Restore, uncomment this: +#!**/packages/repositories.config + +# Windows Azure Build Output +csx/ +*.build.csdef + +# Windows Store app package directory +AppPackages/ + +# Others +sql/ +*.Cache +ClientBin/ +[Ss]tyle[Cc]op.* +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.pfx +*.publishsettings +node_modules/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ diff --git a/CristalDiskMark/source/diskspd22/CmdLineParser/CmdLineParser.cpp b/CristalDiskMark/source/diskspd22/CmdLineParser/CmdLineParser.cpp new file mode 100644 index 0000000..cdf44ad --- /dev/null +++ b/CristalDiskMark/source/diskspd22/CmdLineParser/CmdLineParser.cpp @@ -0,0 +1,2080 @@ +/* + +DISKSPD + +Copyright(c) Microsoft Corporation +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#include "CmdLineParser.h" +#include "Common.h" +#include "XmlProfileParser.h" +#include +#include +#include + +CmdLineParser::CmdLineParser() : + _dwBlockSize(64 * 1024), + _ulWriteRatio(0), + _hEventStarted(nullptr), + _hEventFinished(nullptr) +{ +} + +CmdLineParser::~CmdLineParser() +{ +} + +// Get size in bytes from a string (KMGTb) +bool CmdLineParser::_GetSizeInBytes(const char *pszSize, UINT64& ullSize, const char **pszRest) const +{ + bool fOk = true; + UINT64 ullResult = 0; + UINT64 ullMultiplier = 1; + const char *rest = nullptr; + + fOk = Util::ParseUInt(pszSize, ullResult, rest); + + if (fOk) + { + char ch = static_cast(toupper(*rest)); + + switch (ch) + { + case '\0': { break; } + case 'T': { ullMultiplier *= 1024; } + case 'G': { ullMultiplier *= 1024; } + case 'M': { ullMultiplier *= 1024; } + case 'K': { ullMultiplier *= 1024; ++rest; break; } + case 'B': { ullMultiplier = _dwBlockSize; ++rest; break; } + default: { + + // + // If caller is not expecting continuation, we know this is malformed now and + // can say so with respect to size specifiers. + // If there is continuation, caller is responsible for validating. + // + + if (!pszRest) + { + fOk = false; + fprintf(stderr, "Invalid size '%c'. Valid: K - KiB, M - MiB, G - GiB, T - TiB, B - block\n", *rest); + } + } + } + + if (fOk) + { + // + // Second chance after parsing valid size qualifier. + // + + if (!pszRest && *rest != '\0') + { + fOk = false; + fprintf(stderr, "Unrecognized characters after size specification\n"); + } + + // + // Now apply size specifier. + // + + else if (ullResult <= MAXUINT64 / ullMultiplier) + { + ullResult *= ullMultiplier; + } + else + { + // overflow + fOk = false; + fprintf(stderr, "Overflow applying multipler '%c'\n", ch); + } + } + } + else + { + fprintf(stderr, "Invalid integer\n"); + } + + if (fOk) + { + ullSize = ullResult; + + if (pszRest) + { + *pszRest = rest; + } + } + + return fOk; +} + +bool CmdLineParser::_GetRandomDataWriteBufferData(const string& sArg, UINT64& cb, string& sPath) +{ + bool fOk = true; + size_t iComma = sArg.find(','); + if (iComma == sArg.npos) + { + fOk = _GetSizeInBytes(sArg.c_str(), cb, nullptr); + sPath = ""; + } + else + { + fOk = _GetSizeInBytes(sArg.substr(0, iComma).c_str(), cb, nullptr); + sPath = sArg.substr(iComma + 1); + } + return fOk; +} + +void CmdLineParser::_DisplayUsageInfo(const char *pszFilename) const +{ + // ISSUE-REVIEW: this formats badly in the default 80 column command prompt + printf("\n"); + printf("Usage: %s [options] target1 [ target2 [ target3 ...] ]\n", pszFilename); + printf("version %s (%s)\n", DISKSPD_NUMERIC_VERSION_STRING, DISKSPD_DATE_VERSION_STRING); + printf("\n"); + + printf( + "Valid targets:\n" + " file_path\n" + " #\n" + " :\n" + "\n" + "Sizes, offsets and lengths are specified as integer bytes, or with an\n" + "optional suffix of KMGT (KiB/MiB/GiB/TiB) or b (for blocks, see -b).\n" + "Examples: 4k = 4096\n" + " with -b4k, 8b = 32768 (8 * 4KiB)\n" + "\n" + "Available options:\n" + " -? display usage information\n" + " -: experimental behaviors, as a bitmask of flags. current:\n" + " 1 - allow throughput rate limit sleeps >1ms if indicated by rate\n" + " -ag group affinity - threads assigned round-robin to CPUs by processor groups, 0 - n.\n" + " Groups are filled from lowest to highest processor before moving to the next.\n" + " [default; use -n to disable default affinity]\n" + " -a[g#,]#[,#,...]> advanced CPU affinity - threads assigned round-robin to the CPUs stated, in order of\n" + " specification; g# is the processor group for the following CPUs. If no group is\n" + " stated, 0 is default. Additional groups/processors can be added, comma separated,\n" + " on the same or separate -a parameters.\n" + " Examples: -a0,1,2 and -ag0,0,1,2 are equivalent.\n" + " -ag0,0,1,2,g1,0,1,2 specifies the first three CPUs in groups 0 and 1.\n" + " -ag0,0,1,2,g1,0,1,2 and -ag0,0,1,2 -ag1,0,1,2 are equivalent.\n" + " -b IO size, defines the block \'b\' for sizes stated in units of blocks [default=64K]\n" + " -B[:length] bounds; specify range of target to issue IO to - base offset and length\n" + " (default: IO is issued across the entire target)\n" + " -c create file targets of the given size. Conflicts with non-file target specifications.\n" + " -C cool down time - duration of the test after measurements finished [default=0s].\n" + " -D Capture IOPs statistics in intervals of ; these are per-thread\n" + " per-target: text output provides IOPs standard deviation, XML provides the full\n" + " IOPs time series in addition. [default=1000, 1 second].\n" + " -d duration (in seconds) to run test [default=10s]\n" + " -f maximum target offset to issue IO to (non-inclusive); -Bbase -f(base+length) is the same\n" + " as -Bbase:length. For example, to test only the first sectors of a disk.\n" + " -f open file with one or more additional access hints\n" + " r : the FILE_FLAG_RANDOM_ACCESS hint\n" + " s : the FILE_FLAG_SEQUENTIAL_SCAN hint\n" + " t : the FILE_ATTRIBUTE_TEMPORARY hint\n" + " [default: none]\n" + " -F total number of threads (conflicts with -t)\n" + " -g[i] throughput per-thread per-target throttled to given value; defaults to bytes per millisecond\n" + " With the optional i qualifier the value is IOPS of the specified block size (-b).\n" + " Throughput limits cannot be specified when using completion routines (-x)\n" + " [default: no limit]\n" + " -h deprecated, see -Sh\n" + " -i number of IOs per burst; see -j [default: inactive]\n" + " -j interval in between issuing IO bursts; see -i [default: inactive]\n" + " -I Set IO priority to . Available values are: 1-very low, 2-low, 3-normal (default)\n" + " -l Use large pages for IO buffers\n" + " -L measure latency statistics\n" + " -n disable default affinity (-a)\n" + " -N specify the flush mode for memory mapped I/O\n" + " v : uses the FlushViewOfFile API\n" + " n : uses the RtlFlushNonVolatileMemory API\n" + " i : uses RtlFlushNonVolatileMemory without waiting for the flush to drain\n" + " [default: none]\n" + " -o number of outstanding I/O requests per target per thread\n" + " (1=synchronous I/O, unless more than 1 thread is specified with -F)\n" + " [default=2]\n" + " -O number of outstanding I/O requests per thread - for use with -F\n" + " (1=synchronous I/O)\n" + " -p start parallel sequential I/O operations with the same offset\n" + " (ignored if -r is specified, makes sense only with -o2 or greater)\n" + " -P enable printing a progress dot after each [default=65536]\n" + " completed I/O operations, counted separately by each thread \n" + " -r[align] random I/O aligned to [align] byte offsets within the target range (overrides -s)\n" + " [default alignment=block size (-b)]\n" + " -rd[params] specify an non-uniform distribution for random IO in the target\n" + " [default uniformly random]\n" + " distributions: pct, abs\n" + " all: IO%% and %%Target/Size are cumulative. If the sum of IO%% is less than 100%% the\n" + " remainder is applied to the remainder of the target. An IO%% of 0 indicates a gap -\n" + " no IO will be issued to that range of the target.\n" + " pct : parameter is a combination of IO%%/%%Target separated by : (colon)\n" + " Example: -rdpct90/10:0/10:5/20 specifies 90%% of IO in 10%% of the target, no IO\n" + " next 10%%, 5%% IO in the next 20%% and the remaining 5%% of IO in the last 60%%\n" + " abs : parameter is a combination of IO%%/Target Size separated by : (colon)\n" + " If the actual target size is smaller than the distribution, the relative values of IO%%\n" + " for the valid elements define the effective distribution.\n" + " Example: -rdabs90/10G:0/10G:5/20G specifies 90%% of IO in 10GiB of the target, no IO\n" + " next 10GiB, 5%% IO in the next 20GiB and the remaining 5%% of IO in the remaining\n" + " capacity of the target. If the target is only 20G, the distribution truncates at\n" + " 90/10G:0:10G and all IO is directed to the first 10G (equivalent to -f10G).\n" + " -rs percentage of requests which should be issued randomly; -r is used to specify IO alignment.\n" + " Sequential IO runs are homogeneous when a mixed r/w ratio is specified (-w) and their lengths\n" + " follow a geometric distribution based on the percentage (chance of next IO being sequential).\n" + " -R[p] output format. With the p prefix, the input profile (command line or XML) is validated and\n" + " re-output in the specified format without running load, useful for checking or building\n" + " complex profiles.\n" + " [default: text]\n" + " -s[i][align] stride size of [align] bytes, alignment & offset between operations\n" + " [default=non-interlocked, default alignment=block size (-b)]\n" + " By default threads track independent sequential IO offsets starting at base offset of the target.\n" + " With multiple threads this results in threads overlapping their IOs - see -T to divide\n" + " them into multiple separate sequential streams on the target.\n" + " With the optional i qualifier (-si) threads interlock on a shared sequential offset.\n" + " Interlocked operations may introduce overhead but make it possible to issue a single\n" + " sequential stream to a target which responds faster than one thread can drive.\n" + " (ignored if -r specified, -si conflicts with -p, -rs and -T)\n" + " -S[bhmruw] control caching behavior [default: caching is enabled, no writethrough]\n" + " non-conflicting flags may be combined in any order; ex: -Sbw, -Suw, -Swu\n" + " -S equivalent to -Su\n" + " -Sb enable caching (default, explicitly stated)\n" + " -Sh equivalent -Suw\n" + " -Sm enable memory mapped I/O\n" + " -Su disable software caching, equivalent to FILE_FLAG_NO_BUFFERING\n" + " -Sr disable local caching, with remote sw caching enabled; only valid for remote filesystems\n" + " -Sw enable writethrough (no hardware write caching), equivalent to FILE_FLAG_WRITE_THROUGH or\n" + " non-temporal writes for memory mapped I/O (-Sm)\n" + " -t number of threads per target (conflicts with -F)\n" + " -T starting separation between I/O operations performed on the same target by different threads\n" + " [default=0] (starting offset = base target offset + (thread number * )\n" + " only applies to -s sequential IO with #threads > 1, conflicts with -r and -si\n" + " -v[s] verbose mode - with s, only provide additional summary statistics\n" + " -w percentage of write requests (-w and -w0 are equivalent and result in a read-only workload).\n" + " absence of this switch indicates 100%% reads\n" + " IMPORTANT: a write test will destroy existing data without a warning\n" + " -W warm up time - duration of the test before measurements start [default=5s]\n" + " -x use completion routines instead of I/O Completion Ports\n" + " -X use an XML file to configure the workload. Profile defaults for -W/d/C (durations) and -R/v/z\n" + " (output format, verbosity and random seed) may be overriden by direct specification.\n" + " Targets can be defined in XML profiles as template paths of the form * (*1, *2, ...).\n" + " When run, specify the paths to substitute for the template paths in order on the command line.\n" + " The first specified target is *1, second is *2, and so on.\n" + " Example: diskspd -d60 -Xprof.xml first.bin second.bin (prof.xml using *1 and *2, 60s run)\n" + " -z[seed] set random seed [with no -z, seed=0; with plain -z, seed is based on system run time]\n" + "\n" + "Write buffers:\n" + " -Z zero buffers used for write tests\n" + " -Zr per IO random buffers used for write tests - this incurrs additional run-time\n" + " overhead to create random content and shouln't be compared to results run\n" + " without -Zr\n" + " -Z use a buffer filled with random data as a source for write operations.\n" + " -Z, use a buffer filled with data from as a source for write operations.\n" + "\n" + " By default, write source buffers are filled with a repeating pattern (0, 1, 2, ..., 255, 0, 1, ...)\n" + "\n" + "Synchronization:\n" + " -ys signals event before starting the actual run (no warmup)\n" + " (creates a notification event if does not exist)\n" + " -yf signals event after the actual run finishes (no cooldown)\n" + " (creates a notification event if does not exist)\n" + " -yr waits on event before starting the run (including warmup)\n" + " (creates a notification event if does not exist)\n" + " -yp stops the run when event is set; CTRL+C is bound to this event\n" + " (creates a notification event if does not exist)\n" + " -ye sets event and quits\n" + "\n" + "Event Tracing:\n" + " -e Use query perf timer (qpc), cycle count, or system timer respectively.\n" + " [default = q, query perf timer (qpc)]\n" + " -ep use paged memory for the NT Kernel Logger [default=non-paged memory]\n" + " -ePROCESS process start & end\n" + " -eTHREAD thread start & end\n" + " -eIMAGE_LOAD image load\n" + " -eDISK_IO physical disk IO\n" + " -eMEMORY_PAGE_FAULTS all page faults\n" + " -eMEMORY_HARD_FAULTS hard faults only\n" + " -eNETWORK TCP/IP, UDP/IP send & receive\n" + " -eREGISTRY registry calls\n" + "\n\n"); + + printf("Examples:\n\n"); + printf("Create 8192KB file and run read test on it for 1 second:\n\n"); + printf(" %s -c8192K -d1 testfile.dat\n", pszFilename); + printf("\n"); + printf("Set block size to 4KB, create 2 threads per file, 32 overlapped (outstanding)\n"); + printf("I/O operations per thread, disable all caching mechanisms and run block-aligned random\n"); + printf("access read test lasting 10 seconds:\n\n"); + printf(" %s -b4K -t2 -r -o32 -d10 -Sh testfile.dat\n\n", pszFilename); + printf("Create two 1GB files, set block size to 4KB, create 2 threads per file, affinitize threads\n"); + printf("to CPUs 0 and 1 (each file will have threads affinitized to both CPUs) and run read test\n"); + printf("lasting 10 seconds:\n\n"); + printf(" %s -c1G -b4K -t2 -d10 -a0,1 testfile1.dat testfile2.dat\n", pszFilename); + + printf("\n"); +} + +bool CmdLineParser::_ParseETWParameter(const char *arg, Profile *pProfile) +{ + assert(nullptr != arg); + assert(0 != *arg); + + bool fOk = true; + pProfile->SetEtwEnabled(true); + if (*(arg + 1) != '\0') + { + const char *c = arg + 1; + if (*c == 'p') + { + pProfile->SetEtwUsePagedMemory(true); + } + else if (*c == 'q') + { + pProfile->SetEtwUsePerfTimer(true); + } + else if (*c == 's') + { + pProfile->SetEtwUseSystemTimer(true); //default + } + else if (*c == 'c') + { + pProfile->SetEtwUseCyclesCounter(true); + } + else if (strcmp(c, "PROCESS") == 0) //process start & end + { + pProfile->SetEtwProcess(true); + } + else if (strcmp(c, "THREAD") == 0) //thread start & end + { + pProfile->SetEtwThread(true); + } + else if (strcmp(c, "IMAGE_LOAD") == 0) //image load + { + pProfile->SetEtwImageLoad(true); + } + else if (strcmp(c, "DISK_IO") == 0) //physical disk IO + { + pProfile->SetEtwDiskIO(true); + } + else if (strcmp(c, "MEMORY_PAGE_FAULTS") == 0) //all page faults + { + pProfile->SetEtwMemoryPageFaults(true); + } + else if (strcmp(c, "MEMORY_HARD_FAULTS") == 0) //hard faults only + { + pProfile->SetEtwMemoryHardFaults(true); + } + else if (strcmp(c, "NETWORK") == 0) //tcpip send & receive + { + pProfile->SetEtwNetwork(true); + } + else if (strcmp(c, "REGISTRY") == 0) //registry calls + { + pProfile->SetEtwRegistry(true); + } + else + { + fOk = false; + } + } + else + { + fOk = false; + } + + return fOk; +} + +bool CmdLineParser::_ParseAffinity(const char *arg, TimeSpan *pTimeSpan) +{ + bool fOk = true; + + assert(nullptr != arg); + assert('\0' != *arg); + + const char *c = arg + 1; + + // -a and -ag are functionally equivalent; group-aware affinity. + // Note that group-aware affinity is default. + + // look for the -a simple case + if (*c == '\0') + { + return true; + } + + // look for the -ag simple case + if (*c == 'g') + { + // peek ahead, done? + if (*(c + 1) == '\0') + { + return true; + } + + // leave the parser at the g; this is the start of a group number + } + + // more complex affinity -ag0,0,1,2,g1,0,1,2,... OR -a0,1,2,.. + // n counts the -a prefix, the first parsed character is string index 2 + DWORD nGroup = 0, nNum = 0, n = 2; + bool fGroup = false, fNum = false; + while (*c != '\0') + { + if ((*c >= '0') && (*c <= '9')) + { + // accumulating a number + fNum = true; + nNum = 10 * nNum + (*c - '0'); + } + else if (*c == 'g') + { + // bad: ggggg + if (fGroup) + { + fOk = false; + } + + // now parsing a group number + fGroup = true; + } + else if (*c == ',') + { + // separator; if parsing group and have a number, now have the group + if (fGroup && fNum) + { + if (nNum > MAXWORD) + { + fprintf(stderr, "ERROR: group %u is out of range\n", nNum); + fOk = false; + } + else + { + nGroup = nNum; + nNum = 0; + fGroup = false; + } + } + // at a split but don't have a parsed number, error + else if (!fNum) + { + fOk = false; + } + // have a parsed CPU number + else + { + if (nNum > MAXBYTE) + { + fprintf(stderr, "ERROR: CPU %u is out of range\n", nNum); + fOk = false; + } + else + { + pTimeSpan->AddAffinityAssignment((WORD)nGroup, (BYTE)nNum); + nNum = 0; + fNum = false; + } + } + } + else + { + fOk = false; + } + + // bail out to error pretty print on error + if (!fOk) + { + break; + } + + c++; + n++; + } + + // if parsing a group or don't have a final number, error + if (fGroup || !fNum) + { + fOk = false; + } + + if (fOk && nNum > MAXBYTE) + { + fprintf(stderr, "ERROR: CPU %u is out of range\n", nNum); + fOk = false; + } + + if (!fOk) + { + // mid-parse error, show the point at which it occured + if (*c != '\0') { + fprintf(stderr, "ERROR: syntax error parsing affinity at highlighted character\n-%s\n", arg); + while (n-- > 0) + { + fprintf(stderr, " "); + } + fprintf(stderr, "^\n"); + } + else + { + fprintf(stderr, "ERROR: incomplete affinity specification\n"); + } + } + + if (fOk) + { + // fprintf(stderr, "FINAL parsed group %d CPU %d\n", nGroup, nNum); + pTimeSpan->AddAffinityAssignment((WORD)nGroup, (BYTE)nNum); + } + + return fOk; +} + +bool CmdLineParser::_ParseFlushParameter(const char *arg, MemoryMappedIoFlushMode *FlushMode) +{ + assert(nullptr != arg); + assert(0 != *arg); + + bool fOk = true; + if (*(arg + 1) != '\0') + { + const char *c = arg + 1; + if (_stricmp(c, "v") == 0) + { + *FlushMode = MemoryMappedIoFlushMode::ViewOfFile; + } + else if (_stricmp(c, "n") == 0) + { + *FlushMode = MemoryMappedIoFlushMode::NonVolatileMemory; + } + else if (_stricmp(c, "i") == 0) + { + *FlushMode = MemoryMappedIoFlushMode::NonVolatileMemoryNoDrain; + } + else + { + fOk = false; + } + } + else + { + fOk = false; + } + return fOk; +} + +bool CmdLineParser::_ParseRandomDistribution(const char *arg, vector& vTargets) +{ + vector vOr; + DistributionType dType; + bool fOk = false; + UINT32 pctAcc = 0, pctCur; // accumulated/cur pct io + UINT64 targetAcc = 0, targetCur; // accumulated/cur target + + if (!strncmp(arg, "pct", 3)) + { + dType = DistributionType::Percent; + } + else if (strncmp(arg, "abs", 3)) + { + fprintf(stderr, "Unrecognized random distribution type\n"); + return false; + } + else + { + dType = DistributionType::Absolute; + } + + arg += 3; + + // + // Parse pairs of + // + // * pct: percentage/target percentage + // * abs: percentage/absolute range of target + // + // Ex: 90/10:5/5 => [0,90) -> [0, 10) :: [90, 95) -> [10, 15) + // a remainder of [95, 100) -> [15, 100) would be applied. + // + // Percentages are cumulative and successively define the span of + // the preceding definition. Absolute ranges are also cumulative: + // 10/1G:90/1G puts 90% of accesses in the second 1G range of the + // target. + // + // A single percentage can be 100 but is of limited value since it + // would only be valid as a single element distribution. + // + // Basic numeric validations are done here (similar to XSD for XML). + // Cross validation with other workload parameters (blocksize) and whole + // distribution validation is delayed to common code. + // + + while (true) + { + // Consume IO% integer + fOk = Util::ParseUInt(arg, pctCur, arg); + if (!fOk) + { + fprintf(stderr, "Invalid integer IO%%: must be > 0 and <= %u\n", 100 - pctAcc); + return false; + } + // hole is ok + else if (pctCur > 100) + { + fprintf(stderr, "Invalid IO%% %u: must be >= 0 and <= %u\n", pctCur, 100 - pctAcc); + return false; + } + + // Expect separator + if (*arg++ != '/') + { + fprintf(stderr, "Expected / separator after %u\n", pctCur); + return false; + } + + // Consume Target%/Absolute range integer + if (dType == DistributionType::Percent) + { + // Percent specification + fOk = Util::ParseUInt(arg, targetCur, arg); + if (!fOk) + { + fprintf(stderr, "Invalid integer Target%%: must be > 0 and <= %I64u\n", 100 - targetAcc); + return false; + } + // no hole + else if (targetCur == 0 || targetCur > 100) + { + fprintf(stderr, "Invalid Target%% %I64u: must be > 0 and <= %I64u\n", targetCur, 100 - targetAcc); + return false; + } + } + else + { + // Size specification + fOk = CmdLineParser::_GetSizeInBytes(arg, targetCur, &arg); + if (!fOk) + { + // error already emitted + return fOk; + } + + if (targetCur == 0) + { + fprintf(stderr, "Invalid zero length target range\n"); + return false; + } + } + + // Add range from [accumulator - accumulator + current) => ... + // Note that zero pctCur indicates a hole where no IO is desired - this is recorded + // for fidelity of display/profile but will never match on lookup, as intended. + vOr.emplace_back(pctAcc, pctCur, make_pair(targetAcc, targetCur)); + + // Now move accumulators for the next tuple/completion + pctAcc += pctCur; + targetAcc += targetCur; + + // Expect/consume separator for next tuple? + if (*arg == ':') + { + ++arg; + continue; + } + + // Done? + if (*arg == '\0') + { + break; + } + + fprintf(stderr, "Unexpected characters in specification '%s'\n", arg); + return false; + } + + // Apply to all targets + for (auto& t : vTargets) + { + t.SetDistributionRange(vOr, dType); + } + + return true; +} + +bool CmdLineParser::_ReadParametersFromCmdLine(const int argc, const char *argv[], Profile *pProfile, struct Synchronization *synch, bool& fXMLProfile) +{ + int nParamCnt = argc - 1; + const char** args = argv + 1; + bool fError = false; + + TimeSpan timeSpan; + + // + // Pass 1 - determine parameter set type: cmdline specification or XML, and preparse targets/blocksize + // + + ParseState isXMLSet = ParseState::Unknown; + + ParseState isXMLResultFormat = ParseState::Unknown; + ParseState isProfileOnly = ParseState::Unknown; + ParseState isVerbose = ParseState::Unknown; + ParseState isVerboseStats = ParseState::Unknown; + ParseState isRandomSeed = ParseState::Unknown; + ParseState isWarmupTime = ParseState::Unknown; + ParseState isDurationTime = ParseState::Unknown; + ParseState isCooldownTime = ParseState::Unknown; + ParseState isExperimentFlags = ParseState::Unknown; + + ULONG randomSeedValue = 0; + ULONG warmupTime = 0; + ULONG durationTime = 0; + ULONG cooldownTime = 0; + ULONG experimentFlags = 0; + const char *xmlProfile = nullptr; + + // + // Find all target specifications. Note that this assumes all non-target + // parameters are single tokens; e.g. "-Hsomevalue" and never "-H somevalue". + // Targets follow parameter specifications. + // + + vector vTargets; + for (int i = 0, inTargets = false; i < nParamCnt; ++i) + { + if (!_IsSwitchChar(args[i][0])) + { + inTargets = true; + + Target target; + target.SetPath(args[i]); + vTargets.push_back(target); + } + else if (inTargets) + { + fprintf(stderr, "ERROR: parameters (%s) must come before targets on the command line\n", args[i]); + return false; + } + } + + // + // Find composable and dependent parameters as we resolve the parameter set. + // + + for (int i = 0; i < nParamCnt; ++i) + { + if (_IsSwitchChar(args[i][0])) + { + const char *arg = &args[i][2]; + + switch(args[i][1]) + { + + + case ':': + // Experiment flags + experimentFlags = atoi(arg); + isExperimentFlags = ParseState::True; + break; + + case 'A': /// CrystalDiskMark Process ID + extern DWORD pid; + pid = (DWORD)strtoul(arg + 1, NULL, 10); + break; + + case 'b': + + // Block size does not compose with XML profile spec + if (isXMLSet == ParseState::True) + { + fprintf(stderr, "ERROR: -b is not compatible with -X XML profile specification\n"); + return false; + } + else + { + UINT64 ullBlockSize; + if (_GetSizeInBytes(arg, ullBlockSize, nullptr) && ullBlockSize < MAXUINT32) + { + for (auto &i : vTargets) + { + i.SetBlockSizeInBytes((DWORD)ullBlockSize); + } + } + else + { + fprintf(stderr, "ERROR: invalid block size passed to -b\n"); + return false; + } + _dwBlockSize = (DWORD)ullBlockSize; + + isXMLSet = ParseState::False; + } + break; + + case 'C': + { + int c = atoi(arg); + if (c >= 0) + { + cooldownTime = c; + isCooldownTime = ParseState::True; + } + else + { + fprintf(stderr, "ERROR: invalid cooldown time (-C): '%s'\n", arg); + return false; + } + } + break; + + case 'd': + { + int c = atoi(arg); + if (c >= 0) + { + durationTime = c; + isDurationTime = ParseState::True; + } + else + { + fprintf(stderr, "ERROR: invalid measured duration time (-d): '%s'\n", arg); + return false; + } + } + break; + + case 'W': + { + int c = atoi(arg); + if (c >= 0) + { + warmupTime = c; + isWarmupTime = ParseState::True; + } + else + { + fprintf(stderr, "ERROR: invalid warmup time (-W): '%s'\n", arg); + return false; + } + } + break; + + case 'R': + + // re-output profile only (no run) + if ('p' == *arg) + { + isProfileOnly = ParseState::True; + ++arg; + } + + if ('\0' != *arg) + { + // Explicit results format + if (strcmp(arg, "xml") == 0) + { + isXMLResultFormat = ParseState::True; + } + else if (strcmp(arg, "text") != 0) + { + fprintf(stderr, "ERROR: invalid results format (-R): '%s'\n", arg); + return false; + } + else + { + isXMLResultFormat = ParseState::False; + } + } + else + { + // allow for -Rp shorthand for default profile-only format + if (isProfileOnly != ParseState::True) + { + fprintf(stderr, "ERROR: unspecified results format -R: use [p]\n"); + return false; + } + } + break; + + case 'v': + + if (*arg == '\0') + { + isVerbose = ParseState::True; + } + else if (*arg == 's' && *(arg+1) == '\0') // -vs + { + isVerboseStats = ParseState::True; + } + else + { + fprintf(stderr, "ERROR: invalid verbose mode (-v): '%s'\n", arg); + return false; + } + break; + + case 'X': + + if (isXMLSet == ParseState::Unknown) + { + isXMLSet = ParseState::True; + } + else + { + fprintf(stderr, "ERROR: multiple XML profiles specified (-X)\n"); + return false; + } + xmlProfile = arg; + break; + + case 'z': + { + char *endPtr = nullptr; + + if (*arg == '\0') + { + randomSeedValue = (ULONG) GetTickCount64(); + } + else + { + randomSeedValue = strtoul(arg, &endPtr, 10); + if (*endPtr != '\0') + { + fprintf(stderr, "ERROR: invalid random seed value '%s' specified - must be a valid 32 bit integer\n", arg); + return false; + } + } + + isRandomSeed = ParseState::True; + } + break; + + default: + // no other switches are valid in combination with -X + // if we've seen X, this means it is bad + // if not, we know it will not be X + if (isXMLSet == ParseState::True) + { + fprintf(stderr, "ERROR: invalid XML profile specification; parameter %s not compatible with -X\n", args[i]); + return false; + } + else + { + isXMLSet = ParseState::False; + } + } + } + } + + // XML profile? + if (isXMLSet == ParseState::True) + { + if (!_ReadParametersFromXmlFile(xmlProfile, pProfile, &vTargets)) + { + return false; + } + } + + // + // Apply profile common parameters - note that results format is unmodified if R not explicitly provided + // + + if (isXMLResultFormat == ParseState::True) + { + pProfile->SetResultsFormat(ResultsFormat::Xml); + } + else if (isXMLResultFormat == ParseState::False) + { + pProfile->SetResultsFormat(ResultsFormat::Text); + } + + if (isProfileOnly == ParseState::True) + { + pProfile->SetProfileOnly(true); + } + + if (isVerbose == ParseState::True) + { + pProfile->SetVerbose(true); + } + + if (isVerboseStats == ParseState::True) + { + pProfile->SetVerboseStats(true); + } + + if (isExperimentFlags == ParseState::True) + { + g_ExperimentFlags = experimentFlags; + } + + // + // Apply timespan common composable parameters + // + + if (isXMLSet == ParseState::True) + { + for (auto& ts : const_cast &>(pProfile->GetTimeSpans())) + { + if (isRandomSeed == ParseState::True) { ts.SetRandSeed(randomSeedValue); } + if (isWarmupTime == ParseState::True) { ts.SetWarmup(warmupTime); } + if (isDurationTime == ParseState::True) { ts.SetDuration(durationTime); } + if (isCooldownTime == ParseState::True) { ts.SetCooldown(cooldownTime); } + } + } + else + { + if (isRandomSeed == ParseState::True) { timeSpan.SetRandSeed(randomSeedValue); } + if (isWarmupTime == ParseState::True) { timeSpan.SetWarmup(warmupTime); } + if (isDurationTime == ParseState::True) { timeSpan.SetDuration(durationTime); } + if (isCooldownTime == ParseState::True) { timeSpan.SetCooldown(cooldownTime); } + } + + // Now done if XML profile + if (isXMLSet == ParseState::True) + { + fXMLProfile = true; + return true; + } + + // + // Parse full command line for profile + // + + // initial parse for cache/writethrough + // these are built up across the entire cmd line and applied at the end. + // this allows for conflicts to be thrown for mixed -h/-S as needed. + TargetCacheMode t = TargetCacheMode::Undefined; + WriteThroughMode w = WriteThroughMode::Undefined; + MemoryMappedIoMode m = MemoryMappedIoMode::Undefined; + MemoryMappedIoFlushMode f = MemoryMappedIoFlushMode::Undefined; + + // seen base/max target offset specification yet? + ParseState isMaxTargetOffset = ParseState::Unknown; + ParseState isBaseTargetOffset = ParseState::Unknown; + + bool bExit = false; + while (nParamCnt) + { + const char* arg = *args; + const char* const carg = arg; // save for error reporting, arg is modified during parse + + // Targets follow parameters on command line. If this is a target, we are done now. + if (!_IsSwitchChar(*arg)) + { + break; + } + + // skip switch character, provide length + ++arg; + const size_t argLen = strlen(arg); + + switch (*arg) + { + case '?': + _DisplayUsageInfo(argv[0]); + exit(0); + + case ':': // experiment flags + // handled during composable parameter evaluation + break; + + case 'A': /// CrystalDiskMark Process ID + extern DWORD pid; + pid = (DWORD)strtoul(arg + 1, NULL, 10); + break; + + case 'a': // affinity + //-a1,2,3,4 (assign threads to cpus 1,2,3,4 (round robin)) + if (!_ParseAffinity(arg, &timeSpan)) + { + fError = true; + } + break; + + case 'b': //block size + // handled during composable parameter evaluation + break; + + case 'B': //base target offset (offset from 0) and optional length + if (*(arg + 1) != '\0') + { + UINT64 base; + UINT64 len; + const char *rest; + + if (isBaseTargetOffset == ParseState::True) + { + fprintf(stderr, "ERROR: base target offset (-Bbase[:length]) can only be specified once\n"); + fError = true; + break; + } + + if (_GetSizeInBytes(arg + 1, base, &rest)) + { + for (auto &i : vTargets) + { + i.SetBaseFileOffsetInBytes(base); + } + + isBaseTargetOffset = ParseState::True; + } + else + { + fprintf(stderr, "ERROR: invalid base target offset passed to -B\n"); + fError = true; + break; + } + + if (rest && *rest != '\0') + { + if (*rest != ':') + { + fprintf(stderr, "ERROR: unexpected characters after -Bbase; use \':\' to separate -Bbase:length\n"); + fError = true; + break; + } + + if (*(++rest) == '\0') + { + fprintf(stderr, "ERROR: -Bbase:length - no length provided\n"); + fError = true; + break; + } + + if (isMaxTargetOffset == ParseState::True) + { + fprintf(stderr, "ERROR: maximum target offset (-Bbase:length or -fsize) can only be specified once\n"); + fError = true; + break; + } + + if (!_GetSizeInBytes(rest, len, nullptr) || base + len < base) + { + fprintf(stderr, "ERROR: invalid target length passed to -B\n"); + fError = true; + break; + } + + for (auto &i : vTargets) + { + i.SetMaxFileSize(base + len); + } + + isMaxTargetOffset = ParseState::True; + } + } + else + { + fError = true; + } + break; + + case 'c': //create file of the given size + if (*(arg + 1) != '\0') + { + UINT64 cb; + if (_GetSizeInBytes(arg + 1, cb, nullptr)) + { + for (auto &i : vTargets) + { + i.SetFileSize(cb); + i.SetCreateFile(true); + } + } + else + { + fprintf(stderr, "ERROR: invalid target size passed to -c\n"); + fError = true; + } + } + else + { + fError = true; + } + break; + + case 'C': //cool down time + // handled during composable parameter evaluation + break; + + case 'd': //duration + // handled during composable parameter evaluation + break; + + case 'D': //standard deviation + { + timeSpan.SetCalculateIopsStdDev(true); + + int x = atoi(arg + 1); + if (x > 0) + { + timeSpan.SetIoBucketDurationInMilliseconds(x); + } + } + break; + + case 'e': //etw + if (!_ParseETWParameter(arg, pProfile)) + { + fError = true; + } + break; + + case 'f': + if ('\0' == *(arg + 1)) + { + fError = true; + break; + } + + // max target offset form? + if (isdigit(*(arg + 1))) + { + UINT64 cb; + + if (isMaxTargetOffset == ParseState::True) + { + fprintf(stderr, "ERROR: maximum target offset (-Bbase:length or -fsize) can only be specified once\n"); + fError = true; + break; + } + + if (!_GetSizeInBytes(arg + 1, cb, nullptr)) + { + fprintf(stderr, "ERROR: invalid max target size passed to -f\n"); + fError = true; + break; + } + + for (auto &i : vTargets) + { + i.SetMaxFileSize(cb); + } + + isMaxTargetOffset = ParseState::True; + break; + } + + // while -frs (or -fsr) are generally conflicting intentions as far as + // the OS is concerned, do not enforce + while (*(++arg) != '\0') + { + switch (*arg) + { + case 'r': + for (auto &i : vTargets) + { + i.SetRandomAccessHint(true); + } + break; + case 's': + for (auto &i : vTargets) + { + i.SetSequentialScanHint(true); + } + break; + case 't': + for (auto &i : vTargets) + { + i.SetTemporaryFileHint(true); + } + break; + default: + fError = true; + break; + } + } + break; + + case 'F': //total number of threads + { + int c = atoi(arg + 1); + if (c > 0) + { + timeSpan.SetThreadCount(c); + } + else + { + fError = true; + } + } + break; + + case 'g': //throughput in bytes per millisecond (gNNN) OR iops (gNNNi) + { + // units? + bool isBpms = false; + if (isdigit(arg[argLen - 1])) + { + isBpms = true; + } + else if (arg[argLen - 1] != 'i') + { + // not IOPS, so its bad + fError = true; + } + + if (!fError) + { + int c = atoi(arg + 1); + if (c > 0) + { + for (auto &i : vTargets) + { + if (isBpms) + { + i.SetThroughput(c); + } + else + { + i.SetThroughputIOPS(c); + } + } + } + else + { + fError = true; + } + } + } + break; + + case 'h': // compat: disable os cache and set writethrough; now equivalent to -Sh + if (t == TargetCacheMode::Undefined && + w == WriteThroughMode::Undefined) + { + t = TargetCacheMode::DisableOSCache; + w = WriteThroughMode::On; + } + else + { + fprintf(stderr, "ERROR: -h conflicts with earlier specification of cache/writethrough\n"); + fError = true; + } + break; + + case 'i': //number of IOs to issue before think time + { + int c = atoi(arg + 1); + if (c > 0) + { + for (auto &i : vTargets) + { + i.SetBurstSize(c); + i.SetUseBurstSize(true); + } + } + else + { + fError = true; + } + } + break; + + case 'j': //time to wait between bursts of IOs + { + int c = atoi(arg + 1); + if (c > 0) + { + for (auto &i : vTargets) + { + i.SetThinkTime(c); + i.SetEnableThinkTime(true); + } + } + else + { + fError = true; + } + } + break; + + case 'I': //io priority + { + int x = atoi(arg + 1); + if (x > 0 && x < 4) + { + PRIORITY_HINT hint[] = { IoPriorityHintVeryLow, IoPriorityHintLow, IoPriorityHintNormal }; + for (auto &i : vTargets) + { + i.SetIOPriorityHint(hint[x - 1]); + } + } + else + { + fError = true; + } + } + break; + + case 'l': //large pages + for (auto &i : vTargets) + { + i.SetUseLargePages(true); + } + break; + + case 'L': //measure latency + timeSpan.SetMeasureLatency(true); + break; + + case 'n': //disable affinity (by default simple affinity is turned on) + timeSpan.SetDisableAffinity(true); + break; + + case 'N': + if (!_ParseFlushParameter(arg, &f)) + { + fError = true; + } + break; + + case 'o': //request count (1==synchronous) + { + int c = atoi(arg + 1); + if (c > 0) + { + for (auto &i : vTargets) + { + i.SetRequestCount(c); + } + } + else + { + fError = true; + } + } + break; + + case 'O': //total number of IOs/thread - for use with -F + { + int c = atoi(arg + 1); + if (c > 0) + { + timeSpan.SetRequestCount(c); + } + else + { + fError = true; + } + } + break; + + case 'p': //start async IO operations with the same offset + //makes sense only for -o2 and greater + for (auto &i : vTargets) + { + i.SetUseParallelAsyncIO(true); + } + break; + + case 'P': //show progress every x IO operations + { + int c = atoi(arg + 1); + if (c < 1) + { + c = 65536; + } + pProfile->SetProgress(c); + } + break; + + case 'r': //random access + { + // mixed random/sequential pct split? + if (*(arg + 1) == 's') + { + int c = 0; + + ++arg; + if (*(arg + 1) == '\0') + { + fprintf(stderr, "ERROR: no random percentage passed to -rs\n"); + fError = true; + } + else + { + c = atoi(arg + 1); + if (c <= 0 || c > 100) + { + fprintf(stderr, "ERROR: random percentage passed to -rs should be between 1 and 100\n"); + fError = true; + } + } + if (!fError) + { + for (auto &i : vTargets) + { + // if random ratio is unset and actual alignment is already specified, + // -s was used: don't allow this for clarity of intent + if (!i.GetRandomRatio() && + i.GetBlockAlignmentInBytes(true)) + { + fprintf(stderr, "ERROR: use -r to specify IO alignment when using mixed random/sequential IO (-rs)\n"); + fError = true; + break; + } + // if random ratio was already set to something other than 100% (-r) + // then -rs was specified multiple times: catch and block this + if (i.GetRandomRatio() && + i.GetRandomRatio() != 100) + { + fprintf(stderr, "ERROR: mixed random/sequential IO (-rs) specified multiple times\n"); + fError = true; + break; + } + // Note that -rs100 is the same as -r. It will not result in the element + // in the XML profile; we will still only emit/accept 1-99 there. + // + // Saying -rs0 (sequential) would create an ambiguity between that and -r[nnn]. Rather + // than bend the intepretation of -r[nnn] for the special case of -rs0 we will error + // it out in the bounds check above. + i.SetRandomRatio(c); + } + } + } + + // random distribution + + else if (*(arg + 1) == 'd') + { + // advance past the d + arg += 2; + + fError = !_ParseRandomDistribution(arg, vTargets); + } + + // random block alignment + // if mixed random/sequential not already specified, set to 100% + else + { + + UINT64 cb = _dwBlockSize; + if (*(arg + 1) != '\0') + { + if (!_GetSizeInBytes(arg + 1, cb, nullptr) || (cb == 0)) + { + fprintf(stderr, "ERROR: invalid alignment passed to -r\n"); + fError = true; + } + } + if (!fError) + { + for (auto &i : vTargets) + { + // Do not override -rs specification + if (!i.GetRandomRatio()) + { + i.SetRandomRatio(100); + } + // Multiple -rNN? + // Note that -rs100 -r[NN] will pass since -rs does not set alignment. + // We are only validating a single -rNN specification. + else if (i.GetRandomRatio() == 100 && + i.GetBlockAlignmentInBytes(true)) + { + fprintf(stderr, "ERROR: random IO (-r) specified multiple times\n"); + fError = true; + break; + } + // -s already set the alignment? + if (i.GetBlockAlignmentInBytes(true)) + { + fprintf(stderr, "ERROR: sequential IO (-s) conflicts with random IO (-r/-rs)\n"); + fError = true; + break; + } + i.SetBlockAlignmentInBytes(cb); + } + } + } + } + break; + + case 'R': // output profile/results format engine + // handled during composable parameter evaluation + break; + + case 's': //stride size + { + int idx = 1; + + if ('i' == *(arg + idx)) + { + // do interlocked sequential mode + // ISSUE-REVIEW: this does nothing if -r is specified + // ISSUE-REVIEW: this does nothing if -p is specified + // ISSUE-REVIEW: this does nothing if we are single-threaded + for (auto &i : vTargets) + { + i.SetUseInterlockedSequential(true); + } + + idx++; + } + + for (auto &i : vTargets) + { + // conflict -s with -rs/-s + if (i.GetRandomRatio()) + { + if (i.GetRandomRatio() == 100) { + fprintf(stderr, "ERROR: sequential IO (-s) conflicts with random IO (-r/-rs)\n"); + } + else + { + fprintf(stderr, "ERROR: use -r to specify IO alignment for -rs\n"); + } + fError = true; + break; + } + + // conflict with multiple -s + if (i.GetBlockAlignmentInBytes(true)) + { + fprintf(stderr, "ERROR: sequential IO (-s) specified multiple times\n"); + fError = true; + break; + } + } + + if (*(arg + idx) != '\0') + { + UINT64 cb; + // Note that we allow -s0, as unusual as that would be. + // The counter-case of -r0 is invalid and checked for. + if (_GetSizeInBytes(arg + idx, cb, nullptr)) + { + for (auto &i : vTargets) + { + i.SetBlockAlignmentInBytes(cb); + } + } + else + { + fprintf(stderr, "ERROR: invalid stride size passed to -s\n"); + fError = true; + } + } + else + { + // explicitly pass through the block size so that we can detect + // -rs/-s intent conflicts when attempting to set -rs + for (auto &i : vTargets) + { + i.SetBlockAlignmentInBytes(i.GetBlockSizeInBytes()); + } + } + } + break; + + case 'S': //control os/hw/remote caching and writethrough + { + // parse flags - it is an error to multiply specify either property, which + // can be detected simply by checking if we move one from !undefined. + // this also handles conflict cases. + int idx; + for (idx = 1; !fError && *(arg + idx) != '\0'; idx++) + { + switch (*(arg + idx)) + { + case 'b': + if (t == TargetCacheMode::Undefined) + { + t = TargetCacheMode::Cached; + } + else + { + fprintf(stderr, "ERROR: -Sb conflicts with earlier specification of cache mode\n"); + fError = true; + } + break; + case 'h': + if (t == TargetCacheMode::Undefined && + w == WriteThroughMode::Undefined && + m == MemoryMappedIoMode::Undefined) + { + t = TargetCacheMode::DisableOSCache; + w = WriteThroughMode::On; + } + else + { + fprintf(stderr, "ERROR: -Sh conflicts with earlier specification of cache/writethrough/memory mapped\n"); + fError = true; + } + break; + case 'm': + if (m == MemoryMappedIoMode::Undefined && + t != TargetCacheMode::DisableOSCache) + { + m = MemoryMappedIoMode::On; + } + else + { + fprintf(stderr, "ERROR: -Sm conflicts with earlier specification of memory mapped IO/unbuffered IO\n"); + fError = true; + } + break; + case 'r': + if (t == TargetCacheMode::Undefined) + { + t = TargetCacheMode::DisableLocalCache; + } + else + { + fprintf(stderr, "ERROR: -Sr conflicts with earlier specification of cache mode\n"); + fError = true; + } + break; + case 'u': + if (t == TargetCacheMode::Undefined && + m == MemoryMappedIoMode::Undefined) + { + t = TargetCacheMode::DisableOSCache; + } + else + { + fprintf(stderr, "ERROR: -Su conflicts with earlier specification of cache mode/memory mapped IO\n"); + fError = true; + } + break; + case 'w': + if (w == WriteThroughMode::Undefined) + { + w = WriteThroughMode::On; + } + else + { + fprintf(stderr, "ERROR -Sw conflicts with earlier specification of write through\n"); + fError = true; + } + break; + default: + fprintf(stderr, "ERROR: unrecognized option provided to -S\n"); + fError = true; + break; + } + } + + // bare -S, parse loop did not advance + if (!fError && idx == 1) + { + if (t == TargetCacheMode::Undefined && + m == MemoryMappedIoMode::Undefined) + { + t = TargetCacheMode::DisableOSCache; + } + else + { + fprintf(stderr, "ERROR: -S conflicts with earlier specification of cache mode\n"); + fError = true; + } + } + } + break; + + case 't': //number of threads per file + { + int c = atoi(arg + 1); + if (c > 0) + { + for (auto &i : vTargets) + { + i.SetThreadsPerFile(c); + } + } + else + { + fError = true; + } + } + break; + + case 'T': //offsets between threads reading the same file + { + UINT64 cb; + if (_GetSizeInBytes(arg + 1, cb, nullptr) && (cb > 0)) + { + for (auto &i : vTargets) + { + i.SetThreadStrideInBytes(cb); + } + } + else + { + fprintf(stderr, "ERROR: invalid offset passed to -T\n"); + fError = true; + } + } + break; + + case 'v': //verbose mode + // handled during composable parameter evaluation + break; + + case 'w': //write test [default=read] + { + int c = 0; + + if (*(arg + 1) == '\0') + { + fprintf(stderr, "ERROR: no write ratio passed to -w\n"); + fError = true; + } + else + { + c = atoi(arg + 1); + if (c < 0 || c > 100) + { + fprintf(stderr, "ERROR: write ratio passed to -w must be between 0 and 100 (percent)\n"); + fError = true; + } + } + if (!fError) + { + for (auto &i : vTargets) + { + i.SetWriteRatio(c); + } + } + } + break; + + case 'W': //warm up time + // handled during composable parameter evaluation + break; + + case 'x': //completion routines + timeSpan.SetCompletionRoutines(true); + break; + + case 'y': //external synchronization + switch (*(arg + 1)) + { + + case 's': + _hEventStarted = CreateEvent(NULL, TRUE, FALSE, arg + 2); + if (NULL == _hEventStarted) + { + fprintf(stderr, "Error creating/opening start notification event: '%s'\n", arg + 2); + exit(1); // TODO: this class shouldn't terminate the process + } + break; + + case 'f': + _hEventFinished = CreateEvent(NULL, TRUE, FALSE, arg + 2); + if (NULL == _hEventFinished) + { + fprintf(stderr, "Error creating/opening finish notification event: '%s'\n", arg + 2); + exit(1); // TODO: this class shouldn't terminate the process + } + break; + + case 'r': + synch->hStartEvent = CreateEvent(NULL, TRUE, FALSE, arg + 2); + if (NULL == synch->hStartEvent) + { + fprintf(stderr, "Error creating/opening wait-for-start event: '%s'\n", arg + 2); + exit(1); // TODO: this class shouldn't terminate the process + } + break; + + case 'p': + synch->hStopEvent = CreateEvent(NULL, TRUE, FALSE, arg + 2); + if (NULL == synch->hStopEvent) + { + fprintf(stderr, "Error creating/opening force-stop event: '%s'\n", arg + 2); + exit(1); // TODO: this class shouldn't terminate the process + } + break; + + case 'e': + { + HANDLE hEvent = OpenEvent(EVENT_MODIFY_STATE, FALSE, arg + 2); + if (NULL == hEvent) + { + fprintf(stderr, "Error opening event '%s'\n", arg + 2); + exit(1); // TODO: this class shouldn't terminate the process + } + if (!SetEvent(hEvent)) + { + fprintf(stderr, "Error setting event '%s'\n", arg + 2); + exit(1); // TODO: this class shouldn't terminate the process + } + CloseHandle(hEvent); + printf("Succesfully set event: '%s'\n", arg + 2); + bExit = true; + break; + } + + default: + fError = true; + } + + case 'z': //random seed + // handled during composable parameter evaluation + break; + + case 'Z': //zero write buffers + if (*(arg + 1) == '\0') + { + for (auto &i : vTargets) + { + i.SetZeroWriteBuffers(true); + } + } + else if (*(arg + 1) == 'r' && *(arg + 2) == '\0') + { + timeSpan.SetRandomWriteData(true); + } + else + { + UINT64 cb = 0; + string sPath; + if (_GetRandomDataWriteBufferData(string(arg + 1), cb, sPath) && (cb > 0)) + { + for (auto &i : vTargets) + { + i.SetRandomDataWriteBufferSize(cb); + i.SetRandomDataWriteBufferSourcePath(sPath); + } + } + else + { + fprintf(stderr, "ERROR: invalid size passed to -Z\n"); + fError = true; + } + } + break; + + default: + fprintf(stderr, "ERROR: invalid option: '%s'\n", carg); + return false; + } + + if (fError) + { + // note: original pointer to the cmdline argument, without parse movement + fprintf(stderr, "ERROR: incorrectly provided option: '%s'\n", carg); + return false; + } + + --nParamCnt; + ++args; + } + + // + // exit if a user specified an action which was already satisfied and doesn't require running test + // + if (bExit) + { + printf("Now exiting...\n"); + exit(1); // TODO: this class shouldn't terminate the process + } + + if (vTargets.size() < 1) + { + fprintf(stderr, "ERROR: need to provide at least one filename\n"); + return false; + } + + // apply resultant cache/writethrough/memory mapped io modes to the targets + for (auto &i : vTargets) + { + if (t != TargetCacheMode::Undefined) + { + i.SetCacheMode(t); + } + if (w != WriteThroughMode::Undefined) + { + i.SetWriteThroughMode(w); + } + if (m != MemoryMappedIoMode::Undefined) + { + i.SetMemoryMappedIoMode(m); + } + if (f != MemoryMappedIoFlushMode::Undefined) + { + i.SetMemoryMappedIoFlushMode(f); + } + } + + // ... and apply targets to the timespan + for (auto &i : vTargets) + { + timeSpan.AddTarget(i); + } + pProfile->AddTimeSpan(timeSpan); + + return true; +} + +bool CmdLineParser::_ReadParametersFromXmlFile(const char *pszPath, Profile *pProfile, vector *pvSubstTargets) +{ + XmlProfileParser parser; + + return parser.ParseFile(pszPath, pProfile, pvSubstTargets, NULL); +} + +bool CmdLineParser::ParseCmdLine(const int argc, const char *argv[], Profile *pProfile, struct Synchronization *synch, SystemInformation *pSystem) +{ + assert(nullptr != argv); + assert(nullptr != pProfile); + assert(NULL != synch); + + if (argc < 2) + { + _DisplayUsageInfo(argv[0]); + return false; + } + + string sCmdLine; + for (int i = 0; i < argc - 1; i++) + { + sCmdLine += argv[i]; + sCmdLine += ' '; + } + if (argc > 0) + { + sCmdLine += argv[argc - 1]; + } + pProfile->SetCmdLine(sCmdLine); + + bool fOk = true; + bool fXMLProfile = false; + + fOk = _ReadParametersFromCmdLine(argc, argv, pProfile, synch, fXMLProfile); + + // Check additional restrictions and conditions on the parsed profile. + // Note that on the current cmdline, all targets receive the same parameters + // so their mutual consistency only needs to be checked once. Do not check + // system consistency in profile-only operation (this is only required at + // execution time). + + if (fOk) + { + fOk = pProfile->Validate(!fXMLProfile, pProfile->GetProfileOnly() ? nullptr : pSystem); + } + + return fOk; +} diff --git a/CristalDiskMark/source/diskspd22/CmdRequestCreator/CmdRequestCreator.cpp b/CristalDiskMark/source/diskspd22/CmdRequestCreator/CmdRequestCreator.cpp new file mode 100644 index 0000000..96eaac6 --- /dev/null +++ b/CristalDiskMark/source/diskspd22/CmdRequestCreator/CmdRequestCreator.cpp @@ -0,0 +1,230 @@ +/* + +DISKSPD + +Copyright(c) Microsoft Corporation +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +// CmdRequestCreator.cpp : Defines the entry point for the console application. +// + +#include "CmdRequestCreator.h" +#include +#include +#include +#include "common.h" +#include "errors.h" +#include "CmdLineParser.h" +#include "XmlProfileParser.h" +#include "IORequestGenerator.h" +#include "ResultParser.h" +#include "XmlResultParser.h" + +/*****************************************************************************/ +// global variables +static HANDLE g_hAbortEvent = NULL; // handle to the 'abort' event + // it allows stopping I/O Request Generator in the middle of its work + // the results of its work will be passed to the Results Parser +static HANDLE g_hEventStarted = NULL; // event signalled to notify that the actual (measured) test is to be started +static HANDLE g_hEventFinished = NULL; // event signalled to notify that the actual test has finished + +/*****************************************************************************/ +BOOL WINAPI ctrlCRoutine(DWORD dwCtrlType) +{ + if( CTRL_C_EVENT == dwCtrlType ) + { + printf("\n*** Interrupted by Ctrl-C. Stopping I/O Request Generator. ***\n"); + if( !SetEvent(g_hAbortEvent) ) + { + fprintf(stderr, "Warning: Setting abort event failed (error code: %u)\n", GetLastError()); + } + SetConsoleCtrlHandler(ctrlCRoutine, FALSE); + + //indicate that the signal has been handled + return TRUE; + } + else + { + return FALSE; + } +} + +/*****************************************************************************/ +void TestStarted() +{ + if( (NULL != g_hEventStarted) && !SetEvent(g_hEventStarted) ) + { + fprintf(stderr, "Warning: Setting test start notification event failed (error code: %u)\n", GetLastError()); + } +} + +/*****************************************************************************/ +void TestFinished() +{ + if( (NULL != g_hEventFinished) && !SetEvent(g_hEventFinished) ) + { + fprintf(stderr, "Warning: Setting test finish notification event failed (error code: %u)\n", GetLastError()); + } +} + +/*****************************************************************************/ +/// for CrystalDiskMark +DWORD pid = 0; + +int __cdecl main(int argc, const char* argv[]) +{ + /// for CrystalDiskMark + int totalScore = 0; + double averageLatency = 0.0; + + // + // parse cmd line parameters + // + struct Synchronization synch; //sychronization structure + synch.ulStructSize = sizeof(synch); + synch.hStopEvent = NULL; + synch.hStartEvent = NULL; + + CmdLineParser cmdLineParser; + Profile profile; + if (!cmdLineParser.ParseCmdLine(argc, argv, &profile, &synch, &g_SystemInformation)) + { + return ERROR_PARSE_CMD_LINE; + } + + // Instantiate parsers + ResultParser resultParser; + XmlResultParser xmlResultParser; + IResultParser *pResultParser = nullptr; + if (profile.GetResultsFormat() == ResultsFormat::Xml) + { + pResultParser = &xmlResultParser; + } + else + { + pResultParser = &resultParser; + } + + // Profile only? If so, complete now. + if (profile.GetProfileOnly()) + { + string s = pResultParser->ParseProfile(profile); + printf("%s", s.c_str()); + return 0; + } + + synch.pfnCallbackTestStarted = TestStarted; + synch.pfnCallbackTestFinished = TestFinished; + + // + // create abort event if stop event is not explicitly provided by the user (otherwise use the stop event) + // + + if (NULL == synch.hStopEvent) + { + synch.hStopEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + if( NULL == synch.hStopEvent ) + { + fprintf(stderr, "Unable to create an abort event for CTRL+C\n"); + //FUTURE EXTENSION: change error code + return 1; + } + } + g_hAbortEvent = synch.hStopEvent; // set abort event to either stop event provided by user or the just created event + + // + // capture ctrl+c + // + if( !SetConsoleCtrlHandler(ctrlCRoutine, TRUE) ) + { + fprintf(stderr, "Unable to set CTRL+C routine\n"); + //FUTURE EXTENSION: change error code + return 1; + } + + TraceLoggingRegister(g_hEtwProvider); + + // + // call IO request generator + // + + IORequestGenerator ioGenerator; + /// for CrystalDiskMark + if (!ioGenerator.GenerateRequests(profile, *pResultParser, &synch, &totalScore, &averageLatency)) + // if (!ioGenerator.GenerateRequests(profile, *pResultParser, &synch)) + { + if (profile.GetResultsFormat() == ResultsFormat::Xml) + { + fprintf(stderr, "\n"); + } + + fprintf(stderr, "Error generating I/O requests\n"); + return 1; + } + + TraceLoggingUnregister(g_hEtwProvider); + + if( NULL != synch.hStartEvent ) + { + CloseHandle(synch.hStartEvent); + } + if( NULL != synch.hStopEvent ) + { + CloseHandle(synch.hStopEvent); + } + if( g_hEventStarted ) + { + CloseHandle(g_hEventStarted); + } + if( NULL != g_hEventFinished ) + { + CloseHandle(g_hEventFinished); + } + + /// for CrystalDiskMark + CHAR name[32]; + snprintf(name, 32, "CrystalDiskMark%08X", pid); + auto size = 8; + + HANDLE hSharedMemory = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, NULL, size, name); + if (hSharedMemory != NULL) + { + auto pMemory = (double*)MapViewOfFile(hSharedMemory, FILE_MAP_ALL_ACCESS, NULL, NULL, size); + if (pMemory != NULL) + { + *pMemory = averageLatency; + UnmapViewOfFile(pMemory); + CloseHandle(hSharedMemory); + } + } + printf("Score: %d\n", totalScore); + printf("averageLatency: %f\n", averageLatency); + //fprintf(stderr, "%f", averageLatency); + + return totalScore; + + + // return 0; +} \ No newline at end of file diff --git a/CristalDiskMark/source/diskspd22/CmdRequestCreator/diskspd.rc b/CristalDiskMark/source/diskspd22/CmdRequestCreator/diskspd.rc new file mode 100644 index 0000000..bebe04b --- /dev/null +++ b/CristalDiskMark/source/diskspd22/CmdRequestCreator/diskspd.rc @@ -0,0 +1,19 @@ +#include +#include "Version.h" + +DISKSPD.XSD HTML "..\\XmlProfileParser\\diskspd.xsd" + +#include + +#define VER_FILETYPE VFT_APP +#define VER_FILESUBTYPE VFT2_UNKNOWN +#define VER_FILEDESCRIPTION_STR "DiskSpd Storage Performance Tool" +#define VER_INTERNALNAME_STR "diskspd.exe" + +#undef VER_PRODUCTVERSION +#define VER_PRODUCTVERSION DISKSPD_MAJOR,DISKSPD_MINOR,DISKSPD_BUILD,DISKSPD_QFE + +#undef VER_PRODUCTVERSION_STR +#define VER_PRODUCTVERSION_STR DISKSPD_NUMERIC_VERSION_STRING + +#include "common.ver" diff --git a/CristalDiskMark/source/diskspd22/Common/CmdLineParser.h b/CristalDiskMark/source/diskspd22/Common/CmdLineParser.h new file mode 100644 index 0000000..c1010d7 --- /dev/null +++ b/CristalDiskMark/source/diskspd22/Common/CmdLineParser.h @@ -0,0 +1,73 @@ +/* + +DISKSPD + +Copyright(c) Microsoft Corporation +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#pragma once +#include "Common.h" + +namespace UnitTests { class CmdLineParserUnitTests; } + +class CmdLineParser +{ +public: + CmdLineParser(); + ~CmdLineParser(); + + bool ParseCmdLine(const int argc, const char *argv[], Profile *pProfile, struct Synchronization *synch, SystemInformation *pSystem = nullptr); + +private: + bool _ReadParametersFromCmdLine(const int argc, const char *argv[], Profile *pProfile, struct Synchronization *synch, bool& fXMLProfile); + bool _ReadParametersFromXmlFile(const char *pszPath, Profile *pProfile, vector *pvSubstTargets); + + bool _ParseETWParameter(const char *arg, Profile *pProfile); + bool _ParseFlushParameter(const char *arg, MemoryMappedIoFlushMode *FlushMode ); + bool _ParseAffinity(const char *arg, TimeSpan *pTimeSpan); + bool _ParseRandomDistribution(const char *arg, vector& vTargets); + + void _DisplayUsageInfo(const char *pszFilename) const; + bool _GetSizeInBytes(const char *pszSize, UINT64& ullSize, const char **pszRest) const; + bool _GetRandomDataWriteBufferData(const string& sArg, UINT64& cb, string& sPath); + + static bool _IsSwitchChar(const char c) { return (c == '/' || c == '-'); } + enum class ParseState { + Unknown, + True, + False, + Bad + }; + + DWORD _dwBlockSize; // block size; other parameters may be stated in blocks + // so the block size is needed to process them + + UINT32 _ulWriteRatio; // default percentage of write requests + + HANDLE _hEventStarted; // event signalled to notify that the actual (measured) test is to be started + HANDLE _hEventFinished; // event signalled to notify that the actual test has finished + + friend class UnitTests::CmdLineParserUnitTests; +}; diff --git a/CristalDiskMark/source/diskspd22/Common/CmdRequestCreator.h b/CristalDiskMark/source/diskspd22/Common/CmdRequestCreator.h new file mode 100644 index 0000000..f8d2937 --- /dev/null +++ b/CristalDiskMark/source/diskspd22/Common/CmdRequestCreator.h @@ -0,0 +1,38 @@ +/* + +DISKSPD + +Copyright(c) Microsoft Corporation +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + +#pragma once + +#include +#include \ No newline at end of file diff --git a/CristalDiskMark/source/diskspd22/Common/Common.cpp b/CristalDiskMark/source/diskspd22/Common/Common.cpp new file mode 100644 index 0000000..997d580 --- /dev/null +++ b/CristalDiskMark/source/diskspd22/Common/Common.cpp @@ -0,0 +1,1273 @@ +/* + +DISKSPD + +Copyright(c) Microsoft Corporation +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#include "Common.h" + +TRACELOGGING_DEFINE_PROVIDER(g_hEtwProvider, + "Microsoft-Windows-DiskSpd", // {CA13DB84-D0A9-5145-FCA4-468DA92FDC2D} + (0xca13db84, 0xd0a9, 0x5145, 0xfc, 0xa4, 0x46, 0x8d, 0xa9, 0x2f, 0xdc, 0x2d)); + +SystemInformation g_SystemInformation; +ULONG g_ExperimentFlags; + +UINT64 PerfTimer::GetTime() +{ + LARGE_INTEGER li; + QueryPerformanceCounter(&li); + return li.QuadPart; +} + +UINT64 PerfTimer::_GetPerfTimerFreq() +{ + LARGE_INTEGER li; + QueryPerformanceFrequency(&li); + return li.QuadPart; +} + +const UINT64 PerfTimer::TIMER_FREQ = _GetPerfTimerFreq(); + +double PerfTimer::PerfTimeToMicroseconds(const double perfTime) +{ + return perfTime / (TIMER_FREQ / 1000000.0); +} + +double PerfTimer::PerfTimeToMilliseconds(const double perfTime) +{ + return PerfTimeToMicroseconds(perfTime) / 1000; +} + +double PerfTimer::PerfTimeToSeconds(const double perfTime) +{ + return PerfTimeToMilliseconds(perfTime) / 1000; +} + +double PerfTimer::PerfTimeToMicroseconds(const UINT64 perfTime) +{ + return PerfTimeToMicroseconds(static_cast(perfTime)); +} + +double PerfTimer::PerfTimeToMilliseconds(const UINT64 perfTime) +{ + return PerfTimeToMilliseconds(static_cast(perfTime)); +} + +double PerfTimer::PerfTimeToSeconds(const UINT64 perfTime) +{ + return PerfTimeToSeconds(static_cast(perfTime)); +} + +UINT64 PerfTimer::MicrosecondsToPerfTime(const double microseconds) +{ + return static_cast(TIMER_FREQ * (microseconds / 1000000.0)); +} + +UINT64 PerfTimer::MillisecondsToPerfTime(const double milliseconds) +{ + return static_cast(TIMER_FREQ * (milliseconds / 1000.0)); +} + +UINT64 PerfTimer::SecondsToPerfTime(const double seconds) +{ + return static_cast(TIMER_FREQ * seconds); +} + +Random::Random(UINT64 ulSeed) +{ + UINT32 i; + + _ulState[0] = 0xf1ea5eed; + _ulState[1] = ulSeed; + _ulState[2] = ulSeed; + _ulState[3] = ulSeed; + + for (i = 0; i < 20; i++) { + Rand64(); + } +} + +void Random::RandBuffer(BYTE *pBuffer, UINT32 ulLength, bool fPseudoRandomOkay) +{ + UINT64 *pBuffer64; + UINT32 Remaining = (UINT32)(((ULONG_PTR)pBuffer) & 7); + UINT64 r1, r2, r3, r4, r5; + + // + // Align to 8 bytes + // + + if (Remaining != 0) { + r1 = Rand64(); + + while (Remaining != 0 && ulLength != 0) { + *pBuffer = (BYTE)(r1 & 0xFF); + r1 >>= 8; + pBuffer++; + ulLength--; + Remaining--; + } + } + + pBuffer64 = (UINT64*)pBuffer; + Remaining = ulLength / 8; + ulLength -= Remaining * 8; + pBuffer += Remaining * 8; + + if (fPseudoRandomOkay) { + + // + // Generate 5 random numbers and then mix them to produce + // 16 random (but correlated) numbers. We want to do 16 + // numbers at a time for optimal cache line alignment. + // Only do this if the caller is okay with numbers that + // aren't independent. A detailed analysis of the data + // could probably detect that the first 5 numbers determine + // the next 11. For most purposes this won't matter (for + // instance it's unlikely compression algorithms will be + // able to detect this and utilize it). + // + + while (Remaining > 16) { + r1 = Rand64(); + r2 = Rand64(); + r3 = Rand64(); + r4 = Rand64(); + r5 = Rand64(); + + pBuffer64[0] = r1; + pBuffer64[1] = r2; + pBuffer64[2] = r3; + pBuffer64[3] = r4; + pBuffer64[4] = r5; + + // + // Throw in some rotates so that the below numbers + // aren't the xor sum of previous numbers. + // + + r1 = _rotl64(r1, 7); + pBuffer64[5] = r1 ^ r2; + pBuffer64[6] = r1 ^ r3; + pBuffer64[7] = r1 ^ r4; + pBuffer64[8] = r1 ^ r5; + + r2 = _rotl64(r2, 13); + pBuffer64[9] = r2 ^ r3; + pBuffer64[10] = r2 ^ r4; + pBuffer64[11] = r2 ^ r5; + + r3 = _rotl64(r3, 19); + pBuffer64[12] = r3 ^ r4; + pBuffer64[13] = r3 ^ r5; + + pBuffer64[14] = r1 ^ r2 ^ r3; + pBuffer64[15] = r1 ^ _rotl64(r4 ^ r5, 39); + + pBuffer64 += 16; + Remaining -= 16; + } + } + + // + // Fill in the tail of the buffer + // + + while (Remaining >= 4) { + r1 = Rand64(); + r2 = Rand64(); + r3 = Rand64(); + r4 = Rand64(); + + pBuffer64[0] = r1; + pBuffer64[1] = r2; + pBuffer64[2] = r3; + pBuffer64[3] = r4; + + pBuffer64 += 4; + Remaining -= 4; + } + + while (Remaining != 0) { + *pBuffer64 = Rand64(); + pBuffer64++; + Remaining--; + } + + if (ulLength != 0) { + r1 = Rand64(); + + while (ulLength != 0) { + *pBuffer = (BYTE)(r1 & 0xFF); + r1 >>= 8; + pBuffer++; + ulLength--; + } + } +} + +string Util::DoubleToStringHelper(const double d) +{ + char szFloatBuffer[100]; + sprintf_s(szFloatBuffer, _countof(szFloatBuffer), "%10.3lf", d); + + return string(szFloatBuffer); +} + +string ThreadTarget::GetXml(UINT32 indent) const +{ + char buffer[4096]; + string sXml; + + AddXmlInc(sXml, "\n"); + + sprintf_s(buffer, _countof(buffer), "%u\n", _ulThread); + AddXml(sXml, buffer); + + if (_ulWeight != 0) + { + sprintf_s(buffer, _countof(buffer), "%u\n", _ulWeight); + AddXml(sXml, buffer); + } + + AddXmlDec(sXml, "\n"); + + return sXml; +} + +string Target::GetXml(UINT32 indent) const +{ + char buffer[4096]; + string sXml; + + AddXmlInc(sXml, "\n"); + AddXml(sXml, "" + _sPath + "\n"); + + sprintf_s(buffer, _countof(buffer), "%u\n", _dwBlockSize); + AddXml(sXml, buffer); + + sprintf_s(buffer, _countof(buffer), "%I64u\n", _ullBaseFileOffset); + AddXml(sXml, buffer); + + AddXml(sXml, _fSequentialScanHint ? "true\n" : "false\n"); + AddXml(sXml, _fRandomAccessHint ? "true\n" : "false\n"); + AddXml(sXml, _fTemporaryFileHint ? "true\n" : "false\n"); + AddXml(sXml, _fUseLargePages ? "true\n" : "false\n"); + + // TargetCacheMode::Cached is implied default + switch (_cacheMode) + { + case TargetCacheMode::DisableLocalCache: + AddXml(sXml, "true\n"); + break; + case TargetCacheMode::DisableOSCache: + AddXml(sXml, "true\n"); + break; + } + + // WriteThroughMode::Off is implied default + switch (_writeThroughMode) + { + case WriteThroughMode::On: + AddXml(sXml, "true\n"); + break; + } + + // MemoryMappedIoMode::Off is implied default + switch (_memoryMappedIoMode) + { + case MemoryMappedIoMode::On: + AddXml(sXml, "true\n"); + break; + } + + // MemoryMappedIoFlushMode::Undefined is implied default + switch (_memoryMappedIoFlushMode) + { + case MemoryMappedIoFlushMode::ViewOfFile: + AddXml(sXml, "ViewOfFile\n"); + break; + case MemoryMappedIoFlushMode::NonVolatileMemory: + AddXml(sXml, "NonVolatileMemory\n") + break; + case MemoryMappedIoFlushMode::NonVolatileMemoryNoDrain: + AddXml(sXml, "NonVolatileMemoryNoDrain\n"); + break; + } + + AddXmlInc(sXml, "\n"); + if (_fZeroWriteBuffers) + { + AddXml(sXml, "zero\n"); + } + else if (_cbRandomDataWriteBuffer == 0) + { + AddXml(sXml, "sequential\n"); + } + else + { + AddXml(sXml, "random\n"); + AddXmlInc(sXml, "\n"); + sprintf_s(buffer, _countof(buffer), "%I64u\n", _cbRandomDataWriteBuffer); + AddXml(sXml, buffer); + if (_sRandomDataWriteBufferSourcePath != "") + { + AddXml(sXml, "" + _sRandomDataWriteBufferSourcePath + "\n"); + } + AddXmlDec(sXml, "\n"); + } + AddXmlDec(sXml, "\n"); + + AddXml(sXml, _fParallelAsyncIO ? "true\n" : "false\n"); + + if (_fUseBurstSize) + { + sprintf_s(buffer, _countof(buffer), "%u\n", _dwBurstSize); + AddXml(sXml, buffer); + } + + if (_fThinkTime) + { + sprintf_s(buffer, _countof(buffer), "%u\n", _dwThinkTime); + AddXml(sXml, buffer); + } + + if (_fCreateFile) + { + sprintf_s(buffer, _countof(buffer), "%I64u\n", _ullFileSize); + AddXml(sXml, buffer); + } + + // If XML contains , is ignored + if (_ulRandomRatio > 0) + { + sprintf_s(buffer, _countof(buffer), "%I64u\n", GetBlockAlignmentInBytes()); + AddXml(sXml, buffer); + + // 100% random is alone + if (_ulRandomRatio != 100) + { + sprintf_s(buffer, _countof(buffer), "%u\n", GetRandomRatio()); + AddXml(sXml, buffer); + } + + // Distributions only occur in profiles with random IO. + + if (_vDistributionRange.size()) + { + char *type = nullptr; + + switch (_distributionType) + { + case DistributionType::Absolute: + type = "Absolute"; + break; + + case DistributionType::Percent: + type = "Percent"; + break; + + default: + assert(false); + } + + AddXmlInc(sXml, "\n"); + AddXmlInc(sXml, "<"); + sXml += type; + sXml += ">\n"; + + for (auto r : _vDistributionRange) + { + sprintf_s(buffer, _countof(buffer), "%I64u", r._span, r._dst.second); + AddXml(sXml, buffer); + sXml += "\n"; + } + + AddXmlDec(sXml, "\n"; + AddXmlDec(sXml, "\n"); + } + } + else + { + sprintf_s(buffer, _countof(buffer), "%I64u\n", GetBlockAlignmentInBytes()); + AddXml(sXml, buffer); + + AddXml(sXml, _fInterlockedSequential ? + "true\n" : + "false\n"); + } + + sprintf_s(buffer, _countof(buffer), "%I64u\n", _ullThreadStride); + AddXml(sXml, buffer); + + sprintf_s(buffer, _countof(buffer), "%I64u\n", _ullMaxFileSize); + AddXml(sXml, buffer); + + sprintf_s(buffer, _countof(buffer), "%u\n", _dwRequestCount); + AddXml(sXml, buffer); + + sprintf_s(buffer, _countof(buffer), "%u\n", _ulWriteRatio); + AddXml(sXml, buffer); + + // Preserve specified units + if (_dwThroughputIOPS) + { + sprintf_s(buffer, _countof(buffer), "%u\n", _dwThroughputIOPS); + AddXml(sXml, buffer); + } + else + { + sprintf_s(buffer, _countof(buffer), "%u\n", _dwThroughputBytesPerMillisecond); + AddXml(sXml, buffer); + } + + sprintf_s(buffer, _countof(buffer), "%u\n", _dwThreadsPerFile); + AddXml(sXml, buffer); + + if (_ioPriorityHint == IoPriorityHintVeryLow) + { + AddXml(sXml, "1\n"); + } + else if (_ioPriorityHint == IoPriorityHintLow) + { + AddXml(sXml, "2\n"); + } + else if (_ioPriorityHint == IoPriorityHintNormal) + { + AddXml(sXml, "3\n"); + } + else + { + AddXml(sXml, "* UNSUPPORTED *\n"); + } + + sprintf_s(buffer, _countof(buffer), "%u\n", _ulWeight); + AddXml(sXml, buffer); + + if (_vThreadTargets.size() > 0) + { + AddXmlInc(sXml, "\n"); + + for (const auto& threadTarget : _vThreadTargets) + { + sXml += threadTarget.GetXml(indent); + } + + AddXmlDec(sXml, "\n"); + } + + AddXmlDec(sXml, "\n"); + + return sXml; +} + +bool Target::_FillRandomDataWriteBuffer(Random *pRand) +{ + assert(_pRandomDataWriteBuffer != nullptr); + bool fOk = true; + size_t cb = static_cast(GetRandomDataWriteBufferSize()); + if (GetRandomDataWriteBufferSourcePath() == "") + { + pRand->RandBuffer(_pRandomDataWriteBuffer, (UINT32)cb, false); + } + else + { + // fill buffer from file + HANDLE hFile = CreateFile(GetRandomDataWriteBufferSourcePath().c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, 0, nullptr); + if (hFile != INVALID_HANDLE_VALUE) + { + UINT64 cbLeftToRead = GetRandomDataWriteBufferSize(); + BYTE *pBuffer = _pRandomDataWriteBuffer; + bool fReadSuccess = true; + while (fReadSuccess && cbLeftToRead > 0) + { + DWORD cbToRead = static_cast(min(64 * 1024, cbLeftToRead)); + DWORD cbRead; + fReadSuccess = ((ReadFile(hFile, pBuffer, cbToRead, &cbRead, nullptr) == TRUE) && (cbRead > 0)); + pBuffer += cbRead; + } + + // if the file is smaller than the buffer, repeat its content + BYTE *pSource = _pRandomDataWriteBuffer; + const BYTE *pPastEnd = pSource + GetRandomDataWriteBufferSize(); + while (pBuffer < pPastEnd) + { + *pBuffer++ = *pSource++; + } + CloseHandle(hFile); + } + else + { + printf("\n\nERROR: Unable to open entropy file '%s'\n\n", GetRandomDataWriteBufferSourcePath().c_str()); + fOk = false; + } + } + return fOk; +} + +bool Target::AllocateAndFillRandomDataWriteBuffer(Random *pRand) +{ + assert(_pRandomDataWriteBuffer == nullptr); + bool fOk = false; + size_t cb = static_cast(GetRandomDataWriteBufferSize()); + if (cb < 1) + { + return fOk; + } + + // TODO: make sure the size if <= max value for size_t + if (GetUseLargePages()) + { + size_t cbMinLargePage = GetLargePageMinimum(); + size_t cbRoundedSize = (cb + cbMinLargePage - 1) & ~(cbMinLargePage - 1); + _pRandomDataWriteBuffer = (BYTE *)VirtualAlloc(nullptr, cbRoundedSize, MEM_COMMIT | MEM_RESERVE | MEM_LARGE_PAGES, PAGE_EXECUTE_READWRITE); + } + else + { + _pRandomDataWriteBuffer = (BYTE *)VirtualAlloc(nullptr, cb, MEM_COMMIT, PAGE_READWRITE); + } + + fOk = (_pRandomDataWriteBuffer != nullptr); + if (fOk) + { + fOk = _FillRandomDataWriteBuffer(pRand); + } + return fOk; +} + +void Target::FreeRandomDataWriteBuffer() +{ + if (nullptr != _pRandomDataWriteBuffer) + { + VirtualFree(_pRandomDataWriteBuffer, 0, MEM_RELEASE); + _pRandomDataWriteBuffer = nullptr; + } +} + +BYTE* Target::GetRandomDataWriteBuffer(Random *pRand) +{ + size_t cbBuffer = static_cast(GetRandomDataWriteBufferSize()); + size_t cbBlock = GetBlockSizeInBytes(); + + // leave enough bytes in the buffer for one block + size_t randomOffset = pRand->Rand32() % (cbBuffer - (cbBlock - 1)); + + bool fUnbufferedIO = (_cacheMode == TargetCacheMode::DisableOSCache); + if (fUnbufferedIO) + { + // for unbuffered IO, offset in the buffer needs to be 512-byte aligned + const size_t cbAlignment = 512; + randomOffset -= (randomOffset % cbAlignment); + } + + BYTE *pBuffer = reinterpret_cast(reinterpret_cast(_pRandomDataWriteBuffer)+randomOffset); + + // unbuffered IO needs aligned addresses + assert(!fUnbufferedIO || (reinterpret_cast(pBuffer) % 512 == 0)); + assert(pBuffer >= _pRandomDataWriteBuffer); + assert(pBuffer <= _pRandomDataWriteBuffer + GetRandomDataWriteBufferSize() - GetBlockSizeInBytes()); + + return pBuffer; +} + +string TimeSpan::GetXml(UINT32 indent) const +{ + string sXml; + char buffer[4096]; + + AddXmlInc(sXml, "\n"); + AddXml(sXml, _fCompletionRoutines ? "true\n" : "false\n"); + AddXml(sXml,_fMeasureLatency ? "true\n" : "false\n"); + AddXml(sXml, _fCalculateIopsStdDev ? "true\n" : "false\n"); + AddXml(sXml, _fDisableAffinity ? "true\n" : "false\n"); + + sprintf_s(buffer, _countof(buffer), "%u\n", _ulDuration); + AddXml(sXml, buffer); + + sprintf_s(buffer, _countof(buffer), "%u\n", _ulWarmUp); + AddXml(sXml, buffer); + + sprintf_s(buffer, _countof(buffer), "%u\n", _ulCoolDown); + AddXml(sXml, buffer); + + sprintf_s(buffer, _countof(buffer), "%u\n", _dwThreadCount); + AddXml(sXml, buffer); + + sprintf_s(buffer, _countof(buffer), "%u\n", _dwRequestCount); + AddXml(sXml, buffer); + + sprintf_s(buffer, _countof(buffer), "%u\n", _ulIoBucketDurationInMilliseconds); + AddXml(sXml, buffer); + + sprintf_s(buffer, _countof(buffer), "%u\n", _ulRandSeed); + AddXml(sXml, buffer); + + if (_vAffinity.size() > 0) + { + AddXmlInc(sXml, "\n"); + for (const auto& a : _vAffinity) + { + sprintf_s(buffer, _countof(buffer), "\n", a.wGroup, a.bProc); + AddXml(sXml, buffer); + } + AddXmlDec(sXml, "\n"); + } + + AddXmlInc(sXml, "\n"); + for (const auto& target : _vTargets) + { + sXml += target.GetXml(indent); + } + AddXmlDec(sXml, "\n"); + AddXmlDec(sXml, "\n"); + return sXml; +} + +void TimeSpan::MarkFilesAsPrecreated(const vector vFiles) +{ + for (auto sFile : vFiles) + { + for (auto pTarget = _vTargets.begin(); pTarget != _vTargets.end(); pTarget++) + { + if (sFile == pTarget->GetPath()) + { + pTarget->SetPrecreated(true); + } + } + } +} + +string Profile::GetXml(UINT32 indent) const +{ + string sXml; + char buffer[4096]; + + AddXmlInc(sXml, "\n"); + + sprintf_s(buffer, _countof(buffer), "%u\n", _dwProgress); + AddXml(sXml, buffer); + + if (g_ExperimentFlags) + { + // only output if on so that downlevel doesn't get (and fail: not in downlevel xsd) unless actually specified + sprintf_s(buffer, _countof(buffer), "%u\n", g_ExperimentFlags); + AddXml(sXml, buffer); + } + + if (_resultsFormat == ResultsFormat::Text) + { + AddXml(sXml, "text\n"); + } + else if (_resultsFormat == ResultsFormat::Xml) + { + AddXml(sXml, "xml\n"); + } + else + { + AddXml(sXml, "* UNSUPPORTED *\n"); + } + + AddXml(sXml, _fVerbose ? "true\n" : "false\n"); + if (_fVerboseStats) + { + // only output if on so that downlevel doesn't get (and fail: not in downlevel xsd) unless actually specified + AddXml(sXml, "true\n"); + } + + if (_precreateFiles == PrecreateFiles::UseMaxSize) + { + AddXml(sXml, "UseMaxSize\n"); + } + else if (_precreateFiles == PrecreateFiles::OnlyFilesWithConstantSizes) + { + AddXml(sXml, "CreateOnlyFilesWithConstantSizes\n"); + } + else if (_precreateFiles == PrecreateFiles::OnlyFilesWithConstantOrZeroSizes) + { + AddXml(sXml, "CreateOnlyFilesWithConstantOrZeroSizes\n"); + } + + if (_fEtwEnabled) + { + AddXmlInc(sXml, "\n"); + AddXml(sXml, _fEtwProcess ? "true\n" : "false\n"); + AddXml(sXml, _fEtwThread ? "true\n" : "false\n"); + AddXml(sXml, _fEtwImageLoad ? "true\n" : "false\n"); + AddXml(sXml, _fEtwDiskIO ? "true\n" : "false\n"); + AddXml(sXml, _fEtwMemoryPageFaults ? "true\n" : "false\n"); + AddXml(sXml, _fEtwMemoryHardFaults ? "true\n" : "false\n"); + AddXml(sXml, _fEtwNetwork ? "true\n" : "false\n"); + AddXml(sXml, _fEtwRegistry ? "true\n" : "false\n"); + AddXml(sXml, _fEtwUsePagedMemory ? "true\n" : "false\n"); + AddXml(sXml, _fEtwUsePerfTimer ? "true\n" : "false\n"); + AddXml(sXml, _fEtwUseSystemTimer ? "true\n" : "false\n"); + AddXml(sXml, _fEtwUseCyclesCounter ? "true\n" : "false\n"); + AddXmlDec(sXml, "\n"); + } + + AddXmlInc(sXml, "\n"); + for (const auto& timespan : _vTimeSpans) + { + sXml += timespan.GetXml(indent); + } + AddXmlDec(sXml, "\n"); + AddXmlDec(sXml, "\n"); + return sXml; +} + +void Profile::MarkFilesAsPrecreated(const vector vFiles) +{ + for (auto pTimeSpan = _vTimeSpans.begin(); pTimeSpan != _vTimeSpans.end(); pTimeSpan++) + { + pTimeSpan->MarkFilesAsPrecreated(vFiles); + } +} + +bool Profile::Validate(bool fSingleSpec, SystemInformation *pSystem) const +{ + bool fOk = true; + + if (GetTimeSpans().size() == 0) + { + fprintf(stderr, "ERROR: no timespans specified\n"); + fOk = false; + } + else + { + for (const auto& timeSpan : GetTimeSpans()) + { + if (pSystem != nullptr) + { + for (const auto& Affinity : timeSpan.GetAffinityAssignments()) + { + if (Affinity.wGroup >= pSystem->processorTopology._vProcessorGroupInformation.size()) + { + fprintf(stderr, "ERROR: affinity assignment to group %u; system only has %u groups\n", + Affinity.wGroup, + (int) pSystem->processorTopology._vProcessorGroupInformation.size()); + + fOk = false; + + } + if (fOk && !pSystem->processorTopology._vProcessorGroupInformation[Affinity.wGroup].IsProcessorValid(Affinity.bProc)) + { + fprintf(stderr, "ERROR: affinity assignment to group %u cpu %u not possible; group has a max of %u cpus\n", + Affinity.wGroup, + Affinity.bProc, + pSystem->processorTopology._vProcessorGroupInformation[Affinity.wGroup]._maximumProcessorCount); + + fOk = false; + } + + if (fOk && !pSystem->processorTopology._vProcessorGroupInformation[Affinity.wGroup].IsProcessorActive(Affinity.bProc)) + { + fprintf(stderr, "ERROR: affinity assignment to group %u cpu %u not possible; cpu is not active (current mask 0x%p)\n", + Affinity.wGroup, + Affinity.bProc, + (void *) pSystem->processorTopology._vProcessorGroupInformation[Affinity.wGroup]._activeProcessorMask); + + fOk = false; + } + } + } + + // ISSUE: many of the following validation errors are stated in cmdline terms, which is not helpful for XML + + if (timeSpan.GetDisableAffinity() && timeSpan.GetAffinityAssignments().size() > 0) + { + fprintf(stderr, "ERROR: -n and -a parameters cannot be used together\n"); + fOk = false; + } + + // ISSUE: with XML and the following the target specification validation it would be useful to say what + // target they're for + + for (const auto& target : timeSpan.GetTargets()) + { + const bool targetHasMultipleThreads = (timeSpan.GetThreadCount() > 1) || (target.GetThreadsPerFile() > 1); + + if (timeSpan.GetThreadCount() > 0 && target.GetThreadsPerFile() > 1) + { + fprintf(stderr, "ERROR: -F and -t parameters cannot be used together\n"); + fOk = false; + } + + if (target.GetThroughputInBytesPerMillisecond() > 0 && timeSpan.GetCompletionRoutines()) + { + fprintf(stderr, "ERROR: -g throughput control cannot be used with -x completion routines\n"); + fOk = false; + } + + // If burst size is specified think time must be specified and If think time is specified burst size should be non zero + if ((target.GetThinkTime() == 0 && target.GetBurstSize() > 0) || (target.GetThinkTime() > 0 && target.GetBurstSize() == 0)) + { + fprintf(stderr, "ERROR: need to specify -j with -i\n"); + fOk = false; + } + + if (timeSpan.GetThreadCount() > 0 && timeSpan.GetRequestCount() > 0) + { + if (target.GetThroughputInBytesPerMillisecond() > 0) + { + fprintf(stderr, "ERROR: -g throughput control cannot be used with -O outstanding requests per thread\n"); + fOk = false; + } + + if (target.GetThinkTime() > 0) + { + fprintf(stderr, "ERROR: -j think time cannot be used with -O outstanding requests per thread\n"); + fOk = false; + } + + if (target.GetUseParallelAsyncIO()) + { + fprintf(stderr, "ERROR: -p parallel IO cannot be used with -O outstanding requests per thread\n"); + fOk = false; + } + + if (target.GetWeight() == 0) + { + fprintf(stderr, "ERROR: a non-zero target Weight must be specified\n"); + fOk = false; + } + + for (const auto& threadTarget : target.GetThreadTargets()) + { + if (threadTarget.GetThread() >= timeSpan.GetThreadCount()) + { + fprintf(stderr, "ERROR: illegal thread specified for ThreadTarget\n"); + fOk = false; + } + } + } + else if (target.GetThreadTargets().size() != 0) + { + fprintf(stderr, "ERROR: ThreadTargets can only be specified when the timespan ThreadCount and RequestCount are specified\n"); + fOk = false; + } + + if (target.GetRandomRatio()) + { + if (target.GetThreadStrideInBytes() > 0) + { + fprintf(stderr, "ERROR: -T conflicts with -r\n"); + fOk = false; + // although ullThreadStride==0 is a valid value, it's interpreted as "not provided" for this warning + } + + if (target.GetUseInterlockedSequential()) + { + fprintf(stderr, "ERROR: -si conflicts with -r\n"); + fOk = false; + } + + if (target.GetUseParallelAsyncIO()) + { + fprintf(stderr, "ERROR: -p conflicts with -r\n"); + fOk = false; + } + } + else + { + if (target.GetDistributionRange().size() != 0) + { + fprintf(stderr, "ERROR: random distribution ranges (-rd) do not apply to sequential-only IO patterns\n"); + fOk = false; + } + + if (target.GetUseParallelAsyncIO() && target.GetRequestCount() == 1) + { + fprintf(stderr, "WARNING: -p does not have effect unless outstanding I/O count (-o) is > 1\n"); + } + + if (target.GetUseInterlockedSequential()) + { + if (target.GetThreadStrideInBytes() > 0) + { + fprintf(stderr, "ERROR: -si conflicts with -T\n"); + fOk = false; + } + + if (target.GetUseParallelAsyncIO()) + { + fprintf(stderr, "ERROR: -si conflicts with -p\n"); + fOk = false; + } + + if (!targetHasMultipleThreads) + { + fprintf(stderr, "WARNING: single-threaded test, -si ignored\n"); + } + } + else + { + if (targetHasMultipleThreads && !target.GetThreadStrideInBytes()) + { + fprintf(stderr, "WARNING: target access pattern will not be sequential, consider -si\n"); + } + + if (!targetHasMultipleThreads && target.GetThreadStrideInBytes()) + { + fprintf(stderr, "ERROR: -T has no effect unless multiple threads per target are used\n"); + fOk = false; + } + } + } + + // Distribution ranges are only applied to random loads. Note validation failure in the sequential case. + // TBD this should be moved to a proper Distribution class. + { + UINT32 ioAcc = 0; + UINT64 targetAcc = 0; + bool absZero = false, absZeroLast = false; + for (const auto& r : target.GetDistributionRange()) + { + if (target.GetDistributionType() == DistributionType::Absolute) + { + // allow zero target span in last position + absZeroLast = false; + if (r._dst.second == 0 && !absZero) + { + // legal in last position + absZero = absZeroLast = true; + } + else if (r._dst.second < target.GetBlockSizeInBytes()) + { + fprintf(stderr, "ERROR: invalid random distribution target range %I64u - must be a minimum of the specified block size (%u bytes)\n", r._dst.second, target.GetBlockSizeInBytes()); + fOk = false; + break; + } + } + + // Validate accumulating IO% + if (ioAcc + r._span > 100) + { + fprintf(stderr, "ERROR: invalid random distribution IO%% %u: can be at most %u - total must be <= 100%%\n", r._span, 100 - ioAcc); + fOk = false; + break; + } + + // Validate accumulating Target% + // Note that absolute range needs no additional validation - known nonzero/large enough for IO + if (target.GetDistributionType() == DistributionType::Percent) + { + if (targetAcc + r._dst.second > 100) + { + fprintf(stderr, "ERROR: invalid random distribution Target%% %I64u: can be at most %I64u - total must be <= 100%%\n", r._dst.second, 100 - targetAcc); + fOk = false; + break; + } + + // Consuming the target before consuming the IO is invalid. + // No holes in IO. + if (targetAcc + r._dst.second == 100 && ioAcc + r._span < 100) + { + fprintf(stderr, "ERROR: invalid random distribution: the target is covered with %u%% IO left to distribute\n", 100 - (ioAcc + r._span)); + fOk = false; + break; + } + } + + ioAcc += r._span; + targetAcc += r._dst.second; + } + + // Percent dist Target% must sum to 100%. IO% underflow (either due to early Target% 100% or Target% overflow) is handled above. + if (target.GetDistributionType() == DistributionType::Percent && + targetAcc != 100) + { + fprintf(stderr, "ERROR: invalid random distribution span: Target%% (%I64u%%) must total 100%%\n", targetAcc); + fOk = false; + } + if (absZero && !absZeroLast) + { + fprintf(stderr, "ERROR: invalid zero target range in random distribution - must be a minimum of the specified block size (%u bytes)\n", target.GetBlockSizeInBytes()); + fOk = false; + } + } + + if (target.GetRandomDataWriteBufferSize() > 0) + { + if (target.GetRandomDataWriteBufferSize() < target.GetBlockSizeInBytes()) + { + fprintf(stderr, "ERROR: custom write buffer (-Z) is smaller than the block size. Write buffer size: %I64u block size: %u\n", + target.GetRandomDataWriteBufferSize(), + target.GetBlockSizeInBytes()); + fOk = false; + } + } + + if (target.GetMemoryMappedIoMode() == MemoryMappedIoMode::On) + { + if (timeSpan.GetCompletionRoutines()) + { + fprintf(stderr, "ERROR: completion routines (-x) can't be used with memory mapped IO (-Sm)\n"); + fOk = false; + } + if (target.GetCacheMode() == TargetCacheMode::DisableOSCache) + { + fprintf(stderr, "ERROR: unbuffered IO (-Su or -Sh) can't be used with memory mapped IO (-Sm)\n"); + fOk = false; + } + } + + if (target.GetMemoryMappedIoMode() == MemoryMappedIoMode::Off && + target.GetMemoryMappedIoFlushMode() != MemoryMappedIoFlushMode::Undefined) + { + fprintf(stderr, "ERROR: memory mapped flush mode (-N) can only be specified with memory mapped IO (-Sm)\n"); + fOk = false; + } + + if (GetProfileOnly() == false) + { + auto sPath = target.GetPath(); + + if (sPath[0] == TEMPLATE_TARGET_PREFIX) + { + fprintf(stderr, "ERROR: template target '%s' was not substituted - all template targets must be substituted to run a profile\n", sPath.c_str()); + fOk = false; + } + } + + // Note that this error is only possible with -f or XML. The -Bbase:length form is immune. + if (target.GetMaxFileSize() && target.GetMaxFileSize() <= target.GetBaseFileOffsetInBytes()) + { + fprintf(stderr, "ERROR: maximum (-f) target offset must be greater than base (-B)\n"); + fOk = false; + } + + // If we know there is only a single target specification (the parameters which apply to targets) shared + // across the one or more targets, we can stop. In practical terms this is the command line case - for + // XML we don't know, and do need to keep going. This early exit lets us avoid repeating the same sets + // of error messages per each target we would otherwise loop over. + // + // If we ever did target property validation (say, v. its size) we'd want to divide out the validations + // into parameter-only v. parameter/property cases for similar reasons. + if (fSingleSpec) + { + break; + } + } + } + } + + return fOk; +} + +bool ThreadParameters::AllocateAndFillBufferForTarget(const Target& target) +{ + bool fOk = true; + BYTE *pDataBuffer = nullptr; + DWORD requestCount = target.GetRequestCount(); + size_t cbDataBuffer; + + // Use global request count + if (pTimeSpan->GetThreadCount() != 0 && + pTimeSpan->GetRequestCount() != 0) { + + requestCount = pTimeSpan->GetRequestCount(); + } + + // Create separate read & write buffers so the write content doesn't get overriden by reads + cbDataBuffer = (size_t) target.GetBlockSizeInBytes() * requestCount * 2; + if (target.GetUseLargePages()) + { + size_t cbMinLargePage = GetLargePageMinimum(); + size_t cbRoundedSize = (cbDataBuffer + cbMinLargePage - 1) & ~(cbMinLargePage - 1); + pDataBuffer = (BYTE *)VirtualAlloc(nullptr, cbRoundedSize, MEM_COMMIT | MEM_RESERVE | MEM_LARGE_PAGES, PAGE_EXECUTE_READWRITE); + } + else + { + pDataBuffer = (BYTE *)VirtualAlloc(nullptr, cbDataBuffer, MEM_COMMIT, PAGE_READWRITE); + } + + fOk = (pDataBuffer != nullptr); + + //fill buffer (useful only for write tests) + if (fOk && target.GetWriteRatio() > 0) + { + if (target.GetZeroWriteBuffers()) + { + memset(pDataBuffer, 0, cbDataBuffer); + } + else + { + for (size_t i = 0; i < cbDataBuffer; i++) + { + pDataBuffer[i] = (BYTE)(i % 256); + } + } + } + + if (fOk) + { + vpDataBuffers.push_back(pDataBuffer); + vulReadBufferSize.push_back(cbDataBuffer / 2); + } + + return fOk; +} + +BYTE* ThreadParameters::GetReadBuffer(size_t iTarget, size_t iRequest) +{ + return vpDataBuffers[iTarget] + (iRequest * vTargets[iTarget].GetBlockSizeInBytes()); +} + +BYTE* ThreadParameters::GetWriteBuffer(size_t iTarget, size_t iRequest) +{ + BYTE *pBuffer = nullptr; + + Target& target(vTargets[iTarget]); + size_t cb = static_cast(target.GetRandomDataWriteBufferSize()); + if (cb == 0) + { + pBuffer = vpDataBuffers[iTarget] + vulReadBufferSize[iTarget] + (iRequest * vTargets[iTarget].GetBlockSizeInBytes()); + + // + // This is a very efficient algorithm for generating random content at + // run-time. When tested in a single-threaded, CPU limited environment + // with 4K random writes, doing memset to fill the buffer got 112K IOPS, + // this algorithm got 111K IOPS. Using a static buffer got 118K IOPS. + // This was tested with a 64-bit diskspd.exe. With a 32-bit version it + // may be more efficient to do 32-bit operations. + // + + if (pTimeSpan->GetRandomWriteData() && + !target.GetZeroWriteBuffers()) + { + pRand->RandBuffer(pBuffer, vTargets[iTarget].GetBlockSizeInBytes(), true); + } + } + else + { + pBuffer = target.GetRandomDataWriteBuffer(pRand); + } + return pBuffer; +} + +bool ThreadParameters::InitializeMappedViewForTarget(Target& target, DWORD DesiredAccess) +{ + bool fOk = true; + DWORD dwProtect = PAGE_READWRITE; + + if (DesiredAccess == GENERIC_READ) + { + dwProtect = PAGE_READONLY; + } + + HANDLE hFile = CreateFileMapping(target.GetMappedViewFileHandle(), NULL, dwProtect, 0, 0, NULL); + fOk = (hFile != NULL); + if (fOk) + { + DWORD dwDesiredAccess = FILE_MAP_WRITE; + + if (DesiredAccess == GENERIC_READ) + { + dwDesiredAccess = FILE_MAP_READ; + } + + BYTE *mapView = (BYTE*) MapViewOfFile(hFile, dwDesiredAccess, 0, 0, 0); + fOk = (mapView != NULL); + if (fOk) + { + target.SetMappedView(mapView); + } + else + { + fprintf(stderr, "FATAL ERROR: Could not map view for target '%s'. Error code: 0x%x\n", target.GetPath().c_str(), GetLastError()); + } + } + else + { + fprintf(stderr, "FATAL ERROR: Could not create a file mapping for target '%s'. Error code: 0x%x\n", target.GetPath().c_str(), GetLastError()); + } + return fOk; +} + +DWORD ThreadParameters::GetTotalRequestCount() const +{ + DWORD cRequests = 0; + + for (const auto& t : vTargets) + { + cRequests += t.GetRequestCount(); + } + + if (pTimeSpan->GetRequestCount() != 0 && + pTimeSpan->GetThreadCount() != 0) + { + cRequests = pTimeSpan->GetRequestCount(); + } + + return cRequests; +} + +void EtwResultParser::ParseResults(vector vResults) +{ + if (TraceLoggingProviderEnabled(g_hEtwProvider, + TRACE_LEVEL_NONE, + DISKSPD_TRACE_INFO)) + { + for (size_t ullResults = 0; ullResults < vResults.size(); ullResults++) + { + const Results& results = vResults[ullResults]; + for (size_t ullThread = 0; ullThread < results.vThreadResults.size(); ullThread++) + { + const ThreadResults& threadResults = results.vThreadResults[ullThread]; + for (const auto& targetResults : threadResults.vTargetResults) + { + if (targetResults.ullReadIOCount) + { + _WriteResults(IOOperation::ReadIO, targetResults, ullThread); + } + if (targetResults.ullWriteIOCount) + { + _WriteResults(IOOperation::WriteIO, targetResults, ullThread); + } + } + } + } + } +} + +void EtwResultParser::_WriteResults(IOOperation type, const TargetResults& targetResults, size_t ullThread) +{ + UINT64 ullIOCount = (type == IOOperation::ReadIO) ? targetResults.ullReadIOCount : targetResults.ullWriteIOCount; + UINT64 ullBytesCount = (type == IOOperation::ReadIO) ? targetResults.ullReadBytesCount : targetResults.ullWriteBytesCount; + + TraceLoggingWrite(g_hEtwProvider, + "Statistics", + TraceLoggingLevel((TRACE_LEVEL_NONE)), + TraceLoggingString((type == IOOperation::ReadIO) ? "Read" : "Write", "IO Type"), + TraceLoggingUInt64(ullThread, "Thread"), + TraceLoggingUInt64(ullBytesCount, "Bytes"), + TraceLoggingUInt64(ullIOCount, "IO Count"), + TraceLoggingString(targetResults.sPath.c_str(), "Path"), + TraceLoggingUInt64(targetResults.ullFileSize, "File Size")); +} diff --git a/CristalDiskMark/source/diskspd22/Common/Common.h b/CristalDiskMark/source/diskspd22/Common/Common.h new file mode 100644 index 0000000..ebd9487 --- /dev/null +++ b/CristalDiskMark/source/diskspd22/Common/Common.h @@ -0,0 +1,2695 @@ +/* + +DISKSPD + +Copyright(c) Microsoft Corporation +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include //ntdll.dll +#include +#include "Histogram.h" +#include "IoBucketizer.h" +#include "ThroughputMeter.h" +#include "Version.h" + +using namespace std; + +TRACELOGGING_DECLARE_PROVIDER(g_hEtwProvider); + +#define DISKSPD_TRACE_INFO 0x00000000 +#define DISKSPD_TRACE_RESERVED 0x00000001 +#define DISKSPD_TRACE_IO 0x00000100 + +typedef void (WINAPI *PRINTF)(const char*, va_list); //function used for displaying formatted data (printf style) + +#define ROUND_DOWN(_x,_alignment) \ + ( ((_x)/(_alignment)) * (_alignment) ) + +#define ROUND_UP(_x,_alignment) \ + ROUND_DOWN((_x) + (_alignment) - 1, (_alignment)) + +#define TB (((UINT64)1)<<40) +#define GB (((UINT64)1)<<30) +#define MB (((UINT64)1)<<20) +#define KB (((UINT64)1)<<10) + +#define EXPERIMENT_TPUT_CALC 0x1 // precise ms sleep calculation for low rate throughput control +extern ULONG g_ExperimentFlags; + +struct ETWEventCounters +{ + UINT64 ullIORead; // Read + UINT64 ullIOWrite; // Write + UINT64 ullMMTransitionFault; // Transition fault + UINT64 ullMMDemandZeroFault; // Demand Zero fault + UINT64 ullMMCopyOnWrite; // Copy on Write + UINT64 ullMMGuardPageFault; // Guard Page fault + UINT64 ullMMHardPageFault; // Hard page fault + UINT64 ullNetTcpSend; // Send + UINT64 ullNetTcpReceive; // Receive + UINT64 ullNetUdpSend; // Send + UINT64 ullNetUdpReceive; // Receive + UINT64 ullNetConnect; // Connect + UINT64 ullNetDisconnect; // Disconnect + UINT64 ullNetRetransmit; // ReTransmit + UINT64 ullNetAccept; // Accept + UINT64 ullNetReconnect; // ReConnect + UINT64 ullRegCreate; // NtCreateKey + UINT64 ullRegOpen; // NtOpenKey + UINT64 ullRegDelete; // NtDeleteKey + UINT64 ullRegQuery; // NtQueryKey + UINT64 ullRegSetValue; // NtSetValueKey + UINT64 ullRegDeleteValue; // NtDeleteValueKey + UINT64 ullRegQueryValue; // NtQueryValueKey + UINT64 ullRegEnumerateKey; // NtEnumerateKey + UINT64 ullRegEnumerateValueKey; // NtEnumerateValueKey + UINT64 ullRegQueryMultipleValue; // NtQueryMultipleValueKey + UINT64 ullRegSetInformation; // NtSetInformationKey + UINT64 ullRegFlush; // NtFlushKey + UINT64 ullThreadStart; + UINT64 ullThreadEnd; + UINT64 ullProcessStart; + UINT64 ullProcessEnd; + UINT64 ullImageLoad; +}; + +// structure containing informations about ETW session +struct ETWSessionInfo +{ + ULONG ulBufferSize; + ULONG ulMinimumBuffers; + ULONG ulMaximumBuffers; + ULONG ulFreeBuffers; + ULONG ulBuffersWritten; + ULONG ulFlushTimer; + LONG lAgeLimit; + ULONG ulNumberOfBuffers; + ULONG ulEventsLost; + ULONG ulLogBuffersLost; + ULONG ulRealTimeBuffersLost; +}; + +// structure containing parameters concerning ETW session provided by user +struct ETWMask +{ + BOOL bProcess; + BOOL bThread; + BOOL bImageLoad; + BOOL bDiskIO; + BOOL bMemoryPageFaults; + BOOL bMemoryHardFaults; + BOOL bNetwork; + BOOL bRegistry; + BOOL bUsePagedMemory; + BOOL bUsePerfTimer; + BOOL bUseSystemTimer; + BOOL bUseCyclesCounter; +}; + +namespace UnitTests +{ + class PerfTimerUnitTests; + class ProfileUnitTests; + class TargetUnitTests; + class IORequestGeneratorUnitTests; +} + +class PerfTimer +{ +public: + + static UINT64 GetTime(); + + static double PerfTimeToMicroseconds(const double); + static double PerfTimeToMilliseconds(const double); + static double PerfTimeToSeconds(const double); + static double PerfTimeToMicroseconds(const UINT64); + static double PerfTimeToMilliseconds(const UINT64); + static double PerfTimeToSeconds(const UINT64); + + static UINT64 MicrosecondsToPerfTime(const double); + static UINT64 MillisecondsToPerfTime(const double); + static UINT64 SecondsToPerfTime(const double); + +private: + + static const UINT64 TIMER_FREQ; + static UINT64 _GetPerfTimerFreq(); + + friend class UnitTests::PerfTimerUnitTests; +}; + +template +class Range +{ +public: + Range( + T1 Source, + T1 Span, + T2 Dest + ) : + _src(Source), + _span(Span), + _dst(Dest) + {} + + constexpr bool operator<(const Range& other) const + { + // + // This is used for comparison of effective distributions during result reporting (dedup). + // + // A hole with _span == 0 sorts < range with _span > 0 + // Note that a hole will never match in a find(). + // + + return _src < other._src || + (_src == other._src && + (_span < other._span || + (_span == other._span && _dst < other._dst))); + } + + static Range const * find(const vector>& v, T1 c) + { + // v must be sorted + size_t s = 0, mid, e = v.size() - 1; + + while (true) + { + mid = s + ((e - s) / 2); + if (c < v[mid]._src) { + if (s == mid) + { + return nullptr; + } + e = mid - 1; + } + else if (c > v[mid]._src + v[mid]._span - 1) + { + if (e == mid) + { + return nullptr; + } + s = mid + 1; + } + else + { + return &v[mid]; + } + } + } + + T1 _src, _span; + T2 _dst; +}; + +typedef Range> DistributionRange; + +enum class DistributionType +{ + None, + Absolute, + Percent +}; + +// +// This code implements Bob Jenkins public domain simple random number generator +// See http://burtleburtle.net/bob/rand/smallprng.html for details +// + +class Random +{ +public: + Random(UINT64 ulSeed = 0); + + inline UINT64 Rand64() + { + UINT64 e; + + e = _ulState[0] - _rotl64(_ulState[1], 7); + _ulState[0] = _ulState[1] ^ _rotl64(_ulState[2], 13); + _ulState[1] = _ulState[2] + _rotl64(_ulState[3], 37); + _ulState[2] = _ulState[3] + e; + _ulState[3] = e + _ulState[0]; + + return _ulState[3]; + } + + inline UINT32 Rand32() + { + return (UINT32)Rand64(); + } + + void RandBuffer(BYTE *pBuffer, UINT32 ulLength, bool fPseudoRandomOkay); + +private: + UINT64 _ulState[4]; +}; + +struct PercentileDescriptor +{ + double Percentile; + string Name; +}; + +class Util +{ +public: + static string DoubleToStringHelper(const double); + template static T QuotientCeiling(T dividend, T divisor) + { + return (dividend + divisor - 1) / divisor; + } + + // True if result is <= ratio. + // The ratio is on the interval [0, 100]: + // 0 will never occur (always false) + // 100 will always occur (always true) + + static bool BooleanRatio(Random *pRand, UINT32 ulRatio) + { + return ((pRand->Rand32() % 100 + 1) <= ulRatio); + } + + // + // This is close to strtoul[l], returning the next character to parse in the input string. + // This character can be used for validation (should there be any non-integer remaining), + // interpreting units that follow the integer (KMGTB), or parsing further (int[]) + // content in the string. + // + // Return value indicates whether any integers were parsed to Output. Continue is only modified + // on success, and will point to the terminator on completion. False is returned on overflow. + // + + template + static bool ParseUInt(const char* Input, T& Output, const char*& Continue) + { + T current = 0, last = 0; + const char* input = Input; + bool parsed = false; + + while (*input) + { + if (*input < '0' || *input > '9') + { + break; + } + + parsed = true; + current *= 10; + current += static_cast(*input) - static_cast('0'); + + // + // Overflow? + // + + if (current < last) + { + parsed = false; + break; + } + last = current; + + input += 1; + } + + // + // Return if string was consumed + // + // + + if (parsed) + { + Continue = input; + Output = current; + } + + return parsed; + } +}; + +// To keep track of which type of IO was issued +enum class IOOperation +{ + Unknown = 0, + ReadIO, + WriteIO +}; + +class TargetResults +{ +public: + TargetResults() : + ullFileSize(0), + ullBytesCount(0), + ullIOCount(0), + ullReadBytesCount(0), + ullReadIOCount(0), + ullWriteBytesCount(0), + ullWriteIOCount(0) + { + + } + + void Add( + DWORD dwBytesTransferred, + IOOperation type, + UINT64 ullIoStartTime, + UINT64 ullIoEndTime, + UINT64 ullSpanStartTime, + bool fMeasureLatency, + bool fCalculateIopsStdDev + ) + { + if (type == IOOperation::ReadIO) + { + ullReadBytesCount += dwBytesTransferred; // update read bytes counter + ullReadIOCount++; // update completed read I/O operations counter + } + else + { + ullWriteBytesCount += dwBytesTransferred; // update write bytes counter + ullWriteIOCount++; // update completed write I/O operations counter + } + + ullBytesCount += dwBytesTransferred; // update bytes counter + ullIOCount++; // update completed I/O operations counter + + // end time is 0 if we're not measuring latency + assert(((fMeasureLatency || fCalculateIopsStdDev) && ullIoEndTime != 0) || + (!fMeasureLatency && !fCalculateIopsStdDev)); + + if (ullIoEndTime == 0) + { + return; + } + + UINT64 ullDuration = ullIoEndTime - ullIoStartTime;; + double lfDurationUsec = PerfTimer::PerfTimeToMicroseconds(ullDuration); + + if (fMeasureLatency) + { + if (type == IOOperation::ReadIO) + { + readLatencyHistogram.Add(static_cast(lfDurationUsec)); + } + else + { + writeLatencyHistogram.Add(static_cast(lfDurationUsec)); + } + } + + if (fCalculateIopsStdDev) + { + UINT64 ullRelativeCompletionTime = ullIoEndTime - ullSpanStartTime; + + if (type == IOOperation::ReadIO) + { + readBucketizer.Add(ullRelativeCompletionTime, lfDurationUsec); + } + else + { + writeBucketizer.Add(ullRelativeCompletionTime, lfDurationUsec); + } + } + } + + string sPath; + UINT64 ullFileSize; //size of the file + UINT64 ullBytesCount; //number of accessed bytes + UINT64 ullIOCount; //number of performed I/O operations + UINT64 ullReadBytesCount; //number of bytes read + UINT64 ullReadIOCount; //number of performed Read I/O operations + UINT64 ullWriteBytesCount; //number of bytes written + UINT64 ullWriteIOCount; //number of performed Write I/O operations + + Histogram readLatencyHistogram; + Histogram writeLatencyHistogram; + + IoBucketizer readBucketizer; + IoBucketizer writeBucketizer; + + // Effective distribution after applying to target size (if specified/non-empty) + vector vDistributionRange; +}; + +typedef struct _WAIT_STATS { + ULONGLONG Wait; + ULONGLONG ThrottleWait; + ULONGLONG ThrottleSleep; + ULONGLONG Lookaside; + ULONGLONG LookasideCompletion[8]; // 0 == none, 1 == 1, ... 7 = 7+ +} WAIT_STATS; + +class ThreadResults +{ +public: + ThreadResults() + { + WaitStats = { 0 }; + } + + WAIT_STATS WaitStats; + vector vTargetResults; +}; + +class Results +{ +public: + bool fUseETW; + struct ETWEventCounters EtwEventCounters; + struct ETWMask EtwMask; + struct ETWSessionInfo EtwSessionInfo; + vector vThreadResults; + UINT64 ullTimeCount; + vector vSystemProcessorPerfInfo; +}; + +typedef void (*CALLBACK_TEST_STARTED)(); //callback function to notify that the measured test is about to start +typedef void (*CALLBACK_TEST_FINISHED)(); //callback function to notify that the measured test has just finished + +class ProcessorGroupInformation +{ +public: + WORD _groupNumber; + BYTE _maximumProcessorCount; + BYTE _activeProcessorCount; + KAFFINITY _activeProcessorMask; + + ProcessorGroupInformation() = delete; + ProcessorGroupInformation( + WORD Group, + BYTE MaximumProcessorCount, + BYTE ActiveProcessorCount, + KAFFINITY ActiveProcessorMask) : + _groupNumber(Group), + _maximumProcessorCount(MaximumProcessorCount), + _activeProcessorCount(ActiveProcessorCount), + _activeProcessorMask(ActiveProcessorMask) + { + } + + ProcessorGroupInformation( + WORD Group, + PROCESSOR_GROUP_INFO& GroupInfo) : + _groupNumber(Group), + _maximumProcessorCount(GroupInfo.MaximumProcessorCount), + _activeProcessorCount(GroupInfo.ActiveProcessorCount), + _activeProcessorMask(GroupInfo.ActiveProcessorMask) + { + } + + // This logic is strictly unaware that sparse processor masks are not possible; + // address this later, not important. See comments around RelationGroup query. + bool IsProcessorActive(BYTE Processor) const + { + return (IsProcessorValid(Processor) && + (((KAFFINITY)1 << Processor) & _activeProcessorMask) != 0); + } + + bool IsProcessorValid(BYTE Processor) const + { + return (Processor < _maximumProcessorCount); + } +}; + +class ProcessorNumaInformation +{ +public: + DWORD _ulProcCount; + DWORD _nodeNumber; + vector> _vProcessorMasks; +}; + +class ProcessorCoreInformation +{ +public: + WORD _groupNumber; + KAFFINITY _processorMask; + BYTE _efficiencyClass; + BYTE _groupCoreNumber; + + ProcessorCoreInformation() = delete; + ProcessorCoreInformation( + WORD Group, + KAFFINITY ProcessorMask, + BYTE EfficiencyClass) : + _groupNumber(Group), + _processorMask(ProcessorMask), + _efficiencyClass(EfficiencyClass), + _groupCoreNumber(0) + { + } +}; + +class ProcessorSocketInformation +{ +public: + DWORD _ulProcCount; + DWORD _ulSocketNumber; + vector> _vProcessorMasks; +}; + +class ProcessorTopology +{ +public: + vector _vProcessorGroupInformation; + vector _vProcessorNumaInformation; + vector _vProcessorSocketInformation; + vector _vProcessorCoreInformation; + + DWORD _ulProcessorCount; // total number of (active) processors + BYTE _ubPerformanceEfficiencyClass; // highest performance class present + bool _fSMT; // any SMT cores present + + ProcessorTopology() + { + BOOL fResult; + PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX pInformation; + DWORD AllocSize = 1024; + DWORD ReturnedLength = AllocSize; + LOGICAL_PROCESSOR_RELATIONSHIP NumaRelation; + pInformation = (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX) new char[AllocSize]; + + _ulProcessorCount = 0; + _ubPerformanceEfficiencyClass = 0; + _fSMT = false; + + //// + // Group Relations + //// + + fResult = GetLogicalProcessorInformationEx(RelationGroup, pInformation, &ReturnedLength); + if (!fResult && GetLastError() == ERROR_INSUFFICIENT_BUFFER) + { + delete [] pInformation; + AllocSize = ReturnedLength; + pInformation = (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX) new char[AllocSize]; + fResult = GetLogicalProcessorInformationEx(RelationGroup, pInformation, &ReturnedLength); + } + + if (fResult) + { + // Group information comes back as a single (large) element, not an array. + assert(ReturnedLength == pInformation->Size); + + // + // Fill in group topology vector + // + // Note: maximum processor count has no utility other than an indication of the + // bit width of the KAFFINITY mask that might have set values. But: + // + // 1) any mask will be a contiguous run of set bits (no sparse holes); there is + // no case where a 0 bit will be present to indicate a gap/disabled processor + // 2) all system APIs (such as the cpu utilization query) are defined over active + // processors + // + // There are (new?) cases where maximum is represented as > active on large systems, + // which makes these distinctions critical... active processor count is the only + // count that matters. + // + // For the sake of documentation we do save & report out the masks as reported by the + // system, but the only ones we look at are limited to cases where we get information + // in the form of GROUP_AFFINITY, which is just group # and mask (like NUMA and package + // association). + // + + for (WORD i = 0; i < pInformation->Group.ActiveGroupCount; i++) + { + _vProcessorGroupInformation.emplace_back( + i, + pInformation->Group.GroupInfo[i] + ); + + _ulProcessorCount += _vProcessorGroupInformation[i]._activeProcessorCount; + } + } + + //// + // NUMA Relations + //// + + // + // Dynamically detect the available NUMA relations. Non-Ex returns exactly one relation and + // does not define the GroupCount field. Ex scales to return multiple groups for large systems + // with > 64 per NUMA domain and does populate GroupCount. + // + + NumaRelation = RelationNumaNodeEx; + ReturnedLength = AllocSize; + fResult = GetLogicalProcessorInformationEx(NumaRelation, pInformation, &ReturnedLength); + if (!fResult && GetLastError() == ERROR_GEN_FAILURE) + { + NumaRelation = RelationNumaNode; + fResult = GetLogicalProcessorInformationEx(NumaRelation, pInformation, &ReturnedLength); + } + if (!fResult && GetLastError() == ERROR_INSUFFICIENT_BUFFER) + { + delete [] pInformation; + AllocSize = ReturnedLength; + pInformation = (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX) new char[AllocSize]; + fResult = GetLogicalProcessorInformationEx(NumaRelation, pInformation, &ReturnedLength); + } + + if (fResult) + { + PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX cur = pInformation; + + while (ReturnedLength > 0) + { + ProcessorNumaInformation node; + + assert(ReturnedLength >= cur->Size); + + if (cur->Size > ReturnedLength) + { + break; + } + + node._nodeNumber = cur->NumaNode.NodeNumber; + node._ulProcCount = 0; + for (WORD i = 0; i < (NumaRelation == RelationNumaNode ? 1 : cur->NumaNode.GroupCount); i++) + { + node._ulProcCount += ProcessorTopology::MaskCount(cur->NumaNode.GroupMasks[i].Mask); + node._vProcessorMasks.emplace_back(cur->NumaNode.GroupMasks[i].Group, + cur->NumaNode.GroupMasks[i].Mask); + } + + _vProcessorNumaInformation.push_back(node); + + ReturnedLength -= cur->Size; + cur = (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX)((PCHAR)cur + cur->Size); + } + } + + //// + // Socket/Package Relations + //// + + ReturnedLength = AllocSize; + fResult = GetLogicalProcessorInformationEx(RelationProcessorPackage, pInformation, &ReturnedLength); + if (!fResult && GetLastError() == ERROR_INSUFFICIENT_BUFFER) + { + delete [] pInformation; + AllocSize = ReturnedLength; + pInformation = (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX) new char[AllocSize]; + fResult = GetLogicalProcessorInformationEx(RelationProcessorPackage, pInformation, &ReturnedLength); + } + + if (fResult) + { + PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX cur = pInformation; + + DWORD socketNumber = 0; + while (ReturnedLength != 0) + { + ProcessorSocketInformation socket; + + assert(ReturnedLength >= cur->Size); + + if (cur->Size > ReturnedLength) + { + break; + } + + socket._ulProcCount = 0; + socket._ulSocketNumber = socketNumber; + for (WORD i = 0; i < cur->Processor.GroupCount; i++) + { + socket._ulProcCount += ProcessorTopology::MaskCount(cur->Processor.GroupMask[i].Mask); + socket._vProcessorMasks.emplace_back(cur->Processor.GroupMask[i].Group, + cur->Processor.GroupMask[i].Mask); + } + + _vProcessorSocketInformation.push_back(socket); + + ReturnedLength -= cur->Size; + cur = (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX)((PCHAR)cur + cur->Size); + socketNumber += 1; + } + } + + //// + // Core Relations + //// + + ReturnedLength = AllocSize; + fResult = GetLogicalProcessorInformationEx(RelationProcessorCore, pInformation, &ReturnedLength); + if (!fResult && GetLastError() == ERROR_INSUFFICIENT_BUFFER) + { + delete [] pInformation; + AllocSize = ReturnedLength; + pInformation = (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX) new char[AllocSize]; + fResult = GetLogicalProcessorInformationEx(RelationProcessorCore, pInformation, &ReturnedLength); + } + + // + // The EfficiencyClass member was added with Windows 10 + // + + BOOL fEfficiencyClass = false; + if (IsWindows10OrGreater()) + { + fEfficiencyClass = true; + } + + if (fResult) + { + PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX cur = pInformation; + BYTE curEfficiency; + + while (ReturnedLength != 0) + { + assert(ReturnedLength >= cur->Size); + + if (cur->Size > ReturnedLength) + { + break; + } + + // + // Determine the highest performance core class and presence of SMT as we sweep. + // Note that SMT is per core and can be asymmetric. + // + + if (fEfficiencyClass) + { + curEfficiency = cur->Processor.EfficiencyClass; + if (_ubPerformanceEfficiencyClass < curEfficiency) + { + _ubPerformanceEfficiencyClass = curEfficiency; + } + } + + if (cur->Processor.Flags & LTP_PC_SMT) + { + _fSMT = true; + } + + assert(pInformation->Processor.GroupCount == 1); + + _vProcessorCoreInformation.emplace_back(cur->Processor.GroupMask[0].Group, + cur->Processor.GroupMask[0].Mask, + fEfficiencyClass ? cur->Processor.EfficiencyClass : (BYTE)0); + + ReturnedLength -= cur->Size; + cur = (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX)((PCHAR)cur + cur->Size); + } + + // Now guarantee ascending order of group number & cpu mask so that group-relative core number can be assigned + + sort(_vProcessorCoreInformation.begin(), _vProcessorCoreInformation.end(), + [](const ProcessorCoreInformation& a, const ProcessorCoreInformation& b) + { + return a._groupNumber < b._groupNumber || + (a._groupNumber == b._groupNumber && a._processorMask < b._processorMask); + }); + + // Assign group-relative core number + + BYTE coreNumber = 0; + WORD group = 0; + for (auto& core : _vProcessorCoreInformation) + { + if (core._groupNumber != group) + { + group = core._groupNumber; + coreNumber = 0; + } + core._groupCoreNumber = coreNumber++; + } + } + + // TODO: Get the cache relationships as well??? + + delete [] pInformation; + } + + bool IsGroupValid(WORD Group) + { + if (Group < _vProcessorGroupInformation.size()) + { + return true; + } + else + { + return false; + } + } + + // Return the next active processor in the system, exclusive (Next = true) + // or inclusive (Next = false) of the input group/processor. + // Iteration is in order of absolute processor number. + // This does assume at least one core is active, but that is a given. + // + // This logic is strictly unaware that sparse processor masks are not possible; + // address this later, not important. See comments around RelationGroup query. + void GetActiveGroupProcessor(WORD& Group, BYTE& Processor, bool Next) + { + if (Next) + { + Processor++; + } + + while (!_vProcessorGroupInformation[Group].IsProcessorActive(Processor)) + { + if (!_vProcessorGroupInformation[Group].IsProcessorValid(Processor)) + { + Processor = 0; + if (!IsGroupValid(++Group)) + { + Group = 0; + } + } + else + { + Processor++; + } + } + } + + // + // Efficiency of these mappings is not a first order concern. We simply use these to avoid assuming + // ordering of groups/masks of processors within topology structures. There's strictly no reason, + // for example, that socket 0 contains the first groups (0, 1, etc.) of processors, at least not + // documented or guaranteed. + // + + DWORD GetNumaOfProcessor(WORD Group, BYTE Processor) const + { + for (const auto& numa : _vProcessorNumaInformation) + { + for (const auto& mask : numa._vProcessorMasks) + { + if (mask.first == Group && (mask.second & ((KAFFINITY)1 << Processor))) + { + return numa._nodeNumber; + } + } + } + + assert(false); + return 0; + } + + DWORD GetSocketOfProcessor(WORD Group, BYTE Processor) const + { + for (const auto& socket : _vProcessorSocketInformation) + { + for (const auto& mask : socket._vProcessorMasks) + { + if (mask.first == Group && (mask.second & ((KAFFINITY)1 << Processor))) + { + return socket._ulSocketNumber; + } + } + } + + assert(false); + return 0; + } + + BYTE GetCoreOfProcessor(WORD Group, BYTE Processor, BYTE& EfficiencyClass) const + { + for (const auto& core : _vProcessorCoreInformation) + { + if (core._groupNumber == Group && (core._processorMask & ((KAFFINITY)1 << Processor))) + { + EfficiencyClass = core._efficiencyClass; + return core._groupCoreNumber; + } + } + + assert(false); + return 0; + } + + static unsigned int MaskCount(KAFFINITY Mask) + { + // + // Trivial popcount for affinity mask w/o insn dependency + // + + unsigned int count = 0; + + while (Mask) + { + Mask &= (Mask - 1); + count++; + } + + return count; + } +}; + +// +// Helper macros for outputting indented XML. They assume a local variable "indent". +// Use the Inc form when outputting the opening tag for a multi-line section: +// Use Dec for the closing tag: +// + +// start line with indent +#define AddXml(s,str) { (s).append(indent, ' '); (s) += (str); } +// start new indented section +#define AddXmlInc(s,str) { (s).append(indent, ' '); indent += 2; (s) += (str); } +// end indented section +#define AddXmlDec(s,str) { if (indent >= 2) { indent -= 2; }; (s).append(indent, ' '); (s) += (str); } + +class SystemInformation +{ +private: + SYSTEMTIME StartTime; + +public: + ProcessorTopology processorTopology; + string sComputerName; + string sActivePolicyName; + string sActivePolicyGuid; + + SystemInformation() + { + char buffer[128]; + DWORD cb = _countof(buffer); + GUID *guid = NULL; + BOOL fResult; + +#pragma prefast(suppress:38020, "Yes, we're aware this is an ANSI API in a UNICODE project") + fResult = GetComputerNameExA(ComputerNamePhysicalDnsHostname, buffer, &cb); + if (fResult) + { + sComputerName = buffer; + } + + // capture start time + GetSystemTime(&StartTime); + + if (PowerGetActiveScheme(NULL, &guid) == ERROR_SUCCESS && + PowerReadFriendlyName(NULL, guid, NULL, NULL, NULL, &cb) == ERROR_SUCCESS) + { + PUCHAR pwrBuffer; + + if (cb <= _countof(buffer)) + { + pwrBuffer = (PUCHAR) buffer; + } + else + { + pwrBuffer = new UCHAR[cb]; + } + + if (PowerReadFriendlyName(NULL, guid, NULL, NULL, pwrBuffer, &cb) == ERROR_SUCCESS) + { + // Cast wide string down to basic - all of our current output streams are basic + wstring wActivePolicyName = (PWCHAR) pwrBuffer; + std::wstring_convert> cvt; + sActivePolicyName = cvt.to_bytes(wActivePolicyName); + } + + if (pwrBuffer != (PVOID) buffer) + { + delete pwrBuffer; + } + } + + if (sActivePolicyName.empty()) + { + sActivePolicyName = ""; + } + + if (guid) + { + sprintf_s(buffer, _countof(buffer), + "%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", + guid->Data1, guid->Data2, guid->Data3, + guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3], + guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]); + + sActivePolicyGuid = buffer; + + LocalFree(guid); + } + } + + // for unit test, squelch variable timestamp + void SystemInformation::ResetTime() + { + StartTime = { 0 }; + } + + string SystemInformation::GetText() const + { + char szBuffer[128]; // guid (36ch), timestamp and power friendly (up to 64ch) + int nWritten; + string sText("System information:\n\n"); + + // identify computer which ran the test + sText += "\tcomputer name: "; + sText += sComputerName; + sText += "\n"; + + sText += "\tstart time: "; + if (StartTime.wYear) { + + nWritten = sprintf_s(szBuffer, _countof(szBuffer), + "%u/%02u/%02u %02u:%02u:%02u UTC", + StartTime.wYear, + StartTime.wMonth, + StartTime.wDay, + StartTime.wHour, + StartTime.wMinute, + StartTime.wSecond); + assert(nWritten && nWritten < _countof(szBuffer)); + sText += szBuffer; + } + + sText += "\n\n\tcpu count:\t\t"; + sText += to_string(processorTopology._ulProcessorCount); + sText += "\n\tcore count:\t\t"; + sText += to_string(processorTopology._vProcessorCoreInformation.size()); + sText += "\n\tgroup count:\t\t"; + sText += to_string(processorTopology._vProcessorGroupInformation.size()); + sText += "\n\tnode count:\t\t"; + sText += to_string(processorTopology._vProcessorNumaInformation.size()); + sText += "\n\tsocket count:\t\t"; + sText += to_string(processorTopology._vProcessorSocketInformation.size()); + sText += "\n\theterogeneous cores:\t"; + sText += processorTopology._ubPerformanceEfficiencyClass ? "y\n" : "n\n"; + + sText += "\n\tactive power scheme:\t"; + sText += sActivePolicyName; + + if (!sActivePolicyGuid.empty()) + { + sText += " ("; + sText += sActivePolicyGuid; + sText += ")"; + } + + sText += "\n"; + + return sText; + } + + string SystemInformation::GetXml(UINT32 indent) const + { + char szBuffer[64]; // enough for 64bit mask (17ch) and timestamp + int nWritten; + string sXml; + + AddXmlInc(sXml, "\n"); + + // identify computer which ran the test + AddXml(sXml, ""); + sXml += sComputerName; + sXml += "\n"; + + // identify tool version which performed the test + AddXmlInc(sXml, "\n"); + AddXml(sXml,"" DISKSPD_NUMERIC_VERSION_STRING "\n"); + AddXml(sXml, "" DISKSPD_DATE_VERSION_STRING "\n"); + AddXmlDec(sXml, "\n"); + + AddXml(sXml, ""); + if (StartTime.wYear) { + + nWritten = sprintf_s(szBuffer, _countof(szBuffer), + "%u/%02u/%02u %02u:%02u:%02u UTC", + StartTime.wYear, + StartTime.wMonth, + StartTime.wDay, + StartTime.wHour, + StartTime.wMinute, + StartTime.wSecond); + assert(nWritten && nWritten < _countof(szBuffer)); + sXml += szBuffer; + } + sXml += "\n"; + + AddXml(sXml, "\n"; + + // processor topology + AddXmlInc(sXml, "\n" : "false\">\n"; + + for (const auto& g : processorTopology._vProcessorGroupInformation) + { + AddXml(sXml, "\n"; + + } + for (const auto& n : processorTopology._vProcessorNumaInformation) + { + AddXmlInc(sXml, "\n"; + for (const auto& g : n._vProcessorMasks) + { + AddXml(sXml, "\n"; + } + AddXmlDec(sXml, "\n"); + } + for (const auto& s : processorTopology._vProcessorSocketInformation) + { + AddXmlInc(sXml, "\n"; + for (const auto& g : s._vProcessorMasks) + { + AddXml(sXml, "\n"; + } + AddXmlDec(sXml, "\n"); + } + for (const auto& h : processorTopology._vProcessorCoreInformation) + { + AddXml(sXml, "\n"; + } + + AddXmlDec(sXml, "\n"); + AddXmlDec(sXml, "\n"); + + return sXml; + } +}; + +extern SystemInformation g_SystemInformation; + +struct Synchronization +{ + ULONG ulStructSize; //size of the structure that the caller is aware of (to easier achieve backward compatibility in a future) + HANDLE hStopEvent; //an event to be signalled if the scenario is to be stop before time ellapses + HANDLE hStartEvent; //an event for signalling start + CALLBACK_TEST_STARTED pfnCallbackTestStarted; //a function to be called if the measured test is about to start + CALLBACK_TEST_FINISHED pfnCallbackTestFinished; //a function to be called as soon as the measrued test finishes +}; + +#define STRUCT_SYNCHRONIZATION_SUPPORTS(pSynch, Field) ( \ + (NULL != (pSynch)) && \ + ((pSynch)->ulStructSize >= offsetof(struct Synchronization, Field) + sizeof((pSynch)->Field)) \ + ) + +// caching modes +// cached -> default (-Sb explicitly) +// disableoscache -> no_intermediate_buffering (-S or -Su) +// disablelocalcache -> cached, but then tear down local rdr cache (-Sr) +enum class TargetCacheMode { + Undefined = 0, + Cached, + DisableOSCache, + DisableLocalCache +}; + +// writethrough modes +// off -> default +// on -> (-Sw or implied with -Sh == -Suw/-Swu) +enum class WriteThroughMode { + Undefined = 0, + Off, + On, +}; + +// memory mapped IO modes +// off -> default +// on -> (-Sm or -Smw) +enum class MemoryMappedIoMode { + Undefined = 0, + Off, + On, +}; + +// memory mapped IO flush modes +// off / Undefined -> default +// on -> (-Sm or -Smw) +enum class MemoryMappedIoFlushMode { + Undefined = 0, + ViewOfFile, + NonVolatileMemory, + NonVolatileMemoryNoDrain, +}; + +enum class IOMode +{ + Unknown, + Random, + Sequential, + Mixed, + InterlockedSequential, + ParallelAsync +}; + +class ThreadTarget +{ +public: + + ThreadTarget() : + _ulThread(0xFFFFFFFF), + _ulWeight(0) + { + } + + void SetThread(UINT32 ulThread) { _ulThread = ulThread; } + UINT32 GetThread() const { return _ulThread; } + + void SetWeight(UINT32 ulWeight) { _ulWeight = ulWeight; } + UINT32 GetWeight() const { return _ulWeight; } + + string GetXml(UINT32 indent) const; + +private: + UINT32 _ulThread; + UINT32 _ulWeight; +}; + +// Character which leads off a template target definition; e.g. *1, *2 +#define TEMPLATE_TARGET_PREFIX ('*') + +class Target +{ +public: + + Target() : + _dwBlockSize(64 * 1024), + _dwRequestCount(2), + _ullBlockAlignment(0), + _ulWriteRatio(0), + _ulRandomRatio(0), + _ullBaseFileOffset(0), + _fParallelAsyncIO(false), + _fInterlockedSequential(false), + _cacheMode(TargetCacheMode::Cached), + _writeThroughMode(WriteThroughMode::Off), + _memoryMappedIoMode(MemoryMappedIoMode::Off), + _memoryMappedIoNvToken(nullptr), + _memoryMappedIoFlushMode(MemoryMappedIoFlushMode::Undefined), + _fZeroWriteBuffers(false), + _dwThreadsPerFile(1), + _ullThreadStride(0), + _fCreateFile(false), + _fPrecreated(false), + _ullFileSize(0), + _ullMaxFileSize(0), + _fUseBurstSize(false), + _dwBurstSize(0), + _dwThinkTime(0), + _fThinkTime(false), + _fSequentialScanHint(false), + _fRandomAccessHint(false), + _fTemporaryFileHint(false), + _fUseLargePages(false), + _mappedViewFileHandle(INVALID_HANDLE_VALUE), + _mappedView(NULL), + _ioPriorityHint(IoPriorityHintNormal), + _ulWeight(1), + _dwThroughputBytesPerMillisecond(0), + _dwThroughputIOPS(0), + _cbRandomDataWriteBuffer(0), + _sRandomDataWriteBufferSourcePath(), + _pRandomDataWriteBuffer(nullptr), + _distributionType(DistributionType::None) + { + } + + IOMode GetIOMode() const + { + if (GetRandomRatio() == 100) + { + return IOMode::Random; + } + else if (GetRandomRatio() != 0) + { + return IOMode::Mixed; + } + else if (GetUseParallelAsyncIO()) + { + return IOMode::ParallelAsync; + } + else if (GetUseInterlockedSequential()) + { + return IOMode::InterlockedSequential; + } + else + { + return IOMode::Sequential; + } + } + + void SetPath(const string& sPath) { _sPath = sPath; } + void SetPath(const char *pPath) { _sPath = pPath; } + const string& GetPath() const { return _sPath; } + + void SetBlockSizeInBytes(DWORD dwBlockSize) { _dwBlockSize = dwBlockSize; } + DWORD GetBlockSizeInBytes() const { return _dwBlockSize; } + + void SetBlockAlignmentInBytes(UINT64 ullBlockAlignment) + { + _ullBlockAlignment = ullBlockAlignment; + } + // actual is used in validation to detect unclear/mis-specified intent + // like -rs -s + UINT64 GetBlockAlignmentInBytes(bool actual = false) const + { + return _ullBlockAlignment ? _ullBlockAlignment : (actual ? 0 : _dwBlockSize); + } + + void SetWriteRatio(UINT32 writeRatio) { _ulWriteRatio = writeRatio; } + UINT32 GetWriteRatio() const { return _ulWriteRatio; } + + void SetRandomRatio(UINT32 randomRatio) { _ulRandomRatio = randomRatio; } + UINT32 GetRandomRatio() const { return _ulRandomRatio; } + + void SetBaseFileOffsetInBytes(UINT64 ullBaseFileOffset) { _ullBaseFileOffset = ullBaseFileOffset; } + UINT64 GetBaseFileOffsetInBytes() const { return _ullBaseFileOffset; } + UINT64 GetThreadBaseRelativeOffsetInBytes(UINT32 ulThreadNo) const { return ulThreadNo * _ullThreadStride; } + UINT64 GetThreadBaseFileOffsetInBytes(UINT32 ulThreadNo) const { return _ullBaseFileOffset + GetThreadBaseRelativeOffsetInBytes(ulThreadNo); } + + + void SetSequentialScanHint(bool fBool) { _fSequentialScanHint = fBool; } + bool GetSequentialScanHint() const { return _fSequentialScanHint; } + + void SetRandomAccessHint(bool fBool) { _fRandomAccessHint = fBool; } + bool GetRandomAccessHint() const { return _fRandomAccessHint; } + + void SetTemporaryFileHint(bool fBool) { _fTemporaryFileHint = fBool; } + bool GetTemporaryFileHint() const { return _fTemporaryFileHint; } + + void SetUseLargePages(bool fBool) { _fUseLargePages = fBool; } + bool GetUseLargePages() const { return _fUseLargePages; } + + void SetRequestCount(DWORD dwRequestCount) { _dwRequestCount = dwRequestCount; } + DWORD GetRequestCount() const { return _dwRequestCount; } + + void SetCacheMode(TargetCacheMode cacheMode) { _cacheMode = cacheMode; } + TargetCacheMode GetCacheMode() const { return _cacheMode; } + + void SetWriteThroughMode(WriteThroughMode writeThroughMode ) { _writeThroughMode = writeThroughMode; } + WriteThroughMode GetWriteThroughMode() const { return _writeThroughMode; } + + void SetMemoryMappedIoMode(MemoryMappedIoMode memoryMappedIoMode ) { _memoryMappedIoMode = memoryMappedIoMode; } + MemoryMappedIoMode GetMemoryMappedIoMode() const { return _memoryMappedIoMode; } + + void SetMemoryMappedIoNvToken(PVOID memoryMappedIoNvToken) { _memoryMappedIoNvToken = memoryMappedIoNvToken; } + PVOID GetMemoryMappedIoNvToken() const { return _memoryMappedIoNvToken; } + + void SetMemoryMappedIoFlushMode(MemoryMappedIoFlushMode memoryMappedIoFlushMode) { _memoryMappedIoFlushMode = memoryMappedIoFlushMode; } + MemoryMappedIoFlushMode GetMemoryMappedIoFlushMode() const { return _memoryMappedIoFlushMode; } + + void SetZeroWriteBuffers(bool fBool) { _fZeroWriteBuffers = fBool; } + bool GetZeroWriteBuffers() const { return _fZeroWriteBuffers; } + + void SetRandomDataWriteBufferSize(UINT64 cbWriteBuffer) { _cbRandomDataWriteBuffer = cbWriteBuffer; } + UINT64 GetRandomDataWriteBufferSize(void) const { return _cbRandomDataWriteBuffer; } + + void SetRandomDataWriteBufferSourcePath(string sPath) { _sRandomDataWriteBufferSourcePath = sPath; } + string GetRandomDataWriteBufferSourcePath() const { return _sRandomDataWriteBufferSourcePath; } + + void SetUseBurstSize(bool fBool) { _fUseBurstSize = fBool; } + bool GetUseBurstSize() const { return _fUseBurstSize; } + + void SetBurstSize(DWORD dwBurstSize) { _dwBurstSize = dwBurstSize; } + DWORD GetBurstSize() const { return _dwBurstSize; } + + void SetThinkTime(DWORD dwThinkTime) { _dwThinkTime = dwThinkTime; } + DWORD GetThinkTime() const { return _dwThinkTime; } + + void SetEnableThinkTime(bool fBool) { _fThinkTime = fBool; } + bool GetEnableThinkTime() const { return _fThinkTime; } + + void SetThreadsPerFile(DWORD dwThreadsPerFile) { _dwThreadsPerFile = dwThreadsPerFile; } + DWORD GetThreadsPerFile() const { return _dwThreadsPerFile; } + + void SetCreateFile(bool fBool) { _fCreateFile = fBool; } + bool GetCreateFile() const { return _fCreateFile; } + + void SetFileSize(UINT64 ullFileSize) { _ullFileSize = ullFileSize; } + UINT64 GetFileSize() const { return _ullFileSize; } // TODO: InBytes + + void SetMaxFileSize(UINT64 ullMaxFileSize) { _ullMaxFileSize = ullMaxFileSize; } + UINT64 GetMaxFileSize() const { return _ullMaxFileSize; } + + void SetUseParallelAsyncIO(bool fBool) { _fParallelAsyncIO = fBool; } + bool GetUseParallelAsyncIO() const { return _fParallelAsyncIO; } + + void SetUseInterlockedSequential(bool fBool) { _fInterlockedSequential = fBool; } + bool GetUseInterlockedSequential() const { return _fInterlockedSequential; } + + void SetThreadStrideInBytes(UINT64 ullThreadStride) { _ullThreadStride = ullThreadStride; } + UINT64 GetThreadStrideInBytes() const { return _ullThreadStride; } + + void SetMappedViewFileHandle(HANDLE FileHandle) { _mappedViewFileHandle = FileHandle; } + HANDLE GetMappedViewFileHandle() const { return _mappedViewFileHandle; } + + void SetMappedView(BYTE *MappedView) { _mappedView = MappedView; } + BYTE* GetMappedView() const { return _mappedView; } + + void SetIOPriorityHint(PRIORITY_HINT _hint) + { + assert(_hint < MaximumIoPriorityHintType); + _ioPriorityHint = _hint; + } + PRIORITY_HINT GetIOPriorityHint() const { return _ioPriorityHint; } + + void SetWeight(UINT32 ulWeight) { _ulWeight = ulWeight; } + UINT32 GetWeight() const { return _ulWeight; } + + void AddThreadTarget(const ThreadTarget &threadTarget) + { + _vThreadTargets.push_back(threadTarget); + } + vector GetThreadTargets() const { return _vThreadTargets; } + + void SetPrecreated(bool fBool) { _fPrecreated = fBool; } + bool GetPrecreated() const { return _fPrecreated; } + + // Convert units to BPMS. Nonzero value of IOPS indicates originally specified units for display/profile. + void SetThroughputIOPS(DWORD dwIOPS) + { + _dwThroughputIOPS = dwIOPS; + _dwThroughputBytesPerMillisecond = (dwIOPS * _dwBlockSize) / 1000; + } + DWORD GetThroughputIOPS() const { return _dwThroughputIOPS; } + void SetThroughput(DWORD dwThroughputBytesPerMillisecond) + { + _dwThroughputIOPS = 0; + _dwThroughputBytesPerMillisecond = dwThroughputBytesPerMillisecond; + } + DWORD GetThroughputInBytesPerMillisecond() const { return _dwThroughputBytesPerMillisecond; } + + string GetXml(UINT32 indent) const; + + bool AllocateAndFillRandomDataWriteBuffer(Random *pRand); + void FreeRandomDataWriteBuffer(); + BYTE* GetRandomDataWriteBuffer(Random *pRand); + + void SetDistributionRange(const vector& v, DistributionType t) + { + _vDistributionRange = v; _distributionType = t; + + // Now place final element if IO% is < 100. + // If this is an absolute specification, it will map to zero length here and + // conversion will occur at the time of target open to the rest of the target. + // For the percent specification we place the final element as-if directly stated, + // consuming the tail length. + // + // This done here so that the stated specification is indeed complete, and not left + // for the effective distribution. + // + // TBD this should be moved to a proper Distribution class. + + const DistributionRange& last = *_vDistributionRange.rbegin(); + + UINT32 ioCur = last._src + last._span; + if (ioCur < 100) + { + UINT64 targetCur = last._dst.first + last._dst.second; + if (t == DistributionType::Percent && targetCur < 100) + { + // tail is available + // if tail is not available, this will be caught by validation + _vDistributionRange.emplace_back(ioCur, 100 - ioCur, make_pair(targetCur, 100 - targetCur)); + } + else + { + _vDistributionRange.emplace_back(ioCur, 100 - ioCur, make_pair(targetCur, 0)); + } + } + } + auto& GetDistributionRange() const { return _vDistributionRange; } + auto GetDistributionType() const { return _distributionType; } + + DWORD GetCreateFlags(bool fAsync) + { + DWORD dwFlags = FILE_ATTRIBUTE_NORMAL; + + if (GetSequentialScanHint()) + { + dwFlags |= FILE_FLAG_SEQUENTIAL_SCAN; + } + + if (GetRandomAccessHint()) + { + dwFlags |= FILE_FLAG_RANDOM_ACCESS; + } + + if (GetTemporaryFileHint()) + { + dwFlags |= FILE_ATTRIBUTE_TEMPORARY; + } + + if (fAsync) + { + dwFlags |= FILE_FLAG_OVERLAPPED; + } + + if (GetCacheMode() == TargetCacheMode::DisableOSCache) + { + dwFlags |= FILE_FLAG_NO_BUFFERING; + } + + if (GetWriteThroughMode( ) == WriteThroughMode::On) + { + dwFlags |= FILE_FLAG_WRITE_THROUGH; + } + + return dwFlags; + } + +private: + string _sPath; + DWORD _dwBlockSize; + DWORD _dwRequestCount; // TODO: change the name to something more descriptive (OutstandingRequestCount?) + + UINT64 _ullBlockAlignment; + UINT32 _ulWriteRatio; + UINT32 _ulRandomRatio; + + UINT64 _ullBaseFileOffset; + + TargetCacheMode _cacheMode; + WriteThroughMode _writeThroughMode; + MemoryMappedIoMode _memoryMappedIoMode; + MemoryMappedIoFlushMode _memoryMappedIoFlushMode; + PVOID _memoryMappedIoNvToken; + DWORD _dwThreadsPerFile; + UINT64 _ullThreadStride; + + UINT64 _ullFileSize; + UINT64 _ullMaxFileSize; + + DWORD _dwBurstSize; // number of IOs in a burst + DWORD _dwThinkTime; // time to pause before issuing the next burst of IOs + + DWORD _dwThroughputBytesPerMillisecond; // set to 0 to disable throttling + DWORD _dwThroughputIOPS; // if IOPS are specified they are converted to BPMS but saved for fidelity to XML/output + + bool _fThinkTime:1; // variable to decide whether to think between IOs (default is false) (removed by using _dwThinkTime==0?) + bool _fUseBurstSize:1; // TODO: "use" or "enable"?; since burst size must be specified with the think time, one variable should be sufficient + bool _fZeroWriteBuffers:1; + bool _fCreateFile:1; + bool _fPrecreated:1; // used to track which files have been created before the first timespan and which have to be created later + bool _fParallelAsyncIO:1; + bool _fInterlockedSequential:1; + bool _fSequentialScanHint:1; // open file with the FILE_FLAG_SEQUENTIAL_SCAN hint + bool _fRandomAccessHint:1; // open file with the FILE_FLAG_RANDOM_ACCESS hint + bool _fTemporaryFileHint:1; // open file with the FILE_ATTRIBUTE_TEMPORARY hint + bool _fUseLargePages:1; // Use large pages for IO buffers + + UINT64 _cbRandomDataWriteBuffer; // if > 0, then the write buffer should be filled with random data + string _sRandomDataWriteBufferSourcePath; // file that should be used for filling the write buffer (if the path is not available, use a crypto provider) + BYTE *_pRandomDataWriteBuffer; // a buffer used for write data when _cbWriteBuffer > 0; it's shared by all the threads working on this target + + HANDLE _mappedViewFileHandle; + BYTE *_mappedView; + + PRIORITY_HINT _ioPriorityHint; + + UINT32 _ulWeight; + vector _vThreadTargets; + + vector _vDistributionRange; + DistributionType _distributionType; + + bool _FillRandomDataWriteBuffer(Random *pRand); + + friend class UnitTests::ProfileUnitTests; + friend class UnitTests::TargetUnitTests; +}; + +class AffinityAssignment +{ +public: + WORD wGroup; + BYTE bProc; + + AffinityAssignment() = delete; + AffinityAssignment(WORD p_wGroup, BYTE p_bProc) : + wGroup(p_wGroup), + bProc(p_bProc) + { + } +}; + +class TimeSpan +{ +public: + TimeSpan() : + _ulDuration(10), + _ulWarmUp(5), + _ulCoolDown(0), + _ulRandSeed(0), + _dwThreadCount(0), + _dwRequestCount(0), + _fRandomWriteData(false), + _fDisableAffinity(false), + _fCompletionRoutines(false), + _fMeasureLatency(false), + _fCalculateIopsStdDev(false), + _ulIoBucketDurationInMilliseconds(1000) + { + } + + void ClearAffinityAssignment() + { + _vAffinity.clear(); + } + void AddAffinityAssignment(WORD wGroup, BYTE bProc) + { + _vAffinity.emplace_back(wGroup, bProc); + } + const auto& GetAffinityAssignments() const { return _vAffinity; } + + void AddTarget(const Target& target) + { + _vTargets.push_back(Target(target)); + } + + vector GetTargets() const { return _vTargets; } + + void SetDuration(UINT32 ulDuration) { _ulDuration = ulDuration; } + UINT32 GetDuration() const { return _ulDuration; } + + void SetWarmup(UINT32 ulWarmup) { _ulWarmUp = ulWarmup; } + UINT32 GetWarmup() const { return _ulWarmUp; } + + void SetCooldown(UINT32 ulCooldown) { _ulCoolDown = ulCooldown; } + UINT32 GetCooldown() const { return _ulCoolDown; } + + void SetRandSeed(UINT32 ulRandSeed) { _ulRandSeed = ulRandSeed; } + UINT32 GetRandSeed() const { return _ulRandSeed; } + + void SetRandomWriteData(bool fRandomWriteData) { _fRandomWriteData = fRandomWriteData; } + bool GetRandomWriteData() const { return _fRandomWriteData; } + + void SetThreadCount(DWORD dwThreadCount) { _dwThreadCount = dwThreadCount; } + DWORD GetThreadCount() const { return _dwThreadCount; } + + void SetRequestCount(DWORD dwRequestCount) { _dwRequestCount = dwRequestCount; } + DWORD GetRequestCount() const { return _dwRequestCount; } + + void SetDisableAffinity(bool fDisableAffinity) { _fDisableAffinity = fDisableAffinity; } + bool GetDisableAffinity() const { return _fDisableAffinity; } + + void SetCompletionRoutines(bool fCompletionRoutines) { _fCompletionRoutines = fCompletionRoutines; } + bool GetCompletionRoutines() const { return _fCompletionRoutines; } + + void SetMeasureLatency(bool fMeasureLatency) { _fMeasureLatency = fMeasureLatency; } + bool GetMeasureLatency() const { return _fMeasureLatency; } + + void SetCalculateIopsStdDev(bool fCalculateStdDev) { _fCalculateIopsStdDev = fCalculateStdDev; } + bool GetCalculateIopsStdDev() const { return _fCalculateIopsStdDev; } + + void SetIoBucketDurationInMilliseconds(UINT32 ulIoBucketDurationInMilliseconds) { _ulIoBucketDurationInMilliseconds = ulIoBucketDurationInMilliseconds; } + UINT32 GetIoBucketDurationInMilliseconds() const { return _ulIoBucketDurationInMilliseconds; } + + string GetXml(UINT32 indent) const; + void MarkFilesAsPrecreated(const vector vFiles); + +private: + vector _vTargets; + UINT32 _ulDuration; + UINT32 _ulWarmUp; + UINT32 _ulCoolDown; + UINT32 _ulRandSeed; + DWORD _dwThreadCount; + DWORD _dwRequestCount; + bool _fRandomWriteData; + bool _fDisableAffinity; + vector _vAffinity; + bool _fCompletionRoutines; + bool _fMeasureLatency; + bool _fCalculateIopsStdDev; + UINT32 _ulIoBucketDurationInMilliseconds; + + friend class UnitTests::ProfileUnitTests; +}; + +enum class ResultsFormat +{ + Text, + Xml +}; + +enum class PrecreateFiles +{ + None, + UseMaxSize, + OnlyFilesWithConstantSizes, + OnlyFilesWithConstantOrZeroSizes +}; + +class Profile +{ +public: + Profile() : + _fProfileOnly(false), + _fVerbose(false), + _fVerboseStats(false), + _dwProgress(0), + _fEtwEnabled(false), + _fEtwProcess(false), + _fEtwThread(false), + _fEtwImageLoad(false), + _fEtwDiskIO(false), + _fEtwMemoryPageFaults(false), + _fEtwMemoryHardFaults(false), + _fEtwNetwork(false), + _fEtwRegistry(false), + _fEtwUsePagedMemory(false), + _fEtwUsePerfTimer(false), + _fEtwUseSystemTimer(false), + _fEtwUseCyclesCounter(false), + _resultsFormat(ResultsFormat::Text), + _precreateFiles(PrecreateFiles::None) + { + } + + void ClearTimeSpans() + { + _vTimeSpans.clear(); + } + + void AddTimeSpan(const TimeSpan& timeSpan) + { + _vTimeSpans.push_back(TimeSpan(timeSpan)); + } + + const vector& GetTimeSpans() const { return _vTimeSpans; } + + void SetProfileOnly(bool b) { _fProfileOnly = b; } + bool GetProfileOnly() const { return _fProfileOnly; } + + void SetVerbose(bool b) { _fVerbose = b; } + bool GetVerbose() const { return _fVerbose; } + + void SetVerboseStats(bool b) { _fVerboseStats = b; } + bool GetVerboseStats() const { return _fVerboseStats; } + + void SetProgress(DWORD dwProgress) { _dwProgress = dwProgress; } + DWORD GetProgress() const { return _dwProgress; } + + void SetCmdLine(string sCmdLine) { _sCmdLine = sCmdLine; } + string GetCmdLine() const { return _sCmdLine; }; + + void SetResultsFormat(ResultsFormat format) { _resultsFormat = format; } + ResultsFormat GetResultsFormat() const { return _resultsFormat; } + + void SetPrecreateFiles(PrecreateFiles c) { _precreateFiles = c; } + PrecreateFiles GetPrecreateFiles() const { return _precreateFiles; } + + //ETW + void SetEtwEnabled(bool b) { _fEtwEnabled = b; } + void SetEtwProcess(bool b) { _fEtwProcess = b; } + void SetEtwThread(bool b) { _fEtwThread = b; } + void SetEtwImageLoad(bool b) { _fEtwImageLoad = b; } + void SetEtwDiskIO(bool b) { _fEtwDiskIO = b; } + void SetEtwMemoryPageFaults(bool b) { _fEtwMemoryPageFaults = b; } + void SetEtwMemoryHardFaults(bool b) { _fEtwMemoryHardFaults = b; } + void SetEtwNetwork(bool b) { _fEtwNetwork = b; } + void SetEtwRegistry(bool b) { _fEtwRegistry = b; } + void SetEtwUsePagedMemory(bool b) { _fEtwUsePagedMemory = b; } + void SetEtwUsePerfTimer(bool b) { _fEtwUsePerfTimer = b; } + void SetEtwUseSystemTimer(bool b) { _fEtwUseSystemTimer = b; } + void SetEtwUseCyclesCounter(bool b) { _fEtwUseCyclesCounter = b; } + + bool GetEtwEnabled() const { return _fEtwEnabled; } + bool GetEtwProcess() const { return _fEtwProcess; } + bool GetEtwThread() const { return _fEtwThread; } + bool GetEtwImageLoad() const { return _fEtwImageLoad; } + bool GetEtwDiskIO() const { return _fEtwDiskIO; } + bool GetEtwMemoryPageFaults() const { return _fEtwMemoryPageFaults; } + bool GetEtwMemoryHardFaults() const { return _fEtwMemoryHardFaults; } + bool GetEtwNetwork() const { return _fEtwNetwork; } + bool GetEtwRegistry() const { return _fEtwRegistry; } + bool GetEtwUsePagedMemory() const { return _fEtwUsePagedMemory; } + bool GetEtwUsePerfTimer() const { return _fEtwUsePerfTimer; } + bool GetEtwUseSystemTimer() const { return _fEtwUseSystemTimer; } + bool GetEtwUseCyclesCounter() const { return _fEtwUseCyclesCounter; } + + string GetXml(UINT32 indent) const; + bool Validate(bool fSingleSpec, SystemInformation *pSystem = nullptr) const; + void MarkFilesAsPrecreated(const vector vFiles); + +private: + Profile(const Profile& T); + + vector_vTimeSpans; + bool _fVerbose; + bool _fVerboseStats; + bool _fProfileOnly; + DWORD _dwProgress; + string _sCmdLine; + ResultsFormat _resultsFormat; + PrecreateFiles _precreateFiles; + + //ETW + bool _fEtwEnabled; + bool _fEtwProcess; + bool _fEtwThread; + bool _fEtwImageLoad; + bool _fEtwDiskIO; + bool _fEtwMemoryPageFaults; + bool _fEtwMemoryHardFaults; + bool _fEtwNetwork; + bool _fEtwRegistry; + bool _fEtwUsePagedMemory; + bool _fEtwUsePerfTimer; + bool _fEtwUseSystemTimer; + bool _fEtwUseCyclesCounter; + + friend class UnitTests::ProfileUnitTests; +}; + +class IORequest +{ +public: + IORequest(Random *pRand) : + _ioType(IOOperation::ReadIO), + _pRand(pRand), + _iCurrentTarget(0), + _ullStartTime(0), + _ulRequestIndex(0xFFFFFFFF), + _ullTotalWeight(0), + _fEqualWeights(true), + _ActivityId() + { + memset(&_overlapped, 0, sizeof(OVERLAPPED)); + } + + static IORequest *OverlappedToIORequest(OVERLAPPED *pOverlapped) + { + return CONTAINING_RECORD(pOverlapped, IORequest, _overlapped); + } + + OVERLAPPED *GetOverlapped() { return &_overlapped; } + + void AddTarget(Target *pTarget, UINT32 ulWeight) + { + _vTargets.push_back(pTarget); + _vulTargetWeights.push_back(ulWeight); + _ullTotalWeight += ulWeight; + + if (ulWeight != _vulTargetWeights[0]) { + _fEqualWeights = false; + } + } + + Target *GetCurrentTarget() { return _vTargets[_iCurrentTarget]; } + size_t GetCurrentTargetIndex() { return _iCurrentTarget; } + + Target *GetNextTarget() + { + UINT64 ullWeight; + + if (_vTargets.size() == 1) { + _iCurrentTarget = 0; + } + else if (_fEqualWeights) { + _iCurrentTarget = _pRand->Rand32() % _vTargets.size(); + } + else { + ullWeight = _pRand->Rand64() % _ullTotalWeight; + + for (size_t iTarget = 0; iTarget < _vTargets.size(); iTarget++) { + if (ullWeight < _vulTargetWeights[iTarget]) { + _iCurrentTarget = iTarget; + break; + } + + ullWeight -= _vulTargetWeights[iTarget]; + } + } + + return GetCurrentTarget(); + } + + void SetIoType(IOOperation ioType) { _ioType = ioType; } + IOOperation GetIoType() const { return _ioType; } + + void SetStartTime(UINT64 ullStartTime) { _ullStartTime = ullStartTime; } + UINT64 GetStartTime() const { return _ullStartTime; } + + void SetRequestIndex(UINT32 ulRequestIndex) { _ulRequestIndex = ulRequestIndex; } + UINT32 GetRequestIndex() const { return _ulRequestIndex; } + + void SetActivityId(GUID ActivityId) { _ActivityId = ActivityId; } + GUID GetActivityId() const { return _ActivityId; } + +private: + OVERLAPPED _overlapped; + vector _vTargets; + vector _vulTargetWeights; + UINT64 _ullTotalWeight; + bool _fEqualWeights; + Random *_pRand; + size_t _iCurrentTarget; + IOOperation _ioType; + UINT64 _ullStartTime; + UINT32 _ulRequestIndex; + GUID _ActivityId; +}; + +typedef struct _ACTIVITY_ID { + UINT32 Thread; + UINT32 Reserved; + UINT64 Count; +} ACTIVITY_ID; + +C_ASSERT(sizeof(ACTIVITY_ID) == sizeof(GUID)); + +// Forward declaration +class ThreadTargetState; + +class ThreadParameters +{ +public: + ThreadParameters() : + pProfile(nullptr), + pTimeSpan(nullptr), + pullSharedSequentialOffsets(nullptr), + ulRandSeed(0), + ulThreadNo(0), + ulRelativeThreadNo(0) + { + } + + const Profile *pProfile; + const TimeSpan *pTimeSpan; + + vector vTargets; + vector vTargetStates; + vector vhTargets; + + vector vulReadBufferSize; + vector vpDataBuffers; + vector vIORequest; + vector vThroughputMeters; + + // For interlocked sequential access (-si): + // Pointers to offsets shared between threads, incremented with an interlocked op + UINT64* pullSharedSequentialOffsets; + + Random *pRand; + + UINT32 ulRandSeed; + UINT32 ulThreadNo; + UINT32 ulRelativeThreadNo; + + // accounting + volatile bool *pfAccountingOn; + PUINT64 pullStartTime; + ThreadResults *pResults; + + //progress dots + DWORD dwIOCnt; + + //group affinity + WORD wGroupNum; + DWORD bProcNum; + + HANDLE hStartEvent; + + // TODO: check how it's used + HANDLE hEndEvent; //used only in case of completion routines (not for IO Completion Ports) + + bool AllocateAndFillBufferForTarget(const Target& target); + BYTE* GetReadBuffer(size_t iTarget, size_t iRequest); + BYTE* GetWriteBuffer(size_t iTarget, size_t iRequest); + DWORD GetTotalRequestCount() const; + bool InitializeMappedViewForTarget(Target& target, DWORD DesiredAccess); + + GUID NextActivityId() + { + GUID ActivityId; + ACTIVITY_ID* ActivityGuid = (ACTIVITY_ID*)&ActivityId; + + ActivityGuid->Thread = ulThreadNo; + ActivityGuid->Reserved = 0; + // The count is byte swapped so it's understandable in a trace. + ActivityGuid->Count = _byteswap_uint64(++_ullActivityCount); + + return ActivityId; + } + +private: + ThreadParameters(const ThreadParameters& T); + UINT64 _ullActivityCount; +}; + +class ThreadTargetState +{ + public: + + ThreadTargetState( + const ThreadParameters *pTp, + size_t iTarget, + UINT64 targetSize + ) : + _tp(pTp), + _target(&_tp->vTargets[iTarget]), + _targetSize(targetSize), + _mode(_target->GetIOMode()), + + _nextSeqOffset(0), + _lastIO(IOOperation::Unknown), + _sharedSeqOffset(nullptr), + _ioDistributionSpan(100) + { + // + // Now calculate the maximum base-relative file offset that IO can be issued at. + // + // Trim by max file size limit, and reduce by base file offset. + // + + if (_target->GetMaxFileSize()) + { + _relTargetSize = _targetSize > _target->GetMaxFileSize() ? _target->GetMaxFileSize() : _targetSize; + } + else + { + _relTargetSize = _targetSize; + } + + _relTargetSize -= _target->GetBaseFileOffsetInBytes(); + + // + // Align relative to the maximum offset at which aligned IO could be issued at. + // + + _relTargetSizeAligned = _relTargetSize - _target->GetBlockSizeInBytes(); + _relTargetSizeAligned -= _relTargetSizeAligned % _target->GetBlockAlignmentInBytes(); + _relTargetSizeAligned += _target->GetBlockAlignmentInBytes(); + + // Grab the shared sequential pointer if this is interlocked. + + if (_mode == IOMode::InterlockedSequential) + { + assert(_tp->pullSharedSequentialOffsets != nullptr); + _sharedSeqOffset = &_tp->pullSharedSequentialOffsets[iTarget]; + } + + // Convert and finalize the random distribution stated in the target using final bounds. + + switch (_target->GetDistributionType()) + { + case DistributionType::Percent: + { + UINT32 ioCarry = 0; + + for (auto& r : _target->GetDistributionRange()) + { + // + // The basic premise is to align the range's bounds to discover whether there are + // any aligned offsets within it. To do this we align DOWN. This moves the adjacent + // end of this range and base of the next in lockstep. + // + // There are two basic branches and three subcases in each: + // + // * aligned base + // * unaligned base + // * and within each + // * aligned end + // * unaligned end in same alignment unit + // * unaligned end in next/following alignment unit + // + // * aligned/aligned will not move b/e, there will be a positive range + // * aligned/unaligned-next will move e in step with the following b + // and there will be a positive range + // * aligned/unaligned-same will result in b=e after aligning; IO at b is + // the only possible IO + // + // Unaligned base is more interesting due to degenerate spans, spans where the + // mimimum %range is smaller than the block alignment. For instance, a 100KiB target + // with a 4K alignment has a 1%/1KB minimum and may create these cases. + // + // * unaligned/aligned aligns base (down) and there is a positive range + // * unaligned/unaligned-next aligns both down and there is a positive range + // * unaligned/unaligned-same has no aligned offset in the range; we can detect + // this by aligning e first and seeing if it is less than unaligned b. there + // are two subcases: + // * if the prior range is of zero length, we roll this range's IO% onto it - + // this combines two or more adjacent degenerate spans + // * if it was not of zero length, we roll over the IO% to the next/last range + // + // Now, in the cases where we have a positive range we may still find our aligned + // base is the same as the prior range - the prior was degenerate and the current + // is not. In this case we need to round our base up so that we do not share a base. + // We may then find that our rounded up base makes us degenerate and ... roll over. + // + // Note that this is a closed/open interval. The end offset is NOT a member of this + // range. Consider an 8KiB file divided 50:50 into two 4KB ranges. The first range is + // [0,4KB) and the second is [4KB, 8KB). The IO at offset 4KB belongs to the second + // range, not the first. + // + + // + // Skip holes. These have the effect of excluding a range of the target by way of + // zero IO will be issued to them; the resulting range is still IO 0-100%. + // + + if (!r._span) { + continue; + } + + UINT64 b, e; + + b = ((r._dst.first * _relTargetSizeAligned) / 100); + // guarantee end (don't lose it in integer math) + if (r._dst.first + r._dst.second == 100) + { + e = _relTargetSizeAligned; + } + else + { + e = b + ((r._dst.second * _relTargetSizeAligned) / 100); + } + + e = ROUND_DOWN(e, _target->GetBlockAlignmentInBytes()); + + // unaligned/unaligned-same + // carryover IO% to next/last range + if (e < b) + { + // is the prior range degenerate? + // if so, extend its IO% + // note that this cannot happen for the first range, so there + // will always be a range to look at. + if (_vDistributionRange.rbegin()->_dst.first == e) + { + _vDistributionRange.rbegin()->_span += r._span; + } + // carry over to next + else + { + ioCarry = r._span; + } + + continue; + } + + b = ROUND_DOWN(b, _target->GetBlockAlignmentInBytes()); + + // Now if b < e (a positive range) we may discover we're adjacent + // to a degenerate range. This is the case of re-aligning b up. + // Note that the degenerate range logically rounds up - this does + // not affect operation, but presents the correct appearance of a + // closed/open interval with respect to the subsequent range. + // Case: -rdpct10/1:10/1 + // + // It is possible b == e: this is a case where b was already aligned + // and we're placing a normal degenerate span. No special handling. + + if (b < e && + _vDistributionRange.size() && + _vDistributionRange.rbegin()->_dst.first == b) + { + + b += _target->GetBlockAlignmentInBytes(); + _vDistributionRange.rbegin()->_dst.second += _target->GetBlockAlignmentInBytes(); + + // Now there are two degenerate cases to manage. + + // if we're dealing with a degenerate at the tail, allow carryover + if (b == _relTargetSizeAligned) + { + ioCarry = r._span; + continue; + } + + // otherwise, if the range became degenerate in the up-alignment, it must + // combine with the prior degenerate since its logical range is included + // with it. + if (b == e) + { + _vDistributionRange.rbegin()->_span += r._span; + continue; + } + + // fall through to place re-aligned b/e (non degenerate) + } + + // prefer to roll IO% to the smaller of prior range/this range + if (ioCarry && + _vDistributionRange.rbegin()->_span < r._span) + { + _vDistributionRange.rbegin()->_span += ioCarry; + ioCarry = 0; + } + + _vDistributionRange.emplace_back( + r._src - ioCarry, + r._span + ioCarry, + make_pair(b, e - b)); + + ioCarry = 0; + } + + // Apply trailing carryover to final range, extending it. + // Guarantee target range extends to aligned size - rollover is always from + // a degenerate range we could not place directly. We need to gross up the + // actual tail so that the effective correctly spans the open/closed interval + // to target size. + // -rdpct10/96:10/3:80/1 - the last range is degenerate and needs to roll. + if (ioCarry) + { + DistributionRange& last = *_vDistributionRange.rbegin(); + + last._span += ioCarry; + last._dst.second = _relTargetSizeAligned - last._dst.first; + } + } + break; + + case DistributionType::Absolute: + { + UINT32 ioUsed = 0; + + for (auto& r : _target->GetDistributionRange()) + { + // + // The premise for absolute distributions is similar but without the complication of + // degenerate ranges. The offsets are provided and we only need to push the last to + // the end of the range if it was left open (its length is zero). They do not need to + // be aligned, similar to -T thread stride - this is the caller's dilemma. We already + // know by validation that IO can be issued in the range since any absolute distribution + // with a range < block size would have been rejected. + // + // If the range was not left open we have two cases: + // + // * the end is within the final range + // * the end is past it + // + // If the end is within the final range that will again be the caller's dilemma, we'll + // simply trim the length of that range. If it is past it, we will discard the trailing + // ranges and trim the maximum IO% so that they become a proportional specification of the + // IO. For instance, if a 10/10/80 winds up with the 80% not addressable in the file, the + // maximum IO% trims to 20 and it logically becomes a 50:50 split (10:10). + // + + UINT64 l; + + // + // Skip holes. These have the effect of excluding a range of the target by way of + // zero IO will be issued to them; the resulting range is still IO 0-100%. + // + + if (!r._span) { + continue; + } + + // beyond end? done, with whatever tail IO% not seen + if (r._dst.first >= _relTargetSize) + { + break; + } + // open end or spans end? - set to aligned remainder + else if (r._dst.second == 0 || + r._dst.first + r._dst.second > _relTargetSize) + { + // ensure tail can accept IO by blocksize - caller has stated this is aligned by + // its specification + l = _relTargetSize - r._dst.first; + + if (l < _target->GetBlockSizeInBytes()) + { + break; + } + } + else + { + l = r._dst.second; + } + + _vDistributionRange.emplace_back( + r._src, + r._span, + make_pair(r._dst.first, l)); + + ioUsed += r._span; + } + + // reduce the IO distribution to that specified by the ranges consumed. + // it is still logically 100%, simply over a range of less than 0-100. + _ioDistributionSpan = ioUsed; + } + break; + + // none + default: + break; + } + + Reset(); + } + + // + // Reset IO pointer/type state to initial conditions. + // + + VOID Reset() + { + // + // Now set the (base-relative) initial sequential offset + // * sequential: based on thread stride + // * mixed: randomized starting position + // + // Note this is repeated for ParallelAsync initialization since sequential offset is in the IO request there. + // + + switch (_mode) + { + case IOMode::Sequential: + _nextSeqOffset = _target->GetThreadBaseRelativeOffsetInBytes(_tp->ulRelativeThreadNo); + break; + + case IOMode::Mixed: + _nextSeqOffset = NextRelativeRandomOffset(); + break; + + default: + break; + } + + _lastIO = NextIOType(true); + } + + // + // Validate whether this thread can start IO given thread stride and file size. + // + + bool CanStart() + { + UINT64 startingFileOffset = _target->GetThreadBaseRelativeOffsetInBytes(_tp->ulRelativeThreadNo); + + if (startingFileOffset + _target->GetBlockSizeInBytes() > _relTargetSize) + { + return false; + } + + return true; + } + + UINT64 TargetSize() + { + return _targetSize; + } + + VOID InitializeParallelAsyncIORequest(IORequest& ioRequest) const + { + ULARGE_INTEGER initialOffset; + + // + // Bias backwards by one IO so that this functions as the last-IO-issued pointer. + // It will be incremented to the expected first offset. Note: absolute offset. + // + + initialOffset.QuadPart = _target->GetThreadBaseFileOffsetInBytes(_tp->ulRelativeThreadNo) - _target->GetBlockAlignmentInBytes(); + + ioRequest.GetOverlapped()->Offset = initialOffset.LowPart; + ioRequest.GetOverlapped()->OffsetHigh = initialOffset.HighPart; + } + + UINT64 NextRelativeSeqOffset() + { + UINT64 nextOffset; + + nextOffset = _nextSeqOffset; + + // Wrap? + + if (nextOffset + _target->GetBlockSizeInBytes() > _relTargetSize) { + nextOffset = _target->GetThreadBaseRelativeOffsetInBytes(_tp->ulRelativeThreadNo) % _target->GetBlockAlignmentInBytes(); + } + + _nextSeqOffset = nextOffset + _target->GetBlockAlignmentInBytes(); + + return nextOffset; + } + + UINT64 NextRelativeInterlockedSeqOffset() + { + UINT64 nextOffset; + + // advance shared and rewind to get offset to use + nextOffset = InterlockedAdd64((PLONG64) _sharedSeqOffset, _target->GetBlockAlignmentInBytes()); + nextOffset -= _target->GetBlockAlignmentInBytes(); + + nextOffset %= _relTargetSizeAligned; + return nextOffset; + } + + UINT64 NextRelativeParaSeqOffset(IORequest& ioRequest) + { + ULARGE_INTEGER nextOffset; + + // + // Note: parallel seq differs from the other sequential cases in that the + // pointer indicates the prior IO, not the offset to issue the current at. + // Advance it. + // + + nextOffset.LowPart = ioRequest.GetOverlapped()->Offset; + nextOffset.HighPart = ioRequest.GetOverlapped()->OffsetHigh; + nextOffset.QuadPart -= _target->GetBaseFileOffsetInBytes(); // absolute -> relative + nextOffset.QuadPart += _target->GetBlockAlignmentInBytes(); // advance past last IO (!) + + // Wrap? + + if (nextOffset.QuadPart + _target->GetBlockSizeInBytes() > _relTargetSize) { + nextOffset.QuadPart = _target->GetThreadBaseRelativeOffsetInBytes(_tp->ulRelativeThreadNo) % _target->GetBlockAlignmentInBytes(); + } + + return nextOffset.QuadPart; + } + + UINT64 NextRelativeRandomOffset() const + { + UINT64 nextOffset = _tp->pRand->Rand64(); + nextOffset -= nextOffset % _target->GetBlockAlignmentInBytes(); + + // + // With a distribution we choose by bucket. Note the bucket is already aligned. + // + + if (_vDistributionRange.size()) + { + auto r = DistributionRange::find(_vDistributionRange, _tp->pRand->Rand64() % _ioDistributionSpan); + nextOffset %= r->_dst.second; // trim to range length (already aligned) + nextOffset += r->_dst.first; // bump by range base + } + // Full width. + else + { + nextOffset %= _relTargetSizeAligned; + } + + return nextOffset; + } + + UINT64 NextRelativeMixedOffset(bool& fRandom) + { + ULARGE_INTEGER nextOffset; + + fRandom = Util::BooleanRatio(_tp->pRand, _target->GetRandomRatio()); + + if (fRandom) + { + nextOffset.QuadPart = NextRelativeRandomOffset(); + _nextSeqOffset = nextOffset.QuadPart + _target->GetBlockAlignmentInBytes(); + return nextOffset.QuadPart; + } + + return NextRelativeSeqOffset(); + } + + IOOperation NextIOType(bool newType) + { + IOOperation ioType; + + if (_target->GetWriteRatio() == 0) + { + ioType = IOOperation::ReadIO; + } + else if (_target->GetWriteRatio() == 100) + { + ioType = IOOperation::WriteIO; + } + else if (_mode == IOMode::Mixed && !newType) + { + // repeat last IO if not needing a new choice (e.g., random) + ioType = _lastIO; + } + else + { + ioType = Util::BooleanRatio(_tp->pRand, _target->GetWriteRatio()) ? IOOperation::WriteIO : IOOperation::ReadIO; + _lastIO = ioType; + } + + return ioType; + } + + void NextIORequest(IORequest &ioRequest) + { + bool fRandom = false; + ULARGE_INTEGER nextOffset = { 0 }; + + switch (_mode) + { + case IOMode::Sequential: + nextOffset.QuadPart = NextRelativeSeqOffset(); + break; + + case IOMode::InterlockedSequential: + nextOffset.QuadPart = NextRelativeInterlockedSeqOffset(); + break; + + case IOMode::ParallelAsync: + nextOffset.QuadPart = NextRelativeParaSeqOffset(ioRequest); + break; + + case IOMode::Mixed: + nextOffset.QuadPart = NextRelativeMixedOffset(fRandom); + break; + + case IOMode::Random: + nextOffset.QuadPart = NextRelativeRandomOffset(); + fRandom = true; + break; + + default: + assert(false); + } + + // + // Convert relative offset to absolute. + // + + nextOffset.QuadPart += _target->GetBaseFileOffsetInBytes(); + + // + // Move offset into the IO request and decide what IO type will be issued. + // Mixed which has chosen sequential will repeat last IO type so that seq + // runs are homogeneous. + // + + ioRequest.GetOverlapped()->Offset = nextOffset.LowPart; + ioRequest.GetOverlapped()->OffsetHigh = nextOffset.HighPart; + ioRequest.SetIoType(NextIOType(fRandom)); + } + + private: + + const ThreadParameters *_tp; + const Target *_target; + const UINT64 _targetSize; // unmodified absolute target size + const IOMode _mode; // thread's mode of IO operations to this target (Random, Sequential, etc.) + + // + // Offsets/sizes are zero-based relative to target base offset, not absolute file offset. + // Relative size is trimmed with respect to block alignment, if specified. + // + + UINT64 _relTargetSize; // relative target size for IO v. base/max + UINT64 _relTargetSizeAligned; // relative target size for zero-base aligned IO (applies to: Random, InterlockedSequential) + UINT64 _nextSeqOffset; // next IO offset to issue sequential IO at (applies to: Sequential & Mixed) + volatile UINT64 *_sharedSeqOffset; // ... for interlocked IO (applies to: InterlockedSequential) + IOOperation _lastIO; // last IO type (applies to: Mixed) + +public: + + // + // Random distribution (stated in absolute offsets of target) + // + + vector _vDistributionRange; + UINT32 _ioDistributionSpan; + + friend class UnitTests::IORequestGeneratorUnitTests; +}; + +class IResultParser +{ +public: + virtual string ParseResults(const Profile& profile, const SystemInformation& system, vector vResults) = 0; + virtual string ParseProfile(const Profile& profile) = 0; + /// for CrystalDiskMark + virtual int GetTotalScore() = 0; + virtual double GetAverageLatency() = 0; +}; + +class EtwResultParser +{ +public: + static void ParseResults(vector vResults); + +private: + static void _WriteResults(IOOperation type, const TargetResults& targetResults, size_t uThread); +}; diff --git a/CristalDiskMark/source/diskspd22/Common/Histogram.h b/CristalDiskMark/source/diskspd22/Common/Histogram.h new file mode 100644 index 0000000..abe5d2b --- /dev/null +++ b/CristalDiskMark/source/diskspd22/Common/Histogram.h @@ -0,0 +1,330 @@ +/* + +DISKSPD + +Copyright(c) Microsoft Corporation +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#pragma once + +#include +#include +#include +#include +#include +#include + +// Plain min/max macros from common headers will interfere with std::numeric_limits + +#pragma push_macro("min") +#pragma push_macro("max") +#undef min +#undef max + +template +class Histogram +{ +private: + + mutable std::unordered_map _data; + mutable unsigned _samples; + + mutable std::map _sdata; + mutable unsigned _ssamples; + + // Save most recent percentile/iterator/nth-distance query. If the next is strictly >= it allows + // an efficient forward iteration through an ascending set of queries. + + mutable double _lastptile; + mutable unsigned _lastptilen; + mutable decltype(_sdata.cbegin()) _lastptilepos; + + // A histogram starts writable/unsealed and automatically seals after the first read operation. + // Subsequent writes which add data restart from empty. + + void _SealData() const + { + if (!_data.empty()) + { + _sdata.clear(); + + _sdata = std::map(_data.cbegin(), _data.cend()); + _ssamples = _samples; + + // invalid ptile > 1; first ptile query will initialize + _lastptile = 1.1; + + _data.clear(); + _samples = 0; + } + } + +public: + + Histogram() + : _samples(0), + _ssamples(0) + {} + + void Clear() + { + _data.clear(); + _samples = 0; + + _sdata.clear(); + _ssamples = 0; + + } + + void Add(T v) + { + _data[v]++; + _samples++; + } + + void Merge(const Histogram &other) + { + for (auto i : other._data) + { + _data[ i.first ] += i.second; + } + + _samples += other._samples; + } + + T GetMin() const + { + _SealData(); + + // Default low if empty + if (!_ssamples) + { + return std::numeric_limits::min(); + } + + return _sdata.cbegin()->first; + } + + T GetMax() const + { + _SealData(); + + // Default low if empty + if (!_ssamples) + { + return std::numeric_limits::min(); + } + + return _sdata.crbegin()->first; + } + + unsigned GetSampleBuckets() const + { + return (unsigned) (_samples ? _data.size() : _sdata.size()); + } + + unsigned GetSampleSize() const + { + return _samples ? _samples : _ssamples; + } + + T GetPercentile(double p) const + { + if ((p < 0.0) || (p > 1.0)) + { + throw std::invalid_argument("Percentile must be >= 0 and <= 1"); + } + + _SealData(); + + // Default low if empty + if (!_ssamples) + { + return std::numeric_limits::min(); + } + + const double target = p * _ssamples; + + // Default to beginning; n is the number of samples iterated over so far + unsigned n = 0; + auto pos = _sdata.cbegin(); + + // Resume from last? + if (p >= _lastptile) + { + n = _lastptilen; + pos = _lastptilepos; + } + + while (pos != _sdata.cend()) + { + if (n + pos->second >= target) + { + // Save position. Note the pre-incremented distance through the histogram + // must be saved in case next is still in the same bucket. + _lastptile = p; + _lastptilen = n; + _lastptilepos = pos; + + return pos->first; + } + + n += pos->second; + ++pos; + } + + throw std::overflow_error("overran end trying to find percentile"); + } + + T GetPercentile(int p) const + { + return GetPercentile(static_cast(p) / 100); + } + + T GetMedian() const + { + return GetPercentile(0.5); + } + + double GetStdDev() const { return GetStandardDeviation(); } + double GetAvg() const { return GetMean(); } + + double GetMean() const + { + _SealData(); + + // Default low if empty + if (!_ssamples) + { + return std::numeric_limits::min(); + } + + double sum(0); + + for (const auto i : _sdata) + { + double bucket_val = + static_cast(i.first) * i.second / _ssamples; + + if (sum + bucket_val < 0) + { + throw std::overflow_error("while trying to accumulate sum"); + } + + sum += bucket_val; + } + + return sum; + } + + double GetStandardDeviation() const + { + double mean(GetMean()); + double ssd(0); + + for (const auto i : _sdata) + { + double dev = static_cast(i.first) - mean; + double sqdev = dev * dev; + ssd += i.second * sqdev; + } + + return sqrt(ssd / _ssamples); + } + + std::string GetHistogramCsv(const unsigned bins) const + { + return GetHistogramCsv(bins, GetMin(), GetMax()); + } + + std::string GetHistogramCsv(const unsigned bins, const T LOW, const T HIGH) const + { + _SealData(); + + // ISSUE-REVIEW + // Currently bins are defined as strictly less-than + // their upper limit, with the exception of the last + // bin. Otherwise where would I put the max value? + const double binSize = static_cast((HIGH - LOW) / bins); + double limit = static_cast(LOW); + + std::ostringstream os; + os.precision(std::numeric_limits::digits10); + + auto pos = _sdata.cbegin(); + unsigned cumulative = 0; + + for (unsigned bin = 1; bin <= bins; ++bin) + { + unsigned count = 0; + limit += binSize; + + while (pos != _sdata.end() && + (pos->first < limit || bin == bins)) + { + count += pos->second; + ++pos; + } + + cumulative += count; + + os << limit << "," << count << "," << cumulative << std::endl; + } + + return os.str(); + } + + std::string GetRawCsv() const + { + _SealData(); + + std::ostringstream os; + os.precision(std::numeric_limits::digits10); + + for (const auto i : _sdata) + { + os << i.first << "," << i.second << std::endl; + } + + return os.str(); + } + + std::string GetRaw() const + { + _SealData(); + + std::ostringstream os; + + for (const auto i : _sdata) + { + os << i.second << " " << i.first << std::endl; + } + + return os.str(); + } +}; + +#pragma pop_macro("min") +#pragma pop_macro("max") diff --git a/CristalDiskMark/source/diskspd22/Common/IORequestGenerator.h b/CristalDiskMark/source/diskspd22/Common/IORequestGenerator.h new file mode 100644 index 0000000..550a579 --- /dev/null +++ b/CristalDiskMark/source/diskspd22/Common/IORequestGenerator.h @@ -0,0 +1,84 @@ +/* + +DISKSPD + +Copyright(c) Microsoft Corporation +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#pragma once +#define INITGUID //Include this #define to use SystemTraceControlGuid in Evntrace.h. +#include //ETW +#include //ntdll.dll + + +void PrintError(const char *format, ...); +namespace UnitTests +{ + class IORequestGeneratorUnitTests; +} + +class IORequestGenerator +{ +public: + IORequestGenerator() : + _hNTDLL(nullptr) + { + + } + + //bool GenerateRequests(Profile& profile, IResultParser& resultParser, struct Synchronization *pSynch); + /// for CrystalDiskMark + bool GenerateRequests(Profile& profile, IResultParser& resultParser, struct Synchronization* pSynch, int* totalScore, double* averageLatency); + +private: + + struct CreateFileParameters + { + string sPath; + UINT64 ullFileSize; + bool fZeroWriteBuffers; + }; + + bool _GenerateRequestsForTimeSpan(const Profile& profile, const TimeSpan& timeSpan, Results& results, struct Synchronization *pSynch); + void _AbortWorkerThreads(HANDLE hStartEvent, vector& vhThreads) const; + void _CloseOpenFiles(vector& vhFiles) const; + DWORD _CreateDirectoryPath(const char *path) const; + bool _CreateFile(UINT64 ullFileSize, const char *pszFilename, bool fZeroBuffers, bool fVerbose) const; + bool _GetActiveGroupsAndProcs() const; + struct ETWSessionInfo _GetResultETWSession(const EVENT_TRACE_PROPERTIES *pTraceProperties) const; + bool _GetSystemPerfInfo(vector& vSPPI, bool fVerbose) const; + void _InitializeGlobalParameters(); + bool _LoadDLLs(); + bool _StopETW(bool fUseETW, TRACEHANDLE hTraceSession) const; + void _TerminateWorkerThreads(vector& vhThreads) const; + bool _ValidateProfile(const Profile& profile) const; + vector _GetFilesToPrecreate(const Profile& profile) const; + void _MarkFilesAsCreated(Profile& profile, const vector& vFiles) const; + bool _PrecreateFiles(Profile& profile) const; + + HINSTANCE volatile _hNTDLL; //handle to ntdll.dll + + friend class UnitTests::IORequestGeneratorUnitTests; +}; diff --git a/CristalDiskMark/source/diskspd22/Common/IoBucketizer.cpp b/CristalDiskMark/source/diskspd22/Common/IoBucketizer.cpp new file mode 100644 index 0000000..672eb54 --- /dev/null +++ b/CristalDiskMark/source/diskspd22/Common/IoBucketizer.cpp @@ -0,0 +1,228 @@ +/* + +DISKSPD + +Copyright(c) Microsoft Corporation +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#include "IoBucketizer.h" +#include + +/* +Calculating stddev using an online algorithm: +avg = sum(1..n, a[n]) / n +stddev = sqrt(sum(1..n, (a[n] - avg)^2) / n) + = sqrt(sum(1..n, a[n]^2 - 2 * a[n] * avg + avg^2) / n) + = sqrt((sum(1..n, a[n]^2) - 2 * avg * sum(1..n, a[n]) + n * avg^2) / n) + = sqrt((sum(1..n, a[n]^2) - 2 * (sum(1..n, a[n]) / n) * sum(1..n, a[n]) + n * (sum(1..n], a[n]) / n)^2) / n) + = sqrt((sum(1..n, a[n]^2) - (2 / n) * sum(1..n, a[n])^2 + (1 / n) * sum(1..n, a[n])^2) / n) + = sqrt((sum(1..n, a[n]^2) - (1 / n) * sum(1..n, a[n])^2) / n) + +So if we track n, sum(a[n]) and sum(a[n]^2) we can calculate the stddev. This +is used to calculate the stddev of the latencies below. +*/ + +const unsigned __int64 INVALID_BUCKET_DURATION = 0; + +IoBucketizer::IoBucketizer() + : _bucketDuration(INVALID_BUCKET_DURATION), + _validBuckets(0), + _totalBuckets(0) +{} + +void IoBucketizer::Initialize(unsigned __int64 bucketDuration, size_t validBuckets) +{ + if (_bucketDuration != INVALID_BUCKET_DURATION) + { + throw std::runtime_error("IoBucketizer has already been initialized"); + } + if (bucketDuration == INVALID_BUCKET_DURATION) + { + throw std::invalid_argument("Bucket duration must be a positive integer"); + } + + _bucketDuration = bucketDuration; + _validBuckets = validBuckets; + _vBuckets.resize(_validBuckets); +} + +void IoBucketizer::Add(unsigned __int64 ioCompletionTime, double ioDuration) +{ + if (_bucketDuration == INVALID_BUCKET_DURATION) + { + throw std::runtime_error("IoBucketizer has not been initialized"); + } + + size_t bucketNumber = static_cast(ioCompletionTime / _bucketDuration); + _totalBuckets = bucketNumber + 1; + + if (bucketNumber >= _validBuckets) + { + return; + } + + _vBuckets[bucketNumber].lfSumDuration += ioDuration; + _vBuckets[bucketNumber].lfSumSqrDuration += ioDuration * ioDuration; + + if (_vBuckets[bucketNumber].ulCount == 0 || + ioDuration < _vBuckets[bucketNumber].lfMinDuration) + { + _vBuckets[bucketNumber].lfMinDuration = ioDuration; + } + if (_vBuckets[bucketNumber].ulCount == 0 || + ioDuration > _vBuckets[bucketNumber].lfMaxDuration) + { + _vBuckets[bucketNumber].lfMaxDuration = ioDuration; + } + + _vBuckets[bucketNumber].ulCount++; +} + +size_t IoBucketizer::GetNumberOfValidBuckets() const +{ + return (_totalBuckets > _validBuckets ? _validBuckets : _totalBuckets); +} + +unsigned int IoBucketizer::GetIoBucketCount(size_t bucketNumber) const +{ + if (bucketNumber < _validBuckets) + { + return _vBuckets[bucketNumber].ulCount; + } + + return 0; +} + +double IoBucketizer::GetIoBucketMinDurationUsec(size_t bucketNumber) const +{ + if (bucketNumber < _validBuckets) + { + return _vBuckets[bucketNumber].lfMinDuration; + } + + return 0; +} + +double IoBucketizer::GetIoBucketMaxDurationUsec(size_t bucketNumber) const +{ + if (bucketNumber < _validBuckets) + { + return _vBuckets[bucketNumber].lfMaxDuration; + } + + return 0; +} + +double IoBucketizer::GetIoBucketAvgDurationUsec(size_t bucketNumber) const +{ + if (bucketNumber < _validBuckets && _vBuckets[bucketNumber].ulCount != 0) + { + return _vBuckets[bucketNumber].lfSumDuration / static_cast(_vBuckets[bucketNumber].ulCount); + } + + return 0; +} + +double IoBucketizer::GetIoBucketDurationStdDevUsec(size_t bucketNumber) const +{ + if (bucketNumber < _validBuckets && _vBuckets[bucketNumber].ulCount != 0) + { + double sum_of_squares = _vBuckets[bucketNumber].lfSumSqrDuration; + double square_of_sum = _vBuckets[bucketNumber].lfSumDuration * _vBuckets[bucketNumber].lfSumDuration; + double count = static_cast(_vBuckets[bucketNumber].ulCount); + double square_stddev = (sum_of_squares - (square_of_sum / count)) / count; + + return sqrt(square_stddev); + } + + return 0; +} + +double IoBucketizer::_GetMeanIOPS() const +{ + size_t numBuckets = GetNumberOfValidBuckets(); + double sum = 0; + + for (size_t i = 0; i < numBuckets; i++) + { + sum += static_cast(_vBuckets[i].ulCount) / numBuckets; + } + + return sum; +} + +double IoBucketizer::GetStandardDeviationIOPS() const +{ + size_t numBuckets = GetNumberOfValidBuckets(); + + if(numBuckets == 0) + { + return 0.0; + } + + double mean = _GetMeanIOPS(); + double ssd = 0; + + for (size_t i = 0; i < numBuckets; i++) + { + double dev = static_cast(_vBuckets[i].ulCount) - mean; + double sqdev = dev*dev; + ssd += sqdev; + } + + return sqrt(ssd / numBuckets); +} + +void IoBucketizer::Merge(const IoBucketizer& other) +{ + if(other._vBuckets.size() > _vBuckets.size()) + { + _vBuckets.resize(other._vBuckets.size()); + } + for(size_t i = 0; i < other._vBuckets.size(); i++) + { + _vBuckets[i].ulCount += other._vBuckets[i].ulCount; + _vBuckets[i].lfSumDuration += other._vBuckets[i].lfSumDuration; + _vBuckets[i].lfSumSqrDuration += other._vBuckets[i].lfSumSqrDuration; + + if (i >= _validBuckets || + other._vBuckets[i].lfMinDuration < _vBuckets[i].lfMinDuration) + { + _vBuckets[i].lfMinDuration = other._vBuckets[i].lfMinDuration; + } + if (other._vBuckets[i].lfMaxDuration > _vBuckets[i].lfMaxDuration) + { + _vBuckets[i].lfMaxDuration = other._vBuckets[i].lfMaxDuration; + } + } + if (other._validBuckets > _validBuckets) + { + _validBuckets = other._validBuckets; + } + if (other._totalBuckets > _totalBuckets) + { + _totalBuckets = other._totalBuckets; + } +} diff --git a/CristalDiskMark/source/diskspd22/Common/IoBucketizer.h b/CristalDiskMark/source/diskspd22/Common/IoBucketizer.h new file mode 100644 index 0000000..6d501c4 --- /dev/null +++ b/CristalDiskMark/source/diskspd22/Common/IoBucketizer.h @@ -0,0 +1,73 @@ +/* + +DISKSPD + +Copyright(c) Microsoft Corporation +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#pragma once + +#include + +class IoBucketizer +{ +public: + IoBucketizer(); + void Initialize(unsigned __int64 bucketDuration, size_t validBuckets); + + size_t GetNumberOfValidBuckets() const; + unsigned int GetIoBucketCount(size_t bucketNumber) const; + double GetIoBucketMinDurationUsec(size_t bucketNumber) const; + double GetIoBucketMaxDurationUsec(size_t bucketNumber) const; + double GetIoBucketAvgDurationUsec(size_t bucketNumber) const; + double GetIoBucketDurationStdDevUsec(size_t bucketNumber) const; + void Add(unsigned __int64 ioCompletionTime, double ioDuration); + double GetStandardDeviationIOPS() const; + void Merge(const IoBucketizer& other); +private: + double _GetMeanIOPS() const; + + struct IoBucket { + IoBucket() : + ulCount(0), + lfMinDuration(0), + lfMaxDuration(0), + lfSumDuration(0), + lfSumSqrDuration(0) + { + } + + unsigned int ulCount; + double lfMinDuration; + double lfMaxDuration; + double lfSumDuration; + double lfSumSqrDuration; + }; + + unsigned __int64 _bucketDuration; + size_t _validBuckets; + size_t _totalBuckets; + std::vector _vBuckets; +}; diff --git a/CristalDiskMark/source/diskspd22/Common/OverlappedQueue.h b/CristalDiskMark/source/diskspd22/Common/OverlappedQueue.h new file mode 100644 index 0000000..622ac67 --- /dev/null +++ b/CristalDiskMark/source/diskspd22/Common/OverlappedQueue.h @@ -0,0 +1,50 @@ +/* + +DISKSPD + +Copyright(c) Microsoft Corporation +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#pragma once +#include + +// +// OverlappedQueue is a simple class that implements a queue for OVERLAPPED elements +// +class OverlappedQueue +{ +public: + OverlappedQueue(void); + + void Add(OVERLAPPED *pOverlapped); + bool IsEmpty(void) const; + OVERLAPPED * Remove(void); + size_t GetCount() const; + +private: + OVERLAPPED *_pHead; + OVERLAPPED *_pTail; + size_t _cItems; +}; \ No newline at end of file diff --git a/CristalDiskMark/source/diskspd22/Common/ResultParser.h b/CristalDiskMark/source/diskspd22/Common/ResultParser.h new file mode 100644 index 0000000..3015fab --- /dev/null +++ b/CristalDiskMark/source/diskspd22/Common/ResultParser.h @@ -0,0 +1,76 @@ +/* + +DISKSPD + +Copyright(c) Microsoft Corporation +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#pragma once +#include "Common.h" + +namespace UnitTests +{ + class ResultParserUnitTests; +} + +class ResultParser : public IResultParser +{ +public: + string ParseResults(const Profile& profile, const SystemInformation& system, vector vResults); + string ParseProfile(const Profile& profile); + + /// for CrystalDiskMark + int GetTotalScore(); + double GetAverageLatency(); + +private: + void _DisplayFileSize(UINT64 fsize, UINT32 align = 0); + void _DisplayETWSessionInfo(struct ETWSessionInfo sessionInfo); + void _DisplayETW(struct ETWMask ETWMask, struct ETWEventCounters EtwEventCounters); + void _Print(const char *format, ...); + void _PrintProfile(const Profile& profile); + void _PrintSystemInfo(const SystemInformation& system); + void _PrintCpuUtilization(const Results& results, const SystemInformation& system); + enum class _SectionEnum {TOTAL, READ, WRITE}; + void _PrintSectionFieldNames(const TimeSpan& timeSpan); + void _PrintSectionBorderLine(const TimeSpan& timeSpan); + void _PrintSection(_SectionEnum, const TimeSpan&, const Results&); + void _PrintLatencyPercentiles(const Results&); + void _PrintLatencyChart(const Histogram& readLatencyHistogram, + const Histogram& writeLatencyHistogram, + const Histogram& totalLatencyHistogram); + void _PrintTimeSpan(const TimeSpan &timeSpan); + void _PrintTarget(const Target &target, bool fUseThreadsPerFile, bool fUseRequestsPerFile, bool fCompletionRoutines); + void _PrintDistribution(DistributionType dT, const vector& v, char* spc); + void _PrintEffectiveDistributions(const Results& results); + void _PrintWaitStats(const Results& result); + + string _sResult; + /// for CrystalDiskMark + int _totalScore; + double _averageLatency; + + friend class UnitTests::ResultParserUnitTests; +}; \ No newline at end of file diff --git a/CristalDiskMark/source/diskspd22/Common/ThroughputMeter.h b/CristalDiskMark/source/diskspd22/Common/ThroughputMeter.h new file mode 100644 index 0000000..0375f05 --- /dev/null +++ b/CristalDiskMark/source/diskspd22/Common/ThroughputMeter.h @@ -0,0 +1,61 @@ +/* + +DISKSPD + +Copyright(c) Microsoft Corporation +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#pragma once +#include + +// ThroughputMeter class assists in metering out throughput over +// time. The meter is started by calling Start() with the throughput +// to be simulated. GetSleepTime() returns 0 when the next IO can be issued. +// Adjust() is called to notify the ThroughputMeter about how many bytes were read/written. +class ThroughputMeter +{ +public: + ThroughputMeter(void); + + bool IsRunning(void) const; + void Start(DWORD cBytesPerMillisecond, DWORD dwBlockSize, DWORD dwThinkTime, DWORD dwBurstSize); + DWORD GetSleepTime(void) const; + void Adjust(size_t cb); + +private: + DWORD _GetThrottleTime(void) const; + + bool _fRunning; // true = throughput monitoring is on + bool _fThrottle; // true = throttling is on + bool _fThink; // true = think time is enabled + ULONGLONG _cbCompleted; // completed IO + DWORD _cbBlockSize; + DWORD _cBytesPerMillisecond; // rate of throttling + ULONGLONG _ullStartTimestamp; + ULONGLONG _ullDelayUntil; // timestamp at which the next IO can be executed + DWORD _thinkTime; // time to sleep between burst of IOs + DWORD _burstSize; // number of IOs in a burst. meaningless if think time is zero + DWORD _cIO; // count of IOs in the current burst +}; \ No newline at end of file diff --git a/CristalDiskMark/source/diskspd22/Common/Version.h b/CristalDiskMark/source/diskspd22/Common/Version.h new file mode 100644 index 0000000..a04a6e9 --- /dev/null +++ b/CristalDiskMark/source/diskspd22/Common/Version.h @@ -0,0 +1,52 @@ +/* + +DISKSPD + +Copyright(c) Microsoft Corporation +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +// versioning material. for simplicity in consumption, please ensure that the date string +// parses via the System.Datetime constructor as follows (in Powershell): +// +// [datetime] "string" +// +// this should result in a valid System.Datetime object, rendered like: +// +// Monday, June 16, 2014 12:00:00 AM + +#define DISKSPD_RELEASE_TAG "" +#define DISKSPD_REVISION "" + +#define DISKSPD_MAJOR 2 +#define DISKSPD_MINOR 2 +#define DISKSPD_BUILD 0 +#define DISKSPD_QFE 0 + +#define DISKSPD_MAJORMINOR_VER_STR(x,y,z) #x "." #y "." #z +#define DISKSPD_MAJORMINOR_VERSION_STRING(x,y,z) DISKSPD_MAJORMINOR_VER_STR(x,y,z) +#define DISKSPD_MAJORMINOR_VERSION_STR DISKSPD_MAJORMINOR_VERSION_STRING(DISKSPD_MAJOR, DISKSPD_MINOR, DISKSPD_BUILD) + +#define DISKSPD_NUMERIC_VERSION_STRING DISKSPD_MAJORMINOR_VERSION_STR DISKSPD_REVISION DISKSPD_RELEASE_TAG +#define DISKSPD_DATE_VERSION_STRING "2024/6/3" diff --git a/CristalDiskMark/source/diskspd22/Common/XmlProfileParser.h b/CristalDiskMark/source/diskspd22/Common/XmlProfileParser.h new file mode 100644 index 0000000..0d1ab3e --- /dev/null +++ b/CristalDiskMark/source/diskspd22/Common/XmlProfileParser.h @@ -0,0 +1,65 @@ +/* + +DISKSPD + +Copyright(c) Microsoft Corporation +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#pragma once +#include +#include "Common.h" + +class XmlProfileParser +{ +public: + bool ParseFile(const char *pszPath, Profile *pProfile, vector *pvSubstTargets, HMODULE hModule); + +private: + HRESULT _ParseEtw(IXMLDOMDocument2 *pXmlDoc, Profile *pProfile); + HRESULT _ParseTimeSpans(IXMLDOMDocument2 *pXmlDoc, Profile *pProfile, vector>& vSubsts); + HRESULT _ParseTimeSpan(IXMLDOMNode *pXmlNode, TimeSpan *pTimeSpan, vector>& vSubsts); + HRESULT _ParseTargets(IXMLDOMNode *pXmlNode, TimeSpan *pTimeSpan, vector>& vSubsts); + HRESULT _ParseRandomDataSource(IXMLDOMNode *pXmlNode, Target *pTarget); + HRESULT _ParseWriteBufferContent(IXMLDOMNode *pXmlNode, Target *pTarget); + HRESULT _ParseTarget(IXMLDOMNode *pXmlNode, Target *pTarget); + HRESULT _ParseThreadTargets(IXMLDOMNode *pXmlNode, Target *pTarget); + HRESULT _ParseThroughput(IXMLDOMNode *pXmlNode, Target *pTarget); + HRESULT _ParseThreadTarget(IXMLDOMNode *pXmlNode, ThreadTarget *pThreadTarget); + HRESULT _ParseAffinityAssignment(IXMLDOMNode *pXmlNode, TimeSpan *pTimeSpan); + HRESULT _ParseAffinityGroupAssignment(IXMLDOMNode *pXmlNode, TimeSpan *pTimeSpan); + HRESULT _ParseDistribution(IXMLDOMNode *pXmlNode, Target *pTarget); + HRESULT _SubstTarget(Target *pTarget, vector>& vSubsts); + + HRESULT _GetString(IXMLDOMNode *pXmlNode, const char *pszQuery, string *psValue) const; + HRESULT _GetUINT32(IXMLDOMNode *pXmlNode, const char *pszQuery, UINT32 *pulValue) const; + HRESULT _GetUINT64(IXMLDOMNode *pXmlNode, const char *pszQuery, UINT64 *pullValue) const; + HRESULT _GetDWORD(IXMLDOMNode *pXmlNode, const char *pszQuery, DWORD *pdwValue) const; + HRESULT _GetBool(IXMLDOMNode *pXmlNode, const char *pszQuery, bool *pfValue) const; + + HRESULT _GetUINT32Attr(IXMLDOMNode *pXmlNode, const char *pszAttr, UINT32 *pulValue) const; + + HRESULT _GetVerbose(IXMLDOMDocument2 *pXmlDoc, bool *pfVerbose); + HRESULT _GetProgress(IXMLDOMDocument2 *pXmlDoc, DWORD *pdwProgress); +}; \ No newline at end of file diff --git a/CristalDiskMark/source/diskspd22/Common/XmlResultParser.h b/CristalDiskMark/source/diskspd22/Common/XmlResultParser.h new file mode 100644 index 0000000..89c2678 --- /dev/null +++ b/CristalDiskMark/source/diskspd22/Common/XmlResultParser.h @@ -0,0 +1,61 @@ +/* + +DISKSPD + +Copyright(c) Microsoft Corporation +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#pragma once +#include "Common.h" + +class XmlResultParser: public IResultParser +{ +public: + string ParseResults(const Profile& profile, const SystemInformation& system, vector vResults); + string ParseProfile(const Profile& profile); + /// for CrystalDiskMark + int GetTotalScore(); + double GetAverageLatency(); + +private: + void _PrintCpuUtilization(const Results& results, const SystemInformation& system); + void _PrintETW(struct ETWMask ETWMask, struct ETWEventCounters EtwEventCounters); + void _PrintETWSessionInfo(struct ETWSessionInfo sessionInfo); + void _PrintLatencyPercentiles(const Results& results); + void _PrintTargetResults(const TargetResults& results); + void _PrintTargetLatency(const TargetResults& results); + void _PrintTargetIops(const IoBucketizer& readBucketizer, const IoBucketizer& writeBucketizer, UINT32 bucketTimeInMs); + void _PrintOverallIops(const Results& results, UINT32 bucketTimeInMs); + void _PrintIops(const IoBucketizer& readBucketizer, const IoBucketizer& writeBucketizer, UINT32 bucketTimeInMs); + void _PrintWaitStats(const ThreadResults& threadResult); + + void _PrintV(const char *format, va_list listArg); + void _Print(const char *format, ...); + void _PrintInc(const char *format, ...); + void _PrintDec(const char *format, ...); + + string _sResult; + UINT32 _indent = 0; +}; \ No newline at end of file diff --git a/CristalDiskMark/source/diskspd22/Common/errors.h b/CristalDiskMark/source/diskspd22/Common/errors.h new file mode 100644 index 0000000..f11b5ca --- /dev/null +++ b/CristalDiskMark/source/diskspd22/Common/errors.h @@ -0,0 +1,38 @@ +/* + +DISKSPD + +Copyright(c) Microsoft Corporation +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#ifndef __DISKSPD_ERRORS_H +#define __DISKSPD_ERRORS_H + +#define ERROR_LOAD_LIBRARY 1 //error during LoadLibrary call +#define ERROR_GET_PROC_ADDRESS 2 //error during GetProcAddress +#define ERROR_PARSE_CMD_LINE 3 //error parsing cmd line parameters +#define ERROR_WAIT_FOR_START_SIGNAL 4 //error waiting for a signal to start work + +#endif \ No newline at end of file diff --git a/CristalDiskMark/source/diskspd22/Common/etw.h b/CristalDiskMark/source/diskspd22/Common/etw.h new file mode 100644 index 0000000..a14b670 --- /dev/null +++ b/CristalDiskMark/source/diskspd22/Common/etw.h @@ -0,0 +1,41 @@ +/* + +DISKSPD + +Copyright(c) Microsoft Corporation +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#pragma once + + +#include +#include ///WNODE_HEADER +#define INITGUID //Include this #define to use SystemTraceControlGuid in Evntrace.h. +#include //ETW +#include "Common.h" + +BOOL TraceEvents(); +TRACEHANDLE StartETWSession(const Profile& profile); +PEVENT_TRACE_PROPERTIES StopETWSession(TRACEHANDLE hTraceSession); \ No newline at end of file diff --git a/CristalDiskMark/source/diskspd22/Frameworks/VMFleet/ArcVM-Setup.md b/CristalDiskMark/source/diskspd22/Frameworks/VMFleet/ArcVM-Setup.md new file mode 100644 index 0000000..d64535a --- /dev/null +++ b/CristalDiskMark/source/diskspd22/Frameworks/VMFleet/ArcVM-Setup.md @@ -0,0 +1,329 @@ +# From Setup to Start-FleetSweep for Arc Enabled Virtual Machines in HCI clusters + +This is the traditional path of setting up VMFleet to deploy Arc enabled VMs on HCI clusters and running it using your desired DiskSpd parameters/flags. + + + +## Prerequisites + +Before we begin setting up VMFleet, there are a few prerequisites that you should have ready. + +Ensure an HCI cluster is setup. + +Ensure that you have 1 CSV per node + +Within Storage Spaces Direct, CPU usage is based on the host. Therefore, it is recommended that you split the storage load by creating as many CSVs as there are host nodes. We can go ahead and create a CSV per node in the cluster. + +You may run the following: + + +``` +Get-ClusterNode |% { + New-Volume -StoragePoolFriendlyName SU1_Pool* -FriendlyName $_ -FileSystem CSVFS_ReFS -Size +} + +``` + +Ensure that you create a “collect” volume. + +You may run the following: + +``` + +New-Volume -StoragePoolFriendlyName SU1_Pool* -FriendlyName collect -FileSystem CSVFS_ReFS -Size 200GB + +``` + +If you have ran VMFleet in the past, please ensure that prior VMFleet directories are completely removed from existing volumes. + +Retrieve or install a Server Core VHDX file. If you do not have one handy, we can create a new one by following the below instructions. + +Download WS2019 Server Core ISO from the public website. + +Open Hyper-V Manager. + +Click “New”, then “Virtual Machine”. + +Navigate through the prompts and pick a location to store your VM. + +Once your VM is created, boot up the VM and follow the instructions. This is where you will decide your VM password, or what we will later call, “adminpass”. + +This is important as we will use this later, so make sure you write this down. + +Log out of the VM, and navigate to where you stored your VM. You should find a “Virtual Hard Disks” folder. Inside, you should find your new Server Core VHDX file. + +Rename it to “Base1.vhdx”. + +Copy or move the file to the cluster environment that you want to run VMFleet in. + +Done! + +### Deployment + +1. First, we need to install the new PowerShell Module from the PowerShell Gallery and then load it into our terminal. We also need to disable cache as it is not supported currently for ArcVMs. Run the following: + +``` +Install-Module -Name “VMFleet” +Import-Module VMFleet +Set-ClusterStorageSpacesDirect -CacheState Disabled; + +``` + + +2. Sanity Check: + Run "Get-Module VMFleet" to confirm the module exists. + + Run "Get-Command -Module VMFleet" to obtain a list of functions included in the module. + + We will now set up the directory structure within the “Collect” CSV created earlier. Run "Install-Fleet" + + This creates the necessary VMFleet directories which include: + + * Collect/control + + Contains arc.json which stores Arc configuration and the scripts that the Virtual Machines continuously monitor. + + * Control.ps1: the control script the VMs use to implement the control loop (what used to be called “master.ps1”). + + * Run.ps1: The VMs continuously look for the most recent version of run.ps1 and runs the newly updated script (parameters). + + * Collect/flag + + Location where the control script drops the “go”, “pause”, and “done” flag files. Users should not need to look at these files. + + * Collect/result + + Location of the output files from the VMFleet test run. + + * Collect/tools + + DiskSpd will be preinstalled in this folder. + +3. You need to create a new or use existing Resource group under the same subscription as the Resource bridge VM is under. Set-ArcConfig will take care of creating one if not already present. + +4. Setup configuration required for creating Arc enabled Virtual Machines. + +``` +Set-ArcConfig -ResourceGroup [ENTER_RESOURCE_GROUP] -AzureRegistrationUser [ENTER_AZURE_REGUSER] -AzureRegistrationPassword [ENTER_AZURE_REGPASS]-StoragePathCsv [ENTER_CSV_PATH] -Enabled $true -StoragePathName [ENTER_StoragePath_Name] -ImageName [ENTER_Image_Name] -ResetSalt +``` + + -"ResourceGroup" is the resource group where ARC VMs will be deployed. + + -"AzureRegistrationUser" and "AzureRegistrationPassword" are the azure account credentials. + + -"StoragePathCsv" (optional) is the csv path where storage path resource will be created. If not provided, one of the existing csvs which were created earlier will be used by default. + + -"StoragePathName" (optional) is the storage path name which will be used to create gallery image. If not provided, default name will be used. + + -"ImageName" (optional) is the gallery image name which will be used to create Arc-enabled virtual machines. If not provided, default name will be used. Currently, only windows gallery image is the supported image type for Arc-Enabled VMs. + + -"Enabled" (optional) is set to $false by default. Set to $true if Arc-enabled virtual machines are to be created. + + -"ResetSalt" (optional) is a flag used to reset salt. Salt is a random 4 character (alphanumeric) used in Arc resource names for arc enabled virtual machines (for eg: vm-group-node-salt-001). In case, user wants to regenerate the salt, they can run "Set-ArcConfig -ResetSalt" which will override existing salt with a new one in the arc.json and this will be used to create new VMs. This is useful in case of multiple clusters under same subscription using same resource group on a virtual setup. A 4 character (alphanumeric) Salt will be generated by default when user runs Set-ArcConfig the first time and stored in arc.json along with other arc configs. Within Set-ArcConfig, a quick test is done to check if atleast one vm exists with same salt in the resource group. If it does, it is regenerated. + +5. By default, VMs with 2GB static memory and 1 processor count will be created. + + Note: Please move the VHDX file into the collect folder. CSV Cache is also turned off by default. + + We will now create our “fleet” of VMs by running: + +``` +New-Fleet -basevhd -vms [ENTER_NUM_VMS] -adminpass [ENTER_ADMINPASS] -connectuser [ENTER_NODE_USER] -connectpass [ENTER_NODE_PASS] +``` + + -"adminpass" is the administrator password for the Server Core Image. This is the password you set on your Virtual Machine earlier. + + -"connectuser" is a domain account with access to the cluster. + + -"connectpass " is the password for the above domain account. + + -"vms" is the number of VM's to create per node. + +6. If "vms" parameter is not provided, the default is a 1:1 subscription ratio where the Number of VMs = Number of physical cores. + +[Optional] You can consider modifying the VM hardware configuration. Run + +``` +Set-Fleet -ProcessorCount 1 -MemoryStartupBytes 2048mb -MemoryMaximumBytes 2048mb -MemoryMinimumBytes 2048mb + ``` + +Note: + +If you specify “MemoryMaximumBytes”, you must specify “MemoryMinimumBytes”, which implies that your VMs will have dynamic memory. + +If you omit “MemoryMaximumBytes” or “MemoryMinimumBytes”, it implies that your VMs will have static memory. + +If MemoryStartupBytes = MemoryMinimumBytes = MemoryMaximumBytes, that also denotes static memory. + +“MemoryStartupBytes” is a mandatory parameter. + + +### Start Running VMFleet! + +7. Open 2 PowerShell terminals. In the first one, run Watch-Cluster and in the second one, run Start-Fleet. This second function will turn on all the VMs in a “paused” state. + +8. At this point you can run Start-FleetSweep [ENTER_PARAMETERS] or take this time to explore and run any of the other functions! + +Here is a sample sweep command to help you get started: "Start-FleetSweep -b 4 -t 8 -o 8 -w 0 -d 300 -p r" + +9. Done! + +### Aftermath + +Once you are done running VMFleet you can run Stop-Fleet to shut down all the virtual machines or run Remove-Fleet to completely delete all the virtual machines on your environment. + +# From Setup to Measure-FleetCoreWorkload + +This is a new workflow for setting up VMFleet and the predefined profile workloads (General, Peak, VDI, SQL). + + + +## Prerequisites + +Before we begin setting up VMFleet, there are a few prerequisites that you should have ready. + +Ensure an HCI cluster is setup. + +Ensure that you have 1 CSV per node + +Within Storage Spaces Direct, CPU usage is based on the host. Therefore, it is recommended that you split the storage load by creating as many CSVs as there are host nodes. We can go ahead and create a CSV per node in the cluster. + +In order to be precise about the CSV size, please use our new VMFleet command: "Get-FleetVolumeEstimate" + +This will output a prescribed CSV size based on different resiliency types. We recommend you select a 2-way mirrored value or 3-way mirrored value depending on your node count. + +1. You may run the following: (use the CSV size from Get-FleetVolumeEstimate) + +``` +Get-ClusterNode |% { + New-Volume -StoragePoolFriendlyName SU1_Pool* -FriendlyName $_ -FileSystem CSVFS_ReFS -Size +} +``` + + Ensure that you create a “collect” volume. + +2. You may run the following: + +``` +New-Volume -StoragePoolFriendlyName SU1_Pool* -FriendlyName collect -FileSystem CSVFS_ReFS -Size 200GB +``` + +3. If you have ran VMFleet in the past, please ensure that prior VMFleet directories are completely removed from existing volumes. + + Retrieve or install a Server Core VHDX file. If you do not have one handy, we can create a new one by following the below instructions. + + Download WS2019 Server Core ISO from the public website. + + Open Hyper-V Manager. + + Click “New”, then “Virtual Machine”. + + Navigate through the prompts and pick a location to store your VM. + + Once your VM is created, boot up the VM and follow the instructions. This is where you will decide your VM password, or what we will later call, “adminpass”. + + This is important as we will use this later, so make sure you write this down. + + Log out of the VM, and navigate to where you stored your VM. You should find a “Virtual Hard Disks” folder. Inside, you should find your new Server Core VHDX file. + Rename it to “Base1.vhdx”. + + Copy or move the file to the cluster environment that you want to run VMFleet in. + +4. Done! + +## Deployment +5. Let’s begin deploying VMFleet. First, we need to install the new PowerShell Module from the PowerShell Gallery and then load it into the terminal. Run the following: + +``` +Install-Module -Name “VMFleet” +Import-Module VMFleet +Set-ClusterStorageSpacesDirect -CacheState Disabled; +``` + + + +## Sanity Check: + +6. Run "Get-Module VMFleet" to confirm the module exists. + +7. Run "Get-Command -Module VMFleet" to obtain a list of commands included in the module. + +8. We will now set up the directory structure within the “Collect” CSV that we created earlier. Run "Install-Fleet" + +9. You need to create a new or use existing Resource group under the same subscription as the Resource bridge VM is under. Set-ArcConfig will take care of creating one if not already present. + +10. Setup configuration required for creating Arc enabled Virtual Machines. + +``` +Set-ArcConfig -ResourceGroup [ENTER_RESOURCE_GROUP] -AzureRegistrationUser [ENTER_AZURE_REGUSER] -AzureRegistrationPassword [ENTER_AZURE_REGPASS]-StoragePathCsv [ENTER_CSV_PATH] -Enabled $true -StoragePathName [ENTER_StoragePath_Name] -ImageName [ENTER_Image_Name] -ResetSalt +``` + + -"ResourceGroup" is the resource group where ARC VMs will be deployed. + + -"AzureRegistrationUser" and "AzureRegistrationPassword" are the azure account credentials. + + -"StoragePathCsv" (optional) is the csv path where storage path resource will be created. If not provided, one of the existing csvs which were created earlier will be used by default. + + -"StoragePathName" (optional) is the storage path name which will be used to create gallery image. If not provided, default name will be used. + + -"ImageName" (optional) is the gallery image name which will be used to create Arc-enabled virtual machines. If not provided, default name will be used. + + -"Enabled" (optional) is set to $false by default. Set to $true if Arc-enabled virtual machines are to be created. + + -"ResetSalt" (optional) is a flag used to reset salt. Salt is a random 4 character (alphanumeric) used in Arc resource names for arc enabled virtual machines (for eg: vm-group-node-salt-001). In case, user wants to regenerate the salt, they can run "Set-ArcConfig -ResetSalt" which will override existing salt with a new one in the arc.json and this will be used to create new VMs. This is useful in case of multiple clusters under same subscription using same resource group on a virtual setup. A 4 character (alphanumeric) Salt will be generated by default when user runs Set-ArcConfig the first time and stored in arc.json along with other arc configs. Within Set-ArcConfig, a quick test is done to check if atleast one vm exists with same salt in the resource group. If it does, it is regenerated. + +11. By default, VMs with 2GB static memory and 1 processor count will be created. + + Note: Please move the VHDX file into the collect folder. CSV Cache is also turned off by default. + + We will now create our “fleet” of VMs by running: + +``` +New-Fleet -basevhd -vms [ENTER_NUM_VMS] -adminpass [ENTER_ADMINPASS] -connectuser [ENTER_NODE_USER] -connectpass [ENTER_NODE_PASS] +``` + + -"adminpass" is the administrator password for the Server Core Image. This is the password you set on your Virtual Machine earlier. + + -"connectuser" is a domain account with access to the cluster. + + -"connectpass " is the password for the above domain account. + + -"vms" is the number of VM's to create per node. + + +12. Measure-FleetCoreWorkload also collects diagnostic data (Get-SDDCDiagnosticInfo). Therefore, before running the command, we must also install the NuGet Package if you have not previously done so. In doing so, we also need to temporairly set the PSGallery as a trusted repository source (Note: This will temporarily relax the security boundary). + + +``` +$repo = Get-PSRepository -Name PSGallery +if ($null -eq $repo) { Write-Host "The PSGallery is not configured on this system, please address this before continuing" } +else { + if ($repo.InstallationPolicy -ne 'Trusted') { + Write-Host "Setting the PSGallery repository to Trusted, original InstallationPolicy: $($repo.InstallationPolicy)" + Set-PSRepository -Name PSGallery -InstallationPolicy Trusted + } + + ### Installing the pre-requisite modules + + Install-PackageProvider NuGet -Force + Install-Module -Name PrivateCloud.DiagnosticInfo -Force + Install-Module -Name MSFT.Network.Diag -Force + + if ($repo.InstallationPolicy -ne 'Trusted') { + Write-Host "Resetting the PSGallery repository to $($repo.InstallationPolicy)" + Set-PSRepository -Name PSGallery -InstallationPolicy $repo.InstallationPolicy + } +} +``` + +## Run Measure-FleetCoreWorkload! +13. We can now run Measure-FleetCoreWorkload. Running the command below will automatically run all 4 workloads (General, Peak, VDI, SQL) and place the individual outputs in the result directory. IMPORTANT: If you plan on running another test, please clear the result directory. + + +``` +Measure-FleetCoreWorkload +``` + +14. Congratulations! You’re done! All you need to do is wait for the test to complete. + +Note: If you ever run into an error and need to rerun Measure-FleetCoreWorkload, don’t be afraid to do so! It is smart enough to pick up from where it last stopped and continue the test without starting from scratch. diff --git a/CristalDiskMark/source/diskspd22/Frameworks/VMFleet/Profile.psm1 b/CristalDiskMark/source/diskspd22/Frameworks/VMFleet/Profile.psm1 new file mode 100644 index 0000000..9fefe39 --- /dev/null +++ b/CristalDiskMark/source/diskspd22/Frameworks/VMFleet/Profile.psm1 @@ -0,0 +1,1031 @@ +<# +VM Fleet + +Copyright(c) Microsoft Corporation +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +#> + +# +# Template Profiles +# +# Template profiles state througput in relative units per target per timespan. +# If a timespan contains two targets, one with 1 relative IOPS and one with 9 +# relative IOPS, applying an aggregate IOPS throughput of 100 would result in +# 10 & 90 respectively. +# +# Throughput MUST be in template in order to apply throughput limits. +# + +# Note: random/stridesize elements MUST be removed if -Random will be allowed for +# a profile. + +# +# Peak/General: a single thread high-QD unbuffered/writethrough single target template +# with latency/iops measured. 10MiB random write data source. All substitutions +# allowed. +# +# Peak and General differ in distribution. General is across a non-uniform distribution +# of the entire available workingset, while Peak has no built-in distribution. This allows +# Peak to be instantiated with a reduced workingset (-BaseOffset/-MaxOffset) for a uniformly +# loaded small workingset. +# +# +# Derived from: -t1 -b4k -o32 -w0 -r -Suw -D -L -Z10m *1 +# Random element removed, also BaseFileOffset/MaxFileSize +# Profile specific required parameters override WriteRatio, BlockSize +# + +$PeakProfile = @" + + 0 + xml + false + + + false + true + true + false + + + + 1000 + 0 + + + *1 + 4096 + true + true + + random + + 10485760 + + + 0 + 32 + 0 + 0 + 1 + 3 + + + + + +"@ + +$GeneralProfile = @" + + 0 + xml + false + + + false + true + true + false + + + + 1000 + 0 + + + *1 + 4096 + true + true + + random + + 10485760 + + + + + 5 + 10 + + + 0 + 32 + 0 + 0 + 1 + 3 + + + + + +"@ + +# VDI Profile: DiskSpd parameters that mimic a VDI workload +# +# Derived from: +# (write component) -t1 -o8 -b32k -w100 -g6i -rs20 -rdpct95/5:4/10 -Z10m -f10g *1 +# (read component) -t1 -o8 -b8k -w0 -g6i -rs80 -rdpct95/5:4/10 -f8g *1 + + +$VDIProfile = @" + + 0 + xml + false + + + false + true + true + false + + + 0 + 1000 + 0 + + + *1 + 32768 + 0 + 10737418240 + true + true + + random + + 10485760 + + + 32768 + 20 + + + 5 + 10 + + + 0 + 8 + 100 + 6 + 1 + 3 + + + *1 + 8192 + 0 + 8589934592 + true + true + + sequential + + 8192 + 80 + + + 5 + 10 + + + 0 + 8 + 0 + 6 + 1 + 3 + + + + + +"@ + +# SQL Profile: DiskSpd parameters that mimic an SQL workload with log transaction +# +# Derived from: +# (OLTP) -t4 -o32 -r -b8k -g1500i -w30 -rdpct95/5:4/10 -B5g -Z10m *1 +# (Log) -t1 -o1 -s -b32k -g300i -w100 -f5g -Z10m *1 + +$SQLProfile = @" + + 0 + xml + false + + + false + true + true + false + + + + 1000 + 0 + + + *1 + 8192 + 5368709120 + 0 + true + true + + random + + 10485760 + + + 8192 + + + 5 + 10 + + + 0 + 32 + 30 + 1500 + 4 + 3 + + + *1 + 32768 + 0 + 5368709120 + true + true + + random + + 10485760 + + + 32768 + 0 + 1 + 100 + 300 + 1 + 3 + + + + + +"@ + +# +# Requires - parameters which must be provided +# AllowsRandSeq - compatibility with -Random/-Sequential rewrite rule +# Compatibility - list of parameters for compatibility check +# Compatible - provides sense of the Compatibility list for simpler bulk inclusion/exclusion +# true - an inclusion list; parameters not mentioned are not allowed (empty = none allowed) +# false - an exclusion list; parameters mentioned are not allowed (empty = all allowed) +# + +$FleetProfiles = @{ + Peak = @{ + Profile = $PeakProfile + AllowRandSeq = $true + Requires = @('WriteRatio', 'BlockSize') + Compatibility = $null + Compatible = $false + } + + General = @{ + Profile = $GeneralProfile + AllowRandSeq = $true + Requires = @('WriteRatio', 'BlockSize') + Compatibility = $null + Compatible = $false + } + + VDI = @{ + Profile = $VDIProfile + AllowRandSeq = $false + Requires = $null + Compatibility = $null + Compatible = $true + } + + SQL = @{ + Profile = $SQLProfile + AllowRandSeq = $false + Requires = $null + Compatibility = $null + Compatible = $true + } +} + +function Get-FleetProfileXml +{ + [CmdletBinding()] + param( + [Parameter()] + [string] + $Name, + + [Parameter()] + [uint32] + $Warmup = 300, + + [Parameter()] + [uint32] + $Duration = 60, + + [Parameter()] + [uint32] + $Cooldown = 30, + + [ValidateRange(0, 100)] + [uint32] + $WriteRatio, + + [Parameter()] + [uint32] + $ThreadsPerTarget, + + [Parameter()] + [uint32] + $BlockSize, + + [Parameter()] + [uint32] + $Alignment, + + [Parameter()] + [switch] + $Random, + + [Parameter()] + [switch] + $Sequential, + + [ValidateRange(0, 100)] + [uint32] + $RandomRatio, + + [Parameter()] + [uint32] + $RequestCount, + + [Parameter()] + [uint64] + $ThreadStride, + + [Parameter()] + [uint64] + $BaseOffset, + + [Parameter()] + [uint64] + $MaxOffset, + + [Parameter()] + [ValidateRange(1,60)] + [uint32] + $IoBucketDurationSeconds + ) + + $x = $null + + # + # Get base profile and validate profile-specific paramters + # + + if (-not $PSBoundParameters.ContainsKey('Name')) + { + Write-Error "Available profiles: $(@($FleetProfiles.Keys | Sort-Object) -join ', ')" + return + } + elseif (-not $FleetProfiles.ContainsKey($Name)) + { + Write-Error "Unknown profile $Name; available: $(@($FleetProfiles.Keys | Sort-Object) -join ', ')" + return + } + + # + # Switch validation + # + + if ($PsBoundParameters.ContainsKey('Sequential') -and $PsBoundParameters.ContainsKey('Random')) + { + Write-Error "Random and Sequential cannot be specified together" + return + } + + # + # Requires check + # + + $err = @() + foreach ($arg in $FleetProfiles[$Name].Requires) + { + if (-not $PSBoundParameters.ContainsKey($arg)) + { + $err += ,$arg + } + } + + if ($err.Count) + { + Write-Error "$Name profile requires specification of $($err -join ', ')" + return + } + + # + # Incompatible check + # + + if (-not ($FleetProfiles[$Name].Compatible)) + { + foreach ($arg in $FleetProfiles[$Name].Compatibility) + { + if ($PSBoundParameters.ContainsKey($arg)) + { + $err += ,$arg + } + } + } + + # + # Compatible check + # + + else + { + # Always-on core parameters + required list + compatible list + $baseParameters = @('Name', 'Warmup', 'Duration', 'Cooldown') + + foreach ($arg in $PSBoundParameters.Keys) + { + if ($baseParameters -notcontains $arg -and + $FleetProfiles[$Name].Requires -notcontains $arg -and + $FleetProfiles[$Name].Compatibility -notcontains $arg) + { + $err += ,$arg + } + } + } + + if ($err.Count) + { + Write-Error "$Name profile does not allow specification of $($err -join ', ')" + return + } + + # + # Now load/modify profile. + # + + $x = [xml] $FleetProfiles[$Name].Profile + + # + # Perform replacements @ TimeSpan + # + + foreach ($timeSpan in $x.SelectNodes("Profile/TimeSpans/TimeSpan")) + { + $timeSpan.Warmup = [string] $Warmup + $timeSpan.Duration = [string] $Duration + $timeSpan.Cooldown = [string] $Cooldown + + if ($PSBoundParameters.ContainsKey('IoBucketDurationSeconds')) + { + $timeSpan.IoBucketDuration = [string] ($IoBucketDurationSeconds * 1000) + } + + # Autoscale to best clock fit >1000 n-second IOPS bucket datapoints. + else + { + $timeSpan.IoBucketDuration = [string] ((FitClockRate -TotalSeconds $Duration -Samples 1000) * 1000) + } + } + + # + # Perform replacements @ Target + # + + foreach ($targetSet in $x.SelectNodes("Profile/TimeSpans/TimeSpan/Targets")) + { + $targets = $targetSet.SelectNodes("Target") + + foreach ($target in $targets) + { + # + # 1:1 Common Substitutions + # + + $TargetSubstitutions = @{ + BlockSize = 'BlockSize' + RequestCount = 'RequestCount' + ThreadsPerTarget = 'ThreadsPerFile' + ThreadStride = 'ThreadStride' + WriteRatio = 'WriteRatio' + MaxOffset = 'MaxFileSize' + BaseOffset = 'BaseFileOffset' + } + + foreach ($s in $TargetSubstitutions.Keys) + { + if ($PSBoundParameters.ContainsKey($s)) + { + SetSingleNode -Xml $x -ParentNode $target -Node $TargetSubstitutions[$s] -Value ([string] $PSBoundParameters[$s]) + } + } + + # + # Target Random/Sequential/Alignment + # + + if ($FleetProfiles[$Name].AllowRandSeq) + { + # Inherit default buffer alignment from buffer size + if (-not $PSBoundParameters.ContainsKey('Alignment')) + { + $Alignment = $BlockSize + } + + # Random or RandomRatio + if ($Random -or $PsBoundParameters.ContainsKey('RandomRatio')) + { + $e = $x.CreateNode([xml.xmlnodetype]::Element, 'Random', '') + $e.InnerText = [string] $Alignment + $null = $target.AppendChild($e) + + if ($PsBoundParameters.ContainsKey('RandomRatio')) + { + $e = $x.CreateNode([xml.xmlnodetype]::Element, 'RandomRatio', '') + $e.InnerText = [string] $RandomRatio + $null = $target.AppendChild($e) + } + } + + # Sequential (default if neither specified) + elseif ($Sequential -or -not $Random) + { + $e = $x.CreateNode([xml.xmlnodetype]::Element, 'StrideSize', '') + $e.InnerText = [string] $Alignment + $null = $target.AppendChild($e) + + # + # Remove any distribution attached to the target - not compatibile (or relevant); + # sequential is sequential. + # + + $dists = $target.SelectNodes("Distribution") + foreach ($dist in $dists) + { + $null = $target.RemoveChild($dist) + } + } + } + } + } + + $x +} + +function Set-FleetProfile +{ + [CmdletBinding()] + param( + [Parameter(ValueFromPipeline = $true, Mandatory = $true)] + [xml] + $ProfileXml, + + [Parameter()] + [uint32] + $Throughput, + + [Parameter()] + [ValidateSet("IOPS","BPMS")] + [string] + $ThroughputUnit = "IOPS", + + [Parameter()] + [uint32] + $Warmup, + + [Parameter()] + [uint32] + $Duration, + + [Parameter()] + [uint32] + $Cooldown + ) + + process + { + $x = $ProfileXml.Clone() + + foreach ($timeSpan in $x.SelectNodes("Profile/TimeSpans/TimeSpan")) + { + if ($PSBoundParameters.ContainsKey('Warmup')) + { + $timeSpan.Warmup = [string] $Warmup + } + + if ($PSBoundParameters.ContainsKey('Cooldown')) + { + $timeSpan.Cooldown = [string] $Cooldown + } + + if ($PSBoundParameters.ContainsKey('Duration')) + { + $timeSpan.Duration = [string] $Duration + } + + if ($PSBoundParameters.ContainsKey('Throughput')) + { + # Fail if timespan is in threadpool form - DISKSPD does not support + # throughput in this case. + + $t = $timeSpan.SelectSingleNode("ThreadCount") + if ($null -ne $t -and $t.InnerText -ne 0) + { + throw "Cannot set bounded throughput on profile using thread pool (-F/TimeSpan ThreadCount)" + } + + foreach ($targetSet in $timeSpan.SelectNodes("Targets")) + { + # + # Pass 1 - Total + # + + $total = [uint32] 0 + $nTargets = 0 + foreach ($target in $targetSet.Target) + { + $thisTput = 0 + $e = $target.SelectSingleNode("Throughput") + if ($null -ne $e) + { + $thisTput = [uint32] $e.InnerText + + $e = $target.SelectSingleNode("ThreadsPerFile") + if ($null -eq $e -or ([uint32] $e.InnerText) -eq 0) + { + throw "ThreadsPerFile is not present - zero or absent - to scale Throughput (target $nTargets)" + } + + $thisTput *= [uint32] $e.InnerText + } + + if (($total -ne 0 -and $thisTput -eq 0) -or + ($total -eq 0 -and $thisTput -ne 0 -and $nTargets -ne 0)) + { + throw "Cannot set throughput on profile with a combination of bounded/unbounded targets (target $nTargets)" + } + + $total += $thisTput + ++$nTargets + } + + # If there is no throughout specified (unbounded) and no ratio specified + # in the profile, we are done - already unbounded. + + if ($Throughput -eq 0 -and $total -eq 0) { continue } + + # + # Pass 2a - Distribute nonzero by ratio, as well as zero to single target + # + + if ($Throughput -ne 0 -or $targets.Count -eq 1) + { + foreach ($target in $targetSet.Target) + { + + # Distribute equally + if ($total -eq 0) + { + SetSingleNode -Xml $x -ParentNode $target -Node 'Throughput' -Value ([int] ($Throughput / $nTargets)) + $e = $target.SelectSingleNode("Throughput") + } + + # Distribute proportionally + # Note: in absolute terms the numerator $thisTput should be scaled by #threads to arrive at + # a fraction the new throughput, but then we would immediatly divide #threads out of the result + # to arrive at per thread throughput; this can be avoided. + else + { + $e = $target.SelectSingleNode("Throughput") + $thisTput = [uint32] $e.InnerText + $e.InnerText = [string] [int] ($Throughput * ($thisTput / $total)) + } + + $e.SetAttribute('unit', $ThroughputUnit) + } + } + + # Pass 2b - Distribute "zero" across multiple by converting target threads to pool + # with weighted ratio of throughputs on targets. Set interlocked sequential + # on sequential targets unless a nonzero threadstride is already present. + # This can result in a close approximation of unbounded result on the tput + # limited specification without needing dynamic scale-up, but should be used + # with caution. + else + { + # Loop targets to count threads, move tputs to weights and set interlocked sequential. + + $nThreads = 0 + foreach ($target in $targetSet.Target) + { + # Count threads + $e = $target.SelectSingleNode("ThreadsPerFile") + if ($null -eq $e -or $e.InnerText -eq 0) + { + throw "Invalid -t/ThreadsPerFile specification (absent or zero) converting to unbounded form" + } + $thisThreads = [uint32] $e.InnerText + $nThreads += $thisThreads + + # Remove ThreadsPerFile/RequestCount @ Target + $null = $target.RemoveChild($e) + $e = $target.SelectSingleNode("RequestCount") + if ($null -ne $e) { $null = $target.RemoveChild($e) } + + # Move Throuhput to Weight. Note - Throughput guaranteed to exist or we would have + # returned at the 0/0 check. Weight scales by number of threads on the target. + $e = $target.SelectSingleNode("Throughput") + $thisTput = [uint32] $e.InnerText + $null = $target.RemoveChild($e) + + SetSingleNode -Xml $x -ParentNode $target -Node 'Weight' -Value ($thisTput * $thisThreads) + + # Sequential target without ThreadStride? Move to interlocked. + $e = $target.SelectSingleNode("StrideSize") + if ($null -ne $e) + { + $e = $target.SelectSingleNode("ThreadStride") + if ($null -eq $e -or $e.InnerText -eq 0) + { + SetSingleNode -Xml $x -ParentNode $target -Node 'InterlockedSequential' -Value 'true' + } + } + } + + # Now set TimeSpan level thread pool with high request count + + SetSingleNode -Xml $x -ParentNode $timeSpan -Node 'ThreadCount' -Value $nThreads + SetSingleNode -Xml $x -ParentNode $timeSpan -Node 'RequestCount' -Value 32 + } + } + } + } + + $x + } +} +function GetFleetProfileFootprint +{ + [CmdletBinding()] + param( + [Parameter(ValueFromPipeline = $true, Mandatory = $true)] + [xml] + $ProfileXml, + + [Parameter()] + [switch] + $Read + ) + + $r = @{} + + # Capture min base offset and max max offset across timespans for each target. + # Note that 0 max offset indicates it is not bounded (bounded by target size). + + foreach ($target in $ProfileXml.SelectNodes("Profile/TimeSpans/TimeSpan/Targets/Target")) + { + # Skip write-only target specs if only interested in read workingset + if ($Read -and $target.WriteRatio -eq '100') + { + continue + } + + $bo = [uint64](GetSingleNode $target 'BaseFileOffset') + $mo = [uint64](GetSingleNode $target 'MaxFileSize') + + $node = $r[$target.Path] + + if ($null -ne $node) + { + if ($node.BaseOffset -gt $bo) + { + $r[$target.Path].BaseOffset = $bo + } + + if ($mo -eq 0) + { + $r[$target.Path].MaxOffset = 0 + } + elseif ($node.MaxOffset -ne 0 -and $node.MaxOffset -lt $mo) + { + $r[$target.Path].MaxOffset = $mo + } + } + else + { + $r[$target.Path] = [pscustomobject] @{ + BaseOffset = $bo + MaxOffset = $mo + } + } + } + + $r +} + +function Convert-FleetXmlToString +{ + [CmdletBinding()] + param( + [Parameter(ValueFromPipeline = $true, Mandatory = $true)] + [object] + $InputObject + ) + + process { + + switch ($InputObject.GetType().FullName) + { + "System.Xml.XmlDocument" { break } + "System.Xml.XmlElement" { break } + default { + throw "Unknown object type $_ - must be XmlDocument or XmlElement" + } + } + + $sw = [System.IO.StringWriter]::new() + $xo = [System.Xml.XmlTextWriter]::new($sw) + $xo.Formatting = [System.Xml.Formatting]::Indented + + $InputObject.WriteTo($xo) + $sw.ToString() + } +} + +function FitClockRate +{ + param( + [ValidateRange(1,(1000*60*60))] + [uint32] + $TotalSeconds, + + [uint32] + $Samples + ) + + # Perform a best-fit for the longest interval which produces at least $Samples over + # the given $TotalSeconds time period and evenly divide minutes/hours. E.g.: + # 1..60 |? { 60 % $_ -eq 0 }) + # + # Range is sanity capped at 1000h. + + $div = 1,2,3,4,5,6,10,12,15,20,30,60 + $last = 1 + + # First multiple is seconds, second produces minutes. + + foreach ($mul in (1,60)) + { + foreach ($d in $div) + { + # Skip 60s and roll over to 1 minute. + # 60 is only used for minutes. (e.g., 1hr) + if ($mul -eq 1 -and $d -eq 60 ) { break } + + if (($TotalSeconds / ($d * $mul)) -lt $Samples) + { + return $last + } + + $last = $d * $mul + } + } + + return $last +} +function SetSingleNode +{ + param( + [xml] + $Xml, + + [xml.xmlelement] + $ParentNode, + + [string] + $Node, + + [string] + $Value + ) + + # Set/Create child node to given value + + $e = $ParentNode.SelectSingleNode($Node) + if ($null -ne $e) + { + $e.InnerText = $Value + } + else + { + $e = $Xml.CreateNode([xml.xmlnodetype]::Element, $Node, '') + $e.InnerText = $Value + $null = $ParentNode.AppendChild($e) + } +} + +function GetSingleNode +{ + param( + [xml.xmlelement] + $ParentNode, + + [string] + $Node + ) + + # Gete child node, if present + + $e = $ParentNode.SelectSingleNode($Node) + if ($null -ne $e) + { + return $e.InnerText + } + + return $null +} + +function IsProfileSingleTimespan +{ + param( + [xml] + $ProfileXml + ) + + $ts = @($ProfileXml.SelectNodes("Profile/TimeSpans/TimeSpan")) + return ($ts.Count -eq 1) +} + +function IsProfileThroughputLimited +{ + param( + [xml] + $ProfileXml + ) + + $tputs = @($ProfileXml.SelectNodes("Profile/TimeSpans/TimeSpan/Targets/Target/Throughput")) + + foreach ($t in $tputs) + { + if (([uint32]$t.InnerText) -ne 0) + { + return $true + } + } + + return $false +} + +function IsProfileSingleTarget +{ + param( + [xml] + $ProfileXml + ) + + $tgts = @($ProfileXml.SelectNodes("Profile/TimeSpans/TimeSpan/Targets/Target")) + return ($tgts.Count -eq 1) +} \ No newline at end of file diff --git a/CristalDiskMark/source/diskspd22/Frameworks/VMFleet/VMFleet.Tests.ps1 b/CristalDiskMark/source/diskspd22/Frameworks/VMFleet/VMFleet.Tests.ps1 new file mode 100644 index 0000000..1c050cb --- /dev/null +++ b/CristalDiskMark/source/diskspd22/Frameworks/VMFleet/VMFleet.Tests.ps1 @@ -0,0 +1,728 @@ +Describe "TestModulePresent" { + + BeforeAll { + + $script:e = $null + } + + if (Test-Path .\VMFleet.psd1) + { + It "ShouldLoad-Local" { + { Import-Module .\VMFleet.psd1 -Force -ErrorVariable script:e } | Should Not Throw + $script:e | Should BeNullOrEmpty Because "this should be successful" + } + } + else + { + It "ModuleExists-Installed" { + Get-Module VMFleet -ListAvailable -ErrorVariable script:e | Should Not BeNullOrEmpty Because "module should be installed on system" + $script:e | Should BeNullOrEmpty Because "this should be successful" + } + + It "ShouldLoad-Installed" { + { Import-Module VMFleet -Force -ErrorVariable script:e } | Should Not Throw + $script:e | Should BeNullOrEmpty Because "this should be successful" + } + } + + It "ShouldBeLoaded" { + Get-Module VMFleet -ErrorVariable script:e | Should Not BeNullOrEmpty Because "module should now be loaded" + $script:e | Should BeNullOrEmpty Because "this should be successful" + } +} + +InModuleScope VMFleet { + + Describe "GetDistributedShift" { + + BeforeAll { + + $a = @('a', 'b', 'c', 'd', 'e') + $b = @('f', 'g', 'h', 'i', 'j') + $c = @('k', 'l', 'm', 'n', 'o') + $d = @('p', 'q', 'r', 's', 't') + + $bad = @('z') + + $a20 = 1..20 |% { "a$_" } + $b20 = 1..20 |% { "b$_" } + $c20 = 1..20 |% { "c$_" } + $d20 = 1..20 |% { "d$_" } + } + + It "ShouldRequireListOfLists" { + GetDistributedShift -Group $a -N 1 | Should Throw + } + + It "ShouldRequireMoreThanOne" { + GetDistributedShift -Group @($a) -N 1 | Should Throw + } + + It "ShouldRequireAllSameSize" { + GetDistributedShift -Group $a,$b,$bad -N 1 | Should Throw + } + + It "ShouldRequirePositiveRotation" { + GetDistributedShift -Group $a,$b -N 0 | Should Throw + } + + It "ShouldNotShiftTooMany" { + GetDistributedShift -Group $a,$b -N 6 | Should Throw + } + + # + # Two group rotations + # + + It "Rotate2-1" { + { GetDistributedShift -Group $a,$b -N 1 } | Should Not Throw + $a1, $b1 = GetDistributedShift -Group $a,$b -N 1 + $a1.Count | Should Be 5 + $b1.Count | Should Be 5 + + ($a1 -join '') | Should Be "abcdj" + ($b1 -join '') | Should Be "fghie" + } + + It "Rotate2-2" { + { GetDistributedShift -Group $a,$b -N 2 } | Should Not Throw + $a1, $b1 = GetDistributedShift -Group $a,$b -N 2 + $a1.Count | Should Be 5 + $b1.Count | Should Be 5 + + ($a1 -join '') | Should Be "abcij" + ($b1 -join '') | Should Be "fghde" + } + + It "Rotate2-3" { + { GetDistributedShift -Group $a,$b -N 3 } | Should Not Throw + $a1, $b1 = GetDistributedShift -Group $a,$b -N 3 + $a1.Count | Should Be 5 + $b1.Count | Should Be 5 + + ($a1 -join '') | Should Be "abhij" + ($b1 -join '') | Should Be "fgcde" + } + + It "Rotate2-4" { + { GetDistributedShift -Group $a,$b -N 4 } | Should Not Throw + $a1, $b1 = GetDistributedShift -Group $a,$b -N 4 + $a1.Count | Should Be 5 + $b1.Count | Should Be 5 + + ($a1 -join '') | Should Be "aghij" + ($b1 -join '') | Should Be "fbcde" + } + + It "Rotate2-5" { + { GetDistributedShift -Group $a,$b -N 5 } | Should Not Throw + $a1, $b1 = GetDistributedShift -Group $a,$b -N 5 + $a1.Count | Should Be 5 + $b1.Count | Should Be 5 + + ($a1 -join '') | Should Be "fghij" + ($b1 -join '') | Should Be "abcde" + } + + # + # Three group rotations + # + + It "Rotate3-1" { + { GetDistributedShift -Group $a,$b,$c -N 1 } | Should Not Throw + $a1, $b1, $c1 = GetDistributedShift -Group $a,$b,$c -N 1 + $a1.Count | Should Be 5 + $b1.Count | Should Be 5 + $c1.Count | Should Be 5 + + ($a1 -join '') | Should Be "abcdo" + ($b1 -join '') | Should Be "fghie" + ($c1 -join '') | Should Be "klmnj" + } + + It "Rotate3-2" { + { GetDistributedShift -Group $a,$b,$c -N 2 } | Should Not Throw + $a1, $b1, $c1 = GetDistributedShift -Group $a,$b,$c -N 2 + $a1.Count | Should Be 5 + $b1.Count | Should Be 5 + $c1.Count | Should Be 5 + + ($a1 -join '') | Should Be "abcio" + ($b1 -join '') | Should Be "fghne" + ($c1 -join '') | Should Be "klmdj" + } + + It "Rotate3-3" { + { GetDistributedShift -Group $a,$b,$c -N 3 } | Should Not Throw + $a1, $b1, $c1 = GetDistributedShift -Group $a,$b,$c -N 3 + $a1.Count | Should Be 5 + $b1.Count | Should Be 5 + $c1.Count | Should Be 5 + + ($a1 -join '') | Should Be "abmio" + ($b1 -join '') | Should Be "fgcne" + ($c1 -join '') | Should Be "klhdj" + } + + It "Rotate3-4" { + { GetDistributedShift -Group $a,$b,$c -N 4 } | Should Not Throw + $a1, $b1, $c1 = GetDistributedShift -Group $a,$b,$c -N 4 + $a1.Count | Should Be 5 + $b1.Count | Should Be 5 + $c1.Count | Should Be 5 + + ($a1 -join '') | Should Be "agmio" + ($b1 -join '') | Should Be "flcne" + ($c1 -join '') | Should Be "kbhdj" + } + + It "Rotate3-5" { + { GetDistributedShift -Group $a,$b,$c -N 5 } | Should Not Throw + $a1, $b1, $c1 = GetDistributedShift -Group $a,$b,$c -N 5 + $a1.Count | Should Be 5 + $b1.Count | Should Be 5 + $c1.Count | Should Be 5 + + ($a1 -join '') | Should Be "kgmio" + ($b1 -join '') | Should Be "alcne" + ($c1 -join '') | Should Be "fbhdj" + } + + It "RotateLarge4-1" { + { GetDistributedShift -Group $a20,$b20,$c20,$d20 -N 1 } | Should Not Throw + $g = GetDistributedShift -Group $a20,$b20,$c20,$d20 -N 1 + + # note last group rotates 1 + $g[0] -join '' | Should Be "a1a2a3a4a5a6a7a8a9a10a11a12a13a14a15a16a17a18a19d20" + $g[1] -join '' | Should Be "b1b2b3b4b5b6b7b8b9b10b11b12b13b14b15b16b17b18b19a20" + $g[2] -join '' | Should Be "c1c2c3c4c5c6c7c8c9c10c11c12c13c14c15c16c17c18c19b20" + $g[3] -join '' | Should Be "d1d2d3d4d5d6d7d8d9d10d11d12d13d14d15d16d17d18d19c20" + } + + It "RotateLarge4-2" { + { GetDistributedShift -Group $a20,$b20,$c20,$d20 -N 2 } | Should Not Throw + $g = GetDistributedShift -Group $a20,$b20,$c20,$d20 -N 2 + + # note last group rotates 1, next 2 + $g[0] -join '' | Should Be "a1a2a3a4a5a6a7a8a9a10a11a12a13a14a15a16a17a18c19d20" + $g[1] -join '' | Should Be "b1b2b3b4b5b6b7b8b9b10b11b12b13b14b15b16b17b18d19a20" + $g[2] -join '' | Should Be "c1c2c3c4c5c6c7c8c9c10c11c12c13c14c15c16c17c18a19b20" + $g[3] -join '' | Should Be "d1d2d3d4d5d6d7d8d9d10d11d12d13d14d15d16d17d18b19c20" + } + + It "RotateLarge4-3" { + { GetDistributedShift -Group $a20,$b20,$c20,$d20 -N 3 } | Should Not Throw + $g = GetDistributedShift -Group $a20,$b20,$c20,$d20 -N 3 + + # note last group rotates 1, then 2, 3 + $g[0] -join '' | Should Be "a1a2a3a4a5a6a7a8a9a10a11a12a13a14a15a16a17b18c19d20" + $g[1] -join '' | Should Be "b1b2b3b4b5b6b7b8b9b10b11b12b13b14b15b16b17c18d19a20" + $g[2] -join '' | Should Be "c1c2c3c4c5c6c7c8c9c10c11c12c13c14c15c16c17d18a19b20" + $g[3] -join '' | Should Be "d1d2d3d4d5d6d7d8d9d10d11d12d13d14d15d16d17a18b19c20" + } + + It "RotateLarge4-4" { + { GetDistributedShift -Group $a20,$b20,$c20,$d20 -N 4 } | Should Not Throw + $g = GetDistributedShift -Group $a20,$b20,$c20,$d20 -N 4 + + # note last group rotates 1, then 2, 3, and back to 1 + $g[0] -join '' | Should Be "a1a2a3a4a5a6a7a8a9a10a11a12a13a14a15a16d17b18c19d20" + $g[1] -join '' | Should Be "b1b2b3b4b5b6b7b8b9b10b11b12b13b14b15b16a17c18d19a20" + $g[2] -join '' | Should Be "c1c2c3c4c5c6c7c8c9c10c11c12c13c14c15c16b17d18a19b20" + $g[3] -join '' | Should Be "d1d2d3d4d5d6d7d8d9d10d11d12d13d14d15d16c17a18b19c20" + } + } + + Describe "FilterObject" { + + BeforeAll { + $o12 = [PSCustomObject]@{ + K1 = 1 + K2 = 2 + } + $o13 = [PSCustomObject]@{ + K1 = 1 + K2 = 3 + } + } + + It "PassWithEmpty" { + $o12 | FilterObject -Filter @{} | Should Not BeNullOrEmpty + } + It "PassWithOneK" { + $o12 | FilterObject -Filter @{ K1 = 1 } | Should Not BeNullOrEmpty + } + It "PassWithTwoK" { + $o12 | FilterObject -Filter @{ K1 = 1; K2 = 2 } | Should Not BeNullOrEmpty + } + It "PassWithOneKDiffType" { + $o12 | FilterObject -Filter @{ K1 = '1' } | Should Not BeNullOrEmpty + } + It "PassWithTwoKDiffType" { + $o12 | FilterObject -Filter @{ K1 = '1'; K2 = '2' } | Should Not BeNullOrEmpty + } + It "NotPassMismatchSameType" { + $o12 | FilterObject -Filter @{ K1 = 2 } | Should BeNullOrEmpty + } + It "NotPassMismatchDiffType" { + $o12 | FilterObject -Filter @{ K1 = '2' } | Should BeNullOrEmpty + } + + It "ShouldPassMultipleMatch" { + $r = @($o12,$o12 | FilterObject -Filter @{ K1 = 1 }) + $r.Count | Should Be 2 + } + + It "ShouldPassTheMatch" { + $r = @($o12,$o13 | FilterObject -Filter @{ K2 = 2 }) + $r.Count | Should Be 1 + $r.K1 | Should Be 1 + $r.K2 | Should Be 2 + } + } +} + +Describe "SetFleetProfile" { + + BeforeAll { + + It "ShouldBeExpectedSqlProfile" { + { Get-FleetprofileXml -Name SQL } | Should Not Throw + $x = Get-FleetprofileXml -Name SQL + + $x.Profile.TimeSpans.TimeSpan.Targets.Target[0].Throughput.InnerText | Should Be 1500 + $x.Profile.TimeSpans.TimeSpan.Targets.Target[1].Throughput.InnerText | Should Be 300 + } + + $x = Get-FleetprofileXml -Name SQL + + $oWarmup = $x.Profile.TimeSpans.TimeSpan.Warmup + $oDuration = $x.Profile.TimeSpans.TimeSpan.Duration + $oCooldown = $x.Profile.TimeSpans.TimeSpan.Cooldown + } + + It "ShouldSetByParam" { + { Set-FleetProfile -ProfileXml $x -Throughput 1000 } | Should Not Throw + $xn = Set-FleetProfile -ProfileXml $x -Throughput 1000 + + # original composition is 1500*4 threads + 300*1 thread = 6300 + # 1000 * 6000/6300 / 4 threads = 238 + # 1000 * 300/6300 / 1 thread = 48 + $xn.Profile.TimeSpans.TimeSpan.Targets.Target[0].Throughput.InnerText | Should Be 238 + $xn.Profile.TimeSpans.TimeSpan.Targets.Target[1].Throughput.InnerText | Should Be 48 + } + + It "ShouldSetByPipeline" { + { $x | Set-FleetProfile -Throughput 1000 } | Should Not Throw + $xn = $x | Set-FleetProfile -Throughput 1000 + + $xn.Profile.TimeSpans.TimeSpan.Targets.Target[0].Throughput.InnerText | Should Be 238 + $xn.Profile.TimeSpans.TimeSpan.Targets.Target[1].Throughput.InnerText | Should Be 48 + } + + It "ShouldSetUnbounded" { + { $x | Set-FleetProfile -Throughput 0 } | Should Not Throw + $xn = $x | Set-FleetProfile -Throughput 0 + + $xn.Profile.TimeSpans.TimeSpan.ThreadCount | Should be 5 + $xn.Profile.TimeSpans.TimeSpan.RequestCount | Should be 32 + + $xn.Profile.TimeSpans.SelectNodes("TimeSpan/Targets/Target/ThreadsPerFile") | Should BeNullOrEmpty + $xn.Profile.TimeSpans.SelectNodes("TimeSpan/Targets/Target/RequestCount") | Should BeNullOrEmpty + $xn.Profile.Timespans.TimeSpan.Targets.Target[1].InterlockedSequential | Should Be 'true' + } + + It "ShouldSetWarmup" { + $oWarmup | Should Not Be 33 + { $x | Set-FleetProfile -Warmup 33 } | Should Not Throw + $xn = $x | Set-FleetProfile -Warmup 33 + + $xn.Profile.TimeSpans.TimeSpan.Warmup | Should Be 33 + $xn.Profile.TimeSpans.TimeSpan.Duration | Should Be $oDuration + $xn.Profile.TimeSpans.TimeSpan.Cooldown | Should Be $oCooldown + } + + It "ShouldSetDuration" { + $oDuration | Should Not Be 33 + { $x | Set-FleetProfile -Duration 33 } | Should Not Throw + $xn = $x | Set-FleetProfile -Duration 33 + + $xn.Profile.TimeSpans.TimeSpan.Warmup | Should Be $oWarmup + $xn.Profile.TimeSpans.TimeSpan.Duration | Should Be 33 + $xn.Profile.TimeSpans.TimeSpan.Cooldown | Should Be $oCooldown + } + + It "ShouldSetCooldown" { + $oCooldown | Should Not Be 33 + { $x | Set-FleetProfile -Cooldown 33 } | Should Not Throw + $xn = $x | Set-FleetProfile -Cooldown 33 + + $xn.Profile.TimeSpans.TimeSpan.Warmup | Should Be $oWarmup + $xn.Profile.TimeSpans.TimeSpan.Duration | Should Be $oDuration + $xn.Profile.TimeSpans.TimeSpan.Cooldown | Should Be 33 + } +} + +Describe "GetFleetProfileXml" { + It "HasPeak" { + { $peak = Get-FleetProfileXml -Name Peak -BlockSize 8KB -WriteRatio 0 } | Should Not Throw + $peak = Get-FleetProfileXml -Name Peak -BlockSize 8KB -WriteRatio 0 + $peak | Should Not BeNullOrEmpty + } + + It "PeakDoesNotDefineBaseMax" { + $peak = Get-FleetProfileXml -Name Peak -BlockSize 8KB -WriteRatio 0 + $peak.SelectNodes('Profile/TimeSpans/TimeSpan/Targets/Target/BaseFileOffset') | Should BeNullOrEmpty + $peak.SelectNodes('Profile/TimeSpans/TimeSpan/Targets/Target/MaxFileSize') | Should BeNullOrEmpty + } + + It "PeakShouldAcceptBase" { + $peak = Get-FleetProfileXml -Name Peak -BlockSize 8KB -WriteRatio 0 -BaseOffset 1GB + $peak.SelectNodes('Profile/TimeSpans/TimeSpan/Targets/Target/MaxFileSize') | Should BeNullOrEmpty + $n = $peak.SelectNodes('Profile/TimeSpans/TimeSpan/Targets/Target/BaseFileOffset') + $n | Should Not BeNullOrEmpty + $n.Count | Should Be 1 + + $n.Item(0).InnerText | Should Be ([string] 1GB) + } + + It "PeakShouldAcceptMax" { + $peak = Get-FleetProfileXml -Name Peak -BlockSize 8KB -WriteRatio 0 -MaxOffset 2GB + $peak.SelectNodes('Profile/TimeSpans/TimeSpan/Targets/Target/BaseFileOffset') | Should BeNullOrEmpty + $n = $peak.SelectNodes('Profile/TimeSpans/TimeSpan/Targets/Target/MaxFileSize') + $n | Should Not BeNullOrEmpty + + $n.Count | Should Be 1 + $n.Item(0).InnerText | Should Be ([string] 2GB) + } + + It "PeakShouldAcceptBaseMax" { + $peak = Get-FleetProfileXml -Name Peak -BlockSize 8KB -WriteRatio 0 -BaseOffset 1GB -MaxOffset 2GB + + $n = $peak.SelectNodes('Profile/TimeSpans/TimeSpan/Targets/Target/BaseFileOffset') + $n | Should Not BeNullOrEmpty + $n.Count | Should Be 1 + $n.Item(0).InnerText | Should Be ([string] 1GB) + + $n = $peak.SelectNodes('Profile/TimeSpans/TimeSpan/Targets/Target/MaxFileSize') + $n | Should Not BeNullOrEmpty + $n.Count | Should Be 1 + $n.Item(0).InnerText | Should Be ([string] 2GB) + } + + It "PeakShouldAcceptThreads" { + $peak = Get-FleetProfileXml -Name Peak -BlockSize 8KB -WriteRatio 0 -ThreadsPerTarget 2 + + $n = $peak.SelectNodes('Profile/TimeSpans/TimeSpan/Targets/Target/ThreadsPerFile') + $n | Should Not BeNullOrEmpty + $n.Count | Should Be 1 + $n.Item(0).InnerText | Should Be ([string] 2) + } +} + + +InModuleScope VMFleet { + + Describe "GetNextSplit" { + + It "ShouldBeLargest@End" { + $o = [PSCustomObject]@{ + Value = 0 + CutoffType =[CutoffType]::No + }, + [PSCustomObject]@{ + Value = 5 + CutoffType =[CutoffType]::No + }, + [PSCustomObject]@{ + Value = 15 + CutoffType =[CutoffType]::No + }, + [PSCustomObject]@{ + Value = 40 + CutoffType =[CutoffType]::No + } + + $p1, $p2 = GetNextSplit $o 'Value' -OrderBy 'Value' + $p1.Value | Should Be 40 + $p2.Value | Should Be 15 + } + + It "ShouldBeLargest@Begin" { + $o = [PSCustomObject]@{ + Value = 40 + CutoffType =[CutoffType]::No + }, + [PSCustomObject]@{ + Value = 5 + CutoffType =[CutoffType]::No + }, + [PSCustomObject]@{ + Value = 15 + CutoffType =[CutoffType]::No + }, + [PSCustomObject]@{ + Value = 0 + CutoffType =[CutoffType]::No + } + + $p1, $p2 = GetNextSplit $o 'Value' -OrderBy 'Value' + $p1.Value | Should Be 40 + $p2.Value | Should Be 15 + } + + It "ShouldBeFirstOfEqual" { + $o = [PSCustomObject]@{ + Value = 0 + Order = 0 + CutoffType =[CutoffType]::No + }, + [PSCustomObject]@{ + Value = 10 + Order = 1 + CutoffType =[CutoffType]::No + }, + [PSCustomObject]@{ + Value = 20 + Order = 2 + CutoffType =[CutoffType]::No + }, + [PSCustomObject]@{ + Value = 30 + Order = 3 + CutoffType =[CutoffType]::No + } + + $p1, $p2 = GetNextSplit $o 'Value' -OrderBy 'Value' + $p1.Value | Should Be 10 + $p2.Value | Should Be 0 + } + + It "ShouldRespectOrder" { + $o = [PSCustomObject]@{ + Value = 0 + Order = 0 + CutoffType =[CutoffType]::No + }, + [PSCustomObject]@{ + Value = 10 + Order = 2 + CutoffType =[CutoffType]::No + }, + [PSCustomObject]@{ + Value = 20 + Order = 3 + CutoffType =[CutoffType]::No + }, + [PSCustomObject]@{ + Value = 30 + Order = 1 + CutoffType =[CutoffType]::No + } + + $p1, $p2 = GetNextSplit $o 'Value' -OrderBy 'Order' + $p1.Value | Should Be 30 + $p2.Value | Should Be 0 + } + + It "ShouldRespectCutoff" { + $o = [PSCustomObject]@{ + Value = 0 + CutoffType =[CutoffType]::No + }, + [PSCustomObject]@{ + Value = 10 + CutoffType =[CutoffType]::No + }, + [PSCustomObject]@{ + Value = 30 + CutoffType =[CutoffType]::Scale + }, + [PSCustomObject]@{ + Value = 60 + CutoffType =[CutoffType]::Scale + } + + $p1, $p2 = GetNextSplit $o 'Value' -OrderBy 'Value' + $p1.Value | Should Be 30 + $p2.Value | Should Be 10 + } + + It "ShouldRespectCutoffOrdered" { + $o = [PSCustomObject]@{ + Value = 0 + CutoffType =[CutoffType]::No + }, + [PSCustomObject]@{ + Value = 30 + CutoffType =[CutoffType]::Scale + }, + [PSCustomObject]@{ + Value = 10 + CutoffType =[CutoffType]::No + }, + [PSCustomObject]@{ + Value = 60 + CutoffType =[CutoffType]::Scale + } + + $p1, $p2 = GetNextSplit $o 'Value' -OrderBy 'Value' + $p1.Value | Should Be 30 + $p2.Value | Should Be 10 + } + } + + Describe "GetUpperAnchor" { + + It "ShouldReturnFinalIfNotCutoff" { + $o = [PSCustomObject]@{ + Value = 0 + Order = 0 + CutoffType =[CutoffType]::No + }, + [PSCustomObject]@{ + Value = 10 + Order = 2 + CutoffType =[CutoffType]::No + }, + [PSCustomObject]@{ + Value = 20 + Order = 3 + CutoffType =[CutoffType]::No + }, + [PSCustomObject]@{ + Value = 30 + Order = 1 + CutoffType =[CutoffType]::No + } + + $p1,$p2 = GetUpperAnchor $o -OrderBy 'Order' + $p1.Value | Should Be 20 + $p2.Value | Should Be 10 + } + + It "ShouldReturnFirstCutoff" { + $o = [PSCustomObject]@{ + Value = 0 + Order = 0 + CutoffType =[CutoffType]::No + }, + [PSCustomObject]@{ + Value = 10 + Order = 2 + CutoffType =[CutoffType]::Scale + }, + [PSCustomObject]@{ + Value = 20 + Order = 3 + CutoffType =[CutoffType]::No + }, + [PSCustomObject]@{ + Value = 30 + Order = 1 + CutoffType =[CutoffType]::No + } + + $p1,$p2 = GetUpperAnchor $o -OrderBy 'Order' + $p1.Value | Should Be 10 + $p2.Value | Should Be 30 + } + } + + Describe "IsProfileThroughputLimited" { + + It "PeakIsNot" { + $x = Get-FleetProfileXml -Name Peak -BlockSize 4KB -WriteRatio 0 + IsProfileThroughputLimited -ProfileXml $x | Should Be $false + } + + It "SqlIs" { + $x = Get-FleetProfileXml -Name Sql + IsProfileThroughputLimited -ProfileXml $x | Should Be $true + } + } + + Describe "IsProfileSingleTimespan" { + + It "PeakIs" { + $x = Get-FleetProfileXml -Name Peak -BlockSize 4KB -WriteRatio 0 + IsProfileSingleTimespan -ProfileXml $x | Should Be $true + } + } + + Describe "IsProfileSingleTarget" { + + It "PeakIs" { + $x = Get-FleetProfileXml -Name Peak -BlockSize 4KB -WriteRatio 0 + IsProfileSingleTarget -ProfileXml $x | Should Be $true + } + + It "SqlIsNot" { + $x = Get-FleetProfileXml -Name Sql + IsProfileSingleTarget -ProfileXml $x | Should Be $false + } + } + + Describe "GetFleetProfileFootprint" { + + BeforeAll { + $sql = Get-FleetProfileXml -Name SQL + $vdi = Get-FleetProfileXml -Name VDI + } + + It "CheckVDI" { + $vdi | Should Not BeNullOrEmpty + $f = GetFleetProfileFootprint -ProfileXml $vdi + $f.Count | Should Be 1 + $f['*1'].BaseOffset | Should Be 0 + $f['*1'].MaxOffset | Should Be (10GB) + } + + It "CheckVDIRead" { + $vdi | Should Not BeNullOrEmpty + $f = GetFleetProfileFootprint -ProfileXml $vdi -Read + $f.Count | Should Be 1 + $f['*1'].BaseOffset | Should Be 0 + $f['*1'].MaxOffset | Should Be (8GB) + } + + It "CheckSQL" { + $sql | Should Not BeNullOrEmpty + $f = GetFleetProfileFootprint -ProfileXml $sql + $f.Count | Should Be 1 + $f['*1'].BaseOffset | Should Be 0 + $f['*1'].MaxOffset | Should Be 0 + } + + It "CheckSQLRead" { + $sql | Should Not BeNullOrEmpty + $f = GetFleetProfileFootprint -ProfileXml $sql -Read + $f.Count | Should Be 1 + $f['*1'].BaseOffset | Should Be (5GB) + $f['*1'].MaxOffset | Should Be 0 + } + } + + Describe "TimespanToString" { + + BeforeAll { + $t0 = [datetime] '7/31/1996 12:00PM' + } + + It "Seconds" { + TimespanToString ($t0.AddMilliseconds(1500) - $t0) | Should Be "01.5s" + } + + It "Minutes" { + TimespanToString ($t0.AddMinutes(15) - $t0) | Should Be "15m:00.0s" + } + + It "Hours" { + TimespanToString ($t0.AddHours(15) - $t0) | Should Be "15h:00m:00.0s" + } + + It "Days" { + TimespanToString ($t0.AddDays(15) - $t0) | Should Be "15d.00h:00m:00.0s" + } + } +} \ No newline at end of file diff --git a/CristalDiskMark/source/diskspd22/Frameworks/VMFleet/VMFleet.format.ps1xml b/CristalDiskMark/source/diskspd22/Frameworks/VMFleet/VMFleet.format.ps1xml new file mode 100644 index 0000000..2b6393c --- /dev/null +++ b/CristalDiskMark/source/diskspd22/Frameworks/VMFleet/VMFleet.format.ps1xml @@ -0,0 +1,82 @@ + + + + + + StorageBusBindingTableView + + VolumeEstimate + + + + + + + + + + + + + + + + + + + + + + + + + + + VolumeType + + + Right + + $v = $_.MirrorSize; + $postfixes = @( "B", "KB", "MB", "GB", "TB", "PB" ) + for ($i=0; $v -ge 1024 -and $i -lt $postfixes.Length; $i++) { $v /= 1024; } + return "" + [System.Math]::Round($v,2) + " " + $postfixes[$i]; + + + + MirrorTierName + + + Right + + $v = $_.ParitySize; + $postfixes = @( "B", "KB", "MB", "GB", "TB", "PB" ) + for ($i=0; $v -ge 1024 -and $i -lt $postfixes.Length; $i++) { $v /= 1024; } + return "" + [System.Math]::Round($v,2) + " " + $postfixes[$i]; + + + + ParityTierName + + + Right + + $v = $_.Size; + $postfixes = @( "B", "KB", "MB", "GB", "TB", "PB" ) + for ($i=0; $v -ge 1024 -and $i -lt $postfixes.Length; $i++) { $v /= 1024; } + return "" + [System.Math]::Round($v,2) + " " + $postfixes[$i]; + + + + + + + + + \ No newline at end of file diff --git a/CristalDiskMark/source/diskspd22/Frameworks/VMFleet/VMFleet.psd1 b/CristalDiskMark/source/diskspd22/Frameworks/VMFleet/VMFleet.psd1 new file mode 100644 index 0000000..f0bb05b --- /dev/null +++ b/CristalDiskMark/source/diskspd22/Frameworks/VMFleet/VMFleet.psd1 @@ -0,0 +1,197 @@ +<# +VM Fleet + +Copyright(c) Microsoft Corporation +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +#> + +# +# Module manifest for module 'VMFleet' +# +# Generated on: 1/30/2021 +# + +@{ + +# Script module or binary module file associated with this manifest. +RootModule = 'VMFleet.psm1' + +# Version number of this module. Even build# is release, odd pre-release (Mj.Mn.Bd.Rv) +ModuleVersion = '2.1.0.0' + +# Supported PSEditions +# CompatiblePSEditions = @() + +# ID used to uniquely identify this module +GUID = '753ad5da-01b3-4cc8-a475-16a09a021384' + +# Author of this module +Author = 'Microsoft Corporation' + +# Company or vendor of this module +CompanyName = 'Microsoft Corporation' + +# Copyright statement for this module +Copyright = '(c) 2021 Microsoft Corporation. All rights reserved.' + +# Description of the functionality provided by this module +Description = 'VM Fleet is a performance characterization and analyst framework for exploring the storage capabilities of Windows Server Hyper-Converged environments with Storage Spaces Direct' + +# Minimum version of the Windows PowerShell engine required by this module +PowerShellVersion = '5.1' + +# Name of the Windows PowerShell host required by this module +# PowerShellHostName = '' + +# Minimum version of the Windows PowerShell host required by this module +# PowerShellHostVersion = '' + +# Minimum version of Microsoft .NET Framework required by this module. This prerequisite is valid for the PowerShell Desktop edition only. +# DotNetFrameworkVersion = '' + +# Minimum version of the common language runtime (CLR) required by this module. This prerequisite is valid for the PowerShell Desktop edition only. +# CLRVersion = '' + +# Processor architecture (None, X86, Amd64) required by this module +# ProcessorArchitecture = '' + +# Modules that must be imported into the global environment prior to importing this module +# RequiredModules = @() + +# Assemblies that must be loaded prior to importing this module +# RequiredAssemblies = @() + +# Script files (.ps1) that are run in the caller's environment prior to importing this module. +# ScriptsToProcess = @() + +# Type files (.ps1xml) to be loaded when importing this module +# TypesToProcess = @() + +# Format files (.ps1xml) to be loaded when importing this module +FormatsToProcess = @( 'VMFleet.format.ps1xml' ) + +# Modules to import as nested modules of the module specified in RootModule/ModuleToProcess +NestedModules = @( + 'Profile.psm1', + 'WatchCluster.psm1', + 'WatchCPU.psm1' +) + +# Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export. +FunctionsToExport = @( + 'Clear-FleetPause', + 'Clear-FleetRunState', + 'Convert-FleetXmlToString', + 'Get-FleetComputeTemplate', + 'Get-FleetDisk', + 'Get-FleetDataDiskEstimate', + 'Get-FleetPath', + 'Get-FleetPause', + 'Get-FleetPolynomialFit', + 'Get-FleetPowerScheme', + 'Get-FleetProfileXml', + 'Get-FleetResultLog', + 'Get-FleetVersion', + 'Get-FleetVM', + 'Get-FleetVolumeEstimate', + 'Install-Fleet', + 'Measure-FleetCoreWorkload', + 'Move-Fleet', + 'New-Fleet', + 'Remove-Fleet', + 'Repair-Fleet', + 'Set-ArcConfig', + 'Set-Fleet', + 'Set-FleetPause', + 'Set-FleetPowerScheme', + 'Set-FleetProfile', + 'Set-FleetQoS', + 'Set-FleetRunProfileScript', + 'Show-Fleet', + 'Show-FleetCpuSweep', + 'Show-FleetPause', + 'Start-Fleet', + 'Start-FleetReadCacheWarmup', + 'Start-FleetResultRun', + 'Start-FleetRun', + 'Start-FleetSweep', + 'Start-FleetWriteWarmup', + 'Stop-Fleet', + 'Test-FleetResultRun', + 'Use-FleetPolynomialFit', + 'Watch-FleetCluster', + 'Watch-FleetCPU', + 'Initialize-ArcVMs' +) + +# Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export. +CmdletsToExport = @( + +) + +# Variables to export from this module +VariablesToExport = $null + +# Aliases to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no aliases to export. +AliasesToExport = @() + +# DSC resources to export from this module +# DscResourcesToExport = @() + +# List of all modules packaged with this module +# ModuleList = @() + +# List of all files packaged with this module +# FileList = @() + +# Private data to pass to the module specified in RootModule/ModuleToProcess. This may also contain a PSData hashtable with additional module metadata used by PowerShell. +PrivateData = @{ + + PSData = @{ + + # Tags applied to this module. These help with module discovery in online galleries. + # Tags = @() + + # A URL to the license for this module. + # LicenseUri = '' + + # A URL to the main website for this project. + ProjectUri = 'https://www.github.com/microsoft/diskspd' + + # A URL to an icon representing this module. + # IconUri = '' + + # ReleaseNotes of this module + # ReleaseNotes = '' + + } # End of PSData hashtable + +} # End of PrivateData hashtable + +# HelpInfo URI of this module +# HelpInfoURI = '' + +# Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix. +# DefaultCommandPrefix = '' + +} \ No newline at end of file diff --git a/CristalDiskMark/source/diskspd22/Frameworks/VMFleet/VMFleet.psm1 b/CristalDiskMark/source/diskspd22/Frameworks/VMFleet/VMFleet.psm1 new file mode 100644 index 0000000..d22a180 --- /dev/null +++ b/CristalDiskMark/source/diskspd22/Frameworks/VMFleet/VMFleet.psm1 @@ -0,0 +1,9294 @@ +<# +VM Fleet + +Copyright(c) Microsoft Corporation +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +#> + +Set-StrictMode -Version 3.0 + +# Globals @ Module-only scope (others in CommonFunc) + +enum PauseState { + Current + Stale +} + +enum CutoffType { + No + Scale + CPU + WriteLatency + ReadLatency + Surge +} + +enum RunType { + Default + Baseline + AnchorSearch +} + +enum VolumeType +{ + Mirror + NestedMirror + Parity + MAP + Collect +} + +class VolumeEstimate +{ + [VolumeType] $VolumeType + [uint64] $MirrorSize + [string] $MirrorTierName + [uint64] $ParitySize + [string] $ParityTierName + [uint64] $Size + + VolumeEstimate( + [VolumeType] $VolumeType, + [uint64] $MirrorSize, + [string] $MirrorTierName, + [uint64] $ParitySize, + [string] $ParityTierName + ) + { + $this.VolumeType = $VolumeType + $this.MirrorSize = $MirrorSize + $this.MirrorTierName = $MirrorTierName + $this.ParitySize = $ParitySize + $this.ParityTierName = $ParityTierName + $this.Size = $MirrorSize + $ParitySize + } +} + +$vmSwitchName = 'FleetInternal' +$vmSwitchIP = '169.254.1.1' + +# Note: this can be directly determined by Get-SmbClientConfiguration. Changes are not expected, but +# since the controlling timeout is in the guest lets simply wire it down. Actual is normally 10s, use +# +2s for margin. +$smbInfoCacheLifetime = 12 + +# +# Embedded scripts for VM control/pickup +# +# These are installed in the control directory and referenced/run by the VM Fleet. +# The Set verb is used as a meta-comment. These are never executed in context of the module +# and are not exported. +# + +# +# The reference manual-edit runner script +# +function Set-FleetBaseScript +{ + # buffer size/alighment, threads/target, outstanding/thread, write% + $b = 4; $t = 1; $o = 32; $w = 0 + + # optional - specify rate limit in iops, translated to bytes/ms for DISKSPD + # $iops = 500 + if ($null -ne $iops) { $g = $iops * $b * 1KB / 1000 } + + # io pattern, (r)andom or (s)equential (si as needed for multithread) + $p = 'r' + + # durations of test, cooldown, warmup + $d = 30*60; $cool = 30; $warm = 60 + + $addspec = '' + $gspec = $null + + # cap -> true to capture xml results, otherwise human text + $cap = $false + + ### prior to this is template + + if ($null -ne $g) { $gspec = "g$($g)" } + $result = "result-b$($b)t$($t)o$($o)w$($w)p$($p)$($gspec)" + if ($addspec.Length) { $result += "-$($addspec)" } + $result += "-$(Get-Content C:\vmspec.txt).xml" + $dresult = "l:\result" + $lresultf = Join-Path "C:\run" $result + $dresultf = Join-Path $dresult $result + + if (-not (Get-Item $dresultf -ErrorAction SilentlyContinue)) { + + if ($cap) { + $res = 'xml' + } else { + $res = 'text' + } + + # look for data disk - if present, it will always be disk 1. disk 0 is boot/os. + # only use it if it is a raw device. we do not have a convention for using a + # filesystem on it at this time. + $d1 = Get-Disk -Number 1 -ErrorAction SilentlyContinue + if ($null -ne $d1 -and $d1.IsBoot -eq $false -and $d1.PartitionStyle -eq 'RAW') + { + $target = '#1' + } + else + { + $target = (Get-ChildItem C:\run\testfile?.dat) + } + + $gspec = $null + if ($null -ne $g) { $gspec = "-g$($g)" } + $o = C:\run\diskspd.exe -Z20M -z -h `-t$t `-o$o $gspec `-b$($b)k `-$($p)$($b)k `-w$w `-W$warm `-C$cool `-d$($d) -D -L `-R$res $target + + if ($cap) { + + # export result and indicate done flag to control + + $o | Out-File $lresultf -Encoding ascii -Width ([int32]::MaxValue) + [PSCustomObject]@{ + Result = @( $lresultf ) + Stash = $null + } + + } else { + + #emit to human watcher + $o | Out-Host + } + + } else { + + Write-Host -fore green already done $dresultf + + # indicate done flag to control + # this should only occur if controller does not change variation + [PSCustomObject]@{ + Result = $null + Stash = $null + } + } + + [system.gc]::Collect() +} + +# +# The VM controller script, run by the VMs on start/login +# +function Set-FleetControlScript +{ + param( + [string] $connectuser, + [string] $connectpass + ) + + function Get-ProcessDump + { + [CmdletBinding()] + param( + [Parameter(Mandatory = $true, ValueFromPipeline = $true)] + [System.Diagnostics.Process] + $Process, + + [Parameter(Mandatory = $true)] + [string] + $DumpFile + ) + + begin + { + $wer = [PSObject].Assembly.GetType('System.Management.Automation.WindowsErrorReporting') + $methods = $wer.GetNestedType('NativeMethods', 'NonPublic') + $flags = [Reflection.BindingFlags] 'NonPublic, Static' + $api = $methods.GetMethod('MiniDumpWriteDump', $Flags) + + # Normalize unqualified paths to current working directory + $dfp = Split-Path $DumpFile -Parent + if ($dfp.Length -eq 0) + { + $DumpFile = Join-Path $PWD.Path $DumpFile + } + } + + process + { + # Subst in PID to uniquify multiple processes / same name + $dfs = $DumpFile -split '\.' + $dfs[-2] += "-$($Process.ID)" + $df = $dfs -join '.' + + $f = New-Object IO.FileStream($df, [IO.FileMode]::Create) + + $r = $api.Invoke($null, @($Process.Handle, + $Process.Id, + $f.SafeFileHandle, + [UInt32] 2, # FullMemory + [IntPtr]::Zero, + [IntPtr]::Zero, + [IntPtr]::Zero)) + + $f.Close() + + if (-not $r) + { + $errorCode = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error() + + # Remove any partially written dump file. + Remove-Item $df -Force -ErrorAction SilentlyContinue + + throw "failed to dump $($Process.Name) PID $($Process.Id), error $errorcode" + } + else + { + Get-ChildItem $df + } + } + } + + function CopyKeyIf + { + param( + [Parameter(Mandatory = $true, Position = 0)] + [hashtable] + $HSource, + + [Parameter(Mandatory = $true, Position = 1)] + [hashtable] + $HDest, + + [Parameter(Mandatory = $true, Position = 2)] + [string] + $Key + ) + + if ($HSource.ContainsKey($Key)) + { + $HDest[$Key] = $HSource[$Key] + } + } + + function LogOutput + { + [CmdletBinding()] + param( + [Parameter(Mandatory = $true, Position = 0, ValueFromRemainingArguments)] + [ValidateNotNullOrEmpty()] + [string[]] + $Message, + + [Parameter()] + [System.ConsoleColor] + $ForegroundColor, + + [Parameter()] + [switch] + $IsVb, + + [Parameter()] + [switch] + $NoNewline, + + [Parameter()] + [switch] + $CarriageReturn + ) + + $m = ((Get-Date).GetDateTimeFormats('s')[0] + ": $($Message -join ' ')") + if ($PSBoundParameters.ContainsKey('IsVb')) + { + Write-Verbose $m + } + else + { + $whParam = @{} + CopyKeyIf $PSBoundParameters $whParam 'ForegroundColor' + CopyKeyIf $PSBoundParameters $whParam 'NoNewline' + if ($PSBoundParameters.ContainsKey('CarriageReturn')) + { + $m += "`r" + } + Write-Host @whParam $m + } + } + + function DisableWindowsRE + { + # + # Disable the Windows Recovery console. Under aggresive conditions like repeated start/stop on the part + # of a runner, Windows RE may get triggered and trap the VMs in the recovery console. While recoverable + # with Repair-Fleet, lets prevent that since RE doesn't provide value to VM Fleet ops. + # + # It would be nice if we could do this during VM provisioning. + # + + $state = reagentc /info |% { + + if ( $_ -match 'Windows RE status:\s+(\S+)') + { + $matches[1] + } + } + + if ($state -eq 'Enabled') + { + $out = reagentc /disable + $status = $? + LogOutput "Disabling Windows RE: $out" + if (-not $status) + { + LogOutput -ForegroundColor Red "Failed to disable Windows RE - VM may enter the recovery console" + } + } + } + + function ValidateSmbMapping + { + param( + [Parameter(Mandatory = $true)] + $LocalDriveLetter, + + [Parameter(Mandatory = $true)] + $RemotePath, + + [Parameter()] + $UserName, + + [Parameter()] + $Password, + + [Parameter()] + $TestPath + ) + + $maxAttempt = 10 + $localPath = "$($LocalDriveLetter):" + if ($PSBoundParameters.ContainsKey('TestPath')) + { + # Cannot Join-Path since it will attempt to resolve: this may not exist at time zero + $testPath = $localPath + '\' + $TestPath + } + else + { + $testPath = $localPath + } + + $mapParams = @{ + LocalPath = $localPath + RemotePath = $RemotePath + } + CopyKeyIf $PSBoundParameters $mapParams 'UserName' + CopyKeyIf $PSBoundParameters $mapParams 'Password' + + function Create + { + LogOutput "CREATE SMB Mapping $localPath => $remotePath" + $null = New-SmbMapping @mapParams + } + + function Teardown + { + LogOutput "REMOVE SMB Mapping $localPath => $remotePath" + Remove-SmbMapping -LocalPath $localPath -Force -Confirm:$false -UpdateProfile + } + + for ($nAttempt = 0; $true; $nAttempt += 1) + { + # Indicate connection rebuild attempts (do not emit on first pass - successful validation s.b. silent) + if ($nAttempt -gt 0) + { + LogOutput "VALIDATE SMB Mapping $localPath => $remotePath (attempt $nAttempt)" + } + + # Throw out after maxAttempts + if ($nAttempt -ge $maxAttempt) + { + LogOutput -ForegroundColor Red "FAIL: SMB connection not recoverable after $maxAttempt tries" + throw "SMB Connection Failure" + } + + $mapping = Get-SmbMapping -LocalPath $localPath -ErrorAction SilentlyContinue + + # Create missing mapping + if ($null -eq $mapping) + { + LogOutput "NOT PRESENT SMB Mapping @ $localPath" + Start-Sleep 1 + Create + continue + } + + # Mapping reports bad, teardown and recreate + if ($mapping.Status -ne 'OK') + { + LogOutput "NOT OK SMB Mapping @ $localPath reporting status = $($mapping.Status)" + Start-Sleep 1 + Teardown + Create + continue + } + + # If test path inaccessible, try teardown/recreate to recover + if (-not (Test-Path -Path $testPath -ErrorAction Continue)) + { + LogOutput "ACCESS FAILED to test path @ $testPath" + Start-Sleep 1 + Teardown + Create + continue + } + + # Indicate connection rebuilt successfully (do not emit on successful validation of existing) + if ($nAttempt -gt 0) + { + LogOutput -ForegroundColor Green "SMB Mapping $localPath => $remotePath connected" + } + + break + } + } + + # Drive mapping for initial/periodic validation + $mapParam = @{ + LocalDriveLetter = 'L' + RemotePath = '\\169.254.1.1\c$\clusterstorage\collect' + TestPath = 'flag\pause' + UserName = $connectuser + Password = $connectpass + } + + # Initial configuration checks + ValidateSmbMapping @mapParam + DisableWindowsRE + + # update tooling + Copy-Item L:\tools\* C:\run -Force + + $run = 'C:\run\run.ps1' + $control = 'C:\run\control.ps1' + $stashDir = "C:\run\stash" + + $null = mkdir $stashDir -ErrorAction SilentlyContinue + + $myname = Get-Content C:\vmspec.txt + $mypause = "L:\flag\pause-$myname" + $mydone = "L:\flag\done-$myname" + + $pause = $false + $gowait = $false + $gowaitf = $false + + function get-newfile { + param( + [string] + $Source, + + [string] + $Dest, + + [string[]] + $Exclude, + + [switch] + $Silent + ) + + $gcParam = @{ Path = $Source } + if ($PSBoundParameters.ContainsKey('Exclude')) + { + $gcParam['Exclude'] = $Exclude + } + $sf = Get-ChildItem @gcParam | Sort-Object -Property LastWriteTime -Descending | Select-Object -first 1 + $df = Get-Item $Dest -ErrorAction SilentlyContinue + + # no source? + if ($null -eq $sf) + { + LogOutput -ForegroundColor Green NO source present + return $null + } + + # no destination, always take source + if ($null -eq $df) + { + return $sf + } + + if ($sf.LastWriteTime -gt $df.LastWriteTime) + { + $sfh = Get-FileHash $sf + $dfh = Get-FileHash $df + + # files are different, indicate + if ($sfh.Hash -ne $dfh.Hash) + { + return $sf + } + + # files are the same but the last write time has moved - ignore, pull + # up lastwrite on destination + + LogOutput -ForegroundColor Green IGNORE newer last write with no source change + $df.LastWriteTime = $sf.LastWriteTime + } + + # Have latest, indicate no new + return $null + } + + function get-flagfile( + [ValidateSet('Go','Pause','Done')] + [string] $Flag + ) + { + switch ($Flag) + { + 'Go' { $f = 'L:\flag\go' } + 'Pause' { $f = 'L:\flag\pause' } + 'Done' { $f = "L:\flag\done-$myname" } + } + + if (Test-Path $f) { + [int](Get-Content $f -ErrorAction SilentlyContinue) + } else { + 0 + } + } + + # Active (responded to) and Current (content) of respective flag + $flag = @{} + foreach ($f in 'pause','go') + { + $flag.$f = [pscustomobject] @{ acked = 0; current = 0 } + } + + # Get acked go flag at time zero; ticks forward during operation + $flag.go.acked = get-flagfile Done + + while ($true) { + + ValidateSmbMapping @mapParam + + # update control? + # this passes back out to the launcher which re-executes the controller + $newf = get-newfile -Source L:\control\control.ps1 -Dest $control -Silent + if ($null -ne $newf) { + LogOutput "New $($newf.Name) @ $($newf.LastWriteTime)" + Copy-Item $newf -Destination $control -Force + break + } + + try + { + # check go epoch - this can change while paused (say, clear) + $flag.go.current = get-flagfile Go + + # outside go run, drop ack + if ($flag.go.current -eq 0 -and $flag.go.acked -ne 0) + { + LogOutput "CLEAR Go ENTER FREE RUN" + Write-Output 0 > $mydone + $flag.go.acked = 0 + } + + # check and acknowledge pause - only drop flag once + $flag.pause.current = get-flagfile Pause + if ($flag.pause.current -ne 0) { + + # drop into pause flagfile if needed + if ($pause -eq $false -or ($flag.pause.acked -ne $flag.pause.current)) { + + LogOutput -ForegroundColor Red "PAUSED (flag @ $($flag.pause.current))" + Write-Output $flag.pause.current > $mypause + $flag.pause.acked = $flag.pause.current + + $pause = $true + } + + continue + } + + # pause is now clear + $pause = $false + if ($flag.pause.acked -ne 0) + { + LogOutput -ForegroundColor Red "PAUSE RELEASED (flag @ $($flag.pause.acked))" + $flag.pause.acked = 0 + + # Reissue go wait logging as appropriate + $gowait = $gowaitf = $false + } + + # if go is zero this is free-running new/existing run file + # if go is nonzero but we have already acked, we are waiting for a new go + if ($flag.go.current -ne 0) + { + if ($flag.go.current -eq $flag.go.acked) + { + if ($gowait -eq $false) + { + $gowait = $true + LogOutput -ForegroundColor Cyan "WAITING FOR GO" + } + + continue + } + } + + # check for update to run script + $newf = get-newfile -Source L:\control\*.ps1 -Dest $run -Exclude control.ps1 + $runf = Get-Item $run -ErrorAction SilentlyContinue + + if ($null -eq $runf -and $null -eq $newf) { + LogOutput -ForegroundColor Yellow "NO run file local or from fleet" + continue + } + + # if go is nonzero, only move on new run file + if ($flag.go.current -ne 0) + { + if ($null -eq $newf) + { + if ($gowaitf -eq $false) + { + $gowaitf = $true + LogOutput -ForegroundColor Cyan "WAITING on run file for GO $($flag.go.current)" + } + + continue + } + } + + # GO check complete, lift squelches + $gowait = $gowaitf = $false + + # copy new file if available + if ($null -ne $newf) + { + Copy-Item $newf -Destination $run -Force + $runf = Get-Item $run + $msg = "NEW $($newf.Name) =>" + } + else + { + $msg = "EXISTING" + } + LogOutput -ForegroundColor Cyan "$msg $($runf.Name) $($runf.lastwritetime)" + + # log start (free/GO) + if ($flag.go.current -ne 0) + { + $msg = "GO $($flag.go.current)" + } + else + { + $msg = "FREE RUN" + } + LogOutput -ForegroundColor Cyan "STARTING $msg" + LogOutput -ForegroundColor Cyan "BEGIN" ("*"*20) + + # If data disk is present, bring it online/readwrite if needed (initial state). + # Note that only a single disk is supported at this time. + # This is delayed so that hot-resize/attach is possible without restarting the VM. + $d1 = Get-Disk -Number 1 -ErrorAction SilentlyContinue + if ($null -ne $d1) + { + if ($d1.IsOffline) { $d1 | Set-Disk -IsOffline:$false } + if ($d1.IsReadOnly) { $d1 | Set-Disk -IsReadOnly:$false } + } + + # launch and monitor pause and new run file + $j = start-job -arg $run { param($run) & $run } + while ($null -eq ($jf = wait-job $j -Timeout 1)) + { + $halt = $null + + # check pause or new run file: if so, stop and loop + if (0 -ne (get-flagfile Pause)) + { + $halt = 'pause set' + + # snap diskspd process dumps in case this pause is due to forced + # termination as a result of non-responsive / slow result return + Remove-Item c:\run\diskspd*.dmp -ErrorAction SilentlyContinue -Force + Get-Process diskspd | Get-ProcessDump -DumpFile c:\run\diskspd.dmp |% { LogOutput "DUMP: $($_.FullName)" } + } + # unexpected go change? + elseif ($flag.go.current -ne (get-flagfile Go)) + { + $halt = 'go change' + } + # normal edit/drop loop (non-go/done control) - new run file + elseif (get-newfile -Source L:\control\*.ps1 -Dest $run -Exclude control.ps1 -Silent) + { + $halt = 'new run file' + } + # new controller dropped + elseif (get-newfile -Source L:\control\control.ps1 -Dest $control -Silent) + { + $halt = 'new controller' + } + + if ($null -ne $halt) + { + LogOutput -ForegroundColor Yellow "STOPPING (reason: $halt)" + $j | stop-job + $j | remove-job + + # halts end any outstanding GO run + if ($flag.go.current -ne 0) + { + LogOutput -ForegroundColor Yellow "HALT GO $($flag.go.current)" + Write-Output $flag.go.current > $mydone + $flag.go.acked = $flag.go.current + } + break + } + } + + # job finished? + if ($null -ne $jf) { + $result = $jf | receive-job + + if ($null -ne $result) + { + # log free run completion + if ($flag.go.current -eq 0) + { + LogOutput -ForegroundColor Yellow "DONE CURRENT" + } + # log/ack GO completion + else + { + LogOutput -ForegroundColor Yellow "DONE GO $($flag.go.current)" + Write-Output $flag.go.current > $mydone + } + $flag.go.acked = $flag.go.current + + # clear prior stash, if any + Get-ChildItem $stashDir | Remove-Item -Recurse -Force + + # validate SMB connection before pushing results out + ValidateSmbMapping @mapParam + + # propagate any results, stashing them locally along + # with any other content requested (triage material) + foreach ($f in $result.Result) + { + $null = xcopy /j /y /q $f "l:\result" + $null = xcopy /j /y /q $f $stashDir + Remove-Item $f -Force + } + + foreach ($f in $result.Stash) + { + $null = xcopy /j /y /q $f $stashDir + Remove-Item $f -Force + } + } + + $jf | remove-job + } + + LogOutput -ForegroundColor Cyan "END" ("*"*20) + } + catch + { + $_ + } + finally + { + # force gc to teardown potentially conflicting handles and enforce min pause + [system.gc]::Collect() + Start-Sleep 1 + } + } +} + +function Set-SweepTemplateScript +{ + # __Unique__ + # buffer size/alighment, threads/target, outstanding/thread, write% + $b = __b__; $t = __t__; $o = __o__; $w = __w__ + + # optional - specify rate limit in iops _-gNNNi + $iops = __iops__ + + # io pattern, (r)andom or (s)equential (si as needed for multithread) + $p = '__p__' + + # durations of test, cooldown, warmup + $d = __d__; $cool = __Cool__; $warm = __Warm__ + + # handle autoscaled thread count (1 per LP/VCPU) + if ($t -eq 0) + { + $t = (Get-CimInstance Win32_Processor | Measure-Object -Property NumberOfLogicalProcessors -Sum).Sum + } + + # sweep template always captures + $addspec = '-__AddSpec__' + if ($addspec.Length -eq 1) { $addspec = $null } + $iopspec = $null + if ($null -ne $iops) { $iopspec = "iops$($iops)" } + $result = "result-b$($b)t$($t)o$($o)w$($w)p$($p)$($iopspec)$($addspec)-$(Get-Content C:\vmspec.txt).xml" + $dresult = "L:\result" + $lresultf = Join-Path "C:\run" $result + $dresultf = Join-Path $dresult $result + + ### prior to this is template + + if (-not (Get-Item $dresultf -ErrorAction SilentlyContinue)) { + + # look for data disk - if present, it will always be disk 1. disk 0 is boot/os. + # only use it if it is a raw device. we do not have a convention for using a + # filesystem on it at this time. + $d1 = Get-Disk -Number 1 -ErrorAction SilentlyContinue + if ($null -ne $d1 -and $d1.IsBoot -eq $false -and $d1.PartitionStyle -eq 'RAW') + { + $target = '#1' + } + else + { + $target = (Get-ChildItem C:\run\testfile?.dat) + } + + $res = 'xml' + $gspec = $null + if ($null -ne $iops) { $gspec = "-g$($iops)i" } + + C:\run\diskspd.exe -Z20M -z -h `-t$t `-o$o $gspec `-b$($b)k `-$($p)$($b)k `-w$w `-W$warm `-C$cool `-d$($d) -D -L `-R$res $target > $lresultf + + [PSCustomObject]@{ + Result = @( $lresultf ) + Stash = $null + } + + } else { + + write-host -fore green already done $dresultf + + # indicate done flag to control + # this should only occur if control does not change variation + [PSCustomObject]@{ + Result = $null + Stash = $null + } + } + + [system.gc]::Collect() +} + +function Set-RunProfileTemplateScript +{ + # __Unique__ + $addspec = '__AddSpec__' + $result = "result" + if ($addspec.Length) { $result += "-$($addspec)" } + $result += "-$(Get-Content C:\vmspec.txt).xml" + $dresult = "L:\result" + $lresultf = Join-Path "C:\run" $result + $dresultf = Join-Path $dresult $result + + $prof = '__Profile__' + $lprof = "C:\run\profile.xml" + + if (-not (Get-Item $dresultf -ErrorAction SilentlyContinue)) { + + # look for data disk - if present, it will always be disk 1. disk 0 is boot/os. + # only use it if it is a raw device. we do not have a convention for using a + # filesystem on it at this time. + $d1 = Get-Disk -Number 1 -ErrorAction SilentlyContinue + if ($null -ne $d1 -and $d1.IsBoot -eq $false -and $d1.PartitionStyle -eq 'RAW') + { + $target = '#1' + } + else + { + $target = (Get-ChildItem C:\run\testfile?.dat) + } + + Copy-Item $prof $lprof + C:\run\diskspd.exe -z `-X$($lprof) $target > $lresultf + + # stash profile for triage and return payload for export + [PSCustomObject]@{ + Result = @( $lresultf ) + Stash = @( $lprof ) + } + } else { + + write-host -fore green already done $dresultf + + # indicate done flag to control + # this should only occur if control does not change variation + [PSCustomObject]@{ + Result = $null + Stash = $null + } + } + + [system.gc]::Collect() +} + +################### + +# Common functions for local/remote sessions + +$CommonFunc = { + + # + # Globals + # + + enum PathType { + + # Paths + Collect + Control + Result + Tools + Flag + + # Files + Pause + Go + Done + } + + $collectVolumeName = 'collect' + + function CreateErrorRecord + { + [CmdletBinding()] + param + ( + [String] + $ErrorId, + + [String] + $ErrorMessage, + + [System.Management.Automation.ErrorCategory] + $ErrorCategory, + + [Exception] + $Exception, + + [Object] + $TargetObject + ) + + if($null -eq $Exception) + { + $Exception = New-Object System.Management.Automation.RuntimeException $ErrorMessage + } + + $errorRecord = New-Object System.Management.Automation.ErrorRecord @($Exception, $ErrorId, $ErrorCategory, $TargetObject) + return $errorRecord + } + + # Copy key/value from Source->Destination hash if present + function CopyKeyIf + { + param( + [Parameter(Mandatory = $true, Position = 0)] + [hashtable] + $HSource, + + [Parameter(Mandatory = $true, Position = 1)] + [hashtable] + $HDest, + + [Parameter(Mandatory = $true, Position = 2)] + [string] + $Key + ) + + if ($HSource.ContainsKey($Key)) + { + $HDest[$Key] = $HSource[$Key] + } + } + + function LogOutput + { + [CmdletBinding()] + param( + [Parameter(Mandatory = $true, Position = 0, ValueFromRemainingArguments)] + [ValidateNotNullOrEmpty()] + [string[]] + $Message, + + [Parameter()] + [System.ConsoleColor] + $ForegroundColor, + + [Parameter()] + [switch] + $IsVb, + + [Parameter()] + [switch] + $NoNewline, + + [Parameter()] + [switch] + $CarriageReturn + ) + + $m = ((Get-Date).GetDateTimeFormats('s')[0] + ": $($Message -join ' ')") + if ($PSBoundParameters.ContainsKey('IsVb')) + { + Write-Verbose $m + } + else + { + $whParam = @{} + CopyKeyIf $PSBoundParameters $whParam 'ForegroundColor' + CopyKeyIf $PSBoundParameters $whParam 'NoNewline' + if ($PSBoundParameters.ContainsKey('CarriageReturn')) + { + $m += "`r" + } + Write-Host @whParam $m + } + } + + # + # Convert an absolute local path to the equivalent remote path via SMB admin shares + # ex: C:\foo\bar & scratch -> \\scratch\C$\foo\bar + # + + function Get-AdminSharePathFromLocal + { + [CmdletBinding()] + param( + [Parameter()] + [string] + $Node, + + [Parameter()] + [string] + $LocalPath + ) + + "\\"+$Node+"\"+$LocalPath[0]+"$\"+$LocalPath.Substring(3,$LocalPath.Length-3) + } + function Stop-After($step) + { + if ($stopafter -eq $step) { + Write-Host -ForegroundColor Green Stop after $step + return $true + } + return $false + } + + function Get-AccessNode + { + [CmdletBinding()] + param ( + [Parameter()] + [string] + $Cluster = '.' + ) + + $nodes = @(Get-ClusterNode @PsBoundParameters |? State -eq Up) + if ($nodes.Length -eq 0) + { + throw "No nodes of cluster $Cluster are accessible at this time" + } + + $nodes[0].Name + } + + # + # This helper function deals with stable identification of the CSV corresponding + # to a given virtual disk. + # + # In system restore case where a cluster is brought up on previously configured storage + # the CSV name will not restate the virtualdisk name. By looking at the volume device path + # seen by CSV and the volume stack we can make the association. At the volume layer the + # filesystem label will (should) reliably give us the name mapping - and is defensive against + # potentially renamed CSV mounts. + # + # The name is attached to the CSV object as the VDName property. + # + function GetMappedCSV + { + [CmdletBinding()] + param( + [Parameter()] + [string] + $Cluster = '.' + ) + + $node = Get-AccessNode @PsBoundParameters + $csv = Get-ClusterSharedVolume @PsBoundParameters + + # Map of volume path (ex: \?\Volume{9759283a-54c7-40b3-b07d-faef008e1a8d}\) to volume object + $vh = @{} + Get-Volume -CimSession $node |? FileSystem -eq CSVFS |% { $vh[$_.Path] = $_ } + + $csv |% { + + # If the CSV maps to a visible volume, attach the filesystemlabel of the respective volume + # to it. Its volume path us mentioned here under the CSV object. + $v = $vh[$_.SharedVolumeInfo.Partition.Name] + + if ($null -ne $v) + { + $VDName = $v.FileSystemLabel + } + else + { + $VDName = $null + } + + # Add and emit + $_ | Add-Member -NotePropertyName VDName -NotePropertyValue $VDName -PassThru + } + } + + function Get-FleetPath + { + [CmdletBinding()] + param ( + [Parameter()] + [string] + $Cluster = ".", + + [Parameter()] + [PathType[]] + $PathType, + + [Parameter()] + [switch] + $Local + ) + + $c = Get-Cluster -Name $Cluster + if ($null -eq $c) + { + return $null + } + + $accessNode = $null + if (-not $Local -and $PSBoundParameters.ContainsKey("Cluster")) + { + $accessNode = Get-AccessNode -Cluster $Cluster + } + + $clusterStorage = $c.SharedVolumesRoot + $collectPath = Join-Path $clusterStorage $collectVolumeName + + foreach ($type in $PathType) + { + $path = switch ($type) + { + ([PathType]::Collect) { $collectPath } + ([PathType]::Control) { Join-Path $collectPath "control" } + + # Note: these paths should move up to collect at v1.0 (don't bury them in control) + + ([PathType]::Result) { Join-Path $collectPath "result" } + ([PathType]::Tools) { Join-Path $collectPath "tools" } + ([PathType]::Flag) { Join-Path $collectPath "flag" } + + ([PathType]::Done) { Join-Path $collectPath "flag\done" } + ([PathType]::Go) { Join-Path $collectPath "flag\go" } + ([PathType]::Pause) { Join-Path $collectPath "flag\pause" } + } + + if ($null -ne $accessNode) + { + $path = Get-AdminSharePathFromLocal -Node $accessNode $path + } + + $path + } + } + + function GetLogmanLocal + { + [CmdletBinding()] + param( + [Parameter(Mandatory = $true)] + [string] + $Name + ) + + $raw = logman query $Name + if ($?) + { + $inctrs = $false + $ctrs = @() + $props = @{} + + $raw |% { + if ($inctrs) + { + # Trim leading spaces. Empty terminates the block. + $ctr = $_ -replace '^\s+','' + if ($ctr.Length -eq 0) + { + $inctrs = $false + } + else + { + $ctrs += $ctr + } + } + elseif ($_ -match '\S+\:\s+\S+') + { + $kv = $_ -split ':\s+',2 + # Basic k: v property + $props[$kv[0] -replace '\s',''] = $kv[1] + } + elseif ($_ -eq 'Counters:') + { + # Begin consuming counter names + $inctrs = $true + } + } + + $props['Counters'] = $ctrs + [pscustomobject] $props + } + } + + # Initializes Archci configs and retrieves extended location required for resource creation using Azure CLI + function InitializeAndGetArcHCIExtendedLoc($azUser, $azPassword, $resourceGroup) { + az config set extension.use_dynamic_install=yes_without_prompt core.encrypt_token_cache=false core.disable_confirm_prompt=true core.only_show_errors=true; + $subscription = ((Get-AzureStackHCI | select AzureResourceUri).AzureResourceUri).Split("/")[2] + $location = (Get-AzureStackHCI | select Region).Region + $isLoggedIn = az login -u $azUser -p $azPassword + if($isLoggedIn -eq $null){ + throw "Azure login failed with error - $isLoggedIn" + } + az account set -s $subscription + try{ + $groupResult = az group show --name $resourceGroup | ConvertFrom-Json + if ($groupResult.properties.provisioningState -eq "Succeeded") { + LogOutput "Resource group $resourceGroup already exists" + } + else { + LogOutput "Creating new Resource group $resourceGroup ..." + az group create --name $resourceGroup --location $location + } + $rbResourceGroup = ((Get-AzureStackHCI | select AzureResourceUri).AzureResourceUri).Split("/")[4] + $customLocationResult = az customlocation list --resource-group $rbResourceGroup | ConvertFrom-Json + $extendedLocation = $customLocationResult[0].id # by default uses the first available custom location + } + catch{ + throw $_.Exception.Message + } + return $extendedLocation + } + + function ApplySpecialization( $path, $vmspec, $admin, $adminPass, $connectUser, $connectPass ) { + # all steps here can fail immediately without cleanup + + # error accumulator + $ok = $true + + # create run directory + + Remove-Item -Recurse -Force z:\run -ErrorAction SilentlyContinue + mkdir z:\run + $ok = $ok -band $? + if (-not $ok) { + Write-Error "failed run directory creation for $vhdpath" + return $ok + } + + # autologon + $null = reg load 'HKLM\tmp' z:\windows\system32\config\software + $ok = $ok -band $? + $null = reg add 'HKLM\tmp\Microsoft\Windows NT\CurrentVersion\WinLogon' /f /v DefaultUserName /t REG_SZ /d $admin + $ok = $ok -band $? + $null = reg add 'HKLM\tmp\Microsoft\Windows NT\CurrentVersion\WinLogon' /f /v DefaultPassword /t REG_SZ /d $adminPass + $ok = $ok -band $? + $null = reg add 'HKLM\tmp\Microsoft\Windows NT\CurrentVersion\WinLogon' /f /v AutoAdminLogon /t REG_DWORD /d 1 + $ok = $ok -band $? + $null = reg add 'HKLM\tmp\Microsoft\Windows NT\CurrentVersion\WinLogon' /f /v Shell /t REG_SZ /d 'powershell.exe -noexit -command C:\users\administrator\launch.ps1' + $ok = $ok -band $? + + $null = reg unload 'HKLM\tmp' + $ok = $ok -band $? + if (-not $ok) { + Write-Error "failed autologon injection for $vhdpath" + return $ok + } + + # scripts + + Copy-Item -Force C:\ClusterStorage\collect\control\control.ps1 z:\run\control.ps1 + $ok = $ok -band $? + if (-not $ok) { + Write-Error "failed injection of specd master.ps1 for $vhdpath" + return $ok + } + + # + # Wrapper for the controller script to auto-restart on failure/update. + # This is the autologin script itself. + # + function Set-FleetLauncherScript { + $script = 'C:\run\control.ps1' + + while ($true) { + Write-Host -fore Green Launching $script `@ $(Get-Date) + try { & $script -connectuser __CONNECTUSER__ -connectpass '__CONNECTPASS__' } catch {} + Start-Sleep -Seconds 1 + } + } + + Remove-Item -Force z:\users\administrator\launch.ps1 -ErrorAction SilentlyContinue + (Get-Command Set-FleetLauncherScript).ScriptBlock | % { + $_ -replace '__CONNECTUSER__',$connectUser -replace '__CONNECTPASS__',$connectPass + } > z:\users\administrator\launch.ps1 + $ok = $ok -band $? + if (-not $ok) { + Write-Error "failed injection of launch.ps1 for $vhdpath" + return $ok + } + + Write-Output $vmspec > z:\vmspec.txt + $ok = $ok -band $? + if (-not $ok) { + Write-Error "failed injection of vmspec for $vhdpath" + return $ok + } + + # load files + $f = 'z:\run\testfile1.dat' + if (-not (Get-Item $f -ErrorAction SilentlyContinue)) { + fsutil file createnew $f (10GB) + $ok = $ok -band $? + fsutil file setvaliddata $f (10GB) + $ok = $ok -band $? + } + if (-not $ok) { + Write-Error "failed creation of initial load file for $vhdpath" + return $ok + } + + return $ok + } + + function SpecializeVhd { + [CmdletBinding()] + param( + [Parameter(Mandatory = $true)][string]$vhdpath, + [Parameter(Mandatory = $true)][string]$admin, + [Parameter(Mandatory = $true)][string]$adminPass, + [Parameter(Mandatory = $true)][string]$connectUser, + [Parameter(Mandatory = $true)][string]$connectPass, + [Parameter(Mandatory = $false)][string]$name + ) + $ok = $true + $vhd = (Get-Item $vhdpath) + if ($name) { + $vmspec = $name + } + else { + $vmspec = $vhd.BaseName + } + + + # mount vhd and its largest partition + $o = Mount-VHD $vhd -NoDriveLetter -Passthru + if ($null -eq $o) { + Write-Error "failed mount for $vhdpath" + return $false + } + $p = Get-Disk -number $o.DiskNumber | Get-Partition | Sort-Object -Property size -Descending | Select-Object -first 1 + $p | Add-PartitionAccessPath -AccessPath Z: + $ok = ApplySpecialization Z: $vmspec $admin $adminPass $connectUser $connectPass + + Remove-PartitionAccessPath -AccessPath Z: -InputObject $p + Dismount-VHD -DiskNumber $o.DiskNumber + + return $ok + } +} + +# Evaluate common block into local session +. $CommonFunc + +# Utility functions only for the local session + +function TimespanToString +{ + param( + [timespan] $TimeSpan + ) + + # Autoranging output + if ($TimeSpan.TotalDays -ge 1) + { + $TimeSpan.ToString("dd\d\.hh\h\:mm\m\:ss\.f\s") + } + elseif ($TimeSpan.TotalHours -ge 1) + { + $TimeSpan.ToString("hh\h\:mm\m\:ss\.f\s") + } + elseif ($TimeSpan.TotalMinutes -ge 1) + { + $TimeSpan.ToString("mm\m\:ss\.f\s") + } + else + { + $TimeSpan.ToString("ss\.f\s") + } +} + +# Produce a good-enough parse of logman collector status +function GetLogman +{ + [CmdletBinding()] + param( + [Parameter( + Mandatory = $true + )] + [string[]] + $Computer, + + [Parameter()] + [string] + $Name = "" + ) + + $n = "perfctr" + if ($Name.Length) { $n += "-$Name" } + + Invoke-CommonCommand -ComputerName $Computer -InitBlock $CommonFunc -ScriptBlock { + + GetLogmanLocal -Name $using:n + } +} + +# Start/restart perf collection on given computer(s)/counter set with named blg +function StartLogman +{ + [CmdletBinding()] + param( + [Parameter( + Mandatory = $true + )] + [string[]] + $Computer, + + [Parameter()] + [string] + $Name = "", + + [Parameter( + Mandatory = $true + )] + [string[]] + $Counters, + + [Parameter()] + [ValidateRange(1,60)] + [int] + $SampleInterval = 1 + ) + + $n = "perfctr" + if ($Name.Length) { $n += "-$Name" } + + Invoke-CommonCommand -ComputerName $Computer -InitBlock $CommonFunc -ScriptBlock { + + # clean up any pre-existing collector & corresponding blg due to failed teardown/et.al. + $existing = GetLogmanLocal -Name $using:n + if ($null -ne $existing) + { + Write-Verbose "logman stop/delete pre-existing $($using:n)" + if ($existing.Status -eq 'Running') + { + $null = logman stop $using:n + } + $null = logman delete $using:n + if (Test-Path $existing.OutputLocation) + { + Remove-Item $existing.OutputLocation -Force + } + } + + $f = Join-Path $env:TEMP "$($using:n)-$($env:COMPUTERNAME).blg" + + # clean up any stale pre-existing blg + if (Test-Path $f) { Remove-Item $f -Force } + + $o = logman create counter $using:n -o $f -f bin -si $using:SampleInterval --v -c $using:Counters 2>&1 + $s = $? + $m = "logman create @ $env:COMPUTERNAME : $o" + if (-not $s) { Write-Error $m } else { Write-Verbose $m } + + $o = logman start $using:n + $s = $? + $m = "logman start @ $env:COMPUTERNAME : $o" + if (-not $s) { Write-Error $m } else { Write-Verbose $m } + } +} + +# Stop perf collection on given computer(s)/counter set with named blg +# Note that copyout is remoted; assumes $Computer is a cluster node and $Path is CSV +function StopLogman +{ + [CmdletBinding()] + param( + [Parameter( + Mandatory = $true + )] + [string[]] + $Computer, + + [Parameter()] + [string] + $Name = "", + + [Parameter()] + [string] $Path + ) + + $n = "perfctr" + if ($Name.Length) { $n += "-$Name" } + + Invoke-CommonCommand -ComputerName $Computer -InitBlock $CommonFunc -ScriptBlock { + $f = Join-Path $env:TEMP "$($using:n)-$($env:COMPUTERNAME).blg" + + $o = logman stop $using:n 2>&1 + $s = $? + $m = "logman stop @ $env:COMPUTERNAME : $o" + if (-not $s) { Write-Error $m } else { Write-Verbose $m } + + $o = logman delete $using:n 2>&1 + $s = $? + $m = "logman delete @ $env:COMPUTERNAME : $o" + if (-not $s) { Write-Error $m } else { Write-Verbose $m } + + if ($using:Path.Length) + { + $o = xcopy /j /y /q $f $using:Path 2>&1 + $s = $? + $m = "xcopy @ $env:COMPUTERNAME : $o" + if (-not $s) { Write-Error $m } else { Write-Verbose $m } + } + + Remove-Item -Force $f + } +} + +# +# Invoke commands with a common initialization block of utility fns. +# When -AsJob, the sessions are persisted onto the parent job object +# for later cleanup on completion. +# +function Invoke-CommonCommand +{ + [CmdletBinding(DefaultParameterSetName = "Default")] + param( + + [Parameter(ParameterSetName = "Default")] + [Parameter(ParameterSetName = "AsJob")] + [Parameter(Position = 0)] + [string[]] + $ComputerName = @(), + + [Parameter(ParameterSetName = "Default")] + [Parameter(ParameterSetName = "AsJob")] + [scriptblock] + $InitBlock, + + [Parameter( + ParameterSetName = "Default", + Mandatory = $true + )] + [Parameter( + ParameterSetName = "AsJob", + Mandatory = $true + )] + [scriptblock] + $ScriptBlock, + + [Parameter(ParameterSetName = "Default")] + [Parameter(ParameterSetName = "AsJob")] + [Object[]] + $ArgumentList, + + [Parameter( + ParameterSetName = "AsJob", + Mandatory = $true + )] + [switch] + $AsJob, + + [Parameter(ParameterSetName = "AsJob")] + [string] + $JobName + ) + + $Sessions = @() + if ($ComputerName.Count -eq 0) + { + $Sessions = New-PSSession -Cn localhost -EnableNetworkAccess + } + else + { + $Sessions = New-PSSession -ComputerName $ComputerName + } + + # Guarantee session cleanup if exception thrown w/o either attaching to job + # for later removal or synch completion of work. + try + { + # Replay the verbose preference onto the seesions so logging is passed + Invoke-Command -Session $Sessions { $VerbosePreference = $using:VerbosePreference } + + if ($null -ne $InitBlock) + { + Invoke-Command -Session $Sessions $InitBlock + } + + switch($PSCmdlet.ParameterSetName) + { + "AsJob" + { + Invoke-Command -Session $Sessions -AsJob -JobName $JobName -ScriptBlock $ScriptBlock -ArgumentList $ArgumentList | + Add-Member -NotePropertyName ActiveSession -NotePropertyValue $Sessions.Id -PassThru + + # Attached, no cleanup here. + $Sessions = @() + } + + default + { + Invoke-Command -Session $Sessions -ScriptBlock $ScriptBlock -ArgumentList $ArgumentList + $Sessions | Remove-PSSession + } + } + } + finally + { + $Sessions | Remove-PSSession + } +} + +function RemoveCommonJobSession +{ + param ( + [Parameter(ValueFromPipeline = $true)] + [object] + $j + ) + + # Remove sessions from completed CommonCommand jobs + + process { + if (Get-Member -InputObject $j ActiveSession) + { + Remove-PSSession -Id $j.ActiveSession + } + } +} + +####################### + +function Get-FleetVersion +{ + [CmdletBinding()] + param ( + [Parameter()] + [string] + $Cluster = "." + ) + + $path = Get-FleetPath -PathType Tools @PSBoundParameters + + $vmfleet = Get-Command Get-FleetVersion + [PSCustomObject]@{ + Component = $vmfleet.Source + Version = $vmfleet.Version + } + + $diskspdPath = (Join-Path $path 'diskspd.exe') + if (Test-Path $diskspdPath) + { + $diskspd = Get-Command $diskspdPath + [PSCustomObject]@{ + Component = $diskspd.Name + Version = $diskspd.Version + } + } +} + +function Get-FleetPauseEpoch +{ + [CmdletBinding(DefaultParameterSetName = "ByCluster")] + param ( + [Parameter(ParameterSetName = "ByCluster")] + [string] + $Cluster = ".", + + [Parameter(ParameterSetName = "ByPath")] + [string] + $Path + ) + + switch($PSCmdlet.ParameterSetName) + { + "ByCluster" { $Path = Get-FleetPath -PathType Pause @PSBoundParameters } + } + + $ep = Get-Content $Path -ErrorAction SilentlyContinue + if ($null -eq $ep) + { + $ep = 0 + } + + $ep +} + +# +# Get-FleetPause +# +function Get-FleetPause +{ + [CmdletBinding(DefaultParameterSetName = "ByCluster")] + param ( + [Parameter(ParameterSetName = "ByCluster")] + [string] + $Cluster = ".", + + [Parameter(ParameterSetName = "ByPath")] + [string] + $Path + ) + + $pauseEpoch = Get-FleetPauseEpoch @PSBoundParameters -ErrorAction SilentlyContinue + + # non-0 indicates VMs are paused + $pauseEpoch -ne 0 +} + +# +# Show-Pause - text report of pause state +# +function Show-FleetPause +{ + [CmdletBinding(DefaultParameterSetName = "ByCluster")] + param ( + [Parameter(ParameterSetName = "ByCluster")] + [string] + $Cluster = ".", + + [Parameter(ParameterSetName = "ByPath")] + [string] + $Path + ) + + $pausePath = Get-FleetPath -PathType Pause @PSBoundParameters + $pauseEpoch = Get-FleetPauseEpoch -Path $pausePath -ErrorAction SilentlyContinue + if ($pauseEpoch -eq 0) + { + Write-Host -ForegroundColor red "Pause not in force" + return + } + + # Now correlate to online vms and see if we agree all online are paused. + + $vms = @(Get-ClusterGroup |? GroupType -eq VirtualMachine |? Name -like 'vm-*' |? State -eq Online) + $pausedVMs = @($vms | FilterPausedVMs -Path $pausePath) + + if ($pausedVMs.Count -eq $vms.Count) + { + Write-Host -ForegroundColor green "OK: All $($vms.count) VMs paused" + } + else + { + Write-Host -fore red "WARNING: of $($vms.Count), still waiting on $($vms.Count - $pausedVMs.Count) to acknowledge pause" + + Compare-Object $vms $pausedVMs -Property Name -PassThru | Sort-Object -Property Name | Format-Table -AutoSize Name,OwnerNode | Out-Host + } +} + +function FilterPausedVMs +{ + [CmdletBinding()] + param( + [Parameter(ParameterSetName = "ByPath")] + [string] + $Path, + + [Parameter(ValueFromPipeline = $true)] + [Microsoft.FailoverClusters.PowerShell.ClusterGroup[]] + $VM + ) + + begin + { + $pauseEpoch = Get-FleetPauseEpoch -Path $Path -ErrorAction SilentlyContinue + + # accumulate hash of pause flags mapped to current/stale state + $h = @{} + + Get-ChildItem "$($Path)-*" |% { + + $thisPause = Get-Content $_ -ErrorAction SilentlyContinue + if ($thisPause -eq $pauseEpoch) + { + $pauseType = [PauseState]::Current + } + else + { + $pauseType = [PauseState]::Stale + } + + if ($_.name -match 'pause-(vm.+)') + { + # VM Name + $h[$matches[1]] = $pauseType + } + else + { + Write-Warning "malformed pause $($_.Name) present" + } + } + } + + process + { + # Pass through all VMs which have responsed to the current pause. + if ($h[$VM.Name] -eq [PauseState]::Current) + { + $VM + } + } +} + +function Set-FleetPause +{ + [CmdletBinding(DefaultParameterSetName = "ByCluster")] + param ( + [Parameter(ParameterSetName = "ByCluster")] + [string] + $Cluster = ".", + + [Parameter(ParameterSetName = "ByPath")] + [string] + $Path, + + [Parameter()] + [ValidateRange(0,120)] + [int] + $Timeout = 120, + + [Parameter()] + [switch] + $Force + ) + + # Parameter set specifying cluster only + $clusterParam = @{} + CopyKeyIf $PSBoundParameters $clusterParam 'Cluster' + + $pausePath = Get-FleetPath @clusterParam -PathType Pause + + if ((-not $Force) -and (Get-FleetPause -Path $pausePath)) + { + LogOutput -IsVb "pause is already set @ $((Get-Item $pausePath).LastWriteTime)" + return + } + + # if forcing (live check), there may be a nonzero existing pause. + # ensure the new nonzero pause flag is distinct. + $currentPause = Get-FleetPauseEpoch -Path $pausePath + do { + $newPause = Get-Random -Minimum 1 + if ($newPause -eq $currentPause) { continue } + Write-Output $newPause > $pausePath + break + } until ($false) + + LogOutput -IsVb "pause set @ $((Get-Item $pausePath).LastWriteTime)" + + # Wait for pause to settle? + if ($Timeout -gt 0) + { + $t0 = Get-Date + $vms = @(Get-ClusterGroup @clusterParam |? GroupType -eq VirtualMachine |? Name -like 'vm-*' |? State -eq Online) + + do { + + $td = (Get-Date) - $t0 + + $pausedVMs = @($vms | FilterPausedVMs -Path $pausePath) + if ($pausedVMs.Count -eq $vms.Count) + { + break + } + + if ($td.TotalSeconds -gt $Timeout) + { + Write-Error "Wait for pause ack timed out - only $($pausedVMs.Count)/$($vms.Count) pause responses. Check fleet health with Get-FleetVM -ControlResponse and Repair-Fleet if needed." + return + } + + LogOutput -IsVb "WAIT pause ack @ $($pausedVMs.Count)/$($vms.Count) paused" + Start-Sleep 2 + + } while ($true) + + LogOutput -IsVb "pause ack $($vms.Count) total ($('{0:0.0}' -f $td.TotalSeconds)s to ack)" + } +} + +function Clear-FleetPause +{ + [CmdletBinding(DefaultParameterSetName = "ByCluster")] + param ( + [Parameter(ParameterSetName = "ByCluster")] + [string] + $Cluster = ".", + + [Parameter(ParameterSetName = "ByPath")] + [string] + $Path + ) + + $pausePath = Get-FleetPath -PathType Pause @PSBoundParameters + + if (-not (Get-FleetPause -Path $pausePath)) + { + LogOutput -IsVb "pause is already cleared @ $((Get-Item $pausePath).LastWriteTime)" + return + } + + Write-Output 0 > $pausePath + LogOutput -IsVb "pause cleared @ $((Get-Item $pausePath).LastWriteTime)" +} + +function Install-Fleet +{ + [CmdletBinding()] + param ( + [Parameter()] + [string] + $Cluster = ".", + + [Parameter()] + [switch] + $KeepBlockCache, + + [Parameter()] + [switch] + $NoTools, + + [Parameter()] + [switch] + $Force + ) + + # Parameter set specifying cluster only + $clusterParam = @{} + CopyKeyIf $PSBoundParameters $clusterParam 'Cluster' + + # + # Ensure there is a collect volume and at least 1 CSV with prefix per + # node of the cluster. + # + + $csvs = @(GetMappedCSV @clusterParam) + $nodes = @(Get-ClusterNode @clusterParam) + + # Now accumulate the other potential configuration errors so we can emit all of them before stopping + $e = $false + + # Ensure there is a collect volume. + if ($csvs.Count -eq 0 -or $csvs.VDName -notcontains $collectVolumeName) + { + $errorObject = CreateErrorRecord -ErrorId "No $($collectVolumeName) CSV found" ` + -ErrorMessage "VM Fleet requires one volume named '$($collectVolumeName)' which will hold VM Fleet data/scripts" ` + -ErrorCategory ([System.Management.Automation.ErrorCategory]::ObjectNotFound) ` + -Exception $null ` + -TargetObject $null + + $psCmdlet.WriteError($errorObject) + $e = $true + } + else + { + LogOutput -IsVb "collect volume exists" + } + + # Ensure there is at least one volume per node. Note this is warning since the volume size estimator is neccesarily part + $h = @{ } + foreach ($node in $nodes) + { + $h[$node] = 0 + } + + foreach ($csv in $csvs) + { + foreach ($node in $nodes) + { + if ($csv.VDName -match "^$node(?:-.+){0,1}$") + { + LogOutput -IsVb "volume $($csv.VDName) matched to node $node" + $h[$node] += 1 + break + } + } + } + + foreach ($node in $nodes) + { + if ($h[$node] -eq 0) + { + $errorObject = CreateErrorRecord -ErrorId "No CSV found for node" ` + -ErrorMessage "Node $($node): VM Fleet requires at least one volume prefixed with node name which will be used to hold VM data/metadata. Use Get-FleetVolumeEstimate for recommended sizings." ` + -ErrorCategory ([System.Management.Automation.ErrorCategory]::ObjectNotFound) ` + -Exception $null ` + -TargetObject $null + + $psCmdlet.WriteError($errorObject) + $e = $true + } + } + + # Now halt if volume configuration was incomplete/missing. + if ($e) + { + return + } + + # Install directory structure + + $paths = ($controlPath, $flagPath, $resultPath, $toolsPath) = Get-FleetPath -PathType Control,Flag,Result,Tools @clusterParam + foreach ($path in $paths) + { + if (-not (Test-Path $path)) + { + LogOutput -IsVb "installing path: $path" + $null = New-Item -Path $path -ItemType Directory + } + else + { + LogOutput -IsVb "path exists: $path" + } + } + + # Set fleet pause so that VMs come up idle + Set-FleetPause -Timeout 0 + + # + # Unwrap VM scripts (control, run*) + # + + $f = Join-Path $controlPath "control.ps1" + if (-not (Test-Path $f) -or $Force) + { + $c = Get-Command Set-FleetControlScript + if (Test-Path $f) { Remove-Item $f -Force } + $c.ScriptBlock | Out-File -FilePath "$($f).tmp" -Width ([int32]::MaxValue) -Force + Move-Item "$($f).tmp" $f + } + + $f = Join-Path $controlPath "run.ps1" + if (-not (Test-Path $f) -or $Force) + { + $c = Get-Command Set-FleetBaseScript + if (Test-Path $f) { Remove-Item $f -Force } + $c.ScriptBlock | Out-File -FilePath "$($f).tmp" -Width ([int32]::MaxValue) -Force + Move-Item "$($f).tmp" $f + } + + if (-not $KeepBlockCache) + { + LogOutput -IsVb "disabling CSV block cache (recommended)" + (Get-Cluster @clusterParam).BlockCacheSize = 0 + } + + if (-not $NoTools) + { + # DISKSPD + + $diskspdPath = (Join-Path $toolsPath "diskspd.exe") + $exist = Test-Path $diskspdPath + if (-not $exist -or $Force) + { + if ($exist) + { + LogOutput -IsVb "removing prior install of DISKSPD" + Remove-Item -Force $diskspdPath + } + + try + { + # Temporary ZIP file. Expand-Archive insists on the extension. + $z = New-TemporaryFile + $z = Rename-Item $z $($z.BaseName + ".zip") -PassThru + + # Temporary directory for extraction. + $d = New-TemporaryFile + Remove-Item $d + $d = New-Item -ItemType Directory $d + + LogOutput -IsVb "downloading DISKSPD" + + try { + + $diskspdURI = "https://aka.ms/getdiskspd" + + # Force TLS1.2. Downlevel TLS defaults may be rejected. Restore after download. + $oldTls = [Net.ServicePointManager]::SecurityProtocol + [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 + Invoke-WebRequest -Uri $diskspdURI -OutFile $z + [Net.ServicePointManager]::SecurityProtocol = $oldTls + + Expand-Archive $z -DestinationPath $d + + # Now pull the architecture appropriate diskspd and remove the zip content + Copy-Item (Join-Path $d (Join-Path $env:PROCESSOR_ARCHITECTURE "diskspd.exe")) $toolsPath + } + catch + { + Write-Warning "Cannot download DISKSPD from public site @ $diskspdURI : please acquire and place @ $toolsPath before running loads requiring it " + } + + } + finally + { + if (Test-Path $z) { Remove-Item $z -Force } + if (Test-Path $d ) { Remove-Item $d -Recurse -Force} + } + } + else + { + LogOutput -IsVb "DISKSPD already present" + } + } + + # + # Speedbrake: Fleet requires DISKSPD >= 2.1.0.0 for new features + # + + $v = Get-FleetVersion + $diskspd = $v |? Component -eq diskspd.exe + $vmfleet = $v |? Component -eq VMFleet + + if ($null -eq $diskspd) + { + Write-Error ("DISKSPD is not present. VM Fleet {0} requires DISKSPD for its core measurement functionality. Please update and, if running, restart the fleet to pick up the tool." -f ( + $vmfleet.Version)) + } + elseif ($diskspd.Version.CompareTo([Version]'2.1.0.0') -lt 0) + { + Write-Error ("The installed DISKSPD is version {0}. VM Fleet {1} requires the functionality of DISKSPD 2.1.0.0. Please update and, if running, restart the fleet to pick up the new version." -f ( + $diskspd.Version, + $vmfleet.Version)) + } +} + +function New-Fleet +{ + [CmdletBinding(DefaultParameterSetName = "ByCluster")] + param( + [Parameter(ParameterSetName = "ByCluster")] + [string] + $Cluster = ".", + + [Parameter(ParameterSetName = "ByNode", Mandatory = $true)] + <# + [ArgumentCompleter({ + param ( $commandName, + $parameterName, + $wordToComplete, + $commandAst, + $fakeBoundParameters ) + # Perform calculation of tab completed values here. + })] + #> + [string[]] + $Node, + + [Parameter(ParameterSetName = "ByCluster")] + [Parameter(ParameterSetName = "ByNode")] + [Parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [string] + $BaseVHD, + + [Parameter(ParameterSetName = "ByCluster")] + [Parameter(ParameterSetName = "ByNode")] + [ValidateRange(1, 4096)] + [int] + $VMs, + + [Parameter(ParameterSetName = "ByCluster")] + [Parameter(ParameterSetName = "ByNode")] + [string[]] + $Groups = @(), + + [Parameter(ParameterSetName = "ByCluster")] + [Parameter(ParameterSetName = "ByNode")] + [Parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [string] + $AdminPass, + + [Parameter(ParameterSetName = "ByCluster")] + [Parameter(ParameterSetName = "ByNode")] + [ValidateNotNullOrEmpty()] + [string] + $Admin = 'administrator', + + [Parameter(ParameterSetName = "ByCluster")] + [Parameter(ParameterSetName = "ByNode")] + [Parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [string] + $ConnectPass, + + [Parameter(ParameterSetName = "ByCluster")] + [Parameter(ParameterSetName = "ByNode")] + [Parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [string] + $ConnectUser, + + [Parameter(ParameterSetName = "ByCluster")] + [Parameter(ParameterSetName = "ByNode")] + [ValidateSet('CreateVMSwitch','CopyVHD','CreateVM','CreateVMGroup','AssertComplete')] + [string] + $StopAfter, + + [Parameter(ParameterSetName = "ByCluster")] + [Parameter(ParameterSetName = "ByNode")] + [ValidateSet('Force','Auto','None')] + [string] + $Specialize = 'Auto', + + [Parameter(ParameterSetName = "ByCluster")] + [Parameter(ParameterSetName = "ByNode")] + [switch] + $KeepVHD + ) + + # Parameter set specifying cluster only + $clusterParam = @{} + CopyKeyIf $PSBoundParameters $clusterParam 'Cluster' + + ################## + + # check if Arc enabled VMs should be created + $createArcVMs = $false + $arcConfig = Get-ArcConfig -Cluster $Cluster + $resourceGroup, $azUser, $azPassword, $storagePath, $image, $salt = $null + if($arcConfig -and $arcConfig.Enabled){ + $createArcVMs = $true + $resourceGroup, + $azUser, + $azPassword, + $storagePath, + $image, + $salt = + $arcConfig.ResourceGroup, + $arcConfig.AzureRegistrationUser, + $arcConfig.AzureRegistrationPassword, + $arcConfig.StoragePathName, + $arcConfig.ImageName, + $arcConfig.Salt + LogOutput "Create Arc-enabled Virtual Machines? $createArcVMs" + } + + # validate existence of BaseVHD + if (-not (Test-Path -Path $BaseVHD)) { + $errorObject = CreateErrorRecord -ErrorId "No BaseVHD" ` + -ErrorMessage "The base VHD path $BaseVHD was not found" ` + -ErrorCategory ([System.Management.Automation.ErrorCategory]::ObjectNotFound) ` + -Exception $null ` + -TargetObject $null + + $psCmdlet.WriteError($errorObject) + return + } + + # resolve BaseVHD to fully qualified path + $BaseVHD = (Get-Item $BaseVHD).FullName + + if (@(Get-ClusterNode @clusterParam |? State -ne Up).Count -ne 0) { + $errorObject = CreateErrorRecord -ErrorId "Cluster nodes not up" ` + -ErrorMessage "Some nodes of cluster $Cluster are not up - please address before creating the fleet" ` + -ErrorCategory ([System.Management.Automation.ErrorCategory]::ResourceUnavailable) ` + -Exception $null ` + -TargetObject $null + + $psCmdlet.WriteError($errorObject) + return + } + + switch ($psCmdlet.ParameterSetName) + { + "ByCluster" { $Nodes = @(Get-ClusterNode @clusterParam) } + } + + # convert to fixed vhd(x) if needed + if ((Get-Vhd $BaseVHD).VhdType -ne 'Fixed' -and -not $KeepVHD) { + + # push dynamic vhd to tmppath and place converted at original + # note that converting a dynamic will leave a sparse hole on refs + # this is OK, since the copy will not copy the hole + $f = Get-Item $BaseVHD + $tmpname = "tmp-$($f.Name)" + $tmppath = Join-Path $f.DirectoryName $tmpname + Remove-Item -Force $tmppath -ErrorAction SilentlyContinue + Rename-Item $f.FullName $tmpname + + LogOutput -IsVb "convert $($f.FullName) to fixed via $tmppath" + Convert-VHD -Path $tmppath -DestinationPath $f.FullName -VHDType Fixed + if (-not $?) { + Rename-Item $tmppath $f.Name + + # allow likely error from Convert-VHD to flow out + return + } + + Remove-Item $tmppath + } + + # + # Autoscaled VMs (1 per physical core) if not specified + # + + if (-not $PSBoundParameters.ContainsKey('VMs')) + { + $g = @(Get-CimInstance -CimSession $nodes.Name Win32_Processor | Group-Object -Property NumberOfEnabledCore) + + if ($g.Count -eq 0) + { + $errorObject = CreateErrorRecord -ErrorId "Cannot query enabled processor cores" ` + -ErrorMessage "Cannot query enabled processor core from cluster nodes" ` + -ErrorCategory ([System.Management.Automation.ErrorCategory]::ResourceUnavailable) ` + -Exception $null ` + -TargetObject $null + + $psCmdlet.WriteError($errorObject) + return + } + + if ($g.Count -ne 1 -or $g[0].Group.Count % $nodes.Count) + { + $errorObject = CreateErrorRecord -ErrorId "Non-uniform processors" ` + -ErrorMessage "Cluster $Cluster nodes have processors with differing numbers of enabled processor cores - please verify configuration" ` + -ErrorCategory ([System.Management.Automation.ErrorCategory]::ResourceUnavailable) ` + -Exception $null ` + -TargetObject $null + + $psCmdlet.WriteError($errorObject) + return + } + + $VMs = ($g[0].Group.NumberOfEnabledCore | Measure-Object -Sum).Sum / $nodes.Count + + LogOutput -IsVb "Autoscaling number of VMs to $VMs / node" + } + + # Create the fleet vmswitches with a fixed IP at the base of the APIPA range + Invoke-CommonCommand $nodes -InitBlock $CommonFunc -ScriptBlock { + + if (-not (Get-VMSwitch -Name $using:vmSwitchName -ErrorAction SilentlyContinue)) { + + $null = New-VMSwitch -name $using:vmSwitchName -SwitchType Internal + $null = Get-NetAdapter |? DriverDescription -eq 'Hyper-V Virtual Ethernet Adapter' |? Name -eq "vEthernet ($($using:vmSwitchName))" | New-NetIPAddress -PrefixLength 16 -IPAddress $using:vmSwitchIP + LogOutput "CREATE internal vmswitch $($using:vmSwitchName) @ $($env:COMPUTERNAME)" + } + } + + #### STOPAFTER + if (Stop-After "CreateVMSwitch" $stopafter) { + return + } + + # create $vms vms per each csv named as + # vm name is vm-<$group>-- + + # note that this would pass as a shallow copy of the object; this is why they are unpacked + # into a (flat) custom object + $csvs = GetMappedCSV @clusterParam |% { [PSCustomObject]@{ + VDName = $_.VDName + FriendlyVolumeName = $_.SharedVolumeInfo.FriendlyVolumeName + }} + + # Create Gallery Image and Storage Path Arc resources if Arc VM flag set to true + if ($createArcVMs) { + if(-not ($arcConfig | Get-Member -Name 'StoragePathCsv' -MemberType Properties)){ + foreach ($csv in $csvs) { + # identify the Csv which can be used to create storage path + # the trailing characters (if any) are the group prefix + if ($csv.VDName -match "^$env:COMPUTERNAME(?:-.+){0,1}") { + $arcConfig | Add-Member -MemberType NoteProperty -Name "StoragePathCsv" -Value $csv.FriendlyVolumeName + $storagePathCsv = $arcConfig.StoragePathCsv + break + } + } + } + $result = Invoke-CommonCommand $nodes[0] -InitBlock $CommonFunc -ArgumentList @($BaseVHD) -ScriptBlock { + param($vhdPath) + $retryCount = 0 + while ($retryCount -lt 3) { + try { + $extendedLocation = InitializeAndGetArcHCIExtendedLoc $using:azUser $using:azPassword $using:resourceGroup + if (-not $extendedLocation) { + LogOutput -ForegroundColor Red "Error generating Extended Location value" + return "Error occurred while getting extended location" + } + + $location = (Get-AzureStackHCI | select Region).Region + + $spId = $null + $spResult = az stack-hci-vm storagepath list --resource-group $using:resourceGroup --query "[?name=='$($using:storagePath)' && properties.provisioningState=='Succeeded'].id" --output tsv + if ($null -ne $spResult) { + LogOutput "Storage path $using:storagePath already exists" + } + elseif (az stack-hci-vm storagepath list --resource-group $using:resourceGroup --query "[?name=='$($using:storagePath)' && properties.provisioningState=='Failed'].id" --output tsv) { + LogOutput "$using:storagePath exists with provision status Failed. Deleting existing storage path and recreating..." + az stack-hci-vm storagepath delete --name $using:storagePath --resource-group $using:resourceGroup --yes + $spResult = az stack-hci-vm storagepath create --name $using:storagePath --resource-group $using:resourceGroup --custom-location $extendedLocation --path $using:storagePathCsv --location $location | ConvertFrom-Json + } + else { + LogOutput "Creating storage path $storagePath..." + $spResult = az stack-hci-vm storagepath create --name $using:storagePath --resource-group $using:resourceGroup --custom-location $extendedLocation --path $using:storagePathCsv --location $location | ConvertFrom-Json + } + + if (-not $spResult) { + throw "Failed to create storage path $using:storagePath" + } + if($spResult.Id) { + $spId = $spResult.Id + } + else { + $spId = $spResult + } + LogOutput "Initialized storage path: $using:storagePath, creating image with $vhdPath..." + + $imgResult = az stack-hci-vm image list --resource-group $using:resourceGroup --query "[?name=='$($using:image)' && properties.provisioningState=='Succeeded'].id" --output tsv + if ($null -ne $imgResult) { + LogOutput "Image $using:image already exists." + } + elseif (az stack-hci-vm image list --resource-group $using:resourceGroup --query "[?name=='$($using:image)' && properties.provisioningState=='Failed'].id" --output tsv) { + LogOutput "$using:image exists with provision status Failed. Deleting existing image and recreating..." + az stack-hci-vm image delete --name $using:image --resource-group $using:resourceGroup --yes + $imgResult = az stack-hci-vm image create --name $using:image --resource-group $using:resourceGroup --location $location --custom-location $extendedLocation --os-type Windows --storage-path-id $spId --image-path $vhdPath | ConvertFrom-Json + } + else { + LogOutput "Creating image $using:image..." + $imgResult = az stack-hci-vm image create --name $using:image --resource-group $using:resourceGroup --location $location --custom-location $extendedLocation --os-type Windows --storage-path-id $spId --image-path $vhdPath | ConvertFrom-Json + } + + if (-not $imgResult) { + throw "Failed to create image $using:image" + } + + LogOutput "Initialized Gallery image: $using:image" + LogOutput -ForegroundColor Green "Finished initialization of resources using Azure CLI" + break + } + catch { + $retryCount++ + if ($retryCount -eq 3) { + return "Error occurred while creating Azure resources for all retry counts" + } + } + } + } + if($result -ne $null -and $result.Contains("Error")){ + return $result + } + } + + #### STOPAFTER + if (Stop-After "CreateVMSwitch" $stopafter) { + return + } + + Invoke-CommonCommand $nodes -InitBlock $CommonFunc -ArgumentList @(,$csvs) -ScriptBlock { + param($csvs) + + foreach ($csv in $csvs) { + + if ($($using:groups).Length -eq 0) { + $groups = @( 'base' ) + } else { + $groups = $using:groups + } + + # identify the CSvs for which this node should create its VMs + # the trailing characters (if any) are the group prefix + if ($csv.VDName -notmatch "^$env:COMPUTERNAME(?:-.+){0,1}") { + continue + } + + foreach ($group in $groups) { + + if ($csv.VDName -match "^$env:COMPUTERNAME-([^-]+)$") { + $g = $group+$matches[1] + } else { + $g = $group + } + + foreach ($vm in 1..$using:vms) { + + $stop = $false + + $newvm = $false + if($using:createArcVMs) { + $name = ("vm-$g-$env:COMPUTERNAME-$using:salt-{0:000}" -f $vm) + } + else { + $name = ("vm-$g-$env:COMPUTERNAME-{0:000}" -f $vm) + } + + $placePath = $csv.FriendlyVolumeName + $vmPath = Join-Path $placePath $name + $vhdPath = Join-Path $vmPath "$name.vhdx" + + # if the vm cluster group exists, we are already deployed + if (-not (Get-ClusterGroup -Name $name -ErrorAction SilentlyContinue)) { + + if (-not $stop) { + $stop = Stop-After "AssertComplete" + } + + if ($stop) { + + LogOutput -ForegroundColor Red "vm $name not deployed" + + } else { + + LogOutput "CREATE vm $name @ path $vmPath" + + # always specialize new vms + $newvm = $true + + # We're on the canonical node to create the vm; if the vm exists, tear it down and refresh + $o = Get-VM -Name $name -ErrorAction SilentlyContinue + + if ($null -ne $o) { + + # interrupted between vm creation and role creation; redo it + LogOutput "REMOVE vm $name for re-creation" + + if ($o.State -ne 'Off') { + Stop-VM -Name $name -TurnOff -Force -Confirm:$false + } + if($using:createArcVMs){ + az stack-hci-vm delete --name $name --resource-group $using:resourceGroup --yes + } + else { + Remove-VM -Name $name -Force -Confirm:$false + } + } + # we do not need to copy vhd for Arc vms. It is done by the product code itself + if($using:createArcVMs -eq $false){ + # scrub and re-create the vm metadata path and vhd + if (Test-Path $vmPath) + { + Remove-Item -Recurse $vmPath + } + + $null = New-Item -ItemType Directory $vmPath + Copy-Item $using:BaseVHD $vhdPath + + #### STOPAFTER + if (-not $stop) { + $stop = Stop-After "CopyVHD" $using:stopafter + } + + if (-not $stop) { + + # Create A1 VM. use set-vmfleet to alter fleet sizing post-creation. + # Do not monitor the internal switch connection; this allows live migration + # despite the internal switch. + $o = New-VM -VHDPath $vhdPath -Generation 2 -SwitchName $using:vmSwitchName -Path $placePath -Name $name + if ($null -ne $o) + { + $o | Set-VM -ProcessorCount 1 -MemoryStartupBytes 1.75GB -StaticMemory + $o | Get-VMNetworkAdapter | Set-VMNetworkAdapter -NotMonitoredInCluster $true + } + } + } + else { + $retrycount = 0 + while($retrycount -lt 3){ + try{ + $vmResult = $null + $extendedLocation = InitializeAndGetArcHCIExtendedLoc $using:azUser $using:azPassword $using:resourceGroup + $location = (Get-AzureStackHCI | select Region).Region + LogOutput "Creating Arc HCI VM - $name ..." + $vmResult = az stack-hci-vm create --name $name --resource-group $using:resourceGroup --admin-username $using:admin --admin-password $using:adminpass --computer-name $using:admin --location $location --enable-agent False --enable-vm-config-agent false --os-type "Windows" --custom-location $extendedLocation --image $using:image --storage-path-id $using:storagePath --hardware-profile memory-mb="2048" processors="1" vm-size="Custom" + LogOutput "Result returned for $name - $vmResult" + if($vmResult -eq $null){ + $msg = "Error creating Virtual machine $name at retry count $retryCount" + LogOutput -ForegroundColor Yellow $msg + throw $msg + } + break + } + catch { + $retrycount++ + if($retrycount -eq 3){ + LogOutput -ForegroundColor Yellow "Error occurred while creating $name for all retry counts" + $stop = $true + } + } + } + if (-not $stop) { + # validating creation of Arc VMs using powershell commands + # hyperv Arc VM names + $vmname = "Virtual Machine " + $name + $Stoploop = $false + $Retrycount = 0 + do { + try { + LogOutput "Executing Get-ClusterResource -Name $vmname" + $o = Get-ClusterResource -Name $vmname + if ($o -eq $null) { + throw "Null returned by Get-ClusterResource due to some error" + } + else { + LogOutput "Creation of vm completed at hyperv level" + $Stoploop = $true + } + } + catch { + if ($Retrycount -gt 10) { + LogOutput -ForegroundColor Red "Could not get VM $vmname after 10 retries using Get-ClusterResource" + $Stoploop = $true + } + else { + LogOutput -ForegroundColor Yellow "Could not get VM $vmname at $RetryCount retry count. Retrying in 6 minutes..." + Start-Sleep -Seconds 360 + $Retrycount += 1 + } + } + } + While ($Stoploop -eq $false) + } + } + #### STOPAFTER + if (-not $stop) { + $stop = Stop-After "CreateVM" $using:stopafter + } + + if (-not $stop -and $using:createArcVMs -ne $true) { + # Create clustered vm role (don't emit) and assign default owner node. + # Swallow the (expected) warning that will be referring to the internal + # vmswitch as being a local-only resource. Since we replicate the vswitch + # with the same IP on each cluster node, it does work. + # + # If an error occurs, it will emit per normal. + $null = $o | Add-ClusterVirtualMachineRole -WarningAction SilentlyContinue + Set-ClusterOwnerNode -Group $o.VMName -Owners $env:COMPUTERNAME + } + } + + } else { + LogOutput -ForegroundColor Green "vm $name already deployed" + } + + #### STOPAFTER + if (-not $stop) { + $stop = Stop-After "CreateVMGroup" $using:stopafter + } + + if ((-not $stop -or ($using:specialize -eq 'Force')) -and -not $using:createArcVMs) { + # specialize as needed + # auto only specializes new vms; force always; none skips it + if (($using:specialize -eq 'Auto' -and $newvm) -or ($using:specialize -eq 'Force')) { + LogOutput "SPECIALIZE vm $name" + if (-not (SpecializeVhd $vhdPath $using:admin $using:adminpass $using:connectuser $using:connectpass)) { + LogOutput -ForegroundColor red "Failed specialize of vm $name @ $vhdPath, halting." + } + } else { + LogOutput -ForegroundColor green skip specialize $vhdPath + } + } + } + } + } + } + + if($createArcVMs){ + Stop-Fleet + LogOutput "Updating network adapter for Fleet to add internal switch" + $clusterName = (Get-Cluster).Name + $nodes = @(Get-ClusterNode -Cluster $clusterName | ? State -eq Up) + $regPattern = "^vm-.{1,}-" + $salt + "-\d{3}$" + foreach ($o in Get-VM -CimSession $nodes.Name | ? Name -match $regPattern) { + $o | Add-VMNetworkAdapter -SwitchName $vmSwitchName + $o | Get-VMNetworkAdapter | Connect-VMNetworkAdapter -SwitchName $vmSwitchName + $o | Get-VMNetworkAdapter | Set-VMNetworkAdapter -NotMonitoredInCluster $true + Set-ClusterOwnerNode -Group $o.VMName -Owners $env:COMPUTERNAME + LogOutput "Network Adapter attached to VM" + } + Stop-Fleet + Initialize-ArcVMs $admin $adminpass $connectuser $connectpass $salt + } +} + +# Initialize Arc VMs +function Initialize-ArcVMs ($admin ,$adminpass, $connectuser, $connectpass, $salt){ + $clusterName = (Get-Cluster).Name + $nodes = @(Get-ClusterNode -Cluster $clusterName | ? State -eq Up) + $regPattern = "^vm-.{1,}-" + $salt + "-\d{3}$" + foreach ($vm in Get-VM -CimSession $nodes.Name | ? Name -match $regPattern) { + $vmname = "Virtual Machine " + $vm.Name + $name = $vm.Name + $vhdPath = $vm | Select-Object -ExpandProperty HardDrives | Where-Object Path -like "*OSDisk*.vhdx" | Select Path + if($vhdPath -eq $null){ + LogOutput -ForegroundColor red "Could not find vhd path for $vmname." + } + $path = $vhdPath.Path + if (-not (SpecializeVhd $path $admin $adminpass $connectuser $connectpass $name)) { + LogOutput -ForegroundColor red "Failed specialize of vm $name @ $path, halting." + } + else { LogOutput -ForegroundColor green "Successfully Specialized $vmname" } + } +} + +function Remove-Fleet +{ + [CmdletBinding()] + param( + [Parameter()] + [string] + $Cluster = ".", + + [Parameter()] + [string[]] + $VMs + ) + + # Parameter set specifying cluster only + $clusterParam = @{} + CopyKeyIf $PSBoundParameters $clusterParam 'Cluster' + + # check if Arc enabled VMs should be created + $arcConfig = Get-ArcConfig -Cluster $Cluster + $arcEnvEnabled = $arcConfig -and $arcConfig.Enabled + $resourceGroup, $azUser, $azPassword, $storagePath, $img, $salt = $null + if($arcEnvEnabled){ + $resourceGroup, + $azUser, + $azPassword, + $storagePath, + $img, + $salt = + $arcConfig.ResourceGroup, + $arcConfig.AzureRegistrationUser, + $arcConfig.AzureRegistrationPassword, + $arcConfig.StoragePathName, + $arcConfig.ImageName, + $arcConfig.Salt + LogOutput "Is environment HCI Arc-enabled? $arcEnvEnabled" + } + + if ($vms) + { + LogOutput -IsVb "Removing VM Fleet content for: $vms" + } + else + { + LogOutput -IsVb "Removing VM Fleet" + } + + # stop and remove clustered vm roles + Get-ClusterGroup @clusterParam |? GroupType -eq VirtualMachine |? { + + if ($vms) + { + $_.Name -in $vms + } + elseif($arcEnvEnabled) + { + $_.Name -match "^vm-.{1,}-" + $salt + "-\d{3}$" + } + else + { + $_.Name -like 'vm-*' + } + } |% { + + LogOutput -IsVb "Removing ClusterGroup for $($_.Name)" + $null = $_ | Stop-ClusterGroup + $_ | Remove-ClusterGroup -RemoveResources -Force + } + + # Capture flag file path for the installation + $flagPath = Get-FleetPath -PathType Flag @clusterParam + + # remove all vms + Invoke-CommonCommand (Get-ClusterNode @clusterParam) -InitBlock $CommonFunc -ScriptBlock { + + Get-VM |? { + if ($using:vms) + { + $_.Name -in $using:vms + } + elseif($using:arcEnvEnabled) + { + $_.Name -match "^vm-.{1,}-" + $using:salt + "-\d{3}$" + } + else + { + $_.Name -like 'vm-*' + } + } |% { + + LogOutput -IsVb "Removing VM for $($_.Name) @ $($env:COMPUTERNAME)" + if($using:arcEnvEnabled) { + InitializeAndGetArcHCIExtendedLoc $using:azUser $using:azPassword $using:resourceGroup + $vmName = $_.Name + az stack-hci-vm delete --name $vmName --resource-group $using:resourceGroup --yes + LogOutput "Removed $vmName" + } + else { + $_ | Remove-VM -Confirm:$false -Force + # remove hosting directory and any flag files associated with this VM + Remove-Item $_.Path -Recurse -Force + } + + $f = Join-Path $using:flagPath "*-$($_.Name)" + if (Test-Path $f) + { + Remove-Item $f + } + } + + # do not remove the internal switch if teardown is partial + if ($null -eq $using:vms) + { + $switch = Get-VMSwitch -SwitchType Internal + if ($null -ne $switch) + { + LogOutput -IsVb "Removing Internal VMSwitch @ $($env:COMPUTERNAME)" + $switch | Remove-VMSwitch -Confirm:$False -Force + } + } + } + + if($arcEnvEnabled){ + $nodes = Get-ClusterNode @clusterParam + Invoke-CommonCommand $nodes[0] -InitBlock $CommonFunc -ScriptBlock { + InitializeAndGetArcHCIExtendedLoc $using:azUser $using:azPassword $using:resourceGroup + $imgList = az stack-hci-vm image list --resource-group $using:resourceGroup | ConvertFrom-Json + $existingImage = $imgList | Where-Object name -eq $using:img + if($existingImage){ + LogOutput "Deleting image - $($using:img)" + az stack-hci-vm image delete --name $using:img --resource-group $using:resourceGroup --yes + } + $spList = az stack-hci-vm storagepath list --resource-group $using:resourceGroup | ConvertFrom-Json + $existingSP = $spList | Where-Object name -eq $using:storagePath + if($existingSP){ + LogOutput "Deleting Storage Path - $($using:storagePath)" + az stack-hci-vm storagepath delete --name $using:storagePath --resource-group $using:resourceGroup --yes + } + } + } + + # Fallback to clear remnant content due to earlier errors/etc. + + # Now delete content from csvs corresponding to the cluster nodes + $csv = GetMappedCSV @clusterParam + + Get-ClusterNode |% { + $csv |? VDName -match "$($_.Name)(-.+)?" + } |% { + + Get-ChildItem -Directory $_.sharedvolumeinfo.friendlyvolumename |? { + if ($vms) + { + $_.Name -in $vms + } + else + { + $_.Name -like 'vm-*' + } + } |% { + + LogOutput -IsVb "Removing CSV content for $($_.BaseName) @ $($_.FullName)" + if(-not $arcEnvEnabled){ + # remove hosting directory and any flag files associated with this VM + Remove-Item $_.FullName -Recurse -Force + } + $f = Join-Path $flagPath "*-$($_.Name)" + if (Test-Path $f) + { + Remove-Item $f + } + } + } +} + +function Start-Fleet +{ + [CmdletBinding(DefaultParameterSetName = "ByPercent")] + param( + [Parameter(ParameterSetName = "ByNumber")] + [Parameter(ParameterSetName = "ByPercent")] + [string] + $Cluster = ".", + + [Parameter(ParameterSetName = "ByNumber")] + [Parameter(ParameterSetName = "ByPercent")] + [Parameter()] + [string[]] + $Group = @("*"), + + [Parameter(ParameterSetName = "ByNumber", Mandatory = $true)] + [ValidateRange(1, [uint32]::MaxValue)] + [int] + $Number, + + [Parameter(ParameterSetName = "ByPercent")] + [ValidateRange(1, 100)] + [double] + $Percent = 100 + ) + + # Parameter set specifying cluster only + $clusterParam = @{} + CopyKeyIf $PSBoundParameters $clusterParam 'Cluster' + + $node = @(Get-ClusterNode @clusterParam) + $numNode = $node.Count + + # Pause and clear fleet run state so that VMs arrive as a coordinated group + Set-FleetPause @clusterParam -Timeout 0 + Clear-FleetRunState @clusterParam + + Invoke-CommonCommand ($node |? State -eq Up) -InitBlock $CommonFunc -ScriptBlock { + + $n = $using:Number + $pct = $using:Percent + + $using:Group |% { + + # Get group vms - assume symmetry per node + $vms = @(Get-ClusterGroup |? GroupType -eq VirtualMachine |? Name -like "vm-$_-*") + + # + # Start number/percentage is keyed by VM number label, not dependent on current + # position of VMs within the cluster. For instance, starting 5 VMs/node will start + # vm-etc-001, 002, 003, 004, and 005 wherever they are. + # + # This allows composition with Move-Fleet and partial redistribution of VMs. + # + + # Start subset up to VM #n? + $(if (0 -ne $n) + { + $vms |? OwnerNode -eq $env:COMPUTERNAME |? { $n -ge [int] ($_.Name -split '-')[-1] } + + LogOutput -IsVb "Starting up to VM $n" + } + # Start subset up to VM #n as defined by %age? + elseif ($pct -ne 100) + { + $n = [int] ($vms.Count * $pct / 100 / $using:numNode) + if ($n -eq 0) { $n = 1 } + + $vms |? OwnerNode -eq $env:COMPUTERNAME |? { $n -ge [int] ($_.Name -split '-')[-1] } + + LogOutput -IsVb ("Starting {0:P1} ({1}) VMs / node" -f ( + ($pct/100), + $n)) + } + # Start all + else + { + $vms |? OwnerNode -eq $env:COMPUTERNAME + }) |? { + + # failed is an unclean offline tbd root causes (can usually be recovered with a restart) + $_.State -eq 'Offline' -or $_.State -eq 'Failed' + + } | Start-ClusterGroup |% { LogOutput "Start $($_.Name)" } + } + } +} + +function Stop-Fleet +{ + [CmdletBinding()] + param( + [Parameter()] + [string] + $Cluster = ".", + + [Parameter()] + [string[]] + $Group = @('*') + ) + + # Parameter set specifying cluster only + $clusterParam = @{} + CopyKeyIf $PSBoundParameters $clusterParam 'Cluster' + + $Node = Get-ClusterNode @clusterParam |? State -eq Up + + # Pause and clear fleet run state so that VMs depart as a coordinated group + Set-FleetPause @clusterParam + Clear-FleetRunState @clusterParam + + Invoke-CommonCommand $Node -InitBlock $CommonFunc -ScriptBlock { + + foreach ($g in $using:Group) + { + # + # Get all non-offline VMs to work on. Note that the State property is dynamically evaluated on reference. + # This list only needs to be acquired once. Note that we do shutdown by resource (the VM) while start + # must go by group to ensure the complete group (including the VM configuration resource) is brought up + # + + $vms = Get-ClusterResource |? OwnerNode -eq $env:COMPUTERNAME |? ResourceType -eq 'Virtual Machine' |? OwnerGroup -like "vm-$g-*" |? State -ne 'Offline' + + try + { + # + # Put all VMs in OfflineAction = Shutdown + # https://docs.microsoft.com/en-us/previous-versions/windows/desktop/mscs/virtual-machines-offlineaction + # + + $vms | Set-ClusterParameter -Name OfflineAction -Value 2 + $vms | Stop-ClusterResource |% { LogOutput "Shutdown $($_.OwnerGroup)" } + + # + # Use TurnOff on remaining nonresponsive VMs + # + + $vms |? State -ne 'Offline' | Set-ClusterParameter -Name OfflineAction -Value 0 + $vms |? State -ne 'Offline' | Stop-ClusterResource |% { LogOutput "TurnOff non-responsive $($_.OwnerGroup)" } + } + finally + { + # + # Restore all VMs to OfflineAction - Save (default) + # + + $vms | Set-ClusterParameter -Name OfflineAction -Value 1 + } + } + } +} + +function Repair-Fleet +{ + [CmdletBinding()] + param ( + [Parameter()] + [string] + $Cluster = '.', + + [Parameter()] + [switch] + $BringUp + ) + + # Parameter set specifying cluster only + $clusterParam = @{} + CopyKeyIf $PSBoundParameters $clusterParam 'Cluster' + + $vms = Get-FleetVM @clusterParam -ControlResponse + + # + # In BringUp mode try to start any group which is Offline + # + + $startVM = @() + if ($BringUp) + { + $startVM = @($vms |? ClusterState -eq 'Offline') + + if ($startVM.Count) + { + $startGroups = foreach ($vm in $startVM) + { + Get-ClusterGroup @clusterParam -Name $vm.Name + } + + $startGroups | Start-ClusterGroup |% { LogOutput "Start $($_.Name)" } + } + + $expectedOffline = 0 + } + + # + # Count offline VMs so that we can check that our actions don't create more. + # + else + { + $expectedOffline = @($vms |? ClusterState -eq 'Offline').Count + } + + # + # Now restart all VMs which are not Offline. This rolls up the VM, heartbeat and control response issues. + # Any offline VMs we decided to start for Bringup are continuing to arrive as this is done. + # + + $repairVM = @($vms |? State -ne Offline |? State -ne Ok) + + # + # If there are no VMs to restart and none that we already started (=> need control checks), done. + # + + if ($repairVM.Count -eq 0 -and $startVM.Count -eq 0) + { + return + } + + if ($repairVM.Count) + { + # + # Get all VM resources to work on. Note that the State property is dynamically evaluated on reference. + # This list only needs to be acquired once. Note that we do shutdown by resource (the VM) while start + # must go by group to ensure the complete group (including the VM configuration resource) is brought up + # + + $vms = Get-ClusterResource @clusterParam |? ResourceType -eq 'Virtual Machine' |? OwnerGroup -in $repairVM.Name + + try + { + # + # Put all VMs in OfflineAction = Shutdown + # https://docs.microsoft.com/en-us/previous-versions/windows/desktop/mscs/virtual-machines-offlineaction + # + + $vms | Set-ClusterParameter -Name OfflineAction -Value 2 + $vms | Stop-ClusterResource |% { LogOutput "Repair Shutdown $($_.OwnerGroup)" } + + # + # Use TurnOff on remaining nonresponsive VMs + # + + $vms |? State -ne 'Offline' | Set-ClusterParameter -Name OfflineAction -Value 0 + $vms |? State -ne 'Offline' | Stop-ClusterResource |% { LogOutput "Repair TurnOff non-responsive $($_.OwnerGroup)" } + } + finally + { + # + # Restore all VMs to OfflineAction - Save (default) + # + + $vms | Set-ClusterParameter -Name OfflineAction -Value 1 + } + + # + # Now get the cluster groups to turn on. + # + + $vms = Get-ClusterGroup @clusterParam |? GroupType -eq 'VirtualMachine' |? Name -in $repairVM.Name + $vms | Start-ClusterGroup |% { LogOutput "Repair Start $($_.Name)" } + } + + # + # Wait for VM hearbeats (NoContact) to arrive. The health check assumes any non-OK lower level state + # is indeed fatal and control response is not needed; we know some VMs are restarting and may not be + # reporting to HyperV yet. Wait for Hyperv. + # + + $await = 5 + do { + + Start-Sleep 10 + $vms = Get-FleetVM + + if (@($vms |? State -eq NoContact).Count -eq 0) + { + break + } + + } while (--$await) + + # + # Now get the full health including control response for final validation + # + + $await = 5 + + do { + + $vms = Get-FleetVM -ControlResponse + + # + # If we've maintained the expected number of offline VMs and the balance are OK, repair has been + # successful. Otherwise throw the assertion. + # + + $nowOffline = @($vms |? ClusterState -eq 'Offline').Count + $nowOk = @($vms |? State -eq 'Ok').Count + + if ($nowOffline -eq $expectedOffline -and + $nowOk -eq ($vms.Count - $expectedOffline)) + { + return + } + + LogOutput "Fleet repair re-probe, pausing 5s" + Start-Sleep 5 + + } while (--$await) + + throw "Fleet repair failed: $($vms.Count) total VMs, $nowOffline offline (expected $expectedOffline), $nowOk Ok (expected $($vms.Count - $expectedOffline))" +} + +function Get-FleetVM +{ + [CmdletBinding()] + param ( + [Parameter()] + [string] + $Cluster = ".", + + [Parameter()] + [string] + $Group = '*', + + [Parameter()] + [switch] + $ControlResponse, + + [Parameter()] + [uint32] + $Timeout = 60 + ) + + # Parameter set specifying cluster only + $clusterParam = @{} + CopyKeyIf $PSBoundParameters $clusterParam 'Cluster' + # check if VMs are created in Arc environment + $arcConfig = Get-ArcConfig -Cluster $Cluster + $arcEnvEnabled = $arcConfig -and $arcConfig.Enabled + $salt = $null + if($arcEnvEnabled) { + $salt = $arcConfig.Salt + } + # + # Start timeout; only takes effect after first control response check. + # + + $t0 = Get-Date + + $clusterView = @{} + $vmView = @{} + Get-ClusterGroup @clusterParam |? GroupType -eq VirtualMachine |? Name -like "vm-$Group-*" |% { $clusterView[$_.Name] = $_ } + Get-VM -CimSession @(Get-ClusterNode @clusterParam |? State -eq Up).Name |? { + if($arcEnvEnabled) + { + $_.Name -like "^vm-$Group-.{1,}-" + $salt + "-\d{3}$" + } + else + { + $_.Name -like "vm-$Group-*" + } + } |% { $vmView[$_.Name] = $_ } + # Union into a composite vm health/state object + # Pass 1 through cluster groups. Pass 2 through VMs to detect those + # not attached as cluster groups (not expected). + # + # Accumulate in hash for return. + + $h = @{} + $ok = 0 + + foreach ($cvm in $clusterView.Values) + { + if ($vmView.Contains($cvm.Name)) { + $vmState = $vmView[$cvm.Name].State + } + else + { + $vmState = 'Unknown' + } + + if ($vmView.Contains($cvm.Name)) { + $vmHeartbeat = $vmView[$cvm.Name].Heartbeat + $vmId = $vmView[$cvm.Name].VMId.Guid + } + else + { + $vmHeartbeat = 'Unknown' + $vmId = $null + } + + # Aggregate state is the union of cluster, vm and heartbeat in that priority order + if ($cvm.State -ne 'Online') + { + $state = $cvm.State + } + elseif ($vmState -ne 'Running') + { + $state = $vmState + } + elseif ($vmHeartbeat -like 'Ok*') + { + $state = 'Ok' + ++$ok + } + else + { + $state = $vmHeartbeat + } + + $h[$cvm.Name] = [pscustomobject] @{ + Name = $cvm.Name + VMId = $vmid + OwnerNode = $cvm.OwnerNode + State = $state + ClusterState = $cvm.State + VMState = $vmState + Heartbeat = $vmHeartbeat + ControlResponse = 'Unknown' + }; + } + + foreach ($vvm in $vmView.Values) + { + # Already visited by cluster view? + if ($clusterView.Contains($vvm.Name)) { continue } + + $h[$vvm.Name] = [pscustomobject] @{ + Name = $vvm.Name + VMId = $vvm.VMId.Guid + OwnerNode = $vvm.ComputerName + State = "NotClustered" + ClusterState = "NotClustered" + VMState = $vvm.State + Heartbeat = $vvm.Heartbeat + ControlResponse = 'Unknown' + }; + } + + # + # If there are no Ok VMs at the higher layer health checks (group, vm, heartbeat), + # no control response work to perform - we alredy know they are all failed. If there + # are OK VMs and we are asked to, then perform the control respone check. The basic + # reason this is opt in is that it *is* currently disruptive to running operations. + # It is conceivable that we should have a way for the control loop to chirp out without + # relying on the pause indication, but deferred for now. + # + + if ($ok -ne 0 -and $ControlResponse) + { + # + # Fill filter hash for all Ok VMs; these are the ones relevant to the + # pause flag live check. + # + + $checkPause = @{} + foreach ($vm in $h.Values) + { + if ($vm.State -eq 'Ok') + { + $checkPause["pause-$($vm.Name)"] = $true + } + } + + $flagPath = Get-FleetPath @clusterParam -PathType Flag + + # + # Force pause response from all VM and wait (under timeout) for the responses. + # Note the residual possibility that a given VM has never paused and will now + # create its pause for the first time - must enumerate on each check. + # + + Set-FleetPause @clusterParam -Force -Timeout 0 + $pauseEpoch = Get-FleetPauseEpoch @clusterParam + + do { + + Start-Sleep -Seconds 1 + + # File -> Value map of responses + $pauseValues = @{} + Get-ChildItem $flagPath\pause-* |? { $checkPause[$_.BaseName] } |% { $pauseValues[$_.BaseName] = Get-Content $_ } + + # If we have responses from all VMs ... + if ($pauseValues.Count -eq $checkPause.Count) + { + # Now group responses - if there is one ... + $pauseGroup = @($pauseValues.Values | Group-Object -AsHashTable) + + if ($pauseGroup.Count -eq 1) + { + # Crack value enumerator to comparable value. + $pauseValue = $pauseGroup.Values |% { $_ } + + # If it is the same as the current epoch, we are done. + if ($pauseValue -eq $pauseEpoch) + { + break + } + } + } + + } while (((Get-Date) - $t0).TotalSeconds -lt $Timeout) + + # + # Now roll the pause values (Ok or leave unmodifed/Unknown) onto the VM control response. + # + + foreach ($k in $pauseValues.Keys) + { + if ($pauseValues[$k] -eq $pauseEpoch) + { + $r = 'Ok' + } + else + { + $r = 'NoControlResponse' + } + + $h[$k -replace 'pause-',''].ControlResponse = $r + } + + # + # ControlResponse overrides Ok on final State response. + # VMs which are already non-Ok continue to carry that indication. + # + + foreach ($k in $h.Keys) + { + if ($h[$k].ControlResponse -ne 'Ok' -and $h[$k].State -eq 'Ok') + { + $h[$k].State = 'NoControlResponse' + } + } + } + + $h.Values +} + +function Show-Fleet +{ + [CmdletBinding()] + param ( + [Parameter()] + [string] + $Cluster = ".", + + [Parameter()] + [string] + $Group = '*' + ) + + # Parameter set specifying cluster only + $clusterParam = @{} + CopyKeyIf $PSBoundParameters $clusterParam 'Cluster' + + $vm = Get-FleetVM @PSBoundParameters + + ########################################################### + write-host -fore green By State + $vm | Group-Object -Property State,ClusterState,VMState,HeartBeat | Sort-Object -Property Name |` + Format-Table -AutoSize -Property @{ Label = 'Count'; Expression = { $_.Count }}, + @{ Label = 'State'; Expression = { $_.Group[0].State }}, + @{ Label = 'ClusterState'; Expression = { $_.Group[0].ClusterState }}, + @{ Label = 'VMState'; Expression = { $_.Group[0].VMState }}, + @{ Label = 'Heartbeat'; Expression = { $_.Group[0].Heartbeat }} + + ########################################################### + write-host -fore green By Host + $vm | Group-Object -Property OwnerNode,State,ClusterState,VMState,HeartBeat | Sort-Object -Property Name |` + Format-Table -AutoSize -Property @{ Label = 'Count'; Expression = { $_.Count }}, + @{ Label = 'OwnerNode'; Expression = { $_.Group[0].OwnerNode }}, + @{ Label = 'State'; Expression = { $_.Group[0].State }}, + @{ Label = 'ClusterState'; Expression = { $_.Group[0].ClusterState }}, + @{ Label = 'VMState'; Expression = { $_.Group[0].VMState }}, + @{ Label = 'Heartbeat'; Expression = { $_.Group[0].Heartbeat }} + + ########################################################### + write-host -fore green By Group + $vm |% { + if ($_.Name -match "^vm-([^-]+)-") { + $_ | Add-Member -NotePropertyName Group -NotePropertyValue $matches[1] -PassThru + } + } | Group-Object -Property Group,State,ClusterState,VMState,HeartBeat| Sort-Object -Property Name | ` + Format-Table -AutoSize -Property @{ Label = 'Count'; Expression = { $_.Count }}, + @{ Label = 'Group'; Expression = { $_.Group[0].Group }}, + @{ Label = 'State'; Expression = { $_.Group[0].State }}, + @{ Label = 'ClusterState'; Expression = { $_.Group[0].ClusterState }}, + @{ Label = 'VMState'; Expression = { $_.Group[0].VMState }}, + @{ Label = 'Heartbeat'; Expression = { $_.Group[0].Heartbeat }} + + ########################################################### + write-host -fore green By IOPS + # build 5 orders of log steps + $logstep = 10,20,50 + $log = 1 + $logs = 1..5 |% { + + $logstep |% { $_ * $log } + $log *= 10 + } + + # build log step names; 0 is the > range catchall + $lognames = @{} + foreach ($step in $logs) { + + if ($step -eq $logs[0]) { + $lognames[$step] = "< $step" + } else { + $lognames[$step] = "$pstep - $($step - 1)" + } + $pstep = $step + } + $lognames[0] = "> $($logs[-1])" + + # now bucket up VMs by flow rates + $qosbuckets = @{} + $qosbuckets[0] = 0 + $logs |% { + $qosbuckets[$_] = 0 + } + + $node = Get-AccessNode @clusterParam + + # Note: group all vm disks together and bucket sum of IOPS + Get-StorageQoSFlow -CimSession $node | Group-Object -Property InitiatorName |% { + + $initiatorIops = ($_.Group | Measure-Object -Sum InitiatorIops).Sum + $found = $false + foreach ($step in $logs) { + + if ($initiatorIops -lt $step) { + $qosbuckets[$step] += 1; + $found = $true + break + } + } + # if not bucketed, it is greater than range + if (-not $found) { + $qosbuckets[0] += 1 + } + } + + # find min/max buckets with nonzero counts, by $logs index + # this lets us present a continuous range, with interleaved zeroes + $bmax = -1 + $bmin = -1 + foreach ($i in 0..($logs.Count - 1)) { + if ($qosbuckets[$logs[$i]]) { + + if ($bmin -lt 0) { + $bmin = $i + } + $bmax = $i + } + } + # raise max if we have > range + if ($qosbuckets[0]) { + $bmax = $logs.Count - 1 + } + $range = @($logs[$bmin..$bmax]) + # add > range if needed, at end + if ($qosbuckets[0]) { + $range += 0 + } + + $(foreach ($i in $range) { + + New-Object -TypeName psobject -Property @{ + Count = $qosbuckets[$i]; + IOPS = $lognames[$i] + } + }) | Format-Table Count,IOPS -AutoSize +} + +function Move-Fleet +{ + [CmdletBinding(DefaultParameterSetName = "Default")] + param( + [Parameter(ParameterSetName = 'Default')] + [Parameter(ParameterSetName = 'ByPercent')] + [string] + $Cluster = ".", + + [Parameter(ParameterSetName = 'Default')] + [Parameter(ParameterSetName = 'ByPercent')] + [switch] + $KeepCSV, + + [Parameter(ParameterSetName = 'Default')] + [Parameter(ParameterSetName = 'ByPercent')] + [switch] + $KeepVM, + + [Parameter(ParameterSetName = 'Default')] + [Parameter(ParameterSetName = 'ByPercent')] + [switch] + $ShiftCSV, + + [Parameter(ParameterSetName = 'Default')] + [Parameter(ParameterSetName = 'ByPercent')] + [ValidateRange(0,100)] + [uint32] + $DistributeVMPercent = 0, + + [Parameter(ParameterSetName = 'ByPercent', Mandatory = $true)] + [ValidateRange(1,100)] + [uint32] + $VMPercent = 100, + + [Parameter(ParameterSetName = 'Default')] + [switch] + $Running + ) + + # Parameter set specifying cluster only + $clusterParam = @{} + CopyKeyIf $PSBoundParameters $clusterParam 'Cluster' + + # Note that the collect volume is never affected by fleet CSV movements + $nodes = @(Get-ClusterNode @clusterParam | Sort-Object -Property Name) + $nodesLive = @($nodes |? State -eq Up) + + if ($nodes.Count -le 1 -or $nodesLive.Count -le 1) + { + Write-Error "Cluster only contains a single node ($($nodes.Count)) or less than two live nodes ($($nodesLive.Count) - movement not possible" + return + } + + $csv = GetMappedCSV @clusterParam |? VDName -ne $collectVolumeName + + if ($ShiftCSV) + { + # Shift rotates all csv's node ownership by one node, in lexical order of + # current node owner name. This is useful for forcing all-out-of-position ops + # quickly without VM movement. + LogOutput "Shifting CSV owners" + + # CSV object's OwnerNode is dynamically computed. Build a hash of new OwnerNodes + # for the CSV in pass 1 and move in pass 2. + $moveh = @{} + foreach ($n in 0..($nodes.Length - 1)) + { + $moveTo = ($n + 1) % $nodes.Length + $moveh[$nodes[$moveTo].Name] = $csv |? { $_.OwnerNode.Name -eq $nodes[$n].Name } + } + + foreach ($n in $moveh.Keys) + { + $moveh[$n] | Move-ClusterSharedVolume $n @clusterParam + } + } + + # Re-home all CSV unless declined + elseif (-not $KeepCSV) + { + LogOutput "Aligning CSVs" + + # move all csvs named by node names back to their named node + $nodes |% { + $node = $_ + $csv |? VDName -match "$($node.Name)(?:-.+){0,1}" |? OwnerNode -ne $node.Name |% { $_ | Move-ClusterSharedVolume $node.Name @clusterParam } + } + } + + if (-not $KeepVM) + { + if ($DistributeVMPercent -gt 0) + { + LogOutput "Distributing VMs ($DistributeVMPercent%)" + } + else + { + LogOutput "Aligning VMs" + } + + # + # Build aligned ownership lists in order of node list, in lexical name + # order to take advantage of the stable distribution shift. Shifting by 60% + # will build on the moves for 50%, and so forth. + # + + $vms = Get-ClusterGroup @clusterParam |? GroupType -eq VirtualMachine + + # + # Only rotate online VMs? This allows one model of composing partial startup with rotation - start + # given number in-place and apply rotation to those. + # + + if ($Running) + { + $vms = $vms |? State -eq Online + + if ($vms.Count -eq 0) + { + Write-Error "No VMs currently running, no rotation performed" + } + } + + $groups = [collections.arraylist]@() + $count = 0 + foreach ($node in $nodes) + { + $arr = [collections.arraylist]@() + foreach ($vm in $vms | Sort-Object -Property Name) + { + if ($vm.Name -match "vm-.*-$($node.Name).*-\d+$") + { + $null = $arr.Add($vm) + } + } + if ($count -eq 0) + { + $count = $arr.Count + } + elseif ($count -ne $arr.Count) + { + Write-Error "Node $node only has $($arr.Count) aligned VMs created for it. Please check that all nodes had the same number of VMs created (New-Fleet -VMs)." + } + $null = $groups.Add($arr) + } + + if($VMPercent -lt 100) + { + # + # How many VMs per node to consider in the rotation (partial start cases, without -Running). + # Discard upper portion of VMs/node. Note this is/must be consistent with start-fleet, + # get-fleetdatadiskestimate and other vm-percentage calculations. + # + + $n = [int] ($VMPercent * $groups[0].Count /100 ) + if ($n -eq 0) { $n = 1 } + + # No trim if rounding took it back to 100%. + + if ($n -ne $groups[0].Count) + { + foreach ($g in $groups) + { + $g.RemoveRange($n, $g.Count - $n) + } + } + } + + if ($DistributeVMPercent -gt 0) + { + # + # How many VMs to distribute (at least 1 VM/node) + # + + $n = [int] ($DistributeVMPercent * $groups[0].Count / 100) + if ($n -eq 0) { $n = 1 } + + $groups = GetDistributedShift -Group $groups -N $n + } + + try + { + # + # Strip out VMs already in the correct location and farm out movement + # to the respective host node. + # + + $j = @() + for ($i = 0; $i -lt $groups.Count; ++$i) + { + $moveList = @(foreach ($vm in $groups[$i]) + { + if ($vm.OwnerNode -ne $nodes[$i]) + { + $vm + } + }) + + if ($moveList.Count -eq 0) + { + continue + } + + $target = $nodes[$i].Name + LogOutput Moving $moveList.Count VMs to $target + + # + # Carefully quote the movelist so that it passes as a single parameter (list of a single element, a list) + # + + $j += Invoke-CommonCommand -AsJob -InitBlock $CommonFunc -ArgumentList @(,$moveList) -ScriptBlock { + + [CmdletBinding()] + param( + [object[]] + $vms + ) + + foreach ($vm in $vms) + { + LogOutput "Moving $($vm.Name): $($vm.OwnerNode) -> $using:target" + + $expectedState = $vm.State + + try + { + # The default move type is live, but live does not degenerately handle offline vms yet. + # Discard the warning stream - if an issue occurs the cluster will offer a generic comment + # about credential remoting (in addition to the error) which is not going to be relevant in + # our cases. + if ($vm.State -eq 'Offline') + { + $null = Move-ClusterVirtualMachineRole @using:clusterParam -Name $vm.Name -Node $using:target -MigrationType Quick -ErrorAction Stop 3> $null + } + else + { + $null = Move-ClusterVirtualMachineRole @using:clusterParam -Name $vm.Name -Node $using:target -ErrorAction Stop 3> $null + } + } + catch + { + # + # Workaround false failure of VM quick/offline migration - sink the error if VM appears to land, otherwise propagate it. + # + + $checkVM = Get-ClusterGroup @using:clusterParam -Name $vm.Name + + $await = 0 + if ($expectedState -eq 'Offline') + { + $await = 5 + do { + + if ($checkVM.State -eq $expectedState -and $checkVM.OwnerNode -eq $using:target) + { + LogOutput "Verified VM quick migration on retry $(5 - $await + 1) $($vm.Name) -> $using:target" + break + } + + if (-not --$await) + { + break + } + + Start-Sleep 1 + $checkVM = Get-ClusterGroup @using:clusterParam -Name $vm.Name + + } while ($true) + } + + if ($await -eq 0) + { + if ($checkVM.State -ne $expectedState) { LogOutput "Verify $($vm.Name) $($checkVM.State) != $expectedState" } + if ($checkVM.OwnerNode -ne $using:target) { LogOutput "Verify $($vm.Name) $($checkVM.OwnerNode) != $($using:target)" } + LogOutput -ForegroundColor Red "Error moving $($vm.Name)" + + $errorObject = CreateErrorRecord -ErrorId $_.FullyQualifiedErrorId ` + -ErrorMessage $null ` + -ErrorCategory $_.CategoryInfo.Category ` + -Exception $_.Exception ` + -TargetObject $_.TargetObject + + $psCmdlet.WriteError($errorObject) + } + } + } + } + } + + # + # And await completion (errors flow through) + # + + $jobErrors = @() + while ($true) + { + $done = @($j | Wait-Job -Timeout 1) + try { + $j | Receive-Job + } catch { + $jobErrors += $_ + } + if ($done.Count -eq $j.Count) + { + break + } + } + } + finally + { + $j | RemoveCommonJobSession + $j | Remove-Job + } + + if ($jobErrors.Count) + { + $jobErrors |% { Write-Error -ErrorRecord $_ } + } + } +} + +function Set-FleetPowerScheme +{ + param ( + [Parameter()] + [string] + $Cluster = ".", + + [Parameter(Mandatory = $true)] + [ValidateSet("Balanced","HighPerformance","PowerSaver")] + [string] + $Scheme + ) + + $node = Get-ClusterNode -Cluster $Cluster |? State -eq Up + + switch ($Scheme) + { + "Balanced" { $guid = '381b4222-f694-41f0-9685-ff5bb260df2e' } + "HighPerformance" { $guid = '8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c' } + "PowerSaver" { $guid = 'a1841308-3541-4fab-bc81-f71556f20b4a' } + } + + Invoke-CommonCommand -ComputerName $node -ScriptBlock { + powercfg /setactive $using:guid + } +} + +function Get-FleetPowerScheme +{ + param ( + [Parameter()] + [string] + $Cluster = "." + ) + + $node = Get-ClusterNode -Cluster $Cluster |? State -eq Up + + $scheme = Invoke-CommonCommand -ComputerName $node -ScriptBlock { + powercfg /getactivescheme + } + + # Map/Normalize names off of GUID (i8ln?) + $normalScheme = foreach ($s in $scheme) + { + $null = $s -match 'GUID:\s+(\S+)' + + switch ($matches[1]) + { + '381b4222-f694-41f0-9685-ff5bb260df2e' { $name = "Balanced" } + '8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c' { $name = "HighPerformance" } + 'a1841308-3541-4fab-bc81-f71556f20b4a' { $name = "PowerSaver" } + + default { + Write-Error "Unnown running power scheme guid $($matches[1]) - please provide feedback to VM Fleet and normalize to known (Balanced, High Performance or Power Saver - see powercfg /list)" + return + } + } + + [pscustomobject] @{ Name = $name; Node = $s.PSComputerName } + } + + $g = @($normalScheme | Group-Object -Property Name ) + + if ($g.Count -eq 1) + { + return $g[0].Name + } + + foreach ($s in $normalScheme) + { + Write-Warning "Node $($s.Node): $($s.Name)" + } + + Write-Error "Inconsistent power schemes running in cluster - please verify intended configuration" +} + +function Set-FleetQoS +{ + # apply given QoS policy (by name) to all VMs on specified nodes + [CmdletBinding(DefaultParameterSetName = "ByCluster")] + param ( + [Parameter(ParameterSetName = "ByCluster")] + [string] + $Cluster = ".", + + [Parameter(ParameterSetName = "ByNode", Mandatory = $true)] + [string[]] + $Node, + + [Parameter()] + [string] + $Name + ) + + if ($PSCmdlet.ParameterSetName -eq 'ByCluster') + { + $Node = Get-ClusterNode -Cluster $Cluster |? State -eq Up + } + + if ($PSBoundParameters.ContainsKey('Name')) + { + # QoS policy must exist, else error out + $qosp = Get-StorageQoSPolicy -Name $Name -CimSession $Node[0] + if ($null -eq $qosp) + { + # cmdlet error sufficient + return + } + + $id = $qosp.PolicyId + LogOutput -IsVb "applying QoS Policy: $Name (PolicyID $id)" + } + else + { + # clears QoS policy + $id = $null + LogOutput -IsVb "removing QoS Policy" + } + + Invoke-Command $Node { + + Get-VM |% { Get-VMHardDiskDrive $_ |% { Set-VMHardDiskDrive -QoSPolicyID $using:id -VMHardDiskDrive $_ }} + } +} + +# +# Dynamic ValidateSet should be used when available - not present in inbox PS5.1 +# This would replace the large ValidateSet with a simple [ValidateSet([VMSpec])] +# + +# class VMSpec : System.Management.Automation.IValidateSetValuesGenerator { +class VMSpec { + + [int] $ProcessorCount + [int64] $MemoryStartupBytes + [string] $Alias + + VMSpec( + [int] + $ProcessorCount, + + [int64] + $MemoryStartupBytes, + + [string] + $Alias + ) + { + $this.ProcessorCount = $ProcessorCount + $this.MemoryStartupBytes = $MemoryStartupBytes + $this.Alias = $Alias + } + + <# + [String[]] GetValidValues() { + + return $script:VMSpecs.Keys + } + #> +} + +$VMSpecs = @{} +$VMSpecs['A1v2'] = [VMSpec]::new(1, 2GB, $null) +$VMSpecs['A2v2'] = [VMSpec]::new(2, 4GB, $null) +$VMSpecs['A4v2'] = [VMSpec]::new(4, 8GB, $null) +$VMSpecs['A8v2'] = [VMSpec]::new(8, 16GB, $null) + +$VMSpecs['A2mv2'] = [VMSpec]::new(2, 16GB, $null) +$VMSpecs['A4mv2'] = [VMSpec]::new(4, 32GB, $null) +$VMSpecs['A8mv2'] = [VMSpec]::new(8, 64GB, $null) + +# example of an alias when vcpu/mem are the same +# $VMSpecs['D1v2'] = [VMSpec]::new(0, 0, 'A1v2') + +#> + +function Get-FleetComputeTemplate +{ + [CmdletBinding()] + param( + [Parameter(Mandatory = $true)] + [ValidateSet( + 'A1v2','A2mv2','A2v2','A4mv2','A4v2','A8mv2','A8v2' + )] + [string] + $ComputeTemplate + ) + + $spec = $VMSpecs[$ComputeTemplate] + if ($spec.ProcessorCount -eq 0) { + $spec = $VMSpec[$spec.Alias] + } + + $spec +} + +function Set-Fleet +{ + [CmdletBinding(DefaultParameterSetName = "FullSpecStatic")] + param( + [Parameter(ParameterSetName = 'DataDisk')] + [Parameter(ParameterSetName = 'FullSpecDynamic')] + [Parameter(ParameterSetName = 'FullSpecStatic')] + [string] + $Cluster = ".", + + [Parameter(ParameterSetName = 'FullSpecDynamic', Mandatory = $true)] + [Parameter(ParameterSetName = 'FullSpecStatic', Mandatory = $true)] + [int] + $ProcessorCount, + + [Parameter(ParameterSetName = 'FullSpecDynamic', Mandatory = $true)] + [Parameter(ParameterSetName = 'FullSpecStatic', Mandatory = $true)] + [int64] + $MemoryStartupBytes, + + [Parameter(ParameterSetName = 'FullSpecDynamic', Mandatory = $true)] + [int64] + $MemoryMaximumBytes, + + [Parameter(ParameterSetName = 'FullSpecDynamic', Mandatory = $true)] + [int64] + $MemoryMinimumBytes, + + # Note: ValidateSet MUST be kept in line with definitions. + # This can become dyanmic if/when we can move forward to PS 6.1/later + # where the dynamic ValidateSet capability can be used. + [Parameter(ParameterSetName = 'SizeSpec')] + [ValidateSet( + 'A1v2','A2mv2','A2v2','A4mv2','A4v2','A8mv2','A8v2' + )] + [string] + $ComputeTemplate = 'A1v2', + + [Parameter(ParameterSetName = 'DataDisk', Mandatory = $true)] + [uint64] + $DataDiskSize, + + [Parameter(ParameterSetName = 'DataDisk')] + [switch] + $Running + ) + + $nodes = @(Get-ClusterNode -Cluster $Cluster |? State -eq Up) + # check if VMs are created in Arc environment + $arcConfig = Get-ArcConfig -Cluster $Cluster + $arcEnvEnabled = $arcConfig -and $arcConfig.Enabled + $resourceGroup, $salt = $null + if($arcEnvEnabled) { + $resourceGroup = $arcConfig.ResourceGroup + $salt = $arcConfig.Salt + } + # Fill parameters + $p = @{} + if($arcEnvEnabled){ + $p['ArcEnvEnabled'] = $arcEnvEnabled + $p['ResourceGroup'] = $resourceGroup + } + switch ($PSCmdlet.ParameterSetName) { + + 'FullSpecDynamic' + { + $p['DynamicMemory'] = $true + + $p['ProcessorCount'] = $ProcessorCount + $p['MemoryMaximumBytes'] = $MemoryMaximumBytes + $p['MemoryMinimumBytes'] = $MemoryMinimumBytes + $p['MemoryStartupBytes'] = $MemoryStartupBytes + + LogOutput -IsVb "DynamicMemory: applying ProcessorCount $ProcessorCount Memory[ Start $('{0:N2}' -f ($MemoryStartupBytes/1GB))GB : $('{0:N2}' -f ($MemoryMinimumBytes/1GB))GB - $('{0:N2}' -f ($MemoryMaximumBytes/1GB))GB ]" + } + + 'FullSpecStatic' + { + $p['StaticMemory'] = $true + + $p['ProcessorCount'] = $ProcessorCount + $p['MemoryStartupBytes'] = $MemoryStartupBytes + + LogOutput -IsVb "StaticMemory: applying ProcessorCount $ProcessorCount Memory[ $('{0:N2}' -f ($MemoryStartupBytes/1GB))GB ]" + } + + 'SizeSpec' + { + $spec = Get-FleetComputeTemplate -ComputeTemplate $ComputeTemplate + + $p['ProcessorCount'] = $spec.ProcessorCount + $p['StaticMemory'] = $true + $p['MemoryStartupBytes'] = $spec.MemoryStartupBytes + + LogOutput -IsVb "StaticMemory: applying $ComputeTemplate compute template: ProcessorCount $($spec.ProcessorCount) Memory[ $('{0:N2}' -f ($spec.MemoryStartupBytes/1GB))GB ]" + } + } + + if ($PSCmdlet.ParameterSetName -ne 'DataDisk') + { + Invoke-Command $nodes -ArgumentList $p { + + param($p) + + foreach ($vm in Get-VM) + { + # Match off home node name from VM. This identifies the VM directory location. + if ($vm.Name -notmatch 'vm-[^-]+-(.*)-(\d+)') + { + # not a fleet VM + continue + } + + if ($vm.State -ne 'Off') + { + Write-Error "Cannot set VM properties on VMs which are not offline: $($vm.Name) ($($vm.State))" + } + else + { + if($p['ArcEnvEnabled']){ + $name = $vm.Name + $cpuCount = $p['ProcessorCount'] + $memorymb = $p['MemoryStartupBytes']/1048576 + $rg = $p['ResourceGroup'] + # for now, this script only supports static memory for Arc vms + az stack-hci-vm update --name $name --v-cpus-available $cpuCount --memory-mb $memorymb --resource-group $rg + # currently, vms go back to running state instead of original state before peforming an update + az stack-hci-vm stop --name $name --resource-group $rg + } + else { + $vm | Set-VM @p + } + + continue + } + } + } + } + else + { + # + # This needs to run without remoting. The cluster cmdlets embedded within the HyperV set are not reliably + # executable in remote sessions due to credential delegation when not using CredSSP. Specifically, + # Update-ClusterVirtualMachineConfiguration is invoked to update the clustered role when disks are modifieed. + # + + $vms = @(Get-VM -CimSession $nodes.Name |? { + if($arcEnvEnabled) { + $_.Name -match "^vm-.{1,}-" + $salt + "-\d{3}$" + } + else { + $_.Name -like 'vm-*' + } + } + ) + for ($i = 0; $i -lt $vms.Count; ++$i) + { + $vm = $vms[$i] + + $pcomplete = [int](100*$i/($vms.Count)) + Write-Progress -Id 0 -Activity "Updating VM Data Disks" -PercentComplete (100*$i/($vms.Count)) -CurrentOperation $vm.Name -Status "$pcomplete% Complete:" + + # Skip non-running VMs? + if ($Running -and $vm.State -ne 'Running') + { + continue + } + # Explicitly work on non-running VMs? Skip running VMs. + elseif ($PSBoundParameters.ContainsKey('Running') -and -not $Running -and $vm.State -eq 'Running') + { + continue + } + + # + # ControllerNumber/Location 0/0 is the boot/OS VHD - that is not modified. + # Order the list so that the boot/OS VHD will always be the first, data the second. + # + + $vhd = @($vm | Get-VMHardDiskDrive | Sort-Object -Property ControllerNumber,ControllerLocation) + + if ($vhd.Count) + { + # Only expect exactly one or zero data disks at this time. Do not operate if additional + # devices have been added. + if ($vhd.Count -gt 2) + { + Write-Error "Unexpected number of VM hard disks ($($vhd.Count)) attached to VM $($vm.Name): expecting at most a single data disk" + continue + } + + function Remove + { + Write-Progress -Id 1 -ParentId 0 -Activity "Detaching VM Data Disk from VM" + $path = $vhd[1].Path + $vhd[1] | Remove-VMHardDiskDrive + Write-Progress -Id 1 -ParentId 0 -Activity "Removing VM Data Disk" + Remove-Item $path -Force + Write-Progress -Id 1 -ParentId 0 -Activity "Removing VM Data Disk" -Completed + } + + function Create + { + if($arcEnvEnabled){ + $vmName = $vm.Name + $dataDiskName = "data-$vmName.vhdx" + $path = Join-Path $vm.Path $dataDiskName + } + else { + $path = Join-Path $vm.Path "data.vhdx" + } + + if ($null -eq $path) + { + continue + } + + # Scrub stale/detached vhdx + if (Test-Path $path) + { + Remove-Item $path -Force + } + + Write-Progress -Id 1 -ParentId 0 -Activity "Creating VM Data Disk" + # Allow VHD objects for newly created VHDX to appear on the pipeline. Note that HCI is 4KN, do not create + # the default 512e layout. + New-VHD -Path $path -SizeBytes $DataDiskSize -Fixed -LogicalSectorSize 4096 + + Write-Progress -Id 1 -ParentId 0 -Activity "Extending VM Data Disk Valid Data Length" + # Push valid data - this could be parameterized to expose the true fresh-out-of-box + # case of an empty/sparsed VHDX. This does not replace pre-seasoning though it does + # eliminate the first level of FS effects. + # Redirect stdout, allow stderr to flow out. + fsutil file setvaliddata $path (Get-Item $path).Length > $null + + Write-Progress -Id 1 -ParentId 0 -Activity "Creating VM Data Disk" -Completed + $vm | Add-VMHardDiskDrive -Path $path + } + + # Remove? + if ($DataDiskSize -eq 0) + { + # No data device? + if ($vhd.Count -eq 1) + { + LogOutput "Confirmed no data disk attached to $($vm.Name)" + continue + } + + LogOutput "Removing data disk from $($vm.Name)" + Remove + } + + # Create data VHD? + elseif ($vhd.Count -eq 1) + { + LogOutput "Creating data disk for $($vm.Name)" + Create + } + + # Resize existing data VHD. Note that this is destructive - we do not attempt to manage + # a first-class resize up/down of the disk and its contained partitions/filesystems. + # We assume for now that any disk level initialization will be repeated by the calling + # framework, as notified by new vhd objects being returned in the pipeline. + else + { + $vhdx = Get-VHD -ComputerName $vm.ComputerName -VMId $vm.Id |? Path -eq $vhd[1].Path + if ($null -eq $vhdx) + { + Write-Error "Could not find VHDX on VM ($vm.Name) corresponding to $($vhd[1].Path)" + } + elseif ($vhdx.Size -ne $DataDiskSize) + { + # Native Resize-VHD does not apply to fixed VHDX - Remove/Create new + LogOutput "Resizing (remove/create) data disk for $($vm.Name)" + Remove + Create + } + } + } + } + + Write-Progress -Id 0 -Activity "Updating VM Data Disks" -Completed + } +} + +function Get-FleetDisk +{ + [CmdletBinding()] + param( + [Parameter()] + [string] + $Cluster = '.', + + [Parameter()] + [switch] + $OsDisk, + + [Parameter()] + [switch] + $All + ) + + $nodes = @(Get-ClusterNode -Cluster $Cluster |? State -eq Up) + foreach ($vhd in Get-VM -CimSession $nodes.Name |? Name -like 'vm-*' | Get-VMHardDiskDrive) + { + # If not including OS disk, only emit non-boot devices (boot is always at 0/0) + if ($All -or + ($OsDisk -and ($vhd.ControllerLocation -eq 0 -and $vhd.ControllerNumber -eq 0)) -or + (-not $OsDisk -and ($vhd.ControllerLocation -ne 0 -or $vhd.ControllerNumber -ne 0))) + { + $vhd + } + } +} + +function Get-FleetVolumeEstimate +{ + [CmdletBinding()] + param( + [Parameter()] + [string] + $Cluster = '.', + + [Parameter()] + [uint64] + $CollectVolumeSize = (200GB), + + [Parameter()] + [ValidateRange(1,50)] + [uint32] + $MAPMirrorPercentage = 20 + ) + + $pool = @(Get-StorageSubsystem -CimSession $Cluster |? AutomaticClusteringEnabled | Get-StoragePool |? IsPrimordial -eq $false) + + if ($pool.Count -eq 0) + { + Write-Error "No pool found" + return + } + + if ($pool.Count -ne 1) + { + Write-Error "Unexpected number of pools found ($($pool.Count)) - please verify environment configuration" + return + } + + $pool = $pool[0] + $poolFree = $pool.Size - $pool.AllocatedSize + + # + # Get relevant m/p storage tiers. Subtle point - 2019 documented creating nested tiers manually w/o On. + # So we search for NestedMirror* (w/wo mediatype) and *Parity*, the latter so we get [Nested]ParityOn as well + # as NestedParity. Since we demand only one matching we're safe against odd cases. + # + + $tierM = @($pool | Get-StorageTier |? ResiliencySettingName -eq Mirror |? FriendlyName -like 'MirrorOn*') + $tierNM = @($pool | Get-StorageTier |? ResiliencySettingName -eq Mirror |? FriendlyName -like 'NestedMirror*') + $tierP = @($pool | Get-StorageTier |? ResiliencySettingName -eq Parity |? FriendlyName -like '*Parity*') + + if ($tierM.Count -eq 0) + { + Write-Error "No per-media type mirror resiliency tier (MirrorOn) found for storage pool `'$($pool.FriendlyName)`' - please verify environment configuration" + return + } + + if ($tierM.Count -gt 1) + { + Write-Error "Multiple per-media type mirror resiliency tiers (MirrorOn) found for storage pool `'$($pool.FriendlyName)`' - estimation not supported" + return + } + else + { + $tierM = $tierM[0] + } + + if ($tierNM.Count -gt 1) + { + Write-Error "Multiple per-media type nested mirror resiliency tiers (NestedMirrorOn) found for storage pool `'$($pool.FriendlyName)`' - estimation not supported" + return + } + elseif ($tierNM.Count -ne 0) + { + $tierNM = $tierNM[0] + } + else + { + $tierNM = $null + } + + if ($tierP.Count -gt 1) + { + Write-Error "Multiple per-media type parity resiliency tiers (MirrorOn) found for storage pool `'$($pool.FriendlyName)`' - estimation not supported" + } + + if ($tierP.Count -eq 0) + { + Write-Warning "No per-media type parity resiliency tier (ParityOn) found for storage pool `'$($pool.FriendlyName)`' - parity estimation skipped" + $tierP = $null + } + else + { + $tierP = $tierP[0] + } + + # Mirror efficiency is simply number of copies. + $pEff = 0 + $mEff = 1 / $tierM.NumberOfDataCopies + if ($null -ne $tierNM) { $nmEff = 1 / $tierNM.NumberOfDataCopies } + + if ($null -ne $tierP) + { + # Estimate parity tier efficiency based on reported max v. free space. + $tierPEst = Get-StorageTierSupportedSize -InputObject $tierP + $pEff = $tierPEst.TierSizeMax / $poolFree + } + + # Determine reserve capacity per default guidance - one capacity device per node up to 4 total in cluster. + # For estimation take the largest such device - if there is variance it should be within a very narrow + # band (e.g., all 10TB devices plus or minus some small amount). + $nodeCount = @(Get-ClusterNode -Cluster $Cluster).Count + $capDevice = $pool | Get-PhysicalDisk -CimSession $Cluster |? Usage -eq Auto-Select | Sort-Object -Property Size -Descending | Select-Object -First 1 + + if ($null -eq $capDevice) + { + Write-Error "Could not determine capacity device size for storage pool `'$($pool.FriendlyName)`' - please verify environment configuration and validate that there are Auto-Select devices reported" + } + + if ($nodeCount -gt 4) + { + $capReserve = $capDevice.Size * 4 + } + else + { + $capReserve = $capDevice.Size * $nodeCount + } + + LogOutput -IsVb ("Pool {0:0.00}TiB total {1:0.00}TiB free: {2:0.00}TiB capacity devices in {3:0} node cluster => {4:0.00}TiB rebuild reserve" -f ( + ($pool.Size/1TB), + ($poolFree/1TB), + ($capDevice.Size/1TB), + ($nodeCount), + ($capReserve/1TB))) + + $nmVb = $null + if ($null -ne $tierNM) { $nmVb = ", {0:P1} nested mirror efficiency" -f $nmEff } + + LogOutput -IsVb ("Using {0:P1} mirror efficiency$nmVb, {1:P1} parity efficiency and {2}:{3} MAP mirror:parity ratio" -f ( + $mEff, + $pEff, + $MAPMirrorPercentage, + (100-$MAPMirrorPercentage))) + + # + # Now roll up to the usable free space in the pool. This is the actual (current) free space plus the space + # taken by existing (if any) non-infrastructure volumes, the only one of which is ClusterPerformanceHistory. + # + + $collect = $null + + # Add back the footprint of existing infra volumes (if any). It might be best to validate that all of the + # ones other than (potentiall existing) collect do indeed match to nodes per the fleet naming convention, + # but there should be no other volumes present. + $pool | Get-VirtualDisk |? FriendlyName -notin @('ClusterPerformanceHistory') |% { + + $poolFree += $_.FootprintOnPool + if ($_.FriendlyName -eq 'collect') + { + $collect = $_ + } + } + + # If an explicit collect size is provided, use it. + # If the collect volume already exists, warn if the provided (if any) collect size estimate does not match. + # If an explicit collect size is not provided, use the existing volume if present. + if ($PSBoundParameters.ContainsKey('CollectVolumeSize')) + { + if ($null -ne $collect -and + $CollectVolumeSize -ne $collect.Size) + { + Write-Warning ("A collect volume already exists but is not the same size as specified - {0:0.00}GiB != {1:0.00}GiB. The estimates will assume this is the desired size and that the existing volume would be deleted and recreated following the new specification. If this is not the intent, rerun without specifying the size to base the estimates on the existing volume." -f ( + ($collect.Size/1GB), + ($CollectVolumeSize/1GB))) + } + + # Per spec; existing volume (if any) was already accounted in usable space + LogOutput -IsVb ("Collect: volume size specified is {0:0.00}GiB" -f ($CollectVolumeSize/1GB)) + $poolFree -= $CollectVolumeSize / $mEff + } + else + { + if ($null -ne $collect) + { + # Use existing volume; take it back out of usable space + LogOutput -IsVb ("Collect: using existing volume ({0:0.00}GiB)" -f ($collect.Size/1GB)) + $poolFree -= $collect.FootprintOnPool + } + else + { + # Per default spec + LogOutput -IsVb ("Collect: using default volume size ({0:0.00}GiB)" -f ($CollectVolumeSize/1GB)) + $poolFree -= $CollectVolumeSize / $mEff + } + } + + # Finally, remove the repair reserve + $poolFree -= $capReserve + + # + # Now estimate mirror and MAP volume tier sizes to arrive within a near margin of the usable free space. + # + + function RoundSize + { + param( [uint64] $size ) + + # Basic precision constrol: + # Truncate TiB/GiB to nearest 10GiB, nearest 5GiB if < 500GiB + $sizeGB = [uint32] ($size/1GB) + if ($sizeGB -lt 500) + { + $sizeGB -= $sizeGB % 5 + } + else + { + $sizeGB -= $sizeGB % 10 + } + + return $sizeGB * 1GB + } + + # Collect volume estimate, if it does not already exist or an overriding size was specified. + if ($null -eq $collect -or $PSBoundParameters.ContainsKey('CollectVolumeSize')) + { + [VolumeEstimate]::new([VolumeType]::Collect, $CollectVolumeSize, $tierm.FriendlyName, 0, $null) + } + + # Mirror + $vsizeM = RoundSize (($poolFree * $mEff)/$nodeCount) + [VolumeEstimate]::new([VolumeType]::Mirror, $vsizeM, $tierM.FriendlyName, 0, $null) + + # Nested Mirror? + if ($null -ne $tierNM) + { + $vsizeM = RoundSize (($poolFree * $nmEff)/$nodeCount) + [VolumeEstimate]::new([VolumeType]::NestedMirror, $vsizeM, $tierNM.FriendlyName, 0, $null) + } + + if ($null -ne $tierP) + { + # MAP + # This is derived by solving the system of equations + # p/peff + m/meff = poolFree + # p/m = the given ratio of parity to mirror capacity + # Note we can substitute for p (or m) in terms of the ratio; the solution + # flows from there. MAP on environments with nested mirror defined are + # presumed to use that tier definition for MAP. + + if ($null -ne $tierNM) + { + $mEffToUse = $nmEff + $mTierName = $tierNM.FriendlyName + } + else + { + $mEffToUse = $mEff + $mTierName = $tierM.FriendlyName + } + + $pmRatio = (100 - $MAPMirrorPercentage)/$MAPMirrorPercentage + $vsizeM = [uint64] ($poolFree / ($pmRatio/$pEff + 1/$mEffToUse)) + $vsizeP = RoundSize ($pmRatio * $vsizeM / $nodeCount) + $vsizeM = RoundSize ($vsizeM / $nodeCount) + [VolumeEstimate]::new([VolumeType]::MAP, $vsizeM, $mTierName, $vsizeP, $tierP.FriendlyName) + } +} + +function Get-FleetDataDiskEstimate +{ + [CmdletBinding(DefaultParameterSetName = 'Default')] + param( + [Parameter(ParameterSetName = 'Default')] + [Parameter(ParameterSetName = 'ByPercent')] + [Parameter(ParameterSetName = 'ByVMs')] + [string] + $Cluster = '.', + + [Parameter(ParameterSetName = 'Default')] + [Parameter(ParameterSetName = 'ByPercent')] + [Parameter(ParameterSetName = 'ByVMs')] + [double] + [ValidateRange(10,1000)] + $CachePercent, + + [Parameter(ParameterSetName = 'Default')] + [Parameter(ParameterSetName = 'ByPercent')] + [Parameter(ParameterSetName = 'ByVMs')] + [ValidateRange(1,100)] + [double] + $CapacityPercent, + + [Parameter(ParameterSetName = 'Default')] + [Parameter(ParameterSetName = 'ByPercent')] + [Parameter(ParameterSetName = 'ByVMs')] + [switch] + $Higher, + + [Parameter(ParameterSetName = 'ByVMs', Mandatory = $true)] + [uint32] + $VMs, + + [Parameter(ParameterSetName = 'Default')] + [switch] + $Running, + + [Parameter(ParameterSetName = 'ByPercent', Mandatory = $true)] + [ValidateRange(1,100)] + [double] + $VMPercent + ) + + $clusterParam = @{} + CopyKeyIf $PSBoundParameters $clusterParam 'Cluster' + + if (-not $PSBoundParameters.ContainsKey('CachePercent') -and + -not $PSBoundParameters.ContainsKey('CapacityPercent')) + { + throw "One or both of CachePercent or CapacityPercent must be specified." + } + + $pool = @(Get-StorageSubsystem -CimSession $Cluster |? AutomaticClusteringEnabled | Get-StoragePool |? IsPrimordial -eq $false) + + if ($pool.Count -eq 0) + { + Write-Error "No pool found" + return + } + + if ($pool.Count -ne 1) + { + Write-Error "Unexpected number of pools found ($($pool.Count)) - please verify environment configuration" + return + } + + $cacheDevice = @($pool | Get-PhysicalDisk -CimSession $Cluster |? Usage -eq Journal) + + if ($cacheDevice.Count -eq 0 -and -not $PSBoundParameters.ContainsKey('CapacityPercent')) + { + Write-Error "There are no identifiable cache devices (Usage = Journal) - please verify environment configuration" + return + } + + if ($cacheDevice |? HealthStatus -ne Healthy) + { + Write-Warning "There are cache devices that are not healthy - please verify environment before proceeding" + } + + if ($cacheDevice.Count -ne 0) + { + $cacheCapacity = ($cacheDevice | Measure-Object -Property Size -Sum).Sum + } + else + { + $cacheCapacity = 0 + } + + $nodes = @(Get-ClusterNode @clusterParam) + + if ($nodes |? State -ne Up) + { + Write-Warning "There are nodes which are not currently up - please verify environment before proceeding" + } + + ## + # Get available space + ## + + $availableCapacity = 0 + $totalVolumeCapacity = 0 + + # + # Get total/data space available in fleet volumes + # + + $nodes = Get-ClusterNode @clusterParam + $volumes = Get-Volume -CimSession $Cluster + + foreach ($volume in $volumes) + { + foreach ($node in $nodes) + { + if ($volume.FileSystemLabel -match "^$node(?:-.+){0,1}$") + { + LogOutput -IsVb "volume $($volume.FileSystemLabel) matched to node $node" + $availableCapacity += $volume.SizeRemaining + $totalVolumeCapacity += $volume.Size + break + } + } + } + + # + # Get size of current data disks (if any) to account for reusable space. Note this is + # physical used capacity, not logical capacity presented to VM. + # + + $curDataDiskCapacity = 0 + $dataDisk = @(Get-FleetDisk @clusterParam) + + if ($dataDisk.Count) + { + # + # Note that disk paths are local to the cluster. + # En-list list of paths to pass as single list parameter. + # + + $curDataDiskCapacity = Invoke-Command -ComputerName $Cluster -ArgumentList @(,@($dataDisk.Path)) { + + param( + [string[]] + $paths + ) + + $s = 0 + foreach ($p in $paths) + { + $s += (Get-Item $p).Length + } + $s + } + } + + # + # Add in current utilization - available for use (resize) + # + + $availableCapacity += $curDataDiskCapacity + + # + # Now validate and convert VM count from VMs/node to total VMs. + # This is consistent with New-Fleet. + # + + if (-not $PSBoundParameters.ContainsKey('VMs')) + { + $vmGroups = @(Get-ClusterGroup @clusterParam |? GroupType -eq VirtualMachine |? Name -like 'vm-*') + + # + # Limit estimate to VMs currently running? Allows for at-a-distance dynamic resizing of fleet (e.g., start + # a fraction, resize per-vm workingset so that they cover) + # Limit to a percentage of configured VMs? Not dependent on VMs being started yet. + # + + $VMs = $totalVMs = $vmGroups.Count + if ($VMs % $nodes.Count) + { + Write-Error "There are an uneven number of Fleet VMs: $VMs VMs for $($nodes.Count) nodes - please verify environment configuration" + return + } + elseif ($VMs -eq 0) + { + Write-Error "No Fleet VMs found - please verify environment configuration" + return + } + + if ($Running) + { + $vmGroups = @($vmGroups |? State -eq Online) + $VMs = $vmGroups.Count + + if ($VMs -eq 0) + { + Write-Error "No running Fleet VMs found - please verify environment configuration" + return + } + + LogOutput -IsVb "Estimate based on running VM count of $VMs of the $totalVMs total" + } + elseif ($PSBoundParameters.ContainsKey('VMPercent')) + { + # Note this is in absolute numbers of VMs. Round to an even number of VMs/node, and take 0 upward to 1/node. + $VMs = [int] ($VMPercent * $VMs / 100) + $VMs -= $VMs % $nodes.Count + if ($VMs -eq 0) { $VMs = $nodes.Count } + + LogOutput -IsVb "Estimate based on $VMs VMs, $VMPercent% of the $totalVMs total VMs (evenly distributed per node)" + } + else + { + LogOutput -IsVb "Estimate based on the $totalVMs total VMs" + } + } + else + { + $VMs *= $nodes.Count + } + + ## + # Generate estimates - one or two depending on call method + ## + + $cacheEst = $null + $capEst = $null + + # + # Truncate to the nearest 512MiB. Coerce the multiplier result back to uint64. + # + + $trunc = 512MB + if ($PSBoundParameters.ContainsKey('CachePercent') -and $cacheCapacity -ne 0) + { + $c = ([uint64]($CachePercent * $cacheCapacity)) / $VMs / 100 + $c -= $c % $trunc + + if ($c * $VMs -ge $availableCapacity) + { + Write-Warning "There is is not enough capacity to reach the specified percentage of cache capacity - please verify environment before proceeding. Truncating to available capacity." + + $c = $availableCapacity / $VMs + $c -= $c % $trunc + } + + $cacheEst = $c + } + + if ($PSBoundParameters.ContainsKey('CapacityPercent')) + { + $c = ([uint64]($CapacityPercent * $availableCapacity)) / $VMs / 100 + $c -= $c % $trunc + + $capEst = $c + } + + ## + # Pick higher (or lower) - $null is excluded automatically + ## + + if ($Higher) + { + $dataDiskCapacity = ($cacheEst, $capEst | Measure-Object -Maximum).Maximum + } + else + { + $dataDiskCapacity = ($cacheEst, $capEst | Measure-Object -Minimum).Minimum + } + + if ($null -ne $cacheEst) + { + LogOutput -IsVb ("Cache percentage of {0:P1} yielded {1:0.0}GiB/VM" -f ( + ($CachePercent/100), + ($cacheEst/1GB))) + } + + if ($null -ne $capEst) + { + LogOutput -IsVb ("Capacity percentage of {0:P1} yielded {1:0.0}GiB/VM" -f ( + ($CapacityPercent/100), + ($capEst/1GB))) + } + + if ($null -ne $cacheEst -and $null -ne $capEst) + { + if ($Higher) + { + LogOutput -IsVb "Chose HIGHER estimate" + } + else + { + LogOutput -IsVb "Chose LOWER estimate" + } + } + + ## + # Informational output + ## + + LogOutput -IsVb ("Estimated data disk is {0:0.0}GiB/VM " -f ( + ($dataDiskCapacity/1GB))) + LogOutput -IsVb ("Environment: {0} nodes, $VMs total VMs" -f ( + $nodes.Count)) + LogOutput -IsVb ("Available for data disks: {0:0.00}TiB ({1:P1}) of total {2:0.00}TiB volume capacity - {3:0.00}TiB is in use (OS disks, VM metadata, other content)" -f ( + ($availableCapacity/1TB), + ($availableCapacity/$totalVolumeCapacity), + ($totalVolumeCapacity/1TB), + (($totalVolumeCapacity - $availableCapacity)/1TB))) + + if ($cacheCapacity -ne 0) + { + LogOutput -IsVb ("Cache (v. Available): {0:0.00}TiB cache capacity, available volume capacity is {1:0.00}x cache, cache is {2:P1} of available)" -f ( + ($cacheCapacity/1TB), + ($availableCapacity/$cacheCapacity), + ($cacheCapacity/$availableCapacity))) + LogOutput -IsVb ("Cache (v. Total): {0:0.00}TiB cache capacity, total volume capacity is {1:0.00}x cache, cache is {2:P1} of total)" -f ( + ($cacheCapacity/1TB), + ($totalVolumeCapacity/$cacheCapacity), + ($cacheCapacity/$totalVolumeCapacity))) + } + + # Result is uint64 + return $dataDiskCapacity +} + +# a single named Variable with a set of values +class Variable { + + [int] $_ordinal + [object[]] $_list + [string] $_label + + Variable([string] $label, [object[]] $list) + { + $this._list = $list + $this._ordinal = 0 + $this._label = $label + } + + # current value of the Variable ("red"/"blue"/"green") + [object] value() + { + if ($null -ne $this._list -and $this._list.Count -gt 0) + { + return $this._list[$this._ordinal] + } + else + { + return $null + } + } + + # label/name of the Variable ("color") + [object] label() + { + return $this._label + } + + # increment to the next member, return whether a logical carry + # has occured (overflow) + [bool] increment() + { + # empty list passes through + if ($null -eq $this._list -or $this._list.Count -eq 0) + { + return $true + } + + # non-empty list, increment + $this._ordinal += 1 + if ($this._ordinal -eq $this._list.Count) + { + $this._ordinal = 0 + return $true + } + return $false + } + + # back to initial state + [void] reset() + { + $this._ordinal = 0 + } +} + +# a set of Variables which allows enumeration of their combinations +# this behaves as a numbering system indexing the respective Variables +# order is not specified +class VariableSet { + + [hashtable] $_set = @{} + + VariableSet([Variable[]] $list) + { + $list |% { $this._set[$_.label()] = $_ } + $this._set.Values |% { $_.reset() } + } + + # increment the enumeration + # returns true if the enumeration is complete + [bool] increment() + { + $carry = $false + foreach ($v in $this._set.Values) + { + # if the Variable returns the carry flag, increment + # the next, and so forth + $carry = $v.increment() + if (-not $carry) { break } + } + + # done if the most significant carried over + return $carry + } + + # enumerator of all Variables + [object] getset() + { + return $this._set.Values + } + + # return value of specific Variable + [object] get([string]$label) + { + return $this._set[$label].value() + } + + # return a label representing the current value of the set, following the input label template + # add a leading '-' to get a seperator + # use a leading '$' to eliminate repetition of label (just produce value) + [string] label([string[]] $template) + { + return $($template |% { + + $str = $_ + $pfx = '' + $done = $false + $norep = $false + do { + switch ($str[0]) + { + '-' { + $pfx = '-' + $str = $str.TrimStart('-') + } + '$' { + $norep = $true + $str = $str.TrimStart('$') + } + default { + $done = $true + } + } + } while (-not $done) + + $lookstr = $str + if ($norep) { + $str = '' + } + + # only produce labels for non-null, non-empty (as string) values + if ($this._set.Contains($lookstr) -and $null -ne $this._set[$lookstr].value()) + { + $vstr = [string] $this._set[$lookstr].value() + if ($vstr.Length) { "$pfx$str" + $vstr } + } + }) -join $null + } +} + +function GetDoneFlags +{ + [CmdletBinding()] + param( + [Parameter( + Mandatory = $true + )] + [string] + $DonePath, + + [Parameter( + Mandatory = $true + )] + [int] + $GoEpoch, + + [Parameter( + Mandatory = $true + )] + [Microsoft.FailoverClusters.PowerShell.ClusterGroup[]] + $VM, + + [Parameter()] + [double] + $Timeout = 120, + + [Parameter()] + [switch] + $AssertNone, + + [Parameter()] + [string] + $Tag = '' + ) + + # Hash of VMs to wait on. false indicates not done, true done. Prepopulate to filter flags. + $vmDone = @{} + foreach ($v in $VM) + { + $vmDone[$v.Name] = $false + } + + $done = 0 + $tries = 0 + $t0 = Get-Date + $t1 = $t2 = $null + $itdur = $totdur = New-TimeSpan -Seconds 0 + + $timedOut = $false + + do { + + if ($null -ne $t1) { + Start-Sleep 2 + } + + # increment attempts and capture start of the iteration + $tries += 1 + $t1 = Get-Date + + $doneFile = Get-ChildItem "$DonePath-*" + + foreach ($f in $doneFile) + { + # Now split the VM name from the flag file name (done-vm-xyz); ignore malformed, + # ones which are not in our expected set, and ones already done. + $names = $f.Name -split '-',2 + if ($names.Count -eq 2 -and + $vmDone.ContainsKey($names[1]) -and + $vmDone[$names[1]] -eq $false) + { + $thisDone = [int](Get-Content $f.FullName -ErrorAction SilentlyContinue) + if ($thisDone -eq $GoEpoch) { + + # if asserting that none should be complete, this is an error! + if ($AssertNone) { + LogOutput -ForegroundColor Red "ERROR: $($names[1]) is already done" + } + + $done += 1 + $vmDone[$names[1]] = $true + } + } + + $t2 = Get-Date + $itdur = $t2 - $t1 + $totdur = $t2 - $t0 + + if ((-not $timedOut) -and $Timeout -ne 0 -and $totdur.TotalSeconds -ge $Timeout) + { + $timedOut = $true + + # Detail - time out early for the assertion test so that we don't run the risk of + # this running past the total iteration time and being spoofed into failure by + # seeing actual completions. + # + # Normally these sweeps take O(1)s even for large numbers of VMs. + # + # In the completion test we want to finish the full sweep so we can provide + # the correct counts. + if ($AssertNone) + { + break + } + } + } + + # color status message per condition + if ($AssertNone -and $timedOut) { + $color = [System.ConsoleColor]::Yellow + $Tag = $Tag + " TIMED OUT " + } elseif (($AssertNone -and $done -ne 0) -or $done -ne $VM.Count) { + $color = [System.ConsoleColor]::Yellow + } else { + $color = [System.ConsoleColor]::Green + } + + LogOutput -ForegroundColor $color "$Tag CHECK $tries : $done/$($VM.Count) done " $('({0:F2}s, total {1:F2}s)' -f $itdur.TotalSeconds, $totdur.TotalSeconds) + + # loop if not asserting, not all vms are done, and still have timeout to use + } while ((-not $AssertNone) -and $done -ne $VM.Count -and (-not $timedOut)) + + # asserting that none should be complete? + if ($AssertNone) + { + # this is the right regardless of whether the check timed out + # timeout is not ideal but is also not failure + return ($done -eq 0) + } + + # return incomplete run failure + elseif ($done -ne $VM.Count) { + LogOutput -ForegroundColor Red ABORT: only received "$done/$($VM.Count)" completions in $tries attempts + + # log out VMs not done + $en = $vmDone.GetEnumerator() + while ($en.MoveNext()) + { + if ($en.Value -eq $false) { + LogOutput -ForegroundColor Yellow NOT DONE: $en.Key + } + } + + return $false + } + + # all worked! + return $true +} + +function ClearDoneFlags +{ + [CmdletBinding()] + param( + [Parameter( + Mandatory = $true + )] + [string] + $DonePath + ) + + Get-ChildItem "$DonePath-*" | Remove-Item -Force +} + +function GetProfileDuration +{ + [CmdletBinding()] + param( + [Parameter( + ParameterSetName = "ByProfilePath", + Mandatory = $true + )] + [string] + $ProfilePath, + + [Parameter( + ParameterSetName = "ByProfileXML", + Mandatory = $true + )] + [xml] + $ProfileXml, + + [switch] + $Total, + + [switch] + $Warmup, + + [switch] + $Duration, + + [switch] + $Cooldown + ) + + if ($PSCmdlet.ParameterSetName -eq "ByProfilePath") + { + $ProfileXml = [xml] (Get-Content $ProfilePath) + } + + if ($null -eq $ProfileXml) + { + Write-Error "XML profile not readable" + return + } + + $timeSpans = $ProfileXml.SelectNodes("Profile/TimeSpans/TimeSpan") + + if ($null -eq $timeSpans) + { + Write-Error "XML Profile does not contain TimeSpan elements - verify this is a profile" + return + } + + $w = $d = $c = 0 + $timeSpans |% { + if ($_.Item("Warmup")) { $w += [int] $_.Warmup } + if ($_.Item("Duration")) { $d += [int] $_.Duration } + if ($_.Item("Cooldown")) { $c += [int] $_.Cooldown } + } + + if ($PSBoundParameters.ContainsKey('Total')) + { + return $w + $d + $c + } + + if ($PSBoundParameters.ContainsKey('Warmup')) { $w } + if ($PSBoundParameters.ContainsKey('Duration')) { $d } + if ($PSBoundParameters.ContainsKey('Cooldown')) { $c } +} + +function Clear-FleetRunState +{ + [CmdletBinding()] + param( + [Parameter()] + [string] + $Cluster = "." + ) + + ############# + $clusterParam = @{} + CopyKeyIf $PSBoundParameters $clusterParam 'Cluster' + + # Go/Done Paths + ($goPath, $donePath) = Get-FleetPath -PathType Go,Done @clusterParam + + # Scrub, reset go counter to zero + Get-ChildItem "$donePath-*" | Remove-Item -Force + Write-Output 0 > $goPath +} + +function Create-TemplateRunScript +{ + [CmdletBinding()] + param( + [string] + $AddSpec = "", + + [string] + $controlPath, + + [string] + $RunFile = "sweep.ps1", + + [string] + $RunProfileFile = "sweep.xml" + ) + + # Pause for SMB dir/info cache to expire and surface go flag. + # Runner will wait for new content - note unique guid. + Start-Sleep $smbInfoCacheLifetime + + $vmprof = "L:\control\$RunProfileFile" + $guid = [System.Guid]::NewGuid().Guid + + $f = Join-Path $controlPath $RunFile + $(Get-Command Set-RunProfileTemplateScript).ScriptBlock |% { + + # apply subsitutions to produce a new run file + $line = $_ + $line = $line -replace '__AddSpec__',$AddSpec + $line = $line -replace '__Profile__',$vmprof + $line = $line -replace '__Unique__',$guid + $line + + } | Out-File "$($f).tmp" -Encoding ascii -Width ([int32]::MaxValue) + if (Test-Path $f) { Remove-Item $f -Force } + Rename-Item "$($f).tmp" $RunFile +} + +function Start-FleetRun +{ + [CmdletBinding()] + param( + [Parameter()] + [string] + $Cluster = ".", + + [Parameter()] + [string] + $AddSpec = "", + + [Parameter( + ParameterSetName = "ByProfilePath", + Mandatory = $true + )] + [string] + $ProfilePath, + + [Parameter( + ParameterSetName = "ByProfileXml", + Mandatory = $true + )] + [xml] + $ProfileXml, + + [Parameter(ParameterSetName = "ByProfilePath")] + [Parameter(ParameterSetName = "ByProfileXml")] + [string] + $RunFile = "sweep.ps1", + + [Parameter(ParameterSetName = "ByProfilePath")] + [Parameter(ParameterSetName = "ByProfileXml")] + [string] + $RunProfileFile = "sweep.xml", + + [Parameter( + ParameterSetName = "ByPrePlaced", + Mandatory = $true + )] + [switch] + $PrePlaced, + + [Parameter( + ParameterSetName = "ByPrePlaced", + Mandatory = $true + )] + [int] + $Duration, + + [Parameter()] + [switch] + $Async, + + [Parameter()] + [string[]] + $pc = $null, + + [Parameter()] + [ValidateRange(1,60)] + [int] + $SampleInterval = 1 + ) + + # + # Core utility to put a given single run/iteration into the fleet with the + # go/done response mechanism. + # + # * ByPrePlaced - a pre-placed run script (*.ps1) is assumed, and the expected + # duration must be provded. + # * ByProfilePath - a pre-placed DISKSPD profile is specified. A template run + # script is emitted to run. + # + + ############# + $clusterParam = @{} + CopyKeyIf $PSBoundParameters $clusterParam 'Cluster' + + # Async is not compatible with performance counter capture. Consider supporting fully external management + # of async runs (including logman/done flag checks) for future. + if ($PSBoundParameters.ContainsKey('pc') -and $Async) + { + Write-Error "Performance counter captures (pc) cannot be done for Async runs" + return + } + + # Paths including node-local CSV path to results (for blg drop) + ($controlPath, $goPath, $donePath) = Get-FleetPath -PathType Control,Go,Done @clusterParam + $resultPathLocal = Get-FleetPath -PathType Result -Local @clusterParam + + # Get expected run duration in the implicit cases + switch ($psCmdlet.ParameterSetName) + { + "ByPrePlaced" { break } + "ByProfileXml" + { + $Duration = GetProfileDuration -ProfileXml $ProfileXml -Total + } + "ByProfilePath" + { + $Duration = GetProfileDuration -ProfilePath $ProfilePath -Total + } + } + + if ($null -eq $Duration -or $Duration -eq 0) + { + Write-Error "Run duration could not be determined, cannot continue" + return + } + + # Place profile in the control area? + switch ($psCmdlet.ParameterSetName) + { + "ByPrePlaced" + { + # Pause for SMB dir/info cache to expire and surface preplaced file. + # Dropping go flag will release the run. + Start-Sleep $smbInfoCacheLifetime + break + } + "ByProfileXml" + { + $runProfileFilePath = Join-Path $controlPath $RunProfileFile + Remove-Item $runProfileFilePath -Force -ErrorAction SilentlyContinue + $ProfileXml | Convert-FleetXmlToString | Out-File $runProfileFilePath -Encoding ascii -Width ([int32]::MaxValue) -Force + } + "ByProfilePath" + { + $runProfileFilePath = Join-Path $controlPath $RunProfileFile + Remove-Item $runProfileFilePath -Force -ErrorAction SilentlyContinue + Copy-Item $ProfilePath $runProfileFilePath -Force + } + } + + # Get nodes for performance counter capture (if needed) + if ($null -ne $pc) + { + $nodes = Get-ClusterNode @clusterParam |? State -eq Up | Sort-Object -Property Name + } + + # VMs expected to participate + $vms = @(Get-ClusterGroup @clusterParam |? GroupType -eq VirtualMachine |? Name -like "vm-*" |? State -eq Online) + + if (Get-FleetPause @clusterParam) + { + $clearPause = $true + } + else + { + $clearPause = $false + } + + # Kick off go iteration + $goepoch = [int](Get-Content $goPath -ErrorAction SilentlyContinue) + $goepoch += 1 + + LogOutput "START Go Epoch: $goepoch" + Write-Output $goepoch > $goPath + + # Create templated run script to inject this profile? + if ($psCmdlet.ParameterSetName -ne "ByPrePlaced") + { + Create-TemplateRunScript $AddSpec $controlPath $RunFile $RunProfileFile + } + + # capture time zero + $t0 = get-date + + # release pause + if ($clearPause) + { + LogOutput "CLEAR pause at Go" + Clear-FleetPause @clusterParam + } + + # arm flag to guarantee teardown of logman instances on exception + $stopLogman = $false + + try + { + # start performance counter capture + if ($null -ne $pc) + { + StartLogman -Computer $nodes -Name $AddSpec -Counters $pc -SampleInterval $SampleInterval + $stopLogman = $true + } + + ###### + + # If total run is more than ffMin seconds, sleep to ffCheckAt and look for false completions + # for up to ffCheckWindow seconds. Controlling the check duration is important in case it + # takes an unexpectedly long time to go through the done flags, regardless of reason. + + $fastFailMin = 60 + $fastFailCheckAt = 20 + $fastFailCheckWindow = 15 + + if ($Duration -gt $fastFailMin) + { + # Account for time taken to this point (logman/clear) to arrive at the check time + $td = (Get-Date) - $t0 + $remainingSleep = $fastFailCheckAt - $td.TotalSeconds + + if ($remainingSleep -gt 0) + { + LogOutput SLEEP TO RUN CHECK "($('{0:0.00}' -f $remainingSleep) seconds)" + Start-Sleep -Milliseconds ($remainingSleep*1000) + $td = (Get-Date) - $t0 + } + + LogOutput RUN CHECK Go Epoch: $goepoch + + # Calculate effective time to check flags: how far into the timeout interval + # are we already. Note that this may wind up missing early completion if the run + # is very short. TBD positive successful completion ack as opposed to job completion. + $fastFailCheckTimeout = $fastFailCheckWindow - ($td.TotalSeconds - $fastFailCheckAt) + + if ($fastFailCheckTimeout -gt 0) + { + if (-not (GetDoneFlags -DonePath $donePath -GoEpoch $goepoch -VM $vms -AssertNone -Tag 'RUN' -Timeout $fastFailCheckTimeout)) + { + throw "Unexpected early completion of load, please check profile and virtual machines for errors" + } + } + LogOutput -ForegroundColor green RUN CHECK PASS Go Epoch: $goepoch + } + + # If this is an async run, done here. + # Consider exposing logman and done flag check for fully external async management of runs. + if ($Async) + { + return + } + + # Sleep for the remaining interval + $td = (Get-Date) - $t0 + $remainingsleep = $Duration - $td.TotalSeconds + + if ($remainingsleep -gt 0) + { + LogOutput SLEEP TO END "($('{0:0.00}' -f $remainingsleep) seconds)" + Start-Sleep -Milliseconds ($remainingsleep*1000) + } + + # Stop performance counter capture + # Do this before polling done flags, which can take time + if ($stopLogman) + { + StopLogman -Computer $nodes -Name $AddSpec -Path $resultPathLocal + $stopLogman = $false + } + + if (-not (GetDoneFlags -DonePath $donePath -GoEpoch $goepoch -VM $vms -Tag COMPLETION)) + { + throw "Load did not fully complete, please check profile and virtual machines for errors" + } + } + catch + { + # Pause fleet under error conditions + + Set-FleetPause + throw + } + finally + { + # Stop and abandon capture if normal termination did not occur (do not pull blg back) + if ($stopLogman) + { + StopLogman -Computer $nodes -Name $AddSpec + } + + if (-not $Async) + { + # Work around two issues for callers: + # + # * conflicting handles on the XML result files (sleep) + # * delegated xcopy in StopLogman appears to leave references that + # hold up access to BLG until the CSV is bounced. + # + # TBD track these down. Overlap the 20s wait for XML handles with the CSV move. + # + # Async runs will need to manage this (if needed) directly if/when full external + # management is supported. + + $t0 = Get-Date + $null = Get-ClusterSharedVolume @clusterParam |? Name -match $collectVolumeName | Move-ClusterSharedVolume + + $td = (Get-Date) - $t0 + $tms = 20*1000 - $td.TotalMilliseconds + if ($tms -gt 0) + { + Start-Sleep -Milliseconds $tms + } + } + } +} + +function Start-FleetSweep +{ + [CmdletBinding()] + param( + [Parameter()] + [string] + $Cluster = ".", + + [Parameter()] + [string] + $AddSpec, + + [Parameter()] + [string] + $RunTemplate, + + [Parameter()] + [string] + $RunFile = "sweep.ps1", + + [Parameter()] + [string[]] + $LabelTemplate = @('b','t','o','w','p','iops','-$addspec'), + + [Parameter(Mandatory =$true)] + [int[]] + $b, + + [Parameter(Mandatory =$true)] + [int[]] + $t, + + [Parameter(Mandatory =$true)] + [int[]] + $o, + + [Parameter(Mandatory =$true)] + [int[]] + $w, + + [Parameter()] + [ValidateSet('r','s','si')] + [string[]] + $p = 'r', + + [Parameter()] + [int[]] + $iops = $null, + + [Parameter()] + [ValidateRange(1,[int]::MaxValue)] + [int] + $d = 30, + + [Parameter()] + [ValidateRange(0,[int]::MaxValue)] + [int] + $Warm = 60, + + [Parameter()] + [ValidateRange(0,[int]::MaxValue)] + [int] + $Cool = 30, + + [Parameter()] + [string[]] + $pc = $null, + + [Parameter()] + [ValidateRange(1,60)] + [int] + $SampleInterval = 1 + ) + + ############# + $clusterParam = @{} + CopyKeyIf $PSBoundParameters $clusterParam 'Cluster' + + # Paths including node-local CSV path to results (for blg drop) + ($controlPath, $goPath, $donePath) = Get-FleetPath -PathType Control,Go,Done @clusterParam + + # Convert RunFile to fully qualified. Any type of non-plain filename is not allowed: this will + # always be placed in the control path. + if ($RunFile.Contains('\')) + { + Write-Error "$RunFile must be a plain filename, to be created in the control path ($controlPath)" + return + } + $RunFilePath = Join-Path $controlPath $RunFile + + function NewRunFile + { + param( + [VariableSet] + $vs, + + [string] + $runtemplate + ) + + $guid = [System.Guid]::NewGuid().Guid + + # Use template script if offered, else builtin + $(if ($runtemplate.Length -gt 0) + { + Get-Content $runtemplate + } + else + { + (Get-Command Set-SweepTemplateScript).ScriptBlock + }) |% { + + # apply current subsitutions to produce a new run file + + $line = $_ + + foreach ($v in $vs.getset()) { + # non-null goes in as is, null goes in as evaluatable $null + if ($null -ne $v.value()) { + $vsub = $v.value() + } else { + $vsub = '$null' + } + $line = $line -replace "__$($v.label())__",$vsub + } + + $line = $line -replace '__Unique__',$guid + $line + + } | Out-File "$($RunFilePath).tmp" -Encoding ascii -Width ([int32]::MaxValue) + if (Test-Path $RunFilePath) { Remove-Item $RunFilePath -Force } + Rename-Item "$($RunFilePath).tmp" $RunFile + } + + function ShowRun( + [VariableSet] $vs + ) + { + # show current substitions (minus the underscore bracketing) + LogOutput -ForegroundColor green RUN PARAMETERS + foreach ($v in $vs.getset()) { + if ($null -ne $v.value()) { + $vsub = $v.value() + } else { + $vsub = '$null' + } + LogOutput -ForegroundColor green "`t$($v.label()) = $($vsub)" + } + } + + function GetRunDuration( + [VariableSet] $vs + ) + { + $vs.get('d') + $vs.get('Warm') + $vs.get('Cool') + } + + ############# + + # Start paused so that when run state is cleared VMs do not enter free run + # and begin executing the first run file for this sweep pass. + Set-FleetPause @clusterParam + Clear-FleetRunState @clusterParam + + # construct the Variable list describing the sweep + + ############################ + ############################ + ## Modify from here down + ############################ + ############################ + + # add any additional sweep parameters here to match those specified on the command line + # ensure your sweep template script contains substitutable elements for each + # + # __somename__ + # + # bracketed by two underscore characters. Consider adding your new parameters to + # the label template so that result files are well-named and distinguishable. + + $v = @() + $v += [Variable]::new('b',$b) + $v += [Variable]::new('t',$t) + $v += [Variable]::new('o',$o) + $v += [Variable]::new('w',$w) + $v += [Variable]::new('p',$p) + $v += [Variable]::new('iops',$iops) + $v += [Variable]::new('d',$d) + $v += [Variable]::new('Warm',$warm) + $v += [Variable]::new('Cool',$cool) + $v += [Variable]::new('AddSpec',$addspec) + + $sweep = [VariableSet]::new($v) + + try + { + do + { + Write-Host -ForegroundColor Cyan ('-'*20) + + ShowRun $sweep + NewRunFile $sweep $RunTemplate + + Start-FleetRun -PrePlaced @clusterParam -AddSpec ($sweep.label($LabelTemplate)) -Duration (GetRunDuration $sweep) -pc $pc -SampleInterval $SampleInterval -ErrorVariable e + + if ($e.Count) + { + return + } + + } while (-not $sweep.increment()) + } + finally + { + # Set pause to quiesce the system. + # Remove the sweep runfile. + if (-not (Get-FleetPause)) + { + Set-FleetPause @clusterParam + } + + if (Test-Path $RunFilePath) + { + Remove-Item $RunFilePath -Force + } + } +} + +function Start-FleetWriteWarmup +{ + [CmdletBinding()] + param( + [Parameter()] + [string] + $Cluster = '.', + + [Parameter(Mandatory = $true)] + [uint64] + $VMWorkingSetSize + ) + + $nodes = Get-ClusterNode -Cluster $Cluster |? State -eq Up + + $vm = @(Get-FleetVM -Cluster $Cluster |? State -eq Ok) + if ($vm.Count -eq 0) + { + throw 'No running VMs found' + } + + # Write warmup is a sequential workingset rewrite. One example of similar issues addressed in public + # specification is in the SNIA Solid State Performance Test Specification's "Workload Independent + # Pre-Conditioning" (see v 2.0.2 sec 3.3 and references throughout). Although VM Fleet is operating + # at an aggregate level, the same princple applies the the virtual storage stack. + # + # In general VM Fleet will avoid most known reasons to need to do this, at least for the sake of + # its current goal of measuring conditions in long-term running state: it does not use block cloning + # or leave workingsets in sparse states (currently), for instance. + # + # However, a major reason for VM Fleet to handle this is on parity volumes: Spaces tracks whether parity + # stripes have been written so that it can calculate parity incrementally v. requiring a full stripe + # read/write. The tracking for this also allows the read path to optimize away the reads, similar to + # sparse/valid data length management. If portions of the workingset wind up being initially allocated + # v. parity storage, reads to that content would be optimized away until a write workload came in and + # hit it. While certainly an interesting condition to evaluate, it is indeed a distinct and shorter term + # operating condition. + + LogOutput "WRITE WARMUP: START" + + # + # Now warm up. Build a write profile with one thread of sequential IO. + # + + $t0 = $null + $warmupRun = 3600 * 24 * 7 + $blockSize = 128KB + + $dynamicProfile = Get-FleetProfileXml -Name Peak -ThreadsPerTarget 1 -WriteRatio 100 -BlockSize $blockSize -Alignment $blockSize -RequestCount 8 -Sequential -Duration $warmupRun + + $t0 = Get-Date + Start-FleetRun -ProfileXml $dynamicProfile -Async + + $pc = @('\Cluster CSVFS(_Total)\Write Bytes/sec', + '\Cluster Storage Hybrid Disks(_Total)\Disk Write Bytes/sec' + ) + + $sampleInterval = 15 + + # Track total CSV write bytes to enforce minimum traversal of the logical workingset. + # The physical workingset traversal (and disk write bytes) are informative, only. + $totalws = $vm.Count * $VMWorkingSetSize + $totalwb = [uint64] 0 + + # Traverse 2.2x since we don't have direct visibility into each VM's progress + $traversews = 2.2 * $totalws + + LogOutput ("WRITE WARMUP: $($vm.Count) VMs @ {0:0.00}GiB/VM => {1:0.00}TiB total workingset to traverse" -f ( + ($VMWorkingSetSize/1GB), + ($traversews/1TB))) + + try + { + do + { + # Aggregate samples across the cluster - note that all counters are currently unique + # by counter name, just use that. + $samples = Get-Counter $pc -ComputerName $nodes -SampleInterval $sampleInterval + $samplesAgg = @{} + $samples.CounterSamples |% { + + # Counter name is fifth element when split by seperator: \\machine\set(instance)\ctr + $ctr = ($_.Path -split '\\')[4] + if ($samplesAgg.ContainsKey($ctr)) + { + $samplesAgg.$ctr += $_.CookedValue + } + else + { + $samplesAgg.$ctr = $_.CookedValue + } + } + + $csvwb = [uint64] ($samplesAgg."Write Bytes/sec") + $dwb = [uint64] ($samplesAgg."Disk Write Bytes/sec") + + $totalwb += $csvwb * $sampleInterval + + LogOutput ("Write rate: {0:0.00}GiB/s, total {1:0.00}TiB {2:P1} complete (physical: {3:0.00}GiB/s, {4:0.0}x amplification)" -f ( + ($csvwb/1GB), + ($totalwb/1TB), + ($totalwb/$traversews), + ($dwb/1GB), + ($dwb/$csvwb))) + + } while ($traversews -gt $totalwb) + } + finally + { + # Halt the warmup (throw/normal completion) + Set-FleetPause + } + + $td = (Get-Date) - $t0 + LogOutput "WRITE WARMUP COMPLETE: took $(TimespanToString $td)" +} + +function Start-FleetReadCacheWarmup +{ + [CmdletBinding()] + param( + [Parameter()] + [string] + $Cluster = '.', + + [Parameter(Mandatory = $true)] + [xml] + $ProfileXml, + + [Parameter(Mandatory = $true)] + [uint64] + $VMWorkingSetSize + ) + + $sess = New-CimSession -ComputerName $Cluster + $s2d = Get-ClusterS2D -CimSession $sess + $nodes = Get-ClusterNode -Cluster $Cluster |? State -eq Up + + # Cache disabled is normal for flat configurations, no read warmup. + if ($s2d.CacheState -ne 'Enabled') + { + LogOutput "READ CACHE WARMUP: cache not enabled, no warmup to perform" + return + } + + # Get read workingset of the profile - if there is none, there is no warmup. + # More than one named target is unsupported for now. + $readWorkingSet = GetFleetProfileFootprint -ProfileXml $ProfileXml -Read + if ($readWorkingSet.Count -eq 0) + { + LogOutput "READ CACHE WARMUP: profile does not define a read workingset, no warmup to perform" + return + } + if ($readWorkingSet.Count -gt 1) + { + throw "Read Cache Warmup does not currently support more than one target/profile ($($readWorkingset.Count) found)" + } + + $pool = @(Get-StorageSubsystem -CimSession $sess |? AutomaticClusteringEnabled | Get-StoragePool |? IsPrimordial -eq $false) + $poold = @($pool | Get-PhysicalDisk -CimSession $sess) + + # Compare capacity devices against cache mode - any operating with read cache require warmup + $capg = @($poold |? Usage -ne Journal | Group-Object -NoElement -Property MediaType) + $cached = @($poold |? Usage -eq Journal) + + # Although an administrator is encouraged to bring up a flat configuration with CacheState = Disabled, + # it is not required. Assume this is as-intended. + if ($cached.Count -eq 0) + { + LogOutput "READ CACHE WARMUP: no cache devices in cache-ready configuration, no warmup to perform" + return + } + + if ($capg.Count) + { + $reasons = 0 + foreach ($type in $capg.Name) + { + switch ($type) + { + 'HDD' { if ($s2d.CacheModeHDD -ne 'WriteOnly') { $reasons += 1 }} + 'SSD' { if ($s2d.CacheModeSSD -ne 'WriteOnly') { $reasons += 1 }} + } + } + + if ($reasons -eq 0) + { + LogOutput "READ CACHE WARMUP: capacity devices are not caching reads, no warmup to perform" + return + } + } + else + { + return + } + + $vm = @(Get-FleetVM -Cluster $Cluster |? State -eq Ok) + if ($vm.Count -eq 0) + { + throw 'No running VMs found' + } + + # Now reason about total cache capacity and the profile's read workingset footprint across the running VMs. + # + # Produce a warmup profile covering up to 60% of the cache on that footprint. In cache rich environments + # this may span the entire fleet disk capacity. Example: + # + # * 10 TiB cache capacity -> 6 TiB potential warmup + # * 48 VMs -> ~128 GiB potential warmup/VM + # * data disk of 512 GiB + # * profile's read IO base of 5 GiB -> 100% span -> 507GiB read workingset + # * => generate warmup profile with IO base of 5 GiB -> max of 133 GiB (128 GiB total warmup) + + $warmPct = 0.6 + $cacheCapacity = ($cached | Measure-Object -Property AllocatedSize -Sum).Sum + $cacheCapacityVM = $warmPct * $cacheCapacity / $vm.Count + + LogOutput "READ CACHE WARMUP: START" + LogOutput -IsVb ("$($cached.Count) cache devices totaling {0:0.00} TiB capacity" -f ($cacheCapacity/1TB)) + LogOutput -IsVb ("$($vm.Count) VMs => {0:0.00} GiB cache available per VM (at {1:P1} target of total)" -f + (($cacheCapacityVM/1GB), + $warmPct)) + + $readBase = $readWorkingSet.Values.BaseOffset + $readMax = $readWorkingSet.Values.MaxOffset + if ($readMax -eq 0) + { + $readMax = $VMWorkingSetSize + } + + LogOutput -IsVb ("Profile read range: [{0:0.00}GiB - {1:0.00}GiB] ({2:0.00}GiB total) of total {3:0.00}GiB VM workingset" -f + (($readBase/1GB), + ($readMax/1GB), + (($readMax - $readBase)/1GB), + ($VMWorkingSetSize/1GB))) + + if (($readMax - $readBase) -gt $cacheCapacityVM) + { + $readMax = $readBase + $cacheCapacityVM + LogOutput -IsVb ("Limit to warmable: [{0:0.00}GiB - {1:0.00}GiB] ({2:0.00}GiB total)" -f + (($readBase/1GB), + ($readMax/1GB), + (($readMax - $readBase)/1GB))) + } + else + { + LogOutput -IsVb "Full range warmable" + } + + # + # Now warm up. Build read profile with two threads, each thread warming half of the target: one on even numbered + # blocks and one on odd via one thread starting at ThreadStride 1/2 way around the target + blocksize. + # This sidesteps sequential IO detection. Blocksize must be small enough to meet cache criteria even when L1 + # age is under threshold goal (just > ~1 day). + # + # Time is a placeholder; in practice, the run will be failed if we loop the workingset more times than expected + # without converging. An explicitly indefinite runtime would be preferable. + # + + $t0 = $null + $warmupRun = 3600 * 24 * 7 + $blockSize = 56KB + + # Now align the base/max to our warmup block size. The difference between this and the actual range is not material + # at the scale of GiB of workingset; if this assumption does not hold it could be reasonable to autoscale the blocksize + # to better fit the (assumedly very small) workingset size. Base up, max down. + + $readBaseAligned = $readBase + $blockSize - 1 + $readBaseAligned -= $readBaseAligned % $blockSize + $readMaxAligned = $readMax - ($readMax % $blockSize) + + $threadStride = $blockSize + $blockSize*([uint64](($readMaxAligned - $readBaseAligned)/$blockSize))/2 + + # Too small? + if ($readMaxAligned -le $readBaseAligned -or + $threadStride -le $readBaseAligned -or + $threadStride -ge $readMaxAligned) + { + LogOutput "READ CACHE WARMUP COMPLETE: minimal workingset" + return + } + + $dynamicProfile = Get-FleetProfileXml -Name Peak -BaseOffset $readBaseAligned -MaxOffset $readMaxAligned -ThreadsPerTarget 2 -WriteRatio 0 -BlockSize $blockSize -Alignment ($blockSize*2) -ThreadStride $threadStride -RequestCount 8 -Sequential -Duration $warmupRun + + try + { + # Trigger temporary change to cache on first read miss, avoiding time which might be + # required to pass the cache aging and multiple-hit requirements, among others. + # Sink warnings (2019 does not support this). + SetCacheBehavior -Cluster $Cluster -PopulateOnFirstMiss 3>$null + + $t0 = Get-Date + Start-FleetRun -ProfileXml $dynamicProfile -Async + + $pc = @('\Cluster Storage Hybrid Disks(_Total)\Cache Hit Reads/sec', + '\Cluster Storage Hybrid Disks(_Total)\Cache Miss Reads/sec', + '\Cluster Storage Hybrid Disks(_Total)\Cache Populate Bytes/sec', + '\Cluster Storage Hybrid Disks(_Total)\Disk Reads/sec', + '\Cluster Storage Hybrid Disks(_Total)\Disk Read Bytes/sec' + ) + + $sampleInterval = 15 + + # Track total disk read bytes to enforce minimum traversal of the working set + # after reaching potential completion criteria. + $totalws = $vm.Count * ($readMax - $readBase) + $pendingCompletion = $false + $completeMsg = $null + + $totaldrb = [uint64] 0 + $completedrb = [uint64] 0 + $anyWarmup = $false + + # AtComp/MinMax workingset traversals + # + # * make AtComp traverses once completion condition triggers + # * make at least Min traverses if any warmup begins (any step sees non-completion) + # * make at most Max traverses, then flag inability to complete + # + # Note AtComp takes precedence over Min if completion triggers on the first step. This + # allows fast(est) verification of an already warmed system. + + $traverseAtComp = 1.2 * $totalws + $traverseMin = 2.0 * $totalws + $traverseMax = 20.0 * $totalws + + LogOutput ("READ CACHE WARMUP: $($vm.Count) VMs @ {0:0.00}GiB/VM => {1:0.00}TiB total workingset" -f ( + (($readMax - $readBase)/1GB), + ($totalws/1TB))) + + do + { + # Aggregate samples across the cluster - note that all counters are currently unique + # by counter name, just use that. + $samples = Get-Counter $pc -ComputerName $nodes -SampleInterval $sampleInterval + $samplesAgg = @{} + $samples.CounterSamples |% { + + # Counter name is fifth element when split by seperator: \\machine\set(instance)\ctr + $ctr = ($_.Path -split '\\')[4] + if ($samplesAgg.ContainsKey($ctr)) + { + $samplesAgg.$ctr += $_.CookedValue + } + else + { + $samplesAgg.$ctr = $_.CookedValue + } + } + + $cpb = $samplesAgg."Cache Populate Bytes/sec" + $chr = $samplesAgg."Cache Hit Reads/sec" + $cmr = $samplesAgg."Cache Miss Reads/sec" + $dr = $samplesAgg."Disk Reads/sec" + $drbt = [uint64] ($samplesAgg."Disk Read Bytes/sec" * $sampleInterval) + + if ($pendingCompletion) + { + $completedrb += $drbt + } + $totaldrb += $drbt + $wsMsg = $null + + # Miss rate hitting near actual zero? + if ([int][math]::Floor($cmr) -eq 0) + { + if (-not $pendingCompletion) + { + LogOutput "PENDING COMPLETION: reached zero cache miss rate" + $pendingCompletion = $true + } + elseif ($completedrb -gt $traverseAtComp -and + ($anyWarmup -eq $false -or $totaldrb -gt $traverseMin)) + { + $completeMsg = ("reached zero cache miss rate at {0:0.00}TiB ws traversal" -f ( + ($totaldrb/1TB))) + break + } + } + # Sustaining hit:miss ratio > 100 for an entire traversal + elseif ($chr/$cmr -gt 100) + { + if (-not $pendingCompletion) + { + LogOutput "PENDING COMPLETION: hit:miss ratio > 100" + $pendingCompletion = $true + } + elseif ($completedrb -gt $traverseAtComp -and + ($anyWarmup -eq $false -or $totaldrb -gt $traverseMin)) + { + $completeMsg = ("hit:miss ratio > 100 at {0:0.00}TiB ws traversal" -f ( + ($totaldrb/1TB))) + break + } + } + elseif ($pendingCompletion) + { + # Not meeting criteria. Reset fuse. + $completedrb = [uint64] 0 + $pendingCompletion = $false + $wsMsg = ', resetting completion checks due to high miss rate' + + $anyWarmup = $true + } + + # Inform workingset state + if ($null -eq $wsMsg) + { + if ($pendingCompletion) + { + $m = $null + $toGo = 0 + $compToGo = 0 + $minToGo = 0 + if ($traverseAtComp -ge $completedrb) { $compToGo = $traverseAtComp - $completedrb } + if ($traverseMin -ge $totaldrb) { $minToGo = $traverseMin - $totaldrb } + + # Per completion condition, min must be satisfied if any warmup condition occured. + # Note whether this is in play or not for diagnostics (fast completion). + if ($anyWarmup) + { + if ($minToGo -gt $compToGo) { $toGo = $minToGo } else { $toGo = $compToGo } + } + else + { + $toGo = $compToGo + $m = ' (minimal warmup)' + } + $wsMsg = (", {0:0.00}TiB to complete ws traversal$m" -f (($toGo)/1TB)) + } + else + { + $wsMsg = (', {0:0.00}TiB ws traversed' -f ($totaldrb/1TB)) + } + } + + LogOutput ("Read IOPS: hit {0:N0} miss {1:N0} => {2:N0} total (populate @ {3:0.0} MiB/s$wsMsg)" -f + ($chr, $cmr, $dr, ($cpb/1MB))) + + # If warmup has traversed the maximum and completion is not triggered, give up - something must have + # gone wrong with the cachable workingset estimation. + if ($totaldrb -gt $traverseMax -and -not $pendingCompletion) + { + throw "FAIL: read cache warmup has not converged" + } + + } while ($true) + } + finally + { + # Halt the warmup (throw/normal completion) + Set-FleetPause + + # Clear cache behavior change + # Sink warnings (2019 does not support this). + SetCacheBehavior -Cluster $Cluster -PopulateOnFirstMiss:$false 3>$null + } + + $td = (Get-Date) - $t0 + LogOutput "READ CACHE WARMUP COMPLETE: $completeMsg, took $(TimespanToString $td)" +} + +function Get-PerformanceCounter +{ + [CmdletBinding()] + param( + [Parameter( + Mandatory = $true + )] + [System.IO.FileInfo] + $Blg, + + [Parameter( + Mandatory = $true + )] + [int] + $Warmup, + + [Parameter( + Mandatory = $true + )] + [int] + $Duration, + + [Parameter()] + [switch] + $SumProduct, + + [Parameter( + Mandatory = $true + )] + [string[]] + $Ctrs + ) + + # import, extending the counter names with the required computername wildcard + # swallow all errors - we'll handle per-sample/countersample issues individually as long as we get data + $sample = @(Import-Counter -Path $Blg -Counter ($Ctrs |% { "\\*\$_" }) -ErrorAction SilentlyContinue -ErrorVariable e) + + # if we got nothing, something fatal has occured; throw the first error received + if (-not $sample.Count) + { + throw $e[0] + } + + # !sumproduct: return average of individual counters, multiple values + # sumproduct : return average of sumproduct of counters, single value + # + # The result of each branch is that we have an list of lists (one or more) + # which are then individually averaged into the output. In matrix terms, + # this is transposing the list from time-major order (the samples) to + # counter-major order. + + $nctr = $nresult = $sample[0].CounterSamples.Count + if ($SumProduct) + { + $nresult = 1 + } + + # vector of counter vectors - all empty to start + $result = [object[]]::new($nresult) + $result = ,@() * $nresult + + # vector of running counts of good samples to track baseline status (i.e., is it valid) + # all imported relative counters are invalid until the *second* status = 0 sample present in the + # stream. as a result all start off invalid. on sample failure, they go invalid again. + # + # all counters must be good to produce a sumproduct sample + + $ngood = @(0) * $nctr + + # check individual counter status + + $t0 = $null + foreach ($s in $sample) + { + # number of counters that don't have usable values this sample + # " with bad data + # these are different states - the first sample with valid data + # for a relative counter is not usable since its delta cannot + # be computed yet; this is why we have to wait for the second + $skip = 0 + $nbad = 0 + + # Pass 1 - check individual counter status + for ($i = 0; $i -lt $s.CounterSamples.Count; $i++) + { + # save status based on this sample ... + if ($s.CounterSamples[$i].Status -ne 0) + { + # ... bad, skip + # in practice we expect all to be PDH_INVALID_DATA = c0000bc6 + $ngood[$i] = 0 + $skip++ + $nbad++ + } + elseif (-not $ngood[$i]) + { + # ... now good, next will be ok + $ngood[$i] = 1 + $skip++ + } + else + { + # ... baselined, good + $ngood[$i]++ + } + } + + # entire row bad? + # detail: import-counter returns current time if all counters are bad (!) + # so we have to completely drop the sample + if ($nbad -eq $s.CounterSamples.Count) + { + continue + } + + # save time zero from the first valid sample + if ($null -eq $t0) + { + $t0 = $s.Timestamp + } + + # figure out how far into the sample this is - done? skip warmup? + # note that sample/counter validity is why its easier to roll through + # all rows to know when the first sample of interest is in hand. timestamp + # jitter and drops make things more complicated than simply indexing. + $td = ($s.Timestamp - $t0).TotalSeconds + if ($td -ge $Warmup + $Duration) + { + break + } + + if ($td -lt $Warmup) + { + continue + } + + + # Pass 2 - extend result + + if ($SumProduct) + { + $x = 1 + + for ($i = 0; $i -lt $nctr; $i++) + { + # any unusable value skips the sumproduct + if ($ngood[$i] -le 1) + { + $x = $null + break + } + + $x *= $s.CounterSamples[$i].CookedValue + } + + if ($null -ne $x) + { + $result[0] += ,$x + } + } + else + { + for ($i = 0; $i -lt $nctr; $i++) + { + # any unusable value skips just this counter + if ($ngood[$i] -le 1) + { + continue + } + + $result[$i] += ,$s.CounterSamples[$i].CookedValue + } + } + } + + # Average each counter strip (single sumproduct or individual) to output + foreach ($r in $result) + { + ($r | Measure-Object -Average).Average + } +} + +function ItemToDecimal +{ + [CmdletBinding()] + param( + [Parameter()] + [object] + $item + ) + + if ($null -ne $item) + { + return [decimal] $item."#text" + } + else + { + return [decimal] 0 + } +} + +# Post-process DISKSPD results per VM +function ReduceDISKSPDResultToRowResult +{ + [CmdletBinding()] + param( + [Parameter( + ValueFromPipeline = $true, + Mandatory = $true + )] + [System.IO.FileInfo] + $ResultFile + ) + + # Row object is a collection of NoteProperty constructed by parsing various properties + # from the result XML onto a new, flat object. + # + # Latency: Read/Write @ Average, Median/90/99th ptile + # IOPS + # Result filename + + begin { + $rw = @("Read", "Write") + $ms = "Milliseconds" + $av = "Average" + + $badFile = @() + } + + process { + + try { + $x = [xml](Get-Content $ResultFile) + } + catch + { + $badFile += $ResultFile + } + + # Use ordered table to produce a predictable column layout if exported. + # Result File + Average IOPS + + $props = [ordered] @{ Result = $ResultFile.BaseName } + + # Lack of target result elements indicates execution failure; TBD reporting. + $timeSpan = $x.SelectNodes('Results/TimeSpan') + $target = $x.SelectNodes('Results/TimeSpan/Thread/Target') + if ($target.Count) + { + $rio =($target | Measure-Object -Sum ReadCount).Sum + $wio =($target | Measure-Object -Sum WriteCount).Sum + $rb =($target | Measure-Object -Sum ReadBytes).Sum + $wb =($target | Measure-Object -Sum WriteBytes).Sum + + $totalTime = ($timeSpan | Measure-Object -Sum TestTimeSeconds).Sum + + $props["IOPS"] = [decimal] (($rio + $wio) / $totalTime) + $props["AverageReadIOPS"] = [decimal] ($rio / $totalTime) + $props["AverageWriteIOPS"] = [decimal] ($wio / $totalTime) + $props["AverageReadBW"] = [decimal] ($rb / $totalTime) + $props["AverageWriteBW"] = [decimal] ($wb / $totalTime) + } + else + { + $props["IOPS"] = [decimal] 0 + $props["AverageReadIOPS"] = [decimal] 0 + $props["AverageWriteIOPS"] = [decimal] 0 + $props["AverageReadBW"] = [decimal] 0 + $props["AverageWriteBW"] = [decimal] 0 + } + + # Latencies, Average and PTile + foreach ($type in $rw) + { + foreach ($ptile in @(50, 90, 99)) + { + $tile = $x.Results.TimeSpan.Latency.Bucket[$ptile] + + # ReadMilliseconds ... per ptile bucket + $prop = $type + $ms + $props[$prop + $ptile] = ItemToDecimal $tile.Item($prop) + } + + # AverageReadMillisconds + # Encode as Average|type, omit $ms + $prop = $av + $type + $ms + $props[$prop] = ItemToDecimal $x.Results.TimeSpan.Latency.Item($prop) + } + + [PsCustomObject] $props + } + + end { + + if ($badFile.Count) + { + throw "Invalid XML results, cannot post process: $($badFile.Name -join ', ')" + } + } +} +function ReduceRowResultToSummary +{ + [CmdletBinding()] + param( + [Parameter( + ValueFromPipeline = $true, + Mandatory = $true + )] + [System.Object] + $RowObject + ) + + # Row object is a collection of NoteProperty. + # Single summary property bag is composed of each decimal property reduced to aggregate by type. + # + # * *IOPS are summed + # * Average[Type]Milliseconds are SumProduct averaged with Average[Type]IOPS + # * others are averaged + # + # This does presume column name schema ReduceDISKSPDResultToRowResult, which could be better + # expressed dynamically. + + begin { + $rows = @() + $cols = @() + + $colAverage = @() + $colSumProduct = @() + $colSum = @() + } + + process { + # Get column schema (all decimal properties) + if ($cols.Count -eq 0) + { + $cols = @(@($RowObject | Get-Member |? MemberType -eq NoteProperty |? Definition -like decimal*).Name) + + $colAverage = @($cols -notlike "*IOPS" -notlike "*BW" -notlike "Average*Milliseconds") + $colSumProduct = @($cols -like "Average*Milliseconds") + $colSum = @($cols -like "*IOPS") + $colSum += @($cols -like "*BW") + } + + $rows += $RowObject + } + + end { + # Build property bag, simple averages/sums first. + $props = @{} + $rows | Measure-Object -Property $colAverage -Average |% { $props[$_.Property] = $_.Average } + $rows | Measure-Object -Property $colSum -Sum |% { $props[$_.Property] = $_.Sum } + + # The product column is always a sum aggregate; note aggregate sum is already available in the + # property bag. Compute running sumproduct and divide the aggregate to produce the average. + foreach ($col in $colSumProduct) + { + # Average[Type]Milliseconds * Average[Type]IOPS + $pcol = $col -replace "Milliseconds","IOPS" + $sumproduct = ($rows |% { $_.$col * $_.$pcol } | Measure-Object -Sum).Sum + + # Handle hard zeros (e.g., no reads, no writes) + if ($props[$pcol] -ne 0) + { + $props[$col] = $sumproduct / $props[$pcol] + } + else + { + $props[$col] = 0 + } + } + + $props + } +} + +function ProcessDISKSPDResult +{ + [CmdletBinding()] + param( + [Parameter( + Mandatory = $true + )] + [System.IO.DirectoryInfo] + $ResultDirectory, + + [Parameter()] + [string] + $AddSpec = "", + + [Parameter()] + [string] + $PerVMResultFile = "", + + [Parameter( + Mandatory = $true + )] + [int] + $Warmup, + + [Parameter( + Mandatory = $true + )] + [int] + $Duration + ) + + # common parameter set for counter interval + $intervalParam = @{} + CopyKeyIf $PSBoundParameters $intervalParam 'Warmup' + CopyKeyIf $PSBoundParameters $intervalParam 'Duration' + + # Patterns for perfctr and VM result files + $perfctrPat = (Join-Path $ResultDirectory "perfctr") + if ($PSBoundParameters.ContainsKey('AddSpec')) { $perfctrPat += "-$AddSpec"} + $perfctrPat += "-*.blg" + + $resultPat = (Join-Path $ResultDirectory "result") + if ($PSBoundParameters.ContainsKey('AddSpec')) { $resultPat += "-$AddSpec"} + $resultPat += "-*.xml" + + # Process a directory collecting DISKSPD results + Performance Counters to a property bag + + # Row reduction - table of per-vm results, optionally dropped to TSV + $row = @(Get-ChildItem $resultPat | ReduceDISKSPDResultToRowResult) + + if ($row.Count -eq 0) + { + Write-Error "No results found in directory: $ResultDirectory" + return + } + + if ($PerVMResultFile.Length) + { + $row | Export-Csv -NoTypeInformation -Delimiter "`t" -Path (Join-Path $ResultDirectory $PerVMResultFile) + } + + # + # Now summarize per-vm rows to property bag and add performance counter properties for final return + # + + $props = $row | ReduceRowResultToSummary + + # get central seconds for the performance counters + + # get average cpu utilization for each node + # get average of all nodes + + $avcpu = $(Get-ChildItem $perfctrPat |% { + + # SumProduct of total run time and processor performance is the normalized total CPU utilization + # Note each ctr% is in the range (decimal) 0-100, so we must remove the extra factor of 100 to + # wind up with a value 0-100 + ($cpu) = Get-PerformanceCounter @intervalParam -Blg $_ -SumProduct -Ctrs '\Hyper-V Hypervisor Logical Processor(_Total)\% Total Run Time','\Processor Information(_Total)\% Processor Performance' + $cpu/100 + + } | Measure-Object -Average).Average + + # Get average CSV data for central seconds, all nodes + # Note we must SumProduct average latency and iops per node to get total latency + # and then divide by total iops to get whole-cluster average. + + $t_csvr = 0 + $t_csvw = 0 + $t_csvrb = 0 + $t_csvwb = 0 + $t_csvrlat = 0 + $t_csvwlat = 0 + + Get-ChildItem $perfctrPat |% { + + # units of average total seconds of latency/second + ($csvrlat) = Get-PerformanceCounter @intervalParam -Blg $_ -SumProduct -Ctrs '\Cluster CSVFS(_Total)\avg. sec/read','\Cluster CSVFS(_Total)\reads/sec' + ($csvwlat) = Get-PerformanceCounter @intervalParam -Blg $_ -SumProduct -Ctrs '\Cluster CSVFS(_Total)\avg. sec/write','\Cluster CSVFS(_Total)\writes/sec' + + # average iops + ($csvr, $csvw, $csvrb, $csvwb) = Get-PerformanceCounter @intervalParam -Blg $_ -Ctrs '\Cluster CSVFS(_Total)\reads/sec','\Cluster CSVFS(_Total)\writes/sec','\Cluster CSVFS(_Total)\read bytes/sec','\Cluster CSVFS(_Total)\write bytes/sec' + + # LogOutput -IsVb ("$($_.BaseName) : aggregate csv read latency/s {0:N3} csv write latency/s {1:N3} csv read/s {2:N0} csv write/s {3:N0}" -f $csvrlat, $csvwlat, $csvr, $csvw) + + # aggregate totals across cluster: iops and aggregate latency/second + $t_csvr += $csvr + $t_csvw += $csvw + $t_csvrb += $csvrb + $t_csvwb += $csvwb + $t_csvrlat += $csvrlat + $t_csvwlat += $csvwlat + } + + # convert total latency to average latency/io + if ($t_csvr -ne 0) + { + $t_csvrlat /= $t_csvr + } + if ($t_csvw -ne 0) + { + $t_csvwlat /= $t_csvw + } + + # + # Add to bag and return + # Normalize latency to milliseconds for consistency with DISKSPD + # + $props["AverageCPU"] = $avcpu + $props["AverageCSVReadMilliseconds"] = $t_csvrlat * 1000 + $props["AverageCSVWriteMilliseconds"] = $t_csvwlat * 1000 + $props["AverageCSVReadIOPS"] = $t_csvr + $props["AverageCSVWriteIOPS"] = $t_csvw + $props["AverageCSVReadBW"] = $t_csvrb + $props["AverageCSVWriteBW"] = $t_csvwb + $props["AverageCSVIOPS"] = $t_csvr + $t_csvw + + return $props +} + +function ConvertToOrderedObject +{ + [CmdletBinding(DefaultParameterSetName = "Properties")] + param( + [Parameter( + ParameterSetName = "Properties", + Mandatory = $true + )] + [hashtable] + $Properties, + + [Parameter( + ParameterSetName = "InputObject", + Mandatory = $true + )] + [PSCustomObject] + $InputObject, + + [Parameter()] + [string[]] + $LeftColumn + ) + + # This wraps conversion of a property bag or a generic custom object so that + # the enumeration order of the properties on the resulting new custom object is + # defined for later operations (Export-CSV in particular). + # + # Insertion order to the ordered hashtable defines the result. + + $oh = [ordered] @{} + + switch ($PSCmdlet.ParameterSetName) + { + "Properties" + { + # specific columns in defined order ("left" in csv column sense) + foreach ($k in $LeftColumn) + { + $oh[$k] = $Properties[$k] + } + + # remainder lexically + foreach ($k in $Properties.Keys | Sort-Object) + { + if (-not $oh.Contains($k)) + { + $oh[$k] = $Properties[$k] + } + } + break + } + + "InputObject" + { + # left columns + foreach ($k in $LeftColumn) + { + $oh[$k] = $InputObject.$k + } + + # all note properties + foreach ($k in ($InputObject | Get-Member |? MemberType -eq NoteProperty).Name | Sort-Object) + { + if (-not $oh.Contains($k)) + { + $oh[$k] = $InputObject.$k + } + } + break + } + } + + [PSCustomObject] $oh +} + +function IsWithin( + [double] + $Base, + + [double] + $Target, + + [ValidateRange(1,50)] + [double] + $Percentage + ) +{ + return ([math]::abs($Target/$Base - 1) -le ($Percentage/100)) +} + +function IsAbove( + [double] + $Base, + + [double] + $Target, + + [ValidateRange(1,50)] + [double] + $Percentage + ) +{ + return (($Target/$Base - 1) -gt ($Percentage/100)) +} + +function Measure-FleetCoreWorkload +{ + [CmdletBinding()] + param( + [Parameter()] + [string] + $Cluster = ".", + + [Parameter()] + [string] + $ResultDirectory, + + [Parameter()] + [string] + $LogFile = "coreworkload.log", + + # Note: passing of an [ordered] table is not possible + # with a type specification. Type is manually validated, + # allowing for a plain unordered hashtable as well. + [Parameter()] + $KeyColumn, + + [Parameter()] + [uint32] + $Warmup = 300, + + [Parameter()] + [switch] + $SkipSddcDiagInfo, + + [Parameter()] + [switch] + $UseStorageQos + ) + + # Remoting parametersets + $clusterParam = @{} + CopyKeyIf $PSBoundParameters $clusterParam 'Cluster' + + $runParam = @{} + CopyKeyIf $PSBoundParameters $runParam 'Cluster' + CopyKeyIf $PSBoundParameters $runParam 'UseStorageQos' + + # If SddcDiagInfo is not skipped, absence of the command is an error + if (-not $SkipSddcDiagInfo -and -not (Get-Command Get-SddcDiagnosticInfo)) + { + throw "The PrivateCloud.DiagnosticInfo module must be present in order for SddcDiagnosticInfo to be gathered (Get-SddcDiagnosticInfo). Please install the module and retry, or use -SkipSddcDiagInfo to omit." + } + + $resultPath = Get-FleetPath -PathType Result @clusterParam + + # place result files in result directory unless a qualified path is provided + if (-not $LogFile.Contains('\')) { + $LogFile = Join-Path $resultPath $LogFile + } + + $myKeyColumn = $null + if ($PSBoundParameters.ContainsKey('KeyColumn')) + { + # Clone KeyColumn to allow non-modifying insert of ordered workload name / metadata columns + $myKeyColumn = [ordered] @{} + if ($KeyColumn.GetType().Name -eq 'OrderedDictionary') + { + foreach ($k in $KeyColumn.Keys) + { + $myKeyColumn[$k] = $KeyColumn[$k] + } + } + elseif ($KeyColumn.GetType().Name -eq 'Hashtable') + { + # provide lexical order of unordered input columns + foreach ($k in $KeyColumn.Keys | Sort-Object) + { + $myKeyColumn[$k] = $KeyColumn[$k] + } + } + else + { + Write-Error "KeyColumn must be a regular unordered or [ordered] hashtable." + return + } + } + else + { + $myKeyColumn = @{} + } + + $runParam.KeyColumn = $myKeyColumn + + # Inner loop warmup is min of specified or 30s. This is the time spent warming the + # search iterations during workload sweeps after full warmup has occured. + if ($Warmup -lt 30) + { + $SearchWarmup = $Warmup + } + else + { + $SearchWarmup = 30 + } + + # + # Apply values first to keycolumns and then for running configuration (iff required for run - see runners) + # + + function ApplyVMTemplate + { + param( + [string] + $ComputeTemplate, + + [double] + $VMPercent = 100, + + [switch] + $KeyColumn + ) + + if ($KeyColumn) + { + $spec = Get-FleetComputeTemplate -ComputeTemplate $ComputeTemplate + $myKeyColumn.ComputeTemplate = $ComputeTemplate + $myKeyColumn.ProcessorCount = $spec.ProcessorCount + $myKeyColumn.MemoryStartupBytes = $spec.MemoryStartupBytes + $myKeyColumn.FleetVMPercent = $VMPercent + } + else + { Set-Fleet @clusterParam -ComputeTemplate $myKeyColumn.ComputeTemplate } + } + + function ApplyVMDataDisk + { + param( + [switch] + $KeyColumn + ) + + if ($KeyColumn) + { + $dataDiskSize = Get-FleetDataDiskEstimate @clusterParam -CachePercent 200 -CapacityPercent 30 -VMPercent $myKeyColumn.FleetVMPercent -Verbose + + # Opt to use internal load file if disk size would be smaller. + # This can happen in storage limited/compute rich builds. + if ($dataDiskSize -le 10GB) + { + $dataDiskSize = 0 + } + $myKeyColumn.DataDiskBytes = $dataDiskSize + } + else + { + $d = Set-Fleet -DataDiskSize $myKeyColumn.DataDiskBytes -Running + + # If data disks were newly created, execute write warmup. + if ($null -ne $d) + { + Start-FleetWriteWarmup -VMWorkingSetSize $myKeyColumn.DataDiskBytes + } + } + } + + function StartVM + { + if ($state.ContainsKey('startVM')) { return } + $state.startVM = $true + + AlignVM + ApplyVMTemplate $myKeyColumn.ComputeTemplate $myKeyColumn.FleetVMPercent + Start-Fleet @clusterParam -Percent $myKeyColumn.FleetVMPercent + ApplyVMDataDisk + } + + function AlignVM + { + param( + [switch] + $IfStarted + ) + + if ($IfStarted -and -not $state.ContainsKey('startVM')) { return } + + Move-Fleet @clusterParam -DistributeVMPercent (100 - $myKeyColumn.VMAlignmentPct) -VMPercent $myKeyColumn.FleetVMPercent + Repair-Fleet @clusterParam + } + + function ReadWarmup + { + param( + [xml] + $ProfileXml + ) + + if ($myKeyColumn.DataDiskBytes -eq 0) { + $sz = 10GB + } + else + { + $sz = $myKeyColumn.DataDiskBytes + } + + Start-FleetReadCacheWarmup @clusterParam -ProfileXml $ProfileXml -VMWorkingSetSize $sz -Verbose + } + + # + # Per VM-configuration runners + # + # VM start/move and (re)configuration is delayed until we discover a result which has not been + # produced yet. This allows for low impact & idempotent restart - for instance, if all + # results with a given configuration have already been produced. This becomes important + # since the common case for restart will be that an error was encountered and we want to + # restart at the existing configuration (after validating, quickly, that all prior are done). + # + # Move must be evaluated every time alignment logically changes. Move only needs to happen if + # VMs are started, however. + # + + function RunInner1VCPUMatrix + { + $once = $true + foreach ($w in 0, 10, 30) + { + $myKeyColumn.Workload = "General4KWriteRatio$w" + $ProfileXml = Get-FleetProfileXml -Name General -Warmup $Warmup -Duration 60 -Cooldown 30 -WriteRatio $w -ThreadsPerTarget 1 -BlockSize 4KB -Random -RandomRatio 50 -RequestCount 32 + if (-not (Test-FleetResultRun @clusterParam -KeyColumn $myKeyColumn)) { + StartVM + if ($once) + { + $once = $false + ReadWarmup -ProfileXml $ProfileXml + } + Start-FleetResultRun @runParam -ProfileXml $ProfileXml -CpuSweep -SearchWarmup $SearchWarmup + } + } + + # Peak with 5GB workingset + $myKeyColumn.Workload = "Peak4kRead" + $ProfileXml = Get-FleetProfileXml -Name Peak -Warmup $Warmup -Duration 60 -Cooldown 30 -MaxOffset 5GB -WriteRatio 0 -ThreadsPerTarget 1 -BlockSize 4KB -Random -RequestCount 32 + if (-not (Test-FleetResultRun @clusterParam -KeyColumn $myKeyColumn)) { + StartVM + ReadWarmup -ProfileXml $ProfileXml + Start-FleetResultRun @runParam -ProfileXml $ProfileXml + } + + $myKeyColumn.Workload = "Vdi" + $ProfileXml = Get-FleetProfileXml -Name Vdi -Warmup $Warmup -Duration 60 -Cooldown 30 + if (-not (Test-FleetResultRun @clusterParam -KeyColumn $myKeyColumn)) { + StartVM + ReadWarmup -ProfileXml $ProfileXml + Start-FleetResultRun @runParam -ProfileXml $ProfileXml -CpuSweep -SearchWarmup $SearchWarmup -CutoffAverageCPU 40 -CutoffAverageLatencyMs 3 + } + } + + function RunInner4VCPUMatrix + { + $myKeyColumn.Workload = "Sql" + $ProfileXml = Get-FleetProfileXml -Name Sql -Warmup $Warmup -Duration 60 -Cooldown 30 + if (-not (Test-FleetResultRun @clusterParam -KeyColumn $myKeyColumn)) { + StartVM + ReadWarmup -ProfileXml $ProfileXml + Start-FleetResultRun @runParam -ProfileXml $ProfileXml -CpuSweep -SearchWarmup $SearchWarmup -CutoffAverageCPU 40 -CutoffAverageLatencyMs 3 + } + } + + try + { + $originalEAP = $null + $originalPowerScheme = $null + + Start-Transcript -Path $LogFile -Append + + $originalEAP = $ErrorActionPreference + $ErrorActionPreference = [System.Management.Automation.ActionPreference]::Stop + + # Show versioning up top; delay exporting until creation of the final packaging to + # avoid interference from result sweeps/etc. + Get-FleetVersion @clusterParam |% { + "Version: $($_.Component) $($_.Version)" + } + + $originalPowerScheme = Get-FleetPowerScheme @clusterParam + Set-FleetPowerScheme @clusterParam -Scheme HighPerformance + $myKeyColumn.PowerScheme = 'HighPerformance' + + # + # VM Config @ A1v2 + # + + $state = @{} + Stop-Fleet @clusterParam + ApplyVMTemplate -KeyColumn A1v2 100 + ApplyVMDataDisk -KeyColumn + + foreach ($alignment in 100,70) + { + $myKeyColumn.VMAlignmentPct = $alignment + AlignVM -IfStarted + RunInner1VCPUMatrix + } + + # + # VM Config @ A4v2 + # + + $state = @{} + Stop-Fleet @clusterParam + ApplyVMTemplate -KeyColumn A4v2 25 + ApplyVMDataDisk -KeyColumn + + foreach ($alignment in 100,70) + { + $myKeyColumn.VMAlignmentPct = $alignment + AlignVM -IfStarted + RunInner4VCPUMatrix + } + } + finally + { + if ($null -ne $originalEAP) { $ErrorActionPreference = $originalEAP } + if ($null -ne $originalPowerScheme) { Set-FleetPowerScheme @clusterParam -Scheme $originalPowerScheme } + Stop-Transcript + } + + # + # Add Get-Sddc? + # + + if (-not $SkipSddcDiagInfo -and -not (Test-Path (Join-Path $resultPath "HealthTest*"))) + { + LogOutput "Gathering SddcDiagnosticInfo to document running environment" + + # Six hours should be sufficient for all usual purposes, slim down capture size + Get-SddcDiagnosticInfo @clusterParam -ZipPrefix (Join-Path $resultPath "HealthTest") -HoursOfEvents 6 + } + + # + # Add additional metadata for the run (versioning) + # + + Get-FleetVersion | Export-Clixml (Join-Path $resultPath "version.xml") + + # + # Now create the final packaging + # + + if ($PSBoundParameters.ContainsKey('ResultDirectory')) + { + $finalResult = (Join-Path $ResultDirectory "result-coreworkload-") + } + else + { + # Note: file in same directory as the result directory (...\collect\result-coreworkload-xyz.zip) + $finalResult = $resultPath + "-coreworkload-" + } + + $finalResult += (Get-Date).ToString('yyyyMMdd-HHmm') + $finalResult += ".zip" + + LogOutput "Compressing final result archive: $finalResult" + Compress-Archive -Path $resultPath\* -DestinationPath $finalResult -ErrorAction Stop + + # + # Bounce CSV to workaround very itermittent issue where a latent handle prevents BLG deletion. + # TBD root cause. + # + + $null = Get-ClusterSharedVolume @clusterParam |? Name -match $collectVolumeName | Move-ClusterSharedVolume + + LogOutput "Clearing result directory: $resultPath" + Remove-Item $resultPath\* -Recurse + + LogOutput -ForegroundColor Green "DONE: final result archive $finalResult" +} + +function Get-FleetResultLog +{ + [CmdletBinding()] + param( + [string] + $ResultLog, + + # Note: passing of an [ordered] table is not possible + # with a type specification. Type is manually validated, + # allowing for a plain unordered hashtable as well. + [Parameter()] + $KeyColumn + ) + + function Typeify + { + param( + [Parameter(ValueFromPipeline = $true)] + $InputObject + ) + + process { + + # Convert all properties which appear to be numeric to actual numerics. + # Use 64bit integers for lack of a better estimation of a safe default + # type that will not overflow if/when operated on. + # + # Convert all properties which appear to be booleans to actual booleans. + + foreach ($prop in (Get-Member -InputObject $InputObject -MemberType NoteProperty).Name) + { + switch -regex ($InputObject.$prop) + { + '^\d+$' { + $InputObject.$prop = [uint64] $InputObject.$prop + } + '^-\d+$' { + $InputObject.$prop = [int64] $InputObject.$prop + } + '^-?\d+\.\d+$' { + $InputObject.$prop = [double] $InputObject.$prop + } + '^True$' { + $InputObject.$prop = $true + } + '^False$' { + $InputObject.$prop = $false + } + } + } + + $InputObject + } + } + + if ($PSBoundParameters.ContainsKey('KeyColumn') -and + (-not ($KeyColumn.GetType().Name -eq 'OrderedDictionary' -or + $KeyColumn.GetType().Name -eq 'Hashtable'))) + { + Write-Error "KeyColumn must be a regular unordered or [ordered] hashtable." + return + } + + if ($PSBoundParameters.ContainsKey('KeyColumn')) + { + Import-Csv $ResultLog -Delimiter "`t" | FilterObject -Filter $KeyColumn | Typeify + } + else + { + Import-Csv $ResultLog -Delimiter "`t" | Typeify + } +} + +function Test-FleetResultRun +{ + [CmdletBinding()] + param( + [Parameter()] + [string] + $Cluster = ".", + + [Parameter()] + [string] + $ResultLog = "result-log.tsv", + + # Note: passing of an [ordered] table is not possible + # with a type specification. Type is manually validated, + # allowing for a plain unordered hashtable as well. + [Parameter(Mandatory = $true)] + $KeyColumn + ) + + # Remoting parametersets + $clusterParam = @{} + CopyKeyIf $PSBoundParameters $clusterParam 'Cluster' + + if (-not $ResultLog.Contains('\')) { + + # Note we only need the resultpath if not fuilly qualified + $resultPath = Get-FleetPath -PathType Result @clusterParam + $ResultLog = Join-Path $resultPath $ResultLog + } + + if (-not (Test-Path $ResultLog)) + { + return $false + } + + $n = 0 + Get-FleetResultLog -ResultLog $ResultLog -KeyColumn $KeyColumn |% { $n += 1 } + + # If any - there may be a ? if we match multiple (incomplete keys?), but there may be utility there. + return ($n -ne 0) +} + +# Generates and sets up the run profile XML file for a given workload profile +# Can be used for free runs +function Set-FleetRunProfileScript +{ + param( + [string] + $Cluster = ".", + + [Parameter(Mandatory=$true)] + [xml] + $ProfileXml, + + [switch] + $CpuSweep, + + [switch] + $UseStorageQos, + + [uint32] + $SearchWarmup = 0, + + [string] + $RunFile = "sweep.ps1", + + [string] + $RunProfileFile = "sweep.xml" + ) + + $clusterParam = @{} + CopyKeyIf $PSBoundParameters $clusterParam 'Cluster' + + if ($CpuSweep -and -not (IsProfileSingleTimespan -ProfileXml $ProfileXml)) + { + Write-Error "Profile for a CpuSweep can only contain a single timespan" + return + } + + $QoS = 0 + + if (IsProfileThroughputLimited -ProfileXml $ProfileXml) + { + $addspec = "baseline" + if ($CpuSweep) + { + if(IsProfileSingleTarget -ProfileXml $ProfileXml -and $SearchWarmup) + { + $ProfileXml = $ProfileXml | Set-FleetProfile -Warmup $SearchWarmup + } + } + } + else + { + $addspec = "qos$qos" + if ($CpuSweep) + { + if ($UseStorageQos) + { + Set-StorageQosPolicy -Name SweepQoS -MaximumIops $QoS @cimParam + } + else + { + $ProfileXml = $ProfileXml | Set-FleetProfile -Throughput $QoS -ThroughputUnit IOPS + } + } + } + + $accessNode = Get-AccessNode @clusterParam + $cimParam = @{ CimSession = $accessNode } + + if ($VerbosePreference) + { + $ProfileXml | Convert-FleetXmlToString |% { LogOutput -IsVb $_ } + } + + $Duration = GetProfileDuration -ProfileXml $ProfileXml -Total + + if ($null -eq $Duration -or $Duration -eq 0) + { + Write-Error "Run duration could not be determined, cannot continue" + return + } + + $controlPath = Get-FleetPath -PathType Control @clusterParam + $runProfileFilePath = Join-Path $controlPath $RunProfileFile + Remove-Item $runProfileFilePath -Force -ErrorAction SilentlyContinue + $ProfileXml | Convert-FleetXmlToString | Out-File $runProfileFilePath -Encoding ascii -Width ([int32]::MaxValue) -Force + + Create-TemplateRunScript $addspec $controlPath $RunFile $RunProfileFile +} + +function Start-FleetResultRun +{ + [CmdletBinding(DefaultParameterSetName = 'Default')] + param( + [Parameter(ParameterSetName = 'Default')] + [Parameter(ParameterSetName = 'CpuSweep')] + [Parameter(ParameterSetName = 'CpuSweepCombinedLatency')] + [string] + $Cluster = ".", + + [Parameter(ParameterSetName = 'Default', Mandatory = $true)] + [Parameter(ParameterSetName = 'CpuSweep', Mandatory = $true)] + [Parameter(ParameterSetName = 'CpuSweepCombinedLatency', Mandatory = $true)] + [xml] + $ProfileXml, + + [Parameter(ParameterSetName = 'Default')] + [Parameter(ParameterSetName = 'CpuSweep')] + [Parameter(ParameterSetName = 'CpuSweepCombinedLatency')] + [string] + $ResultFile = "result.tsv", + + [Parameter(ParameterSetName = 'Default')] + [Parameter(ParameterSetName = 'CpuSweep')] + [Parameter(ParameterSetName = 'CpuSweepCombinedLatency')] + [string] + $ResultLog = "result-log.tsv", + + # Note: passing of an [ordered] table is not possible + # with a type specification. Type is manually validated, + # allowing for a plain unordered hashtable as well. + [Parameter(ParameterSetName = 'Default')] + [Parameter(ParameterSetName = 'CpuSweep')] + [Parameter(ParameterSetName = 'CpuSweepCombinedLatency')] + $KeyColumn, + + [Parameter(ParameterSetName = 'Default')] + [Parameter(ParameterSetName = 'CpuSweep')] + [Parameter(ParameterSetName = 'CpuSweepCombinedLatency')] + [string] + $RunLabel, + + [Parameter(ParameterSetName = 'CpuSweep', Mandatory = $true)] + [Parameter(ParameterSetName = 'CpuSweepCombinedLatency', Mandatory = $true)] + [switch] + $CpuSweep, + + [Parameter(ParameterSetName = 'CpuSweep')] + [Parameter(ParameterSetName = 'CpuSweepCombinedLatency')] + [uint32] + $SearchWarmup = 0, + + [Parameter(ParameterSetName = 'CpuSweep')] + [Parameter(ParameterSetName = 'CpuSweepCombinedLatency')] + [switch] + $UseStorageQos, + + [Parameter(ParameterSetName = 'CpuSweep')] + [Parameter(ParameterSetName = 'CpuSweepCombinedLatency')] + [ValidateRange(1,100)] + [double] + $CutoffAverageCPU, + + # Latency cutoffs - ranges are arbitrarily chosen to loosely bracket + # reasonable values : 10us - 1s + [Parameter(ParameterSetName = 'CpuSweep')] + [ValidateRange(0.01,1000)] + [double] + $CutoffAverageReadLatencyMs, + + [Parameter(ParameterSetName = 'CpuSweep')] + [ValidateRange(0.01,1000)] + [double] + $CutoffAverageWriteLatencyMs, + + [Parameter(ParameterSetName = 'CpuSweepCombinedLatency', Mandatory = $true)] + [ValidateRange(0.01,1000)] + [double] + $CutoffAverageLatencyMs + ) + + # Remoting parametersets + $clusterParam = @{} + CopyKeyIf $PSBoundParameters $clusterParam 'Cluster' + + # + # Validate + # + # CpuSweep only applies to a single timespan; we do not currently reason about averaging results + # through multiple timespans. + # + + if ($CpuSweep -and -not (IsProfileSingleTimespan -ProfileXml $ProfileXml)) + { + Write-Error "Profile for a CpuSweep can only contain a single timespan" + return + } + + # Produce ordered set of key columns + $orderedKeyColumn = [ordered] @{} + if ($PSBoundParameters.ContainsKey('KeyColumn')) + { + if ($KeyColumn.GetType().Name -eq 'OrderedDictionary') + { + $orderedKeyColumn = $KeyColumn + } + elseif ($KeyColumn.GetType().Name -eq 'Hashtable') + { + $orderedKeyColumn = [ordered] @{} + foreach ($k in $KeyColumn.Keys | Sort-Object) + { + $orderedKeyColumn[$k] = $KeyColumn[$k] + } + } + else + { + Write-Error "KeyColumn must be a regular unordered or [ordered] hashtable." + return + } + } + + # Already complete? + if ($orderedKeyColumn.Count -and (Test-FleetResultRun @clusterParam -ResultLog $ResultLog -KeyColumn $KeyColumn)) + { + LogOutput -ForegroundColor Cyan "Run already measured for $($orderedKeyColumn.Keys |% { $_, $orderedKeyColumn[$_] -join '=' })" + return + } + + $accessNode = Get-AccessNode @clusterParam + $cimParam = @{ CimSession = $accessNode } + + $resultPath = Get-FleetPath -PathType Result @clusterParam + + # place result files in result directory unless a qualified path is provided + if (-not $ResultFile.Contains('\')) { + $ResultFile = Join-Path $resultPath $ResultFile + } + if (-not $ResultLog.Contains('\')) { + $ResultLog = Join-Path $resultPath $ResultLog + } + + # + # Expected counter set for post-processing. + # + + $pc = @('\Hyper-V Hypervisor Logical Processor(_Total)\% Total Run Time', + '\Processor Information(_Total)\% Processor Performance', + '\Cluster CSVFS(_Total)\reads/sec', + '\Cluster CSVFS(_Total)\avg. sec/read', + '\Cluster CSVFS(_Total)\writes/sec', + '\Cluster CSVFS(_Total)\avg. sec/write', + '\Cluster CSVFS(_Total)\read bytes/sec', + '\Cluster CSVFS(_Total)\write bytes/sec') + + # Get timing for post processing of data + $Warmup, $Duration = GetProfileDuration -ProfileXml $ProfileXml -Warmup -Duration + + # Limit qos infill search, done if the next best gap is closer than %age + $qosWindow = 8 + + # Limit qos adaptive upper anchor search, done if the gap closes within this %age of upper cutoff + $qosAdaptiveWindow = 2 + + # Percent variance of result IOPS <=> QoS target which will result in a scale/surge cutoff + $qosScaleWindow = 1.5 + + function GetIterationFiles + { + param( + [string] + $resultPath + ) + + # per-vm tsv for iteration + Get-ChildItem $resultPath\* -File -Include result-vm-*.tsv + # all other, excluding main tsv and log + Get-ChildItem $resultPath\* -File -Exclude *.tsv,*.log + } + + # Dynamic scope wrapper for inner loop running the iteration itself + function DoIteration + { + param( + [int] + $QoS = 0, + + [switch] + $IsSearch, + + [switch] + $IsAdaptive, + + [switch] + $IsBaseline + ) + + # + # Measure once. This functions as the short-circuit for the fixed + # QoS bracketing of the sweep. Baselines are simply that. Non + # baselines should not consider the baseline, which will be at + # QoS "zero" (and should not prevent an unconstrained run of a + # baselined profile). + # + # This is also where we decide on the filename labeling for this run + # (if we make it). + # + + if ($IsBaseline) + { + $prior = @($results |? RunType -eq ([RunType]::Baseline)) + $addspec = "baseline" + } + else + { + $prior = @($results |? RunType -ne ([RunType]::Baseline) |? QOSperVM -eq $QoS) + $addspec = "qos$qos" + } + + if ($prior.Count -eq 1) + { + LogOutput "Result already captured" + return $prior + } + elseif ($prior.Count -ne 0) + { + throw "Unexpected multiple measurements @ QoS $QoS ($($prior.Count) total) in $ResultFile - please inspect" + } + + # If this is a sweep and not an initial throughput baseline, apply QoS. + # Note sweeps can start with a profile that has no throughput constraints + # as well as ones that do (the latter are "baselines", the former are simply + # unconstrained). + if ($CpuSweep -and -not $IsBaseline) + { + if ($UseStorageQos) + { + Set-StorageQosPolicy -Name SweepQoS -MaximumIops $QoS @cimParam + } + else + { + $ProfileXml = $ProfileXml | Set-FleetProfile -Throughput $QoS -ThroughputUnit IOPS + } + + if ($IsSearch -and $SearchWarmup) + { + $ProfileXml = $ProfileXml | Set-FleetProfile -Warmup $SearchWarmup + $Warmup = $SearchWarmup + } + } + + if ($VerbosePreference) + { + $ProfileXml | Convert-FleetXmlToString |% { LogOutput -IsVb $_ } + } + + # Use thread autoscaling? + Start-FleetRun @clusterParam -pc $pc -SampleInterval 1 -ProfileXml $ProfileXml -AddSpec $addspec + + # Get result property bag and add sweep metadata columns, export. + $props = ProcessDISKSPDResult -ResultDirectory $resultPath -Warmup $Warmup -d $Duration -AddSpec $addspec -PerVMResultFile "result-vm-$addspec.tsv" + + # + # Gather results for this iteration + # + + if ($RunLabel.Length) + { + $dest = Join-Path $resultPath $RunLabel + $null = mkdir $dest -ErrorAction SilentlyContinue + if (-not (Test-Path $dest)) + { + throw "Could not create run result gather directory $dest" + } + GetIterationFiles $resultPath | Move-Item -Destination $dest + + LogOutput Gathered results to $dest + } + + # Insert key columns as metadata for the result table, ending with our QOS. + # Note that all results in a given result file MUST share the same key columns. + + foreach ($k in $orderedKeyColumn.Keys) + { + $props[$k] = $orderedKeyColumn[$k] + } + + # + # Evaluate cutoffs + # + + $cutoff = [CutoffType]::No + + # Surge is a special case where tooling has malfunctioned/errored in some way to run faster than target + if ($PSBoundParameters.ContainsKey('QoS') -and $QoS -ne 0 -and (IsAbove ($QoS * $vms) $props.IOPS $qosScaleWindow)) + { + LogOutput -ForegroundColor Red ('CUTOFF SURGE: {0:N0} IOPS is > {1:P1} above target {2:N0} IOPS (QoS {3:N0} from {4:N0} VMs)' -f ($props.IOPS,($qosScaleWindow/100),($QoS*$vms),$QoS,$vms)) + $cutoff = [CutoffType]::Surge + } + + # Fail to scale - since we checked surge, this will always be slower-than target + elseif ($PSBoundParameters.ContainsKey('QoS') -and $QoS -ne 0 -and -not (IsWithin ($QoS * $vms) $props.IOPS $qosScaleWindow)) + { + LogOutput -ForegroundColor Cyan ('CUTOFF SCALE: {0:N0} IOPS is > {1:P1} off of target {2:N0} IOPS (QoS {3:N0} from {4:N0} VMs)' -f ($props.IOPS,($qosScaleWindow/100),($QoS*$vms),$QoS,$vms)) + $cutoff = [CutoffType]::Scale + } + + # CPU utilizati0on cutoff + elseif ($CutoffAverageCPU -ne 0 -and $CutoffAverageCPU -lt $props.AverageCPU) + { + LogOutput -ForegroundColor Cyan ('CUTOFF CPU: {0:P1} CPU utilization is > {1:P1} cutoff limit' -f (($props.AverageCPU/100),($CutoffAverageCPU/100))) + $cutoff = [CutoffType]::CPU + } + + # + # Single shared latency cutoff + # + + elseif ($CutoffAverageLatencyMs -ne 0 -and + $CutoffAverageLatencyMs -lt $props.AverageReadMilliseconds) + { + LogOutput -ForegroundColor Cyan ('CUTOFF COMBINED LATENCY: read latency {0:N3}ms > {1:N3}ms cutoff limit' -f ($props.AverageReadMilliseconds,$CutoffAverageLatencyMs)) + $cutoff = [CutoffType]::ReadLatency + } + + elseif ($CutoffAverageLatencyMs -ne 0 -and + $CutoffAverageLatencyMs -lt $props.AverageWriteMilliseconds) + { + LogOutput -ForegroundColor Cyan ('CUTOFF COMBINED LATENCY: write latency {0:N3}ms > {1:N3}ms cutoff limit' -f ($props.AverageWriteMilliseconds,$CutoffAverageLatencyMs)) + $cutoff = [CutoffType]::WriteLatency + } + + # + # Individual latency cutoffs + # + + elseif ($CutoffAverageReadLatencyMs -ne 0 -and + $CutoffAverageReadLatencyMs -lt $props.AverageReadMilliseconds) + { + LogOutput -ForegroundColor Cyan ('CUTOFF READ LATENCY: read latency {0:N3}ms > {1:N3}ms cutoff limit' -f ($props.AverageReadMilliseconds,$CutoffAverageReadLatencyMs)) + $cutoff = [CutoffType]::ReadLatency + } + + elseif ($CutoffAverageWriteLatencyMs -ne 0 -and + $CutoffAverageWriteLatencyMs -lt $props.AverageWriteMilliseconds) + { + LogOutput -ForegroundColor Cyan ('CUTOFF WRITE LATENCY: write latency {0:N3}ms > {1:N3}ms cutoff limit' -f ($props.AverageWriteMilliseconds,$CutoffAverageWriteLatencyMs)) + $cutoff = [CutoffType]::WriteLatency + } + + # Add in metadata columns + # CAREFUL: [switch] parameters are a distinct object + if ($IsBaseline.IsPresent) + { + $props.RunType = [RunType]::Baseline + } + elseif ($IsAdaptive.IsPresent) + { + $props.RunType = [RunType]::AnchorSearch + } + else + { + $props.RunType = [RunType]::Default + } + $props.CutoffType = $cutoff + $props.QOSperVM = $QoS + $props.VMCount = $vms + + # Add in optional column(s) + $optColumn = @() + + if ($RunLabel.Length) + { + $props.RunLabel = $RunLabel + $optColumn += 'RunLabel' + } + + # Add to result file and in-memory table, moving metadata (visuals) to the left. Swallow the index of the addded result. + $o = ConvertToOrderedObject -Properties $props -LeftColumn ($optColumn + $orderedKeyColumn.Keys + 'RunType' + 'CutoffType' + 'QOSperVM' + 'VMCount' + 'IOPS') + $o | Export-Csv -NoTypeInformation -Delimiter "`t" -Path $ResultFile -Append -ErrorAction Stop + + $null = $results.Add($o) + + # return current result + return $o + } + + function LogToComplete + { + # No run label => no log (single result run) + if ($RunLabel.Length -eq 0) { return } + + $props = @{} + + foreach ($k in $orderedKeyColumn.Keys) + { + $props[$k] = $orderedKeyColumn[$k] + } + + $props.RunLabel = $RunLabel + $props.Complete = 1 + + # RunLabel on the far left + ConvertToOrderedObject -Properties $props -LeftColumn (@('RunLabel') + $orderedKeyColumn.Keys) | + Export-Csv -NoTypeInformation -Delimiter "`t" -Path $ResultLog -Append -ErrorAction Stop + } + + try + { + # if using in-stack qos mechanism, make qos policy and apply to vms + if ($UseStorageQos) + { + $qosName = 'SweepQoS' + Get-StorageQosPolicy -Name $qosName @cimParam -ErrorAction SilentlyContinue | Remove-StorageQosPolicy -Confirm:$false + $null = New-StorageQosPolicy -Name $qosName -PolicyType Dedicated @cimParam + Set-FleetQos -Name $qosName @clusterParam + } + else + { + # clear any applied in-stack qos + Set-FleetQos @clusterParam + } + + # + # Accumulate iteration result objects for fit. Preload from existing data (if any) so that + # we do not repeat steps. Note that empty key column is a null filter, passing everything. + # + + $results = [collections.arraylist] @() + if (Test-Path $ResultFile) + { + Get-FleetResultLog -ResultLog $ResultFile -KeyColumn $orderedKeyColumn |% { $null = $results.Add($_) } + } + + # + # Use pre-existing iteration's runlabel else generate new guid-based label if none specified. + # + + if ($results.Count) + { + if (Get-Member -InputObject $results[0] -Name RunLabel) + { + $RunLabel = $results[0].RunLabel + } + } + elseif (-not $PSBoundParameters.ContainsKey('RunLabel') -and $orderedKeyColumn.Count) + { + $RunLabel = [System.Guid]::NewGuid().Guid + } + + # + # Log run keys if present + # + + if ($orderedKeyColumn.Count) + { + LogOutput -ForegroundColor Cyan "Starting run for $($orderedKeyColumn.Keys |% { $_, $orderedKeyColumn[$_] -join '=' })" + } + + # + # Count the number of online vms in the configuration so we can reason about IOPS -> QoS relationships. + # + + $vms = @(Get-ClusterGroup @clusterParam |? GroupType -eq VirtualMachine |? Name -like 'vm-*' |? State -eq Online).Count + + # + # Baseline throughput limited profiles else find unconstrained/default upper anchor. + # A baselined run can start a cpusweep loop, following up with the adaptive search to find its upper anchor. + # Unconstrained will start with normal infill. + # + + $sweepAdaptive = $false + $doUnconstrained = $false + $paramUnconstrained = @{ QoS = 0 } + + if (IsProfileThroughputLimited -ProfileXml $ProfileXml) + { + $o = DoIteration -IsBaseline + LogOutput -ForegroundColor Cyan ("RESULT: baseline {0:N0} IOPS @ {1:P1} CPU => {2:N0} IOPS/VM from {3:N0} VMs" -f ($o.IOPS,($o.AverageCPU/100),($o.IOPS/$vms),$vms)) + + # If this is a CPU Sweep, set up for the upper anchor search. + # Single target throughput limited profiles can be run unconstrained (QoS 0) to find the upper anchor. + # Multi-target throughput limited profiles require the adaptive anchor search. + # + # We'll always show the baseline above on restart (may be complete). Then, if a default/infill result + # has not been logged we know that the anchor search is needed or potentially incomplete and the loop + # should start on that side. Conversely, if there is a default/infill we know it is complete. + if ($CpuSweep) + { + if(IsProfileSingleTarget -ProfileXml $ProfileXml) + { + # Unconstrained run here is part of the search (speedy warmup - assume baseline run/restarted after) + $doUnconstrained = $true + $paramUnconstrained.IsSearch = $true + } + elseif (@($results |? RunType -eq [RunType]::Default).Count -eq 0) + { + $sweepAdaptive = $true + } + } + } + + # Default case: take the profile and run it wide open. + else + { + $doUnconstrained = $true + } + + # Note: if this is a CPU Sweep, this may be the second run of a throughput limited profile (above) + if ($doUnconstrained) + { + $o = DoIteration @paramUnconstrained + LogOutput -ForegroundColor Cyan ("RESULT: unconstrained {0:N0} IOPS @ {1:P1} CPU => {2:N0} IOPS/VM from {3:N0} VMs" -f ($o.IOPS,($o.AverageCPU/100),($o.IOPS/$vms),$vms)) + } + + # If not a sweep, this completes the run. + if (-not $CpuSweep) { + LogOutput -ForegroundColor Green "Single run, complete" + LogToComplete + return + } + + # + # Pair of points defining the current place in the sweep. Becomes valid after there are two or more measured points. + # Adaptive: uppermost points defining the adaptive search (upper may represent cutoff) + # Infill: bracketing the current split + # + + $p1 = $p2 = $null + $last = $false + + do { + + # + # Adaptive sweep for upper anchor + # + # Scale up until cutoff is reached, then iteratively split the resulting gap until within + # the given tolerance. + # + + if ($sweepAdaptive) + { + $p2, $p1 = GetUpperAnchor $results -OrderBy 'IOPS' + + # Upper (single or of two) measurement, not cutoff + if ($p2.CutoffType -eq [CutoffType]::No) + { + $qos = 5 * $p2.IOPS / $vms + LogOutput -ForegroundColor Cyan ("ADAPTIVE UP: scaling up to QoS {0:N0} => {1:N0} IOPS from {2:N0} VMs" -f ($qos,($qos*$vms),$vms)) + } + + # Upper is cutoff (single or of two). Split in between to try to close the cutoff gap. + else + { + # Determine lower side of split (either p1 or 0) + $lower = 0 + if ($null -ne $p1) + { + $lower = [int] $p1.IOPS + } + + # If upper points are already within the window, we are done now. Note that one will be the most recently measured. + if ($lower -ne 0 -and (IsWithin $p1.IOPS $p2.IOPS $qosAdaptiveWindow)) + { + LogOutput -ForegroundColor Green ("ADAPTIVE COMPLETE: gap between {1:N0} and {2:N0} IOPS is within {0:P1}" -f (($qosAdaptiveWindow/100),$p1.IOPS,$p2.IOPS)) + $sweepAdaptive = $false + continue + } + + $tgtIOPS = [int] (($p2.IOPS + $lower) / 2) + $qos = $tgtIOPS / $vms + + # Edge case where split bottoms out at an unsplittable small integer (like [2-3] with large percentage delta) + if ($tgtIOPS -eq $lower) + { + LogOutput -ForegroundColor Green ("ADAPTIVE COMPLETE: unsplittable gap between [{0:N0} - {1:N0}] IOPS" -f ($lower,$p2.IOPS)) + $sweepAdaptive = $false + continue + } + + LogOutput -ForegroundColor Cyan ("ADAPTIVE: splitting [{3:N0} - {4:N0} IOPS] to QoS {0:N0} => {1:N0} IOPS from {2:N0} VMs" -f ($qos,($qos*$vms),$vms,$lower,$p2.IOPS)) + + # If the p2 cutoff is within the window of the target, we can pull the adaptive sweep down now. + # + # There are two basoc possibilities: the system will scale onto this target or it will undershoot. + # Regardless of how it might undershoot (triggering the scale cutoff or not) there is no need + # to reason about continuing. If the undershoot did not trigger the scale cutoff and the result + # stayed outside the adaptive cutoff w.r.t. p2 we would continue pounding away. This occurs when p1 + # gets close to the actual scaling limit. + # + # Regardless of the result we'll get we do want this target attempt to try to dial in the upper + # anchor, but we know ahead of time (now) that will complete the search. + + if (IsWithin $tgtIOPS $p2.IOPS $qosAdaptiveWindow) + { + LogOutput -ForegroundColor Green ("ADAPTIVE COMPLETING: gap between {1:N0} and next target {2:N0} IOPS (QoS {3:N0}) is within {0:P1}" -f (($qosAdaptiveWindow/100),$p1.IOPS,$tgtIOPS,$qos)) + $sweepAdaptive = $false + } + } + } + + # + # Infill - anchor identified, filling in the sweep coverage. + # + # Target next QOS based on dividing the largest gap in Average CPU achieved: either splitting + # the IOPS for those measured CPU utilizations OR toward zero, if that is the largest gap in IOPS + # targeted so far. + # + + else + { + # At anchor; halve IOPS/vm to begin sweep. + if ($results.Count -eq 1) + { + $qos = $results.IOPS / 2 / $vms + LogOutput -ForegroundColor Cyan ("START: halving anchor to QoS {0:N0} => target {1:N0} IOPS from {2:N0} VMs" -f $qos,($qos*$vms),$vms) + } + + # Contine sweep at best available split. + else + { + $p2, $p1 = GetNextSplit $results 'AverageCPU' -OrderBy 'IOPS' + $minIOPS = ($results.IOPS | Measure-Object -Minimum).Minimum + + # Determine lower side of split (either p1 or 0, if p2 wound up being a cutoff) + $lower = 0 + if ($null -ne $p1) + { + $lower = [int] $p1.IOPS + } + + # Is gap based on AverageCPU split larger than the minimum? + if ($null -eq $p1 -or $minIOPS -lt ($p2.IOPS - $p1.IOPS)) + { + # Stop if this best split has met the infill goal window + if (IsWithin $p2.IOPS $lower $qosWindow) + { + LogOutput -ForegroundColor Yellow ("STOP: largest measurement gap, between {1:N0} and {2:N0} IOPS, would result in next QOS < +/-{0:P1}" -f (($qosWindow/100),$lower,$p2.IOPS)) + break + } + + # Average and scale IOPS -> VM QOS + $tgtIOPS = [int] (($p2.IOPS + $lower) / 2) + + # Edge case where split bottoms out at an unsplittable small integer (like [2-3] with large percentage delta) + if ($tgtIOPS -eq $lower) + { + LogOutput -ForegroundColor Green ("STOP: unsplittable gap between [{0:N0} - {1:N0}] IOPS" -f ($lower,$p2.IOPS)) + break + } + + $qos = $tgtIOPS / $vms + LogOutput -ForegroundColor Cyan ("CONTINUE: next target at QoS {0:N0} => {1:N0} IOPS from {2:N0} VMs, splitting prior measurments @ {3:N0} & {4:N0} IOPS/VM" -f ($qos,$tgtIOPS,$vms,($lower/$vms),($p2.IOPS/$vms))) + + # Similar to the adaptive case, if the split would logically close within the measurement window, this is now the last measurement. + # Indicate this so that regardless of result (say it does not scale) we complete after this next iteration. + if (IsWithin $tgtIOPS $p2.IOPS $qosWindow) + { + LogOutput -ForegroundColor Green ("INFILL COMPLETING: gap between {1:N0} and next target {2:N0} IOPS (QoS {3:N0}) is within {0:P1}" -f (($qosWindow/100),$p2.IOPS,$tgtIOPS,$qos)) + $last = $true + } + } + else + { + $qos = $minIOPS / 2 / $vms + LogOutput -ForegroundColor Cyan ("CONTINUE: next target at QoS {0:N0} => {1:N0} IOPS from {2:N0} VMs, halving minimum so far @ {3:N0} IOPS/VM" -f ($qos,($qos*$vms),$vms,($minIOPS/$vms))) + } + } + } + + # Coerce to integer for equality comparisons + $qos = [int] $qos + $tgtIOPS = $qos * $vms + + # Bottomed out QoS + if ($qos -eq 0) { break } + + # Final speedbrake - if we land on a prior QoS measurement, done with this phase of the loop. + if ($results |? QOSperVM -eq $qos) + { + LogOutput -ForegroundColor Cyan "STOP: result already captured at QoS $qos" + if ($sweepAdaptive) { + $sweepAdaptive = $false + continue + } + else + { + break + } + } + + # + # Iteration + # + + $o = DoIteration -QoS $qos -IsSearch -IsAdaptive:$sweepAdaptive + LogOutput -ForegroundColor Cyan ("RESULT: {0:N0} IOPS @ {1:P1} CPU => {2:N0} IOPS/VM from {3:N0} VMs v. target {4:N0} IOPS/VM" -f ($o.IOPS,($o.AverageCPU/100),($o.IOPS/$vms),$vms,$qos)) + + # + # If we have a surge result (workload went past window above throughput limit) there is a tool/systemic issue affecting + # results that will need external triage. Stop here. This is an error condition and not a normal cutoff. + # + + if ($o.CutoffType -eq [CutoffType]::Surge) + { + break + } + + } until ($last) + + # Log completion. Note that a thrown error will bypass and not log completion (try again?), and sweep terminating + # cases (e.g., in-window, unphysical QoS) that trigger before exhaustion are indeed (also) completion. + LogOutput -ForegroundColor Green "Sweep, complete" + LogToComplete + } + catch + { + if ($RunLabel.Length) + { + # If this is part of a labeled run, stash any iteration file content in error directory for analysis. + # Replace prior error content, if any. + $errd = (Join-Path $resultPath "error") + if (Test-Path $errd) { Remove-Item $errd -Recurse } + $null = mkdir $errd + $itf = @(GetIterationFiles $resultPath) + if ($itf.Count) + { + LogOutput "Iteration file content saved to $errd for triage" + + # Force continue - we don't want a stacked error trying to move content to lose + # the error which threw us into this condition. + $itf | Move-Item -Destination $errd -ErrorAction Continue + } + } + + throw + } + finally + { + # Clear QoS if used in this sweep + if ($UseStorageQos) + { + Set-FleetQos @clusterParam + } + } +} + +function Show-FleetCpuSweep +{ + [CmdletBinding()] + param( + [Parameter(Mandatory = $true)] + [string] + $ResultFile, + + [Parameter()] + [int] + $SigFigs = 5 + ) + + function GetSigFigs( + [double]$Value, + [int]$SigFigs + ) + { + $log = [math]::Ceiling([math]::log10([math]::abs($value))) + $decimalpt = $sigfigs - $log + + # if all sigfigs are above the decimal point, round off to + # appropriate power of 10 + if ($decimalpt -lt 0) { + $pow = [math]::Abs($decimalpt) + $decimalpt = 0 + $value = [math]::Round($value/[math]::Pow(10,$pow))*[math]::pow(10,$pow) + } + + "{0:F$($decimalpt)}" -f $value + } + + function ShowReport + { + param( + [Parameter()] + [string] + $Header, + + [Parameter()] + [object[]] + $Data + ) + + Write-Host -ForegroundColor Cyan ("-"*20) + Write-Host "Variation: $Header" + + # Special case of a single measured run, no sweep + if ($Data.Count -eq 1) + { + Write-Host ("IOPS = {0} at AverageCPU {1:P2}" -f (GetSigFigs $Data.IOPS $SigFigs),($Data.AverageCPU/100)) + Write-Host "Single measurement of the workload." + return + } + + if ($Data.Count -eq 2) + { + Write-Host "Two measurements of the workload. TBD analysis statement." + return + } + + $fit = Get-FleetPolynomialFit -Order 2 -X $Data.AverageCPU -Y $Data.IOPS + + # sign of the linear/quad terms for the equation display + # the constant term falls out of the plain print + $sign = @() + if ( $fit.a[1] -ge 0) { $sign += '+ ' } else { $sign += '' } + if ( $fit.a[2] -ge 0) { $sign += '+ ' } else { $sign += '' } + + Write-Host ("IOPS = {0} {1}{2}(AverageCPU) {3}{4}(AverageCPU^2)" -f (GetSigFigs $fit.a[0] $SigFigs),$sign[0],(GetSigFigs $fit.a[1] $SigFigs),$sign[1],(GetSigFigs $fit.a[2] $SigFigs)) + Write-Host ("Number of measurements = {1}`nR^2 goodness of fit {0:P2}" -f $fit.r2,$Data.Count) + + # Use quadtratic form to estimate zero intercept (~idle cpu utilization) + # If the discriminant is < 0 something unreasonable happened (a complex solution) + # Note that the usual form will be an inverted parabola (a[2] < 0); provide the + # smallest positive root. + + $discriminant = [math]::pow($fit.a[1],2) - 4 * $fit.a[0] * $fit.a[2] + if ($discriminant -lt 0) + { + Write-Host -ForegroundColor Red "There is no solution for AverageCPU = 0; check results and system conditions for unexpected behavior" + } + else + { + $discriminant = [math]::Sqrt($discriminant) + $r0 = (-$fit.a[1] - $discriminant) / (2*$fit.a[2]) + $r1 = (-$fit.a[1] + $discriminant) / (2*$fit.a[2]) + $r = $null + if ($r0 -ge 0 -and $r0 -lt $r1) + { + $r = $r0 + } + if ($r1 -ge 0) + { + $r = $r1 + } + + if ($null -eq $r) + { + Write-Host -ForegroundColor Red ("Unexpected solutions for AverageCPU @ IOPS = 0 ({0:N2}, {1:N2}); check results and system conditions for unexpected behavior" -f $r0,$r1) + } + else + { + Write-Host ("Estimated background AverageCPU (CPU @ IOPS = 0): {0:P1}" -f ($r/100)) + } + } + } + + # Determine result grouping. We assume that the result file metadata columns end at QOS. + # To the left are arbitrary metadata columns provided by a runner (workload, alignment, etc.). + # Dynamically determine these metadata columns and group the results by them, producing a set of + # results to apply fits to. Some may be single values, not swept by QOS. + + $header = @((Get-Content $ResultFile -TotalCount 1) -split "`t" -replace '"','') + + if ($null -eq $header) + { + Write-Error "Could not read the table header from the result file - is this a CPU sweep result?" + return + } + + $splitIdx = $header.IndexOf('QOSperVM') + if ($splitIdx -eq -1) + { + Write-Error "Result file does not have a QOSperVM column - is this a CPU sweep result?" + return + } + + Write-Host @" +CPU Sweep Report + +The following models are quadratic fits to the measured results at the +given write ratios. + +Take care that these formulae are only used to reason about the region +where these values have a working relationship: + + AverageCPU > background and < 100% + +The second order term (AverageCPU^2) should generally be small negative +value indicating IOPS flattening as the system approaches saturation. + +Use R^2 (coefficient of determination) as a quality check for the fit. +Values close to 100% mean that the data is good fit. If R^2 is significantly +less than 100%, the fit is not good and a closer look at system behavior may +be required. +"@ + + if ($splitIdx -eq 0) + { + # single un-named data set + + ShowReport -Header '' -Data (Get-FleetResultLog $ResultFile) + return + } + + # Columns to the left of QOS minus internal metadata, forming the properties to group by. + $header = [collections.arraylist] $header[0..($splitIdx - 1)] + $header.Remove('RunType') + $header.Remove('CutoffType') + + # Process all groupings + Get-FleetResultLog $ResultFile | Group-Object -Property $header |% { + + $desc = $(foreach ($col in $header) + { + $col,$_.Group[0].$col -join ' = ' + }) -join "`n`t" + + ShowReport -Header $desc -Data $_.Group + } +} + +function SolveLU +{ + param( + [double[,]] + $m, + + [double[]] + $b + ) + + # m must be square + + if ($m.Rank -ne 2) + { + Write-Error "matrix m is not two dimensional: rank $($m.Rank)" + return + } + if ($m.GetLength(0) -ne $m.GetLength(1)) + { + Write-Error "matrix m is not square: $($m.GetLength(0)) x $($m.GetLength(1))" + return + } + if ($m.GetLength(0) -ne $b.GetLength(0)) + { + Write-Error "vector b is not of the same dimension as m: $($b.GetLength(0)) != $($m.GetLength(0))" + return + } + $n = $m.GetLength(0) + + # decompose matrix LU = L+U-I + $lu = [double[,]]::new($n, $n) + $sum = [double] 0 + for ($i = 0; $i -lt $n; ++$i) + { + for ($j = $i; $j -lt $n; ++$j) + { + $sum = [double] 0 + for ($k = 0; $k -lt $i; ++$k) + { + $sum += $lu[$i, $k] * $lu[$k, $j] + } + $lu[$i, $j] = $m[$i, $j] - $sum + } + + for ($j = $i + 1; $j -lt $n; ++$j) + { + $sum = [double] 0 + for ($k = 0; $k -lt $i; ++$k) + { + $sum += $lu[$j, $k] * $lu[$k, $i] + } + $lu[$j, $i] = (1 / $lu[$i, $i]) * ($m[$j, $i] - $sum) + } + } + + # find Ly = b + $y = [double[]]::new($n) + for ($i = 0; $i -lt $n; ++$i) + { + $sum = [double] 0 + for ($k = 0; $k -lt $i; ++$k) + { + $sum += $lu[$i, $k] * $y[$k] + } + $y[$i] = $b[$i] - $sum + } + + # find Ux = y + $x = [double[]]::new($n) + for ($i = $n - 1; $i -ge 0; --$i) + { + $sum = [double] 0 + for ($k = $i + 1; $k -lt $n; ++$k) + { + $sum += $lu[$i, $k] * $x[$k] + } + $x[$i] = (1 / $lu[$i, $i]) * ($y[$i] - $sum) + } + + ,$x +} + +function Get-FleetPolynomialFit +{ + [CmdletBinding()] + param( + [Parameter( + Mandatory = $true + )] + [int] + $Order, + + [Parameter( + Mandatory = $true + )] + [double[]] + $X, + + [Parameter( + Mandatory = $true + )] + [double[]] + $Y + ) + + # + # Return coefficients of least-squares fit for a polynomial of order Order + # over the input X/Y vectors. Return vector a is in ascending order: + # + # a0 + a1 x + a2 x^2 ... = y + # + # System of equations ma = b from polynominal residual function + # Due in part to discussion @ + # https://mathworld.wolfram.com/LeastSquaresFittingPolynomial.html + # https://en.wikipedia.org/wiki/LU_decomposition + # Additional reading: https://neutrium.net/mathematics/least-squares-fitting-of-a-polynomial/ + # + if ($Order -ge $X.Count) + { + Write-Error "Polynomial of order $Order requires at least $($Order + 1) values to fit: $($X.Count) provided" + return $null + } + if ($Y.Count -ne $X.Count) + { + Write-Error "Ranks of X ($($X.Count)) and Y ($($Y.Count)) input vectors not equal" + return $null + } + + # for all col + $m = [double[,]]::new($Order + 1, $Order + 1) + for ($j = 0; $j -le $Order; ++$j) + { + # for all rows below diagonal + for ($i = $j; $i -le $Order; ++$i) + { + # i, j + $m[$i, $j] = ($X |% { [math]::Pow($_, $i + $j) } | Measure-Object -Sum).Sum + # mirror over the diagonal: j, i = i, j + $m[$j, $i] = $m[$i, $j] + } + } + + $b = [double[]]::new($Order + 1) + for ($j = 0; $j -le $Order; ++$j) + { + for ($i = 0; $i -lt $X.Count; ++$i) + { + $b[$j] += [math]::Pow($X[$i], $j) * $Y[$i] + } + } + + $a = SolveLU $m $b + + # calculate residual r2 of the fit + $ssres = [double] 0 + $sstot = [double] 0 + $yMean = ($Y | Measure-Object -Average).Average + for ($i = 0; $i -lt $X.Count; ++$i) + { + $yFit = [double] 0 + for ($j = 0; $j -lt $a.Count; ++$j) + { + $yFit += $a[$j]*[math]::Pow($X[$i], $j) + } + + $ssres += [math]::pow($Y[$i] - $yFit, 2) + $sstot += [math]::pow($Y[$i] - $yMean, 2) + } + + # If sstot is zero this means all measurements are exactly the average value. + # In other words, it is a contstant and the non-constant coefficients are/should + # all be zero with a perfect fit. + if ($sstot -eq 0) + { + $r2 = 1 + } + else + { + $r2 = 1 - ($ssres/$sstot) + } + + + [PsCustomObject] @{ a = $a; r2 = $r2 } +} + +function Use-FleetPolynomialFit +{ + [CmdletBinding()] + param( + [Parameter(Mandatory = $true)] + [double[]] + $A, + + [Parameter(Mandatory = $true)] + [double] + $X + ) + + # Apply the polynomial function defined by the vector of coefficients A + # at the value X. + # + # Y = A0 + A1 X + A2 X^2 + ... + + $accX = [double] 1 + $accY = [double] 0 + foreach ($coeff in $A) + { + $accY += $accX * $coeff + $accX *= $X + } + + $accY +} + +function GetNextSplit +{ + param( + [Parameter(Mandatory = $true)] + [object[]] + $P, + + [Parameter(Mandatory = $true)] + [string] + $V, + + [Parameter(Mandatory = $true)] + [string] + $OrderBy + ) + + # This the adjacent pair of measured points in P with the largest gap in V when ordered by given field. + + $P = $P | Sort-Object -Property $OrderBy + + # Scan for the pair of values with the largest difference. + # Stop if lower result met cutoff conditions - we are willing to interpolate downward from + # a cutoff, but not above one. + $nextIdx = -1 + $nextDelta = 0 + for ($i = 0; $i -lt $P.Count - 1 -and $P[$i].CutoffType -eq [CutoffType]::No; ++$i) + { + $thisDelta = [math]::abs($P[$i + 1].$V - $P[$i].$V) + if ($thisDelta -gt $nextDelta) + { + $nextIdx = $i + $nextDelta = $thisDelta + } + } + + # Return the pair + if ($nextIdx -ge 0) + { + return $P[$nextIdx + 1],$P[$nextIdx] + } + else + { + return $P[0] + } +} + +function GetUpperAnchor +{ + param( + [Parameter(Mandatory = $true)] + [object[]] + $P, + + [Parameter(Mandatory = $true)] + [string] + $OrderBy + ) + + # Single/none + + if ($P.Count -eq 0) { return } + if ($P.Count -eq 1) { return $P[0] } + + # This the adjacent pair of points in P which, when ordered by the given field, the higher of + # which first hit a cutoff or is the highest value. + # + # Return is in descending order (high then low). Return may be none (if no points), one if the + # first point is already at cutoff OR single point present, or two otherwise. If caller says + # $h,$l = GetUpperAnchor then h/l will be $null as appropriate to the case. + + $P = $P | Sort-Object -Property $OrderBy + + $prior = $null + foreach ($pt in $P) + { + if ($pt.CutoffType -ne [CutoffType]::No) { return $pt,$prior } + $prior = $pt + } + + return $P[-1],$P[-2] +} + +function GetDistributedShift +{ + [CmdletBinding()] + param( + [Parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [object[]] + $Group, + + [Parameter(Mandatory = $true)] + [uint32] + $N + ) + + foreach ($g in $Group) + { + if ($g.GetType().Name -ne "Object[]" -and $g.GetType().Name -ne "ArrayList") + { + Write-Error "Group input must be list of lists" + return + } + } + + if ($Group.Count -le 1) + { + Write-Error "Need two or more groups for distributed shift" + return + } + + $counts = @($Group[0].Count) + $e = $false + foreach ($g in $Group[1..($Group.Count - 1)]) + { + $counts += $g.Count + if ($g.Count -ne $counts[0]) + { + $e = $true + } + } + + if ($e) + { + Write-Error "Invalid groups for distributed shift - all must be same size ($($counts -join ' '))" + return + } + + if ($N -eq 0 -or $N -gt $Group[0].Count) + { + Write-Error "Invalid number of VMs/node to rotate - must be 0 < N < $($Group[0].Count)" + return + } + + # + # Distributed Shift: take the N VMs from the end of each ordered set per node and logically rotate + # the resulting groups by an increasing number of positions (1 <= rotation < #groups). + # + # 1: abcde + # 2: fghij + # 3: klmno + # + # => N = 1 + # 1 <= positions rotated + # 1: abcdo + # 2: fghie + # 3: klmnj + # + # => N = 2 + # 21 <= positions rotated + # 1: abcio + # 2: fghne + # 3: klmdj + # + # => N = 3 + # 121 <= positions rotated + # 1: abmio + # 2: fgcne + # 3: klhdj + # + + # + # Build arrays with the bottom elements which will not move. + # + + $arr = @() + + foreach ($g in $Group) + { + if ($N -lt $g.Count) + { + $arr += ,[collections.arraylist]@($g[0..($g.Count - $N - 1)]) + } + else + { + $arr += ,[collections.arraylist]@() + } + } + + # + # Now move across the groups. + # + # This is reversed since rotation amount starts at 1 at the end of the + # array and increases with lower indices. The shift starts in the middle + # and works to the end so we do not modify relative positions (and element + # at index 5 is always at index 5 of a rotation, regardless of how many + # VMs/node are rotated). + # + # Example: when distributing four groups at N = 6 we vary + # between rotating by 1, 2 and 3. This is what it looks + # like in index order + # + # 3 2 1 3 2 1 <- rotation in column + # 0 1 2 3 4 5 <- array index + # + + $rot = 1 + ($N-1)%($arr.Count-1) + for ($srcIdx = -$N; $srcIdx -lt 0; ++$srcIdx) + { + # + # Move across groups in the groups, rotating elements + # + + for($src = 0; $src -lt $arr.Count; ++$src) + { + $dst = ($src + $rot) % $arr.Count + $null = $arr[$dst].Add($Group[$src][$srcIdx]) + } + + # Roll rotation back to max at zero. Reversed since rotation + # is moving in the forward direction through the array. + --$rot + if (-not $rot) { $rot = $arr.Count - 1 } + } + + $arr +} + +function FilterObject +{ + [CmdletBinding()] + param( + [Parameter(ValueFromPipeline = $true)] + $InputObject, + + [Parameter(Mandatory = $true)] + [hashtable] + $Filter + ) + + # + # Utility to filter pipeline objects with an AND equality test + # of all property/values provided in the filter. Note empty + # filter passes every element. + # + + process + { + $pass = $true + + foreach ($k in $Filter.Keys) + { + if ($_.$k -ne $Filter.$k) + { + $pass = $false + break + } + } + + if ($pass) { $_ } + } +} + +function SetCacheBehavior +{ + [CmdletBinding()] + param( + [Parameter()] + [string] + $Cluster = ".", + + [switch] + $PopulateOnFirstMiss + ) + + $property = @{ + Path = 'HKLM:\system\CurrentControlSet\Services\clusbflt\Parameters' + Name = 'CacheFlags' + } + + # Cache behavior modifications are set per node, not at the actual cluster level. This exposes + # a risk that if nodes are down or later added that the behaviors will vary across the cluster. + # This is not desirable, and is at the caller's risk to manage. + $nodes = @(Get-ClusterNode -Cluster $Cluster |? State -eq Up) + + foreach ($node in $nodes) + { + $s = New-PSSession -ComputerName $node + + try + { + $v = Invoke-Command -Session $s { Get-ItemProperty @using:property -ErrorAction SilentlyContinue } + if ($null -eq $v) + { + $currentValue = [uint32] 0 + } + else + { + $currentValue = [uint32] $v.CacheFlags + } + $newValue = $currentValue + + # + # Parameters + # + + if ($PSBoundParameters.ContainsKey('PopulateOnFirstMiss')) + { + $mask = [uint32] 0x80000 + + if ($PopulateOnFirstMiss) { $newValue = $newValue -bor $mask } + else { $newValue = $newValue -band -bnot $mask } + } + + # + # Apply + # + + # Do nothing? + if ($currentValue -eq $newValue) + { + continue + } + + Invoke-Command -session $s { + + # Get control object. If RefreshRegParams is not available, issue warning. + # This is only available with Server 2022+. + $dm = Get-WmiObject -namespace "root\wmi" ClusBfltDeviceMethods + if ($null -eq $dm -or -not (Get-Member -InputObject $dm -Name RefreshRegParams)) + { + Write-Warning "S2D Cache on $($env:COMPUTERNAME) does not support dynamic cache behavior refresh" + return $null + } + + Set-ItemProperty @using:property -Value ([uint32] $using:newValue) -Type ([Microsoft.Win32.RegistryValueKind]::DWord) + + # Trigger refresh - informational object returned which we can discard + $null = $dm.RefreshRegParams() + + # If value is now zero, remove it to keep the registry clean + if ($using:newValue -eq 0) + { + Remove-ItemProperty @using:property + } + } + } + finally + { + Remove-PSSession -Session $s + } + } +} + +function Get-Salt { + $salt = ([char]'a'..[char]'z' + [char]'A'..[char]'Z' + [char]'0'..[char]'9' | Get-Random -Count 4 |% { [char]$_ }) -join '' + Write-Verbose "Generated Salt: $salt" + return $salt; +} + +function Get-ArcConfig { + [CmdletBinding()] + param( + [Parameter()] + [string] + $Cluster = "." + ) + + $controlPath = Get-FleetPath -PathType Control $Cluster + $f = Join-Path $controlPath "arc.json" + if (-not (Test-Path $f)) { + Write-Verbose "arc.json does not exist. Current Arc mode: Disabled." + return $null + } + + $arcConfig = Get-Content -Path $f -Raw | ConvertFrom-Json + return $arcConfig +} + +function Set-ArcConfig { + [CmdletBinding()] + param( + [Parameter()] + [string]$ResourceGroup, + + [Parameter()] + [string]$AzureRegistrationUser, + + [Parameter()] + [string]$AzureRegistrationPassword, + + [Parameter()] + [string]$StoragePathCsv, + + [Parameter()] + [string]$StoragePathName = "arcVmFleetStoragePath", + + [Parameter()] + [string]$ImageName = "arcVmFleetImage", + + [Parameter()] + [bool] + $Enabled = $false, + + [Parameter()] + [switch] + $ResetSalt, + + [Parameter()] + [string] + $Cluster = "." + ) + + if($PSBoundParameters.Count -eq 0){ + Write-Error "Set atleast one property." + return; + } + if($PSBoundParameters.ContainsKey("ResetSalt")) { + $PSBoundParameters.Remove('ResetSalt') | Out-Null + } + $controlPath = Get-FleetPath -PathType Control $Cluster + $f = Join-Path $controlPath "arc.json" + $arcConfig = Get-ArcConfig $Cluster + if(!$arcConfig) { + $arcConfig = new-object PSCustomObject -Property $PSBoundParameters + } + else { + foreach($psbp in $PSBoundParameters.GetEnumerator()) + { + $arcConfig.($psbp.Key) = $psbp.Value + } + } + # Set default values for non-mandatory fields + if($arcConfig.psobject.properties.match('StoragePathName').Count -eq 0) { + $arcConfig | Add-Member -MemberType NoteProperty -Name 'StoragePathName' -Value $StoragePathName + } + if($arcConfig.psobject.properties.match('ImageName').Count -eq 0) { + $arcConfig | Add-Member -MemberType NoteProperty -Name 'ImageName' -Value $ImageName + } + if($arcConfig.psobject.properties.match('Enabled').Count -eq 0) { + $arcConfig | Add-Member -MemberType NoteProperty -Name 'Enabled' -Value $Enabled # disabled by default + } + if(!(Test-ArcConfig $arcConfig)){ + return; + } + $generateSalt = ($arcConfig.psobject.properties.match('Salt').Count -eq 0) -or $ResetSalt + if($generateSalt -or $PSBoundParameters.ContainsKey("ResourceGroup")) { + $retry = 0; + while ($retry -lt 3) { + if($generateSalt) { + $salt = Get-Salt + } + else { + $salt = $arcConfig.Salt + } + $nodes = @(Get-ClusterNode) + $isValidSalt = Invoke-CommonCommand $nodes[0] -InitBlock $CommonFunc -ScriptBlock { + InitializeAndGetArcHCIExtendedLoc $using:arcConfig.AzureRegistrationUser $using:arcConfig.AzureRegistrationPassword $using:arcConfig.ResourceGroup | Out-Null + $vmList = az stack-hci-vm list --resource-group $using:arcConfig.ResourceGroup | ConvertFrom-Json + $reg = "^vm-.{1,}-" + $using:salt + "-\d{3}$" + $vms = $vmList | Where-Object { $_.name -match $reg} + if($null -eq $vms) { return $true } + return $false; + } + + if(!$isValidSalt) { + $generateSalt = $true + $retry++ + } + else { + $arcConfig | Add-Member -MemberType NoteProperty -Name 'Salt' -Value $salt -Force + break + } + } + if($retry -eq 4) { + throw "Unable to create a unique salt with 3 retries. Pick another resource group or run Set-ArcConfig again." + } + } + + $arcConfig | ConvertTo-Json | Set-Content -Path $f -Force:$true + + Write-Host "Configuration updated in $f" +} + +function Test-ArcConfig { + [CmdletBinding()] + param ( + [Parameter(Mandatory=$true)] + [PSCustomObject] + $arcConfig + ) + $isValid = $true + $mandatoryFields = @("ResourceGroup", "AzureRegistrationUser", "AzureRegistrationPassword") + + foreach ($field in $mandatoryFields) { + if($arcConfig.psobject.properties.match($field).Count -eq 0) + { + $isValid = $false; + Write-Error "$field is required." + } + } + return $isValid; +} \ No newline at end of file diff --git a/CristalDiskMark/source/diskspd22/Frameworks/VMFleet/WatchCPU.psm1 b/CristalDiskMark/source/diskspd22/Frameworks/VMFleet/WatchCPU.psm1 new file mode 100644 index 0000000..ddf6106 --- /dev/null +++ b/CristalDiskMark/source/diskspd22/Frameworks/VMFleet/WatchCPU.psm1 @@ -0,0 +1,282 @@ +<# +DISKSPD - VM Fleet + +Copyright(c) Microsoft Corporation +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +#> + +Set-StrictMode -Version 3.0 + +function Watch-FleetCPU +{ + [CmdletBinding()] + param( + [Parameter()] + [string] + $ComputerName = $env:COMPUTERNAME, + + [Parameter()] + [switch] + $Guest, + + [Parameter()] + [int] + $SampleInterval = 2 + ) + + function div-to-width( + [int] $div + ) + { + # 0 - 100 scale + # ex: 4 -> 100/4 = 25 buckets + 1 more for == 100 + 1+100/$div + } + + function center-pad( + [string] $s, + [int] $width + ) + { + if ($width -le $s.length) { + $s + } else { + (' ' * (($width - $s.length)/2) + $s) + } + } + + function get-legend( + [string] $label, + [int] $width, + [int] $div + ) + { + # now produce the scale, a digit at a time in vertical orientation + # at each multiple of 10% which aligns with a measurement bucket. + # the width is the width of the measured values + # + # 0 5 1 + # 0 0 + # 0 + + $lines = @() + $lines += '-' * $width + + foreach ($dig in 0..2) { + $o = foreach ($pos in 0..($width - 1)) { + + $val = $pos * $div + if ($val % 10 -eq 0) { + switch ($dig) { + 0 { if ($val -eq 100) { 1 } else { $val / 10 }} + 1 { if ($val -ne 0) { 0 } else { ' ' }} + 2 { if ($val -eq 100) { 0 } else { ' ' }} + } + } else { ' ' } + } + + $lines += $o -join '' + } + + # trailing comments (horizontal scale name) + $lines += center-pad $label $width + + $lines + } + + # minimum clip, the vertical height available for the cpu core bars + $minClip = 10 + + # these are the valid divisions, in units of percentage width. + # they must evenly divide 100% and either 10% or 20% for scale markings. + # determine which is the best fit based on window width. + + $div = 0 + $divs = 1,2,4,5 + foreach ($i in $divs) { + if ((div-to-width $i) -le [console]::WindowWidth) { + $div = $i + break + } + } + + # if nothing fit ... ask for minimum + # in practice this is not possible, but we check anyway + if ($div -eq 0) { + Write-Error "Window width must be at least $(div-to-width $divs[-1]) columns" + return + } + + $width = div-to-width $div + + # which processor counterset should we use? + # pi is only the root partition if hv is active; when hv is active: + # hvlp is the host physical processors + # hvvp is the guest virtual processors + # via ctrs, hv is active iff hvlp is present and has multiple instances + $cs = Get-Counter -ComputerName $ComputerName -ListSet 'Hyper-V Hypervisor Logical Processor' -ErrorAction SilentlyContinue + $hvactive = $null -ne $cs -and $cs.CounterSetType -eq [Diagnostics.PerformanceCounterCategoryType]::MultiInstance + + if ($Guest -and -not $hvactive) { + Write-Error "Hyper-V is not active on $ComputerName" + return + } + + if ($hvactive) { + if ($Guest) { + $cpuset = "\Hyper-V Hypervisor Virtual Processor(*)\% Guest Run Time" + $legend = get-legend "Percent Guest VCPU Utilization" $width $div + } else { + $cpuset = '\Hyper-V Hypervisor Logical Processor(*)\% Total Run Time' + $legend = get-legend "Percent Host LP Utilization" $width $div + } + } else { + $cpuset = '\Processor Information(*)\% Processor Time' + $legend = get-legend "Percent Processor Utilization" $width $div + } + + # processor performance counter (turbo/speedstep) + # this is used to normalize the total cpu utilization (can be > 100%) + $ppset = '\Processor Information(_Total)\% Processor Performance' + + # account for the constant legend in the window height + # use the remaining height for the vertical cpu core bars. + $clip = [console]::WindowHeight - ($legend.Count + 1) + + # insist on a minimum amount of space + if ($clip -lt $minClip) { + $minWindowHeight = $minClip + $legend.Count + 1 + Write-Error "Window height must be at least $minWindowHeight lines" + return + } + + # set window and buffer size simultaneously so we don't have extra scrollbars + Clear-Host + [console]::SetWindowSize($width, [console]::WindowHeight) + [console]::BufferWidth = [console]::WindowWidth + [console]::BufferHeight = [console]::WindowHeight + + # common params for Get-Counter + $gcParam = @{ + SampleInterval = $SampleInterval + Counter = $cpuset,$ppset + ErrorAction = 'SilentlyContinue' + } + + while ($true) { + + # reset measurements + # these are the vertical height of a cpu bar in each column, e.g. 2 = 2 cpus + $m = @([int] 0) * $width + + # avoid remoting for the local case + if ($ComputerName -eq $env:COMPUTERNAME) { + $ctrs = Get-Counter @gcParam + } else { + $ctrs = Get-Counter @gcParam -ComputerName $ComputerName + } + + # if more than one countersample was returned (ppset + something more), we have data + if ($null -ne $ctrs -and $ctrs.Countersamples.Count -gt 1) + { + # get all specific instances and count them into appropriate measurement bucket + $ctrs.Countersamples |% { + + # get scaling factor for total utility + if ($_.Path -like "*$ppset") { + $pperf = $_.CookedValue/100 + } + + # a cpu: count into appropriate measurement bucket + # (ignore total and/or and per-numa total) + elseif ($_.InstanceName -notlike '*_Total') { + $m[[math]::Floor($_.CookedValue/$div)] += 1 + } + + # get total + # + elseif ($_.InstanceName -eq '_Total') { + $total = $_.CookedValue + } + } + + # now produce the bar area as a series of lines + # work down the veritical altitude of each strip, starting at the clip/top + $altitude = $clip + $lines = do { + $($m |% { + + # top line - if we are potentially clipped, handle + if ($altitude -eq $clip) { + + # clipped? + if ($_ -gt $altitude) { 'x' } + # unclipped but at clip? + elseif ($_ -eq $altitude) { '*' } + # nothing, bar less than altitude + else { ' ' } + + } else { + + # below top line + # >=, output bar + if ($_ -ge $altitude) { '*' } + # <, nothing + else { ' ' } + } + }) -join '' + } while (--$altitude) + + $totalStr = "{0:0.0}%" -f $total + $normalStr = "{0:0.0}%" -f ($total*$pperf) + + # move the cursor to indicate average utilization + # column number is zero based, width is 1-based + $cpos = [math]::Floor(($width - 1)*$total/100) + } + else + { + # Center no data message vertically and horizontally in the frame + + $vpre = [math]::Floor($clip/2) - 1 + $vpost = [math]::Floor($clip/2) + + $lines = @('') * $vpre + $lines += center-pad "No Data Available" $width + $lines += @('') * $vpost + + $totalStr = $normalStr = "---" + + # zero cursor + $cpos = 0 + } + + Clear-Host + Write-Host -NoNewline ($lines + $legend -join "`n") + Write-Host -NoNewLine ("`n" + (center-pad "$ComputerName Total: $totalStr Normalized: $normalStr" $width)) + + # move the cursor to indicate average utilization + # column number is zero based, width is 1-based + [console]::SetCursorPosition($cpos,[console]::CursorTop-$legend.Count) + } +} \ No newline at end of file diff --git a/CristalDiskMark/source/diskspd22/Frameworks/VMFleet/WatchCluster.psm1 b/CristalDiskMark/source/diskspd22/Frameworks/VMFleet/WatchCluster.psm1 new file mode 100644 index 0000000..c7d0908 --- /dev/null +++ b/CristalDiskMark/source/diskspd22/Frameworks/VMFleet/WatchCluster.psm1 @@ -0,0 +1,552 @@ +<# +DISKSPD - VM Fleet + +Copyright(c) Microsoft Corporation +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +#> + +Set-StrictMode -Version 3.0 + +# display name +# ctr name +# display order +# format string +# scalar multiplier + +class CounterColumn { + + [string] $displayname + [string] $setname + [string[]] $ctrname + [int] $width + [string] $fmt + [decimal] $multiplier + [ValidateSet("Average","AverageAggregate","Sum")][string] $aggregate + [boolean] $divider + + CounterColumn( + [string] $displayname, + [string] $setname, + [string[]] $ctrname, + [int] $width, + [string] $fmt, + [decimal] $multiplier, + [string] $aggregate, + [boolean] $divider + ) + { + $this.displayname = $displayname + $this.setname = $setname + $this.ctrname = $ctrname + $this.width = $width + $this.fmt = $fmt + $this.multiplier = $multiplier + $this.aggregate = $aggregate + $this.divider = $divider + + if ($this.width -lt $this.displayname.length + 1) { + $this.width = $this.displayname.length + 1 + } + } +} + +class CounterColumnSet { + + [CounterColumn[]] $columns + [string[]] $counters + [string] $topfmt + [string] $linfmt + [string] $name + + [string] $totalline + [string[]] $nodelines + + CounterColumnSet($name) + { + $this.columns = $null + $this.name = $name + } + + [void] Add([CounterColumn] $c) + { + $this.columns += $c + } + + [void] Seal() + { + # assemble the top-line fmt and per-line fmt strings + # top-line is just strings/width + # per-line adds the (likely numeric) format specifier + $n = 1 + $this.topfmt = $this.linfmt = "{0,-16}" + foreach ($col in $this.columns) { + $str = '' + if ($col.divider) { + $str += '| ' + } + $str += "{$n,-$($col.width)" + $this.topfmt += "$str}" + $this.linfmt += "$($str):$($col.fmt)}" + + $n += 1 + } + + # assemble the list of counter instances that will be needed + # note that some may be internally aggregated (i.e., total = read + write) + # in cases where a counterset does not provide an explicit total + $this.counters = ($this.columns |% { + $s = $_.setname + $_.ctrname |% { "\$($s)(_Total)\$($_)" } + } | group -NoElement).Name + } + + [void] DisplayPre( + [hashtable] $samples, + [hashtable] $psamples + ) + { + # aggregate each column across all live sampled nodes + $this.totalline = $this.linfmt -f $( + "Total" + foreach ($col in $this.columns) { + + # average aggreate doesn't work across nodes if the base is not consistent + # for instance: cannot average latency safely, but can average cpu utilization + if ($col.aggregate -ne 'Average' -or $col.aggregate -eq 'AverageAggregate') { + $(foreach ($node in $psamples.keys) { + get-samples $psamples $node $col + }) | get-aggregate $col + } else { + $null + } + } + ) + + # individual nodes + # flags downed/non-responsive nodes by noting which are not + # present in the processed samples + $this.nodelines = foreach ($node in $samples.keys | sort) { + if ($psamples.ContainsKey($node)) { + $this.linfmt -f $( + $node + foreach ($col in $this.columns) { + $s = get-samples $psamples $node $col + if ($null -ne $s) { + $a = $s | get-aggregate $col + $a + } else { + "-" + } + } + ) + } else { + $this.topfmt -f $( + $node + 0..($this.columns.count - 1) |% { "-" } + ) + } + } + } + + [void] Display() + { + write-host ($this.topfmt -f (,$this.name + $this.columns.displayname)) + write-host -fore green $this.totalline + $this.nodelines |% { write-host $_ } + } +} + +function Watch-FleetCluster +{ + + [CmdletBinding()] + param( + [Parameter()] + [string] + $Cluster = ".", + + [Parameter()] + [int] + $SampleInterval = 2, + + [Parameter()] + [ValidateSet("CSV FS","SSB Cache","SBL","SBL Local","SBL Remote","SBL*","S2D BW","Hyper-V LCPU","SMB SRV","SMB Transport","*")] + [string[]] $Sets = "CSV FS", + + [Parameter()] + [string] + $LogFile + ) + + if ($PSBoundParameters.ContainsKey('LogFile')) + { + $script:log = $LogFile + Remove-Item -Force $log -ErrorAction SilentlyContinue + } + + function WriteLog( + [Parameter(ValueFromPipeline = $true)] + [string[]] + $String + ) + { + PROCESS { + if ($null -ne $script:log) { + "$(get-date) $String" | Out-File -Append -FilePath $script:log -Width 9999 -Encoding ascii + } + } + } + + function get-aggregate( + [CounterColumn] $col + ) + { + BEGIN { + $n = 0 + $v = 0 + } + PROCESS { + $n += 1 + $v += $_ + } + END { + if ($n -gt 0) { + switch -wildcard ($col.aggregate) { + 'Sum' { + #write-host $col.displayname $col.multipler $v + $col.multiplier * $v + } + 'Average*' { + #write-host $col.displayname $col.multiplier $v $n + $col.multiplier * $v / $n + } + } + } else { + $null + } + } + } + + # get samples out of per-node hash of ctr hashes + function get-samples( + [hashtable] $h, + [string] $node, + [CounterColumn] $col + ) + { + foreach ($i in $col.ctrname) { + + $k = "$($col.setname)+$($i)" + + if ($h.ContainsKey($node)) { + if ($h[$node].ContainsKey($k)) { + $h[$node][$k] + } else { + WriteLog "missing $node[$k] : $($h[$node].Keys.Count) total keys" + } + } else { + WriteLog "missing $node" + } + } + } + + $allctrs = @() + + ### + $c = [CounterColumnSet]::new("CSV FS") + $c.Add([CounterColumn]::new("IOPS", "Cluster CSVFS", @("Reads/sec","Writes/sec"), 12, '#,#', 1, 'Sum', $false)) + $c.Add([CounterColumn]::new("Reads", "Cluster CSVFS", @("Reads/sec"), 12, '#,#', 1, 'Sum', $false)) + $c.Add([CounterColumn]::new("Writes", "Cluster CSVFS", @("Writes/sec"), 12, '#,#', 1, 'Sum', $false)) + + $c.Add([CounterColumn]::new("BW (MB/s)", "Cluster CSVFS", @("Read Bytes/sec","Write Bytes/sec"), 13, '#,#', 0.000001, 'Sum', $true)) + $c.Add([CounterColumn]::new("Read", "Cluster CSVFS", @("Read Bytes/sec"), 8, '#,#', 0.000001, 'Sum', $false)) + $c.Add([CounterColumn]::new("Write", "Cluster CSVFS", @("Write Bytes/sec"), 8, '#,#', 0.000001, 'Sum', $false)) + + $c.Add([CounterColumn]::new("Read Lat (ms)", "Cluster CSVFS", @("Avg. sec/Read"), 15, '0.000', 1000, 'Average', $true)) + $c.Add([CounterColumn]::new("Write", "Cluster CSVFS", @("Avg. sec/Write"), 8, '0.000', 1000, 'Average', $false)) + + $c.Add([CounterColumn]::new("Read QAvg", "Cluster CSVFS", @("Avg. Read Queue Length"), 11, '0.000', 1, 'Average', $true)) + $c.Add([CounterColumn]::new("Write", "Cluster CSVFS", @("Avg. Write Queue Length"), 8, '0.000', 1, 'Average', $false)) + + $c.Seal() + $allctrs += $c + + ### + $c = [CounterColumnSet]::new("SSB Cache") + + $c.Add([CounterColumn]::new("Hit/Sec", "Cluster Storage Hybrid Disks", @("Cache Hit Reads/Sec"), 12, '#,#', 1, 'Sum', $false)) + $c.Add([CounterColumn]::new("Miss/Sec", "Cluster Storage Hybrid Disks", @("Cache Miss Reads/Sec"), 12, '#,#', 1, 'Sum', $false)) + $c.Add([CounterColumn]::new("Remap/Sec" ,"Cluster Storage Cache Stores", @("Page ReMap/sec"), 12, '#,#', 1, 'Sum', $false)) + + $c.Add([CounterColumn]::new("Cache (MB/s)", "Cluster Storage Hybrid Disks", @("Cache Populate Bytes/sec","Cache Write Bytes/sec"), 13, '#,#', 0.000001, 'Sum', $true)) + $c.Add([CounterColumn]::new("RdPop", "Cluster Storage Hybrid Disks", @("Cache Populate Bytes/sec"), 8, '#,#', 0.000001, 'Sum', $false)) + $c.Add([CounterColumn]::new("WrPop", "Cluster Storage Hybrid Disks", @("Cache Write Bytes/sec"), 8, '#,#', 0.000001, 'Sum', $false)) + + $c.Add([CounterColumn]::new("Destage (MB/s)", "Cluster Storage Cache Stores", @("Destage Bytes/sec"), 15, '#,#', 0.000001, 'Sum', $true)) + $c.Add([CounterColumn]::new("Update", "Cluster Storage Cache Stores", @("Update Bytes/sec"), 7, '#,#', 0.000001, 'Sum', $false)) + + $c.Add([CounterColumn]::new("Total (Pgs)", "Cluster Storage Cache Stores", @("Cache Pages"), 11, '0.00E+0', 1, 'Sum', $true)) + $c.Add([CounterColumn]::new("Standby", "Cluster Storage Cache Stores", @("Cache Pages StandBy"), 9, '0.00E+0', 1, 'Sum', $false)) + $c.Add([CounterColumn]::new("L0", "Cluster Storage Cache Stores", @("Cache Pages StandBy L0"), 9, '0.00E+0', 1, 'Sum', $false)) + $c.Add([CounterColumn]::new("L1", "Cluster Storage Cache Stores", @("Cache Pages StandBy L1"), 9, '0.00E+0', 1, 'Sum', $false)) + $c.Add([CounterColumn]::new("L2", "Cluster Storage Cache Stores", @("Cache Pages StandBy L2"), 9, '0.00E+0', 1, 'Sum', $false)) + $c.Add([CounterColumn]::new("Dirty", "Cluster Storage Cache Stores", @("Cache Pages Dirty"), 9, '0.00E+0', 1, 'Sum', $false)) + + $c.Seal() + $allctrs += $c + + ### + + foreach ($subset in '','Local','Remote') { + $name = 'SBL' + $prefix = '' + if ($subset.Length) { + $name += " $subset" + $prefix = "$($subset): " + } + + $c = [CounterColumnSet]::new($name) + + $c.Add([CounterColumn]::new("IOPS", "Cluster Disk Counters", @(($prefix + "Read/sec"),($prefix + "Writes/sec")), 12, '#,#', 1, 'Sum', $false)) + $c.Add([CounterColumn]::new("Reads", "Cluster Disk Counters", @($prefix + "Read/sec"), 12, '#,#', 1, 'Sum', $false)) + $c.Add([CounterColumn]::new("Writes", "Cluster Disk Counters", @($prefix + "Writes/sec"), 12, '#,#', 1, 'Sum', $false)) + + $c.Add([CounterColumn]::new("BW (MB/s)", "Cluster Disk Counters", @(($prefix + "Read - Bytes/sec"),($prefix + "Write - Bytes/sec")), 13, '#,#', 0.000001, 'Sum', $true)) + $c.Add([CounterColumn]::new("Read", "Cluster Disk Counters", @($prefix + "Read - Bytes/sec"), 8, '#,#', 0.000001, 'Sum', $false)) + $c.Add([CounterColumn]::new("Write", "Cluster Disk Counters", @($prefix + "Write - Bytes/sec"), 8, '#,#', 0.000001, 'Sum', $false)) + + $c.Add([CounterColumn]::new("Read Lat (ms)", "Cluster Disk Counters", @($prefix + "Read Latency"), 15, '0.000', 1000, 'Average', $true)) + $c.Add([CounterColumn]::new("Write", "Cluster Disk Counters", @($prefix + "Write Latency"), 8, '0.000', 1000, 'Average', $false)) + + $c.Add([CounterColumn]::new("Read QAvg", "Cluster Disk Counters", @($prefix + "Read Avg. Queue Length"), 11, '0.000', 1, 'Average', $true)) + $c.Add([CounterColumn]::new("Write", "Cluster Disk Counters", @($prefix + "Write Avg. Queue Length"), 8, '0.000', 1, 'Average', $false)) + + $c.Seal() + $allctrs += $c + } + + ### + $c = [CounterColumnSet]::new("SMB SRV") + + $c.Add([CounterColumn]::new("IOPS", "SMB Server Shares", @("Data Requests/sec"), 12, '#,#', 1, 'Sum', $false)) + $c.Add([CounterColumn]::new("Reads", "SMB Server Shares", @("Read Requests/sec"), 12, '#,#', 1, 'Sum', $false)) + $c.Add([CounterColumn]::new("Writes", "SMB Server Shares", @("Write Requests/sec"), 12, '#,#', 1, 'Sum', $false)) + + $c.Add([CounterColumn]::new("Data BW (MB/s)", "SMB Server Shares", @("Data Bytes/sec"), 13, '#,#', 0.000001, 'Sum', $true)) + $c.Add([CounterColumn]::new("Read", "SMB Server Shares", @("Read Bytes/sec"), 8, '#,#', 0.000001, 'Sum', $false)) + $c.Add([CounterColumn]::new("Write", "SMB Server Shares", @("Write Bytes/sec"), 8, '#,#', 0.000001, 'Sum', $false)) + + $c.Add([CounterColumn]::new("Total BW (MB/s)", "SMB Server Shares", @("Transferred Bytes/sec"), 13, '#,#', 0.000001, 'Sum', $true)) + $c.Add([CounterColumn]::new("Rcv", "SMB Server Shares", @("Received Bytes/sec"), 8, '#,#', 0.000001, 'Sum', $false)) + $c.Add([CounterColumn]::new("Snd", "SMB Server Shares", @("Sent Bytes/sec"), 8, '#,#', 0.000001, 'Sum', $false)) + + $c.Seal() + $allctrs += $c + + ## + $c = [CounterColumnSet]::new("S2D BW") + + $c.Add([CounterColumn]::new("CSV (MB/s)", "Cluster CSVFS", @("Read Bytes/sec","Write Bytes/sec"), 10, '#,#', 0.000001, 'Sum', $false)) + $c.Add([CounterColumn]::new("Read", "Cluster CSVFS", @("Read Bytes/sec"), 8, '#,#', 0.000001, 'Sum', $false)) + $c.Add([CounterColumn]::new("Write", "Cluster CSVFS", @("Write Bytes/sec"), 8 ,'#,#', 0.000001, 'Sum', $false)) + + $c.Add([CounterColumn]::new("SBL (MB/s)", "Cluster Disk Counters", @("Read - Bytes/sec","Write - Bytes/sec"), 10, '#,#', 0.000001, 'Sum', $true)) + $c.Add([CounterColumn]::new("Read", "Cluster Disk Counters", @("Read - Bytes/sec"), 8, '#,#', 0.000001, 'Sum', $false)) + $c.Add([CounterColumn]::new("Write", "Cluster Disk Counters", @("Write - Bytes/sec"), 8, '#,#', 0.000001, 'Sum', $false)) + + $c.Add([CounterColumn]::new("Cache (MB/s)", "Cluster Storage Hybrid Disks", @("Cache Hit Read Bytes/sec","Cache Write Bytes/sec"), 12, '#,#', 0.000001, 'Sum', $true)) + $c.Add([CounterColumn]::new("Read", "Cluster Storage Hybrid Disks", @("Cache Hit Read Bytes/sec"), 8, '#,#', 0.000001, 'Sum', $false)) + $c.Add([CounterColumn]::new("Write", "Cluster Storage Hybrid Disks", @("Cache Write Bytes/sec"), 8, '#,#', 0.000001, 'Sum', $false)) + + $c.Add([CounterColumn]::new("Disk (MB/s)", "Cluster Storage Hybrid Disks", @("Disk Read Bytes/sec","Disk Write Bytes/sec"), 11, '#,#', 0.000001, 'Sum', $true)) + $c.Add([CounterColumn]::new("Read", "Cluster Storage Hybrid Disks", @("Disk Read Bytes/sec"), 8, '#,#', 0.000001, 'Sum', $false)) + $c.Add([CounterColumn]::new("Write", "Cluster Storage Hybrid Disks", @("Disk Write Bytes/sec"), 8, '#,#', 0.000001, 'Sum', $false)) + + $c.Seal() + $allctrs += $c + + ## + $c = [CounterColumnSet]::new("Hyper-V LCPU") + $c.Add([CounterColumn]::new("Logical Total%", "Hyper-V Hypervisor Logical Processor", @("% Total Run Time"), 8, "0.00", 1, 'AverageAggregate', $false)) + $c.Add([CounterColumn]::new("Guest%", "Hyper-V Hypervisor Logical Processor", @("% Guest Run Time"), 8, "0.00", 1, 'AverageAggregate', $false)) + $c.Add([CounterColumn]::new("Hypervisor%", "Hyper-V Hypervisor Logical Processor", @("% Hypervisor Run Time"), 13, "0.00", 1, 'AverageAggregate', $false)) + + $c.Add([CounterColumn]::new("Root Total%", "Hyper-V Hypervisor Root Virtual Processor", @("% Total Run Time"), 12, "0.00", 1, 'AverageAggregate', $true)) + $c.Add([CounterColumn]::new("Guest%", "Hyper-V Hypervisor Root Virtual Processor", @("% Guest Run Time"), 8, "0.00", 1, 'AverageAggregate', $false)) + $c.Add([CounterColumn]::new("Hypervisor%", "Hyper-V Hypervisor Root Virtual Processor", @("% Hypervisor Run Time"), 12, "0.00", 1, 'AverageAggregate', $false)) + $c.Add([CounterColumn]::new("Remote%", "Hyper-V Hypervisor Root Virtual Processor", @("% Remote Run Time"), 7, "0.00", 1, 'AverageAggregate', $false)) + + $c.Seal() + $allctrs += $c + + ## + $c = [CounterColumnSet]::new("SMB Transport") + $c.add([CounterColumn]::new("Read IOPS", "SMB Client Shares", @("Read Requests/sec"), 11, "#,#", 1, 'Sum', $false)) + $c.add([CounterColumn]::new("Write", "SMB Client Shares", @("Write Requests/sec"), 8, "#,#", 1, 'Sum', $false)) + + $c.add([CounterColumn]::new("RDMA Read", "SMB Client Shares", @("Read Requests transmitted via SMB Direct/sec"), 11, "#,#", 1, 'Sum', $true)) + $c.add([CounterColumn]::new("Write", "SMB Client Shares", @("Write Requests transmitted via SMB Direct/sec"), 8, "#,#", 1, 'Sum', $false)) + + $c.Seal() + $allctrs += $c + + ## + if ($Sets.Count -eq 1 -and $Sets[0] -eq '*') { + $ctrs = $allctrs + } else { + $ctrs = $Sets |% { + $s = $_ + $allctrs |? { $_.name -like $s } # allows the SBL* wildcard + } + } + + function start-sample( + [CounterColumnSet[]] $ctrs, + [int] $SampleInterval + ) + { + # clear any previous job instance + Get-Job -Name watch-cluster -ErrorAction SilentlyContinue | Stop-Job + Get-Job -Name watch-cluster -ErrorAction SilentlyContinue | Remove-Job + + # flatten list of counters and uniquify for the total counter set + # some display counter sets may repeat specific values (which is fine) + $counters = ($ctrs.counters |% { $_ |% { $_ }} | group -NoElement).Name + + icm -AsJob -JobName watch-cluster (Get-ClusterNode -Cluster $Cluster) { + + # extract countersamples, the object does not survive transfer between powershell sessions + # extract as a list, not as the individual counters + get-counter -Continuous -SampleInterval $using:SampleInterval $using:ctrs.counters |% { + ,$_.countersamples + } + } + } + + # start the first sample job and allow frame draw the first time through + $j = start-sample $ctrs $SampleInterval + $downtime = $null + $skipone = $false + $loops = 0 + $restart = $false + + # hash of most recent samples/node + $samples = @{} + Get-ClusterNode -Cluster $Cluster |% { $samples[$_.Name] = $null } + + while ($true) { + + if (-not $restart) { + Start-Sleep -Seconds $SampleInterval + + # sleep again if needed to prime the sample pipeline; + # there are no samples if we just restarted the sampling jobs + if ($skipone) { + $skipone = $false + continue + } + + # receive updates into the per-node hash + foreach ($child in $j.ChildJobs) { + $samples[$child.Location] = $child | receive-job -ErrorAction SilentlyContinue + } + + # null out downed nodes and remember first time we saw one drop out + $down = 0 + $j.ChildJobs |? State -ne Running |% { + $samples[$_.Location] = $null + $down += 1 + } + if ($down -and $null -eq $downtime) { + $downtime = get-date + } + + # if everything is down, we will attempt restart + if ($down -eq $j.ChildJobs.Count) { + $restart = $true + break + } + } + + # if explicit restart is required, or it has been 30 seconds with a downed node, restart the jobs to retry + if ($restart -or ($null -ne $downtime -and ((get-date)-$downtime).totalseconds -gt 30)) { + $j | stop-job + $j | remove-job + $j = start-sample $ctrs $SampleInterval + + # force gc to clear out accumulated job state quickly + [system.gc]::Collect() + + $downtime = $null + $skipone = $true + $restart = $false + continue + } + + # now process samples into per-node hashes of set/ctr containing lists of the + # cooked values acrosss the (possible) multiple instances + $psamples = @{} + foreach ($node in $samples.keys) { + + if ($samples[$node]) { + + $nsamples = @{} + + # flatten samples - if we are lagging, we'll have a list + # of consecutive (increasing by timestamp) samples + # we could try to be more efficient by dumping all but the + # final sample, but later ... + $samples[$node] |% { $_ } |% { + + ($setinst,$ctr) = $($_.path -split '\\')[3..4] + $set = ($setinst -split '\(')[0] + + $k = "$set+$ctr" + $nsamples[$k] = $_.cookedvalue + } + + $psamples[$node] = $nsamples + } + } + + # post-process the samples into the counterset, then clear and dump + $ctrs.DisplayPre($samples, $psamples) + Clear-Host + $drawsep = $false + $ctrs |% { + if ($drawsep) { + write-host -fore Green $('-'*20) + } + $drawsep = $true + $_.Display() + + } + + # restart the jobs every so many loops to prevent resource growth + $loops += 1 + if ($loops -gt 100) { + $loops = 0 + $restart = $true + } + } +} \ No newline at end of file diff --git a/CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/README.md b/CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/README.md new file mode 100644 index 0000000..3b3fe94 --- /dev/null +++ b/CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/README.md @@ -0,0 +1,47 @@ +## VM Fleet ## + +These are the historical release comments for VM Fleet 1.0. + +VM Fleet 0.9 10/2017 (minor) + +* watch-cpu: now provides total normalized cpu utility (accounting for turbo/speedstep) +* sweep-cputarget: now provides average CSV FS read/write latency in the csv + +VM Fleet 0.8 6/2017 + +* get-cluspc: add SMB Client/Server and SMB Direct (not defaulted in Storage group yet) +* test-clusterhealth: flush output pipeline for Debug-StorageSubsystem output +* watch-cluster: restart immediately if all child jobs are no longer running +* watch-cpu: new, visualizer for CPU core utilization distributions + +VM Fleet 0.7 3/2017 + +* create/destroy-vmfleet & update-csv: don't rely on the csv name containing the friendlyname of the vd +* create-vmfleet: err if basevhd inaccessible +* create-vmfleet: simplify call-throughs using $using: syntax +* create-vmfleet: change vhdx layout to match scvmm behavior of seperate directory per VM (important for ReFS MRV) +* create-vmfleet: use A1 VM size by default (1VCPU 1.75GiB RAM) +* start-vmfleet: try starting "failed" vms, usually works +* set-vmfleet: add support for -SizeSpec for A/D/D2v1 & v2 size specification, for ease of reconfig +* stop-vmfleet: pass in full namelist to allow best-case internal parallelization of shutdown +* sweep-cputarget: use %Processor Performance to rescale utilization and account for Turbo effects +* test-clusterhealth: support cleaning out dumps/triage material to simplify ongoing monitoring (assume they're already gathered/etc.) +* test-clusterhealth: additional triage output for storport unresponsive device events +* test-clusterhealth: additional triage comments on SMB client connectivity events +* test-clusterhealth: new test for Mellanox CX3/CX4 error counters that diagnose fabric issues (bad cable/transceiver/roce specifics/etc.) +* get-log: new triage log gatherer for all hv/clustering/smb event channels +* get-cluspc: new cross-cluster performance counter gatherer +* remove run-<>.ps1 scripts that were replaced with run-demo-<>.ps1 +* check-outlier: EXPERIMENTAL way to ferret out outlier devices in the cluster, using average sampled latency + +VM Fleet 0.6 7/18/2016 + +* CPU Target Sweep: a sweep script using StorageQoS and a linear CPU/IOPS model to build an empirical sweep of IOPS as a function of CPU, initially for the three classic small IOPS mixes (100r, 90:10 and 70:30 4K). Includes an analysis script which provides the linear model for each off of the results. +* Update sweep mechanics which allow generalized specification of DISKSPD sweep parameters and host performance counter capture. +* install-vmfleet to automate placement after CSV/VD structure is in place (add path, create dirs, copyin, pause) +* add non-linearity detection to analyze-cputarget +* get-linfit is now a utility script (produces objects describing fits) +* all flag files (pause/go/done) pushed down to control\flag directory +* demo scripting works again and autofills vm/node counts +* watch-cluster handles downed/recovered nodes gracefully +* update-csv now handles node names which are logical prefixes of another (node1, node10) \ No newline at end of file diff --git a/CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/analyze-cputarget.ps1 b/CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/analyze-cputarget.ps1 new file mode 100644 index 0000000..5b4526a --- /dev/null +++ b/CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/analyze-cputarget.ps1 @@ -0,0 +1,79 @@ +param( + [string] $csvfile = $(throw "please provide the path to a cputarget sweep result file"), + [switch] $zerointercept = $false, + [int] $sigfigs = 5 + ) + +function get-sigfigs( + [decimal]$value, + [int]$sigfigs + ) +{ + $log = [math]::Ceiling([math]::log10([math]::abs($value))) + $decimalpt = $sigfigs - $log + + # if all sigfigs are above the decimal point, round off to + # appropriate power of 10 + if ($decimalpt -lt 0) { + $pow = [math]::Abs($decimalpt) + $decimalpt = 0 + $value = [math]::Round($value/[math]::Pow(10,$pow))*[math]::pow(10,$pow) + } + + "{0:F$($decimalpt)}" -f $value +} + +write-host -ForegroundColor Green CPU Target Sweep Report`n +write-host -ForegroundColor Green The following equations and coefficients are the linear +write-host -ForegroundColor Green fit to the measured results at the given write ratios. +write-host -ForegroundColor Cyan ("-"*20) + +write-host -ForegroundColor Yellow NOTE: take care that these formula are only used to reason about +write-host -ForegroundColor Yellow " " the region where these values are in a linear relationship. +write-host -ForegroundColor Yellow " In particular, at high AVCPU the system may be saturated." +write-host -ForegroundColor Yellow "Use R^2 (coefficient of determination) as a quality check for the fit." +write-host -ForegroundColor Yellow "Values close to 100% mean that the data is indeed linear. If R2 is" +write-host -ForegroundColor Yellow "significantly less than 100%, a closer look at system behavior may" +write-host -ForegroundColor Yellow "be required." + +if ($zerointercept) { + write-host -ForegroundColor Red NOTE: forcing to a "(AVCPU=0,IOPS=0)" intercept may introduce error +} else { + write-host -ForegroundColor Red "NOTE: with a non-zero constant coefficient, care should be used at`nlow AVCPU that the result is meaningful" +} + +# do the check fit of QoS to IOPS +# this will let us check for non-CPU limited saturation (poor r2 is a giveaway) +# we can have an excellent CPU->IOPS fit but not actually have been able to stress in much CPU +# and have lots of repeated measurements as we tried to step up QoS +$h = @{} +get-linfit -csvfile $csvfile -xcol QOS -ycol IOPS -idxcol WriteRatio -zerointercept:$zerointercept |% { + $h[$_.Key] = $_ +} + +# now fit IOPS to Average CPU +get-linfit -csvfile $csvfile -xcol AVCPU -ycol IOPS -idxcol WriteRatio -zerointercept:$zerointercept | sort -Property Key |% { + + write-host -ForegroundColor Cyan ("-"*20) + write-host $_.Key + + if ($zerointercept) { + write-host ("{0} = {1}({2})" -f $_.Y,$(get-sigfigs $_.B $sigfigs),$_.X) + } else { + + if ($_.A -ge 0) { + $sign = "+" + } else { + $sign = "" + } + + write-host ("{0} = {1}({2}){4}{3}" -f $_.Y,$(get-sigfigs $_.B $sigfigs),$_.X,$(get-sigfigs $_.A $sigfigs),$sign) + } + + write-host ("N = {1}`nR^2 goodness of fit {0:P2}" -f $_.R2,$_.N) + if ($h[$_.Key].R2 -le 0.5) { + write-host -ForegroundColor Yellow "WARNING: for $($_.Key) it does not appear that IOPS moved in" + write-host -ForegroundColor Yellow "`trelation to attempts to raise the QoS limit. Check if the" + write-host -ForegroundColor Yellow "`tsystem is storage limited for this mix." + } +} \ No newline at end of file diff --git a/CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/check-outlier.ps1 b/CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/check-outlier.ps1 new file mode 100644 index 0000000..ffc621c --- /dev/null +++ b/CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/check-outlier.ps1 @@ -0,0 +1,201 @@ +<# +DISKSPD - VM Fleet + +Copyright(c) Microsoft Corporation +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +#> + +param ( + [int] $interval = 10 + ) + +class RunningStat { + + # This is an implementation of an online (add one value at a time) method to calculate + # up to the fourth central moment (mean, variance, skewness and kurtosis) of a series + # of decimal values. + # + # Implementation is due to https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance + # which is in turn due http://people.xiph.org/~tterribe/notes/homs.html by Timothy Terriberry, + # also cited by Pebay: http://prod.sandia.gov/techlib/access-control.cgi/2008/086212.pdf + # + # Note: skewness appears to match Excel calculations. Kurtosis does NOT at this time, and + # should be used with caution. + + [decimal] $n; + [decimal] $M1; + [decimal] $M2; + [decimal] $M3; + [decimal] $M4; + [decimal] $Min; + [decimal] $Max; + + RunningStat() + { + $this.M1 = 0 + $this.M2 = 0 + $this.M3 = 0 + $this.M4 = 0 + $this.Min = 0 + $this.Max = 0 + } + + [void] Clear() + { + $this.M1 = 0 + $this.M2 = 0 + $this.M3 = 0 + $this.M4 = 0 + $this.Min = 0 + $this.Max = 0 + } + + [void] Add([decimal] $v) + { + $n1 = $this.n + $this.n += 1 + $delta = $v - $this.M1 + $deltan = $delta / $this.n + $deltan2 = $deltan * $deltan + $term1 = $delta * $deltan * $n1 + $this.M1 += $deltan + $this.M4 += $term1 * $deltan2 * (($this.n * $this.n) - (3 * $this.n) + 3) + (6 * $deltan2 * $this.M2) - (4 * $deltan * $this.M3) + $this.M3 += $term1 * $deltan * ($this.n - 2) - (3 * $deltan * $this.M2) + $this.M2 += $term1 + + if ($n1 -eq 0 -or $v -gt $this.Max) { $this.Max = $v } + if ($n1 -eq 0 -or $v -lt $this.Min) { $this.Min = $v } + } + + [decimal] Min() + { + return $this.Min + } + + [decimal] Max() + { + return $this.Max + } + + [decimal] Mean() + { + return $this.M1 + } + + [decimal] Variance() + { + return $this.M2/($this.n - 1) + } + + [decimal] StdDev() + { + return [math]::Sqrt($this.Variance()) + } + + [decimal] Skew() + { + return [math]::Sqrt($this.n) * $this.M3 / [math]::Pow($this.M2, 1.5) + } + + [decimal] Kurtosis() + { + return (($this.n * $this.M4) / ($this.M2 * $this.M2)) - 3 + } +} + +# populate a hash by sbl device number +$dev = gwmi -Namespace root\wmi ClusPortDeviceInformation +$devhash = @{} +$dev |% { $devhash[[int]$_.devicenumber] = $_ } + +function get-outliers( + [string[]] $paths + ) +{ + # filters and labels for the sigma buckets + $sigflt = @(@(">5", '$sig -gt 5'), + @("4-5", '$sig -gt 4 -and $sig -le 5'), + @("3-4", '$sig -gt 3 -and $sig -le 4')) |% { + + new-object -TypeName psobject -Property @{ + Label = $_[0]; + Test= $_[1]; + } + } + + $ctrs = (get-counter -ComputerName (get-clusternode |? State -eq Up) -SampleInterval $interval -Counter $($paths |% { "\Cluster Disk Counters(*)\$_" })).countersamples |? { $_.instancename -ne "_total" } + $stat = [RunningStat]::new() + + foreach ($path in $paths) { + + # select out the specific subset of the counters (read, write, etc.) + $ctr = $ctrs |? { $_.Path -like "*$path" } + + $stat.Clear() + $ctr.CookedValue |% { $stat.Add($_) } + $stddev = $stat.StdDev() + $mean = $stat.Mean() + + # hash of flagged devices + $flagged = @{} + + write-host -ForegroundColor Green ("-"*20) + write-host -ForegroundColor green Sample: $path + write-host Number of measured devices: $ctr.count + write-host Average of $("$path : {0:F3}ms" -f ($mean*1000)) + write-host Standard Deviation of $("{0:F3}ms" -f ($stddev*1000)) + + # enumerate from highest to lowest deviation of merit + foreach ($sigma in $sigflt) { + + # get new outliers at this deviation + $outlier = $ctr | sort -property InstanceName |? { + if ($stddev -eq 0) { $sig = 0 } else { $sig = (($_.CookedValue -$mean)/$stddev) } + -not $flagged[$_.InstanceName] -and (iex $sigma.Test) + } + + if ($outlier) { + + write-host -fore Yellow $sigma.Label sigma : $outlier.count total + $outlier |% { + + # remember we flagged this device already + $flagged[$_.InstanceName] = 1 + + $thisdev = $devhash[[int]$_.InstanceName] + + # parse source node + # \\foo\... -> 0 1 2=foo 3 ... + $sourcenode = ($_.Path -split '\\')[2] + + write-host -ForegroundColor Red $sourcenode SSB Device: $_.InstanceName`n`tAverage of $path $("{0:F3}ms ({1:F1} sigma)" -f ($_.CookedValue * 1000),(($_.CookedValue -$mean)/$stddev)) + write-host -ForegroundColor Red "`tConnected Node:" $thisdev.ConnectedNode + write-host -ForegroundColor Red "`tConnected Node Local PhysicalDisk Number:" $thisdev.ConnectedNodeDeviceNumber + write-host -ForegroundColor Red "`tModel | SerialNumber: $($thisdev.ProductId)` | $($thisdev.SerialNumber)" + } + } + } + } +} + +get-outliers -paths "Remote: Read Latency","Local: Read Latency","Remote: Write Latency","Local: Write Latency" \ No newline at end of file diff --git a/CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/check-pause.ps1 b/CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/check-pause.ps1 new file mode 100644 index 0000000..a353129 --- /dev/null +++ b/CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/check-pause.ps1 @@ -0,0 +1,90 @@ +<# +DISKSPD - VM Fleet + +Copyright(c) Microsoft Corporation +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +#> + +# script to check the state/health of pause in the fleet +# +# isactive - whether there is an active pause (independent of health) +# !isactive - whether there is an active pause and all VMs have responded to it +# +# true/false return + +param( + [switch] $isactive = $false + ) + +$pause = "C:\ClusterStorage\collect\control\flag\pause" +$pauseepoch = gc $pause -ErrorAction SilentlyContinue + +if ($pauseepoch -eq $null) { + write-host -fore red Pause not in force + return $false +} + +# if only performing the pause active check, done +if ($isactive) { + return $true +} + +# accumulate hash of pause flags mapped to current/stale state +$h = @{} + +dir $pause-* |% { + + $thispause = gc $_ -ErrorAction SilentlyContinue + if ($thispause -eq $pauseepoch) { + $pausetype = 'Current' + } else { + $pausetype = 'Stale' + } + + if ($_.name -match 'pause-(.+)\+(vm.+)') { + # 1 is CSV, 2 is VM name + $h[$matches[2]] = $pausetype + } else { + write-host -fore red ERROR: malformed pause $_.name present + } +} + +# now correlate to online vms and see if we agree all online are paused. +# note that if we shutdown some vms and then check pause the current flags +# will be higher than online, so we need to verify individually to not +# spoof ourselves. + +$vms = get-clustergroup |? GroupType -eq VirtualMachine |? Name -like 'vm-*' |? State -eq Online + +$pausedvms = $vms |? { $h[$_.Name] -eq 'Current' } + +if ($pausedvms.Count -eq $vms.Count) { + write-host -fore green OK: All $vms.count VMs paused +} else { + write-host -fore red WARNING: of "$($vms.Count)," still waiting on ($vms.Count - $pausedvms.Count) to acknowledge pause + + compare-object $vms $pausedvms -Property Name -PassThru | sort -Property Name | ft -AutoSize Name,OwnerNode | Out-Host + return $false +} + +return $true \ No newline at end of file diff --git a/CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/check-vmfleet.ps1 b/CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/check-vmfleet.ps1 new file mode 100644 index 0000000..ec4d07a --- /dev/null +++ b/CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/check-vmfleet.ps1 @@ -0,0 +1,126 @@ +<# +DISKSPD - VM Fleet + +Copyright(c) Microsoft Corporation +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +#> + +param ($group = '*') + +$g = Get-ClusterGroup |? GroupType -eq VirtualMachine |? Name -like "vm-$group-*" + + +########################################################### +write-host -fore green State Pivot +$g | group -Property State -NoElement | sort -Property Name | ft -autosize + +########################################################### +write-host -fore green Host Pivot +$g | group -Property OwnerNode,State -NoElement | sort -Property Name | ft -autosize + +########################################################### +write-host -fore green Group Pivot +$g |% { + if ($_.Name -match "^vm-([^-]+)-") { + $_ | add-member -NotePropertyName Group -NotePropertyValue $matches[1] -PassThru + } +} | group -Property Group,State -NoElement | sort -Property Name | ft -AutoSize + +########################################################### +write-host -fore green IOPS Pivot +# build 5 orders of log steps +$logstep = 10,20,50 +$log = 1 +$logs = 1..5 |% { + + $logstep |% { $_ * $log } + $log *= 10 +} + +# build log step names; 0 is the > range catchall +$lognames = @{} +foreach ($step in $logs) { + + if ($step -eq $logs[0]) { + $lognames[$step] = "< $step" + } else { + $lognames[$step] = "$pstep - $($step - 1)" + } + $pstep = $step +} +$lognames[0] = "> $($logs[-1])" + +# now bucket up VMs by flow rates +$qosbuckets = @{} +$qosbuckets[0] = 0 +$logs |% { + $qosbuckets[$_] = 0 +} + +Get-StorageQoSFlow |% { + + $found = $false + foreach ($step in $logs) { + + if ($_.InitiatorIops -lt $step) { + $qosbuckets[$step] += 1; + $found = $true + break + } + } + # if not bucketed, it is greater than range + if (-not $found) { + $qosbuckets[0] += 1 + } +} + +# find min/max buckets with nonzero counts, by $logs index +# this lets us present a continuous range, with interleaved zeroes +$bmax = -1 +$bmin = -1 +foreach ($i in 0..($logs.Count - 1)) { + if ($qosbuckets[$logs[$i]]) { + + if ($bmin -lt 0) { + $bmin = $i + } + $bmax = $i + } +} +# raise max if we have > range +if ($qosbuckets[0]) { + $bmax = $logs.Count - 1 +} +$range = @($logs[$bmin..$bmax]) +# add > range if needed, at end +if ($qosbuckets[0]) { + $range += 0 +} + +$(foreach ($i in $range) { + + New-Object -TypeName psobject -Property @{ + Count = $qosbuckets[$i]; + IOPS = $lognames[$i] + } +}) | ft Count,IOPS \ No newline at end of file diff --git a/CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/clear-pause.ps1 b/CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/clear-pause.ps1 new file mode 100644 index 0000000..711852c --- /dev/null +++ b/CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/clear-pause.ps1 @@ -0,0 +1,38 @@ +<# +DISKSPD - VM Fleet + +Copyright(c) Microsoft Corporation +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +#> + +$pause = "C:\ClusterStorage\collect\control\flag\pause" + +if (gi $pause -ErrorAction SilentlyContinue) { + write-host -fore green Clearing pause from $([string](gi $pause).LastWriteTime) + do { + del $pause -Force -ErrorAction SilentlyContinue + } while (-not $?) + # del $pause-* -ErrorAction SilentlyContinue +} else { + write-host -fore yellow Pause not set +} \ No newline at end of file diff --git a/CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/create-vmfleet.ps1 b/CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/create-vmfleet.ps1 new file mode 100644 index 0000000..088568e --- /dev/null +++ b/CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/create-vmfleet.ps1 @@ -0,0 +1,366 @@ +<# +DISKSPD - VM Fleet + +Copyright(c) Microsoft Corporation +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +#> + +param( + [string]$BaseVHD = $(throw "please specify a base vhd"), + [int]$VMs = $(throw "please specify a number of vms per node csv"), + [string[]]$Groups = @(), + [string]$AdminPass = $(throw 'need admin password for autologin'), + [string]$Admin = 'administrator', + [string]$ConnectPass = $(throw 'need password for loopback host connection'), + [string]$ConnectUser = $(throw 'need username for loopback host connection'), + [validateset('CreateVMSwitch','CopyVHD','CreateVM','CreateVMGroup','AssertComplete')][string]$StopAfter, + [validateset('Force','Auto','None')][string]$Specialize = 'Auto', + [switch]$FixedVHD = $true, + [string[]]$Nodes = @() + ) + +function Stop-After($step) +{ + if ($stopafter -eq $step) { + write-host -ForegroundColor Green Stop after $step + return $true + } + return $false +} + +################## + +# validate existence of basevhd +if (!(test-path -path $BaseVHD)) { + throw "Base VHD $BaseVHD not found" +} + +if (Get-ClusterNode |? State -ne Up) { + throw "not all cluster nodes are up; please address before creating vmfleet" +} + +# if no nodes specified, use the entire cluster +if ($nodes.count -eq 0) { + $nodes = Get-ClusterNode +} + +# convert to fixed vhd(x) if needed +if ((get-vhd $basevhd).VhdType -ne 'Fixed' -and $fixedvhd) { + + # push dynamic vhd to tmppath and place converted at original + # note that converting a dynamic will leave a sparse hole on refs + # this is OK, since the copy will not copy the hole + $f = gi $basevhd + $tmpname = "tmp-$($f.Name)" + $tmppath = join-path $f.DirectoryName $tmpname + del -Force $tmppath -ErrorAction SilentlyContinue + ren $f.FullName $tmpname + + write-host -ForegroundColor Yellow "convert $($f.FullName) to fixed via $tmppath" + convert-vhd -Path $tmppath -DestinationPath $f.FullName -VHDType Fixed + if (-not $?) { + ren $tmppath $f.Name + throw "ERROR: could not convert $($f.fullname) to fixed vhdx" + } + + del $tmppath +} + +# Create the fleet vmswitches with a fixed IP at the base of the APIPA range +icm $nodes { + + if (-not (Get-VMSwitch -Name Internal -ErrorAction SilentlyContinue)) { + + New-VMSwitch -name Internal -SwitchType Internal + Get-NetAdapter |? DriverDescription -eq 'Hyper-V Virtual Ethernet Adapter' |? Name -eq 'vEthernet (Internal)' | New-NetIPAddress -PrefixLength 16 -IPAddress '169.254.1.1' + } +} | ft -AutoSize + +#### STOPAFTER +if (Stop-After "CreateVMSwitch") { + return +} + +# create $vms vms per each csv named as +# vm name is vm-<$group>-- + +icm $nodes -ArgumentList $stopafter,(Get-Command Stop-After) { + + param( [string]$stopafter, + $fn ) + + set-item -Path function:\$($fn.name) -Value $fn.definition + # workaround evaluation bug and make $stopafter evaluate in the session + $null = $stopafter + + function apply-specialization( $path ) + { + # all steps here can fail immediately without cleanup + + # error accumulator + $ok = $true + + # create run directory + + del -Recurse -Force z:\run -ErrorAction SilentlyContinue + mkdir z:\run + $ok = $ok -band $? + if (-not $ok) { + Write-Error "failed run directory creation for $vhdpath" + return $ok + } + + # autologon + $null = reg load 'HKLM\tmp' z:\windows\system32\config\software + $ok = $ok -band $? + $null = reg add 'HKLM\tmp\Microsoft\Windows NT\CurrentVersion\WinLogon' /f /v DefaultUserName /t REG_SZ /d $using:admin + $ok = $ok -band $? + $null = reg add 'HKLM\tmp\Microsoft\Windows NT\CurrentVersion\WinLogon' /f /v DefaultPassword /t REG_SZ /d $using:adminpass + $ok = $ok -band $? + $null = reg add 'HKLM\tmp\Microsoft\Windows NT\CurrentVersion\WinLogon' /f /v AutoAdminLogon /t REG_DWORD /d 1 + $ok = $ok -band $? + $null = reg add 'HKLM\tmp\Microsoft\Windows NT\CurrentVersion\WinLogon' /f /v Shell /t REG_SZ /d 'powershell.exe -noexit -command c:\users\administrator\launch.ps1' + $ok = $ok -band $? + $null = [gc]::Collect() + $ok = $ok -band $? + $null = reg unload 'HKLM\tmp' + $ok = $ok -band $? + if (-not $ok) { + Write-Error "failed autologon injection for $vhdpath" + return $ok + } + + # scripts + + copy -Force C:\ClusterStorage\collect\control\master.ps1 z:\run\master.ps1 + $ok = $ok -band $? + if (-not $ok) { + Write-Error "failed injection of specd master.ps1 for $vhdpath" + return $ok + } + + del -Force z:\users\administrator\launch.ps1 -ErrorAction SilentlyContinue + gc C:\ClusterStorage\collect\control\launch-template.ps1 |% { $_ -replace '__CONNECTUSER__',$using:connectuser -replace '__CONNECTPASS__',$using:connectpass } > z:\users\administrator\launch.ps1 + $ok = $ok -band $? + if (-not $ok) { + Write-Error "failed injection of launch.ps1 for $vhdpath" + return $err + } + + echo $vmspec > z:\vmspec.txt + $ok = $ok -band $? + if (-not $ok) { + Write-Error "failed injection of vmspec for $vhdpath" + return $ok + } + + # load files + $f = 'z:\run\testfile1.dat' + if (-not (gi $f -ErrorAction SilentlyContinue)) { + fsutil file createnew $f (10GB) + $ok = $ok -band $? + fsutil file setvaliddata $f (10GB) + $ok = $ok -band $? + } + if (-not $ok) { + Write-Error "failed creation of initial load file for $vhdpath" + return $ok + } + + return $ok + } + + function specialize-vhd( $vhdpath ) + { + $vhd = (gi $vhdpath) + $vmspec = $vhd.Directory.Name,$vhd.BaseName -join '+' + + # mount vhd and its largest partition + $o = Mount-VHD $vhd -NoDriveLetter -Passthru + if ($o -eq $null) { + Write-Error "failed mount for $vhdpath" + return $false + } + $p = Get-Disk -number $o.DiskNumber | Get-Partition | sort -Property size -Descending | select -first 1 + $p | Add-PartitionAccessPath -AccessPath Z: + + $ok = apply-specialization Z: + + Remove-PartitionAccessPath -AccessPath Z: -InputObject $p + Dismount-VHD -DiskNumber $o.DiskNumber + + return $ok + } + + $csvs = Get-ClusterSharedVolume + + # handle restore cases by mapping the csv to the friendly name of the volume + # don't rely on the csv name to contain this data + + $vh = @{} + Get-Volume |? FileSystem -eq CSVFS |% { $vh[$_.Path] = $_ } + + $csvs |% { + $v = $vh[$_.SharedVolumeInfo.Partition.Name] + if ($v -ne $null) { + $_ | Add-Member -NotePropertyName VDName -NotePropertyValue $v.FileSystemLabel + } + } + + foreach ($csv in $csvs) { + + if ($($using:groups).Length -eq 0) { + $groups = @( 'base' ) + } else { + $groups = $using:groups + } + + # identify the CSvs for which this node should create its VMs + # the trailing characters (if any) are the group prefix + if ($csv.VDName -match "^$env:COMPUTERNAME(?:-.+){0,1}") { + + foreach ($group in $groups) { + + if ($csv.VDName -match "^$env:COMPUTERNAME-([^-]+)$") { + $g = $group+$matches[1] + } else { + $g = $group + } + + foreach ($vm in 1..$using:vms) { + + $stop = $false + + $newvm = $false + $name = "vm-$g-$env:COMPUTERNAME-$vm" + $path = Join-Path $csv.SharedVolumeInfo.FriendlyVolumeName $name + + # place vhdx in subdirectory, per scvmm layout defaults + # $vhd = $path+".vhdx" + $vhd = join-path $path "$name.vhdx" + + # if the vm cluster group exists, we are already deployed + if (-not (Get-ClusterGroup -Name $name -ErrorAction SilentlyContinue)) { + + if (-not $stop) { + $stop = Stop-After "AssertComplete" + } + + if ($stop) { + + Write-Host -ForegroundColor Red "vm $name not deployed" + + } else { + + Write-Host -ForegroundColor Yellow "create vm $name @ metadata path $path with vhd $vhd" + + # create vm if not already done + # note that when restarting interrupted creation, the vm could have moved elsewhere + # under cluster control. + + $o = Get-ClusterGroup |? GroupType -eq VirtualMachine |? Name -eq $name + + if (-not $o) { + + # force re-specialization + $newvm = $true + + # if the cluster group doesn't exist, we're on the canonical node to create the vm + # if the vm exists, tear it down and refresh + + $o = get-vm -Name $name -ErrorAction SilentlyContinue + + if ($o) { + + # interrupted between vm creation and role creation; redo it + write-host "REMOVING vm $name for re-creation" + + if ($o.State -ne 'Off') { + Stop-VM -Name $name -Force -Confirm:$false + } + Remove-VM -Name $name -Force -Confirm:$false + + } else { + + # scrub and re-create the vm metadata path and vhd + rmdir -ErrorAction SilentlyContinue -Recurse $path + $null = mkdir -ErrorAction SilentlyContinue $path + + cp $using:basevhd $vhd + } + + #### STOPAFTER + if (-not $stop) { + $stop = Stop-After "CopyVHD" + } + + if (-not $stop) { + $o = New-VM -VHDPath $vhd -Generation 2 -SwitchName Internal -Path $path -Name $name + + # create A1 VM. use set-vmfleet to alter fleet sizing post-creation. + $o | Set-VM -ProcessorCount 1 -MemoryStartupBytes 1.75GB -StaticMemory + + # do not monitor the internal switch connection; this allows live migration + $o | Get-VMNetworkAdapter| Set-VMNetworkAdapter -NotMonitoredInCluster $true + } + } + + #### STOPAFTER + if (-not $stop) { + $stop = Stop-After "CreateVM" + } + + if (-not $stop) { + + # create clustered vm role and assign default owner node + $o | Add-ClusterVirtualMachineRole + Set-ClusterOwnerNode -Group $o.VMName -Owners $env:COMPUTERNAME + } + } + + } else { + Write-Host -ForegroundColor Green "vm $name already deployed" + } + + #### STOPAFTER + if (-not $stop) { + $stop = Stop-After "CreateVMGroup" + } + + if (-not $stop -or ($using:specialize -eq 'Force')) { + # specialize as needed + # auto only specializes new vms; force always; none skips it + if (($using:specialize -eq 'Auto' -and $newvm) -or ($using:specialize -eq 'Force')) { + write-host -fore yellow specialize $vhd + if (-not (specialize-vhd $vhd)) { + write-host -fore red "Failed specialize of $vhd, halting." + } + } else { + write-host -fore green skip specialize $vhd + } + } + } + } + } + } +} diff --git a/CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/demo.ps1 b/CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/demo.ps1 new file mode 100644 index 0000000..8048fbc --- /dev/null +++ b/CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/demo.ps1 @@ -0,0 +1,72 @@ +<# +DISKSPD - VM Fleet + +Copyright(c) Microsoft Corporation +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +#> + +param([int] $interval = 60) + +$cnodes = (Get-ClusterNode).Count +$cvms = (Get-ClusterGroup |? GroupType -eq 'VirtualMachine').Count/$cnodes + +# loop through the set of run scripts +$f = gi C:\clusterstorage\collect\control\run-demo-*.ps1 + +# qos policies to loop +$policy = 'SilverVM','GoldVM','PlatinumVM',$null,$null + +while ($true) { + + $null = & update-csv.ps1 + + foreach ($run in $f) { + + cls + + # touch the current run file to trigger VM updates + # see the master script + (gi $run).LastWriteTime = (get-date) + + # pull the show-me line of the run script (comment, trimmed) + # format is a single line, with # standing in for newline for multi-line output + # substitute in the configuration's node and vms/node count + # TBD: autodetect vd configuration + $comm = (gc $run | sls '^#-#').Line + + write-host -fore green $($comm.trimstart('#- ') -replace '__CVMS__',$cvms -replace '__CNODES__',$cnodes -replace '#',"`n") + + # apply random QoS policy + $p = $policy[(0..($policy.count - 1) | Get-Random)] + $null = & set-storageqos.ps1 -policyname $p 2>&1 + + write-host -fore yellow `nActive QoS Policy + if ($p) { + Get-StorageQosPolicy -Name $p | ft -AutoSize + } else { + write-host NONE + } + + sleep $interval + } +} \ No newline at end of file diff --git a/CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/destroy-vmfleet.ps1 b/CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/destroy-vmfleet.ps1 new file mode 100644 index 0000000..281ee7a --- /dev/null +++ b/CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/destroy-vmfleet.ps1 @@ -0,0 +1,102 @@ +<# +DISKSPD - VM Fleet + +Copyright(c) Microsoft Corporation +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +#> + +param( + [string[]] $vms = $null + ) + +if ($vms) { + write-host -ForegroundColor Yellow "Destroying VM Fleet content for: $vms" +} else { + write-host -ForegroundColor Yellow "Destroying VM Fleet" +} + +# stop and remove clustered vm roles +write-host -ForegroundColor Green "Removing VM ClusterGroups" +Get-ClusterGroup |? GroupType -eq VirtualMachine |? { + if ($vms) { + $_.Name -in $vms + } else { + $_.Name -like 'vm-*' + } +} |% { + write-host "Removing ClusterGroup for $($_.Name)" + $_ | Stop-ClusterGroup + $_ | Remove-ClusterGroup -RemoveResources -Force +} + +# remove all vms +write-host -ForegroundColor Green "Removing VMs" +icm (Get-ClusterNode) { + Get-VM |? { + if ($using:vms) { + $_.Name -in $using:vms + } else { + $_.Name -like 'vm-*' + } + } |% { + write-host "Removing VM for $($_.Name) @ $($env:COMPUTERNAME)" + $_ | Remove-VM -Confirm:$false -Force + } + + # do not remove the internal switch if teardown is partial + if ($using:vms -eq $null) { + write-host -ForegroundColor Green "Removing Internal VMSwitch" + Get-VMSwitch -SwitchType Internal | Remove-VMSwitch -Confirm:$False -Force + } +} + +# handle restore cases by mapping the csv to the friendly name of the volume +# don't rely on the csv name to contain this data +$csv = Get-ClusterSharedVolume + +$vh = @{} +Get-Volume |? FileSystem -eq CSVFS |% { $vh[$_.Path] = $_ } + +$csv |% { + $v = $vh[$_.SharedVolumeInfo.Partition.Name] + if ($v -ne $null) { + $_ | Add-Member -NotePropertyName VDName -NotePropertyValue $v.FileSystemLabel + } +} + +# now delete content from csvs corresponding to the cluster nodes +write-host -ForegroundColor Green "Removing CSV content for VMs" +Get-ClusterNode |% { + $csv |? VDName -match "$($_.Name)(-.+)?" +} |% { + dir -Directory $_.sharedvolumeinfo.friendlyvolumename |? { + if ($vms) { + $_.Name -in $vms + } else { + $_.Name -like 'vm-*' + } + } |% { + write-host "Removing CSV content for $($_.BaseName) @ $($_.FullName)" + del -Recurse -Force $_.FullName + } +} \ No newline at end of file diff --git a/CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/get-cluspc.ps1 b/CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/get-cluspc.ps1 new file mode 100644 index 0000000..889e01d --- /dev/null +++ b/CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/get-cluspc.ps1 @@ -0,0 +1,281 @@ +<# +DISKSPD - VM Fleet + +Copyright(c) Microsoft Corporation +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +#> + +## +## netsh advfirewall firewall set rule group="Performance Logs and Alerts" new enable=yes +## +[CmdletBinding( DefaultParameterSetName = "BySeconds" )] +param( + + [Parameter( + ParameterSetName = 'BySeconds', + ValueFromPipeline = $false, + ValueFromPipelineByPropertyName = $false, + Mandatory = $false)] + [ValidateRange(1,[int]::MaxValue)] + [int] $Seconds = 1, + + [Parameter( + ParameterSetName = 'ByStart', + ValueFromPipeline = $false, + ValueFromPipelineByPropertyName = $false, + Mandatory = $false)] + [switch] $Start, + + [Parameter( + ParameterSetName = 'ByStop', + ValueFromPipeline = $false, + ValueFromPipelineByPropertyName = $false, + Mandatory = $false)] + [switch] $Stop = $false, + + <# --------- common #> + + [Parameter( + ParameterSetName = 'BySeconds', + Mandatory = $false)] + [Parameter( + ParameterSetName = 'ByStart', + Mandatory = $false)] + [Parameter( + ParameterSetName = 'ByStop', + Mandatory = $false)] + [string] $Cluster = ".", + + <# --------- start-time parameters #> + + [Parameter( + ParameterSetName = 'BySeconds', + Mandatory = $false)] + [Parameter( + ParameterSetName = 'ByStart', + Mandatory = $false)] + [ValidateSet('PhysicalDisk','CPU','SMB','SMBD','SSB','SSB Cache','CSVFS','Storage','Spaces')] + [string[]] $Set = '*', + + [Parameter( + ParameterSetName = 'BySeconds', + Mandatory = $false)] + [Parameter( + ParameterSetName = 'ByStart', + Mandatory = $false)] + [string] $AddSpec, + + [Parameter( + ParameterSetName = 'BySeconds', + Mandatory = $false)] + [Parameter( + ParameterSetName = 'ByStart', + Mandatory = $false)] + [int] $SampleInterval = 1, + + <# --------- stop-time parameters #> + + [Parameter( + ParameterSetName = 'BySeconds', + Mandatory = $false)] + [Parameter( + ParameterSetName = 'ByStop', + Mandatory = $false)] + [switch] $Force = $false, + + [Parameter( + ParameterSetName = 'BySeconds', + Mandatory = $true)] + [Parameter( + ParameterSetName = 'ByStop', + Mandatory = $true)] + [string] $Destination + ) + +if ($psCmdlet.ParameterSetName -ne 'ByStart' -and + (gi -ErrorAction SilentlyContinue $Destination)) { + + if (-not $force) { + Write-Error "$Destination already exists, please delete or use -Force to overwrite" + return + } else { + del -ErrorAction SilentlyContinue $Destination + } +} + +$sets = @{ + 'PhysicalDisk' = '\PhysicalDisk(*)\*','+getclusport'; + 'CSVFS' = '\Cluster CSVFS(*)\*','\Cluster CSV Volume Cache(*)\*','\Cluster CSV Volume Manager(*)\*','\Cluster CSVFS Block Cache(*)\*','\Cluster CSVFS Direct IO(*)\*','\Cluster CSVFS Redirected IO(*)\*','+getcsv'; + 'SSB' = '\Cluster Disk Counters(*)\*','+getclusport'; + 'SMB' = '\SMB Client Shares(*)\*','\SMB Server Shares(*)\*'; + 'SMBD' = '\SMB Direct Connection(*)\*'; + 'SSB Cache' = '\Cluster Storage Hybrid Disks(*)\*','\Cluster Storage Cache Stores(*)\*'; + 'Spaces' = '\Storage Spaces Write Cache(*)\*','\Storage Spaces Tier(*)\*','\Storage Spaces Virtual Disk(*)\*' + 'ReFS' = '\ReFS(*)\*'; + 'CPU' = '\Hyper-V Hypervisor Logical Processor(*)\*','\Processor Information(*)\*'; + + 'Storage' = 'PhysicalDisk','CSVFS','SSB','SSB Cache','ReFS','Spaces'; +} + +$special = @{ + "getclusport" = $false; + "getcsv" = $false; +} + +$cleanup = @() + +$pc = @() +if ($Set.count -eq 1 -and $Set[0] -eq '*') { + # list of all keys + $pc = $sets.keys |% { $_ } +} else { + $pc = $Set +} + +# repeat expansion (sets in sets, possibly containing special collection rules) +do { + $expansion = $false + $pc = $pc |% { + $n = $_ + switch ($n[0]) { + # performance counter - passthru + '\' { $n } + # special collection (sets variable -> $true) + '+' { + + if ($special.ContainsKey($n.Substring(1))) { + $special[$n.Substring(1)] = $true + } else { + throw "unrecognized special gather command $($n.Substring(1))" + } + } + # set expansion + default { + $sets[$n] + $expansion = $true + } + } + } +} while ($expansion) + +# uniq the counters +$pc = ($pc | group -NoElement).Name + +# -- + +function start-logman( + [string] $name, + [string[]] $counters, + [int] $sampleinterval + ) +{ + $computer = $env:COMPUTERNAME + $f = "c:\perfctr-$name-$computer.blg" + + $null = logman create counter "perfctr-$name" -o $f -f bin -si $sampleinterval --v -c $counters + $null = logman start "perfctr-$name" + write-host "performance counters on: $computer" +} + +function stop-logman( + [string] $name + ) +{ + $computer = $env:COMPUTERNAME + $f = "c:\perfctr-$name-$computer.blg" + + $null = logman stop "perfctr-$name" + $null = logman delete "perfctr-$name" + write-host "performance counters off: $computer" + + echo $("\\$computer\$f" -replace ':','$') +} + +if (-not $Stop) { + + icm (get-clusternode -cluster $Cluster |? State -eq Up) -ArgumentList (get-command start-logman) { + + param($fn) + set-item -path function:\$($fn.name) -value $fn.definition + + start-logman $using:AddSpec $using:pc -sampleinterval $using:SampleInterval + } + + if ($Start) { + write-host -ForegroundColor Yellow INFO: captures started - reinvoke with `-stop to complete capture + return + } + + sleep $Seconds + +} else { + + write-host -ForegroundColor Yellow INFO: completing previously started capture +} + +# now capture all counter files +$f = @() +$f += icm (get-clusternode -cluster $Cluster |? State -eq Up) -ArgumentList (get-command stop-logman) { + + param($fn) + set-item -path function:\$($fn.name) -value $fn.definition + + stop-logman $using:AddSpec $using:Destination +} + +# add all counter blg to the cleanup step +$cleanup += $f + +#-- +# specials +#-- + +# make capture directory, and add to cleanup list +# note that all specials are generated into this directory, +# and will be automatically cleaned up when it is deleted +$t = New-TemporaryFile +del $t +$null = md $t +$cleanup += $t + +if ($special['getclusport']) { + + get-clusternode -cluster $Cluster |? State -eq Up |% { + + $exp = "$t\clusport-$_.xml" + gwmi -ComputerName $_ -Namespace root\wmi ClusPortDeviceInformation | export-clixml -Path $exp + $f += $exp + } +} + +if ($special['getcsv']) { + + $exp = "$t\csv.xml" + Get-ClusterSharedVolume -cluster $Cluster | export-clixml -Path $exp + $f += $exp +} + +compress-archive -DestinationPath $Destination -Path $f +del -Force -Recurse $cleanup + +write-host "performance counters: $Destination" \ No newline at end of file diff --git a/CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/get-linfit.ps1 b/CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/get-linfit.ps1 new file mode 100644 index 0000000..f313e62 --- /dev/null +++ b/CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/get-linfit.ps1 @@ -0,0 +1,143 @@ +<# +DISKSPD - VM Fleet + +Copyright(c) Microsoft Corporation +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +#> + +param( + $csvfile, + [string]$delimeter = "`t", + [string]$xcol = $(throw "please specify column containing x values"), + [string]$ycol = $(throw "please specify column containing y values"), + [string[]]$idxcol, + [switch]$zerointercept = $false + ) + +# given the input data, produce the linear fit coefficients for +# +# zerointercept = true: y = bx +# !zerointercept = true: y = a + bx +# +# specify the column containing the x and y measurements +# a single index column can be used to differentiate rows which should be +# used for the fit (i.e., "test1", "test2", ...). +# +# method: ordinary least squares + +function do-linfit( + [string] $xcol, + [string] $ycol, + [string] $key + ) +{ + BEGIN + { + $sumxy = [decimal]0 + $sumx2 = [decimal]0 + $sumx = [decimal]0 + $sumy = [decimal]0 + + $n = 0 + + $pipe = @() + } + + PROCESS + { + $x = [decimal]$_.$xcol + $y = [decimal]$_.$ycol + + $sumxy += $x*$y + $sumx2 += $x*$x + $sumx += $x + $sumy += $y + + $n += 1 + + # accumulate pipeline for second pass + $pipe += $_ + } + + END + { + if ($n -eq 0) { + Write-Error "ERROR: no measurements matched" + return + } + + # perform requested fit + + $a = 0 + $b = 0 + + if ($zerointercept) { + + $a = 0 + $b = ($sumxy/$sumx2) + + } else { + + $b = ($sumxy - (($sumx*$sumy)/$n)) / ($sumx2 - (($sumx*$sumx)/$n)) + $a = ($sumy - $b*$sumx)/$n + } + + # calculate r2 (coefficient of determination) with respect to the fit + $meany = $sumy/$n + + # total sum of squares + $sstot = [decimal]0 + $pipe |% { + $v = [decimal]$_.$ycol - $meany + $sstot += $v*$v + } + + # residual sum of squares + $ssres = [decimal]0 + $pipe |% { + $v = [decimal]$_.$ycol - ($a + $b*[decimal]$_.$xcol) + $ssres += $v*$v + } + + $r2 = 1 - ($ssres/$sstot) + + new-object -TypeName psobject -Property @{ 'A' = $a; 'B' = $b; 'R2' = $r2; 'N' = $n; 'Key' = $key; 'X' = $xcol; 'Y' = $ycol } + } +} + +# process the results into a hash keyed by the index columns +$h = @{} +import-csv -Path $csvfile -Delimiter $delimeter |% { + + $key = "" + foreach ($col in $idxcol) { + $key += "$col $($_.$col)" + } + + $h[$key] += ,$_ +} + +$h.Keys |% { + + $h[$_] | do-linfit -xcol $xcol -ycol $ycol -key $_ +} \ No newline at end of file diff --git a/CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/get-log.ps1 b/CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/get-log.ps1 new file mode 100644 index 0000000..33d0118 --- /dev/null +++ b/CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/get-log.ps1 @@ -0,0 +1,80 @@ +<# +DISKSPD - VM Fleet + +Copyright(c) Microsoft Corporation +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +#> + +param( + [string] $zip = $(throw "please provide zip filename for compressed logs"), + [ValidateSet("*","HyperV","FailoverClustering","SMB")][string[]] $set = "*", + [int] $timespan = 0 + ) + +# convert minutes to milliseconds +if ($timespan -gt 0) { + $timespan *= 60*1000 +} + +$logs = icm (get-clusternode) { + + $map = @{ + "HyperV" = "Microsoft-Windows-Hyper-V"; + "FailoverClustering" = "Microsoft-Windows-FailoverClustering" + "SMB" = "Microsoft-Windows-SMB" + } + + if ($using:set -eq "*") { + $lset = $map.Keys |% { $_ } + } else { + $lset = $using:set + } + +$q = @" +/q:"*[System[TimeCreated[timediff(@SystemTime) <= __TIME__]]]" +"@ + + if ($using:timespan -gt 0) { + $timefilt = $q -replace '__TIME__',$using:timespan + } else { + $timefilt = $null + } + + $lset |% { + + # get logs and normalize to legal filenames + $prov = wevtutil el | sls $map[$_] + $provf = $prov -replace '/','-' + + foreach ($i in 0..($prov.Count - 1)) { + + $localpath = "$($provf[$i])--$env:computername.evtx" + del -Force $localpath -ErrorAction SilentlyContinue + wevtutil epl $prov[$i] "c:\$localpath" $timefilt + write-output "\\$env:computername\c$\$localpath" + } + } +} + +compress-archive -Path $logs -DestinationPath $zip +del -force $logs \ No newline at end of file diff --git a/CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/install-vmfleet.ps1 b/CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/install-vmfleet.ps1 new file mode 100644 index 0000000..469237e --- /dev/null +++ b/CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/install-vmfleet.ps1 @@ -0,0 +1,74 @@ +<# +DISKSPD - VM Fleet + +Copyright(c) Microsoft Corporation +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +#> + +param( + $source = $(throw "Must specify the source directory for the vmfleet scripts") + ) + +$col = get-clustersharedvolume |? Name -match '(collect)' +if ($col -eq $null) { + write-error "The collect CSV is not present" + return +} + +$fqsrc = gi $source +if ($fqsrc -eq $null) { + write-error "The source directory for the vmfleet scripts is not accessible" +} + +# update the csv mounts to their normalized names and install scripts and directory structure +# remove internet-download blocks on ps1 scripting, if present +& $fqsrc\update-csv.ps1 -renamecsvmounts +$control = 'C:\ClusterStorage\collect\control' + +cp -r $fqsrc $control +dir $control\*.ps1 |% { Unblock-File $_ } + +mkdir $control\result +mkdir $control\flag +mkdir $control\tools + + +# put the control directory onto the path +if (-not ([System.Environment]::GetEnvironmentVariable("path") -split ';' |? { $_ -eq $control })) { + $newpath = [System.Environment]::GetEnvironmentVariable("path") + ";$control" + [System.Environment]::SetEnvironmentVariable("path", + $newpath, + [System.EnvironmentVariableTarget]::Process) + [System.Environment]::SetEnvironmentVariable("path", + $newpath, + [System.EnvironmentVariableTarget]::User) +} + +# disable the csv balancer so that motion is under fleet control +(get-cluster).CsvBalancer = 0 + +# finally set fleet pause and touch the base run file so that we ensure +# the fleet will start with it. +set-pause +(gi $control\run.ps1).IsReadOnly = $false +(gi $control\run.ps1).LastWriteTime = (Get-Date) \ No newline at end of file diff --git a/CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/launch-template.ps1 b/CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/launch-template.ps1 new file mode 100644 index 0000000..439df37 --- /dev/null +++ b/CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/launch-template.ps1 @@ -0,0 +1,34 @@ +<# +DISKSPD - VM Fleet + +Copyright(c) Microsoft Corporation +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +#> + +$script = 'c:\run\master.ps1' + +while ($true) { + Write-Host -fore Green Launching $script `@ $(Get-Date) + & $script -connectuser __CONNECTUSER__ -connectpass __CONNECTPASS__ + sleep -Seconds 1 +} diff --git a/CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/master.ps1 b/CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/master.ps1 new file mode 100644 index 0000000..98bc673 --- /dev/null +++ b/CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/master.ps1 @@ -0,0 +1,225 @@ +<# +DISKSPD - VM Fleet + +Copyright(c) Microsoft Corporation +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +#> + +# +# VM Master Script +# +# This script must be executed on autologon by the VM. It establishes a mapping a location containing the Run Script +# and then repeatedly polls/executes the latest one it finds. This allows the runner to inject new run scripts on the +# fly and/or touch pre-existing ones to bump them to the top of the list. +# +# In the initial form, it assumes the VM is connected by an internal switch and it just polls all the node names to +# find the one which will work. This could be improved by using specialization to inject the specific path to a +# configuration file. +# + +param( + [string] $connectuser, + [string] $connectpass + ) + +$null = net use l: /d + +if ($(Get-SmbMapping) -eq $null) { + New-SmbMapping -LocalPath l: -RemotePath \\169.254.1.1\c$\clusterstorage\collect\control -UserName $connectuser -Password $connectpass -ErrorAction SilentlyContinue +} + +# update tooling +cp l:\tools\* c:\run -Force + +$run = 'c:\run\run.ps1' +$master = 'c:\run\master.ps1' + +$mypause = "l:\flag\pause-$(gc c:\vmspec.txt)" +$mydone = "l:\flag\done-$(gc c:\vmspec.txt)" + +$done = $false +$donetouched = $false +$pause = $false + +$tick = 0 + +function get-newfile( + $sourcepat, + $dest, + $clean = $false, + $silent = $false + ) +{ + $sf = dir $sourcepat | sort -Property LastWriteTime -Descending | select -first 1 + $df = gi $dest -ErrorAction SilentlyContinue + + # no source? + if ($sf -eq $null) { + write-host -fore green NO source present + # clean if needed + if ($clean) { + rm $dest + } + # no new file is an update condition + $true + } elseif ($df -eq $null -or $sf.lastwritetime -gt $df.lastwritetime) { + write-host -fore green NEWER source $sf.fullname '=>' $dest + # update with newer source file and indicate update condition + cp $sf.fullname $dest -Force + $true + } else { + if (-not $silent) { + write-host -fore green NO newer source $sf.lastwritetime $sf.fullname '**' $df.LastWriteTime $df.fullname + } + # already have latest, indicate no new + $false + } +} + +function get-flagfile( + [string] $flag, + [switch] $gc = $false + ) +{ + if ($gc) { + gc "l:\flag\$flag" -ErrorAction SilentlyContinue + } else { + gi "l:\flag\$flag" -ErrorAction SilentlyContinue + } +} + +while ($true) { + + # update master control? + # assume runners have a simple loop to re-execute on exit + if (get-newfile l:\master*.ps1 $master -silent:$true) { + break + } + + # check and acknowledge pause - only drop flag once + $pauseepoch = get-flagfile pause -gc:$true + if ($pauseepoch -ne $null) { + + # pause clears done + $done = $false + + # drop into pause flagfile if needed + if ($pause -eq $false) { + write-host -fore red PAUSE IN FORCE + $pause = $true + echo $pauseepoch > $mypause + } else { + if ($tick % 10 -eq 0) { + write-host -fore red -NoNewline '.' + } + } + + } elseif ($done) { + + # drop epoch into done flagfile if needed + if (-not $donetouched) { + echo $goepoch > $mydone + $donetouched = $true + } + + # if go flag is now different, release for the next go around + if ($goepoch -ne (get-flagfile go -gc:$true)) { + $done = $false + write-host -fore cyan `nReleasing from Done + } else { + if ($tick % 10 -eq 0) { + write-host -fore yellow -NoNewline '.' + } + } + + } else { + + # clear pause & donetouched flags + $pause = $false + $donetouched = $false + + # update run script? + $null = get-newfile l:\run*.ps1 $run -clean:$true + $runf = gi $run -ErrorAction SilentlyContinue + + if ($runf -eq $null) { + write-host -fore yellow no control file found + sleep 30 + continue + } + + # update go epoch - a change to this (if present) will be what + # allows us to proceed past a done flag + $goepoch = get-flagfile go -gc:$true + if ($goepoch -ne $null) { + write-host -fore cyan Go Epoch acknowledged at: $goepoch + } + + # acknowledge script + write-host -fore cyan Run Script $runf.lastwritetime "`n$("*"*20)" + gc $runf + write-host -fore cyan ("*"*20) + + # launch and monitor pause and new run file + $j = start-job -arg $run { param($run) & $run } + while (($jf = wait-job $j -Timeout 1) -eq $null) { + + $halt = $null + + # check pause or new run file: if so, stop and loop + if (get-flagfile pause) { + $halt = "pause set" + } + + if (get-newfile l:\run*.ps1 $run -clean:$true -silent:$true) { + $halt = "new run file" + } + + if ($halt -ne $null) { + write-host -fore yellow STOPPING CURRENT "(reason: $halt)" + $j | stop-job + $j | remove-job + break + } + } + + # job finished? + if ($jf -ne $null) { + $result = $jf | receive-job + + if ($result -eq "done") { + write-host -fore yellow DONE CURRENT + $done = $true + } + + $jf | remove-job + } + + write-host -fore cyan ("*"*20) + } + + # force gc to teardown potentially conflicting handles and enforce min pause + [system.gc]::Collect() + sleep 1 + $tick += 1 +} \ No newline at end of file diff --git a/CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/run-demo-100r.ps1 b/CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/run-demo-100r.ps1 new file mode 100644 index 0000000..520f046 --- /dev/null +++ b/CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/run-demo-100r.ps1 @@ -0,0 +1,39 @@ +<# +DISKSPD - VM Fleet + +Copyright(c) Microsoft Corporation +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +#> + +#-# System Config: __CNODES__ Systems x __CVMS__ VMs/System#Storage Config: 3-way S2D Mirror#Current Workload: 100% 4K Random Read + +[string](get-date) + +$b = 4 +$t = 8 +$o = 20 +$w = 0 + +C:\run\diskspd.exe -n -h `-t$t `-o$o `-b$($b)k `-r$($b)k `-w$w -W10 -d60 -C10 -D -L (dir C:\run\testfile?.dat) + +[string](get-date) diff --git a/CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/run-demo-7030.ps1 b/CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/run-demo-7030.ps1 new file mode 100644 index 0000000..ae22f5b --- /dev/null +++ b/CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/run-demo-7030.ps1 @@ -0,0 +1,38 @@ +<# +DISKSPD - VM Fleet + +Copyright(c) Microsoft Corporation +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +#> + +#-# System Config: __CNODES__ Systems x __CVMS__ VMs/System#Storage Config: 3-way S2D Mirror#Current Workload: 70:30 4K Random Read/Write +[string](get-date) + +$b = 4 +$t = 8 +$o = 20 +$w = 30 + +C:\run\diskspd.exe -n -h `-t$t `-o$o `-b$($b)k `-r$($b)k `-w$w -W10 -d60 -C10 -D -L (dir C:\run\testfile?.dat) + +[string](get-date) diff --git a/CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/run-demo-9010.ps1 b/CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/run-demo-9010.ps1 new file mode 100644 index 0000000..36e4986 --- /dev/null +++ b/CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/run-demo-9010.ps1 @@ -0,0 +1,38 @@ +<# +DISKSPD - VM Fleet + +Copyright(c) Microsoft Corporation +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +#> + +#-# System Config: __CNODES__ Systems x __CVMS__ VMs/System#Storage Config: 3-way S2D Mirror#Current Workload: 90:10 4K Random Read/Write +[string](get-date) + +$b = 4 +$t = 8 +$o = 20 +$w = 10 + +C:\run\diskspd.exe -n -h `-t$t `-o$o `-b$($b)k `-r$($b)k `-w$w -W10 -d60 -C10 -D -L (dir C:\run\testfile?.dat) + +[string](get-date) diff --git a/CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/run-sweeptemplate.ps1 b/CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/run-sweeptemplate.ps1 new file mode 100644 index 0000000..2b3ede8 --- /dev/null +++ b/CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/run-sweeptemplate.ps1 @@ -0,0 +1,78 @@ +<# +DISKSPD - VM Fleet + +Copyright(c) Microsoft Corporation +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +#> + +[string](get-date) + +# buffer size/alighment, threads/target, outstanding/thread, write% +$b = __b__; $t = __t__; $o = __o__; $w = __w__ + +# optional - specify rate limit in iops, translated to bytes/ms for DISKSPD +$iops = __iops__ +if ($iops -ne $null) { $g = $iops * $b * 1KB / 1000 } + +# io pattern, (r)andom or (s)equential (si as needed for multithread) +$p = '__p__' + +# durations of test, cooldown, warmup +$d = __d__; $cool = __Cool__; $warm = __Warm__ + +# sweep template always captures +$addspec = '__AddSpec__' +$gspec = $null +if ($g -ne $null) { $gspec = "g$($g)" } +$result = "result-b$($b)t$($t)o$($o)w$($w)p$($p)$($gspec)-$($addspec)-$(gc c:\vmspec.txt).xml" +$dresult = "l:\result" +$lresultf = join-path "c:\run" $result +$dresultf = join-path $dresult $result + +### prior to this is template + +if (-not (gi $dresultf -ErrorAction SilentlyContinue)) { + + $res = 'xml' + $gspec = $null + if ($g -ne $null) { $gspec = "-g$($g)" } + + C:\run\diskspd.exe -Z20M -z -h `-t$t `-o$o $gspec `-b$($b)k `-$($p)$($b)k `-w$w `-W$warm `-C$cool `-d$($d) -D -L `-R$res (dir C:\run\testfile?.dat) > $lresultf + + # export result and indicate done flag to master + # use unbuffered copy to force IO downstream + xcopy /j $lresultf $dresult + del $lresultf + Write-Output "done" + +} else { + + write-host -fore green already done $dresultf + + # indicate done flag to master + # this should only occur if controller does not change variation + Write-Output "done" +} + +[system.gc]::Collect() +[string](get-date) \ No newline at end of file diff --git a/CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/run.ps1 b/CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/run.ps1 new file mode 100644 index 0000000..285e296 --- /dev/null +++ b/CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/run.ps1 @@ -0,0 +1,94 @@ +<# +DISKSPD - VM Fleet + +Copyright(c) Microsoft Corporation +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +#> + +[string](get-date) + +# buffer size/alighment, threads/target, outstanding/thread, write% +$b = 4; $t = 1; $o = 8; $w = 10 + +# optional - specify rate limit in iops, translated to bytes/ms for DISKSPD +$iops = 500 +if ($iops -ne $null) { $g = $iops * $b * 1KB / 1000 } + +# io pattern, (r)andom or (s)equential (si as needed for multithread) +$p = 'r' + +# durations of test, cooldown, warmup +$d = 30*60; $cool = 30; $warm = 60 + +$addspec = 'base' +$gspec = $null +if ($g -ne $null) { $gspec = "g$($g)" } +$result = "result-b$($b)t$($t)o$($o)w$($w)p$($p)$($gspec)-$($addspec)-$(gc c:\vmspec.txt).xml" +$dresult = "l:\result" +$lresultf = join-path "c:\run" $result +$dresultf = join-path $dresult $result + +# cap -> true to capture xml results, otherwise human text +$cap = $false + +### prior to this is template + +if (-not (gi $dresultf -ErrorAction SilentlyContinue)) { + + if ($cap) { + $res = 'xml' + } else { + $res = 'text' + } + + $gspec = $null + if ($g -ne $null) { $gspec = "-g$($g)" } + $o = C:\run\diskspd.exe -Z20M -z -h `-t$t `-o$o $gspec `-b$($b)k `-$($p)$($b)k `-w$w `-W$warm `-C$cool `-d$($d) -D -L `-R$res (dir C:\run\testfile?.dat) + + if ($cap) { + + # export result and indicate done flag to master + # use unbuffered copy to force IO downstream + + $o | Out-File $lresultf -Encoding ascii -Width 9999 + xcopy /j $lresultf $dresult + del $lresultf + Write-Output "done" + + } else { + + #emit to human watcher + $o | Out-Host + } + +} else { + + write-host -fore green already done $dresultf + + # indicate done flag to master + # this should only occur if controller does not change variation + Write-Output "done" +} + +[system.gc]::Collect() +[string](get-date) \ No newline at end of file diff --git a/CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/s2d-vmfleet.docx b/CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/s2d-vmfleet.docx new file mode 100644 index 0000000000000000000000000000000000000000..656eb024d8b0def47323ef93fb56be3101e222a0 GIT binary patch literal 46220 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 JpyIDj{|8Wtb(sJF literal 0 HcmV?d00001 diff --git a/CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/s2d-vmfleet.pdf b/CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/s2d-vmfleet.pdf new file mode 100644 index 0000000000000000000000000000000000000000..34a07045af243637a4bb1e12462bd71012dd7e2e GIT binary patch literal 1043401 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⋙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 uxO>YK7u3fU@y_GVu-0*u+^5Te9Q9*+5$k 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

jYj)P8bdP1 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

b|ZIRA=;10%CWSN03{uE@Rvscun* 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�K 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

41Umo*Z1Sb;;FW}GUMNzJ^1iEP1KJd=gf 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%0A%C6b!|3h)McbzA zI)HgpDq4rvzr%LXcG0%&dpZeX-+B6UW+?b|2c+CUSANJ;u2hBbBsVfPem^hI!VX-o zHKEo$UJVk)lTrAC|Mr~oDa_bYqp11@sSf$sK@!Nc<*q)Q55kDqt0`G;K!55m=q!`IV0!-W~T*e*0D zgPi6QEOZyTYqj0R1P2)l_5$oyc&@!$2=!dE+2R-FI7^H4UP& zFSr16x8gTWsP>g;DZPAYT}vPECtQ2^)a>1c@OPwOy3lsQpjeT-Rj|6~U=7WG;ac>? zxB}6&q~rPE`FBr&=qqB%>c@pxbq(d`;lklGWw)@_OUL85iUH#eA#9>4s6pX zcvdp8jhrJO?7ef?fU7|S$FMEq0DDmyNoSSR(vF=>!ky$<9WEavTL*h z-cp`L5;b4xzlpS?Kz2UjTOPYhdY|a%?;SDX9Wi@CHVDo7%%w?yJ0|lg1@Wzk?^_dJ zy~Gyd&b~OxG|~QUlZ{3W&(yExYFOd2(uDfl>e~EeWi{wyNr_`g%wtKlV@bDTNrhuc zJ)k%(P}~YAt_2kL0*aFY#e;zT%z$4ZfM5NyQRuT#bF)$Pvr#UyQ8%+u2(wY^e=so% zFrTY1Tj#Mjr(;WP4td-N6-VV(JExewv;;F=r{3KYGR+QWf8<2GBTo-bbHr#z1b!pV z`fBjRx)8*={}JmVfpif-y09Q!XprtV&>9SA4F$9Y30i{%twDnXA~(*-pTcRYb8mYN zwIjQ}5fSrkNu7QAX>ov7fIo~$`RF+_g|Aa4p)x;*w_1Z`RLmW;?k9hnCt-1Bo>b(a zv4_V%eh=LUgFqk9fI*5RV|S$$6B|NP8I+QgHEUXvRdH-9t zR5KTIzv3bzXRsGRAHbo_n8A{t6b^SQC($07EnhPbI|s!ntuTpK&1R+_hhK<1^4fxT z)yTGG^y{XFa^zL%Yrwwc)$hHHy~eb;|8l99^ctgu(r1q^9%--YlV>%#qPWttDW zOX($Qe*h-C@`wNUZ!dcP)AM3!>uWN$1wW!=i_jC9_um?r)j$qnOCDpKrP=!D#e%W1 z@R1Kz5&#Hn9T< zwB)@S+0d%YI?WB{mzb%LA zkLcEG7V&gu87Q(?Iq2vmO|I2@?jtUTc#zSb6L=z*4+_*P6|sCB+a~#*TY7Sq&xF^T z?920n#*vlVV-ZRb)In*A5j5P`3)u|O)FDvCVK;oA&%myyNSdZ;9HaWBXrU&D$&;%{ zt5u(APh&HFY4w`X&m0SefZDscauqw zc@UKY$n2awX)LXwxQJM9IxYFZo?1^%ppJGGlPX4dERSlXu5?wch|(`hSW%$Rx4OiMg}v1Ub$}T$uO)@9kOF6VF-kde_RCizlW|}u%C(!6?+PfwsL_gk2C1FISAa{7hhpW7&lH| znLOw_UnF-u;5SRMJHyspBQ~NgbuXz}*H+>?>^f_kwizZ$mpsFL1ud>d>`B{~>Bz7< z@d@vkp4Y5Ro7i+GuyXh7w?^)zgUtRU+9C0d;9+(_cd6}vF2P+%B#Iwm;OlB3Z{bq> zVrqVw9YgN`c1VS9Y5aQpVGdXULz8=Yet9B%I89vB{5YhBR0;`_0qVdu%Ge~6Nz~s6 zOJS=qiR9Bq|B=hcMj^etoWD@OgL^xbw0h5)z{gtODrNnUeUi`H)0bWTRkm@P3xj^N zBoUkQf@Dz2?(5D`9fDw6J~UQeS9Va(?W_HvXEX{CJvr6&^;G}Sb9W3>(rYp`vj@^$ z@U?=gYlMF~&DJAc)usERX+1T!+~UdYE~f8{FBy9?683c5*gjUn^|>2=GgdHWG`8DW z>f`D2?Ca?hM-2KW5-sKGQ4w&UQPVTHvejE{m>Voyv3R59SLMDk5~wTM>;{$;$W$uk zJRuUu7x|%ZvgeL$Q2X#wD0uAHOh_jDBcXf~>frQ{sM{D%x~czs6F%-mI%`f{UdN9g z;|@S67Q`Qp%ngpadH9GJVLDHEDyyH=wy5If!PASq7*R4yxCwWe1ly@y|Q#ClLIjrHSVba3YQr3#M3uc_*-ryeL?$_97@SJj<@|^Nuc4c;{ zcCPlUc5`s=KK31Mo@ica-u3``EP8Bs%zLbPEPHGzZm3-Hd4;Z1gwxXWAY3L4`1ZZ@ zF@}`)!S#jrN%wIXn;8qRL9fDiW7pBw;n(rk!PZgNVb^hA+Zq!Z>lxG35!VUVL9>1H zMy{i*!(<~|#b1S8#a=~TC0>R0X0D^H!)1eC#r1~1rr9AgX1TW9VeaeiE9f)n``3rw zr_$%YW4(iC4CzdCt+@lU)~C9oy2G*Kx`VhQzq8jz8(bM&8KMli0+A0_ z11kcp5AToDM)E}D41KNK7uToQH`R9(q8H2xVFc3yvw^q)w}Il1|Act0v4gT>hxiHa z?Qrou>HX-<=(YDI=uGtLb2_O1lk`*S^YJ6-Mfv6P;B)cQ>68A`>SN(!=G}@RA>beD zV^DcQ?tPF{;KpDv!$0Ux_Rok9j!&77y^o+LZTXjyj8|MC=Y5~q8B(=t~G54f%w~g9t==gL#6xR@@2P(d&cmYYl-9xq?82 z+PLxtXkCV38V+lK$}(gp4bz`h}Q6Fl)>BVB(p=D$|h(b>^Le8&uFh5q*ce+H845x*|9B{q3W_-hJTO9qzN? zYrx^dmN|q@?d_2@a@FRCGoo(UZm#1l*hl(w7<%XkR}U^KWNxU8;x%G zTa7niH_Y&NA(-(~jbD^TzTo!8%#aD`S$}0t$h^mnglC&GA>%4rW(qas6RmOb4JhO&Vp7AA z&!v^EoM|^%I@Ns0c_?tJB?k7@AK2pplBh!bC_S?3}jhe~L%)oBx;BJ1z@XYVw-v46KBZhmwZbFU; z!p0HR!vAC!rAT=QIrJv={{)U2axEMX7>oF**FY=-kX=8tUN_H29r?zC4tN{fq}B5M z0~Jfk!6(h!Q-3!HsP+sLQSDyxN@TbKw#mgwt$lwipmH-W+!fkVPg&&6-kB+i&fVo_ z=vtEI-jv?47^MaXeEn)apoNoUEO4nsl1F zJ@h(+y%jx_I>?Pwb9Bb_azjl}6@V8C_w%Wm7u<S%Qrr)f+xgNYmmR<{VvDA*9-7=<@Ksx~mZ@BK6W2~-e-WU!bqj-;)y%mlD zZ#{;}DIQD0he)@EZY4hX{1aWgvdWjP zY&i8;kg#osTVA31U}Y)`#0UHVtpnn#9tIR-Y5&!itm3 zvSyl>3b&@H!BCXqoYQYYW0qo^)758Q1HOG&UUGgq_L%hG8`d0GH-$>YA2Ys05lRNR z6yp793LPd(WOT&w*~MYkMnacJ4Y!xQc)OnHiuysL71KhY)`WTS72u|>K_`}?O=K2` zVfkBmOw$oVva36%rcdh|^*Y4l(wo6dg61|vDjDVda}xV@$iH5U32QLLvjLA@I?A72 zHx}JYDr8;>r!^X3mxo;fAx@uB>@L!ZcBvY4MU)$q4>*TV|+m zH^CI4e0ML3ge>2=xH4&M{pO+T*Zj#pVjtSPDZyKoFO{^B&Rdc<-K}J!QNNq|uHb~d zz2|EG(D}W8t+(GrqHu2npUeYkdt7{P^ze zGgJ>ibO`rm_|4?wzo3*)6`NRwcP7K}bg+d#zfr#yc=Q?5A3G?i_E7nT`^}~&O|+0J z;>q`eX!}o7#1lFg3if&;|6mcF+}@LUdVQn&3?|(p1#^6$i%x&`D_3c~3eIx}s3 zidm)nV0eh`jSBbzsF80L$@?!2|aaq4`()5_-1qUviH2faPU7|i>c zkYw{+&C36Z8qBI0Of@bS zjc3aiPK+^Aj4{L%J7#8xV`j_D%*@OTvK=!sGcz+YGcz;WPrrNT-GOhuH}}o_`IfeJ z9c^i~mekeVr%qR$Q>VPs_S-Rrb&$^%qNH_ZH&s3I+pJpCxOl;sNxpi*LoDUZyQwq< zN1#-upgl#J;K6jz5ks?TeBH7t#3-~B*f_*GqI$mBBUd94$kovYxjJzo%%TT%>KQfa zT64O%9vEzRkMQqF*)x&TM-*%=i1$?o4k765KV4HCGV&h^z4#IS7{W%3O`2RYr|DDI zmuVTSmJi6|DSb#S48#Y-F=%}>{F>>T7jLc)BQ`}zKQEx(i%YXW)@q&omVqD9;C%cZ z@88zL2*zJlH5@T+8RzZ#klR=lH_O9;&xXSW*NDulcz)K}Mef%J3OL?KaYlQrB19@lzH@Sn6IY9j@Qq3E`;gg>4cBnTc$Y+cMS0b7t zNn5b>kb=|*&6xlz0MF>+m9u{aaA-gpE%4!e%Nx-EB*kPqMyh4Ht%BV){|AToZkjTlGIILTC;ZR+7xY>@ zfUnUlm!-Jx?Od`sn^^38JfwTO-)y6rZLH?hIv8r@u~m!VFN{a58;0pTW4BC)t!YQB zD~5M9Y>RG_N1$n-d7xLnq{6tvn4Gl$%5A<{!(KXW>VkY&l192p?k^A4By{?H%hFizmLM;pn`gy%3GfY~`$Q^@>u3r~RBK3U2J4^J z?6Q)-i^JGnh;)xn!=6w7vc}tkYiPIsGP8MJ)YP{c8t<)a&aQ)bc(o2J5Aw#lczL%y z{HAGaR~zW^!i#6U3uy<~>%wYKO7n!2LYzJ+eS-6e z4CqrDGyNEi3JmUltZc-re%q&WfQ}l4d zX&1sgysjHT)}n)giy)nE%AC2mRF_wMLewzhu5n|M%p0jrghbi?e*X25>QJj)T$aA3 zixL(jXpDmBj{k^dofca#K3@jf#SxGZ(9167U=g5^%y_p;PN`eS3~@;Hba>zxpT?=n z+VVOQXQS8{KkO7k$t*m?xr?3AcXH{q3uch|k4j-T-G!1z9r*UYSPs3C4dwIJ8(}3sGAdx#yF`{T(ZMh zgP)2~C{96T98K}@O~Mp{tWaeh7Yo;P1*7wtG*bRlHr*1D)Tgs?vrSghGWzF@A3t~+ z+OY4;>^l`Yt`%+iA*t}2euQG7P2%h4bW8irVW8n15<$FuRaL3Ws zhoY*C|J>3rvCr|fIF?UIDOZD7^X>7BLcC6cX)OCJuHoMj0r4xDzI<6xC5k{MUXf{` z*&71SPn}|mV-P_rS~e>Bd`7+FQRu!LLwP2w{|YEh&rX;cV|eF!Q}3Ucqzw*>pQ&MZ zN9QKn(VDT+(YZ_mYGuk^A3Z>k()7@+`s3gei}jlo;w^=z9aZVJl0NaFNebJa|=cpeQ z+iUa>B}C3FdE8ZAAT9uCP+soe+}zY$g6GCeeKE}l0MF`-ZvB1$hF4BukT)H zR11u}TK%zu#_crts6Qcr-7!HtATdETfr#xjc9RUe04iqq0*#lzb4~_;q)hqW^Sv8& z`}=q$jbE1^>w3{YBwo!J+8N&+us6nNh-2prtIHM_B<^35bMsG+m=Uz_etS50c!Z2B zOe{$E$Cby7ENm=j^;_K{{JHXJ_hBfn%}{UW%831bdUtw_aR0{FFYZpt@UHFazAPRr zhDEdI?C;XnTE<>2jlEA@{UBo(-1-p6F5xa**!aCYp-qXsE; zv7A}9U$_WmX}Q>a-oIRaI;UTBY2{lWP7!|5-r#pi9j)Izr{d)QmpHu#`o_To{6B*8 z(9dh=;Lk+#liKu|%(^F4Sd(}mJ}hBne5l}Q7~rlX^pocFnUbh}P61H2YVgMKy}w5K zygfzX?KR-b46>Ot;SZC0e_ix>_lv^UYQZ0-_5OnH_r4c}XVQT`%%~m_@0tpQ0kOEBb2Mg}r`7v?|5+0t6s~kX`LnvT$TmQsC;5kx z7=EeNs&YqT&pfSV)3ypRz{SL7sBTmUTZt00LA|L}VD)eT{cTBH&CL;Q;!g;FVDzqz zlN8nW7-30V`grqE0(yI*B?Y=%Yc6)00|Tc7Guvp<51_2_~7xB_QK)cI4w&#QIrW5AwU~IIE6e# z8U>Glh=9iUTmWWd!v5ltNOkc$(A;XNKR3x8--Iv&S#5|cy<{&&R4rO`d5A2gJ(r+~ zk0)c5JYyUxI%V+tQ?6}|`rPVos2D!sQncd-+p=8?GLx@u@mVb_xM(iwsGhmptuMYmUur%2VF=1HVoV=_0# zQ!6gVrqd>#B~CQ`47lO;zP(1BA$lUf{X5Cha-Bh_{t}~{K0zs^aKf`KiD+Do5I;L8 z7J>iawtMNO6_a95+O~`Ka#yKTzr%|zCmnj#k=!mNZv1nN?_q|)RftFa8K|EV5@m2p z5A_WV2s-cTl~v6xnx(SPG*7SoOxFdi(Pg5bFZP)2FRV`7r(dFf(+wQ>+CK_Z`C3C^ zXg9i*2)Dk!4rW!=(AzTCvf$SHQuN?n%F04tuVbFF*t$4WRij4`xrWukc>gPvm4?1t zN4=u4weiYEZfC#0EQB)5X<#8jI#LU>gWHopuN3YZl@b!!;!^T?a#ym08B0ZyMvd0k z5VN@1d7(=;=9&1--4*&X{+-3c*$v)Z+O@{zz*Eet$-9J?v{!jYr`9R$Rl@VaQ^U){ zQ{=Ps6YXH#Z`t3fzYTv+_^mn6E?V06ptkEW?oEP=3`!s8A%EW+0(DkLB3A0nQ510tR`1t_g3 zi)ceP+aj9k!Mk#(A`?kL>eC}3I^1;|u zc}AMKO?!qdBfpMWa-p^@--BsxZvb=*^Upjr9)E3}kl#S={}b{YzW%$~pG#_fd+klC zIsx~)@UE(~M+bW(tsM+gRQ_aO?N1AS&T0HbXpy}})tT_*^GW-T`~jvpYRrl~QXZ)p z0m*Ns%c^o~*;lM4$rVTXk_X1cY7Cy?`D)B-B}V{In96l3A81m%=fgZ#8Q+{M9`5+*s*HROOs$s|a$R=Xw$}Afs-@c!G{Bm@Xb@WN{&f_k8p;mcDCHZ*y zNzu4?Z=@m5)a&|$^KfFO_LGV3l_fiZ)^ITbC=7p~BI3uCLOnmb3 zyu_pdDg3Xu?j`JcG9@4uK-T`jm`SotS0^zVR^hv!NBzKOA&NS?fHixKKl=oIhleONYoDKw zWL7)^XSpE%P_s#voZe7Ww6`+5muSH>=hO{qn{nk5^p0&MG$M*#Vv2+{ZW{A97GqDY z;>=(+UG;aDl8@g<>UwRtQEfC3wF-_XlR--_wU8EwGbYb|*n6Qj<3{Bb;XnDe(*O#O z%q0_yi$~C0Q&FMuY6j;AJ-?ZrZMv~NZbjK`GK+V=E4>bhwC`kzw9l*-b2H{%D2P0y z%SbVs*uU|=Fx46HM=sC&F1M8nvCI&lE(j@MTFWeo&*C z+&xJnrf2Rp%}^B5g%^fnou>@!SKY=b5H7Xcje@7%!R98mvx+{GSi1cqnSw5$DO@uX z<$e<%b!WHO$fMFK6qnEvskpB znyR$p>Qz=x=oJV8<#?k9CVW)j68uE5IK5L=rmUUYaap;a8%!PD3PDZbc?y+W09GB% zkeNTP_7}f>XOx_oPj(C;R}kBV6PQ6oMMG2Mt=k7a4Pmp(Me--P?whf0I<8#K8o?B|JX57t=D zvXwYAYJm=OjM5D`gIS@c_6x-NNNtX%S!(4$@%#85snm@I^^#i45t`cwC4hn9IFj); z%jW!M#D%m<6WX;8w9R@j3VgStslo06bv(jFG>^44YyheGoL9^vkOt)~{A zk*))_$0)>i8fe~)t_mmuLc4{I!lLw&a$W^V9B!n8LloKqlQ|}KSB;n)C2e*mg&3g` z>2VxMC#9JE%KQWKWmaWoNi7fP=i`=DCu3%l+tekesQi=?(Hh~I7?v|k4Q9y>*y4jw z&!)NDDauYyRn%vTV63deMJ1xAtEH&dGH{|N7-Hh56% zsV+>xYbUm2)+Im(CmhjJOTO@E!tMD^l)H@?G%xG*>o!`{>nwc~qv6Jq4r2)J)XN3j z32SsmmBDT*v$Z4%?;w58KF4E9+G}~`wSMChm0>x-?oBJAr|IGyxo4Cgt;1zWw~$?5 zMcA&D4d-JD?rWfkr**8~gu~@G;wQo>M4pK*tBBno*Pec-J|u@rHR2g0aqG(`L{DK7 z-c-&NRjPuPDj>mY! z_He%m`^z&t_jtbv$ICTbcWLO2fvyL;OK@EGazBF8%^=Q4cWAB6O)|E}5XAP$E==~v zp}%&G*6C&e$Kw&AXP{rk-sW8EVO&Xy{3+VtE*6^~a!$xpkOZS5_C+*$d0u(mZf475 zTXgG=3#TcIgUgF+&}2gE!+>lv**NCH(&1NDa?2zequ0wv`u>rtnQd{P#;EpG|L1$= zmu2V3Nw?=ht1y7ofK?&OY223fYgMK7@1V9h{~4+xhTOqP^}u@ucwyy3_$xP+pK2E= z6+O|Fm9Sgx4qX@b4~6iIZ+4VD*qntI2MWK7;g5zN_zaW{p3a&*hAitH{!_*uY06LF|DG%qc!Zt2^p(|y=Y)kEqFM=FYW=^u#Vao(iPK|E`3{=O+qZGrc4hR>i zcV5n%510AH_8%374WcW#)Y^?-Q3R0Td@+9+XSq(PcHW$m;JJYZ9#lYVTCsH^tdCQ{M|{qtxhyg> zC`C+*on;d{V0KJSKg?x1T=-b{cu122zRGGm+DN}6w12fR^o&wrqPGuJi8o@=^tciF zMk~B7VZDpK&z-C^c*pJ%r$-jy0JOkbu{KKK)Y@-vS7$6=eUj7M(ulc8rho6uupE0> zZ+TzGyl~)sJoJm3IZsz~-uGCpH(7x#Pi}JDpI5nB(!Kw)6tOg8G?DUlc$!wjoALH` zI(V9~pLno%aGS(vJw9f4y)Up|pR{6jUfLwSU!L)@r@qm8auA;KaL%>yI({>9K$fb+ zUcdpDM$56GHR;mT2zh}aMd@CB`PK~{z@yY$5@wcY)@HWRoemd7omy|b)g1??rPXM+ zl_hvD*n?rAdV8L2g^_~kq{`)f72C&&5fu9Tb&PTuu&XxhFw{vplfYHg+cMj3zdg;G z02S|`azA8cUzXN!D#3ffInvJiFwHr9J!)4GuX+7#j`cNx`Qb*)Wa!Ro$!q*J^G1{R zf@lOf-RBHv;)t^KsoCqkVkH~QVgUT-IDe8rJ1?S5&L+G5`5lye5O z?t6^fN^OH!%Zo+NXusy5**Hw>_J~l3%(AIOd_SJ?_{b={ymUjYT#NPGO5u-O+(4Gaw#O<5(6Bg5P|&f(?2KL zyR6?O*NSe6UqVmu&Nxyv%tq9NHRhv{nrW$@;@Wnm#a-`BvkVkYmPV9A#@&ueR7XM$ zOG7>)Y4z~9FYZn_fpd4QN+%R<_je~`Ap7H%VSZ!djiW{EqyHp9?5Lu~?7^xPIQQz* z0mSRSaDS7<)6=qDKUsLjeu=x$bj@#Id-HO8bKUjgZP|D*ol@DT(6<~4N0RO!j0Kcm z*aH`I-y|&6H`Wd_ES0&qG&UY;)n~L$lb??{^WtmzRd4l1Mix=l^iT6|J>>TOi0Mh^ zUZhaC=vGw`&}XbQ99Fcu?9<2Gj6SFLJ0|DsW?jP*)_>gMB~|e= zV!JVFKEH8gU2HbWZG@+-WQ1ce?F#cp{weQW48*{*-4S9MZ7@g&CGd_4e@ho7C^1;g zSlFs~WNOpa>^cz^3&h3i(J! z{qgRmJd_X=pkSV0QzhIVgPScp?G<_@8spNTwM!z2q7j3Ss?lUeC*IEWh6%f=h5 ze?GRoUcQ>r*LKwJOySfgpgQf5&A9Ml|bg&h-{ZPe3Vr!LU&d$^u;a zbx0}k;!~btd$Bw1^H1L3cdFeOhb2xwTM0$L7?rWHzq|UYVqb5cWB`(RsDk6sJNdzO{{zVB2obM zazEFmg;b()`iFfF??cP>_y_Fj=~uc@e_`$RQWnn77Nf>`Lf>wF|N3^rsr$!;>=jQc zlrNqqJ7>=}k))a$F%iB-2eDBbn+lq#x-`gW6Wv*1SGoR16B?y32#cvx^jFX9iw-Q; zryIcmCPJvZB|%|gC*oa)W}C15cNqe1)s6%zEs^FYeD&eqSMW(!eneZu4Ayg1pE;ht z1Kpccno`uCVpfILfn-+c+Ws!XWY>au@mw!_xs;!uicm3#fn0F5O22Bk)zBY8R&V+< zdLQkuK_?`nz4M_my^F1)Z&+@WdRA6=w9@+NtYREF>I3AA*rW*nTQ#$74nu7H+!m}O zY@s1Nf9Y_M4@+DJU0@{kj$Z$uXfg?}ZmN3!Pwi9`AY+tGASwDFKQJz(R@AdIrUknK zZ>K47NxlDcbW|O9U%H(@Z`dFV15nYiJs+449b>D|eW5q~m_J^iobQR5lV2x)GP+(^ zp4PebG8=!Qs8T8YQ~V$HwswX&M&2dDX%M(I^6;h_8$?hRE|(0<+;uG*)Ib+B^Jb8$ z%8&LSf=oWeU?CM^CSzZ=RR4@z;neJWv`P36Z?A5XeWJW%lJ7%@p`Q)1OO@XF`{Q1m zod%t+35$OG$6kQ*yPBOHp0^uDCJT`WIlwiT51h#tYLxVeNyM~1jjCpqB!$|`e~S)G zXar}3ZGE6epnL=TVW=%$RJM*yn}MshZmD&`#|4+x`?vL#3;o52vle2cT`TNmS9Qe0 zT`Mp6giY(`^q}xdu$_+Xrw;4WeP_;r3+vWzmxI2-7+lqxQG1*&%eG(t<>h0d9>U}2 zNGcr_ohKA2d(t3S2Yt;`=D7}hi z)~xOqpLZU@p;g%-{Z}y+xTB9tw$pgnCrCTqXEPRNrnwrrBad6q+PK|^KwHe3qj0Duo&6=YzuLz8>0BR&b=7|Xgvzp+TBA`ZL)*PKVY{Pz~MG(@xj)XQ<6ms4tQgoFDeBx>0( zp+5ecJH772(gj%lj=GT18Hv>R%)!2)#okM=P~@yUV2?!E*pl2raWreThsx9BTpwz5 zS0kso(DlZ(5^02Vxk{(AKfcgZ6U_Ox>XOP?@U4Z4+pZp)c&+CSpw8Rrz%6WPn9Hp0 z5f^2PWr9R}$9%37zNTAtwZV3xh2ho}LI;i?D6EY!8puwEln$C6R4O;kZ-9MLgkAEgQciHy~e7mY!9D;}-VsEpxc zXIv%+qMXvpF4N;Nj_I{GxoLlshTgf@W654_c4c;ksM1Hb{}VFxuoXCodB)$v$4wE? zIKuJLKmCeYxF@{DHGf@YO|}ZTBY?x%$mD2ka=JOa*p*jRBBuB8jy=bNZ*{XLqQ_hA zcH2fSJsedh+Lnc+j_8p^p#E8@Tfv(7Hs~`Qa=DM$76%rDm-mSd-EKDm9fYNSiZ=Nw zd_!m1r7#v$L)V!#G<*;W9jZ{5F%~$jnAfy;C8TDck~U>4te4M1CxTbN!WM!v+Pber zCEj{qM;D?qv|~4oGv>PA!xs2bFwuLiu1eZ1yZdK1ZCdxCr;1$GBQtUz4;k2v%8W%M z=*{mAoKd4~()d#Al;2`H{3|y9<=swCML%$B8CSVwF|SaK`TW`-#7PtmzWP$;3cs;w zDe{wvMwm`zmB)0c8KZM8pjj8=!G|C(IRKV~tdu|PL>z!`>^Hx{t zZHX1$o44{>1Idrw2@T$FMH_X4HR+*9-R;jyKHq1FpeG;zLL9VcVrShU)hqmEWAmNW zz~NZUeH{uR)hxQsM07essMG{g#0tkIw=ThSxo=lSCpyF&@Eu#W6COh(fJp?JQvcUC zYzb4ivrVu{ez(IR*t7+epWTFQ zL@oC%$>N3g_OV7#hg<0S{s^v)SDu^c6aK@_)hTS7fKbCPhKT_d`}K&Jw~_QC0nU4nYR|6=!pT* z5wEEyYJL| zgl!K*U4+iN3aTH0(+Yjj1AV!1N$3vIvgNg@_XxogFp-JH6GW?x zbc(4m1ihI#C}u)AEq6-9n8$7J9We=0Etu~TUdqTTiK#kpB^1Frl<86U-Tg? zv12>kL!EN(hP9Fav6GJ+O=Z8woweg~^tGGOja`Wl&3-ue>5JWtQX2bU4H=svyJ4gS z2oYc%>ZA1MR^CFBnK0YEjT{w)OiEY?Lw1C7)qJem`j$kH!ao5{(A(S>kwaG9h9SseJR1g5zKg_aOm= z!-mA+`@llC1D(jlXs-=7aM$@OFurS+o{N?5hb$R=!(Ru$!CwaewC7QNb%lh+CqefM zRAtzaMla?K;jx(_;-YUZ8@)NfXTh!%NerKsOjTIqADF#H6gVw6iBGTe{ zb~!q#92XYsUOt1_DZR)KGtdQ$(Flsjw+VT{O8Q!-hgUg6vYw% zVi5o_eY3ZI8&Vm%L#EBl1tZ;s=O`a4*Kj~bMD!icv_qRDFPM1_vWyI)dA|10y%U3K)6S-zUH7PXm#^f1ozeBW(p zSd*RAvqm+82kt7u$LEKUe@g?9fnY$CwIVY(RT(oZ+@@FoETQFEN0@i9PHP3ijZvvLd@b z>upb46c29m{|Aw@$(&0$brC5eMh>lwmiW8G(N&=CD|EMtB`U$(Q0Qoq>XIX}*>n!A zg0XGtd%`e~3qkcI9-tU*8~yM!cs+_4Wi7c|km#7#VtiBm5K>Dh{s<~n0*#@E+rLyhxVw3%MB=Sw+&%CgYfX+xT&##v`-UN`ZY&%~YGJV0(ah+|D z(QzMbChc1eC2rAzJ;5wBx+)fw)V%nSj5U-h%>R16X`FVJ_&GZuS0HZB@y#ZBkzA=sR0Ie@2SG9TVzc#;qf;r8Rr_}kS5(Yr=(N7$niiWl}(!oL!IB*Q+S zpKCZ#82g4?58q%k2j~(DpoAoUyYXE3{+!ewo%eLx4EDTg@4Ctl>T+U{R|#Q^ZRNq~ zRr2R`G|`_=bjf{5E5F8f**bq!>=bi`$A@;!iCZ_$V^uv0SN#8&w5ms8iqF}gWyX2` zFcXuYjy9~h>tZHU+^=*(ghXv(nvTafR2NK6P>#;L30GBBALG9x~*+c89xf0b1<|-c9492F8EdO5J zCCFJUxWNBk$bX56ATmw=5)7NAZ1<=@g&=+5qknu!Eu{EXBi;S6Ee zWu6Fbr-MHVy>F!PX>@2fwG?jeCvm#mD3dltG(Z<7nPo8e2y&lyiYcg_1#{o7{tvlE zr93_Zwcp+)dFfZoB>aSo#Ce+yR}~9asPupX?U>i($M*W7S$v45ViQX6e8q=ow@2_axrAx(sq)*=|8$fw6W=(tWiIRNGX1 zBnCNgn~sg(`N#wRr(Z!v1sY^`{eG$w`C(@&GZhr7Gb6MlK~omX8%;(gh)-kOn3pw3K9 z7^DQtY5D?KiCm_qhYJszYD|f{_0TO@_ypa?uRZ^XM2emu zuP$pN+V>A551A&w`lr7*p*rlA?3aY!jbFR}32B=`J#q2o6)XaWWV#oDF&4 z^BX9U^)XAf<-ZcH!%pEh;Wf77egNxV;nwgRQ0VTTlW+h9C=UOQ0Jm9;B!}=Y&6f|Q z2S@n@!Mfp5yrbzm;gumLDF(iw;xaZc6f}H&q=k(T=n0wIsPgJyWoX7}zfK@j$tF2` z=3#23G9CUIDcHpLjNgoaQ8B4%y~9_Y?+?WnSx7$q4@UIL2r4aUR`oTS5P%1gY><9v~yghyK5fHXL7h{y(N)WD)p^2}PJ8 ziUPmSA?N;Q;w#=9a%a{jL`Z9LZ~o7?u$wZUg233m{+Cjx@=ngFm|1U~QOg1p2cny3 zt}(Ep(kUg_jiJ)kLy&nwl=(|3h)FLv^H*9NFX%K^~%+M?(wX+nrMnvq_V z9KA?`b-WZxdN@Q}$y@0;y>Jbr=!3(8%1QyMImH}>htA2D@JL&7$O-tKz6=Y?@c3S% z#71ViL+la%vl8J;w!T*EX;`!epqf_fUT~`qPnO289;~21v4Ywz?U!IclW~jv@qyuP+3~Xo@?s%D}E6l?Ah-OWgXBHh{N*i zV}WuZ$e^zVCawc{FmHWsq73)CUd27ogm4KqpdV=gr`Kq(dXKTw0nWJxvqIyXV0Ur# z#J?Ugq}bnNwS_Ey*@W7@^GN>KSRsYqz}zkB!qr2=kNwwh*DoxK?4V#I8n}ncSOHXE zNWH4%in`)54_sKRg11trgNjTB)PX6K0P1iQK0=Cx0nEY0=!MJPAX4>7Mwyid$O(#~ zlPbi@1FlFY`eo`d&<48F$A)Dq!}sZuWAGPYiS@})gvwHg6_Mv<$NoD*p_W3yPj-$R z{qLU=Ltm3z(f2t5e_|2y5Jh|k4{*#B8?=`gC!B~+>b`bhXz9!yiX1!**;T2_9u(`N z(vmg5h9RCgyB5n!Ni0{VP>Q-^rBoVx0i4+}c#*I-s9_Un$psGoEc1#gwtQ0>nu!B@ z`l(Q%&5=d`oD;=k^8IYA_Q$pqVNe&xs$}9u9}w?EOy*JQrO+UXpLk5 zy?Rolp}r1(*@4F5?R@;aV#w1$MGQnk9^!HcO_JV&i9DzB&`VhjIv8L-**g7K7X~d73Xei%1H<*?6CUd+#6Lfb&kxmx~`4MZZ>kljUvttbDl6#MQdut6Y z&X$wd^A{8zLyrPVI; z^UQs)LN{0kX@K45uRI1Rq^I>uol*$sq2^(1G|^@NU23t?ymPR^HUDMF!Zm%hfx82? zhR>RtH$N6f?bNVN4AwsaZ8^0Y)OA*RUj7O-{X)m}F)hbCXoGsS6%727VU#;~hHY5+ z%ZcZ~_vrd7VrkwzSmRP`6^gK?x8xatZcu%nmJ;~E4hkfwyLpKt|4Y;V+i}(Hflg&vLR4}u3eZ^~7dbhgXD5JG! zq=?wTw}Y6^kz4P=jU8YQN{KxEQ_`7Z;=n~-T_0!%6%0V#Fu!u z0j6v}l#(KD&Vy91FWlC>yubVR+E(vr%tYd5e2Sw#c8>fNdr=mIHGnWl4tFFPbhOCF z;rQp6deSYXD9H|V$8Fel#$=sTAr0ckC zB;u(p`4UHzd74PQl)j{g+7VR)1*UBooITnD#hOb8gzF$c|C*e^C1g5mB7rYrlq}~a zjtBQ4!1G$lb%(2Y*i(Ha&}_xp;@eWXaK@`hQ@mTbAKx|i9#X3ol3$+M(B2yq7SVz% zI$B%`8$Lw>09)>;fcaMLP0Ns0{zqu}u!qcdq+>7Q2G9-6`Xf4VeOb~Z`9W9;k{GHa z>G)AH@%@!}yElL{C~6v0DP&*CjbNsO_rN>R1iE>b!P;fm?-DXWd-EQ;s_llZ3Etqo za<9}Br!Z=<(tq$*kX3SDPT{H4+>*ii8+K#3N7qWJrRB=YHTMeirPk^L;eq1_p#Ed) zQSZ_J#?3imwc2B>@r6wZcEj3|7uTDi{}}_ZOXs{|b6u=(dl}_1;zl?t*(P$RN8XaB zq#)%uP2?`3dd@Ziw>HYJ{?nhJdSw5+0U`Y5LH-oj-AroOJ7nT>s9?L-7^;ReUx_IUBui z9I^ESkgB_(895j<$X$m@=zcJSsPDuSA z@xwxv@xv-tEf$z17MYt5rKZ>}`+9+1hS{qKzW#|e^9wmP0a(=n8O^;GbbLmXZM4vC+-?rGsCtM4YRh354WTdC%== zj^1L++F}FOa!Ku|gWYn@dRn@&Bs#K0U$aDiQK{FioiJ*c;NDHM*m*p0_830XQu^-X z_fg={u}t&+t97_1nu|d(3d#WrPs3u6IEJ>vt9v4(~ z&GVszqhAp%)sSstrIa$L4FaitrR0W*zi6wM2=&DztP7~5C-c4;n}gK$BCHVan? z3)&nj2++$qpEo)_g*kU%Y3|~PH=a}C!p)h^znRWIna~^H+2xc zR~>6s{|l<6hGhy>^To<$3Z-SH^NP$T#i0%g==u#j&5N1Y2`hn$$fd2BjelA*<-l^|2y& zeKmQYwr&d&r8#9;lxZD=A)F!Ia9qOScr=3%&Rf-=QFVU?RYmlv^~cP~lFz?~#v`*k zp`wI^1ot_&p;WMLp9v9Z)1y=-eo>Zyp!xxZv9lzUtw|54NEA_$5TGOsjYI1j4$&nQ zsQR6)Oo&qI|E1m!1mikCV+ARD3Nns3w6x(6sQ`h3-`R46Qzp=WqSQipDR~MK3Ut)) z;SeEGft<8ash?4#V)`Kr;(4PoKd1714`ulvioUA~gkX5;2cu$V3j~rgD)dXl(aRYK z1i%vgicO->%O75R0vHy@rfH2v&>9Y4*6f5WUG<$l>N>g;wzU0O(;T;?HEKwxS%F(R z+dFmiN=T?0$vM3yZ{ZrIiIjyV5Ws#(b`9pB7&lD7(-mIpj!+%^3(tuznqB242AVgC z3taomk!z?%n%@!^-1nI>*vE{7adk0qb!imoFew*5x65jFh4S`NXbt`y>ZRIo1iEoA zVlIRw?t~>x=w5p}1@4M=l809XQHEWshV?AG=!_T(2{orj`cG4cj?f z?y*5$*D7s6%588eO=Up#NP0^}=^9-mMqgH!1>jlG9A&Ab(yhLJcq^rmK02_}H%fuA z*rL~mjd-PhuwExkE6t*(*+O|C*kPrz7$pp+st_!UqOuUo45um|#f+jdAIz*?N03-i zK3Ma17I&7E`gR^x7!b0N86%jf$>kb0osvmW)Sd>gDlm$~F9|WIK(TQ`17Sw< z$F?Vtgle7rthD9;Z9Eicg_0b+cEZ5Yo{g&fWcKmOadJF5FgGBI?bLR|3X#|bE1(B4 zxCVS1*snu^NNl1*LJiCgz(Y2I?p^w9bZR+OdP{Y_54bOEL;;EkFZ8gu>Qm0P&JFKGp1`Y=- zV|F`I^%Wpa5EbF2_e58t9_D3wB~A@$txS{FRLz66`9HIK1rejh3wTEA;7iP=TE=a@ z2f_No&LhK_7Q%VbEKK;6+cv~$$=RTtTct^4hh0?>>Issz5~-ttt}v;iye>bf$HKG| zwa3fbdDaH^ZA;Mm{p1Gzb8#*~M6Au+J^(v7{d;*R)s7P;4*@-cw}jze)d z{nygEwEJmrII!^#sIb!sg{#IL(oQx3wA;*hq|Y1M^VO-r@;h5Psot2IawTiyiZ)b7 zSX)YZ!_3Wn#0Cs{7}cqxNmG)FU7>1mRR;tu`c~c-&1;JfILhURS&sc>B}fEkGrV=x z0cWwsV}^1J9SpqKyo`{AtuBYr+>YUes^Oi|Yc|GXx^`4Ww^aIO;FJN7rsg;kxdaeA zSIEc9FMMeaAuX(YXJfde6OY%5-*tl0ujzZRK!1dsFV1W z<#dx)t97F!{dYcH z#UWhl0{B+hf^h7u7=m+)HVIYnTkF~J%Nj|lDE zV{JPA@ln>ho0H|qQ67HA{LT!8yXr?yO9SYw_m-9h`sLFd57MYhHz)mo{z9Y>9tP&b zt2pCELnd`boO0}x^}c+kD|t!|P^Op#k(2yQ%?(I*FTf>b2N;*uFI=7gw$l%{V>Z=N z6zch4jf?CioGJBi<8mP;C1RWsl<>J=?u+aSoGHbz#akMV0+h6w;Bgay9i~va`Buq^ zAYV@4JG`dA#6q#;ZM~@e^%>@)1ue^YS3h^{?M0zi$cO2r7Q%Z;m)FasR*6>zEWvqS zP}yT8I>G#A4~}~yCPDpnPupTM^j|vjVz~&q-IH{96c9$&pG$v*>({u7iteNeJe`Ow|_%iC_QNC&V+%Ox__f=vK_8L zEF^}0KOffd&0)WxK^1F^SLl~L>g`!AZM+J&Oc^|Z3l@5epei;s}XbiXOducD@`aSGa5!7})~65~Qjdq1>H&RcH}Q_aE%mb=Ti zWFtg>JMGqC#)|+LYXS-RijqOx;`q^8?*r54naAOxhict8&fu$ON?a^NaX>6gd3w=NS|e$`O68Q|xz z53sZb``c_F&|juQq7IeNgH8uq?muOXu8y$Kb)l2$>KFF{MfrfBcuo~18BT}tqs#9S znJas~I(gwAz^RGV8x1t_(a;(7X`(~g@42b`r1{Aa7zJKoyDqDoKhJPt4S*pQz#-B<~B=r@A zEHoHRus4KgCo>d>`I2<@H=YdR|Dx?JfZJ@gZNZowGc&}@j+r55$IR@QA!cTXnJH#w zW@cuPnH@7T$_%6Y=biiRow|2wW~yG*+F!44?X8wdCAC^j8yE2x68m&6^z-ai8uSud zOVM_A@~6V^Wm_l%L!p#TV$YG zAxF(!>Hmzu{yg|oFP{H|XL+|Im88%fpTz#i1EzfL33CC~Hb30;o=6*gaZaXu{DGw% zE>mZudY%x?%>If=1GU4~k7wNupQ58&WUPQY6407bY1OKC{KWj2z?r;upJc84&C0C# zOTX)r?`&(3?wuac>l{KG6U^ySrljs|D$5QblF5pXk@W4-#v^ZKl4{rQzi_^k2Nd%d zkA3A{gj*ZI!W|M#fkf^Txnkl2kLfc`0axCx-Qw1o3&Z{k-xJ3MjdRC;A(Xwf*Y>8p zgurm(PNDKh*lU!cYY$DYC}dSMn8vTs#Kmuy1Rc8U_~0i2Ouwcf3bRR@JLm+oa-AIs z#%r?V$2jTN5elC@G{Gbg(kdu!QS}+TK@+1TWv_xh&6gioA8?I+nMwU};|9fmrweYK zO@V-M-}^;U0bAd9HLUiZa#sjd-VGn%w0`WvlcQ#bd-aYSHI5vCr-Sy}(B=hiBwc22 zwE+i@Q^(KEZ{i;>Q_s&Ew&!n~GulQf(St1&G$-Frne{g{&hR6=jcRS_@1q90YO?~k znXnJQb{n%opsv8_0|_)BBmORjaWMD{T3hnzy%yBsxFII>!_AQGE6(tnu*mq8Ug7W| z$@j!FAr|#3U$IU6GSjC7&GKE*^T9akGfo8j`x}APYv`uvbm`P~6qiKbR;(FI+Ln*i zTn~Q_BhS1-#P>ul;u~vjiVm>KOO<7-4>RSMnV?Kt5oJyPUt$z^XznLN>R&i;UxNP| z8uvARBsmN%G#_$@+K)@>OZ0z3658H+9DLX;F z9HRFSR3Iw5zd6r;f(5E9Ltd#ETVrSu*33L1j(bE#yhsT~?%NP{_HX>ZMSKcEiSNUTv-Sy21pgD|#G;wf zK=|4x9SbkLW#R_)LzQeK<1b3uN#}J@PpV)w=Sd^9j1?p3E#kx&>Pp108b|W5{mNkPB}72($re4ECPnf2+RH+ySJ=hjDG zXC7%`9*L+iK;nEW*Nz?|S`2YpQN(Rqvmu+1Z)I8ps4$mMOmjb>*S$ovYoD$i=bz#oYBrdlgPiG%f?;km#_a06^V2fwpX}93 zJqG)f@G}rlhvckHd%LRSt>rZp<*M^}j15%*%oYS=HW|(k)x=89i~U#BUgdXLTR>$d zk!5ND{6Vw)M=Ol%sGWL6FOKjj@#~fUpW+8LX7(Gz;F9WuVzN1BSnVoZ*njWjiPRyjhZ-6zbif<$Cki4U z_duI~vPpB6zTJpab!m1=U5+2M$`ZkP5Q|+(AFby-fP2J*lOIp#VWgMrncy}_EU2}{ zPr1aQy3XaHH+lP8XHVZ?ITVYWnl$(XFY5lxls`Qk$rsCDPGl_#+jzgFsCA)Pc{MY> zY`+^H-E%E91Acz*KF8<;0xa_0Yqg3lG5hcO=kt$`4q4~hZ@lX+q3tQjsB?>9fh82< z{#x@S(rY@MQK;u+%7SxorIpcX^M=M*6$UE3@zARI_q+xre5l~)eX)?E`cK`H!E&*1 zKlPPYT!VARQ2X`M(rEr~Kj0IJ_=6sxv=Z|?vJxMXOkW@=14%yr?)Arz44V9wHQ&~A z{f&Mmlmf3-lq|`704+)*50#hAFhu-pI+PHvR)oyOd;lqGITsl4ZdVv?k-tr=Z)dpw3L^Tv3m;xU4-Ps{6u9?7sQ?QK6~K>B*UtGKM_w#@sNp@nIQ?0zbmMz^Wte!4CwLr$t49zt;aG}NJkmzo%W zKx4vl=x5a)`z|wX%&42pkWtsDnQiad6;cPx=@TD#(3OCGd)WB_#}8j{-(6twR*%av zRQrP3tz%b&2!q=+B)|?9Nu)eHc&-ODLqXuAuHDa{LzMwb)r;aZ)_P^e&gv!jx5MV; zhM83AyzLcTX<@45iz&;KN$}tpZRXGcE`I&|U|~6H?Inn01G8u}YbfB0`omvmB!r`p zU9-ge#-3nBZ}hC(*ujbAX{8PEBKVpK>>YBY$ESJu66N|DXOJ#M%GQ zmo#elcVCj7b-#J+JMQP?-u)g8W%1rbCOjh5aV5%rj1)M~M#n2izRz>|JbX~{{RnQ* zf7c}=PW3r5!5sAQxe;OYz}KKS=%dmHV=vUn6_=;}9JSC)gQBrWWeR<_MSa@6VRcxs zxmgyzhP}R3OhHiArzIdsA`0T*g5E?aho+8sUdi{lFUjUVG5bGGKiu`TYQq)l7yk=F zstS;FzpvxwUqmXp4&7mv{fN@vuN@9H+U>s zcr3WOeH==%2~Ma&(nj-5Z%R`6EGT3CMdNNt18z!{Z%V)4l#+nJX94-~IgiNs8=>1}=m+3wvyk(&ek0U+gx6@o-{=4dsci?n4(eskX|15TD zh5V=#srE2e`S_g4>{Jp0T`A(~aU_e}shONnWoSN;_!nb1X)KFB!^_UtFo~2COOMM0 z8bRX|KkVT6dJo3~eAiV9Z$?hdWpGi=MuqLu>CwFR#Anby-erBL+r|KS-A)6NUi>U2 zr{e=+^Y=}EXzH#!Gkvk~GnGe+Uk1P2^^I&1HGOynrk2n+<@ z%d?Cm*$WVUYnq_a7Kh-MWS5(IQ50t1$=k}x+vI@9f9(!Yh#EYfl1Iv-J+~zN_(+GG z%Er%k8L{%J4`XN3Sl;MlCk4j6z8>`<@&+nim=_s z#oHxtBYAAy1||EtCXu`IN7tXtp@9}B-k6WC&*(2YN)(Dst82v-b42tB% zMmwxCsN`6K!@Jy0J>rINf8IGl*QWvyymIi4j^lHRRXj=xVI(%beQ@S|v)y*18@BSG zQT3c2aX#8L>V00J5Y909JojNq-*6!`PSkKFBprhlBF0&pO&uPL2D6&IfqlmnMrQA? ziHvHmTjd&B;+ewA_mS2`isY=wFn{$AMi}P*16>Sv?hHnR{i=1T+#&U^K1qlQ z+GDJ4;dqff+wW`pTO32*uSD%=xx)`@b8kpfI0~v~6>yA?P8cK6d86`TEd<0oLpmxK zZ6JB9mAcd)&Xzhv*NWF^kZD3MaiHahb}L}p+qlu|AajQKY>U-^2BhBMOCZk>IB!-+ zq8XNxB25@H*kCQ8nHTS(S4i6HAYQpQ0BP6iTB!Hf+o@cYbJubith3x?5sRbCnlWZ+ zwF~`=)!yCEX578c#?cz%sb}k0i;hJZlH?T_R1K%jiwNv0wh(tdcz|y8f3_IAINn?7FXRX*D^0$hbU_}LhSP;DMutj2BV-|czh_YPytwH z_BDgK&K}bqg8a~`1e*&er~xlkdxP7gWb>MXBF+lcI|ptp*pxlqpg}tO^@ix~h%Lb| z)}chB8!&OUxHvTy+n0sp$UDgwNmV+v=9%%uoO=PV7rwLGnyD9??HNw|IdGZdRh*Zi?i;5Sgx z5PdlPf_g}5I8WN4^DDWzhLNmd{8lqLd4#=UNs4}LY8l*eMA`n}EGN8{a>_(D%MwAo z>beZam_EqFP@$y0g}fogh;Z2BQ3`Qsf{w9inE zs)QA=Ut3;cW7gdXD?OYVPW;x180x{-UY|Jk9|vfk8Z8PIBXA8CBpI+-p~RI#!0eZohECjDA?cH`qSujdJ{IjfCO{M zb3<+4C-{J`7O<0HjEXdQE{d2mWdCanMb}(Y_^Y)_AyLx8_Yb|G=9yDw=LA+)J5%`1 zCdDWZ4IQ(b@Rl)DdakiV7dwhGS+8E1sN!hr?lFU^*&$W5E`ZSHxf$`n8ONj?WK;7R z3felCBOiy#n3~r;`!Lxfa^fFm2X&wREV&X0onzQ06}+OO-UZrLt%x|8B-;nrUF=cu zGM=8q82vd%pG6rJ2eC~U`_wOofdSXUQ7S)>6-dpmO_|6f0@Tjye-kv^m=z&hzMFSV zqZ8f^tb71oA*}=4bI*NQiSuqhoQOn=vrl~0uDe$*E3SQaF1ONskIdps3nIw#>D12| z>GP>FM!2c$-$y&dEAcuXFI0X!_;q;H=_jj@#aA;=?+X^f+%CxlY%e!=;DCNGa{Dg=UW>_>FW0S`ocUYNx=&5% z&tqJ@#B_9wHGZvpVLtK)^$4qXJN3%ub88P^*5KOab1@umVNUOSD}H+I5qHt<7X8sq zXOjI$yjSO?9k$uU99ELU!EC;2;Fm!>lRS42r*HPn+4e`g<>$W6vNe{jHzyLO{_7jk z1@H5Xy_%_Kv%Yl#k80S%AMJ~<>ZfB=A3HqTXL36&AIDnTwCk^^Z=Q?rthJ;m!@fTO zkYrMCrKiCH-Qs{Iau*bM7*ue_&1u26Gh zlm%$~(J(~OM)atJ0aMaBcX5lnsFEQfnS|ZAEH`q@m;$_YbPBhE@)=geC{^#Pa6fe? zvH+J(b5}TPkN(nz@d91qRbZj6;408;fn2$CWnLp$@}nBo8cD^Qhn5pUHEw^iS>hZB z`~F)|wEa86oDFKSd2{&6Dlyl_kmma)VVj&cxo-#_UVaj!FQM($N8y5mP`T~L&g}2Y zjZWY?udZ|tFC1(;L&p z;$6x)7M>N9emt9`*kt+H2Emm9Q!Ewgsc%BI1U_di~!C&FRWGrPw$vl3!j0{ zz*WgN(>K#|7Viw7c9+(7iMNNiGjf0sg^Zh`OZa=wz;xw_R;^VxG3GlwVKtJ!yh z&k?I4&v0*FSIM4vpCwjVpNF3r8Pr{YZ(3bG3e^i6bNImO2I0={whIE&F-O*`rn=vA zF{O2-Dn)}$%9>mr&&ipHJJSyyE5=UqlOZdA@M>tfEz2aSEX70P1;;{zI`+=KZ< z%6|u#B)NP;iaRv7=Tq_X~|JuOgp4*{d8QY!EJ&(6Pcw=}@=iW+C=zfF8EzV0m zJhs+A=FriRTy>d@d_uylDYvM+r^2mzN$$8u%CB0LXz8q76@Pj+dBgvd<&&ZFmGe}$ zfXwxjYFtXQ{2`e^={O)NHm(Snbv6p@xjJfl$j-YW&U#|Hn$r{)>e+ipFACA4>bkU6 z*B3y|igZL56%ahT6jBjecnRwaIzM7uI8#LT&YT*LcF8s9KJfmycKUtVr;|m6ux#-m z1S#0!u1vxDh^~`o9>ZexR5(PW(!={m@+kCOwS-~5$TQb=B6h<#7{JyEIJ0s|nmsdg zNeo_DpNRc#YI{rnGu9y;B@=by_|b4gJC$;5zu-Q zbKrIB?q1wFtwVjuft@P7$A6&YSo&Ju`bUTHl2bj6ZXd$5>nVDIW0QR|S$Tr=R)l+< zo+DzP^+2s&Ws)ubz|5hmb7Q4nE_06q<|hY@K<8E-0;Fux zP1px`IIvzZ_N-Im>>15;=N^jMjvvmt? z6gb;X7Z^^kTm#x<*Dq~UbQeUb6p_obvWnj;i5?2@N`gJL_{+0^Qe|-#1<8ftrH7qX z>}pZBQl-}x!O7(U3XUCGCzg$) zLmLc2@j0cg+E+1K1eeh{veQGS7#YM3zzaA=Bu3!H=PHD%yEaHpNW#t+f8K!h4jZAR zobn~IBO<24Wr&^{lEveD~Bs$TRSEJ zoJ)RO83alXd8l-Mz{XtfqJB9i{W9v=Rj|Y-(+yVCuRHE!q_lY*ai|0vj&Ti=ZJe~f zQE9fLqW44{I%?x)<8*9w3akn$9+d8O%y}>O%|py#Y?bbYj-obBXMDwNuix=I89dS- zOz)zPx;vWlGV?M!Xl58^7&qq4m(0~K&&`|7k!`ga7IYwq1%c%`8d@!bF{HN zM>JDBOH?E@^Qtj(jC{q%N5kKJh>;EJ+>MF!#$4O$E=iocKRil%24(2-4tg){mfbAk z{a$#vm}yede)M9}c2U+ohOjRCkd)e1P4s2_M93qyq9Wv|*cg*vB_?SB2>%R~T0DIG z`38gkdpAY;aj8czpYGIb{ocy6?pqa~M0d4d+~LU-kn_gyt@2&1X%7C5bmfO{b@Hg? zoxDdthobEwud!LD@@0}PFe}#hK_O6BfWRX+fxll8XH261uBPA&+cadwK|zCd0+f`a z&Vb@cMT4S(R3ebSkI2Dzne~hz8~!C&egwO(cRT(@aC>fBfm^_f(o4JxD;ic}By8Jp z8;6^Q0KbcVGd#jgM=k<8#%wfZr*PL~@9_HkI`f7OE$&B(A~grUH>GM}{LxqL38nf- zi{5(DTOi5QB@4uaXh&1(%k{CAV|=PUC0SF(6eA}c>U%=Nx{HF1r%T~V=u($sDvah^ z^h3Uc)la>SkMtXNRH?59mehBlX_-yVrmQ>nL@V_rZ~|Xxs0~zwte!|tURLQj$^m9> z44n8qi!l!)!m0VKdzhw`srAh+_4hexOE;?8mPuPDdJ={9gJo+;R8to`N@AwvnzkIN zst3vb1qcOIhmN+}OVX^$C@)X3?gl1{x%bwl>?`GJNwi84qNnztvy6Xj)J+V*m3k)N z{_HMn#lF0irJI|(6SC6mecDv&-UoAc-PZalwtkt8e0|QjlYA3z*2UX%lTY>|fFa@R zrzuJZKH!p?e+6E-YU0OBWs70@1QIK;%i&csU^r2}X|{sd5~WIR^@5A~;j+cFdsW~! z0rpx6#z&_5V>3g+y7c{vleU!C!A#<>{QEAv>j(hZ=7gYdr3+-$cb^g=_mD>KQ9jF; zuyc`NpA@|_PSHy(uj$n6=oD9ojTk$tKELi9v0}2lAAS!`;suuvQLp*@)8)+$T$dm%yNmcm?;r!a3N~UJX-pH9Z&z))oN`M@CAaPME`mzG#SkVVL)^A+RLiR5wiIci{J$K^VWLmD# zuIWj3d3SilAm2;{9`Hk6qP}(G!chuFWzxk?~CDuoFIc}?0;@3v$vdJCrm zs`JJ!7LJBhr(<}(_z-$HVqO4Rj{wpm*GV4Tu~$AowcmGY?x!>dZx`0NEE{UJ_=WCk zo$D%#FX(SwXb&$Ae=Z$cHxC`Ur}llaBYZZ~SQd^?oWe_4=W+K+S((wiA_E;`9jbV+ zX{=T7l}`AaiJ(rrB4gojNU*YWn#*b60BpWphFl((Ub2}%trOnQ>pWu}h zR1H4T4DA-<#1O;m9&+rp={oxZbWdyw{^VbfjV!KK8+ zLSrF8xe~_>*P5k1Mdn?B7vV5eYF|T8Jw#^WpBCB?KToa`vb3Px!V!n4{red9N2>0SkMh}i<1WC{Mj^V46 zQTr7D)QJfP1A-6a+a%1cyV&s3o;SI!DdUQF>WFvNU9exUOLi}IVjW|FIpTtiw=K1E zDwKjl>U?Lcv4y9}*{}&`+Sq5>NUSN(!^y5xp>x1p!azCK3B(%L8Dhz!7kfQ+;d49S8gtb-R?75+IM(>L*BNL7=4@YJAE!r?y z#;SAymG=~BBE_FWq%V33=NVxR7rF>>4VeT~iuq!LD$AVL8flKYpa+zwqMH9ypy8w( zX;VwyhNvhqViKtwY0n*LQ{{owazJTs-GCSMh{GOS;33rcNjk!bkxW+(Znibj2~Lue z&_2RO3ZQaH_U@M!F`btV-sToi8|EyJJM1!(sCuzk~`9pxlz+voH4?N z0%yGrXWilVQ4>D(0ZaHGIF;Rq?3Uu)`w;|&C~>4fDCpzNE0)jyOJK%)%3QwSF8aRc zSDfTP@IV$xZ_4l7B{139J8?ul6UgsIXCt3ntR%cb-UD{NMe*Z|VzJMPa5~W-btqu4 z{J=2k82O}xA@PS)?3#&g!ar&-G_poU1NxW>j4T|2Y%Cu#0(B6FY!(DuvT!i6ERocy zkSVgIWjp$_VKBmQW*%6y#;Tg~RG2B#D1EbSwCx|?{h}Vz^r!tA z%Y>jrYjxw~9sUqOhV^vQPV66qe@xUz&`!n72Z!F&ncyE_;t#vOzjr<@Yu~FA7Ior| z`f?H`0v&D(f%nlagq70{ixjXi4C$;zONJwh>Ydh&mJZC}1T1PYR zPq@fymg#lw@T}f!oe|?oBuD?_B?l`u|1MnzRa)@`=jdi<&Ra(v7q<6NJZaQJV?rH# z+%o5P?zK&;Ptg^!KW0>$C}>h2?t?2O6sM4Q_H2f)i5@8)8hzla7Cbu6%VzH1Di#Sc zZa*6H^#PW^8DQeBSV4c1cgey*U!@>RJizL(e1*??i1o0-J+jLi zOPIH%8;m&_%D_dqj7&nz6!F&O@O{*y&uOYDpQcw?_k%W=^C4JanzDO6Q!To_TFTd_ z%U_*zUc;^h7d8|wF%y6ggbt5m+$r_uYL@F*TOWey=GCpbFccc55tJOT$J zvYG3N?s+kl(#2$6w67Ys-&-l&Gf~n!TZsl=dSNE#Q@xVaEHsnA=m#?}8!0GSdx=LK z@nf6-F?p3Qu`DLoR$n@I+VdtZyxW zJ@1%{Y*>!E{6IH6M?L+FY*65i>A3a9F&Ed6AG$y*+u%2DIu2_Qnc3u@_UtrzOCoXJ z6hYNpx4v()shJVej<;?(>WNFEEkJV&-PsFH^$` zL!UbZOcUJa5twwjx(GIoqz_W}QX3Dn-`kNSJ8Xy@>692MCrWm$4w0`qyJV^cUahcF zrj##8jD8@-9MaXdZoT{EEjR?Sr}rP|8nkl0U-Z5>Ufu3l^*rD&dwQl^W4lZ(hVlMd zC5&8Pn>>(z*uLezQdxFvQtvrqQ3mMG;W&;Y_gu}0z3fley(?e0Xr(>s3QGD&dDMm_ zev-N_ivHjVerbcFGl0+&is&!zRY!hKw14+J1->nGjnxwAtCi1$2MV@9zd4DFac7xK z#|RF?zTCyG$S?c3M9X)&LbcrWesnGpoG@{wmeUJs`9g1h^72{t>b)))4)I}H(9wU6 z2X_0=YZ3F#bVGOy6H_$}8S&odbv>PLy-395CUiR^(vMOv8BRXGJuW_lx4Gy)P({x= zplw=vZRr{gdn5=>zDjuOM+-(b3a~y_TYe{DC%;~=5X{nhug+M5t27E*anD<#kA7pa zt)H^%Sjs=qn@#CH=h~pcXPUz>XbxWb4X@VyNVMH)M5pygZ4|8&w;D$)9Az2dzk0v4 zd00)c1Ris7VGnqq{`j!l!=Q-Q?f)uVWvgU{^+Eu1P-^Wv#kjX=|Et@E`zF%F1v_`o zU943kJN4t_P2jvUDXxF7j-M-JQjD0tHv}jSzf-<~{CIo?J8-&9<+e`Qm^iFDDL?uU z0+U&m<(2e>b-y*hh~|k-r@8um(a`91iwHBL5CSqUY~JWP8ty!1OgVqz!MH zJL*{}2%kc|7%OLms)f<(NzeBV;)VyG@FRn)Z?&6bAzD}_9qD>84d7lQI-69RVY-Oz zZJk-a+wnt26EzqBE55I(Vy2ja=bD)g*U1m!%r8u*TN_UMwau3`*1p;O;Mto_?1U3I ztdXuE4^gT22T|z*8Qlc_!S@1d$uw~#z7I%nHJf?e%-;&&5!PU)1OUf!7N&U_z#iZ1*D{T=%eHq(qoR*Yyz3SiTJ(Gap; z2c(Xg8y>p5^xkIB+CNCoUYrYqwqJD^^mu03%OE@Ew!&X-sPyjDe@EMV`g~SYlz0r< z9%Gf{o$s9wC^tpg^o%d5Bv8%edcUdPKf2zHaU(>snL7=0y_s|JDo*f@+*@Y{_Oi*7 zzH~p{3rM`nh0Bier$=&B0;YNjT>+WYMlHC%F4@=l;yhH%FK_>JqCMJyJ}aNzD6S)G zVwN)xux=qAa>cxc%~E<^G2}zD`Q-oL+RgLnf8Z?rTyF=S^+jj5V-BHLyoq z=~@#B2HU=YS%MAz3APcTGG@r(vIHxv$5OCY0~@njYdz1DdBA(nDlYK8?;CB>;+LZ- zU)Y_$FY>tLIigwCPP8ADKOKPco<#4!6#g-ErwwNX6Xds2X$KJx4G?MWUfA4!U8B9_lGiXHGAmI%uou@fAv$y~pV*CT9OIiTS4$mEHA!^O zaIIj8xlIK5vHk`&gGi+60cs!ZE$kA=HbF)sFZ$RIM=Xu-Eb2_ige#mob5ez1XV zUt;~xbOSU{(AWJNzUVq3vjoV@kc}WY4D<`7=0qN0CLq&>N>unnA6Ww(2f8ak1bZI- zBy6}cJo?C1)oB1-O-up-K?|B;P`|v8ELekq@Va4P7FDD&DH_M7(PmVl|=O>7j z_C;5kPT^x5i&C#Vc(&Dg?S5j-x2KX(T{Z-q&*3}R#TLasR4x{g2FcH zw0I2bKou&3Ds)@3I1c@(CM_{h15%4XYJCMr9R{fnq}*{j*M6!qsKnZsgx6sp;#f%= z{kU4T6MC+OIZRO=z6%X1Wn*;F+IuT)v-j+@HB|{72r8Y@JVA>c?5k(bfr9HV6-3c% zYbV<+G1~kDuD?J!%wG};A`)64QUM~vn*0P0CgmZ!UAe=@*B9w($itZiK)XK=l|<1m zai9RfCJ(L)s=u-&NDcxKU1Ja-28~6xzQn86+pBA^<3E^{o9Os$itnY9T69?!VX`$ zqJlS)E}aR~Ay4$39~@Fjr#*Rd*VIiz)mS zqZ+3KC>3waIFUmvSaPx;^iVp}UtB$hZE_D$cJN6RM#X6{r5m{T3w){53JM+kQx|_YvRhm0|L6E%N%ocxaPvXmhq_ zQ@y0ZO|?U+)v&`2v~N7@+ulv&$UbhIJUHo;C@2ZHPOyC|>8=B#-4lGE9(blaIM0;W zBRf+Yf{_#M&=FjZxoqMe6iMCGxHeicXUs3o9ICF4e+bI9lN_WK9V1plAsS2Z6xwO~ zENqKLaM;9_BQW5-@ZLL{RZVQ{Fd82ttXk) zJ@OIlHGvWlS2v*NpHTR&r1Z|>iwpH0^B$96V1^XFk_y35{;HaAP<^ki%ySU4IdZ-9 ze5$bI@!?8)V0*=>@R>J1rwTN4LVIj`+dT90-NlzztFeF6FX?sr!|zefmujc|Rd;^* zW9|c;;xf)Z{JXlxyvFk^70hicX-^9RH6V2Xy#j<+Rg1(-vS}|H( zaE0GpS{yfICfQ```L zx^Z!*Vvox-Hk)^=J`qFp2Fbf&qPGHE6!+CKCBoK<) zljKHQa&I7rvWxWcJJB%VUpB&$_`D0s@rzFGQItVVMS4m8#M2o2k@z7tYCFPd?-HKj z-=Vy(Qqav%-0u*a@p;^J-;?X5>y>z+*->!zaD=<&RmCU#(d>qG*^9B;AE3jH&5%lU zn5()u_GEqt-ug>wG{}L3JvL&GbPrtp*PBu+Mj=D|xPG@%l_+=l9^Uc?rEkEScq=By z+8&3F-?;P9;dXj@{_zkk1`_q)AHwE&SDuU`5EOQCQ|7r>}paRA+ zS3IdvA<2ZH2F6l|paRP5pLhlDajg`^aEKzmz3y+B z%mcHx1fAMUxFuIGtb{+O2LNiomU6X{P8H+^7`+-oxllvu=y!$SaFB%wRNy0FZjH$K zf6D=TJy}W=$ytAYcP67Cr8r_Mr;-Gc7Lpd0s1!IAuGQ6??5aG6~fq>Lj?P%R4V=*_V+#MkkaYeKvFg-_e%~4dCvDp7_k+J3xTOj7ld4 zp!dz|7>KV)5{#>P{Y>(R-gn=|zkgDGr|R^(OG{7o=QEx+V&cNmiDjw(MGmimyLV<+ zw2pUY*XQeWAn08x;q5!fe$K9GmE8<}Jby+iEBPq=fJ*0erds|}c{#M=>10L=A?HFo zd%5&LMmT|Bz`2fS;QEG=xX6FkuOjy_->Lr;>I0b+bFxuVTkS(Y^9KBsfN&qI6?{Yj zn>{bzYg$4S%z?bruQ`-yR601ZRiJbuAJfah{-RTY z-Fx8q1~JLF7@;_c)`@X#;(@yW(f#_lkYQ=OG~6Ur1)9DdI}wTaGjZXK!6l0N=g9i6 z3kWYkEoufIHG+wV*|6E)#ikw&Bu~q+%Q=pv49OTple*4#bas5eeYK2GaWEsqd z{z8DG25?J9jo-Y#3`TRSg_&t``g7{~!LRilG4~03eE;1hsPqQ2z>HPn*ftdi1ps^U+fGCZ*eBLT4_e)kDAPF{nppstCcJ@zE0cl!Y9_ za;IV(#Y{K&pTfnHsD4dZOz;|qy|%313C!`2j%fq?AUShbSwwTMIUP%K<%CXC*`tgX z^nrz@mHTznBlPiYug-Y=qR7wdObu|xb{TpRb7x|U8aO%j>-tA18oEKLKsEScgi|3E zl+yu^fl69Yidsc0;Xf84DyZ!PHUpKyqMEf5IJEsdsQWs@n4#K@p;A?s&!O6YP=^X! z#onk^=7Iu0&LzVkofuq42-Atf_QG|Y0__c*@k-bYowZ8v4V?&gN5bY{ZHVi5T{oqz zX~Yr%uDjAuP6zy%(Tkt@vyCa=mz>joeP41&ZwDxLnScZly%B{s9 z&-4e=0F8wm8PnOQ6izzRiEv!U5gkoX6~`ZE9|%OR<=tpBNyN$eK3-~Yf{dfDTx**< zwnFB(c9y0+v_W9arqJ{SkPvDU-k6S?RtGJWsq1AJKhgm@P3-j=gY-@0^~;O;RgHEo z#Aen2D|X6TV30 zN=ysTlM@Z!Pq0pvJs5A^(;hM5HX(8xYuZY%CA(x}8V4mCK}^*=7)Rc-O1R2>MY$&) zk1??Q=kdW4^tY*+O$nPLwhI3H$$%8S1Lp1tGoO`&Clk7Z7yjGzx6Z$n{VNvDWC0WK&$Bjs zSJb`MbQb%MCjr&@zwbe<#8_%Y+waLTI#4T-=&0emucM~>v%ic^^Pd;?*Xe*%UiH6f z`R6q~e$ubie@!gKy?r?lTF9Z@57<}F9})uOP_iS)Az3IA;rLn?EFqpyy8Hf65H$Z* zneuiBg%}_XTZuf)GJ<@gC>N0f)yEo8kMd5&g1hdpHkSlA#ADDE7Vk5@z8F{;E%O=52-VWJe9siFsga3>FOYAKFk>9xxfl2---o9f+k>*KB8h zC3QvXpqWh~=*HlN$Pw?qgsSzC>s~{#?2lIQF-^UUd6rjnCfH!|k&F9+97QHXp2K%f zj3<^CN4-Px8Zs1T7-v}1{6kdwo>Z#_dxlntMF~wnT#Xz*iTjEIuMRs7od%mm0yP(&s#h)ebe2d#yv^xApPy&7)r$YQu<%~A!22m&Bc6Z)~@G{NnXM;m?vp_Wi zs!2Frd$na6P%)_aueV1Sw?$O8ULlolp z1GPLNi302@h$5yvU=f!^xb(Wgk#iaO0zXUo%E}k;oRQ3%Am<8r!Xj>wbc7`|-x>30 z%Fih4bIZz$v;omAPE)VYEskC9c)57-iG&I75%Fql?YiDoe1q$=Prt_5@CQD7WM#of zpW?GkZysO9y+e2fJYOLub#OYGlybb{HJ`>TYh#*Wp(DIux}(GJr}nrKQ?M!qY5giX_uE=-FDgw--CL7^Bk zF{???j;C3eXpogU;RJ&1sL_<7(NQeun>1P&@X3g@smhjNmsZM4f0vSO~XWxm|hXTOpx>OQa}279-XpOTX^o;;jLX-m)MMBhAZvYBRQ+yFj2n;or8chsm@e_ES5L8}h&M)dvNrjm! zFDbVn6vIf8p;%FL$Ud15U*~6+sm}gihNMsLo1VIQ*;N9KnLN%X^W3Tn&E>bZDR_VF z>Ne$sB70H%w@bAW1sD})Hv_jRnQn2ME z8NobK8Sgw{Uc#eF48<)eFsFt{Y{mGK+B``gD$uR%_2pPATCq!j{Mu*7yHn#;Nv1n} zdwC#f0LxoxXKtYQxpSwr`uQ!4B8=i0;{O7XKyJT`pU!Y*Vq;>X{vgA-oM#@_vw%}q zaeOtyXSmMi8UF&qjSOGn`nPg?JJ<6n!yOD?WB5A5-TdrXDM^L+q=pExKAdY8|l|Cr(SmH6zE_ype^e)hY;Z&FEdi^LC z&-ceT3FzT zd9#-L@(j~|CZ9Gi{29X+eVlvA$GPw`)1N;&63jxS=km|>950<(tUTE;xb z@pTN>Gu*)S{EXp?3^y@;Gs7*6d70rh#_VLci{WlT6-nS3Mi`$Zi9Lxuq=ue?}C62DLWZiThSS?Es8 zPs~rzBjlI^)&S9Op=Z)*pL$QX_>=E93}PNs)eq73@!-w-#E8U*@62Fe}DULcv4TMUzgCLIhCKaVg+%eTE` z%E8Ju0PEZBVolQr>cg;_jnGF>E>^G-%G2-Br;?*j!>UyStJY$yOH1`NSdpIAe@fT# zO4R`?)h@b`SEv4{u{E!i*}VIm!z*Sk?|$d-x|xeM?!@{!NFPKBR?NXzH-})|RQ0>` zp;$eKfdZ2$FhRjc*bt-i(MTPmkD*L`ELPQsJ`R+bpzI#NiTXs~C+U+w>%FkfWc@y@ zxtcx&bZ3F?X=LaR=+ja241EUbnW;aB6?qoc;;8QI#p>Nf&)>?=6IMnp358$>$Ab@DDzrlUPqbN z(X;S6%)HKEUT1>Wi-D=k-;j^LVSO#EWkY{Pe+GSdR(}>X3toqr*BQ*~O#MauMZ`Dh zn}8R5&tblYneQ3Qcb)m3$$Sqp-*cJoVUO<$W{w1lMiQ1V;)4WE@1R4U>Rt7&D0zo| z2eglj67}?Yz&6qwf$9Ri0KL3YZ;9M(^ft)XQ}2n`FxeTme2?A`}L&E~!+H zLk$lvYVN{tAZk%TS$j|>D5wbvZlhZIqxz#*(YUB&yt0T7!;4(;& zbLFOTV?S2W4ny!>6G#(sRm^An6*wVR;?BUm0j!X#b{tZC3d)t3d0o7j z7vY(gl`Dx{$0CqO&ZlSc0 z=PF|Z__3HH6P4D=?E&m9$Q_XfDh-sP0KPqG@>d8&O0Lp0kb?fp1@hmO`~VjHmv_sq zd{_zj@zN>Ovkrmez4Ea@$`Q!m=kh$cK>+&>>X|GZkSEJ}0KW-NLh+G zvr;aShsebN{B)FPDm?_P&_(VMNEu2Y*^wP-Bw#bSMIfy+sOl!2lA8svg=ph5sU{Ik9u+Q$-AK+b;ndHK{m_^lK&&{UlY*!?0)tdS;%<)FB3f9vV z`p@(?=<09P3Fp!%%RIeOp*x28bWv|`N5;Bb4d14D{27+!kM8wvAX<>PmooP<#J!Ag zFSEIqdE85#dueko9qwhEds&@(nV;_8)7-x|FiwK*`g(n|(OSn?>euSmrfrqK;+>pH z!#&Jlte2hX^8oH0%m=J4(EfhxW{i330A>x!=1PqNxViW|1xaxNSZH!@eMw=4f~F6! zUioo7@cBBzkpNb-c_4skjIxW7&yREPITK->hZUAkeZBPs;`q5`N&K!t%4y2*axr(X zhDp>3@2*Vk2*x$RyBX?w+Ur9SEBFZO2Yg-VVN;Tp>feQ$G3S~ULgJ4JOF`=4NqjMI ziqw%lMv$boKCB9hrhxV!2pgvYFVhAgHIg2vL8hgW(50vSHPDv`Gx3(_^FR&7ocDcy z4YUiEgjj{P2WnV{&<-|{1b+K#Xh?hU?a=_vqOB~$DcpsSDZ%Y4JUc$c?M8YJ$X8>% zH*`!B{T4{srOf}!S=O3WDQgOBu3{?oapi9Ae^=P}ud|)M)rZ%pIp*711TpJY`%*%X z!aCrK2x1j@D4llUG~4C1tfA_UJN1iLfzDbqYs@Fi3y+&l!oEd<*$v_FlPLy-`y zkkAB@!wo{4EAoePwXZbj&d{xRuSnxnac@fdScA?A!CMQ>^0n}Zwo8LFg`lrOpM;8i zWp;;lYil+56KG4uw{8`sv^k-b8axN>??_o2D)g0lR2v(brA!&K7~ekgm1`MlsnrNI)9N90Hd0$^`zko0Ap`KmDGsJ6 zRF7(>Rm>=@2U2Q<8dQ`}-&a2bz6E;mMJN=?_Vwz3x>?K@QOYN%)`m~p|m(^wJ zYNV-1`#?M7E456Wrh=pDQ4vSZ9lmnYv}x)f6`Ee%kJM>MU+tr@qt;J_*Q7p=w1L`G zZKkheN425WS}j0oDOwz;4Xxma)=+DxW^1)nc!ugkq;}Lg`$|TXW16gB)l&PR-iX#f zYf@2G{Zjo>IiP-~z%NqaX{%pq8Cq@ycaoOBS`BRrxoZ_WvGZFXN9Dy%4y}ad_;!rpumDwPK)#kO5hnlmXsz) zIjo#g^L^Csk)M^HXa7l7j;OM)#&ya%d9I9=PCkLOy~~M z8FK($h7A9zmoJUr7o3p3Kw4M!_VSe$zP^jQ&0;4*L9AS4SA+7cLXc2Btiel4dh}U7jx+=VLOUeJl~4jmX1ru zvBpFHVYQd!mcAA~!P*P`2MbY_K9Otr%IubQV~yFstGz7kmO~Y#XpXd!#LfxypR`tR zI9=*d8Vg?s`j2gj0~OqnN~99%178QUp-r)qQ&Fl9wUoND#RdH*^^unO%C(eQQVppY zLH`l-AHGlXQZJ;v{{M^5By7$eSZDtg-^uSac{?t=gPNQpqqvQp`T$DpWLC~GI-LXh zQZM4YR#CfpM$R#ToE`N}9yJQv)xy4Mk9Tsuk7e8(68^5lQk23?_3A6~a4ESspZ(SI z-;G_za6Ma}ZCM&iJbP;#(?1k+i8*__4=e1{159ZOcmC~mV4hv7w>!&Dw#d`-g4uf4 zbFYR_DZVZBdR4->ZoFeSD}ZZF(|A1nxQ0Apw+3()?;jSWap%vaqBNJpw;QNp|NKUV zcT_?5_$ufgUj^OctDrlH8^rseMQPmm)7>#Z_jL?AG3@n)u&rSq7Mdl)B11C|;-r~0tM8ybk1xG6EzhfmIB z6`vw>^-|8?&$^!BIKT{)eim;{>8^AqQu>PBU}cmt3Uq5)?3zx)Z02}{hsc!yV*VH9=n&_ zpYFAX*~4g>J;J`59zw|;|gs}*JM!+kPlgKGQ zS$;B+pU5viiXdLQ5N<8Mwd_RM3BE_MFtM=w?+70ve1$N#d~RY|Vw%71gq5(;b&EWr z?hFLf@2@*W6W9G9!kEMuu3NMz%Dr6va;ok${RN4FGy2pg`5Za_i|d$$(73#D01vuT zpFCFN-A`KK1s$OtLh5_!?$TNWZ+!U^LG&>|hxi+JkuE+{ccaAjwO-J@u+|q+>Ed%W zf~a=`!kY3m{&c}J!HcwvrTBe38MvG%V<+sh@jEq^;g)LmYPAZR*_up41N!tW8D_JY89V_CMhY_GUOo0yZBQ$7#j9R$dT zkTaGOnKH~PFxQFay3TXGHqZ4sJlC6HPS2zEcB#FFdbqnWvj?M$i85Fn%`43-DP%S` zTOr=sY=d}P^BTn4ne7n2*1Q(+_NYCK+B*VXhc;wxL*_O#ZbRcX6tqzaxBx9_XlXa* z`JAv)r#I9#d;Q<9-U4S^x9pd z8AA>DPsT`NB&pDGqY=N)c#OivVbscLMBecLu!4z6r3q-JN8+hus_TTkPA(U|k=w?}o0I?NK&tdwaA!8mZ"l*Q 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%0A_Q)UO=E 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�J4zFC_IXd5WDhy-&T*kKT{0rtyrgF! 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 F{|P9Zl5zk5 literal 0 HcmV?d00001 diff --git a/CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/set-pause.ps1 b/CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/set-pause.ps1 new file mode 100644 index 0000000..9cb8c22 --- /dev/null +++ b/CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/set-pause.ps1 @@ -0,0 +1,36 @@ +<# +DISKSPD - VM Fleet + +Copyright(c) Microsoft Corporation +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +#> + +$pause = "C:\ClusterStorage\collect\control\flag\pause" +$p = gi $pause -ErrorAction SilentlyContinue + +if ($p) { + write-host -fore green Pause already set $p.CreationTime +} else { + echo (get-random) > $pause + write-host -fore red Pause set `@ (get-date) +} diff --git a/CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/set-storageqos.ps1 b/CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/set-storageqos.ps1 new file mode 100644 index 0000000..270d1d8 --- /dev/null +++ b/CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/set-storageqos.ps1 @@ -0,0 +1,54 @@ +<# +DISKSPD - VM Fleet + +Copyright(c) Microsoft Corporation +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +#> + +# apply given QoS policy (by name) to all VMs on specified nodes +param ( + $policyname = $null, + [object[]] $node = $(get-clusternode |? State -eq Up) +) + +if ($policyname -ne $null) { + + # QoS policy must exist, else error out + $qosp = get-storageqospolicy -name $policyname + if ($qosp -eq $null) { + # cmdlet error sufficient + return + } + $id = $qosp.PolicyId + +} else { + + # clears QoS policy + $id = $null +} + +icm $node { + + # note: set-vhdqos should be replaced with set-vmharddiskdrive + get-vm |% { get-vmharddiskdrive $_ |% { Set-VMHardDiskDrive -QoSPolicyID $using:id -VMHardDiskDrive $_ }} +} \ No newline at end of file diff --git a/CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/set-vmfleet.ps1 b/CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/set-vmfleet.ps1 new file mode 100644 index 0000000..bfe60ba --- /dev/null +++ b/CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/set-vmfleet.ps1 @@ -0,0 +1,157 @@ +<# +DISKSPD - VM Fleet + +Copyright(c) Microsoft Corporation +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +#> + +param( [Parameter(ParameterSetName = 'FullSpec', Mandatory = $true)] + [int] $ProcessorCount, + [Parameter(ParameterSetName = 'FullSpec', Mandatory = $true)] + [int64] $MemoryStartupBytes, + [Parameter(ParameterSetName = 'FullSpec')] + [int64] $MemoryMaximumBytes = 0, + [Parameter(ParameterSetName = 'FullSpec')] + [int64] $MemoryMinimumBytes = 0, + [Parameter(ParameterSetName = 'FullSpec')] + [switch]$DynamicMemory = $true, + [Parameter(ParameterSetName = 'SizeSpec', Mandatory = $true)] + [ValidateSet('A0','A1','A1v2','A2','A2mv2','A2v2','A3','A4','A4mv2','A4v2','A5','A6','A7','A8mv2','A8v2','D1','D11','D11v2','D12','D12v2','D13','D13v2','D14','D14v2','D1 +5v2','D1v2','D2','D2v2','D3','D3v2','D4','D4v2','D5v2','DS11','DS11v2','DS12','DS12v2','DS13','DS13v2','DS14','DS14v2','DS15v2')] + [string]$Compute = 'A1' + ) + +# to regenerate validateset +# ($vmsize.keys | sort |% { "'$_'" }) -join ',' + +# c = compute cores +# m = memory +# a = alias for another (ex: d -> ds, d -> dv2) +# note that alias is only chased once + + $vmsize = @{ + + # general purpose table + 'A0' = @{ 'c' = 1; 'm' = 0.75GB; }; + 'A1' = @{ 'c' = 1; 'm' = 1.75GB; }; + 'A2' = @{ 'c' = 2; 'm' = 3.5GB; }; + 'A3' = @{ 'c' = 4; 'm' = 7GB; }; + 'A4' = @{ 'c' = 8; 'm' = 14GB; }; + 'A5' = @{ 'c' = 2; 'm' = 14GB }; + 'A6' = @{ 'c' = 4; 'm' = 28GB }; + 'A7' = @{ 'c' = 8; 'm' = 56GB }; + + 'A1v2' = @{ 'c' = 1; 'm' = 2GB; }; + 'A2v2' = @{ 'c' = 2; 'm' = 4GB; }; + 'A4v2' = @{ 'c' = 4; 'm' = 8GB; }; + 'A8v2' = @{ 'c' = 8; 'm' = 16GB; }; + 'A2mv2' = @{ 'c' = 2; 'm' = 16GB; } + 'A4mv2' = @{ 'c' = 4; 'm' = 32GB; }; + 'A8mv2' = @{ 'c' = 8; 'm' = 64GB; }; + + 'D1' = @{ 'c' = 1; 'm' = 3.5GB }; + 'D2' = @{ 'c' = 2; 'm' = 7GB }; + 'D3' = @{ 'c' = 4; 'm' = 14GB }; + 'D4' = @{ 'c' = 8; 'm' = 28GB }; + + 'D1v2' = @{ 'a' = 'D1' } + 'D2v2' = @{ 'a' = 'D2' } + 'D3v2' = @{ 'a' = 'D3' } + 'D4v2' = @{ 'a' = 'D4' } + 'D5v2' = @{ 'c' = 16; 'm' = 56GB }; + + # memory optimized table (just the d's) + 'D11' = @{ 'c' = 2; 'm' = 14GB }; + 'D12' = @{ 'c' = 4; 'm' = 28GB }; + 'D13' = @{ 'c' = 8; 'm' = 56GB }; + 'D14' = @{ 'c' = 16; 'm' = 112GB }; + + 'DS11' = @{ 'a' = 'D11' }; + 'DS12' = @{ 'a' = 'D12' }; + 'DS13' = @{ 'a' = 'D13' }; + 'DS14' = @{ 'a' = 'D14' }; + + 'D11v2' = @{ 'a' = 'D11' }; + 'D12v2' = @{ 'a' = 'D12' }; + 'D13v2' = @{ 'a' = 'D13' }; + 'D14v2' = @{ 'a' = 'D14' }; + 'D15v2' = @{ 'c' = 20; 'm' = 140GB }; + + 'DS11v2' = @{ 'a' = 'D11v2' }; + 'DS12v2' = @{ 'a' = 'D12v2' }; + 'DS13v2' = @{ 'a' = 'D13v2' }; + 'DS14v2' = @{ 'a' = 'D14v2' }; + 'DS15v2' = @{ 'a' = 'D15v2' }; +} + +$g = Get-ClusterGroup |? GroupType -eq VirtualMachine | group -Property OwnerNode -NoElement + +icm $g.Name { + + # import vmsize hash (cannot $using[$using]) + $vmsize = $using:vmsize + + Get-ClusterGroup |? GroupType -eq VirtualMachine |? OwnerNode -eq $env:COMPUTERNAME |% { + + $g = $_ + + switch ($using:PSCmdlet.ParameterSetName) { + + 'FullSpec' { + + if ($using:MemoryMaximumBytes -eq 0) { + $MemoryMaximumBytes = $MemoryStartupBytes + } else { + $MemoryMaximumBytes = $using:MemoryMaximumBytes + } + if ($using:MemoryMinimumBytes -eq 0) { + $MemoryMinimumBytes = $MemoryStartupBytes + } else { + $MemoryMinimumBytes = $using:MemoryMinimumBytes + } + + $memswitch = '-StaticMemory' + $dynamicMemArg = "" + if ($using:DynamicMemory) { + $memswitch = '-DynamicMemory' + $dynamicMemArg += "-MemoryMinimumBytes $MemoryMinimumBytes -MemoryMaximumBytes $MemoryMaximumBytes" + } + + if ($g.State -ne 'Offline') { + write-host -ForegroundColor Yellow Cannot alter VM sizing on running VMs "($($_.Name))" + } else { + iex "Set-VM -ComputerName $($g.OwnerNode) -Name $($g.Name) -ProcessorCount $using:ProcessorCount -MemoryStartupBytes $using:MemoryStartupBytes $dynamicMemArg $memswitch" + } + } + + 'SizeSpec' { + $a = $vmsize[$using:compute].a + if ($a -eq $null) { + $a = $using:compute + } + + Set-VM -ComputerName $($g.OwnerNode) -Name $($g.Name) -ProcessorCount $vmsize[$a].c -MemoryStartupBytes $vmsize[$a].m -StaticMemory + } + } + } +} diff --git a/CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/start-sweep.ps1 b/CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/start-sweep.ps1 new file mode 100644 index 0000000..ae3042c --- /dev/null +++ b/CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/start-sweep.ps1 @@ -0,0 +1,506 @@ +<# +DISKSPD - VM Fleet + +Copyright(c) Microsoft Corporation +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +#> + +param( + [string] $addspec = "base", + [string] $runtemplate = "c:\clusterstorage\collect\control\run-sweeptemplate.ps1", + [string] $runfile = "c:\clusterstorage\collect\control\run-sweep.ps1", + [string[]] $labeltemplate = @('b','t','o','w','p','-$addspec'), + [Parameter(Mandatory =$true)] + [int[]] $b, + [Parameter(Mandatory =$true)] + [int[]] $t, + [Parameter(Mandatory =$true)] + [int[]] $o, + [Parameter(Mandatory =$true)] + [int[]] $w, + [int[]] $iops = $null, + [ValidateSet('r','s','si')] + [string[]] $p = 'r', + [ValidateRange(1,[int]::MaxValue)] + [int] $d = 60, + [ValidateRange(0,[int]::MaxValue)] + [int] $warm = 60, + [ValidateRange(0,[int]::MaxValue)] + [int] $cool = 60, + [string[]] $pc = $null, + [switch] $midcheck = $false + ) + +############# + +# a single named variable with a set of values +class variable { + + [int] $_ordinal + [object[]] $_list + [string] $_label + + variable([string] $label, [object[]] $list) + { + $this._list = $list + $this._ordinal = 0 + $this._label = $label + } + + # current value of the variable ("red"/"blue"/"green") + [object] value() + { + if ($this._list.count -gt 0) { + return $this._list[$this._ordinal] + } else { + return $null + } + } + + # label/name of the variable ("color") + [object] label() + { + return $this._label + } + + # increment to the next member, return whether a logical carry + # has occured (overflow) + [bool] increment() + { + # empty list passes through + if ($this._list.Count -eq 0) { + return $true + } + + # non-empty list, increment + $this._ordinal += 1 + if ($this._ordinal -eq $this._list.Count) { + $this._ordinal = 0 + return $true + } + return $false + } + + # back to initial state + [void] reset() + { + $this._ordinal = 0 + } +} + +# a set of variables which allows enumeration of their combinations +# this behaves as a numbering system indexing the respective variables +# order is not specified +class variableset { + + [hashtable] $_set = @{} + + variableset([variable[]] $list) + { + $list |% { $this._set[$_.label()] = $_ } + $this._set.Values |% { $_.reset() } + } + + # increment the enumeration + # returns true if the enumeration is complete + [bool] increment() + { + $carry = $false + foreach ($v in $this._set.Values) { + + # if the variable returns the carry flag, increment + # the next, and so forth + $carry = $v.increment() + if (-not $carry) { break } + } + + # done if the most significant carried over + return $carry + } + + # enumerator of all variables + [object] getset() + { + return $this._set.Values + } + + # return value of specific variable + [object] get([string]$label) + { + return $this._set[$label].value() + } + + # return a label representing the current value of the set, following the input label template + # add a leading '-' to get a seperator + # use a leading '$' to eliminate repetition of label (just produce value) + [string] label([string[]] $template) + { + return $($template |% { + + $str = $_ + $pfx = '' + $done = $false + $norep = $false + do { + switch ($str[0]) + { + '-' { + $pfx = '-' + $str = $str.TrimStart('-') + } + '$' { + $norep = $true + $str = $str.TrimStart('$') + } + default { + $done = $true + } + } + } while (-not $done) + + $lookstr = $str + if ($norep) { + $str = '' + } + + # only produce labels for non-null values + if ($this._set[$lookstr].value() -ne $null) { + "$pfx$str" + $this._set[$lookstr].value() + } + }) -join $null + } +} + +############# + +function start-logman( + [string] $computer, + [string] $name, + [string[]] $counters + ) +{ + $f = "c:\perfctr-$name-$computer.blg" + + $null = logman create counter "perfctr-$name" -o $f -f bin -si 1 --v -c $counters -s $computer + $null = logman start "perfctr-$name" -s $computer + write-host "performance counters on: $computer" +} + +function stop-logman( + [string] $computer, + [string] $name, + [string] $path + ) +{ + $f = "c:\perfctr-$name-$computer.blg" + + $null = logman stop "perfctr-$name" -s $computer + $null = logman delete "perfctr-$name" -s $computer + xcopy /j $f $path + del -force $f + write-host "performance counters off: $computer" +} + +function new-runfile( + [variableset] $vs + ) +{ + # apply current subsitutions to produce a new run file + gc $runtemplate |% { + + $line = $_ + + foreach ($v in $vs.getset()) { + # non-null goes in as is, null goes in as evaluatable $null + if ($v.value() -ne $null) { + $vsub = $v.value() + } else { + $vsub = '$null' + } + $line = $line -replace "__$($v.label())__",$vsub + } + + $line + + } | out-file $runfile -Encoding ascii -Width 9999 +} + +function show-run( + [variableset] $vs + ) +{ + # show current substitions (minus the underscore bracketing) + write-host -fore green RUN SPEC `@ (get-date) + foreach ($v in $vs.getset()) { + if ($v.value() -ne $null) { + $vsub = $v.value() + } else { + $vsub = '$null' + } + write-host -fore green "`t$($v.label()) = $($vsub)" + } +} + +function get-runduration( + [variableset] $vs + ) +{ + $vs.get('d') + $vs.get('Warm') + $vs.get('Cool') +} + +function get-doneflags( + [switch] $assertnone = $false + ) +{ + $assert = $false + + $tries = 0 + do { + + if ($tries -gt 0) { + sleep 1 + } + + # increment attempts + $tries += 1 + + # capture start of the iteration + $t0 = (get-date) + + # count number of done flags which agree with completion of the current go epoch + $good = 0 + dir $done |% { + $thisdone = gc $_ -ErrorAction SilentlyContinue + if ($thisdone -eq $goepoch) { + # if asserting that none should be complete, this would be an error! + if ($assertnone) { + write-host -fore red ERROR: $_.basename is already done + $assert = $true + } + $good += 1 + } + } + + # color status message per condition + if ($assert -or $good -ne $vms) { + $color = 'yellow' + } else { + $color = 'green' + } + + $t1 = (get-date) + $tdur = $t1 - $t0 + + write-host -fore $color done check iteration $tries with "$good/$vms" `@ $t1 "($('{0:F2}' -f $tdur.totalseconds) seconds)" + + # loop if not asserting, not all vms are done, and still have timeout to use + } while ((-not $assertnone) -and $good -ne $vms -and $tries -lt $timeout) + + # return assertion status? + if ($assertnone) { + return (-not $assert) + } + + # return incomplete run failure + if ($good -ne $vms) { + write-host -fore red ABORT: only received "$good/$vms" completions in $timeout attempts `@ (get-date) + return $false + } + + # all worked! + return $true +} + +function do-run( + [variableset] $vs + ) +{ + # apply specified run parameters. note null is ignored. + show-run $vs + + write-host -fore yellow Generating new runfile `@ (get-date) + new-runfile $vs + + # if we do not have a pause to clear, need the sleep here since go + # will release the fleet. + # smb fileinfo cache +5 seconds (so that fleet will see updated timestamp) + if (-not ($checkpause -and (check-pause -isactive:$true))) { + $script:checkpause = $false + sleep 15 + } + + write-host START Go Epoch: $goepoch `@ (get-date) + echo $goepoch > $go + + # release any active pause on first loop + if ($checkpause) { + write-host CLEAR PAUSE `@ (get-date) + + # same sleep need, pause will release the fleet + $script:checkpause = $false + sleep 15 + + # capture time zero prior to clear - can take time + $t0 = get-date + + clear-pause + } else { + + # capture time zero + $t0 = get-date + } + + # start performance counter capture + if ($pc -ne $null) { + $curpclabel = $vs.label($labeltemplate) + icm (get-clusternode) -ArgumentList (get-command start-logman) { + + param($fn) + set-item -path function:\$($fn.name) -value $fn.definition + + start-logman $env:COMPUTERNAME $using:curpclabel $using:pc + } + } + + ###### + + # sleep half, check for false done if possible (clear can take time/short runs), continue + $sleep = get-runduration $vs + + $t1 = get-date + $td = $t1 - $t0 + + if ($midcheck) { + + $remainingsleep = $sleep/2 - $td.TotalSeconds + if ($remainingsleep -gt 0) { + write-host SLEEP TO MID-RUN "($('{0:F2}' -f $remainingsleep) seconds)" `@ (get-date) + sleep $remainingsleep + } + + if ($td.TotalSeconds -lt ($sleep - 5)) { + write-host MID-RUN CHECK Go Epoch: $goepoch `@ (get-date) + # check for early completions, assert none are done yet + if (-not (get-doneflags -assertnone:$true)) { + return $false + } + write-host -fore green MID-RUN CHECK PASS Go Epoch: $goepoch `@ (get-date) + } + + # capture time and sleep for the remaining interval + $t1 = get-date + $td = $t1 - $t0 + + $remainingsleep = $sleep - $td.TotalSeconds + if ($remainingsleep -gt 0) { + write-host SLEEP TO END "($('{0:F2}' -f $remainingsleep) seconds)" `@ (get-date) + sleep $remainingsleep + } + + } else { + + sleep ($sleep - $td.TotalSeconds) + } + + ###### + + # stop performance counter capture + if ($pc -ne $null) { + icm (get-clusternode) -ArgumentList (get-command stop-logman) { + + param($fn) + set-item -path function:\$($fn.name) -value $fn.definition + + stop-logman $env:COMPUTERNAME $using:curpclabel "C:\ClusterStorage\collect\control\result" + } + } + + if (-not (get-doneflags)) { + return $false + } + + # advance go epoch + $script:goepoch += 1 + + return $true +} + +############# + +$vms = (get-clustergroup |? GroupType -eq VirtualMachine |? Name -like "vm-*" |? State -ne Offline).count + +# spec location of control files +$go = "c:\clusterstorage\collect\control\flag\go" +$done = "c:\clusterstorage\collect\control\flag\done-*" + +$timeout = 120 +$checkpause = $true + +# ensure we start a new go epoch +$goepoch = 0 +$gocontent = gc $go -ErrorAction SilentlyContinue +if ($gocontent -eq '0') { + $goepoch = 1 +} + +# construct the variable list describing the sweep + +############################ +############################ +## Modify from here down +############################ +############################ + +# add any additional sweep parameters here to match those specified on the command line +# ensure your sweep template script contains substitutable elements for each +# +# __somename__ +# +# bracketed by two underscore characters. Consider adding your new parameters to +# the label template so that result files are well-named and distinguishable. + +$v = @() +$v += [variable]::new('b',$b) +$v += [variable]::new('t',$t) +$v += [variable]::new('o',$o) +$v += [variable]::new('w',$w) +$v += [variable]::new('p',$p) +$v += [variable]::new('iops',$iops) +$v += [variable]::new('d',$d) +$v += [variable]::new('Warm',$warm) +$v += [variable]::new('Cool',$cool) +$v += [variable]::new('AddSpec',$addspec) + +$sweep = [variableset]::new($v) + +do { + + write-host -ForegroundColor Cyan '---' + + $r = do-run $sweep + + if (-not $r) { + return + } + +} while (-not $sweep.increment()) \ No newline at end of file diff --git a/CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/start-vmfleet.ps1 b/CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/start-vmfleet.ps1 new file mode 100644 index 0000000..7b033ab --- /dev/null +++ b/CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/start-vmfleet.ps1 @@ -0,0 +1,53 @@ +<# +DISKSPD - VM Fleet + +Copyright(c) Microsoft Corporation +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +#> + +param( + [string[]] $group = "*", + [int] $number = 0 + ) + +icm (get-clusternode |? State -eq Up) { + + $n = $using:number + + # failed is an unclean offline tbd root causes (can usually be recovered) + + $using:group |% { + + # sorted list of vms by vm number + $vms = @(Get-ClusterGroup |? OwnerNode -eq $env:COMPUTERNAME |? GroupType -eq VirtualMachine |? Name -like "vm-$_-*" | sort -Property @{ Expression = { $null = $_.Name -match '-(\d+)$'; [int] $matches[1] }}) + + # start limited number, if specified, else all + $(if ($n -gt 0 -and $vms.Count -gt $n) { + $vms[0..($n - 1)] + } else { + $vms + }) |? { + $_.State -eq 'Offline' -or $_.State -eq 'Failed' + } | Start-ClusterGroup + } +} | ft -AutoSize \ No newline at end of file diff --git a/CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/stop-vmfleet.ps1 b/CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/stop-vmfleet.ps1 new file mode 100644 index 0000000..3aee22c --- /dev/null +++ b/CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/stop-vmfleet.ps1 @@ -0,0 +1,53 @@ +<# +DISKSPD - VM Fleet + +Copyright(c) Microsoft Corporation +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +#> + +param( + [string[]] $group = @('*'), + [ValidateSet('Save','Shutdown','TurnOff')][string] $method = 'Shutdown' + ) + +icm (get-clusternode |? State -eq Up) -arg $group,$method { + param([string[]] $group, $method) + + $group |% { + + $g = Get-ClusterGroup |? GroupType -eq VirtualMachine |? OwnerNode -eq $env:COMPUTERNAME |? Name -like "vm-$_-*" |? State -ne 'Offline' + + if ($g) { + + # stop-clustergroup currently defaults to vm save + # use remoted stop-vm for the shutdown case + if ($method -eq 'Save') { + $g | Stop-ClusterGroup + } elseif ($method -eq 'TurnOff') { + Stop-VM -ComputerName $env:COMPUTERNAME -Name $g.Name -Force -TurnOff + } else { + Stop-VM -ComputerName $env:COMPUTERNAME -Name $g.Name -Force + } + } + } +} | ft -AutoSize diff --git a/CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/sweep-cputarget.ps1 b/CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/sweep-cputarget.ps1 new file mode 100644 index 0000000..dbe795f --- /dev/null +++ b/CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/sweep-cputarget.ps1 @@ -0,0 +1,212 @@ +<# +DISKSPD - VM Fleet + +Copyright(c) Microsoft Corporation +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +#> + +param( + $outfile = "result-cputarget.tsv", + $cputargets = $(throw "please specify a set of cpu percentage targets"), + $addspec = "" + ) + +$result = "C:\ClusterStorage\collect\control\result" + +# count the number of vms in the configuration +$vms = (Get-ClusterResource |? ResourceType -eq 'Virtual Machine' | measure).Count + +# target cpu utilization and qos to +/- given percentage +$cputargetwindow = 5 +$qoswindow = 5 + +# clean result file and set column headers +del -Force $outfile -ErrorAction SilentlyContinue +'WriteRatio','QOS','AVCPU','IOPS','AVRLat','AVWLat' -join "`t" > $outfile + +# make qos policy and reset +Get-StorageQosPolicy -Name SweepQos -ErrorAction SilentlyContinue | Remove-StorageQosPolicy -Confirm:$false +New-StorageQosPolicy -Name SweepQoS -MinimumIops $qos -MaximumIops $qos -PolicyType Dedicated +set-storageqos -policyname SweepQoS + +function is-within( + $value, + $target, + $percentage + ) +{ + ($value -ge ($target - ($target*($percentage/100))) -and + $value -le ($target + ($target*($percentage/100)))) +} + +function get-pc( + [string] $blg, + [int] $center, + [string] $ctr +) +{ + # get central n samples of a performance counter's sample + $pc = Import-Counter -Path $blg -Counter "\\*\$ctr" + + $t0 = ($pc.length - $center)/2 + $t1 = $t0 + $center - 1 + ($pc[$t0 .. $t1].CounterSamples.CookedValue | measure -Average).Average +} + +$pc = @('\Hyper-V Hypervisor Logical Processor(_Total)\% Total Run Time', + '\Processor Information(_Total)\% Processor Performance', + '\Cluster CSVFS(_Total)\reads/sec', + '\Cluster CSVFS(_Total)\avg. sec/read', + '\Cluster CSVFS(_Total)\writes/sec', + '\Cluster CSVFS(_Total)\avg. sec/write') + +# limit the number of attempts per sweep (mix) to 4 per targeted cpu util +$sweeplimit = ($cputargets.count * 4) + +foreach ($w in 0,10,30) { + + # track measured qos points, starting at given value + $h = @{} + $qosinitial = $qos = 400 + + foreach ($cputarget in $cputargets) { + + # move the qos window using previous run information + if ($cputarget -ne $cputargets[0]) { + $nextqos = [int](($cputarget*$iops/$avcpu)/$vms) + $qos = $nextqos + } + + write-host -ForegroundColor Cyan Starting outer loop with CPU target $cputarget and initial QoS $qos + + do { + + # failsafes + if ($h[$qos]) { write-host -ForegroundColor Red already measured $qos; break } + if ($h.Keys.Count -ge $sweeplimit) { write-host -ForegroundColor Red $sweeplimit tries giving up; break } + + Set-StorageQosPolicy -Name SweepQoS -MaximumIops $qos + write-host -fore Cyan Starting loop with QoS target $qos + + $curaddspec = "$($addspec)w$($w)qos$qos" + start-sweep.ps1 -addspec $curaddspec -b 4 -o 32 -t 1 -w $w -p r -d 60 -warm 15 -cool 15 -pc $pc + + # HACKHACK bounce collect + Get-ClusterSharedVolume |? { $_.SharedVolumeInfo.FriendlyVolumeName -match 'collect' } | Move-ClusterSharedVolume + sleep 1 + + # get average IOPS at DISKSPD + + $iops = $(dir $result\*.xml |% { + $x = [xml](gc $_) + ($x.Results.TimeSpan.Iops.Bucket | measure -Property Total -Average).Average + } | measure -Sum).Sum + + # get average cpu utilization for central 60 seconds of each node + # get average of all nodes + + $avcpu = $(dir $result\*.blg |% { + + $center = 60 + $trt = get-pc $_ $center '\Hyper-V Hypervisor Logical Processor(_Total)\% Total Run Time' + $ppc = get-pc $_ $center '\Processor Information(_Total)\% Processor Performance' + $trt*$ppc/100 + + + } | measure -Average).Average + + # get average latency for central 60 seconds, all nodes + # note we must aggregate the product of av latency and iops per node to get total + # latency, and then divide by total iops to get whole-cluster average. + + $csvrtotal = 0 + $csvwtotal = 0 + + ($avrlat,$avwlat) = $(dir $result\*.blg |% { + + $csvrlat = get-pc $_ $center '\Cluster CSVFS(_Total)\avg. sec/read' + $csvwlat = get-pc $_ $center '\Cluster CSVFS(_Total)\avg. sec/write' + $csvr = get-pc $_ $center '\Cluster CSVFS(_Total)\reads/sec' + $csvw = get-pc $_ $center '\Cluster CSVFS(_Total)\writes/sec' + + $csvrtotal += $csvr + + $csvwtotal += $csvw + + [pscustomobject] @{ 'avrtime' = $csvrlat*$csvr; 'avwtime' = $csvwlat*$csvw } + + } | measure -Sum -Property avrtime,avwtime).Sum + + $avrlat /= $csvrtotal + $avwlat /= $csvwtotal + + # capture results + $w,$qos,$avcpu,$iops,$avrlat,$avwlat -join "`t" >> $outfile + + # archive results + compress-archive -Path $(dir $result\* -Exclude *.zip) -DestinationPath $result\$curaddspec.zip + dir $result\* -Exclude *.zip | del + write-host Archived results to $result\$curaddspec.zip + + # stop within targetwindow% of cpu (+/- % of target) + if (is-within $avcpu $cputarget $cputargetwindow) { + write-host -ForegroundColor Green "Stopping in target window at $('{0:N2}' -f $avcpu) with QoS $qos" + break + } + + # assume cpu and qos have a linear relationship - extrapolate to target + # could do a direct linear fit of measurements so far + $nextqos = [int]($cputarget*$qos/$avcpu) + + # stop if next qos target is within qoswindow% of any previous measurement + $inwindow = $false + foreach ($previous in $h.keys) { + + if (is-within $nextqos $previous $qoswindow) { + $inwindow = $true + break + } + } + + if ($inwindow) { + write-host -ForegroundColor Yellow "Stopping in window of prior measurement at $('{0:N2}' -f $avcpu) with QoS $qos" + break + } + + # stop if next qos target is less than initial + if ($nextqos -lt $qosinitial) { + write-host -ForegroundColor Red "Stopping with underflow targeting $nextqos less than initial $qosinitial" + break + } + + write-host -ForegroundColor Cyan "Loop acheived $('{0:N2}' -f $avcpu) @ QoS $qos v. target $cputarget - next loop targeting QoS $nextqos" + + # record this datapoint as measured, move along to the next + $h[$qos] = 1 + $qos = $nextqos + + } while ($true) + } +} + +set-storageqos -policyname $null \ No newline at end of file diff --git a/CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/test-clusterhealth.ps1 b/CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/test-clusterhealth.ps1 new file mode 100644 index 0000000..4a11545 --- /dev/null +++ b/CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/test-clusterhealth.ps1 @@ -0,0 +1,637 @@ +<# +DISKSPD - VM Fleet + +Copyright(c) Microsoft Corporation +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +#> + +param( + [switch] $CleanOperationalIssues = $false + ) + +function new-namedblock( + [string] $name, + [scriptblock] $block, + [switch] $nullpass = $true, + [int] $mustbe = -1 + ) +{ + new-object psobject -Property @{ + 'Name' = $name; + 'Block' = $block; + 'NullPass' = $nullpass; + 'MustBe' = $mustbe + } +} + +function write-blocktitle( + [string[]] $s + ) +{ + write-host -fore cyan ('*'*20) $s +} + +function display-jobs() +{ + BEGIN { $j = @() } + PROCESS { $j += $_ } + END { + # consume job results + $null = $j | wait-job + $j | sort -Property Name |% { + write-blocktitle $_.Name,('({0:F1}s)' -f ($_.PsEndTime - $_.PsBeginTime).TotalSeconds) + $_ | receive-job + $_ | remove-job + } + } +} + +# script block containers for helper functions + +$evfns = { + + function get-fltevents( + [decimal] $timedeltams, + [string] $provider, + [string[]] $evid, + [scriptblock] $flt = { $true }, + [string] $source = $null + ) + { + # simple query vs. a provider for a single event within some timedelta of current (in ms) + # optional addition of a source provider name filter (for system log filtering) +$qstr = @" + + + + + +"@ + +$srcstr = @" +Provider[@Name='_SOURCE_'] and +"@ + + $events = ($evid |% { + "EventID=$_" + }) -join " or " + + $query = $qstr -replace '_MS_',$timedeltams -replace '_PROV_',$provider -replace '_EVENTS_',$events + if ($source) { + $query = $query -replace '_SOURCE_',($srcstr -replace '_SOURCE_',$source) + } else { + $query = $query -replace '_SOURCE_','' + } + + Get-WinEvent -FilterXml $query -ErrorAction SilentlyContinue | Where-Object -FilterScript $flt + } +} + +$fns = { + + function do-clustersymmetry( + [object] $gather, + [object[]] $filters, + [switch] $saygather = $false + ) + { + # deserialization note: the scriptblocks on the inputs are downconverted to strings + # so as a result we must reinstantiate + + # assert all nodes agree on object counts from the provided gather element + $data = icm (get-clusternode |? State -eq up) ([scriptblock]::create($gather.block)) + + if ($saygather) { + write-host -ForegroundColor yellow ('*'*15) $gather.name + } + + foreach ($f in $filters) { + + write-host -fore yellow ('*'*10) $f.name + $r = $data | where-object -FilterScript ([scriptblock]::create($f.block)) + + # group results by node + $nodeg = $r | group -property pscomputername -NoElement + + # regular symmetery + # if grouping by count (per node) yields more than one element, we know some nodes have different counts + # i.e., not all are 60: perhaps one is 58, etc. + # this is always failure. + if ($nodeg -ne $null -and ($nodeg | group -Property Count | measure).count -ne 1) { + write-host -ForegroundColor Red Fail + $nodeg | sort -Property Name,Count | ft -autosize + } else { + if ($nodeg -ne $null) { + # if no enforced count or count is correct, pass + if ($f.mustbe -lt 0 -or $f.mustbe -eq $nodeg[0].Count) { + write-host -ForegroundColor Green Pass with $nodeg[0].Count per node + } else { + # enforced count not correct + write-host -ForegroundColor Red Fail - required count of $f.mustbe not consistent on each node + $nodeg | sort -Property Name,Count | ft -autosize + } + } elseif ($f.nullpass) { + write-host -ForegroundColor Green Pass with none on any node + } else { + write-host -ForegroundColor Red Fail with none on any node + } + } + } + } +} + +# Detect RDMA its type (by manufacturer) so that, if needed, we can assert QoS/Cos for RoCE + +$netadapters = Get-NetAdapterRdma |? Enabled | Get-NetAdapter + +$rdma = $false +$roce = $false +$rocematch = 'Mellanox' + +if ($netadapters) { + write-host -fore green Detected RDMA adapters: will require RDMA + $rdma = $true + + # will need a tweak as additional non-Mellanox RoCE arrive (and/or if IB) + $qroce = $netadapters |? DriverProvider -match $rocematch + if ($qroce) { + $drvdesc = $qroce[0].DriverDescription + + write-host -fore green Detected $qroce[0].DriverProvider RDMA adapters: will require RoCE configuration + write-host -fore green Adapter Description: $drvdesc + $roce = $true + } +} + +### Basic Health Checks: serialized + +$j = @() + +$j += start-job -Name 'Basic Health Checks' { + + # nodes up + $cn = Get-ClusterNode + + if ($cn.count -eq $($cn |? State -eq Up).count) { + write-host -ForegroundColor Green All cluster nodes Up + } else { + write-host -ForegroundColor Red Following cluster nodes not Up: + $cn |? State -ne Up + } + + # node uptime + $o = icm ($cn |? State -eq Up) { + $w = gwmi win32_operatingsystem + $w.ConvertToDateTime($w.localdatetime) - $w.ConvertToDateTime($w.lastbootuptime) + } + + $reboots = $o |? TotalHours -lt 1 + + if ($reboots.length -and $reboots.length -ne $o.length) { + write-host -ForegroundColor Yellow WARNING: $reboots.length nodes have rebooted in the last hour. Ensure that + write-host -ForegroundColor Yellow `t no unexpected events are occuring in the cluster. + } + + write-host -ForegroundColor Green Cluster node uptime: + $o | sort PsComputerName | ft PsComputerName,@{ Label="Uptime"; Expression={"{0}d:{1:00}h:{2:00}m.{3:00}s" -f $_.Days,$_.Hours,$_.Minutes,$_.Seconds}} + + # subsystem check + $ss = Get-StorageSubSystem |? Model -eq 'Clustered Windows Storage' + + if (($ss | measure).count -ne 1) { + write-host -ForegroundColor Red Expected single clustered storage subsystem, found: + $ss | ft -autosize + return + } + + $ssuh = $ss |? HealthStatus -ne Healthy + + if ($ssuh) { + write-host -ForegroundColor Red WARNING: clustered storage subsystem is not healthy + $ssuh | ft -AutoSize + + write-host -ForegroundColor Red Output of Debug-StorageSubSystem follows + $ssuh | Debug-StorageSubSystem | fl + } else { + write-host -ForegroundColor Green Clustered storage subsystem Healthy + } + + # pool health + $p = $ss | Get-StoragePool |? IsPrimordial -ne $true |? HealthStatus -ne Healthy + + if ($p -eq $null) { + write-host -ForegroundColor Green All pools Healthy + } else { + write-host -ForegroundColor Red Following pools not Healthy: + $p | ft -autosize + } +} + +# vd health + +$j += start-job -name 'Virtual Disk Health' { + + $ss = Get-StorageSubSystem |? Model -eq 'Clustered Windows Storage' + + $vd = $ss | Get-VirtualDisk |? HealthStatus -ne Healthy + + if ($vd -eq $null) { + write-host -fore green All operational virtual disks Healthy + } else { + write-host -fore red Following virtual disks not Healthy: + $vd | ft -autosize + } +} + +# disk state + +$j += start-job -name 'Physical Disk Health' { + $pd = Get-StorageSubSystem |? Model -eq 'Clustered Windows Storage' | Get-PhysicalDisk + + $nonauto = $pd |? Usage -notmatch 'Journal|Auto-Select' + if ($nonauto) { + write-host -fore yellow WARNING: there are physical disks which are not auto-select/journal for usage. + write-host -fore yellow `t It is possible that while storage resilience has been restored from + write-host -fore yellow `t a failure, it is no longer evenly distributed between cluster nodes. + write-host -fore yellow `t Consider recovering before doing performance/operational work. + $nonauto | ft -autosize + } else { + write-host -fore green All physical disks are in normal auto-select or journal state + } +} + +# consolidated op issues - should logically split? + +$j += start-job -name 'Operational Issues and Storage Jobs' -ArgumentList $CleanOperationalIssues { + + param( $CleanOperationalIssues ) + + $ev = icm (get-clusternode) { + get-winevent -LogName Microsoft-Windows-Storage-Storport/Operational |? Id -eq 502 |% { + $ex = [xml]$_.ToXml() + $guid = ($ex.Event.EventData.Data |? Name -eq ClassDeviceGuid).'#text' + $_ | Add-Member -NotePropertyName DeviceGuid -NotePropertyValue $guid -PassThru + } + } + if ($ev) { + write-host -fore yellow WARNING: unresponsive device events have been logged by storport. + write-host -fore yellow `tThese may correspond to retired devices, and should be investigated. + $ev | ft -autosize PsComputerName,TimeCreated,Id,DeviceGuid,Message + + write-host -fore yellow Corresponding devices by Device GUID: + $d = Get-StorageSubSystem Cluster* | Get-StoragePool |? IsPrimordial -eq $false | Get-PhysicalDisk + $ev |% { + $d |? ObjectId -match "PD:$($_.DeviceGuid)" + } | ft -AutoSize + } + + # look for livekernelreport and/or bugcheck dumps + + $dmps = icm (get-clusternode |? State -eq Up) { + + $obj = @() + + $obj += dir $($env:windir + "\livekernelreports") + $obj += dir $($env:windir + "\minidump") -ErrorAction SilentlyContinue + $obj += dir $($env:windir + "\memory.dmp") -ErrorAction SilentlyContinue + + if ($using:CleanOperationalIssues -and $obj.count -gt 0) { + $obj | del -Force -Recurse -ErrorAction SilentlyContinue + } + + $obj + + } | sort -property PsParentPath,LastWriteTime,PsComputerName + + if ($dmps) { + if ($CleanOperationalIssues) { + write-host -fore red NOTE: the following failure reports were forcibly removed + } else { + write-host -fore yellow WARNING: there are failure reports that may require triage + } + + $dmps | ft -AutoSize + } + + # Storage Jobs + + $sj = get-storagejob + if ($sj |? JobState -ne Completed) { + write-host -ForegroundColor red WARNING: there are active storage jobs running. Investigate the root cause before continuing. + $sj | ft -autosize + } else { + write-host -fore green No storage rebuild or regeneration jobs are active + } +} + +# SMB Connectivity Error Check + +$fltblk = { + + param( $ev, $warncol, $warn ) + + $r = icm (get-clusternode |? State -eq Up) -ArgumentList @((get-command get-fltevents), $ev) { + + param($fn, $ev) + + set-item -path function:\$($fn.name) -value $fn.definition + + $flttcp = { + # report tcp (type 1) connectivity events + $x = [xml] $_.ToXml() + [int]($x.Event.EventData.Data |? Name -eq 'ConnectionType').'#text' -eq 1 + } + + $fltrdma = { + # report rdma (type 2) connectivity events + $x = [xml] $_.ToXml() + [int]($x.Event.EventData.Data |? Name -eq 'ConnectionType').'#text' -eq 2 + } + + $last5 = (1000*60*5) + $lasthour = (1000*60*60) + $lastday = (1000*60*60*24) + + new-object psobject -Property @{ + 'RDMA Last5Min' = (get-fltevents -flt $fltrdma -timedeltams $last5 -provider "Microsoft-Windows-SmbClient/Connectivity" -evid $ev).count; + 'RDMA LastHour' = (get-fltevents -flt $fltrdma -timedeltams $lasthour -provider "Microsoft-Windows-SmbClient/Connectivity" -evid $ev).count; + 'RDMA LastDay' = (get-fltevents -flt $fltrdma -timedeltams $lastday -provider "Microsoft-Windows-SmbClient/Connectivity" -evid $ev).count; + 'TCP Last5Min' = (get-fltevents -flt $flttcp -timedeltams $last5 -provider "Microsoft-Windows-SmbClient/Connectivity" -evid $ev).count; + 'TCP LastHour' = (get-fltevents -flt $flttcp -timedeltams $lasthour -provider "Microsoft-Windows-SmbClient/Connectivity" -evid $ev).count; + 'TCP LastDay' = (get-fltevents -flt $flttcp -timedeltams $lastday -provider "Microsoft-Windows-SmbClient/Connectivity" -evid $ev).count; + } + } + + $hdr = (($r[0] | gm -MemberType NoteProperty |? Definition -like 'int*').Name | sort) + $rdmafail = ($r |% { $row = $_; $hdr |? {$_ -like 'RDMA*' } |% { $row.$_ }} | measure -sum).sum -ne 0 + + if ($rdmafail) { + write-host -ForegroundColor $warncol $warn + } + + $r | sort -Property PsComputerName | ft -Property (@('PsComputerName') + $hdr) +} + +$w = @" +WARNING: the SMB Client is receiving RDMA disconnects. This is an error whose root" +`t cause may be PFC/CoS misconfiguration (RoCE) on hosts or switches, physical" +`t issues (ex: bad cable), switch or NIC firmware issues, and will lead to severely" +`t degraded performance. Additional triage is included in other tests." +"@ + +$j += start-job -name 'SMB Connectivity Error Check - Disconnect Failures' -ArgumentList 30804,([ConsoleColor]'Red'),$w -InitializationScript $evfns $fltblk + +$w = @" +WARNING: the SMB Client is receiving RDMA connect errors. This is an error whose root +`t cause may be actual lack of connectivity or fundamental problems with the RDMA +`t network fabric. Please inspect especially if in the Last5 bucket. +"@ + +$j += start-job -name 'SMB Connectivity Error Check - Connect Failures' -ArgumentList 30803,([ConsoleColor]'Yellow'),$w -InitializationScript $evfns $fltblk + +if ($roce) { + + $j += start-job -name 'RoCE: Mellanox Disable Check' -InitializationScript $evfns { + + $r = icm (get-clusternode |? State -eq Up) -ArgumentList (get-command get-fltevents) { + + param($fn) + + set-item -path function:\$($fn.name) -value $fn.definition + + $r = get-fltevents -timedeltams (1000*60*60*24*30) -provider 'System' -source 'mlx4eth63' -evid 35 + } + + if ($r) { + + write-host -ForegroundColor red WARNING: Mellanox indicates that RDMA has been disabled due to mis/non-configuration + write-host -ForegroundColor red `t of Priority Flow Control at some point in the past 30 days. Unless this has been recently + write-host -ForegroundColor red `t "corrected," RDMA may be down. + write-host -ForegroundColor red Most recent event "(System log)" follows + $r[0] | fl + } else { + write-host -ForegroundColor Green Pass + } + } + + $j += start-job -name 'RoCE: Mellanox Error Check' { + + $r = $null + $pc = $null + + switch ($using:drvdesc) { + "Mellanox ConnectX-3 Pro Ethernet Adapter" { + $pc = @{ + '\Mellanox Adapter Diagnostic Counters(_Total)\Responder Out-of-order Sequence Received' = 'Out Of Order'; + '\Mellanox Adapter Traffic Counters(_Total)\Packets Received Bad CRC Error' = 'Rec BadCRC'; + '\Mellanox Adapter Traffic Counters(_Total)\Packets Received Frame Length Error' = 'Rec FrmLenErr'; + '\Mellanox Adapter Traffic Counters(_Total)\Packets Received Symbol Error' = 'Rec SymlErr'; + '\Mellanox Adapter Traffic Counters(_Total)\Packets Received Discarded' = 'Rec Discard'; + '\Mellanox Adapter Traffic Counters(_Total)\Packets Outbound Discarded' = 'Outbnd Discard' + '\Mellanox Adapter Traffic Counters(_Total)\Packets Outbound Errors' = 'Outbnd Err'; + } + } + "Mellanox ConnectX-4 Adapter" { + $pc = @{ + '\Mellanox WinOF-2 Diagnostics(_Total)\Responder out of order sequence received' = 'Out Of Order'; + '\Mellanox WinOF-2 Port Traffic(_Total)\Packets Received Bad CRC Error' = 'Rec BadCRC'; + '\Mellanox WinOF-2 Port Traffic(_Total)\Packets Received Frame Length Error' = 'Rec FrmLenErr'; + '\Mellanox WinOF-2 Port Traffic(_Total)\Packets Received Symbol Error' = 'Rec SymlErr'; + '\Mellanox WinOF-2 Port Traffic(_Total)\Packets Received Discarded' = 'Rec Discard'; + '\Mellanox WinOF-2 Port Traffic(_Total)\Packets Outbound Discarded' = 'Outbnd Discard' + '\Mellanox WinOF-2 Port Traffic(_Total)\Packets Outbound Errors' = 'Outbnd Err'; + } + } + default { + write-host -ForegroundColor Red "Unknown adapter type: $($using:drvdesc)" + } + } + + # no counters, no results + + if ($pc -ne $null) { + + $r = icm (get-clusternode |? State -eq Up) -ArgumentList $pc { + + param($pc) + + $c = get-counter ($pc.Keys |% { $_ }) -ErrorAction SilentlyContinue + if ($c) { + + $o = new-object psobject -Property @{ 'Errors' = $false } + $c.CounterSamples | sort -Property Path |% { + if ($_.path -match '\\\\[^\\]+(\\.*$)') { + $o | Add-Member -NotePropertyName $pc[$matches[1]] -NotePropertyValue $_.CookedValue + if ($_.CookedValue -ne 0) { $o.Errors = $true } + } + } + $o + } + } + } + + if ($r.length -ne (get-clusternode |? State -eq Up).length) { + + write-host -ForegroundColor Yellow WARNING: retransmit statistics not available from all nodes. Ensure driver updates applied. + write-host -ForegroundColor Yellow `t $r.length nodes responded out of $((get-clusternode |? Up).length) + + } + + if ($r |? Errors) { + + write-host -ForegroundColor Red "WARNING: Any non-zero error counters may indicate physical or switch/NIC" + write-host -ForegroundColor Red "`t issues, likely leading to packet drops and retransmits, which will degrade" + write-host -ForegroundColor Red "`t performance. At high enough rates they can lead to SMB connection drops." + } else { + write-host -ForegroundColor Green "Pass - no errors detected" + } + + $hdr = @( 'PsComputerName' ) + $hdr += $($pc.Values |% { $_ }) + + $r | sort -property PsComputerName | ft -Property $hdr + } +} + +## Begin Symmetry Checks + +$totalf = new-namedblock 'Total' { $true } +$totalf_nonull = new-namedblock 'Total' { $true } -nullpass:$false + +### +$t = new-namedblock 'Clusport Device Symmetry Check' { gwmi -namespace root\wmi ClusportDeviceInformation } +$f = @($totalf) +$f += ,(new-namedblock 'Disk Type' { $_.DeviceType -eq 0} -nullpass:$false) +# temporarily remove hybrid check - the attribute is not synchronously updated +# and so may be (harmlessly) inaccurate for a period of time in early configuration +#$f += ,(new-namedblock 'Hybrid Media' { $_.DeviceAttribute -band 0x4}) +$f += ,(new-namedblock 'Solid/Non-Rotational Media' { $_.DeviceAttribute -band 0x8}) +$f += ,(new-namedblock 'Enclosure Type' { $_.DeviceType -eq 1} -nullpass:$false) +$f += ,(new-namedblock 'Virtual' { $_.DeviceAttribute -band 0x1} -nullpass:$true) + +$j += start-job -InitializationScript $fns -Name $t.name { do-clustersymmetry $using:t $using:f } + +### +$t = new-namedblock 'Physical Disk View Symmetry Check' { Get-StorageSubSystem |? Model -eq 'Clustered Windows Storage' | Get-PhysicalDisk } +$f = @($totalf) + +$j += start-job -InitializationScript $fns -Name $t.name { do-clustersymmetry $using:t $using:f } + +### +$t = new-namedblock 'Enclosure View Symmetry Check' { Get-StorageSubSystem |? Model -eq 'Clustered Windows Storage' | Get-StorageEnclosure } +$f = @($totalf) + +$j += start-job -InitializationScript $fns -Name $t.name { do-clustersymmetry $using:t $using:f } + +### +$t = new-namedblock 'SMB SBL Multichannel Symmetry Check' { Get-SmbMultichannelConnection -SmbInstance SBL } +$f = @($totalf) +$f += ,(new-namedblock 'RDMA Capable' { $_.ClientRdmaCapable -and $_.ServerRdmaCapable } -nullpass:$(-not $rdma)) +$f += ,(new-namedblock 'Selected & Non-Failed' { $_.Selected -and -not $_.Failed } -nullpass:$(-not $rdma)) + +$j += start-job -InitializationScript $fns -Name $t.name { do-clustersymmetry $using:t $using:f } + +### +$t = new-namedblock 'SMB CSV Multichannel Symmetry Check' { Get-SmbMultichannelConnection -SmbInstance CSV } +$f = @($totalf) +$f += ,(new-namedblock 'RDMA Capable' { $_.ClientRdmaCapable -and $_.ServerRdmaCapable } -nullpass:$(-not $rdma)) +$f += ,(new-namedblock 'Selected & Non-Failed' { $_.Selected -and -not $_.Failed } -nullpass:$(-not $rdma)) + +$j += start-job -InitializationScript $fns -Name $t.name { do-clustersymmetry $using:t $using:f } + +### +if ($rdma) { + + # rdma gives us an easy way of identifying a set of adapters to do this test with. + # it would be good to extend this more generally + + $t = @() + $t += new-namedblock 'RDMA Adapter IP Check' { Get-NetAdapterRdma |? Enabled | Get-NetAdapter |? HardwareInterface | Get-NetIPAddress -ErrorAction SilentlyContinue |? AddressState -eq 'Preferred' } + $t += new-namedblock 'RDMA Adapter (Virtual) IP Check' { Get-NetAdapterRdma |? Enabled | Get-NetAdapter |? { -not $_.HardwareInterface } | Get-NetIPAddress -ErrorAction SilentlyContinue |? AddressState -eq 'Preferred' } + $t += new-namedblock 'RDMA Adapter (Physical) IP Check' { Get-NetAdapterRdma |? Enabled | Get-NetAdapter |? HardwareInterface | Get-NetIPAddress -ErrorAction SilentlyContinue |? AddressState -eq 'Preferred' } + $f = @($totalf) + + $j += start-job -InitializationScript $fns -Name $t[0].name { + + $using:t |% { do-clustersymmetry $_ $using:f -saygather:$true } + } +} + +### +$t = new-namedblock 'RDMA Adapters Symmetry Check' { Get-NetAdapterRdma |? Enabled | Get-NetAdapter } +$f = @($totalf) +$f += ,(new-namedblock 'Operational' { $_.Speed -gt 0 } -nullpass:$(-not $rdma)) +$f += ,(new-namedblock 'Up' { $_.ifOperStatus -eq 'Up' } -nullpass:$(-not $rdma)) + +$j += start-job -InitializationScript $fns -Name $t.name { do-clustersymmetry $using:t $using:f } + +### +if ($roce) { + + # assert SMB Direct policy defined + $t = new-namedblock 'RoCE/QoS Configuration for SMB Direct' { Get-NetQosPolicy } + $f = @($totalf_nonull) + $f += ,(new-namedblock 'SMB Direct' { $_.NetDirectPort -eq 445 -and $_.PriorityValue -ne 0 } -nullpass:$false) + + $j += start-job -InitializationScript $fns -Name $t.name { do-clustersymmetry $using:t $using:f } + + # this is strictly insufficient, should ensure the enabled one is the same as that defined for SMB Direct + $t = new-namedblock 'RoCE/CoS Definitions' { Get-NetQosFlowControl } + $f = @($totalf_nonull) + $f += ,(new-namedblock 'Enabled' { $_.Enabled } -nullpass:$false) + $f += ,(new-namedblock 'Disabled' { -not $_.Enabled } -nullpass:$false) + + $j += start-job -InitializationScript $fns -Name $t.name { do-clustersymmetry $using:t $using:f } + + <# + # + $t = new-namedblock 'RoCE/CoS Applied to RoCE RNICs' { Get-NetAdapterRdma | get-netadapter -Physical -ErrorAction SilentlyContinue |? DriverProvider -match $using:rocematch } + $f = @($totalf_nonull) + $f += ,(new-namedblock 'Operational FlowControl Specs' { $_.OperationalFlowControl } -nullpass:$false) + $f += ,(new-namedblock 'Operational Port/Protocol Classification Specs' { $_.OperationalClassifications } -nullpass:$false) + $f += ,(new-namedblock 'Operational CoS Traffic Classes' { $_.OperationalTrafficClasses } -nullpass:$false) + + $j += start-job -InitializationScript $fns -Name $t.name { do-clustersymmetry $using:t $using:f } + #> +} + +### +if (Get-StorageFileServer |? SupportsContinuouslyAvailableFileShare) { + + $t = new-namedblock 'SMB Server CA FS Scope Net Interface Symmetry Check' { + + $fs = Get-StorageFileServer |? SupportsContinuouslyAvailableFileShare + if ($fs) { + Get-SmbServerNetworkInterface |? ScopeName -eq $fs.FriendlyName + } else { + $null + } + } + $f = @() + $f = ,(new-namedblock 'Rdma Capable' { $_.RdmaCapable } -nullpass:$(-not $rdma)) + + $j += start-job -InitializationScript $fns -Name $t.name { do-clustersymmetry $using:t $using:f } +} + +# consume job results +$j | display-jobs diff --git a/CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/update-csv.ps1 b/CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/update-csv.ps1 new file mode 100644 index 0000000..1e670f0 --- /dev/null +++ b/CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/update-csv.ps1 @@ -0,0 +1,132 @@ +<# +DISKSPD - VM Fleet + +Copyright(c) Microsoft Corporation +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +#> + +param( + [switch]$disableintegrity = $false, + [switch]$renamecsvmounts = $false, + [switch]$movecsv = $true, + [switch]$movevm = $true, + [switch]$shiftcsv = $false +) + +$csv = get-clustersharedvolume + +# handle restore cases by mapping the csv to the friendly name of the volume +# don't rely on the csv name to contain this data + +$vh = @{} +Get-Volume |? FileSystem -eq CSVFS |% { $vh[$_.Path] = $_ } + +$csv |% { + $v = $vh[$_.SharedVolumeInfo.Partition.Name] + if ($v -ne $null) { + $_ | Add-Member -NotePropertyName VDName -NotePropertyValue $v.FileSystemLabel + } +} + +if ($disableintegrity) { + $csv |% { + dir -r $_.SharedVolumeInfo.FriendlyVolumeName | Set-FileIntegrity -Enable:$false -ErrorAction SilentlyContinue + } +} + +if ($renamecsvmounts) { + $csv |% { + if ($_.SharedVolumeInfo.FriendlyVolumeName -match 'Volume\d+$') { + ren $_.SharedVolumeInfo.FriendlyVolumeName $_.VDName + } + } +} + +function move-csv( + $rehome = $true, + $shift = $false + ) +{ + if ($shift) { + + write-host -fore Yellow Shifting CSV owners + + # rotation order (n0 -> n1, n1 -> n2, ... nn -> n0) + $nodes = (Get-ClusterNode |? State -eq Up | sort -Property Name).Name + $nh = @{} + foreach ($i in 1..($nodes.Length-1)) { + $nh[$nodes[$i-1]] = $nodes[$i] + } + $nh[$nodes[$nodes.Length-1]] = $nodes[0] + + Get-ClusterNode |% { + $node = $_.Name + $csv |? VDName -match "$node(?:-.+){0,1}" |% { + $_ | Move-ClusterSharedVolume $nh[$_.OwnerNode.Name] + } + } + + } elseif ($rehome) { + + # write-host -fore Yellow Re-homing CSVs + + # move all csvs named by node names back to their named node + get-clusternode |? State -eq Up |% { + $node = $_.Name + $csv |? VDName -match "$node(?:-.+){0,1}" |? OwnerNode -ne $node |% { $_ | Move-ClusterSharedVolume $node } + } + } +} + +if ($shiftcsv) { + # shift rotates all csvs node ownership by one node, in lexical order of + # current node owner name. this is useful for forcing out-of-position ops. + move-csv -shift:$true +} elseif ($movecsv) { + # move puts all csvs back on their home node + move-csv -rehome:$true +} + +if ($movevm) { + + icm (Get-ClusterNode |? State -eq Up) { + + Get-ClusterGroup |? GroupType -eq VirtualMachine |% { + + if ($_.Name -like "vm-*-$env:COMPUTERNAME-*") { + if ($env:COMPUTERNAME -ne $_.OwnerNode) { + write-host -ForegroundColor yellow moving $_.name $_.OwnerNode '->' $env:COMPUTERNAME + + # the default move type is live, but live does not degenerately handle offline vms yet + if ($_.State -eq 'Offline') { + Move-ClusterVirtualMachineRole -Name $_.Name -Node $env:COMPUTERNAME -MigrationType Quick + } else { + Move-ClusterVirtualMachineRole -Name $_.Name -Node $env:COMPUTERNAME + } + } else { + # write-host -ForegroundColor green $_.name is on $_.OwnerNode + } + } + } + } +} diff --git a/CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/wait-result.ps1 b/CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/wait-result.ps1 new file mode 100644 index 0000000..0ddb4e2 --- /dev/null +++ b/CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/wait-result.ps1 @@ -0,0 +1,36 @@ +<# +DISKSPD - VM Fleet + +Copyright(c) Microsoft Corporation +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +#> + +while ($true) { + + $empty = dir C:\ClusterStorage\collect\control\result |? Length -eq 0 + if ($empty) { continue } + sleep 20 + break +} + +write-host -fore green Done diff --git a/CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/watch-cluster.ps1 b/CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/watch-cluster.ps1 new file mode 100644 index 0000000..ea7c0fa --- /dev/null +++ b/CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/watch-cluster.ps1 @@ -0,0 +1,531 @@ +<# +DISKSPD - VM Fleet + +Copyright(c) Microsoft Corporation +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +#> + +param( + $Cluster = ".", + $SampleInterval = 2, + [ValidateSet("CSV FS","SSB Cache","SBL","SBL Local","SBL Remote","SBL*","S2D BW","Hyper-V LCPU","SMB SRV","SMB Transport","*")] + [string[]] $Sets = "CSV FS", + $Log = $null +) + +if ($null -ne $log) { + del -Force $log -ErrorAction SilentlyContinue +} + +function write-log( + [string[]] $str + ) +{ + if ($null -ne $log) { + $str |% { + "$(get-date) $_" | Out-File -Append -FilePath $log -Width 9999 -Encoding ascii + } + } +} + +# display name +# ctr name +# display order +# format string +# scalar multiplier + +class CounterColumn { + + [string] $displayname + [string] $setname + [string[]] $ctrname + [int] $width + [string] $fmt + [decimal] $multiplier + [ValidateSet("Average","AverageAggregate","Sum")][string] $aggregate + [boolean] $divider + + CounterColumn( + [string] $displayname, + [string] $setname, + [string[]] $ctrname, + [int] $width, + [string] $fmt, + [decimal] $multiplier, + [string] $aggregate, + [boolean] $divider + ) + { + $this.displayname = $displayname + $this.setname = $setname + $this.ctrname = $ctrname + $this.width = $width + $this.fmt = $fmt + $this.multiplier = $multiplier + $this.aggregate = $aggregate + $this.divider = $divider + + if ($this.width -lt $this.displayname.length + 1) { + $this.width = $this.displayname.length + 1 + } + } +} + +class CounterColumnSet { + + [CounterColumn[]] $columns + [string[]] $counters + [string] $topfmt + [string] $linfmt + [string] $name + + [string] $totalline + [string[]] $nodelines + + CounterColumnSet($name) + { + $this.columns = $null + $this.name = $name + } + + [void] Add([CounterColumn] $c) + { + $this.columns += $c + } + + [void] Seal() + { + # assemble the top-line fmt and per-line fmt strings + # top-line is just strings/width + # per-line adds the (likely numeric) format specifier + $n = 1 + $this.topfmt = $this.linfmt = "{0,-16}" + foreach ($col in $this.columns) { + $str = '' + if ($col.divider) { + $str += '| ' + } + $str += "{$n,-$($col.width)" + $this.topfmt += "$str}" + $this.linfmt += "$($str):$($col.fmt)}" + + $n += 1 + } + + # assemble the list of counter instances that will be needed + # note that some may be internally aggregated (i.e., total = read + write) + # in cases where a counterset does not provide an explicit total + $this.counters = ($this.columns |% { + $s = $_.setname + $_.ctrname |% { "\$($s)(_Total)\$($_)" } + } | group -NoElement).Name + } + + [void] DisplayPre( + [hashtable] $samples, + [hashtable] $psamples + ) + { + # aggregate each column across all live sampled nodes + $this.totalline = $this.linfmt -f $( + "Total" + foreach ($col in $this.columns) { + + # average aggreate doesn't work across nodes if the base is not consistent + # for instance: cannot average latency safely, but can average cpu utilization + if ($col.aggregate -ne 'Average' -or $col.aggregate -eq 'AverageAggregate') { + $(foreach ($node in $psamples.keys) { + get-samples $psamples $node $col + }) | get-aggregate $col + } else { + $null + } + } + ) + + # individual nodes + # flags downed/non-responsive nodes by noting which are not + # present in the processed samples + $this.nodelines = foreach ($node in $samples.keys | sort) { + if ($psamples.ContainsKey($node)) { + $this.linfmt -f $( + $node + foreach ($col in $this.columns) { + $s = get-samples $psamples $node $col + if ($null -ne $s) { + $a = $s | get-aggregate $col + $a + } else { + "-" + } + } + ) + } else { + $this.topfmt -f $( + $node + 0..($this.columns.count - 1) |% { "-" } + ) + } + } + } + + [void] Display() + { + write-host ($this.topfmt -f (,$this.name + $this.columns.displayname)) + write-host -fore green $this.totalline + $this.nodelines |% { write-host $_ } + } +} + +function get-aggregate( + [CounterColumn] $col + ) +{ + BEGIN { + $n = 0 + $v = 0 + } + PROCESS { + $n += 1 + $v += $_ + } + END { + if ($n -gt 0) { + switch -wildcard ($col.aggregate) { + 'Sum' { + #write-host $col.displayname $col.multipler $v + $col.multiplier * $v + } + 'Average*' { + #write-host $col.displayname $col.multiplier $v $n + $col.multiplier * $v / $n + } + } + } else { + $null + } + } +} + +# get samples out of per-node hash of ctr hashes +function get-samples( + [hashtable] $h, + [string] $node, + [CounterColumn] $col + ) +{ + foreach ($i in $col.ctrname) { + + $k = "$($col.setname)+$($i)" + + if ($h.ContainsKey($node)) { + if ($h[$node].ContainsKey($k)) { + $h[$node][$k] + } else { + write-log "missing $node[$k] : $($h[$node].Keys.Count) total keys" + } + } else { + write-log "missing $node" + } + } +} + +$allctrs = @() + +### +$c = [CounterColumnSet]::new("CSV FS") +$c.Add([CounterColumn]::new("IOPS", "Cluster CSVFS", @("Reads/sec","Writes/sec"), 12, '#,#', 1, 'Sum', $false)) +$c.Add([CounterColumn]::new("Reads", "Cluster CSVFS", @("Reads/sec"), 12, '#,#', 1, 'Sum', $false)) +$c.Add([CounterColumn]::new("Writes", "Cluster CSVFS", @("Writes/sec"), 12, '#,#', 1, 'Sum', $false)) + +$c.Add([CounterColumn]::new("BW (MB/s)", "Cluster CSVFS", @("Read Bytes/sec","Write Bytes/sec"), 13, '#,#', 0.000001, 'Sum', $true)) +$c.Add([CounterColumn]::new("Read", "Cluster CSVFS", @("Read Bytes/sec"), 8, '#,#', 0.000001, 'Sum', $false)) +$c.Add([CounterColumn]::new("Write", "Cluster CSVFS", @("Write Bytes/sec"), 8, '#,#', 0.000001, 'Sum', $false)) + +$c.Add([CounterColumn]::new("Read Lat (ms)", "Cluster CSVFS", @("Avg. sec/Read"), 15, '0.000', 1000, 'Average', $true)) +$c.Add([CounterColumn]::new("Write", "Cluster CSVFS", @("Avg. sec/Write"), 8, '0.000', 1000, 'Average', $false)) + +$c.Add([CounterColumn]::new("Read QAvg", "Cluster CSVFS", @("Avg. Read Queue Length"), 11, '0.000', 1, 'Average', $true)) +$c.Add([CounterColumn]::new("Write", "Cluster CSVFS", @("Avg. Write Queue Length"), 8, '0.000', 1, 'Average', $false)) + +$c.Seal() +$allctrs += $c + +### +$c = [CounterColumnSet]::new("SSB Cache") + +$c.Add([CounterColumn]::new("Hit/Sec", "Cluster Storage Hybrid Disks", @("Cache Hit Reads/Sec"), 12, '#,#', 1, 'Sum', $false)) +$c.Add([CounterColumn]::new("Miss/Sec", "Cluster Storage Hybrid Disks", @("Cache Miss Reads/Sec"), 12, '#,#', 1, 'Sum', $false)) +$c.Add([CounterColumn]::new("Remap/Sec" ,"Cluster Storage Cache Stores", @("Page ReMap/sec"), 12, '#,#', 1, 'Sum', $false)) + +$c.Add([CounterColumn]::new("Cache (MB/s)", "Cluster Storage Hybrid Disks", @("Cache Populate Bytes/sec","Cache Write Bytes/sec"), 13, '#,#', 0.000001, 'Sum', $true)) +$c.Add([CounterColumn]::new("RdPop", "Cluster Storage Hybrid Disks", @("Cache Populate Bytes/sec"), 8, '#,#', 0.000001, 'Sum', $false)) +$c.Add([CounterColumn]::new("WrPop", "Cluster Storage Hybrid Disks", @("Cache Write Bytes/sec"), 8, '#,#', 0.000001, 'Sum', $false)) + +$c.Add([CounterColumn]::new("Destage (MB/s)", "Cluster Storage Cache Stores", @("Destage Bytes/sec"), 15, '#,#', 0.000001, 'Sum', $true)) +$c.Add([CounterColumn]::new("Update", "Cluster Storage Cache Stores", @("Update Bytes/sec"), 7, '#,#', 0.000001, 'Sum', $false)) + +$c.Add([CounterColumn]::new("Total (Pgs)", "Cluster Storage Cache Stores", @("Cache Pages"), 11, '0.00E+0', 1, 'Sum', $true)) +$c.Add([CounterColumn]::new("Standby", "Cluster Storage Cache Stores", @("Cache Pages StandBy"), 9, '0.00E+0', 1, 'Sum', $false)) +$c.Add([CounterColumn]::new("L0", "Cluster Storage Cache Stores", @("Cache Pages StandBy L0"), 9, '0.00E+0', 1, 'Sum', $false)) +$c.Add([CounterColumn]::new("L1", "Cluster Storage Cache Stores", @("Cache Pages StandBy L1"), 9, '0.00E+0', 1, 'Sum', $false)) +$c.Add([CounterColumn]::new("L2", "Cluster Storage Cache Stores", @("Cache Pages StandBy L2"), 9, '0.00E+0', 1, 'Sum', $false)) +$c.Add([CounterColumn]::new("Dirty", "Cluster Storage Cache Stores", @("Cache Pages Dirty"), 9, '0.00E+0', 1, 'Sum', $false)) + +$c.Seal() +$allctrs += $c + +### + +foreach ($subset in '','Local','Remote') { + $name = 'SBL' + $prefix = '' + if ($subset.Length) { + $name += " $subset" + $prefix = "$($subset): " + } + + $c = [CounterColumnSet]::new($name) + + $c.Add([CounterColumn]::new("IOPS", "Cluster Disk Counters", @(($prefix + "Read/sec"),($prefix + "Writes/sec")), 12, '#,#', 1, 'Sum', $false)) + $c.Add([CounterColumn]::new("Reads", "Cluster Disk Counters", @($prefix + "Read/sec"), 12, '#,#', 1, 'Sum', $false)) + $c.Add([CounterColumn]::new("Writes", "Cluster Disk Counters", @($prefix + "Writes/sec"), 12, '#,#', 1, 'Sum', $false)) + + $c.Add([CounterColumn]::new("BW (MB/s)", "Cluster Disk Counters", @(($prefix + "Read - Bytes/sec"),($prefix + "Write - Bytes/sec")), 13, '#,#', 0.000001, 'Sum', $true)) + $c.Add([CounterColumn]::new("Read", "Cluster Disk Counters", @($prefix + "Read - Bytes/sec"), 8, '#,#', 0.000001, 'Sum', $false)) + $c.Add([CounterColumn]::new("Write", "Cluster Disk Counters", @($prefix + "Write - Bytes/sec"), 8, '#,#', 0.000001, 'Sum', $false)) + + $c.Add([CounterColumn]::new("Read Lat (ms)", "Cluster Disk Counters", @($prefix + "Read Latency"), 15, '0.000', 1000, 'Average', $true)) + $c.Add([CounterColumn]::new("Write", "Cluster Disk Counters", @($prefix + "Write Latency"), 8, '0.000', 1000, 'Average', $false)) + + $c.Add([CounterColumn]::new("Read QAvg", "Cluster Disk Counters", @($prefix + "Read Avg. Queue Length"), 11, '0.000', 1, 'Average', $true)) + $c.Add([CounterColumn]::new("Write", "Cluster Disk Counters", @($prefix + "Write Avg. Queue Length"), 8, '0.000', 1, 'Average', $false)) + + $c.Seal() + $allctrs += $c +} + +### +$c = [CounterColumnSet]::new("SMB SRV") + +$c.Add([CounterColumn]::new("IOPS", "SMB Server Shares", @("Data Requests/sec"), 12, '#,#', 1, 'Sum', $false)) +$c.Add([CounterColumn]::new("Reads", "SMB Server Shares", @("Read Requests/sec"), 12, '#,#', 1, 'Sum', $false)) +$c.Add([CounterColumn]::new("Writes", "SMB Server Shares", @("Write Requests/sec"), 12, '#,#', 1, 'Sum', $false)) + +$c.Add([CounterColumn]::new("Data BW (MB/s)", "SMB Server Shares", @("Data Bytes/sec"), 13, '#,#', 0.000001, 'Sum', $true)) +$c.Add([CounterColumn]::new("Read", "SMB Server Shares", @("Read Bytes/sec"), 8, '#,#', 0.000001, 'Sum', $false)) +$c.Add([CounterColumn]::new("Write", "SMB Server Shares", @("Write Bytes/sec"), 8, '#,#', 0.000001, 'Sum', $false)) + +$c.Add([CounterColumn]::new("Total BW (MB/s)", "SMB Server Shares", @("Transferred Bytes/sec"), 13, '#,#', 0.000001, 'Sum', $true)) +$c.Add([CounterColumn]::new("Rcv", "SMB Server Shares", @("Received Bytes/sec"), 8, '#,#', 0.000001, 'Sum', $false)) +$c.Add([CounterColumn]::new("Snd", "SMB Server Shares", @("Sent Bytes/sec"), 8, '#,#', 0.000001, 'Sum', $false)) + +$c.Seal() +$allctrs += $c + +## +$c = [CounterColumnSet]::new("S2D BW") + +$c.Add([CounterColumn]::new("CSV (MB/s)", "Cluster CSVFS", @("Read Bytes/sec","Write Bytes/sec"), 10, '#,#', 0.000001, 'Sum', $false)) +$c.Add([CounterColumn]::new("Read", "Cluster CSVFS", @("Read Bytes/sec"), 8, '#,#', 0.000001, 'Sum', $false)) +$c.Add([CounterColumn]::new("Write", "Cluster CSVFS", @("Write Bytes/sec"), 8 ,'#,#', 0.000001, 'Sum', $false)) + +$c.Add([CounterColumn]::new("SBL (MB/s)", "Cluster Disk Counters", @("Read - Bytes/sec","Write - Bytes/sec"), 10, '#,#', 0.000001, 'Sum', $true)) +$c.Add([CounterColumn]::new("Read", "Cluster Disk Counters", @("Read - Bytes/sec"), 8, '#,#', 0.000001, 'Sum', $false)) +$c.Add([CounterColumn]::new("Write", "Cluster Disk Counters", @("Write - Bytes/sec"), 8, '#,#', 0.000001, 'Sum', $false)) + +$c.Add([CounterColumn]::new("Cache (MB/s)", "Cluster Storage Hybrid Disks", @("Cache Hit Read Bytes/sec","Cache Write Bytes/sec"), 12, '#,#', 0.000001, 'Sum', $true)) +$c.Add([CounterColumn]::new("Read", "Cluster Storage Hybrid Disks", @("Cache Hit Read Bytes/sec"), 8, '#,#', 0.000001, 'Sum', $false)) +$c.Add([CounterColumn]::new("Write", "Cluster Storage Hybrid Disks", @("Cache Write Bytes/sec"), 8, '#,#', 0.000001, 'Sum', $false)) + +$c.Add([CounterColumn]::new("Disk (MB/s)", "Cluster Storage Hybrid Disks", @("Disk Read Bytes/sec","Disk Write Bytes/sec"), 11, '#,#', 0.000001, 'Sum', $true)) +$c.Add([CounterColumn]::new("Read", "Cluster Storage Hybrid Disks", @("Disk Read Bytes/sec"), 8, '#,#', 0.000001, 'Sum', $false)) +$c.Add([CounterColumn]::new("Write", "Cluster Storage Hybrid Disks", @("Disk Write Bytes/sec"), 8, '#,#', 0.000001, 'Sum', $false)) + +$c.Seal() +$allctrs += $c + +## +$c = [CounterColumnSet]::new("Hyper-V LCPU") +$c.Add([CounterColumn]::new("Logical Total%", "Hyper-V Hypervisor Logical Processor", @("% Total Run Time"), 8, "0.00", 1, 'AverageAggregate', $false)) +$c.Add([CounterColumn]::new("Guest%", "Hyper-V Hypervisor Logical Processor", @("% Guest Run Time"), 8, "0.00", 1, 'AverageAggregate', $false)) +$c.Add([CounterColumn]::new("Hypervisor%", "Hyper-V Hypervisor Logical Processor", @("% Hypervisor Run Time"), 13, "0.00", 1, 'AverageAggregate', $false)) + +$c.Add([CounterColumn]::new("Root Total%", "Hyper-V Hypervisor Root Virtual Processor", @("% Total Run Time"), 12, "0.00", 1, 'AverageAggregate', $true)) +$c.Add([CounterColumn]::new("Guest%", "Hyper-V Hypervisor Root Virtual Processor", @("% Guest Run Time"), 8, "0.00", 1, 'AverageAggregate', $false)) +$c.Add([CounterColumn]::new("Hypervisor%", "Hyper-V Hypervisor Root Virtual Processor", @("% Hypervisor Run Time"), 12, "0.00", 1, 'AverageAggregate', $false)) +$c.Add([CounterColumn]::new("Remote%", "Hyper-V Hypervisor Root Virtual Processor", @("% Remote Run Time"), 7, "0.00", 1, 'AverageAggregate', $false)) + +$c.Seal() +$allctrs += $c + +## +$c = [CounterColumnSet]::new("SMB Transport") +$c.add([CounterColumn]::new("Read IOPS", "SMB Client Shares", @("Read Requests/sec"), 11, "#,#", 1, 'Sum', $false)) +$c.add([CounterColumn]::new("Write", "SMB Client Shares", @("Write Requests/sec"), 8, "#,#", 1, 'Sum', $false)) + +$c.add([CounterColumn]::new("RDMA Read", "SMB Client Shares", @("Read Requests transmitted via SMB Direct/sec"), 11, "#,#", 1, 'Sum', $true)) +$c.add([CounterColumn]::new("Write", "SMB Client Shares", @("Write Requests transmitted via SMB Direct/sec"), 8, "#,#", 1, 'Sum', $false)) + +$c.Seal() +$allctrs += $c + +## +if ($Sets.Count -eq 1 -and $Sets[0] -eq '*') { + $ctrs = $allctrs +} else { + $ctrs = $Sets |% { + $s = $_ + $allctrs |? { $_.name -like $s } # allows the SBL* wildcard + } +} + +function start-sample( + [CounterColumnSet[]] $ctrs, + [int] $SampleInterval + ) +{ + # clear any previous job instance + Get-Job -Name watch-cluster -ErrorAction SilentlyContinue | Stop-Job + Get-Job -Name watch-cluster -ErrorAction SilentlyContinue | Remove-Job + + # flatten list of counters and uniquify for the total counter set + # some display counter sets may repeat specific values (which is fine) + $counters = ($ctrs.counters |% { $_ |% { $_ }} | group -NoElement).Name + + icm -AsJob -JobName watch-cluster (Get-ClusterNode -Cluster $Cluster) { + + # extract countersamples, the object does not survive transfer between powershell sessions + # extract as a list, not as the individual counters + get-counter -Continuous -SampleInterval $using:SampleInterval $using:ctrs.counters |% { + ,$_.countersamples + } + } +} + +# start the first sample job and allow frame draw the first time through +$j = start-sample $ctrs $SampleInterval +$downtime = $null +$skipone = $false +$loops = 0 +$restart = $false + +# hash of most recent samples/node +$samples = @{} +Get-ClusterNode -Cluster $Cluster |% { $samples[$_.Name] = $null } + +while ($true) { + + if (-not $restart) { + Start-Sleep -Seconds $SampleInterval + + # sleep again if needed to prime the sample pipeline; + # there are no samples if we just restarted the sampling jobs + if ($skipone) { + $skipone = $false + continue + } + + # receive updates into the per-node hash + foreach ($child in $j.ChildJobs) { + $samples[$child.Location] = $child | receive-job -ErrorAction SilentlyContinue + } + + # null out downed nodes and remember first time we saw one drop out + $down = 0 + $j.ChildJobs |? State -ne Running |% { + $samples[$_.Location] = $null + $down += 1 + } + if ($down -and $null -eq $downtime) { + $downtime = get-date + } + + # if everything is down, we will attempt restart + if ($down -eq $j.ChildJobs.Count) { + $restart = $true + break + } + } + + # if explicit restart is required, or it has been 30 seconds with a downed node, restart the jobs to retry + if ($restart -or ($null -ne $downtime -and ((get-date)-$downtime).totalseconds -gt 30)) { + $j | stop-job + $j | remove-job + $j = start-sample $ctrs $SampleInterval + + # force gc to clear out accumulated job state quickly + [system.gc]::Collect() + + $downtime = $null + $skipone = $true + $restart = $false + continue + } + + # now process samples into per-node hashes of set/ctr containing lists of the + # cooked values acrosss the (possible) multiple instances + $psamples = @{} + foreach ($node in $samples.keys) { + + if ($samples[$node]) { + + $nsamples = @{} + + # flatten samples - if we are lagging, we'll have a list + # of consecutive (increasing by timestamp) samples + # we could try to be more efficient by dumping all but the + # final sample, but later ... + $samples[$node] |% { $_ } |% { + + ($setinst,$ctr) = $($_.path -split '\\')[3..4] + $set = ($setinst -split '\(')[0] + + $k = "$set+$ctr" + $nsamples[$k] = $_.cookedvalue + } + + $psamples[$node] = $nsamples + } + } + + # post-process the samples into the counterset, then clear and dump + $ctrs.DisplayPre($samples, $psamples) + Clear-Host + $drawsep = $false + $ctrs |% { + if ($drawsep) { + write-host -fore Green $('-'*20) + } + $drawsep = $true + $_.Display() + + } + + # restart the jobs every so many loops to prevent resource growth + $loops += 1 + if ($loops -gt 100) { + $loops = 0 + $restart = $true + } +} \ No newline at end of file diff --git a/CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/watch-cpu.ps1 b/CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/watch-cpu.ps1 new file mode 100644 index 0000000..31928e2 --- /dev/null +++ b/CristalDiskMark/source/diskspd22/Frameworks/VMFleet1.0/watch-cpu.ps1 @@ -0,0 +1,210 @@ +<# +DISKSPD - VM Fleet + +Copyright(c) Microsoft Corporation +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +#> + +param( + $ComputerName = $env:COMPUTERNAME, + $SampleInterval = 2 + ) + +function div-to-width( + [int] $div + ) +{ + # 0 - 100 scale + # ex: 4 -> 100/4 = 25 buckets + 1 more for == 100 + 1+100/$div +} + +function center-pad( + [string] $s, + [int] $width + ) +{ + if ($width -le $s.length) { + $s + } else { + (' ' * (($width - $s.length)/2) + $s) + } +} + +function get-legend( + [int] $width, + [int] $div + ) +{ + # now produce the scale, a digit at a time in vertical orientation + # at each multiple of 10% which aligns with a measurement bucket. + # the width is the width of the measured values + # + # 0 5 1 + # 0 0 + # 0 + + $lines = @() + $lines += ,('-' * $width) + + foreach ($dig in 0..2) { + $o = foreach ($pos in 0..($width - 1)) { + + $val = $pos * $div + if ($val % 10 -eq 0) { + switch ($dig) { + 0 { if ($val -eq 100) { 1 } else { $val / 10 }} + 1 { if ($val -ne 0) { 0 } else { ' ' }} + 2 { if ($val -eq 100) { 0 } else { ' ' }} + } + } else { ' ' } + } + + $lines += ,($o -join '') + } + + # trailing comments (horizontal scale name) + 'Percent CPU Utilization' |% { + $lines += ,(center-pad $_ $width) + } + + $lines +} + +# these are the valid divisions, in units of percentage width. +# they must evenly divide 100% and either 10% or 20% for scale markings. +# determine which is the best fit based on window width. + +$div = 0 +foreach ($i in 1,2,4,5) { + if ((div-to-width $i) -le [console]::WindowWidth) { + $div = $i + break + } +} + +# if nothing fit, widen to 4% divisions + +if ($div -eq 0) { + $div = 4 +} + +$width = div-to-width $div + +# get the constant legend; use the remaining height for the vertical cpu core bars. +# note total height includes variable label line at bottom (instance + aggregagte) +$legend = get-legend $width $div +$clip = [console]::WindowHeight - $legend.Count - 1 + +# insist on a clip no lower than 10 + +if ($clip -lt 10) { + $clip = 10 +} + +# set window and buffer size simultaneously so we don't have extra scrollbars +cls +[console]::SetWindowSize($width,$clip + $legend.Count + 1) +[console]::BufferWidth = [console]::WindowWidth +[console]::BufferHeight = [console]::WindowHeight + +# scale divisions at x% +# this should evenly divide 100% +$m = [array]::CreateInstance([int],$width) + +# which processor counterset should we use? +# pi is only the root partition if hv is active +# hvlp is the host physical processors when hv is active +# via ctrs, hv is active iff hvlp is present and has multiple instances +$cset = get-counter -ComputerName $ComputerName -ListSet 'Hyper-V Hypervisor Logical Processor' -ErrorAction SilentlyContinue +if ($cs -ne $null -and $cs.CounterSetType -eq [Diagnostics.PerformanceCounterCategoryType]::MultiInstance) { + $cpuset = '\Hyper-V Hypervisor Logical Processor(*)\% Total Run Time' +} else { + $cpuset = '\Processor Information(*)\% Processor Time' +} + +# processor performance counter (turbo/speedstep) +$ppset = '\Processor Information(_Total)\% Processor Performance' + +while ($true) { + + # reset measurements & the lines to output + $lines = @() + foreach ($i in 0..($m.length - 1)) { + $m[$i] = 0 + } + + # avoid remoting for the local case + if ($ComputerName -eq $env:COMPUTERNAME) { + $samp = (get-counter -SampleInterval $SampleInterval -Counter $cpuset,$ppset).Countersamples + } else { + $samp = (get-counter -SampleInterval $SampleInterval -Counter $cpuset,$ppset -ComputerName $ComputerName).Countersamples + } + + # get all specific instances and count them into appropriate measurement bucket + $samp |% { + + if ($_.Path -like "*$ppset") { # scaling factor for total utility + $pperf = $_.CookedValue/100 + } elseif ($_.InstanceName -notlike '*_Total') { # per cpu: ignore total and per-numa total + $m[[math]::Floor($_.CookedValue/$div)] += 1 + } elseif ($_.InstanceName -eq '_Total') { # get total + $total = $_.CookedValue + } + } + + # work down the veritical altitude of each strip, starting at vclip + $altitude = $clip + do { + $lines += ,($($m |% { + + # if we are potentially clipped, handle + if ($altitude -eq $clip) { + + # clipped? + # unclipped but at clip? + # nothing, less than altitude + + if ($_ -gt $altitude) { 'x' } + elseif ($_ -eq $altitude) { '*' } + else { ' ' } + + } else { + # normal + # >=, output + # <, nothing + if ($_ -ge $altitude) { '*' } + else { ' ' } + } + }) -join '') + } while (--$altitude) + + cls + write-host -NoNewline ($lines + $legend -join "`n") + write-host -NoNewLine ("`n" + (center-pad ("{2} Total: {0:0.0}% Normalized: {1:0.0}%" -f $total,($total*$pperf),$ComputerName) $width)) + + # move the cursor to indicate average utilization + # column number is zero based, width is 1-based + [console]::SetCursorPosition([math]::Floor(($width - 1)*$total/100),[console]::CursorTop-$legend.Count) + +} \ No newline at end of file diff --git a/CristalDiskMark/source/diskspd22/IORequestGenerator/IORequestGenerator.cpp b/CristalDiskMark/source/diskspd22/IORequestGenerator/IORequestGenerator.cpp new file mode 100644 index 0000000..735d912 --- /dev/null +++ b/CristalDiskMark/source/diskspd22/IORequestGenerator/IORequestGenerator.cpp @@ -0,0 +1,2866 @@ +/* + +DISKSPD + +Copyright(c) Microsoft Corporation +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +//FUTURE EXTENSION: make it compile with /W4 + +// Windows 7 +#ifndef _WIN32_WINNT +#define _WIN32_WINNT 0x0601 +#endif + +#include "common.h" +#include "IORequestGenerator.h" + +#include +#include +#include //DISK_GEOMETRY +#include +#include + +#include //WNODE_HEADER + +#include "etw.h" +#include +#include "ThroughputMeter.h" +#include "OverlappedQueue.h" + +// Flags for RtlFlushNonVolatileMemory +#ifndef FLUSH_NV_MEMORY_IN_FLAG_NO_DRAIN +#define FLUSH_NV_MEMORY_IN_FLAG_NO_DRAIN (0x00000001) +#endif + +/*****************************************************************************/ +// gets size of a dynamic volume, return zero on failure +// +UINT64 GetDynamicPartitionSize(HANDLE hFile) +{ + assert(NULL != hFile && INVALID_HANDLE_VALUE != hFile); + + UINT64 size = 0; + VOLUME_DISK_EXTENTS diskExt = {0}; + PVOLUME_DISK_EXTENTS pDiskExt = &diskExt; + DWORD bytesReturned; + + DWORD status = ERROR_SUCCESS; + BOOL rslt; + + OVERLAPPED ovlp = {0}; + ovlp.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); + if (ovlp.hEvent == nullptr) + { + PrintError("ERROR: Failed to create event (error code: %u)\n", GetLastError()); + return 0; + } + + rslt = DeviceIoControl(hFile, + IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS, + NULL, + 0, + pDiskExt, + sizeof(VOLUME_DISK_EXTENTS), + &bytesReturned, + &ovlp); + if (!rslt) { + status = GetLastError(); + if (status == ERROR_MORE_DATA) { + status = ERROR_SUCCESS; + + bytesReturned = sizeof(VOLUME_DISK_EXTENTS) + ((pDiskExt->NumberOfDiskExtents - 1) * sizeof(DISK_EXTENT)); + pDiskExt = (PVOLUME_DISK_EXTENTS)LocalAlloc(LPTR, bytesReturned); + + if (pDiskExt) + { + rslt = DeviceIoControl(hFile, + IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS, + NULL, + 0, + pDiskExt, + bytesReturned, + &bytesReturned, + &ovlp); + if (!rslt) + { + status = GetLastError(); + if (status == ERROR_IO_PENDING) + { + if (WAIT_OBJECT_0 != WaitForSingleObject(ovlp.hEvent, INFINITE)) + { + status = GetLastError(); + PrintError("ERROR: Failed while waiting for event to be signaled (error code: %u)\n", status); + } + else + { + status = ERROR_SUCCESS; + assert(pDiskExt->NumberOfDiskExtents <= 1); + } + } + else + { + PrintError("ERROR: Could not obtain dynamic volume extents (error code: %u)\n", status); + } + } + } + else + { + status = GetLastError(); + PrintError("ERROR: Could not allocate memory (error code: %u)\n", status); + } + } + else if (status == ERROR_IO_PENDING) + { + if (WAIT_OBJECT_0 != WaitForSingleObject(ovlp.hEvent, INFINITE)) + { + status = GetLastError(); + PrintError("ERROR: Failed while waiting for event to be signaled (error code: %u)\n", status); + } + else + { + status = ERROR_SUCCESS; + assert(pDiskExt->NumberOfDiskExtents <= 1); + } + } + else + { + PrintError("ERROR: Could not obtain dynamic volume extents (error code: %u)\n", status); + } + } + else + { + assert(pDiskExt->NumberOfDiskExtents <= 1); + } + + if (status == ERROR_SUCCESS) + { + for (DWORD n = 0; n < pDiskExt->NumberOfDiskExtents; n++) { + size += pDiskExt->Extents[n].ExtentLength.QuadPart; + } + } + + if (pDiskExt && (pDiskExt != &diskExt)) { + LocalFree(pDiskExt); + } + CloseHandle(ovlp.hEvent); + + return size; +} + +/*****************************************************************************/ +// gets partition size, return zero on failure +// +UINT64 GetPartitionSize(HANDLE hFile) +{ + assert(NULL != hFile && INVALID_HANDLE_VALUE != hFile); + + PARTITION_INFORMATION_EX pinf; + OVERLAPPED ovlp = {}; + + ovlp.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); + if (ovlp.hEvent == nullptr) + { + PrintError("ERROR: Failed to create event (error code: %u)\n", GetLastError()); + return 0; + } + + DWORD rbcnt = 0; + DWORD status = ERROR_SUCCESS; + UINT64 size = 0; + + if (!DeviceIoControl(hFile, + IOCTL_DISK_GET_PARTITION_INFO_EX, + NULL, + 0, + &pinf, + sizeof(pinf), + &rbcnt, + &ovlp) + ) + { + status = GetLastError(); + if (status == ERROR_IO_PENDING) + { + if (WAIT_OBJECT_0 != WaitForSingleObject(ovlp.hEvent, INFINITE)) + { + PrintError("ERROR: Failed while waiting for event to be signaled (error code: %u)\n", GetLastError()); + } + else + { + size = pinf.PartitionLength.QuadPart; + } + } + else + { + size = GetDynamicPartitionSize(hFile); + } + } + else + { + size = pinf.PartitionLength.QuadPart; + } + + CloseHandle(ovlp.hEvent); + + return size; +} + +/*****************************************************************************/ +// gets physical drive size, return zero on failure +// +UINT64 GetPhysicalDriveSize(HANDLE hFile) +{ + assert(NULL != hFile && INVALID_HANDLE_VALUE != hFile); + + DISK_GEOMETRY_EX geom; + OVERLAPPED ovlp = {}; + + ovlp.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); + if (ovlp.hEvent == nullptr) + { + PrintError("ERROR: Failed to create event (error code: %u)\n", GetLastError()); + return 0; + } + + DWORD rbcnt = 0; + DWORD status = ERROR_SUCCESS; + BOOL rslt; + + rslt = DeviceIoControl(hFile, + IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, + NULL, + 0, + &geom, + sizeof(geom), + &rbcnt, + &ovlp); + + if (!rslt) + { + status = GetLastError(); + if (status == ERROR_IO_PENDING) + { + if (WAIT_OBJECT_0 != WaitForSingleObject(ovlp.hEvent, INFINITE)) + { + PrintError("ERROR: Failed while waiting for event to be signaled (error code: %u)\n", GetLastError()); + } + else + { + rslt = TRUE; + } + } + else + { + PrintError("ERROR: Could not obtain drive geometry (error code: %u)\n", status); + } + } + + CloseHandle(ovlp.hEvent); + + if (!rslt) + { + return 0; + } + + return (UINT64)geom.DiskSize.QuadPart; +} + +/*****************************************************************************/ +// activates specified privilege in process token +// +bool SetPrivilege(LPCSTR pszPrivilege, LPCSTR pszErrorPrefix = "ERROR:") +{ + TOKEN_PRIVILEGES TokenPriv; + HANDLE hToken = INVALID_HANDLE_VALUE; + DWORD dwError; + bool fOk = true; + + if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken)) + { + PrintError("%s Error opening process token (error code: %u)\n", pszErrorPrefix, GetLastError()); + fOk = false; + goto cleanup; + } + + TokenPriv.PrivilegeCount = 1; + TokenPriv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; + if (!LookupPrivilegeValue(nullptr, pszPrivilege, &TokenPriv.Privileges[0].Luid)) + { + PrintError("%s Error looking up privilege value %s (error code: %u)\n", pszErrorPrefix, pszPrivilege, GetLastError()); + fOk = false; + goto cleanup; + } + + if (!AdjustTokenPrivileges(hToken, FALSE, &TokenPriv, 0, nullptr, nullptr)) + { + PrintError("%s Error adjusting token privileges for %s (error code: %u)\n", pszErrorPrefix, pszPrivilege, GetLastError()); + fOk = false; + goto cleanup; + } + + if (ERROR_SUCCESS != (dwError = GetLastError())) + { + PrintError("%s Error adjusting token privileges for %s (error code: %u)\n", pszErrorPrefix, pszPrivilege, dwError); + fOk = false; + goto cleanup; + } + +cleanup: + if (hToken != INVALID_HANDLE_VALUE) + { + CloseHandle(hToken); + } + + return fOk; +} + +BOOL +DisableLocalCache( + HANDLE h +) +/*++ +Routine Description: + + Disables local caching of I/O to a file by SMB. All reads/writes will flow to the server. + +Arguments: + + h - Handle to the file + +Return Value: + + Returns ERROR_SUCCESS (0) on success, nonzero error code on failure. + +--*/ +{ + DWORD BytesReturned = 0; + OVERLAPPED Overlapped = { 0 }; + DWORD Status = ERROR_SUCCESS; + BOOL Success = false; + + Overlapped.hEvent = CreateEvent(nullptr, true, false, nullptr); + if (!Overlapped.hEvent) + { + return GetLastError(); + } + +#ifndef FSCTL_DISABLE_LOCAL_BUFFERING +#define FSCTL_DISABLE_LOCAL_BUFFERING CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 174, METHOD_BUFFERED, FILE_ANY_ACCESS) +#endif + + Success = DeviceIoControl(h, + FSCTL_DISABLE_LOCAL_BUFFERING, + nullptr, + 0, + nullptr, + 0, + nullptr, + &Overlapped); + + if (!Success) { + Status = GetLastError(); + } + + if (!Success && Status == ERROR_IO_PENDING) + { + if (!GetOverlappedResult(h, &Overlapped, &BytesReturned, true)) + { + Status = GetLastError(); + } + else + { + Status = (DWORD) Overlapped.Internal; + } + } + + if (Overlapped.hEvent) + { + CloseHandle(Overlapped.hEvent); + } + + return Status; +} + +/*****************************************************************************/ +// structures and global variables +// +struct ETWEventCounters g_EtwEventCounters; + +__declspec(align(4)) static LONG volatile g_lRunningThreadsCount = 0; //must be aligned on a 32-bit boundary, otherwise InterlockedIncrement + //and InterlockedDecrement will fail on 64-bit systems + +static BOOL volatile g_bRun; //used for letting threads know that they should stop working + +typedef NTSTATUS (__stdcall *NtQuerySysInfo)(SYSTEM_INFORMATION_CLASS, PVOID, ULONG, PULONG); +static NtQuerySysInfo g_pfnNtQuerySysInfo; + +typedef VOID (__stdcall *RtlCopyMemNonTemporal)(VOID UNALIGNED *, VOID UNALIGNED *, SIZE_T); +static RtlCopyMemNonTemporal g_pfnRtlCopyMemoryNonTemporal; + +typedef NTSTATUS (__stdcall *RtlFlushNvMemory)(PVOID, PVOID, SIZE_T, ULONG); +static RtlFlushNvMemory g_pfnRtlFlushNonVolatileMemory; + +typedef NTSTATUS(__stdcall *RtlGetNvToken)(PVOID, SIZE_T, PVOID *); +static RtlGetNvToken g_pfnRtlGetNonVolatileToken; + +typedef NTSTATUS(__stdcall *RtlFreeNvToken)(PVOID); +static RtlFreeNvToken g_pfnRtlFreeNonVolatileToken; + +static BOOL volatile g_bThreadError = FALSE; //true means that an error has occured in one of the threads +BOOL volatile g_bTracing = TRUE; //true means that ETW is turned on + +// TODO: is this still needed? +__declspec(align(4)) static LONG volatile g_lGeneratorRunning = 0; //used to detect if GenerateRequests is already running + +static BOOL volatile g_bError = FALSE; //true means there was fatal error during intialization and threads shouldn't perform their work + +VOID SetProcGroupMask(WORD wGroupNum, ULONG dwProcNum, PGROUP_AFFINITY pGroupAffinity) +{ + //must zero this structure first, otherwise it fails to set affinity + memset(pGroupAffinity, 0, sizeof(GROUP_AFFINITY)); + + pGroupAffinity->Group = wGroupNum; + pGroupAffinity->Mask = (KAFFINITY)1<Group = wGroupNum; + pGroupAffinity->Mask = Mask; +} + +/*****************************************************************************/ +void IORequestGenerator::_CloseOpenFiles(vector& vhFiles) const +{ + for (size_t x = 0; x < vhFiles.size(); ++x) + { + if ((INVALID_HANDLE_VALUE != vhFiles[x]) && (nullptr != vhFiles[x])) + { + if (!CloseHandle(vhFiles[x])) + { + PrintError("Warning: unable to close file handle (error code: %u)\n", GetLastError()); + } + vhFiles[x] = nullptr; + } + } +} + +/*****************************************************************************/ +// wrapper for stderr +void PrintError(const char *format, ...) +{ + assert(NULL != format); + + va_list listArg; + va_start(listArg, format); + vfprintf(stderr, format, listArg); + va_end(listArg); +} + +/*****************************************************************************/ +// prints the string only if verbose mode is set to true +// +static void PrintVerbose(bool fVerbose, const char *format, ...) +{ + assert(NULL != format); + + if(fVerbose ) + { + SYSTEMTIME now; + char szBuffer[64]; // enough for timestamp+null + int nWritten; + + GetLocalTime(&now); + + if (now.wYear) { + + // Mimic .NET 's' sortable time pattern + nWritten = sprintf_s(szBuffer, _countof(szBuffer), + "%u-%02u-%02uT%02u:%02u:%02u", + now.wYear, + now.wMonth, + now.wDay, + now.wHour, + now.wMinute, + now.wSecond); + assert(nWritten && nWritten < _countof(szBuffer)); + + // no newline + printf("%s: " ,szBuffer); + } + + va_list argList; + va_start(argList, format); + vprintf(format, argList); + va_end(argList); + } +} + +/*****************************************************************************/ +// thread for gathering ETW data (etw functions are defined in etw.cpp) +// +DWORD WINAPI etwThreadFunc(LPVOID cookie) +{ + UNREFERENCED_PARAMETER(cookie); + + g_bTracing = TRUE; + BOOL result = TraceEvents(); + g_bTracing = FALSE; + + return result ? 0 : 1; +} + +/*****************************************************************************/ +bool IORequestGenerator::_LoadDLLs() +{ + _hNTDLL = LoadLibraryExW(L"ntdll.dll", nullptr, 0); + if( nullptr == _hNTDLL ) + { + return false; + } + + g_pfnNtQuerySysInfo = (NtQuerySysInfo)GetProcAddress(_hNTDLL, "NtQuerySystemInformation"); + if( nullptr == g_pfnNtQuerySysInfo ) + { + return false; + } + + g_pfnRtlCopyMemoryNonTemporal = (RtlCopyMemNonTemporal)GetProcAddress(_hNTDLL, "RtlCopyMemoryNonTemporal"); + g_pfnRtlFlushNonVolatileMemory = (RtlFlushNvMemory)GetProcAddress(_hNTDLL, "RtlFlushNonVolatileMemory"); + g_pfnRtlGetNonVolatileToken = (RtlGetNvToken)GetProcAddress(_hNTDLL, "RtlGetNonVolatileToken"); + g_pfnRtlFreeNonVolatileToken = (RtlFreeNvToken)GetProcAddress(_hNTDLL, "RtlFreeNonVolatileToken"); + + return true; +} + +/*****************************************************************************/ +bool IORequestGenerator::_GetSystemPerfInfo(vector& vSPPI, bool fVerbose) const +{ + NTSTATUS Status; + ULONG CpuBase; + WORD Group; + WORD GroupCount; + GROUP_AFFINITY GroupAffinity; + + for (CpuBase = 0, Group = 0, GroupCount = (WORD) g_SystemInformation.processorTopology._vProcessorGroupInformation.size(); + Group < GroupCount; + Group++) + { + ProcessorGroupInformation *pGroup = &g_SystemInformation.processorTopology._vProcessorGroupInformation[Group]; + + // + // Note that an inactive group is not queried (its not clear this is a practical case). + // Correct operation assumes the input SPPI array is prezeroed, which DISKSPD does do via + // default vector(size_t) construction. + // + + if (pGroup->_activeProcessorCount != 0) + { + // + // In multigroup environments, affinitize to the group we're querying counters from. + // + + if (GroupCount > 1) + { + SetGroupMask(Group, pGroup->_activeProcessorMask, &GroupAffinity); + if (!SetThreadGroupAffinity(GetCurrentThread(), &GroupAffinity, nullptr)) + { + PrintError("get system perf info: failed to set affinity to Group %u\n", GroupAffinity.Group); + return false; + } + } + + // + // The SPPI vector should (is) always be sized to span CPUs for all groups, make this explicit. + // + + if (CpuBase + pGroup->_activeProcessorCount > vSPPI.size()) + { + PrintError("get system perf info: unable to return (base CPU %u + group active CPU %u > size %u)\n", + CpuBase, + pGroup->_activeProcessorCount, + vSPPI.size()); + assert(false); + return false; + } + + Status = g_pfnNtQuerySysInfo(SystemProcessorPerformanceInformation, + &vSPPI[CpuBase], + sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION) * pGroup->_activeProcessorCount, + nullptr); + + if (!NT_SUCCESS(Status)) + { + PrintError("get system perf info: status 0x%x querying for Group %u (%u CPUs)\n", + Status, + Group, + pGroup->_activeProcessorCount); + return false; + } + + PrintVerbose(fVerbose, + "get system perf info: queried for Group %u (%u CPUs)\n", + Group, + pGroup->_activeProcessorCount); + } + + CpuBase += pGroup->_activeProcessorCount; + } + + return true; +} + +VOID CALLBACK fileIOCompletionRoutine(DWORD dwErrorCode, DWORD dwBytesTransferred, LPOVERLAPPED pOverlapped); + +static bool issueNextIO(ThreadParameters *p, IORequest *pIORequest, DWORD *pdwBytesTransferred, bool useCompletionRoutines) +{ + OVERLAPPED *pOverlapped = pIORequest->GetOverlapped(); + Target *pTarget = pIORequest->GetCurrentTarget(); + size_t iTarget = pIORequest->GetCurrentTargetIndex(); + UINT32 iRequest = pIORequest->GetRequestIndex(); + LARGE_INTEGER li; + BOOL rslt = true; + + // + // Compute next IO + // + + p->vTargetStates[iTarget].NextIORequest(*pIORequest); + + li.LowPart = pIORequest->GetOverlapped()->Offset; + li.HighPart = pIORequest->GetOverlapped()->OffsetHigh; + + if (TraceLoggingProviderEnabled(g_hEtwProvider, + TRACE_LEVEL_VERBOSE, + DISKSPD_TRACE_IO)) + { + GUID ActivityId = p->NextActivityId(); + pIORequest->SetActivityId(ActivityId); + + TraceLoggingWriteActivity(g_hEtwProvider, + "DiskSpd IO", + &ActivityId, + NULL, + TraceLoggingKeyword(DISKSPD_TRACE_IO), + TraceLoggingOpcode(EVENT_TRACE_TYPE_START), + TraceLoggingLevel(TRACE_LEVEL_VERBOSE), + TraceLoggingUInt32(p->ulThreadNo, "Thread"), + TraceLoggingString(pIORequest->GetIoType() == IOOperation::ReadIO ? "Read" : "Write", "IO Type"), + TraceLoggingUInt64(iTarget, "Target"), + TraceLoggingInt32(pTarget->GetBlockSizeInBytes(), "Block Size"), + TraceLoggingInt64(li.QuadPart, "Offset")); + } + +#if 0 + PrintError("t[%u:%u] issuing %u %s @ %I64u)\n", p->ulThreadNo, iTarget, + pTarget->GetBlockSizeInBytes(), + (pIORequest->GetIoType() == IOOperation::ReadIO ? "read" : "write"), + li.QuadPart); +#endif + + if (p->pTimeSpan->GetMeasureLatency() || p->pTimeSpan->GetCalculateIopsStdDev()) + { + pIORequest->SetStartTime(PerfTimer::GetTime()); + } + + if (pIORequest->GetIoType() == IOOperation::ReadIO) + { + if (pTarget->GetMemoryMappedIoMode() == MemoryMappedIoMode::On) + { + if (pTarget->GetWriteThroughMode() == WriteThroughMode::On ) + { + g_pfnRtlCopyMemoryNonTemporal(p->GetReadBuffer(iTarget, iRequest), pTarget->GetMappedView() + li.QuadPart, pTarget->GetBlockSizeInBytes()); + } + else + { + memcpy(p->GetReadBuffer(iTarget, iRequest), pTarget->GetMappedView() + li.QuadPart, pTarget->GetBlockSizeInBytes()); + } + *pdwBytesTransferred = pTarget->GetBlockSizeInBytes(); + } + else + { + if (useCompletionRoutines) + { + rslt = ReadFileEx(p->vhTargets[iTarget], p->GetReadBuffer(iTarget, iRequest), pTarget->GetBlockSizeInBytes(), pOverlapped, fileIOCompletionRoutine); + } + else + { + rslt = ReadFile(p->vhTargets[iTarget], p->GetReadBuffer(iTarget, iRequest), pTarget->GetBlockSizeInBytes(), pdwBytesTransferred, pOverlapped); + } + } + } + else + { + if (pTarget->GetMemoryMappedIoMode() == MemoryMappedIoMode::On) + { + if (pTarget->GetWriteThroughMode() == WriteThroughMode::On) + { + g_pfnRtlCopyMemoryNonTemporal(pTarget->GetMappedView() + li.QuadPart, p->GetWriteBuffer(iTarget, iRequest), pTarget->GetBlockSizeInBytes()); + } + else + { + memcpy(pTarget->GetMappedView() + li.QuadPart, p->GetWriteBuffer(iTarget, iRequest), pTarget->GetBlockSizeInBytes()); + + switch (pTarget->GetMemoryMappedIoFlushMode()) + { + case MemoryMappedIoFlushMode::ViewOfFile: + FlushViewOfFile(pTarget->GetMappedView() + li.QuadPart, pTarget->GetBlockSizeInBytes()); + break; + case MemoryMappedIoFlushMode::NonVolatileMemory: + g_pfnRtlFlushNonVolatileMemory(pTarget->GetMemoryMappedIoNvToken(), pTarget->GetMappedView() + li.QuadPart, pTarget->GetBlockSizeInBytes(), 0); + break; + case MemoryMappedIoFlushMode::NonVolatileMemoryNoDrain: + g_pfnRtlFlushNonVolatileMemory(pTarget->GetMemoryMappedIoNvToken(), pTarget->GetMappedView() + li.QuadPart, pTarget->GetBlockSizeInBytes(), FLUSH_NV_MEMORY_IN_FLAG_NO_DRAIN); + break; + } + } + *pdwBytesTransferred = pTarget->GetBlockSizeInBytes(); + } + else + { + if (useCompletionRoutines) + { + rslt = WriteFileEx(p->vhTargets[iTarget], p->GetWriteBuffer(iTarget, iRequest), pTarget->GetBlockSizeInBytes(), pOverlapped, fileIOCompletionRoutine); + } + else + { + rslt = WriteFile(p->vhTargets[iTarget], p->GetWriteBuffer(iTarget, iRequest), pTarget->GetBlockSizeInBytes(), pdwBytesTransferred, pOverlapped); + } + } + } + + if (p->vThroughputMeters.size() != 0 && p->vThroughputMeters[iTarget].IsRunning()) + { + p->vThroughputMeters[iTarget].Adjust(pTarget->GetBlockSizeInBytes()); + } + + return (rslt) ? true : false; +} + + +void completeIOat(ThreadParameters *p, IORequest *pIORequest, DWORD dwBytesTransferred, UINT64 ullCompletionTime) +{ + if (*p->pfAccountingOn) + { + p->pResults->vTargetResults[pIORequest->GetCurrentTargetIndex()].Add( + dwBytesTransferred, + pIORequest->GetIoType(), + pIORequest->GetStartTime(), + ullCompletionTime, + *(p->pullStartTime), + p->pTimeSpan->GetMeasureLatency(), + p->pTimeSpan->GetCalculateIopsStdDev()); + } + + if (TraceLoggingProviderEnabled(g_hEtwProvider, + TRACE_LEVEL_VERBOSE, + DISKSPD_TRACE_IO)) + { + GUID ActivityId = pIORequest->GetActivityId(); + + TraceLoggingWriteActivity(g_hEtwProvider, + "DiskSpd IO", + &ActivityId, + NULL, + TraceLoggingKeyword(DISKSPD_TRACE_IO), + TraceLoggingOpcode(EVENT_TRACE_TYPE_STOP), + TraceLoggingLevel(TRACE_LEVEL_VERBOSE)); + } + + Target *pTarget = pIORequest->GetCurrentTarget(); + + //check if I/O transferred all of the requested bytes + if (dwBytesTransferred != pTarget->GetBlockSizeInBytes()) + { + PrintError("Warning: thread %u transferred %u bytes instead of %u bytes\n", + p->ulThreadNo, + dwBytesTransferred, + pTarget->GetBlockSizeInBytes()); + } + + // check if we should print a progress dot + if (p->pProfile->GetProgress() != 0) + { + DWORD dwIOCnt = ++p->dwIOCnt; + if (dwIOCnt % p->pProfile->GetProgress() == 0) + { + printf("."); + } + } +} + +void completeIO(ThreadParameters *p, IORequest *pIORequest, DWORD dwBytesTransferred) +{ + if (p->pTimeSpan->GetMeasureLatency() || p->pTimeSpan->GetCalculateIopsStdDev()) + { + completeIOat(p, pIORequest, dwBytesTransferred, PerfTimer::GetTime()); + } + else + { + completeIOat(p, pIORequest, dwBytesTransferred, 0); + } +} + +/*****************************************************************************/ +// function called from worker thread +// performs synch I/O +// +static bool doWorkUsingSynchronousIO(ThreadParameters *p) +{ + BOOL fOk = true; + BOOL rslt = FALSE; + DWORD dwBytesTransferred; + size_t cIORequests = p->vIORequest.size(); + + while(g_bRun && !g_bThreadError) + { + DWORD nIssued = 0; + DWORD dwMinSleepTime = INFINITE; + for (size_t i = 0; i < cIORequests; i++) + { + IORequest *pIORequest = &p->vIORequest[i]; + Target *pTarget = pIORequest->GetNextTarget(); + + if (p->vThroughputMeters.size() != 0) + { + size_t iTarget = pTarget - &p->vTargets[0]; + ThroughputMeter *pThroughputMeter = &p->vThroughputMeters[iTarget]; + + DWORD dwSleepTime = pThroughputMeter->GetSleepTime(); + dwMinSleepTime = min(dwMinSleepTime, dwSleepTime); + if (pThroughputMeter->IsRunning() && dwSleepTime > 0) + { + continue; + } + } + + nIssued += 1; + rslt = issueNextIO(p, pIORequest, &dwBytesTransferred, false); + + if (!rslt) + { + PrintError("t[%u] error during %s error code: %u)\n", (UINT32)i, (pIORequest->GetIoType() == IOOperation::ReadIO ? "read" : "write"), GetLastError()); + fOk = false; + goto cleanup; + } + + completeIO(p, pIORequest, dwBytesTransferred); + } + + // if no IOs were issued, wait for the next scheduling time + if (!nIssued && dwMinSleepTime != INFINITE && dwMinSleepTime != 0) + { + p->pResults->WaitStats.ThrottleSleep += 1; + Sleep(dwMinSleepTime); + } + + assert(!g_bError); // at this point we shouldn't be seeing initialization error + } + +cleanup: + return fOk; +} + +/*****************************************************************************/ +// function called from worker thread +// performs asynch I/O using IO Completion Ports +// +static bool doWorkUsingIOCompletionPorts(ThreadParameters *p, HANDLE hCompletionPort) +{ + assert(nullptr != p); + assert(nullptr != hCompletionPort); + + BOOL fOk = true; + BOOL rslt = FALSE; + DWORD dwBytesTransferred; + OverlappedQueue overlappedQueue; + size_t cIORequests = p->vIORequest.size(); + BOOL fLatencyStats = p->pTimeSpan->GetMeasureLatency() || p->pTimeSpan->GetCalculateIopsStdDev(); + + for (size_t i = 0; i < cIORequests; i++) + { + overlappedQueue.Add(p->vIORequest[i].GetOverlapped()); + } + + // + // perform work + // + DWORD dwMinSleepTime = INFINITE; + DWORD dwWaitTime; + + OVERLAPPED_ENTRY ovlEntry[16]; + const ULONG cOvlEntryMax = _countof(ovlEntry) < (ULONG)cIORequests ? _countof(ovlEntry) : (ULONG)cIORequests; + ULONG cCompleted; + size_t cUntilThrottle = cIORequests; + + while(g_bRun && !g_bThreadError) + { + OVERLAPPED *pReadyOverlapped = overlappedQueue.Remove(); + IORequest *pIORequest = IORequest::OverlappedToIORequest(pReadyOverlapped); + (void) pIORequest->GetNextTarget(); + + // check throttles + if (p->vThroughputMeters.size() != 0) + { + ThroughputMeter *pThroughputMeter = &p->vThroughputMeters[pIORequest->GetCurrentTargetIndex()]; + + cUntilThrottle -= 1; + + DWORD dwSleepTime = pThroughputMeter->GetSleepTime(); + if (pThroughputMeter->IsRunning() && dwSleepTime > 0) + { + dwMinSleepTime = min(dwMinSleepTime, dwSleepTime); + overlappedQueue.Add(pReadyOverlapped); + + // continue if throttle not hit + if (cUntilThrottle) + { + continue; + } + + // at throttle, no IO to dispatch + pIORequest = NULL; + } + } + + // dispatch IO - skipped iff at throttle + if (pIORequest) + { + rslt = issueNextIO(p, pIORequest, &dwBytesTransferred, false); + + if (!rslt && GetLastError() != ERROR_IO_PENDING) + { + UINT32 iIORequest = (UINT32)(pIORequest - &p->vIORequest[0]); + PrintError("t[%u] error during %s error code: %u)\n", iIORequest, (pIORequest->GetIoType()== IOOperation::ReadIO ? "read" : "write"), GetLastError()); + fOk = false; + goto cleanup; + } + + if (rslt && pIORequest->GetCurrentTarget()->GetMemoryMappedIoMode() == MemoryMappedIoMode::On) + { + completeIO(p, pIORequest, dwBytesTransferred); + overlappedQueue.Add(pReadyOverlapped); + + // a completed memory mapped IO resets the throttle so that we traverse + // back to it in fair-order before considering throttle again. + // note this will drop through to lookside for completions, not wait + dwMinSleepTime = INFINITE; + cUntilThrottle = overlappedQueue.GetCount(); + } + } + + // look for IO completion + // queue is fully dispatched: set wait, reset throttle wait + if (!overlappedQueue.GetCount()) + { + assert(!cUntilThrottle); + dwWaitTime = dwMinSleepTime = INFINITE; + p->pResults->WaitStats.Wait += 1; + } + + // queue is not fully dispatched ... + // if at the throttle, wait throttle time and reset + else if (!cUntilThrottle) + { + dwWaitTime = dwMinSleepTime; + dwMinSleepTime = INFINITE; + cUntilThrottle = overlappedQueue.GetCount(); + + if (cIORequests == cUntilThrottle) + { + // all throttled, none dispatched - just sleep + p->pResults->WaitStats.ThrottleSleep += 1; + Sleep(dwWaitTime); + continue; + } + else + { + // throttled, but some dispatched - wait for completions + p->pResults->WaitStats.ThrottleWait += 1; + } + } + + // queue is not fully dispatched ... + // if this run is not for latency stats, optimize for dispatch and + // skip completion lookasides + else if (!fLatencyStats) + { + continue; + } + + // else lookaside + else + { + dwWaitTime = 0; + p->pResults->WaitStats.Lookaside += 1; + } + + if (GetQueuedCompletionStatusEx(hCompletionPort, ovlEntry, cOvlEntryMax, &cCompleted, dwWaitTime, FALSE) != 0) + { + UINT64 ullCompletionTime = 0; + + if (fLatencyStats) + { + // single completion time estimate for all completions + ullCompletionTime = PerfTimer::GetTime(); + } + + for (ULONG i = 0; i < cCompleted; i++) + { + completeIOat(p, IORequest::OverlappedToIORequest(ovlEntry[i].lpOverlapped), ovlEntry[i].dwNumberOfBytesTransferred, ullCompletionTime); + overlappedQueue.Add(ovlEntry[i].lpOverlapped); + } + + // must reevaluate queue in fair order before next throttle + cUntilThrottle = overlappedQueue.GetCount(); + } + else + { + DWORD err = GetLastError(); + if (err != WAIT_TIMEOUT) + { + PrintError("error during overlapped IO operation (error code: %u)\n", err); + fOk = false; + goto cleanup; + } + } + + // stats for lookaside waits + if (dwWaitTime == 0) + { + p->pResults->WaitStats.LookasideCompletion[cCompleted < _countof(p->pResults->WaitStats.LookasideCompletion) ? cCompleted : _countof(p->pResults->WaitStats.LookasideCompletion) - 1] += 1; + } + } // end work loop + +cleanup: + return fOk; +} + +/*****************************************************************************/ +// I/O completion routine. used by ReadFileEx and WriteFileEx +// + +VOID CALLBACK fileIOCompletionRoutine(DWORD dwErrorCode, DWORD dwBytesTransferred, LPOVERLAPPED pOverlapped) +{ + assert(NULL != pOverlapped); + + BOOL rslt = FALSE; + ThreadParameters *p = (ThreadParameters *)pOverlapped->hEvent; + + assert(NULL != p); + + //check error code + if (0 != dwErrorCode) + { + PrintError("Thread %u failed executing an I/O operation (error code: %u)\n", p->ulThreadNo, dwErrorCode); + goto cleanup; + } + + IORequest *pIORequest = IORequest::OverlappedToIORequest(pOverlapped); + + completeIO(p, pIORequest, dwBytesTransferred); + + // start a new IO operation + if (g_bRun && !g_bThreadError) + { + (void) pIORequest->GetNextTarget(); + rslt = issueNextIO(p, pIORequest, NULL, true); + + if (!rslt) + { + PrintError("t[%u:%u] error during %s error code: %u)\n", p->ulThreadNo, pIORequest->GetCurrentTargetIndex(), (pIORequest->GetIoType() == IOOperation::ReadIO ? "read" : "write"), GetLastError()); + goto cleanup; + } + } + +cleanup: + return; +} + +/*****************************************************************************/ +// function called from worker thread +// performs asynch I/O using IO Completion Routines (ReadFileEx, WriteFileEx) +// +static bool doWorkUsingCompletionRoutines(ThreadParameters *p) +{ + assert(NULL != p); + bool fOk = true; + BOOL rslt = FALSE; + + // start IO operations + // completion routines will reissue 1:1 + UINT32 cIORequests = (UINT32)p->vIORequest.size(); + + for (size_t i = 0; i < cIORequests; i++) + { + IORequest *pIORequest = &p->vIORequest[i]; + + rslt = issueNextIO(p, pIORequest, NULL, true); + + if (!rslt) + { + PrintError("t[%u:%u] error during %s error code: %u)\n", p->ulThreadNo, pIORequest->GetCurrentTargetIndex(), (pIORequest->GetIoType() == IOOperation::ReadIO ? "read" : "write"), GetLastError()); + fOk = false; + goto cleanup; + } + } + + DWORD dwWaitResult = 0; + while( g_bRun && !g_bThreadError ) + { + dwWaitResult = WaitForSingleObjectEx(p->hEndEvent, INFINITE, TRUE); + + assert(WAIT_IO_COMPLETION == dwWaitResult || (WAIT_OBJECT_0 == dwWaitResult && (!g_bRun || g_bThreadError))); + + //check WaitForSingleObjectEx status + if( WAIT_IO_COMPLETION != dwWaitResult && WAIT_OBJECT_0 != dwWaitResult ) + { + PrintError("Error in thread %u during WaitForSingleObjectEx (in completion routines)\n", p->ulThreadNo); + fOk = false; + goto cleanup; + } + } +cleanup: + return fOk; +} + +struct UniqueTarget { + string path; + TargetCacheMode caching; + PRIORITY_HINT priority; + DWORD dwDesiredAccess; + DWORD dwFlags; + + bool operator < (const struct UniqueTarget &ut) const { + if (path < ut.path) { + return true; + } + else if (ut.path < path) { + return false; + } + + if (caching < ut.caching) { + return true; + } + else if (ut.caching < caching) { + return false; + } + + if (priority < ut.priority) { + return true; + } + else if (ut.priority < priority) { + return false; + } + + if (dwDesiredAccess < ut.dwDesiredAccess) { + return true; + } + else if (ut.dwDesiredAccess < dwDesiredAccess) { + return false; + } + + if (dwFlags < ut.dwFlags) { + return true; + } + + return false; + } +}; + +/*****************************************************************************/ +// worker thread function +// +DWORD WINAPI threadFunc(LPVOID cookie) +{ + bool fOk = true; + bool fAnyMappedIo = false; + bool fAllMappedIo = true; + ThreadParameters *p = reinterpret_cast(cookie); + HANDLE hCompletionPort = nullptr; + + // + // A single file can be specified in multiple targets, so only open one + // handle for each unique file. + // + + vector vhUniqueHandles; + map mHandleMap; + + bool fCalculateIopsStdDev = p->pTimeSpan->GetCalculateIopsStdDev(); + UINT64 ioBucketDuration = 0; + UINT32 expectedNumberOfBuckets = 0; + if(fCalculateIopsStdDev) + { + UINT32 ioBucketDurationInMilliseconds = p->pTimeSpan->GetIoBucketDurationInMilliseconds(); + ioBucketDuration = PerfTimer::MillisecondsToPerfTime(ioBucketDurationInMilliseconds); + expectedNumberOfBuckets = Util::QuotientCeiling(p->pTimeSpan->GetDuration() * 1000, ioBucketDurationInMilliseconds); + } + + // apply affinity. The specific assignment is provided in the thread profile up front. + if (!p->pTimeSpan->GetDisableAffinity()) + { + GROUP_AFFINITY GroupAffinity; + + PrintVerbose(p->pProfile->GetVerbose(), "thread %u: affinitizing to Group %u / CPU %u\n", p->ulThreadNo, p->wGroupNum, p->bProcNum); + SetProcGroupMask(p->wGroupNum, p->bProcNum, &GroupAffinity); + + HANDLE hThread = GetCurrentThread(); + if (SetThreadGroupAffinity(hThread, &GroupAffinity, nullptr) == FALSE) + { + PrintError("Error setting affinity mask in thread %u\n", p->ulThreadNo); + fOk = false; + goto cleanup; + } + } + + // adjust thread token if large pages are needed + for (auto pTarget = p->vTargets.begin(); pTarget != p->vTargets.end(); pTarget++) + { + if (pTarget->GetUseLargePages()) + { + if (!SetPrivilege(SE_LOCK_MEMORY_NAME)) + { + fOk = false; + goto cleanup; + } + break; + } + } + + UINT32 cIORequests = p->GetTotalRequestCount(); + + size_t iTarget = 0; + for (auto pTarget = p->vTargets.begin(); pTarget != p->vTargets.end(); pTarget++) + { + bool fPhysical = false; + bool fPartition = false; + + string sPath(pTarget->GetPath()); + const char *filename = sPath.c_str(); + + const char *fname = nullptr; //filename (can point to physFN) + char physFN[32]; //disk/partition name + + if (NULL == filename || NULL == *(filename)) + { + PrintError("FATAL ERROR: invalid filename\n"); + fOk = false; + goto cleanup; + } + + //check if it is a physical drive + if ('#' == *filename && NULL != *(filename + 1)) + { + if (pTarget->GetMemoryMappedIoMode() == MemoryMappedIoMode::On) + { + PrintError("Memory mapped I/O is not supported on physical drives\n"); + fOk = false; + goto cleanup; + } + UINT32 nDriveNo = (UINT32)atoi(filename + 1); + fPhysical = true; + sprintf_s(physFN, 32, "\\\\.\\PhysicalDrive%u", nDriveNo); + fname = physFN; + } + + //check if it is a partition + if (!fPhysical && NULL != *(filename + 1) && NULL == *(filename + 2) && isalpha((unsigned char)filename[0]) && ':' == filename[1]) + { + if (pTarget->GetMemoryMappedIoMode() == MemoryMappedIoMode::On) + { + PrintError("Memory mapped I/O is not supported on partitions\n"); + fOk = false; + goto cleanup; + } + fPartition = true; + + sprintf_s(physFN, 32, "\\\\.\\%c:", filename[0]); + fname = physFN; + } + + //check if it is a regular file + if (!fPhysical && !fPartition) + { + fname = sPath.c_str(); + } + + // get/set file flags + DWORD dwFlags = pTarget->GetCreateFlags(cIORequests > 1); + DWORD dwDesiredAccess = 0; + if (pTarget->GetWriteRatio() == 0) + { + dwDesiredAccess = GENERIC_READ; + } + else if (pTarget->GetWriteRatio() == 100) + { + dwDesiredAccess = GENERIC_WRITE; + } + else + { + dwDesiredAccess = GENERIC_READ | GENERIC_WRITE; + } + + if (pTarget->GetMemoryMappedIoMode() == MemoryMappedIoMode::On) + { + dwDesiredAccess = GENERIC_READ | GENERIC_WRITE; + fAnyMappedIo = true; + } + else + { + fAllMappedIo = false; + } + + HANDLE hFile; + UniqueTarget ut; + ut.path = sPath; + ut.priority = pTarget->GetIOPriorityHint(); + ut.caching = pTarget->GetCacheMode(); + ut.dwDesiredAccess = dwDesiredAccess; + ut.dwFlags = dwFlags; + + if (mHandleMap.find(ut) == mHandleMap.end()) { + hFile = CreateFile(fname, + dwDesiredAccess, + FILE_SHARE_READ | FILE_SHARE_WRITE, + nullptr, //security + OPEN_EXISTING, + dwFlags, //flags + nullptr); //template file + if (INVALID_HANDLE_VALUE == hFile) + { + // TODO: error out + PrintError("Error opening file: %s [%u]\n", sPath.c_str(), GetLastError()); + fOk = false; + goto cleanup; + } + + if (pTarget->GetCacheMode() == TargetCacheMode::DisableLocalCache) + { + DWORD Status = DisableLocalCache(hFile); + if (Status != ERROR_SUCCESS) + { + PrintError("Failed to disable local caching (error %u). NOTE: only supported on remote filesystems with Windows 8 or newer.\n", Status); + fOk = false; + goto cleanup; + } + } + + //set IO priority + if (pTarget->GetIOPriorityHint() != IoPriorityHintNormal) + { + _declspec(align(8)) FILE_IO_PRIORITY_HINT_INFO hintInfo; + hintInfo.PriorityHint = pTarget->GetIOPriorityHint(); + if (!SetFileInformationByHandle(hFile, FileIoPriorityHintInfo, &hintInfo, sizeof(hintInfo))) + { + PrintError("Error setting IO priority for file: %s [%u]\n", sPath.c_str(), GetLastError()); + fOk = false; + goto cleanup; + } + } + + mHandleMap[ut] = (UINT32)vhUniqueHandles.size(); + vhUniqueHandles.push_back(hFile); + } + else { + hFile = vhUniqueHandles[mHandleMap[ut]]; + } + + p->vhTargets.push_back(hFile); + + // obtain file/disk/partition size + { + UINT64 fsize = 0; //file size + + //check if it is a disk + if (fPhysical) + { + fsize = GetPhysicalDriveSize(hFile); + } + // check if it is a partition + else if (fPartition) + { + fsize = GetPartitionSize(hFile); + } + // it has to be a regular file + else + { + ULARGE_INTEGER ulsize; + + ulsize.LowPart = GetFileSize(hFile, &ulsize.HighPart); + if (INVALID_FILE_SIZE == ulsize.LowPart && GetLastError() != NO_ERROR) + { + PrintError("Error getting file size\n"); + fOk = false; + goto cleanup; + } + else + { + fsize = ulsize.QuadPart; + } + } + + // check if file size is valid (if it's == 0, it won't be useful) + if (0 == fsize) + { + // TODO: error out + PrintError("ERROR: target size could not be determined\n"); + fOk = false; + goto cleanup; + } + + if (fsize < pTarget->GetMaxFileSize()) + { + PrintError("WARNING: file size %I64u is less than MaxFileSize %I64u\n", fsize, pTarget->GetMaxFileSize()); + } + + // + // Build target state. + // + + p->vTargetStates.emplace_back( + p, + iTarget, + fsize); + + // + // Ensure this thread can start given stride/size of target. + // + + if (!p->vTargetStates[iTarget].CanStart()) + { + PrintError("The file is too small. File: '%s' relative thread %u: file size: %I64u, base offset: %I64u, thread stride: %I64u, block size: %u\n", + pTarget->GetPath().c_str(), + p->ulRelativeThreadNo, + fsize, + pTarget->GetBaseFileOffsetInBytes(), + pTarget->GetThreadStrideInBytes(), + pTarget->GetBlockSizeInBytes()); + fOk = false; + goto cleanup; + } + } + + PrintVerbose(p->pProfile->GetVerbose(), "thread %u: file '%s' relative thread %u (random seed: %u)\n", + p->ulThreadNo, + pTarget->GetPath().c_str(), + p->ulRelativeThreadNo, + p->ulRandSeed); + + if (pTarget->GetRandomRatio() > 0) + { + PrintVerbose(p->pProfile->GetVerbose(), "thread %u: %u%% random IO\n", + p->ulThreadNo, + pTarget->GetRandomRatio()); + } + else + { + PrintVerbose(p->pProfile->GetVerbose(), "thread %u: %ssequential IO\n", + p->ulThreadNo, + pTarget->GetUseInterlockedSequential() ? "interlocked ":""); + } + + // allocate memory for a data buffer + if (!p->AllocateAndFillBufferForTarget(*pTarget)) + { + PrintError("ERROR: Could not allocate a buffer for target '%s'. Error code: 0x%x\n", pTarget->GetPath().c_str(), GetLastError()); + fOk = false; + goto cleanup; + } + + // initialize memory mapped views of files + if (pTarget->GetMemoryMappedIoMode() == MemoryMappedIoMode::On) + { + NTSTATUS status; + PVOID nvToken; + + pTarget->SetMappedViewFileHandle(hFile); + if (!p->InitializeMappedViewForTarget(*pTarget, dwDesiredAccess)) + { + PrintError("ERROR: Could not map view for target '%s'. Error code: 0x%x\n", pTarget->GetPath().c_str(), GetLastError()); + fOk = false; + goto cleanup; + } + + if (pTarget->GetWriteThroughMode() == WriteThroughMode::On && nullptr == g_pfnRtlCopyMemoryNonTemporal) + { + PrintError("ERROR: Windows runtime environment does not support the non-temporal memory copy API for target '%s'.\n", pTarget->GetPath().c_str()); + fOk = false; + goto cleanup; + } + + if ((pTarget->GetMemoryMappedIoFlushMode() == MemoryMappedIoFlushMode::NonVolatileMemory) || (pTarget->GetMemoryMappedIoFlushMode() == MemoryMappedIoFlushMode::NonVolatileMemoryNoDrain)) + { + // RtlGetNonVolatileToken() works only on DAX enabled PMEM devices. + if (g_pfnRtlGetNonVolatileToken != nullptr && g_pfnRtlFreeNonVolatileToken != nullptr) + { + status = g_pfnRtlGetNonVolatileToken(pTarget->GetMappedView(), (SIZE_T) pTarget->GetFileSize(), &nvToken); + if (!NT_SUCCESS(status)) + { + PrintError("ERROR: Could not get non-volatile token for target '%s'. Error code: 0x%x\n", pTarget->GetPath().c_str(), GetLastError()); + fOk = false; + goto cleanup; + } + pTarget->SetMemoryMappedIoNvToken(nvToken); + } + else + { + PrintError("ERROR: Windows runtime environment does not support the non-volatile memory flushing APIs for target '%s'.\n", pTarget->GetPath().c_str()); + fOk = false; + goto cleanup; + } + } + } + + iTarget++; + } + + // TODO: copy parameters for better memory locality? + // TODO: tell the main thread we're ready + + p->pResults->vTargetResults.clear(); + p->pResults->vTargetResults.resize(p->vTargets.size()); + + for (size_t i = 0; i < p->vTargets.size(); i++) + { + p->pResults->vTargetResults[i].sPath = p->vTargets[i].GetPath(); + p->pResults->vTargetResults[i].ullFileSize = p->vTargetStates[i].TargetSize(); + + if(fCalculateIopsStdDev) + { + p->pResults->vTargetResults[i].readBucketizer.Initialize(ioBucketDuration, expectedNumberOfBuckets); + p->pResults->vTargetResults[i].writeBucketizer.Initialize(ioBucketDuration, expectedNumberOfBuckets); + } + + // + // Copy effective distribution range to results for reporting (may be empty) + // + + p->pResults->vTargetResults[i].vDistributionRange = p->vTargetStates[i]._vDistributionRange; + } + + // + // fill the IORequest structures + // + + p->vIORequest.clear(); + + if (p->pTimeSpan->GetThreadCount() != 0 && + p->pTimeSpan->GetRequestCount() != 0) + { + p->vIORequest.resize(cIORequests, IORequest(p->pRand)); + + for (UINT32 iIORequest = 0; iIORequest < cIORequests; iIORequest++) + { + p->vIORequest[iIORequest].SetRequestIndex(iIORequest); + + for (unsigned int iFile = 0; iFile < p->vTargets.size(); iFile++) + { + Target *pTarget = &p->vTargets[iFile]; + const vector vThreadTargets = pTarget->GetThreadTargets(); + UINT32 ulWeight = pTarget->GetWeight(); + + for (UINT32 iThreadTarget = 0; iThreadTarget < vThreadTargets.size(); iThreadTarget++) + { + if (vThreadTargets[iThreadTarget].GetThread() == p->ulRelativeThreadNo) + { + if (vThreadTargets[iThreadTarget].GetWeight() != 0) + { + ulWeight = vThreadTargets[iThreadTarget].GetWeight(); + } + break; + } + } + + // + // Parallel async is not supported with -O for exactly this reason, + // and is validated in the profile before reaching here. Document this + // with the assert in comparison to the code in the non-O case below. + // Parallel depends on the IORequest being for a single file only (the + // seq offset is in the IORequest itself). + // + + assert(pTarget->GetUseParallelAsyncIO() == false); + + p->vIORequest[iIORequest].AddTarget(pTarget, ulWeight); + } + } + } + else + { + for (unsigned int iFile = 0; iFile < p->vTargets.size(); iFile++) + { + Target *pTarget = &p->vTargets[iFile]; + + for (DWORD iRequest = 0; iRequest < pTarget->GetRequestCount(); ++iRequest) + { + IORequest ioRequest(p->pRand); + ioRequest.AddTarget(pTarget, 1); + ioRequest.SetRequestIndex(iRequest); + if (pTarget->GetUseParallelAsyncIO()) + { + p->vTargetStates[iFile].InitializeParallelAsyncIORequest(ioRequest); + } + + p->vIORequest.push_back(ioRequest); + } + } + } + + // + // fill the throughput meter structures + // + size_t cTargets = p->vTargets.size(); + bool fUseThrougputMeter = false; + for (size_t i = 0; i < cTargets; i++) + { + ThroughputMeter throughputMeter; + Target *pTarget = &p->vTargets[i]; + DWORD dwBurstSize = pTarget->GetBurstSize(); + if (p->pTimeSpan->GetThreadCount() > 0) + { + if (pTarget->GetThreadTargets().size() == 0) + { + dwBurstSize /= p->pTimeSpan->GetThreadCount(); + } + else + { + dwBurstSize /= (DWORD)pTarget->GetThreadTargets().size(); + } + } + else + { + dwBurstSize /= pTarget->GetThreadsPerFile(); + } + + if (pTarget->GetThroughputInBytesPerMillisecond() > 0 || pTarget->GetThinkTime() > 0) + { + fUseThrougputMeter = true; + throughputMeter.Start(pTarget->GetThroughputInBytesPerMillisecond(), pTarget->GetBlockSizeInBytes(), pTarget->GetThinkTime(), dwBurstSize); + } + + p->vThroughputMeters.push_back(throughputMeter); + } + + if (!fUseThrougputMeter) + { + p->vThroughputMeters.clear(); + } + + //FUTURE EXTENSION: enable asynchronous I/O even if only 1 outstanding I/O per file (requires another parameter) + if (cIORequests == 1 || fAllMappedIo) + { + //synchronous IO - no setup needed + } + else if (p->pTimeSpan->GetCompletionRoutines() && !fAnyMappedIo) + { + //in case of completion routines hEvent field is not used, + //so we can use it to pass a pointer to the thread parameters + for (UINT32 iIORequest = 0; iIORequest < cIORequests; iIORequest++) { + OVERLAPPED *pOverlapped; + + pOverlapped = p->vIORequest[iIORequest].GetOverlapped(); + pOverlapped->hEvent = (HANDLE)p; + } + } + else + { + // + // create IO completion port if not doing completion routines or synchronous IO + // + for (unsigned int i = 0; i < vhUniqueHandles.size(); i++) + { + hCompletionPort = CreateIoCompletionPort(vhUniqueHandles[i], hCompletionPort, 0, 1); + if (nullptr == hCompletionPort) + { + PrintError("unable to create IO completion port (error code: %u)\n", GetLastError()); + fOk = false; + goto cleanup; + } + } + } + + // + // wait for a signal to start + // + PrintVerbose(p->pProfile->GetVerbose(), "thread %u: waiting for a signal to start\n", p->ulThreadNo); + if( WAIT_FAILED == WaitForSingleObject(p->hStartEvent, INFINITE) ) + { + PrintError("Waiting for a signal to start failed (error code: %u)\n", GetLastError()); + fOk = false; + goto cleanup; + } + PrintVerbose(p->pProfile->GetVerbose(), "thread %u: received signal to start\n", p->ulThreadNo); + + //check if everything is ok + if (g_bError) + { + fOk = false; + goto cleanup; + } + + //error handling and memory freeing is done in doWorkUsingIOCompletionPorts and doWorkUsingCompletionRoutines + if (cIORequests == 1 || fAllMappedIo) + { + // use synchronous IO (it will also clse the event) + if (!doWorkUsingSynchronousIO(p)) + { + fOk = false; + goto cleanup; + } + } + else if (!p->pTimeSpan->GetCompletionRoutines() || fAnyMappedIo) + { + // use IO Completion Ports (it will also close the I/O completion port) + if (!doWorkUsingIOCompletionPorts(p, hCompletionPort)) + { + fOk = false; + goto cleanup; + } + } + else + { + //use completion routines + if (!doWorkUsingCompletionRoutines(p)) + { + fOk = false; + goto cleanup; + } + } + + assert(!g_bError); // at this point we shouldn't be seeing initialization error + + // save results + +cleanup: + if (!fOk) + { + g_bThreadError = TRUE; + } + + // free memory allocated with VirtualAlloc + for (auto i = p->vpDataBuffers.begin(); i != p->vpDataBuffers.end(); i++) + { + if (nullptr != *i) + { +#pragma prefast(suppress:6001, "Prefast does not understand this vector will only contain validly allocated buffer pointers") + VirtualFree(*i, 0, MEM_RELEASE); + } + } + + // free NV tokens + for (auto i = p->vTargets.begin(); i != p->vTargets.end(); i++) + { + if (i->GetMemoryMappedIoNvToken() != nullptr && g_pfnRtlFreeNonVolatileToken != nullptr) + { + g_pfnRtlFreeNonVolatileToken(i->GetMemoryMappedIoNvToken()); + i->SetMemoryMappedIoNvToken(nullptr); + } + } + + // close files + for (auto i = vhUniqueHandles.begin(); i != vhUniqueHandles.end(); i++) + { + CloseHandle(*i); + } + + // close completion ports + if (hCompletionPort != nullptr) + { + CloseHandle(hCompletionPort); + } + + delete p->pRand; + delete p; + + // notify master thread that we've finished + InterlockedDecrement(&g_lRunningThreadsCount); + + return fOk ? 1 : 0; +} + +/*****************************************************************************/ +struct ETWSessionInfo IORequestGenerator::_GetResultETWSession(const EVENT_TRACE_PROPERTIES *pTraceProperties) const +{ + struct ETWSessionInfo session = {}; + if (nullptr != pTraceProperties) + { + session.lAgeLimit = pTraceProperties->AgeLimit; + session.ulBufferSize = pTraceProperties->BufferSize; + session.ulBuffersWritten = pTraceProperties->BuffersWritten; + session.ulEventsLost = pTraceProperties->EventsLost; + session.ulFlushTimer = pTraceProperties->FlushTimer; + session.ulFreeBuffers = pTraceProperties->FreeBuffers; + session.ulLogBuffersLost = pTraceProperties->LogBuffersLost; + session.ulMaximumBuffers = pTraceProperties->MaximumBuffers; + session.ulMinimumBuffers = pTraceProperties->MinimumBuffers; + session.ulNumberOfBuffers = pTraceProperties->NumberOfBuffers; + session.ulRealTimeBuffersLost = pTraceProperties->RealTimeBuffersLost; + } + return session; +} + +DWORD IORequestGenerator::_CreateDirectoryPath(const char *pszPath) const +{ + char *c = nullptr; //variable used to browse the path + char dirPath[MAX_PATH]; //copy of the path (it will be altered) + + //only support absolute paths that specify the drive letter + if (pszPath[0] == '\0' || pszPath[1] != ':') + { + return ERROR_NOT_SUPPORTED; + } + + if (strcpy_s(dirPath, _countof(dirPath), pszPath) != 0) + { + return ERROR_BUFFER_OVERFLOW; + } + + c = dirPath; + while('\0' != *c) + { + if ('\\' == *c) + { + //skip the first one as it will be the drive name + if (c-dirPath >= 3) + { + *c = '\0'; + //create directory if it doesn't exist + if (GetFileAttributes(dirPath) == INVALID_FILE_ATTRIBUTES) + { + if (CreateDirectory(dirPath, NULL) == FALSE) + { + return GetLastError(); + } + } + *c = L'\\'; + } + } + + c++; + } + + return ERROR_SUCCESS; +} + +/*****************************************************************************/ +// create a file of the given size +// +bool IORequestGenerator::_CreateFile(UINT64 ullFileSize, const char *pszFilename, bool fZeroBuffers, bool fVerbose) const +{ + bool fSlowWrites = false; + PrintVerbose(fVerbose, "Creating file '%s' of size %I64u.\n", pszFilename, ullFileSize); + + //enable SE_MANAGE_VOLUME_NAME privilege, required to set valid size of a file + if (!SetPrivilege(SE_MANAGE_VOLUME_NAME, "WARNING:")) + { + PrintError("WARNING: Could not set privileges for setting valid file size; will use a slower method of preparing the file\n", GetLastError()); + fSlowWrites = true; + } + + // there are various forms of paths we do not support creating subdir hierarchies + // for - relative and unc paths specifically. this is fine, and not neccesary to + // warn about. we can add support in the future. + DWORD dwError = _CreateDirectoryPath(pszFilename); + if (dwError != ERROR_SUCCESS && dwError != ERROR_NOT_SUPPORTED) + { + PrintError("WARNING: Could not create intermediate directory (error code: %u)\n", dwError); + } + + // create handle to the file + HANDLE hFile = CreateFile(pszFilename, + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + nullptr, + CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, + nullptr); + if (INVALID_HANDLE_VALUE == hFile) + { + PrintError("Could not create the file (error code: %u)\n", GetLastError()); + return false; + } + + if (ullFileSize > 0) + { + LARGE_INTEGER li; + li.QuadPart = ullFileSize; + + LARGE_INTEGER liNewFilePointer; + + if (!SetFilePointerEx(hFile, li, &liNewFilePointer, FILE_BEGIN)) + { + PrintError("Could not set file pointer during file creation when extending file (error code: %u)\n", GetLastError()); + CloseHandle(hFile); + return false; + } + if (liNewFilePointer.QuadPart != li.QuadPart) + { + PrintError("File pointer improperly moved during file creation when extending file\n"); + CloseHandle(hFile); + return false; + } + + //extends file (warning! this is a kind of "reservation" of space; valid size of the file is still 0!) + if (!SetEndOfFile(hFile)) + { + PrintError("Error setting end of file (error code: %u)\n", GetLastError()); + CloseHandle(hFile); + return false; + } + //try setting valid size of the file (privileges for that are enabled before CreateFile) + if (!fSlowWrites && !SetFileValidData(hFile, ullFileSize)) + { + PrintError("WARNING: Could not set valid file size (error code: %u); trying a slower method of filling the file" + " (this does not affect performance, just makes the test preparation longer)\n", + GetLastError()); + fSlowWrites = true; + } + + //if setting valid size couldn't be performed, fill in the file by simply writing to it (slower) + if (fSlowWrites) + { + li.QuadPart = 0; + if (!SetFilePointerEx(hFile, li, &liNewFilePointer, FILE_BEGIN)) + { + PrintError("Could not set file pointer during file creation (error code: %u)\n", GetLastError()); + CloseHandle(hFile); + return false; + } + if (liNewFilePointer.QuadPart != li.QuadPart) + { + PrintError("File pointer improperly moved during file creation\n"); + CloseHandle(hFile); + return false; + } + + UINT32 ulBufSize; + UINT64 ullRemainSize; + + ulBufSize = 1024*1024; + if (ullFileSize < (UINT64)ulBufSize) + { + ulBufSize = (UINT32)ullFileSize; + } + + vector vBuf(ulBufSize); + for (UINT32 i=0; i 0) + { + DWORD dwBytesWritten; + if ((UINT64)ulBufSize > ullRemainSize) + { + ulBufSize = (UINT32)ullRemainSize; + } + + if (!WriteFile(hFile, &vBuf[0], ulBufSize, &dwBytesWritten, NULL)) + { + PrintError("Error while writng during file creation (error code: %u)\n", GetLastError()); + CloseHandle(hFile); + return false; + } + + if (dwBytesWritten != ulBufSize) + { + PrintError("Improperly written data during file creation\n"); + CloseHandle(hFile); + return false; + } + + ullRemainSize -= ulBufSize; + } + } + } + + //if compiled with debug support, check file size +#ifndef NDEBUG + LARGE_INTEGER li; + if( GetFileSizeEx(hFile, &li) ) + { + assert(li.QuadPart == (LONGLONG)ullFileSize); + } +#endif + + CloseHandle(hFile); + + return true; +} + +/*****************************************************************************/ +void IORequestGenerator::_TerminateWorkerThreads(vector& vhThreads) const +{ + for (UINT32 x = 0; x < vhThreads.size(); ++x) + { + assert(NULL != vhThreads[x]); +#pragma warning( push ) +#pragma warning( disable : 6258 ) + if (!TerminateThread(vhThreads[x], 0)) + { + PrintError("Warning: unable to terminate worker thread %u\n", x); + } +#pragma warning( pop ) + } +} +/*****************************************************************************/ +void IORequestGenerator::_AbortWorkerThreads(HANDLE hStartEvent, vector& vhThreads) const +{ + assert(NULL != hStartEvent); + + if (NULL == hStartEvent) + { + return; + } + + g_bError = TRUE; + if (!SetEvent(hStartEvent)) + { + PrintError("Error signaling start event\n"); + _TerminateWorkerThreads(vhThreads); + } + else + { + //FUTURE EXTENSION: maximal timeout may be added here (and below) + while (g_lRunningThreadsCount > 0) + { + Sleep(100); + } + } +} + +/*****************************************************************************/ +bool IORequestGenerator::_StopETW(bool fUseETW, TRACEHANDLE hTraceSession) const +{ + bool fOk = true; + if (fUseETW) + { + PEVENT_TRACE_PROPERTIES pETWSession = StopETWSession(hTraceSession); + if (nullptr == pETWSession) + { + PrintError("Error stopping ETW session\n"); + fOk = false; + } + else + { + free(pETWSession); + } + } + return fOk; +} + +/*****************************************************************************/ +// initializes all global parameters +// +void IORequestGenerator::_InitializeGlobalParameters() +{ + g_lRunningThreadsCount = 0; //number of currently running worker threads + g_bRun = TRUE; //used for letting threads know that they should stop working + + g_bThreadError = FALSE; //true means that an error has occured in one of the threads + g_bTracing = FALSE; //true means that ETW is turned on + + _hNTDLL = nullptr; //handle to ntdll.dll + g_bError = FALSE; //true means there was fatal error during intialization and threads shouldn't perform their work +} + +bool IORequestGenerator::_PrecreateFiles(Profile& profile) const +{ + bool fOk = true; + + if (profile.GetPrecreateFiles() != PrecreateFiles::None) + { + vector vFilesToCreate = _GetFilesToPrecreate(profile); + vector vCreatedFiles; + for (auto file : vFilesToCreate) + { + fOk = _CreateFile(file.ullFileSize, file.sPath.c_str(), file.fZeroWriteBuffers, profile.GetVerbose()); + if (!fOk) + { + break; + } + vCreatedFiles.push_back(file.sPath); + } + + if (fOk) + { + profile.MarkFilesAsPrecreated(vCreatedFiles); + } + } + + return fOk; +} + +// bool IORequestGenerator::GenerateRequests(Profile& profile, IResultParser& resultParser, struct Synchronization *pSynch) +/// for CrystalDiskMark +bool IORequestGenerator::GenerateRequests(Profile& profile, IResultParser& resultParser, struct Synchronization *pSynch, int* totalScore, double* averageLatency) +{ + bool fOk = _PrecreateFiles(profile); + if (fOk) + { + const vector& vTimeSpans = profile.GetTimeSpans(); + vector vResults(vTimeSpans.size()); + for (size_t i = 0; fOk && (i < vTimeSpans.size()); i++) + { + PrintVerbose(profile.GetVerbose(), "Generating requests for timespan %u.\n", i + 1); + fOk = _GenerateRequestsForTimeSpan(profile, vTimeSpans[i], vResults[i], pSynch); + } + + // TODO: show results only for timespans that succeeded + SystemInformation system; + EtwResultParser::ParseResults(vResults); + string sResults = resultParser.ParseResults(profile, system, vResults); + printf("%s", sResults.c_str()); + fflush(stdout); + + /// for CrystalDiskMark + *totalScore = resultParser.GetTotalScore() * 10; + *averageLatency = resultParser.GetAverageLatency(); + } + + return fOk; +} + +bool IORequestGenerator::_GenerateRequestsForTimeSpan(const Profile& profile, const TimeSpan& timeSpan, Results& results, struct Synchronization *pSynch) +{ + //FUTURE EXTENSION: add new I/O capabilities presented in Longhorn + //FUTURE EXTENSION: add a check if the folder is compressed (cache is always enabled in case of compressed folders) + + //check if I/O request generator is already running + LONG lGenState = InterlockedExchange(&g_lGeneratorRunning, 1); + if (1 == lGenState) + { + PrintError("FATAL ERROR: I/O Request Generator already running\n"); + return false; + } + + //initialize all global parameters (in case of second run, after the first one is finished) + _InitializeGlobalParameters(); + + HANDLE hStartEvent = nullptr; // start event (used to inform the worker threads that they should start the work) + HANDLE hEndEvent = nullptr; // end event (used only in case of completin routines (not for IO Completion Ports)) + + memset(&g_EtwEventCounters, 0, sizeof(struct ETWEventCounters)); // reset all etw event counters + + bool fUseETW = profile.GetEtwEnabled(); //true if user wants ETW + + // + // load dlls + // + assert(nullptr == _hNTDLL); + if (!_LoadDLLs()) + { + PrintError("Error loading NtQuerySystemInformation\n"); + return false; + } + + //FUTURE EXTENSION: check for conflicts in alignment (when cache is turned off only sector aligned I/O are permitted) + //FUTURE EXTENSION: check if file sizes are enough to have at least first requests not wrapping around + + Random r; + vector vTargets = timeSpan.GetTargets(); + // allocate memory for random data write buffers + for (auto i = vTargets.begin(); i != vTargets.end(); i++) + { + if ((i->GetRandomDataWriteBufferSize() > 0) && !i->AllocateAndFillRandomDataWriteBuffer(&r)) + { + return false; + } + } + + // check if user wanted to create a file + for (auto i = vTargets.begin(); i != vTargets.end(); i++) + { + if ((i->GetFileSize() > 0) && (i->GetPrecreated() == false)) + { + string str = i->GetPath(); + if (str.empty()) + { + PrintError("You have to provide a filename\n"); + return false; + } + + //skip physical drives and partitions + if ('#' == str[0] || (':' == str[1] && '\0' == str[2])) + { + continue; + } + + //create only regular files + if (!_CreateFile(i->GetFileSize(), str.c_str(), i->GetZeroWriteBuffers(), profile.GetVerbose())) + { + return false; + } + } + } + + // get thread count + UINT32 cThreads = timeSpan.GetThreadCount(); + if (cThreads < 1) + { + for (auto i = vTargets.begin(); i != vTargets.end(); i++) + { + cThreads += i->GetThreadsPerFile(); + } + } + + // allocate memory for thread handles + vector vhThreads(cThreads); + + // + // allocate memory for performance counters + // + vector vPerfInit(g_SystemInformation.processorTopology._ulProcessorCount); + vector vPerfDone(g_SystemInformation.processorTopology._ulProcessorCount); + vector vPerfDiff(g_SystemInformation.processorTopology._ulProcessorCount); + + // + // create start event + // + hStartEvent = CreateEvent(NULL, TRUE, FALSE, ""); + if (NULL == hStartEvent) + { + PrintError("Error creating the start event\n"); + return false; + } + + // + // create end event + // + if (timeSpan.GetCompletionRoutines()) + { + hEndEvent = CreateEvent(NULL, TRUE, FALSE, ""); + if (NULL == hEndEvent) + { + PrintError("Error creating the end event\n"); + return false; + } + } + + // + // set to high priority to ensure the controller thread gets to run immediately + // when signalled. + // + + SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST); + + // + // create the threads + // + + g_bRun = TRUE; + + // gather affinity information, and move to the first active processor + const auto& vAffinity = timeSpan.GetAffinityAssignments(); + WORD wGroupCtr = 0; + BYTE bProcCtr = 0; + g_SystemInformation.processorTopology.GetActiveGroupProcessor(wGroupCtr, bProcCtr, false); + + volatile bool fAccountingOn = false; + UINT64 ullStartTime; //start time + UINT64 ullTimeDiff; //elapsed test time (in units returned by QueryPerformanceCounter) + vector vullSharedSequentialOffsets(vTargets.size(), 0); + + results.vThreadResults.clear(); + results.vThreadResults.resize(cThreads); + for (UINT32 iThread = 0; iThread < cThreads; ++iThread) + { + PrintVerbose(profile.GetVerbose(), "creating thread %u\n", iThread); + ThreadParameters *cookie = new ThreadParameters(); // threadFunc is going to free the memory + if (nullptr == cookie) + { + PrintError("FATAL ERROR: could not allocate memory\n"); + _AbortWorkerThreads(hStartEvent, vhThreads); + return false; + } + + // each thread has a different random seed + Random *pRand = new Random(timeSpan.GetRandSeed() + iThread); + if (nullptr == pRand) + { + PrintError("FATAL ERROR: could not allocate memory\n"); + _AbortWorkerThreads(hStartEvent, vhThreads); + delete cookie; + return false; + } + + UINT32 ulRelativeThreadNo = 0; + + if (timeSpan.GetThreadCount() > 0) + { + // fixed thread mode: threads operate on specified files + // and receive the entire seq index array. + // relative thread number is the same as thread number. + cookie->pullSharedSequentialOffsets = &vullSharedSequentialOffsets[0]; + ulRelativeThreadNo = iThread; + for (auto i = vTargets.begin(); + i != vTargets.end(); + i++) + { + const vector vThreadTargets = i->GetThreadTargets(); + + // no thread targets specified - add to all threads + if (vThreadTargets.size() == 0) + { + cookie->vTargets.push_back(*i); + } + else + { + // check if the target should be added to the current thread + for (UINT32 iThreadTarget = 0; iThreadTarget < vThreadTargets.size(); iThreadTarget++) + { + if (vThreadTargets[iThreadTarget].GetThread() == iThread) + { + // confirm copy constructor? + cookie->vTargets.push_back(*i); + break; + } + } + } + } + } + else + { + size_t cAssignedThreads = 0; + size_t cBaseThread = 0; + auto psi = vullSharedSequentialOffsets.begin(); + for (auto i = vTargets.begin(); + i != vTargets.end(); + i++, psi++) + { + // per-file thread mode: groups of threads operate on individual files + // and receive the specific seq index for their file (note: singular). + // loop up through the targets to assign thread n to the appropriate file. + // relative thread number is file-relative, so keep track of the base + // thread number for the file and calculate relative to that. + // + // ex: two files, two threads per file + // t0: rt0 for f0 (cAssigned = 2, cBase = 0) + // t1: rt1 for f0 (cAssigned = 2, cBase = 0) + // t2: rt0 for f1 (cAssigned = 4, cBase = 2) + // t3: rt1 for f1 (cAssigned = 4, cBase = 2) + + cAssignedThreads += i->GetThreadsPerFile(); + if (iThread < cAssignedThreads) + { + // confirm copy constructor? + cookie->vTargets.push_back(*i); + cookie->pullSharedSequentialOffsets = &(*psi); + ulRelativeThreadNo = (iThread - cBaseThread) % i->GetThreadsPerFile(); + + PrintVerbose(profile.GetVerbose(), "thread %u is relative thread %u for %s\n", iThread, ulRelativeThreadNo, i->GetPath().c_str()); + break; + } + cBaseThread += i->GetThreadsPerFile(); + } + } + + cookie->pProfile = &profile; + cookie->pTimeSpan = &timeSpan; + cookie->hStartEvent = hStartEvent; + cookie->hEndEvent = hEndEvent; + cookie->ulThreadNo = iThread; + cookie->ulRelativeThreadNo = ulRelativeThreadNo; + cookie->pfAccountingOn = &fAccountingOn; + cookie->pullStartTime = &ullStartTime; + cookie->ulRandSeed = timeSpan.GetRandSeed() + iThread; // each thread has a different random seed + cookie->pRand = pRand; + + //Set thread group and proc affinity + + // Default: Round robin cpus in order of groups, starting at group 0. + // Fill each group before moving to next. + if (vAffinity.size() == 0) + { + cookie->wGroupNum = wGroupCtr; + cookie->bProcNum = bProcCtr; + + // advance to next active + g_SystemInformation.processorTopology.GetActiveGroupProcessor(wGroupCtr, bProcCtr, true); + } + // Assigned affinity. Round robin through the assignment list. + else + { + ULONG i = iThread % vAffinity.size(); + + cookie->wGroupNum = vAffinity[i].wGroup; + cookie->bProcNum = vAffinity[i].bProc; + } + + //create thread + cookie->pResults = &results.vThreadResults[iThread]; + + InterlockedIncrement(&g_lRunningThreadsCount); + DWORD dwThreadId; + HANDLE hThread = CreateThread(NULL, 64 * 1024, threadFunc, cookie, 0, &dwThreadId); + if (NULL == hThread) + { + //in case of error terminate running worker threads + PrintError("ERROR: unable to create thread (error code: %u)\n", GetLastError()); + InterlockedDecrement(&g_lRunningThreadsCount); + _AbortWorkerThreads(hStartEvent, vhThreads); + delete pRand; + delete cookie; + return false; + } + + //store handle to the thread + vhThreads[iThread] = hThread; + } + + if (STRUCT_SYNCHRONIZATION_SUPPORTS(pSynch, hStartEvent) && (NULL != pSynch->hStartEvent)) + { + if (WAIT_OBJECT_0 != WaitForSingleObject(pSynch->hStartEvent, INFINITE)) + { + PrintError("Error during WaitForSingleObject\n"); + _AbortWorkerThreads(hStartEvent, vhThreads); + return false; + } + } + + // + // get cycle count (it will be used to calculate actual work time) + // + DWORD dwWaitStatus = 0; + + //bAccountingOn = FALSE; // clear the accouning flag so that threads didn't count what they do while in the warmup phase + + BOOL bSynchStop = STRUCT_SYNCHRONIZATION_SUPPORTS(pSynch, hStopEvent) && (NULL != pSynch->hStopEvent); + BOOL bBreak = FALSE; + PEVENT_TRACE_PROPERTIES pETWSession = NULL; + + // + // send start signal + // + if (!SetEvent(hStartEvent)) + { + PrintError("Error signaling start event\n"); + // stopETW(bUseETW, hTraceSession); + _TerminateWorkerThreads(vhThreads); //FUTURE EXTENSION: timeout for worker threads + return false; + } + + // + // wait specified amount of time in each phase (warm up, test, cool down) + // + if (timeSpan.GetWarmup() > 0) + { + TraceLoggingActivity WarmActivity; + TraceLoggingWriteStart(WarmActivity, "Warm Up"); + PrintVerbose(profile.GetVerbose(), "starting warm up for %us...\n", timeSpan.GetWarmup()); + + if (bSynchStop) + { + assert(NULL != pSynch->hStopEvent); + dwWaitStatus = WaitForSingleObject(pSynch->hStopEvent, 1000 * timeSpan.GetWarmup()); + if (WAIT_OBJECT_0 != dwWaitStatus && WAIT_TIMEOUT != dwWaitStatus) + { + PrintError("Error during WaitForSingleObject\n"); + _TerminateWorkerThreads(vhThreads); + return false; + } + bBreak = (WAIT_TIMEOUT != dwWaitStatus); + } + else + { + Sleep(1000 * timeSpan.GetWarmup()); + } + + TraceLoggingWriteStop(WarmActivity, "Warm Up"); + } + + if (!bBreak) // proceed only if user didn't break the test + { + //FUTURE EXTENSION: starting ETW session shouldn't be done brutally here, should be done before warmup and here just a fast signal to start logging (see also stopping ETW session) + //FUTURE EXTENSION: put an ETW mark here, for easier parsing by external tools + + // + // start etw session + // + TRACEHANDLE hTraceSession = NULL; + if (fUseETW) + { + PrintVerbose(profile.GetVerbose(), "starting trace session\n"); + hTraceSession = StartETWSession(profile); + if (NULL == hTraceSession) + { + PrintError("Could not start ETW session\n"); + _TerminateWorkerThreads(vhThreads); + return false; + } + + if (NULL == CreateThread(NULL, 64 * 1024, etwThreadFunc, NULL, 0, NULL)) + { + PrintError("Warning: unable to create thread for ETW session\n"); + _TerminateWorkerThreads(vhThreads); + return false; + } + PrintVerbose(profile.GetVerbose(), "tracing events\n"); + } + + // + // notify the front-end that the test is about to start; + // do it before starting timing in order not to perturb measurements + // + if (STRUCT_SYNCHRONIZATION_SUPPORTS(pSynch, pfnCallbackTestStarted) && (NULL != pSynch->pfnCallbackTestStarted)) + { + pSynch->pfnCallbackTestStarted(); + } + + // + // read performance counters + // + if (_GetSystemPerfInfo(vPerfInit, profile.GetVerbose()) == FALSE) + { + PrintError("Error reading performance counters\n"); + _StopETW(fUseETW, hTraceSession); + _TerminateWorkerThreads(vhThreads); + return false; + } + + TraceLoggingActivity RunActivity; + TraceLoggingWriteStart(RunActivity, "Run Time"); + + PrintVerbose(profile.GetVerbose(), "starting measurements for %us...\n", timeSpan.GetDuration()); + + //get cycle count (it will be used to calculate actual work time) + ullStartTime = PerfTimer::GetTime(); + fAccountingOn = true; + + assert(timeSpan.GetDuration() > 0); + if (bSynchStop) + { + assert(NULL != pSynch->hStopEvent); + dwWaitStatus = WaitForSingleObject(pSynch->hStopEvent, 1000 * timeSpan.GetDuration()); + if (WAIT_OBJECT_0 != dwWaitStatus && WAIT_TIMEOUT != dwWaitStatus) + { + PrintError("Error during WaitForSingleObject\n"); + _StopETW(fUseETW, hTraceSession); + _TerminateWorkerThreads(vhThreads); //FUTURE EXTENSION: worker threads should have a chance to free allocated memory (see also other places calling terminateWorkerThreads()) + return FALSE; + } + bBreak = (WAIT_TIMEOUT != dwWaitStatus); + } + else + { + Sleep(1000 * timeSpan.GetDuration()); + } + + //get cycle count and perf counters + fAccountingOn = false; + ullTimeDiff = PerfTimer::GetTime() - ullStartTime; + PrintVerbose(profile.GetVerbose(), "stopped measurements, total measured time %.2lfs...\n", PerfTimer::PerfTimeToSeconds(ullTimeDiff)); + + TraceLoggingWriteStop(RunActivity, "Run Time"); + + if (_GetSystemPerfInfo(vPerfDone, profile.GetVerbose()) == FALSE) + { + PrintError("Error getting performance counters\n"); + _StopETW(fUseETW, hTraceSession); + _TerminateWorkerThreads(vhThreads); + return false; + } + + // + // notify the front-end that the test has just finished; + // do it after stopping timing in order not to perturb measurements + // + if (STRUCT_SYNCHRONIZATION_SUPPORTS(pSynch, pfnCallbackTestFinished) && (NULL != pSynch->pfnCallbackTestFinished)) + { + pSynch->pfnCallbackTestFinished(); + } + + // + // stop etw session + // + if (fUseETW) + { + PrintVerbose(profile.GetVerbose(), "stopping ETW session\n"); + pETWSession = StopETWSession(hTraceSession); + if (NULL == pETWSession) + { + PrintError("Error stopping ETW session\n"); + return false; + } + } + } + else + { + ullTimeDiff = 0; // mark that no test was run + } + + if ((timeSpan.GetCooldown() > 0) && !bBreak) + { + TraceLoggingActivity CoolActivity; + TraceLoggingWriteStart(CoolActivity, "Cool Down"); + PrintVerbose(profile.GetVerbose(), "starting cool down for %us...\n", timeSpan.GetCooldown()); + + if (bSynchStop) + { + assert(NULL != pSynch->hStopEvent); + dwWaitStatus = WaitForSingleObject(pSynch->hStopEvent, 1000 * timeSpan.GetCooldown()); + if (WAIT_OBJECT_0 != dwWaitStatus && WAIT_TIMEOUT != dwWaitStatus) + { + PrintError("Error during WaitForSingleObject\n"); + // stopETW(bUseETW, hTraceSession); + _TerminateWorkerThreads(vhThreads); + return false; + } + } + else + { + Sleep(1000 * timeSpan.GetCooldown()); + } + + TraceLoggingWriteStop(CoolActivity, "Cool Down"); + } + PrintVerbose(profile.GetVerbose(), "finished test...\n"); + + // + // signal the threads to finish + // + g_bRun = FALSE; + if (timeSpan.GetCompletionRoutines()) + { + if (!SetEvent(hEndEvent)) + { + PrintError("Error signaling end event\n"); + // stopETW(bUseETW, hTraceSession); + return false; + } + } + + // + // wait till all of the threads finish + // +#pragma warning( push ) +#pragma warning( disable : 28112 ) + while (g_lRunningThreadsCount > 0) + { + Sleep(10); //FUTURE EXTENSION: a timeout should be implemented + } +#pragma warning( pop ) + + + //check if there has been an error during threads execution + if (g_bThreadError) + { + PrintError("There has been an error during threads execution\n"); + return false; + } + + // + // close events' handles + // + CloseHandle(hStartEvent); + hStartEvent = NULL; + + if (NULL != hEndEvent) + { + CloseHandle(hEndEvent); + hEndEvent = NULL; + } + //FUTURE EXTENSION: hStartEvent and hEndEvent should be closed in case of error too + + // + // compute time spent by each cpu + // + for (DWORD p = 0; p < g_SystemInformation.processorTopology._ulProcessorCount; ++p) + { + assert(vPerfDone[p].IdleTime.QuadPart >= vPerfInit[p].IdleTime.QuadPart); + assert(vPerfDone[p].KernelTime.QuadPart >= vPerfInit[p].KernelTime.QuadPart); + assert(vPerfDone[p].UserTime.QuadPart >= vPerfInit[p].UserTime.QuadPart); + + vPerfDiff[p].IdleTime.QuadPart = vPerfDone[p].IdleTime.QuadPart - vPerfInit[p].IdleTime.QuadPart; + vPerfDiff[p].KernelTime.QuadPart = vPerfDone[p].KernelTime.QuadPart - vPerfInit[p].KernelTime.QuadPart; + vPerfDiff[p].UserTime.QuadPart = vPerfDone[p].UserTime.QuadPart - vPerfInit[p].UserTime.QuadPart; + + // + // Handle clock measurement jitter; if the difference is negative, set it to 0. This is usually seen + // as a -10000000 (full second of 100ns units) difference over very short runs. + // + // If the sum of kernel and user time is 0, treat it as a full idle with placeholder values. This provides + // a nonzero denominator for the CPU utilization calculation and avoids divide by zero -> INF results. + // Note that system clock convention is that kernel time includes idle time. + // + + if (vPerfDiff[p].IdleTime.QuadPart < 0) + { + PrintVerbose(profile.GetVerbose(), "time fixup: IdleTime < 0 @ %u : ticks %lld - %lld\n", p, vPerfDone[p].IdleTime.QuadPart, vPerfInit[p].IdleTime.QuadPart); + vPerfDiff[p].IdleTime.QuadPart = 0; + } + + if (vPerfDiff[p].KernelTime.QuadPart < 0) + { + PrintVerbose(profile.GetVerbose(), "time fixup: KernelTime < 0 @ %u : ticks %lld - %lld\n", p, vPerfDone[p].KernelTime.QuadPart, vPerfInit[p].KernelTime.QuadPart); + vPerfDiff[p].KernelTime.QuadPart = 0; + } + + if (vPerfDiff[p].UserTime.QuadPart < 0) + { + PrintVerbose(profile.GetVerbose(), "time fixup: UserTime < 0 @ %u : ticks %lld - %lld\n", p, vPerfDone[p].UserTime.QuadPart, vPerfInit[p].UserTime.QuadPart); + vPerfDiff[p].UserTime.QuadPart = 0; + } + + if (vPerfDiff[p].KernelTime.QuadPart + vPerfDiff[p].UserTime.QuadPart == 0) + { + PrintVerbose(profile.GetVerbose(), "time fixup: KernelTime+UserTime = 0 @ %u : ticks K (%lld - %lld) + U (%lld - %lld)\n", p, + vPerfDone[p].KernelTime.QuadPart, vPerfInit[p].KernelTime.QuadPart, + vPerfDone[p].UserTime.QuadPart, vPerfInit[p].UserTime.QuadPart); + + vPerfDiff[p].IdleTime.QuadPart = vPerfDiff[p].KernelTime.QuadPart = 1; + } + } + + // + // process results and pass them to the result parser + // + + // get processors perf. info + results.vSystemProcessorPerfInfo = vPerfDiff; + results.ullTimeCount = ullTimeDiff; + + // + // create structure containing etw results and properties + // + results.fUseETW = fUseETW; + if (fUseETW) + { + results.EtwEventCounters = g_EtwEventCounters; + results.EtwSessionInfo = _GetResultETWSession(pETWSession); + + // TODO: refactor to a separate function + results.EtwMask.bProcess = profile.GetEtwProcess(); + results.EtwMask.bThread = profile.GetEtwThread(); + results.EtwMask.bImageLoad = profile.GetEtwImageLoad(); + results.EtwMask.bDiskIO = profile.GetEtwDiskIO(); + results.EtwMask.bMemoryPageFaults = profile.GetEtwMemoryPageFaults(); + results.EtwMask.bMemoryHardFaults = profile.GetEtwMemoryHardFaults(); + results.EtwMask.bNetwork = profile.GetEtwNetwork(); + results.EtwMask.bRegistry = profile.GetEtwRegistry(); + results.EtwMask.bUsePagedMemory = profile.GetEtwUsePagedMemory(); + results.EtwMask.bUsePerfTimer = profile.GetEtwUsePerfTimer(); + results.EtwMask.bUseSystemTimer = profile.GetEtwUseSystemTimer(); + results.EtwMask.bUseCyclesCounter = profile.GetEtwUseCyclesCounter(); + + free(pETWSession); + } + + // free memory used by random data write buffers + for (auto i = vTargets.begin(); i != vTargets.end(); i++) + { + i->FreeRandomDataWriteBuffer(); + } + + // TODO: this won't catch error cases, which exit early + InterlockedExchange(&g_lGeneratorRunning, 0); + return true; +} + +vector IORequestGenerator::_GetFilesToPrecreate(const Profile& profile) const +{ + vector vFilesToCreate; + const vector& vTimeSpans = profile.GetTimeSpans(); + map> filesMap; + for (const auto& timeSpan : vTimeSpans) + { + vector vTargets(timeSpan.GetTargets()); + for (const auto& target : vTargets) + { + struct CreateFileParameters createFileParameters; + createFileParameters.sPath = target.GetPath(); + createFileParameters.ullFileSize = target.GetFileSize(); + createFileParameters.fZeroWriteBuffers = target.GetZeroWriteBuffers(); + + filesMap[createFileParameters.sPath].push_back(createFileParameters); + } + } + + PrecreateFiles filter = profile.GetPrecreateFiles(); + for (auto fileMapEntry : filesMap) + { + if (fileMapEntry.second.size() > 0) + { + UINT64 ullLastNonZeroSize = fileMapEntry.second[0].ullFileSize; + UINT64 ullMaxSize = fileMapEntry.second[0].ullFileSize; + bool fLastZeroWriteBuffers = fileMapEntry.second[0].fZeroWriteBuffers; + bool fHasZeroSizes = false; + bool fConstantSize = true; + bool fConstantZeroWriteBuffers = true; + for (auto file : fileMapEntry.second) + { + ullMaxSize = max(ullMaxSize, file.ullFileSize); + if (ullLastNonZeroSize == 0) + { + ullLastNonZeroSize = file.ullFileSize; + } + if (file.ullFileSize == 0) + { + fHasZeroSizes = true; + } + if ((file.ullFileSize != 0) && (file.ullFileSize != ullLastNonZeroSize)) + { + fConstantSize = false; + } + if (file.fZeroWriteBuffers != fLastZeroWriteBuffers) + { + fConstantZeroWriteBuffers = false; + } + if (file.ullFileSize != 0) + { + ullLastNonZeroSize = file.ullFileSize; + } + fLastZeroWriteBuffers = file.fZeroWriteBuffers; + } + + if (fConstantZeroWriteBuffers && ullMaxSize > 0) + { + struct CreateFileParameters file = fileMapEntry.second[0]; + file.ullFileSize = ullMaxSize; + if (filter == PrecreateFiles::UseMaxSize) + { + vFilesToCreate.push_back(file); + } + else if ((filter == PrecreateFiles::OnlyFilesWithConstantSizes) && fConstantSize && !fHasZeroSizes) + { + vFilesToCreate.push_back(file); + } + else if ((filter == PrecreateFiles::OnlyFilesWithConstantOrZeroSizes) && fConstantSize) + { + vFilesToCreate.push_back(file); + } + } + } + } + + return vFilesToCreate; +} \ No newline at end of file diff --git a/CristalDiskMark/source/diskspd22/IORequestGenerator/OverlappedQueue.cpp b/CristalDiskMark/source/diskspd22/IORequestGenerator/OverlappedQueue.cpp new file mode 100644 index 0000000..23fbd36 --- /dev/null +++ b/CristalDiskMark/source/diskspd22/IORequestGenerator/OverlappedQueue.cpp @@ -0,0 +1,79 @@ +/* + +DISKSPD + +Copyright(c) Microsoft Corporation +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#include "OverlappedQueue.h" +#include + +OverlappedQueue::OverlappedQueue(void) : + _pHead(nullptr), + _pTail(nullptr), + _cItems(0) +{ +} + +void OverlappedQueue::Add(OVERLAPPED *pOverlapped) +{ + pOverlapped->Internal = NULL; + if (_pHead == nullptr) + { + assert(_pTail == nullptr); + _pHead = pOverlapped; + } + else + { + assert(_pTail != nullptr); + _pTail->Internal = (ULONG_PTR)pOverlapped; + } + _pTail = pOverlapped; + _cItems++; +} + +bool OverlappedQueue::IsEmpty(void) const +{ + return (_pHead == nullptr); +} + +OVERLAPPED *OverlappedQueue::Remove(void) +{ + assert(!IsEmpty()); + + OVERLAPPED *pOverlapped = _pHead; + _pHead = (OVERLAPPED *)pOverlapped->Internal; + if (_pHead == nullptr) + { + _pTail = nullptr; + } + _cItems--; + return pOverlapped; +} + +size_t OverlappedQueue::GetCount() const +{ + return _cItems; +} \ No newline at end of file diff --git a/CristalDiskMark/source/diskspd22/IORequestGenerator/ThroughputMeter.cpp b/CristalDiskMark/source/diskspd22/IORequestGenerator/ThroughputMeter.cpp new file mode 100644 index 0000000..726e740 --- /dev/null +++ b/CristalDiskMark/source/diskspd22/IORequestGenerator/ThroughputMeter.cpp @@ -0,0 +1,143 @@ +/* + +DISKSPD + +Copyright(c) Microsoft Corporation +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#include "Common.h" +#include "ThroughputMeter.h" + +ThroughputMeter::ThroughputMeter(void) : + _fRunning(false) +{ +} + +bool ThroughputMeter::IsRunning(void) const +{ + return _fRunning; +} + +void ThroughputMeter::Start(DWORD cBytesPerMillisecond, DWORD dwBlockSize, DWORD dwThinkTime, DWORD dwBurstSize) +{ + // Initialization + _cbCompleted = 0; + _cIO = 0; // number of completed IOs in the current burst + _cbBlockSize = dwBlockSize; + + _fThrottle = false; + _cBytesPerMillisecond = 0; + _fThink = false; + _ullDelayUntil = 0; + _thinkTime = 0; + _burstSize = 0; + _fRunning = false; + + _ullStartTimestamp = GetTickCount64(); + + if (0 != cBytesPerMillisecond) + { + _fThrottle = true; + _cBytesPerMillisecond = cBytesPerMillisecond; + _fRunning = true; + } + else if (0 != dwThinkTime) + { + _fThink = true; + _thinkTime = dwThinkTime; + _burstSize = dwBurstSize; + _fRunning = true; + } +} + +DWORD ThroughputMeter::GetSleepTime(void) const +{ + if (_fThink) + { + ULONGLONG ullTimestamp = GetTickCount64(); + if (ullTimestamp < _ullDelayUntil) + { + return (DWORD)(_ullDelayUntil - ullTimestamp); + } + else + { + return (_fThrottle) ? _GetThrottleTime() : 0; + } + } + else + { + if (_fThrottle) // think time has not been specified only check for throttling + { + return _GetThrottleTime(); + } + else + { + return 0; + } + } +} + +DWORD ThroughputMeter::_GetThrottleTime(void) const +{ + if ((g_ExperimentFlags & EXPERIMENT_TPUT_CALC) == 0) + { + ULONGLONG cbExpected = (GetTickCount64() - _ullStartTimestamp) * _cBytesPerMillisecond; + return cbExpected >= (_cbCompleted + _cbBlockSize) ? 0 : 1; + } + else + { + // prototype to calculate an actual sleep time + // under higher loads the ideal delay is likely in the microsecond range, but the minimum sleep is 1 ms + // however, at low rates it may be reasonable to calculate the delay and use it if > 1ms + + ULONGLONG elapsed = GetTickCount64() - _ullStartTimestamp; + ULONGLONG bytesNext = _cbCompleted + _cbBlockSize; + + if (elapsed * _cBytesPerMillisecond > bytesNext) + { + // below rate - no sleep + return 0; + } + + // above rate - sleep at least 1 ms + ULONGLONG sleepTarget = (bytesNext / _cBytesPerMillisecond) - elapsed; + + return max((DWORD)sleepTarget, 1); + } +} + +void ThroughputMeter::Adjust(size_t cb) +{ + _cbCompleted += cb; + _cIO++; + if (_fThink) + { + if (_cIO >= _burstSize) + { + _cIO = 0; + _ullDelayUntil = GetTickCount64() + _thinkTime; + } + } +} \ No newline at end of file diff --git a/CristalDiskMark/source/diskspd22/IORequestGenerator/etw.cpp b/CristalDiskMark/source/diskspd22/IORequestGenerator/etw.cpp new file mode 100644 index 0000000..a85ff5b --- /dev/null +++ b/CristalDiskMark/source/diskspd22/IORequestGenerator/etw.cpp @@ -0,0 +1,498 @@ +/* + +DISKSPD + +Copyright(c) Microsoft Corporation +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#include "etw.h" +#include "common.h" +#include +#include + +#include //WNODE_HEADER + +#define INITGUID //Include this #define to use SystemTraceControlGuid in Evntrace.h. +#include //ETW + +#include "IORequestGenerator.h" + +// variables declared in IORequestGenerator.cpp +extern struct ETWEventCounters g_EtwEventCounters; +extern BOOL volatile g_bTracing; + + +DEFINE_GUID ( /* 3d6fa8d4-fe05-11d0-9dda-00c04fd7ba7c */ + DiskIoGuid, + 0x3d6fa8d4, + 0xfe05, + 0x11d0, + 0x9d, 0xda, 0x00, 0xc0, 0x4f, 0xd7, 0xba, 0x7c + ); + +DEFINE_GUID ( /* 90cbdc39-4a3e-11d1-84f4-0000f80464e3 */ + FileIoGuid, + 0x90cbdc39, + 0x4a3e, + 0x11d1, + 0x84, 0xf4, 0x00, 0x00, 0xf8, 0x04, 0x64, 0xe3 + ); + +DEFINE_GUID ( /* 2cb15d1d-5fc1-11d2-abe1-00a0c911f518 */ + ImageLoadGuid, + 0x2cb15d1d, + 0x5fc1, + 0x11d2, + 0xab, 0xe1, 0x00, 0xa0, 0xc9, 0x11, 0xf5, 0x18 + ); + +DEFINE_GUID ( /* 3d6fa8d3-fe05-11d0-9dda-00c04fd7ba7c */ + PageFaultGuid, + 0x3d6fa8d3, + 0xfe05, + 0x11d0, + 0x9d, 0xda, 0x00, 0xc0, 0x4f, 0xd7, 0xba, 0x7c + ); + +DEFINE_GUID ( /* 9a280ac0-c8e0-11d1-84e2-00c04fb998a2 */ + TcpIpGuid, + 0x9a280ac0, + 0xc8e0, + 0x11d1, + 0x84, 0xe2, 0x00, 0xc0, 0x4f, 0xb9, 0x98, 0xa2 + ); + +DEFINE_GUID ( /* bf3a50c5-a9c9-4988-a005-2df0b7c80f80 */ + UdpIpGuid, + 0xbf3a50c5, + 0xa9c9, + 0x4988, + 0xa0, 0x05, 0x2d, 0xf0, 0xb7, 0xc8, 0x0f, 0x80 + ); + +DEFINE_GUID ( /* 3d6fa8d0-fe05-11d0-9dda-00c04fd7ba7c */ + ProcessGuid, + 0x3d6fa8d0, + 0xfe05, + 0x11d0, + 0x9d, 0xda, 0x00, 0xc0, 0x4f, 0xd7, 0xba, 0x7c + ); + +DEFINE_GUID ( /* AE53722E-C863-11d2-8659-00C04FA321A1 */ + RegistryGuid, + 0xae53722e, + 0xc863, + 0x11d2, + 0x86, 0x59, 0x0, 0xc0, 0x4f, 0xa3, 0x21, 0xa1 +); + +DEFINE_GUID ( /* 3d6fa8d1-fe05-11d0-9dda-00c04fd7ba7c */ + ThreadGuid, + 0x3d6fa8d1, + 0xfe05, + 0x11d0, + 0x9d, 0xda, 0x00, 0xc0, 0x4f, 0xd7, 0xba, 0x7c + ); + +/*****************************************************************************/ +// consumes events' data +// +BOOL TraceEvents() +{ + TRACEHANDLE handles[1]; + EVENT_TRACE_LOGFILE logfile; + + memset(&logfile, 0, sizeof(EVENT_TRACE_LOGFILE)); + + logfile.LoggerName = KERNEL_LOGGER_NAME; + logfile.LogFileName = NULL; + logfile.LogFileMode = EVENT_TRACE_REAL_TIME_MODE; + + logfile.IsKernelTrace = true; + + handles[0] = OpenTrace(&logfile); + if( (TRACEHANDLE)INVALID_HANDLE_VALUE == handles[0] ) + { + PrintError("ETW ERROR: OpenTrace failed (error code: %d)\n", GetLastError()); + return false; + } + else + { + ProcessTrace(handles, 1, 0, 0); + CloseTrace(handles[0]); + } + + return true; +} + +/*****************************************************************************/ +// allocates memory for ETW properties structure +// +PEVENT_TRACE_PROPERTIES allocateEventTraceProperties() +{ + PEVENT_TRACE_PROPERTIES pProperties = NULL; + size_t size = 0; + + + size = sizeof(EVENT_TRACE_PROPERTIES)+sizeof(KERNEL_LOGGER_NAME); + pProperties = (PEVENT_TRACE_PROPERTIES)malloc(size); + if( NULL == pProperties ) + { + PrintError("FATAL ERROR: unable to allocate memory (error code: %d)\n", GetLastError()); + return NULL; + } + + memset(pProperties, 0, size); + + pProperties->LoggerNameOffset = sizeof(EVENT_TRACE_PROPERTIES); + pProperties->Wnode.BufferSize = (ULONG)size; + pProperties->Wnode.Flags = WNODE_FLAG_TRACED_GUID; + + strcpy_s((char *)pProperties+pProperties->LoggerNameOffset, + size-pProperties->LoggerNameOffset, KERNEL_LOGGER_NAME); + + return pProperties; +} + +/*****************************************************************************/ +// callback function for disk I/O events +void WINAPI eventDiskIo(PEVENT_TRACE pEvent) +{ + if( EVENT_TRACE_TYPE_IO_READ == pEvent->Header.Class.Type ) + { + ++g_EtwEventCounters.ullIORead; + } + else if( EVENT_TRACE_TYPE_IO_WRITE == pEvent->Header.Class.Type ) + { + ++g_EtwEventCounters.ullIOWrite; + } +} + +/*****************************************************************************/ +// callback function for LoadImage events +// +void WINAPI eventLoadImage(PEVENT_TRACE pEvent) +{ + if( EVENT_TRACE_TYPE_LOAD == pEvent->Header.Class.Type ) + { + ++g_EtwEventCounters.ullImageLoad; + } +} + +/*****************************************************************************/ +// callback function for memory events +// +void WINAPI eventPageFault(PEVENT_TRACE pEvent) +{ + if( EVENT_TRACE_TYPE_MM_COW == pEvent->Header.Class.Type ) + { + ++g_EtwEventCounters.ullMMCopyOnWrite; + } + else if( EVENT_TRACE_TYPE_MM_DZF == pEvent->Header.Class.Type ) + { + ++g_EtwEventCounters.ullMMDemandZeroFault; + } + else if( EVENT_TRACE_TYPE_MM_GPF == pEvent->Header.Class.Type ) + { + ++g_EtwEventCounters.ullMMGuardPageFault; + } + else if( EVENT_TRACE_TYPE_MM_HPF == pEvent->Header.Class.Type ) + { + ++g_EtwEventCounters.ullMMHardPageFault; + } + else if( EVENT_TRACE_TYPE_MM_TF == pEvent->Header.Class.Type ) + { + ++g_EtwEventCounters.ullMMTransitionFault; + } +} + +/*****************************************************************************/ +// callback function for network and TCP/IP events +// +void WINAPI eventTcpIp(PEVENT_TRACE pEvent) +{ + if( EVENT_TRACE_TYPE_ACCEPT == pEvent->Header.Class.Type ) + { + ++g_EtwEventCounters.ullNetAccept; + } + else if( EVENT_TRACE_TYPE_CONNECT == pEvent->Header.Class.Type ) + { + ++g_EtwEventCounters.ullNetConnect; + } + else if( EVENT_TRACE_TYPE_DISCONNECT == pEvent->Header.Class.Type ) + { + ++g_EtwEventCounters.ullNetDisconnect; + } + else if( EVENT_TRACE_TYPE_RECEIVE == pEvent->Header.Class.Type ) + { + ++g_EtwEventCounters.ullNetTcpReceive; + } + else if( EVENT_TRACE_TYPE_RECONNECT == pEvent->Header.Class.Type ) + { + ++g_EtwEventCounters.ullNetReconnect; + } + else if( EVENT_TRACE_TYPE_RETRANSMIT == pEvent->Header.Class.Type ) + { + ++g_EtwEventCounters.ullNetRetransmit; + } + else if( EVENT_TRACE_TYPE_SEND == pEvent->Header.Class.Type ) + { + ++g_EtwEventCounters.ullNetTcpSend; + } +} + +/*****************************************************************************/ +// callback function for UDP/IP events +// +void WINAPI eventUdpIp(PEVENT_TRACE pEvent) +{ + if( EVENT_TRACE_TYPE_SEND == pEvent->Header.Class.Type ) + { + ++g_EtwEventCounters.ullNetUdpSend; + } + else if( EVENT_TRACE_TYPE_RECEIVE == pEvent->Header.Class.Type ) + { + ++g_EtwEventCounters.ullNetUdpReceive; + } +} + +/*****************************************************************************/ +// callback function for thread events +// +void WINAPI eventThread(PEVENT_TRACE pEvent) +{ + if( EVENT_TRACE_TYPE_START == pEvent->Header.Class.Type ) + { + ++g_EtwEventCounters.ullThreadStart; + } + else if( EVENT_TRACE_TYPE_END == pEvent->Header.Class.Type ) + { + ++g_EtwEventCounters.ullThreadEnd; + } +} + +/*****************************************************************************/ +// callback function for process events +// +void WINAPI eventProcess(PEVENT_TRACE pEvent) +{ + if( EVENT_TRACE_TYPE_START == pEvent->Header.Class.Type ) + { + ++g_EtwEventCounters.ullProcessStart; + } + else if( EVENT_TRACE_TYPE_END == pEvent->Header.Class.Type ) + { + ++g_EtwEventCounters.ullProcessEnd; + } +} + +/*****************************************************************************/ +// callback function for registry events +// +void WINAPI eventRegistry(PEVENT_TRACE pEvent) +{ + if( EVENT_TRACE_TYPE_REGCREATE == pEvent->Header.Class.Type ) + { + ++g_EtwEventCounters.ullRegCreate; + } + else if( EVENT_TRACE_TYPE_REGDELETE == pEvent->Header.Class.Type ) + { + ++g_EtwEventCounters.ullRegDelete; + } + else if( EVENT_TRACE_TYPE_REGDELETEVALUE == pEvent->Header.Class.Type ) + { + ++g_EtwEventCounters.ullRegDeleteValue; + } + else if( EVENT_TRACE_TYPE_REGENUMERATEKEY == pEvent->Header.Class.Type ) + { + ++g_EtwEventCounters.ullRegEnumerateKey; + } + else if( EVENT_TRACE_TYPE_REGENUMERATEVALUEKEY == pEvent->Header.Class.Type ) + { + ++g_EtwEventCounters.ullRegEnumerateValueKey; + } + else if( EVENT_TRACE_TYPE_REGFLUSH == pEvent->Header.Class.Type ) + { + ++g_EtwEventCounters.ullRegFlush; + } + else if( EVENT_TRACE_TYPE_REGOPEN == pEvent->Header.Class.Type ) + { + ++g_EtwEventCounters.ullRegOpen; + } + else if( EVENT_TRACE_TYPE_REGQUERY == pEvent->Header.Class.Type ) + { + ++g_EtwEventCounters.ullRegQuery; + } + else if( EVENT_TRACE_TYPE_REGQUERYMULTIPLEVALUE == pEvent->Header.Class.Type ) + { + ++g_EtwEventCounters.ullRegQueryMultipleValue; + } + else if( EVENT_TRACE_TYPE_REGQUERYVALUE == pEvent->Header.Class.Type ) + { + ++g_EtwEventCounters.ullRegQueryValue; + } + else if( EVENT_TRACE_TYPE_REGSETINFORMATION == pEvent->Header.Class.Type ) + { + ++g_EtwEventCounters.ullRegSetInformation; + } + else if( EVENT_TRACE_TYPE_REGSETVALUE == pEvent->Header.Class.Type ) + { + ++g_EtwEventCounters.ullRegSetValue; + } +} + +/*****************************************************************************/ +// starts ETW session and sets callback functions for various groups of events +// +TRACEHANDLE StartETWSession(const Profile& profile) +{ + PEVENT_TRACE_PROPERTIES pProperties; + + pProperties = allocateEventTraceProperties(); + if (nullptr == pProperties) + { + return 0; + } + + pProperties->LogFileMode = EVENT_TRACE_REAL_TIME_MODE; + + //use paged memory + if (profile.GetEtwUsePagedMemory()) + { + pProperties->LogFileMode |= EVENT_TRACE_USE_PAGED_MEMORY; + } + + // + // event classes + // + if (profile.GetEtwProcess()) + { + pProperties->EnableFlags |= EVENT_TRACE_FLAG_PROCESS; + SetTraceCallback(&ProcessGuid, eventProcess); + } + + if (profile.GetEtwThread()) + { + pProperties->EnableFlags |= EVENT_TRACE_FLAG_THREAD; + SetTraceCallback(&ThreadGuid, eventThread); + } + + if (profile.GetEtwImageLoad()) + { + pProperties->EnableFlags |= EVENT_TRACE_FLAG_IMAGE_LOAD; + SetTraceCallback(&ImageLoadGuid, eventLoadImage); + } + + if (profile.GetEtwDiskIO()) + { + pProperties->EnableFlags |= EVENT_TRACE_FLAG_DISK_IO; + SetTraceCallback(&DiskIoGuid, eventDiskIo); + } + + if (profile.GetEtwMemoryPageFaults()) + { + pProperties->EnableFlags |= EVENT_TRACE_FLAG_MEMORY_PAGE_FAULTS; + SetTraceCallback(&PageFaultGuid, eventPageFault); + } + + if (profile.GetEtwMemoryHardFaults()) + { + pProperties->EnableFlags |= EVENT_TRACE_FLAG_MEMORY_HARD_FAULTS; + SetTraceCallback(&PageFaultGuid, eventPageFault); + } + + if (profile.GetEtwNetwork()) + { + pProperties->EnableFlags |= EVENT_TRACE_FLAG_NETWORK_TCPIP; + SetTraceCallback(&TcpIpGuid, eventTcpIp); + SetTraceCallback(&UdpIpGuid, eventUdpIp); + } + + if (profile.GetEtwRegistry()) + { + pProperties->EnableFlags |= EVENT_TRACE_FLAG_REGISTRY; + SetTraceCallback(&RegistryGuid, eventRegistry); + } + + // + // timer + // + if (profile.GetEtwUsePerfTimer()) + { + pProperties->Wnode.ClientContext = 1; + } + if (profile.GetEtwUseSystemTimer()) + { + pProperties->Wnode.ClientContext = 2; + } + if (profile.GetEtwUseCyclesCounter()) + { + pProperties->Wnode.ClientContext = 3; + } + + pProperties->Wnode.Guid = SystemTraceControlGuid; + + TRACEHANDLE hTraceSession; + ULONG ret = StartTrace(&hTraceSession, KERNEL_LOGGER_NAME, pProperties); + free(pProperties); + if (ERROR_SUCCESS != ret) + { + PrintError("Error starting trace session\n"); + return 0; + } + + return hTraceSession; +} + +/*****************************************************************************/ +// stops ETW session +// +PEVENT_TRACE_PROPERTIES StopETWSession(TRACEHANDLE hTraceSession) +{ + PEVENT_TRACE_PROPERTIES pProperties; + + pProperties = allocateEventTraceProperties(); + if( NULL == pProperties ) + { + return NULL; + } + + ULONG ret; + + ret = ControlTrace(hTraceSession, NULL, pProperties, EVENT_TRACE_CONTROL_STOP); + if( ERROR_SUCCESS != ret ) + { + PrintError("Error stopping trace session\n"); + return NULL; + } + + //wait + while(g_bTracing) + { + Sleep(10); // TODO: remove active waiting + } + + return pProperties; +} \ No newline at end of file diff --git a/CristalDiskMark/source/diskspd22/LICENSE b/CristalDiskMark/source/diskspd22/LICENSE new file mode 100644 index 0000000..cd7af07 --- /dev/null +++ b/CristalDiskMark/source/diskspd22/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2014 Microsoft + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/CristalDiskMark/source/diskspd22/Process-DiskSpd.ps1 b/CristalDiskMark/source/diskspd22/Process-DiskSpd.ps1 new file mode 100644 index 0000000..be7cb6f --- /dev/null +++ b/CristalDiskMark/source/diskspd22/Process-DiskSpd.ps1 @@ -0,0 +1,228 @@ +<# +DISKSPD + +Copyright(c) Microsoft Corporation +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +#> + +param( + [string] $xmlresultpath = ".", + [string] $outfile = "result.tsv" + ) + +function Log-Host( + $ForegroundColor = 'Green', + [parameter(Position=0, ValueFromRemainingArguments=$true)] $args + ) +{ + write-host -ForegroundColor $ForegroundColor $(get-date -DisplayHint Time) $args +} + +function get-latency( $x ) { + + $x.Results.TimeSpan.Latency.Bucket |% { + $_.Percentile,$_.ReadMilliseconds,$_.WriteMilliseconds -join "`t" + } +} + +function process-result( + ) +{ + PROCESS { + + log-host -fore green $_ + + if ((Get-Content $_ -first 1) -ne '') { + + write-host -ForegroundColor Red ERROR: $_ does not appear to be an DiskSpd XML result. Make sure `-Rxml was specified. + + } else { + + # count valid results + $script:valid += 1 + + $x = [xml](Get-Content $_) + + $lf = $_.fullname -replace '.xml','.lat.tsv' + + if (-not [io.file]::Exists($lf)) { + get-latency $x > $lf + } + + $system = $x.Results.System.ComputerName + $t = $x.Results.TimeSpan.TestTimeSeconds + + # sum read and write iops across all threads and targets + $ri = ($x.Results.TimeSpan.Thread.Target | + measure -sum -Property ReadCount).Sum + $wi = ($x.Results.TimeSpan.Thread.Target | + measure -sum -Property WriteCount).Sum + $rb = ($x.Results.TimeSpan.Thread.Target | + measure -sum -Property ReadBytes).Sum + $wb = ($x.Results.TimeSpan.Thread.Target | + measure -sum -Property WriteBytes).Sum + + $riops = $ri / $t + $wiops = $wi / $t + $rbw = $rb / $t + $wbw = $wb / $t + + # avoid undefined/div-by-zero when calculating coefficient of var + $ricv = $null + if ($riops -gt 0) { $ricv = $x.Results.TimeSpan.Iops.ReadIopsStdDev / $riops } + $wicv = $null + if ($wiops -gt 0) { $wicv = $x.Results.TimeSpan.Iops.WriteIopsStdDev / $wiops } + + if ($ricv -gt 0.10 -or $wicv -gt 0.10) { + log-host -ForegroundColor red ("ricv {0:F3} wicv {1:F3}" -f $ricv,$wicv) + } else { + log-host ("ricv {0:F3} wicv {1:F3}" -f $ricv,$wicv) + } + + # note that with runs specified on the command line, only a single write ratio, + # outstanding request count and blocksize can be specified, so sampling the one + # used for the first thread is sufficient. + # + # this script DOES NOT handle complex timespan specifications + + if (($x.Results.Profile.TimeSpans.TimeSpan.Targets.Target.Random | select -first 1) -gt 0) { + $pat = "Random" + $align = ($x.Results.Profile.TimeSpans.TimeSpan.Targets.Target.Random | select -first 1) + } else { + $pat = "Sequential" + $align = ($x.Results.Profile.TimeSpans.TimeSpan.Targets.Target.StrideSize | select -first 1) + } + + # convert to object form / export-csv + + $o = @{ + 'ResultFileName' = $_.BaseName; + 'Path' = ($x.Results.TimeSpan.Thread.target.path | select -first 1); + 'Affinity' = ($x.Results.Profile.TimeSpans.TimeSpan.DisableAffinity -ne 'true'); + 'System' = $system; + 'TestTime' = $t; + 'WriteRatio' = ($x.Results.Profile.TimeSpans.TimeSpan.Targets.Target.WriteRatio | + select -first 1); + 'Pattern' = $pat; + 'Align' = $align; + 'Threads' = $x.Results.TimeSpan.ThreadCount; + 'Outstanding' = ($x.Results.Profile.TimeSpans.TimeSpan.Targets.Target.RequestCount | + select -first 1); + 'Block' = ($x.Results.Profile.TimeSpans.TimeSpan.Targets.Target.BlockSize | + select -first 1); + 'CPU' = $x.Results.TimeSpan.CpuUtilization.Average.UsagePercent; + 'CPUKern' = $x.Results.TimeSpan.CpuUtilization.Average.KernelPercent; + 'CPUHotCore' = ($x.Results.TimeSpan.CpuUtilization.CPU.UsagePercent |% { [decimal] $_ } | + sort -Descending | select -first 1); + 'CPUHotCoreKern' = ($x.Results.TimeSpan.CpuUtilization.CPU.KernelPercent |% { [decimal] $_ } | + sort -Descending | select -first 1); + 'ReadIOPS' = $riops; + 'ReadIOPSCoV' = $ricv; + 'ReadBW' = $rbw; + 'ReadBytes' = $rb; + 'LatReadAV' = $x.Results.TimeSpan.Latency.AverageReadMilliseconds; + 'WriteIOPS' = $wiops; + 'WriteIOPSCoV' = $wicv; + 'WriteBW' = $wbw; + 'WriteBytes' = $wb; + 'LatWriteAV' = $x.Results.TimeSpan.Latency.AverageWriteMilliseconds; + 'TotIOPS' = $riops + $wiops; + 'TotBW' = $rbw + $wbw; + } + + # extract the subset of latency percentiles as specified above in $l + $h = @{}; $x.Results.TimeSpan.Latency.Bucket |% { $h[$_.Percentile] = $_ } + + $ls = $script:l |% { + $b = $h[$_]; + if ($b.ReadMilliseconds) { $v = $b.ReadMilliseconds } else { $v = "" } + $o["LatRead$_"] = $v + if ($b.WriteMilliseconds) { $v = $b.WriteMilliseconds } else { $v = "" } + $o["LatWrite$_"] = $v + } + + # Parse additional fields from filename? other? here + $add = @() + if ($_.BaseName -match "-wc(\d+)wicpw(\d+)vm(\d+)") { + $add = $matches[1..3] + } elseif ($_.BaseName -match "-basevm(\d+)") { + $add = @('base','base',$matches[1]) + } else { + $add = @('na','na','na') + } + + if ($add.count -gt 0) { + write-host adding fields ($add -join ' : ') + } + + # Place any addons. user to rename manually for the moment. + $n = 1 + $add |% { + $o["Add$n"] = $_ + $n++ + } + + # emit for export + $o + } + } +} + +######################### +# +$delim = "`t" +$l = @(); foreach ($i in 25,50,75,90,95,99,99.9,99.99,99.999,100) { $l += ,[string]$i } + +$files = dir (join-path $xmlresultpath *.xml) + +######################### +# get schema and process/emit column headers +$valid = 0 +$scratch = $files[0] | process-result + +# if no valid results found, stop now +if ($valid -eq 0) { + + write-host -ForegroundColor Red ERROR: `"$xmlresultpath`"` may not contain DISKSPD result files + return +} + +# lexically order the column schema and emit with bounding quotes per field +$fields = $scratch.Keys | sort + +# column headers to output +$($fields |% { "`"$_`"" }) -join "$delim" | Out-File -FilePath $outfile + +######################### +# now process all files for rows +$valid = 0 +$files | process-result |% { + $row = $_ + $($fields |% { "`"$($row[$_])`"" }) -join "$delim" +} | Out-File -FilePath $outfile -Append + +# if some invalid files were found, warn +if ($valid -ne $files.count) { + + write-host -ForegroundColor Red WARNING: `"$xmlresultpath`"` contained $($files.count - $valid) non-DISKSPD xml files + return +} \ No newline at end of file diff --git a/CristalDiskMark/source/diskspd22/README.md b/CristalDiskMark/source/diskspd22/README.md new file mode 100644 index 0000000..782f9b3 --- /dev/null +++ b/CristalDiskMark/source/diskspd22/README.md @@ -0,0 +1,150 @@ +DiskSpd +======= + +DiskSpd is a storage performance tool from the Windows, Windows Server and Cloud Server Infrastructure engineering teams at Microsoft. Please visit for updated documentation. + +In addition to the tool itself, this repository hosts measurement frameworks which utilize DiskSpd. The initial example is [VM Fleet](https://github.com/Microsoft/diskspd/blob/master/Frameworks/VMFleet), used for Windows Server Hyper-Converged environments with Storage Spaces Direct. + +This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. + +Releases +======== + +The [Releases](https://github.com/Microsoft/diskspd/releases) page includes **pre-compiled binaries (ZIP) and source code** for the most current releases of the DiskSpd tool. The latest update to DiskSpd can always be downloaded from (aka ). + +What's New? +=========== + +## DISKSPD + +# DISKSPD 2.2 6/3/2024 + +**NOTE:** changes to the asynchronous IO loop will require rebaselining results with queue depths greater than 1. +The new design drains the completion queue more aggressively, shrinking delays that impacted latency measurement +especially on faster storage targeting higher queue depths. Latency measurement is improved at a very small cost +to rates, as well as improving rates when latency measurement is not used (`-D` or `-L`) due to batch dequeue. + +Smaller IO sizes will see the most change. + +* New: Socket, NUMA, Core and Power Efficiency Class (big/little cores) added to processor topology reporting (XML and text output) + * topology elements only displayed in text results when > 1 are present (e.g. multi-socket systems) + * CPU numbering remains group relative, as is the new Core numbering + * highest Power Efficiency Class is marked with a `P` suffix (this will usually be `1P` v. `0`) + * **NOTE**: efficiency classes can have major impact; work on heterogenous systems **must** be aware of core properties in combination with thread affinity rules (see `-a` and `-n `) +* New: active power scheme reporting +* New: base target offset switch now allows range specification: `-Bbase[:length]`; replaces `-B` and `-f` +* post-run latency histogram processing now significantly faster +* verbose output is more consistent; includes actual warmup, measured and cooldown intervals v. expected + +Binary release supports down to Windows 8 and Windows Server 2012; now uses the Universal CRT. + +# DISKSPD 2.1 7/1/2021 + +* New `-gi` form allowing throughput limit specification in units of IOPS (per specified blocksize) +* New `-rs` to specify mixed random/sequential operation (pct random); geometric distribution of run lengths +* New `-rd` to specify non-uniform IO distributions across target + * `pct` by target percentage + * `abs` by absolute offset +* New `-Rp` to show specified parameter set in indicated profile output form; works with -X XML profiles and conventional command line +* XML results/profiles are now indented for ease of review +* Text result output updates + * now shows values in size units (K/M/G, and now TiB) to two decimals + * thread stride no longer shown unless specified + * -F/-O threadpool parameters shown +* XML profiles can now be built more generically + * XML profiles can be stated in terms of templated target names (*1, *2), replaced in order from command line invocation + * the command line now allows options alongside -X: -v, -z, -R and -W/-d/-C along with template target specs + +# DISKSPD 2.0.21a 9/21/2018 + +* Added support for memory mapped I/O: + * New `-Sm` option to enable memory mapped I/O + * New `-N` option to specify flush options for memory mapped I/O +* Added support for providing Event Tracing for Windows (ETW) events +* Included a Windows Performance Recorder (WPR) profile to enable ETW tracing +* Added system information to the ResultParser output + +# DISKSPD 2.0.20a 2/28/2018 + +* Changes that may require rebaselining of results: + * New random number generator that may show an observable decreased cost + * Switched to 512-byte aligned buffers with the `-Z` option to increase performance +* New `-O` option for specifying the number of outstanding IO requests per thread +* New `-Zr` option for per-IO randomization of write buffer content +* XML: Adds a new `` element to support target weighting schemes +* Enhanced statistics captured from IOPS data +* Added support for validating XML profiles using an in-built XSD +* Added support for handling RAW volumes +* Updated CPU statistics to work on > 64-core systems +* Updated calculation and accuracy of CPU statistics +* Re-enable support for ETW statistics + +# DISKSPD 2.0.18a 5/31/2016 + +* update `/?` example to use `-Sh` v. deprecated `-h` +* fix operation on volumes on GPT partitioned media (:) +* fix IO priority hint to proper stack alignment (if not 8 byte, will fail) +* use iB notation to clarify that text result output is in 2^n units (KiB/MiB/GiB) + +# DISKSPD 2.0.17a 5/01/2016 + +* `-S` is expanded to control write-through independent of OS/software cache. Among other things, this allows buffered write-through to be specified (`-Sbw`). +* XML: adds a new `` element to specify write-through +* XML: `` is no longer emitted (still parsed, though), in favor or `` and `` +* Text output: OS/software cache and write-through state are now documented separately (adjacent lines) +* Latency histogram now reports to 9-nines (one part in one billion) in both text and XML output +* Error message added for failure to open write-content source file (`-Z,`) + +## VM Fleet + +VM Fleet is a performance characterization and analyst framework for exploring the storage capabilities of Windows Server Hyper-Converged environments with Storage Spaces Direct. + +# VM Fleet 2.1.0.0 4/3/2024 + +* Support for Arc VM management (only applicable to clusters managed by Arc) +* `Set-FleetRunProfileScript` - produce a free-run script based on one of the defined workload profiles +* `Watch-FleetCPU` - new support for monitoring guest VCPU utilization (-Guest); can handle data outages +* Fix: performance counter handling now manages intermittent data dropouts (per conventional relog.exe) +* Fix: mid-run vm health check now handles the possibility of many vms taking longer than intended runtime to validate; early exit to avoid false failures +* Fix: ignore reboot required indication from cache layer when changing cache behavior; avoid false failure + +# VM Fleet 2.0.2.2 12/1/2021 + +* Fix cluster remoting issue during New-Fleet caused by 2.0.2.1 work +* Use timestamped logging in New-Fleet, simplify and de-colorize default output + +# VM Fleet 2.0.2.1 11/9/2021 + +* Fix cluster remoting issues in Move-Fleet and Get-FleetDataDiskEstimate +* Fix timing issue with Start-FleetSweep; always start from fleet pause to avoid triggering free run +* Use uniqueness to guarantee Start-FleetSweep runs profile in case of repeat + +# VM Fleet 2.0.2 11/2/2021 + +* Windows Server 2019/RS5 host operation now confirmed & supported +* Read cache warmup for HDD capacity systems should now be faster + +`Set-FleetPause` will wait for VM responses before completion by default (see -Timeout) + +Several minor fixes including: + +* Disable Windows Recovery Console in fleet VMs +* Fix: `Show-Fleet` IOPS view now aggregates all VM disk devices +* Fix: clean up leaked/conflicting data collectors and blg automatically + +# VM Fleet 2.0 9/22/2021 + +* major release and rewrite as a first class Powershell module +* original script-based VM Fleet remains available at Frameworks/VMFleet1.0 +* see the [documentation](https://github.com/microsoft/diskspd/wiki/VMFleet) in the Wiki + +Source Code +=========== + +The source code for DiskSpd is hosted on GitHub at: + + + +Any issues with DiskSpd can be reported using the following link: + + diff --git a/CristalDiskMark/source/diskspd22/ResultParser/ResultParser.cpp b/CristalDiskMark/source/diskspd22/ResultParser/ResultParser.cpp new file mode 100644 index 0000000..8eca72b --- /dev/null +++ b/CristalDiskMark/source/diskspd22/ResultParser/ResultParser.cpp @@ -0,0 +1,1334 @@ +/* + +DISKSPD + +Copyright(c) Microsoft Corporation +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +// ResultParser.cpp : Defines the entry point for the DLL application. +// +#include "ResultParser.h" + +#include "common.h" +#include + +#include +#include +#include //ntdll.dll + +#include //WNODE_HEADER +#include + +#include + +// TODO: refactor to a single function shared with the XmlResultParser +// Note: not thread safe (avoid 4K on the stack) + +static char printBuffer[4096] = {}; + +/// for CrystalDiskMark +int ResultParser::GetTotalScore() +{ + return _totalScore; +} + +double ResultParser::GetAverageLatency() +{ + return _averageLatency; +} + +void ResultParser::_Print(const char *format, ...) +{ + assert(nullptr != format); + va_list listArg; + va_start(listArg, format); + vsprintf_s(printBuffer, _countof(printBuffer), format, listArg); + va_end(listArg); + _sResult += printBuffer; +} + +/*****************************************************************************/ +// display file size in a user-friendly form +// + +struct { + UINT32 sizeShift; + PCHAR name; +} sizeUnits[] = { + { 40, "TiB" }, + { 30, "GiB" }, + { 20, "MiB" }, + { 10, "KiB" } +}; + +void ResultParser::_DisplayFileSize(UINT64 fsize, UINT32 align) +{ + char fmtbuf[16]; + + for (auto& s : sizeUnits) + { + UINT64 sz = (UINT64)1 << s.sizeShift; + if (fsize >= sz) + { + // Even multiple? + if ((fsize & (sz - 1)) == 0) + { + // note: guaranteed no loss of precision - TB shift guarantees + // 0 in high 32bits. + UINT32 f = static_cast(fsize >> s.sizeShift); + + if (align) + { + // "%u%s" + _snprintf_s(fmtbuf, sizeof(fmtbuf), "%%%uu%%s", align); + _Print(fmtbuf, f, s.name); + } + else + { + _Print("%u%s", f, s.name); + } + return; + } + + // Not even, use fp. + double f = static_cast(fsize) / sz; + + if (align) + { + // "%.2f%s" + _snprintf_s(fmtbuf, sizeof(fmtbuf), "%%%u.2f%%s", align); + _Print(fmtbuf, f, s.name); + } + else + { + _Print("%0.2f%s", f, s.name); + } + return; + } + } + + _Print("%I64u", fsize); +} + +/*****************************************************************************/ +void ResultParser::_DisplayETWSessionInfo(struct ETWSessionInfo sessionInfo) +{ + _Print("\n\n"); + _Print(" ETW Buffer Settings & Statistics\n"); + _Print("--------------------------------------------------------\n"); + _Print("(KB) Buffers (Secs) (Mins)\n"); + _Print("Size | Min | Max | Free | Written | Flush Age\n"); + + _Print("%-5lu %5lu %-5lu %-2lu %8lu %8lu %8d\n\n", + sessionInfo.ulBufferSize, + sessionInfo.ulMinimumBuffers, + sessionInfo.ulMaximumBuffers, + sessionInfo.ulFreeBuffers, + sessionInfo.ulBuffersWritten, + sessionInfo.ulFlushTimer, + sessionInfo.lAgeLimit); + + _Print("Allocated Buffers:\t%lu\n", + sessionInfo.ulNumberOfBuffers); + + _Print("Lost Events:\t\t%lu\n", + sessionInfo.ulEventsLost); + + _Print("Lost Log Buffers:\t%lu\n", + sessionInfo.ulLogBuffersLost); + + _Print("Lost Real Time Buffers:\t%lu\n", + sessionInfo.ulRealTimeBuffersLost); +} + +/*****************************************************************************/ +void ResultParser::_DisplayETW(struct ETWMask ETWMask, struct ETWEventCounters EtwEventCounters) +{ + _Print("\n\n\nETW:\n"); + _Print("----\n\n"); + + if (ETWMask.bDiskIO) + { + _Print("\tDisk I/O\n"); + + _Print("\t\tRead: %I64u\n", EtwEventCounters.ullIORead); + _Print("\t\tWrite: %I64u\n", EtwEventCounters.ullIOWrite); + } + if (ETWMask.bImageLoad) + { + _Print("\tLoad Image\n"); + + _Print("\t\tLoad Image: %I64u\n", EtwEventCounters.ullImageLoad); + } + if (ETWMask.bMemoryPageFaults) + { + _Print("\tMemory Page Faults\n"); + + _Print("\t\tCopy on Write: %I64u\n", EtwEventCounters.ullMMCopyOnWrite); + _Print("\t\tDemand Zero fault: %I64u\n", EtwEventCounters.ullMMDemandZeroFault); + _Print("\t\tGuard Page fault: %I64u\n", EtwEventCounters.ullMMGuardPageFault); + _Print("\t\tHard page fault: %I64u\n", EtwEventCounters.ullMMHardPageFault); + _Print("\t\tTransition fault: %I64u\n", EtwEventCounters.ullMMTransitionFault); + } + if (ETWMask.bMemoryHardFaults && !ETWMask.bMemoryPageFaults ) + { + _Print("\tMemory Hard Faults\n"); + _Print("\t\tHard page fault: %I64u\n", EtwEventCounters.ullMMHardPageFault); + } + if (ETWMask.bNetwork) + { + _Print("\tNetwork\n"); + + _Print("\t\tAccept: %I64u\n", EtwEventCounters.ullNetAccept); + _Print("\t\tConnect: %I64u\n", EtwEventCounters.ullNetConnect); + _Print("\t\tDisconnect: %I64u\n", EtwEventCounters.ullNetDisconnect); + _Print("\t\tReconnect: %I64u\n", EtwEventCounters.ullNetReconnect); + _Print("\t\tRetransmit: %I64u\n", EtwEventCounters.ullNetRetransmit); + _Print("\t\tTCP/IP Send: %I64u\n", EtwEventCounters.ullNetTcpSend); + _Print("\t\tTCP/IP Receive: %I64u\n", EtwEventCounters.ullNetTcpReceive); + _Print("\t\tUDP/IP Send: %I64u\n", EtwEventCounters.ullNetUdpSend); + _Print("\t\tUDP/IP Receive: %I64u\n", EtwEventCounters.ullNetUdpReceive); + } + if (ETWMask.bProcess) + { + _Print("\tProcess\n"); + + _Print("\t\tStart: %I64u\n", EtwEventCounters.ullProcessStart); + _Print("\t\tEnd: %I64u\n", EtwEventCounters.ullProcessEnd); + } + if (ETWMask.bRegistry) + { + _Print("\tRegistry\n"); + + _Print("\t\tNtCreateKey: %I64u\n", + EtwEventCounters.ullRegCreate); + + _Print("\t\tNtDeleteKey: %I64u\n", + EtwEventCounters.ullRegDelete); + + _Print("\t\tNtDeleteValueKey: %I64u\n", + EtwEventCounters.ullRegDeleteValue); + + _Print("\t\tNtEnumerateKey: %I64u\n", + EtwEventCounters.ullRegEnumerateKey); + + _Print("\t\tNtEnumerateValueKey: %I64u\n", + EtwEventCounters.ullRegEnumerateValueKey); + + _Print("\t\tNtFlushKey: %I64u\n", + EtwEventCounters.ullRegFlush); + + _Print("\t\tNtOpenKey: %I64u\n", + EtwEventCounters.ullRegOpen); + + _Print("\t\tNtQueryKey: %I64u\n", + EtwEventCounters.ullRegQuery); + + _Print("\t\tNtQueryMultipleValueKey: %I64u\n", + EtwEventCounters.ullRegQueryMultipleValue); + + _Print("\t\tNtQueryValueKey: %I64u\n", + EtwEventCounters.ullRegQueryValue); + + _Print("\t\tNtSetInformationKey: %I64u\n", + EtwEventCounters.ullRegSetInformation); + + _Print("\t\tNtSetValueKey: %I64u\n", + EtwEventCounters.ullRegSetValue); + } + if (ETWMask.bThread) + { + _Print("\tThread\n"); + + _Print("\t\tStart: %I64u\n", EtwEventCounters.ullThreadStart); + _Print("\t\tEnd: %I64u\n", EtwEventCounters.ullThreadEnd); + } +} + +void ResultParser::_PrintDistribution(DistributionType dT, const vector& v, char* spc) +{ + if (dT == DistributionType::None) + { + return; + } + + switch (dT) + { + case DistributionType::Percent: + for (const auto &r : v) + { + _Print(spc); + _Print(" %3u%% of IO => [%2I64u%% - %3I64u%%) of target\n", + r._span, + r._dst.first, + r._dst.first + r._dst.second + ); + } + break; + + case DistributionType::Absolute: + { + const DistributionRange& last = *v.rbegin(); + UINT32 max = last._src + last._span; + + for (const auto &r : v) + { + _Print(spc); + // If this is a trimmed distribution (target was smaller than its range) + // then we need to rescale the trimmed IO% to 100%. Present this with a + // single decimal point, which may of course show rounding. + if (max < 100) + { + _Print(" %0.1f%% of IO => [", (double) 100 * r._span / max); + } + // Otherwise it is a simple 1-100% and can avoid rounding artifacts. + else + { + _Print(" %3u%% of IO => [", r._span); + } + + if (r._dst.first == 0) + { + // directly emit leading zero so we can align it + _Print(" 0 "); + } + else + { + _DisplayFileSize(r._dst.first, 6); + } + _Print(" - "); + // zero length occurs (only) in specification is a placeholder for end of target + if (r._dst.second) + { + _DisplayFileSize(r._dst.first + r._dst.second, 6); + _Print(")\n"); + } + else + { + _Print(" end)\n"); + } + } + } + break; + } +} + +class DistributionRef { +public: + + DistributionRef( + const string &TargetPath, + UINT32 Thread + ) + { + set s; + s.insert(Thread); + + _mTargetThreads.emplace(make_pair(TargetPath, std::move(s))); + } + + // + // Map a target to the set of threads referencing it with a given distribution + // + + map> _mTargetThreads; +}; + +namespace std +{ + template<> + struct less *> + { + // map by pointer, compare with the distributions + bool operator()(const vector * const &lhs, const vector * const &rhs) const + { + return *lhs < *rhs; + } + }; +} + +void ResultParser::_PrintEffectiveDistributions(const Results& results) +{ + // + // Effective distributions can be distinct per target if they vary in size. + // While not possible at the command line, more complex configurations can + // in general specify a distribution per target per thread. + // + // This deduplicates the effective distributions so that we report each + // with the target/thread list which used the (equivalent) distribution + // to access the target. + // + + bool header = false; + UINT32 threadNo = 0; + map *, DistributionRef> m; + + for (auto& thResult : results.vThreadResults) + { + for (auto& tgtResult : thResult.vTargetResults) + { + if (tgtResult.vDistributionRange.size()) + { + auto it = m.find(const_cast *>(&tgtResult.vDistributionRange)); + if (it == m.end()) + { + m.emplace(make_pair(const_cast *>(&tgtResult.vDistributionRange), + DistributionRef(tgtResult.sPath, threadNo))); + } + else + { + it->second._mTargetThreads[tgtResult.sPath].insert(threadNo); + } + } + } + + ++threadNo; + } + + for (auto& r : m) + { + if (!header) + { + header = true; + _Print("\nEffective IO Distributions\n--------------------------\n"); + } + // _Print("target: %s\n", r.second._sTargets.cbegin()->c_str()); + for (auto& tgt : r.second._mTargetThreads) + { + _Print("target: %s [thread:", tgt.first.c_str()); + + UINT32 lastTh = MAXUINT, runLen = 0; + + for (auto& th : tgt.second) + { + if (lastTh != MAXUINT) + { + // accumulate run? + if (lastTh + 1 == th) { + lastTh = th; + ++runLen; + continue; + } + + // end of run - indicate ellision of actual runs + if (runLen > 1) + { + _Print(" -"); + } + _Print(" %u", lastTh); + } + + // start new run (may be singular) + _Print(" %u", th); + lastTh = th; + runLen = 0; + } + + // terminate final run + if (runLen > 1) + { + _Print(" -"); + } + // don't show last thread twice if it terminated run + if (runLen) + { + _Print(" %u", lastTh); + } + + _Print("]\n"); + } + _PrintDistribution(DistributionType::Absolute, *r.first, ""); + } +} + +void ResultParser::_PrintTarget(const Target &target, bool fUseThreadsPerFile, bool fUseRequestsPerFile, bool fCompletionRoutines) +{ + if (target.GetPath().c_str()[0] == TEMPLATE_TARGET_PREFIX) + { + _Print("\tpath: template target '%s'\n", target.GetPath().c_str() + 1); + } + else + { + _Print("\tpath: '%s'\n", target.GetPath().c_str()); + } + _Print("\t\tthink time: %ums\n", target.GetThinkTime()); + _Print("\t\tburst size: %u\n", target.GetBurstSize()); + // TODO: completion routines/ports + + switch (target.GetCacheMode()) + { + case TargetCacheMode::Cached: + _Print("\t\tusing software cache\n"); + break; + case TargetCacheMode::DisableLocalCache: + _Print("\t\tlocal software cache disabled, remote cache enabled\n"); + break; + case TargetCacheMode::DisableOSCache: + _Print("\t\tsoftware cache disabled\n"); + break; + } + + if (target.GetWriteThroughMode() == WriteThroughMode::On) + { + // context-appropriate comment on writethrough + // if sw cache is disabled, commenting on sw write cache is possibly confusing + switch (target.GetCacheMode()) + { + case TargetCacheMode::Cached: + case TargetCacheMode::DisableLocalCache: + _Print("\t\thardware and software write caches disabled, writethrough on\n"); + break; + case TargetCacheMode::DisableOSCache: + _Print("\t\thardware write cache disabled, writethrough on\n"); + break; + } + } + else + { + _Print("\t\tusing hardware write cache, writethrough off\n"); + } + + if (target.GetMemoryMappedIoMode() == MemoryMappedIoMode::On) + { + _Print("\t\tmemory mapped I/O enabled"); + switch(target.GetMemoryMappedIoFlushMode()) + { + case MemoryMappedIoFlushMode::ViewOfFile: + _Print(", flush mode: FlushViewOfFile"); + break; + case MemoryMappedIoFlushMode::NonVolatileMemory: + _Print(", flush mode: FlushNonVolatileMemory"); + break; + case MemoryMappedIoFlushMode::NonVolatileMemoryNoDrain: + _Print(", flush mode: FlushNonVolatileMemory with no drain"); + break; + } + _Print("\n"); + } + + if (target.GetZeroWriteBuffers()) + { + _Print("\t\tzeroing write buffers\n"); + } + + if (target.GetRandomDataWriteBufferSize() > 0) + { + _Print("\t\twrite buffer size: "); + _DisplayFileSize(target.GetRandomDataWriteBufferSize()); + _Print("\n"); + + string sWriteBufferSourcePath = target.GetRandomDataWriteBufferSourcePath(); + if (!sWriteBufferSourcePath.empty()) + { + _Print("\t\twrite buffer source: '%s'\n", sWriteBufferSourcePath.c_str()); + } + else + { + _Print("\t\twrite buffer source: random fill\n"); + } + } + + if (target.GetUseParallelAsyncIO()) + { + _Print("\t\tusing parallel async I/O\n"); + } + + if (target.GetWriteRatio() == 0) + { + _Print("\t\tperforming read test\n"); + } + else if (target.GetWriteRatio() == 100) + { + _Print("\t\tperforming write test\n"); + } + else + { + _Print("\t\tperforming mix test (read/write ratio: %d/%d)\n", 100 - target.GetWriteRatio(), target.GetWriteRatio()); + } + + _Print("\t\tblock size: "); + _DisplayFileSize(target.GetBlockSizeInBytes()); + _Print("\n"); + + if (target.GetRandomRatio() == 100) + { + _Print("\t\tusing random I/O (alignment: "); + } + else + { + if (target.GetRandomRatio() > 0) + { + _Print("\t\tusing mixed random/sequential I/O (%u%% random) (alignment/stride: ", target.GetRandomRatio()); + } + else + { + _Print("\t\tusing%s sequential I/O (stride: ", target.GetUseInterlockedSequential() ? " interlocked":""); + } + } + _DisplayFileSize(target.GetBlockAlignmentInBytes()); + _Print(")\n"); + + if (fUseRequestsPerFile) + { + _Print("\t\tnumber of outstanding I/O operations per thread: %d\n", target.GetRequestCount()); + } + else + { + _Print("\t\trelative IO weight in thread pool: %u\n", target.GetWeight()); + } + + if (0 != target.GetBaseFileOffsetInBytes()) + { + _Print("\t\tbase file offset: "); + _DisplayFileSize(target.GetBaseFileOffsetInBytes()); + _Print("\n"); + } + + if (0 != target.GetMaxFileSize()) + { + _Print("\t\tmax file size: "); + _DisplayFileSize(target.GetMaxFileSize()); + _Print("\n"); + } + + if (0 != target.GetThreadStrideInBytes()) + { + _Print("\t\tthread stride size: "); + _DisplayFileSize(target.GetThreadStrideInBytes()); + _Print("\n"); + } + + if (target.GetSequentialScanHint()) + { + _Print("\t\tusing FILE_FLAG_SEQUENTIAL_SCAN hint\n"); + } + + if (target.GetRandomAccessHint()) + { + _Print("\t\tusing FILE_FLAG_RANDOM_ACCESS hint\n"); + } + + if (target.GetTemporaryFileHint()) + { + _Print("\t\tusing FILE_ATTRIBUTE_TEMPORARY hint\n"); + } + + if (fUseThreadsPerFile) + { + _Print("\t\tthreads per file: %d\n", target.GetThreadsPerFile()); + } + if (target.GetRequestCount() > 1 && fUseThreadsPerFile) + { + if (fCompletionRoutines) + { + _Print("\t\tusing completion routines (ReadFileEx/WriteFileEx)\n"); + } + else + { + _Print("\t\tusing I/O Completion Ports\n"); + } + } + + if (target.GetIOPriorityHint() == IoPriorityHintVeryLow) + { + _Print("\t\tIO priority: very low\n"); + } + else if (target.GetIOPriorityHint() == IoPriorityHintLow) + { + _Print("\t\tIO priority: low\n"); + } + else if (target.GetIOPriorityHint() == IoPriorityHintNormal) + { + _Print("\t\tIO priority: normal\n"); + } + else + { + _Print("\t\tIO priority: unknown\n"); + } + + if (target.GetThroughputIOPS()) + { + _Print("\t\tthroughput rate-limited to %u IOPS\n", target.GetThroughputIOPS()); + } + else if (target.GetThroughputInBytesPerMillisecond()) + { + _Print("\t\tthroughput rate-limited to %u B/ms\n", target.GetThroughputInBytesPerMillisecond()); + } + + if (target.GetDistributionRange().size()) + { + _Print("\t\tIO Distribution:\n"); + _PrintDistribution(target.GetDistributionType(), target.GetDistributionRange(), "\t\t"); + } +} + +void ResultParser::_PrintTimeSpan(const TimeSpan& timeSpan) +{ + _Print("\tduration: %us\n", timeSpan.GetDuration()); + _Print("\twarm up time: %us\n", timeSpan.GetWarmup()); + _Print("\tcool down time: %us\n", timeSpan.GetCooldown()); + if (timeSpan.GetDisableAffinity()) + { + _Print("\taffinity disabled\n"); + } + if (timeSpan.GetMeasureLatency()) + { + _Print("\tmeasuring latency\n"); + } + if (timeSpan.GetCalculateIopsStdDev()) + { + _Print("\tgathering IOPS at intervals of %ums\n", timeSpan.GetIoBucketDurationInMilliseconds()); + } + _Print("\trandom seed: %u\n", timeSpan.GetRandSeed()); + if (timeSpan.GetThreadCount() != 0) + { + _Print("\tthread pool with %u threads\n", timeSpan.GetThreadCount()); + _Print("\tnumber of outstanding I/O operations per thread: %d\n", timeSpan.GetRequestCount()); + } + + const auto& vAffinity = timeSpan.GetAffinityAssignments(); + if ( vAffinity.size() > 0) + { + _Print("\tadvanced affinity round robin (group/core): "); + for (unsigned int x = 0; x < vAffinity.size(); ++x) + { + _Print("%u/%u", vAffinity[x].wGroup, vAffinity[x].bProc); + if (x < vAffinity.size() - 1) + { + _Print(", "); + } + } + _Print("\n"); + } + + if (timeSpan.GetRandomWriteData()) + { + _Print("\tgenerating random data for each write IO\n"); + _Print("\t WARNING: this increases the CPU cost of issuing writes and should only\n"); + _Print("\t be compared to other results using the -Zr flag\n"); + } + + vector vTargets(timeSpan.GetTargets()); + for (auto i = vTargets.begin(); i != vTargets.end(); i++) + { + _PrintTarget(*i, (timeSpan.GetThreadCount() == 0), (timeSpan.GetThreadCount() == 0 || timeSpan.GetRequestCount() == 0), timeSpan.GetCompletionRoutines()); + } +} + +void ResultParser::_PrintProfile(const Profile& profile) +{ + _Print("\nCommand Line: %s\n", profile.GetCmdLine().c_str()); + _Print("\n"); + if (g_ExperimentFlags) + { + _Print("Experiment Flags: 0x%x (%u)\n", g_ExperimentFlags, g_ExperimentFlags); + _Print("\n"); + } + _Print("Input parameters:\n\n"); + if (profile.GetVerbose()) + { + _Print("\tusing verbose mode\n"); + } + + const vector& vTimeSpans = profile.GetTimeSpans(); + int c = 1; + for (auto i = vTimeSpans.begin(); i != vTimeSpans.end(); i++) + { + _Print("\ttimespan: %3d\n", c++); + _Print("\t-------------\n"); + _PrintTimeSpan(*i); + _Print("\n"); + } +} + +void ResultParser::_PrintSystemInfo(const SystemInformation& system) +{ + _Print(system.GetText().c_str()); +} + +void ResultParser::_PrintCpuUtilization(const Results& results, const SystemInformation& system) +{ + const auto& topo = system.processorTopology; + size_t procCount = results.vSystemProcessorPerfInfo.size(); + size_t baseProc = 0; + BYTE efficiencyClass = 0; + BYTE processorCore = 0; + + bool fMultiSocket = topo._vProcessorSocketInformation.size() > 1; + bool fMultiNode = topo._vProcessorNumaInformation.size() > 1; + bool fMultiGroup = topo._vProcessorGroupInformation.size() > 1; + + // + // Columns dynamically expand based on whether the system has multiple of the following, + // in hierarchical order, followed by CPU #: + // + // Socket NUMA Group Core Class + // + // Note that core & cpu number are group-relative, not absolute (or NUMA or socket relative) + // + + _Print("\n"); + if (fMultiSocket) { _Print("Socket | "); } + if (fMultiNode) { _Print("Node | "); } + if (fMultiGroup) { _Print("Group | "); } + if (topo._fSMT) { _Print("Core | "); } + if (topo._ubPerformanceEfficiencyClass) { _Print("Class | "); } + _Print("CPU | Usage | User | Kernel | Idle\n"); + if (fMultiSocket) { _Print("---------"); } + if (fMultiNode) { _Print("-------"); } + if (fMultiGroup) { _Print("--------"); } + if (topo._fSMT) { _Print("-------"); } + if (topo._ubPerformanceEfficiencyClass) { _Print("--------"); } + _Print("----------------------------------------\n"); + + double busyTime = 0; + double totalIdleTime = 0; + double totalUserTime = 0; + double totalKrnlTime = 0; + + for (const auto& group : topo._vProcessorGroupInformation) { + + // Sanity assert - results are sized to the sum of active processors + assert(baseProc + group._activeProcessorCount <= procCount); + + for (BYTE processor = 0; processor < group._activeProcessorCount; processor++) { + + long long fTime = results.vSystemProcessorPerfInfo[baseProc + processor].KernelTime.QuadPart + + results.vSystemProcessorPerfInfo[baseProc + processor].UserTime.QuadPart; + + double idleTime = 100.0 * results.vSystemProcessorPerfInfo[baseProc + processor].IdleTime.QuadPart / fTime; + double krnlTime = 100.0 * results.vSystemProcessorPerfInfo[baseProc + processor].KernelTime.QuadPart / fTime; + double userTime = 100.0 * results.vSystemProcessorPerfInfo[baseProc + processor].UserTime.QuadPart / fTime; + double usedTime = (krnlTime - idleTime) + userTime; + + if (fMultiSocket) { + _Print("%7u| ", topo.GetSocketOfProcessor(group._groupNumber, processor)); + } + if (fMultiNode) { + _Print("%5u| ", topo.GetNumaOfProcessor(group._groupNumber, processor)); + } + if (fMultiGroup) { + _Print("%6u| ", group._groupNumber); + } + processorCore = topo.GetCoreOfProcessor(group._groupNumber, processor, efficiencyClass); + if (topo._fSMT){ + _Print("%5u| ", processorCore); + } + if (topo._ubPerformanceEfficiencyClass) { + _Print("%5u%c| ", + efficiencyClass, + efficiencyClass == topo._ubPerformanceEfficiencyClass ? 'P' : ' '); + } + + _Print("%4u| %6.2lf%%| %6.2lf%%| %6.2lf%%| %6.2lf%%\n", + processor, + usedTime, + userTime, + krnlTime - idleTime, + idleTime); + + busyTime += usedTime; + totalIdleTime += idleTime; + totalUserTime += userTime; + totalKrnlTime += krnlTime; + } + + baseProc += group._activeProcessorCount; + } + + assert(baseProc == procCount); + + if (fMultiSocket) { _Print("---------"); } + if (fMultiNode) { _Print("-------"); } + if (fMultiGroup) { _Print("--------"); } + if (topo._fSMT) { _Print("-------"); } + if (topo._ubPerformanceEfficiencyClass) { _Print("--------"); } + _Print("----------------------------------------\n"); + + if (fMultiSocket) { _Print(" "); } + if (fMultiNode) { _Print(" "); } + if (fMultiGroup) { _Print(" "); } + if (topo._fSMT) { _Print(" "); } + if (topo._ubPerformanceEfficiencyClass) { _Print(" "); } + + _Print("avg.| %6.2lf%%| %6.2lf%%| %6.2lf%%| %6.2lf%%\n", + busyTime / procCount, + totalUserTime / procCount, + (totalKrnlTime - totalIdleTime) / procCount, + totalIdleTime / procCount); +} + +void ResultParser::_PrintSectionFieldNames(const TimeSpan& timeSpan) +{ + _Print("thread | bytes | I/Os | MiB/s | I/O per s %s%s%s| file\n", + timeSpan.GetMeasureLatency() ? "| AvgLat " : "", + timeSpan.GetCalculateIopsStdDev() ? "| IopsStdDev " : "", + timeSpan.GetMeasureLatency() ? "| LatStdDev " : ""); +} + +void ResultParser::_PrintSectionBorderLine(const TimeSpan& timeSpan) +{ + _Print("------------------------------------------------------------------%s%s%s------------\n", + timeSpan.GetMeasureLatency() ? "-----------" : "" , + timeSpan.GetCalculateIopsStdDev() ? "-------------" : "", + timeSpan.GetMeasureLatency() ? "------------" : ""); +} + +void ResultParser::_PrintSection(_SectionEnum section, const TimeSpan& timeSpan, const Results& results) +{ + double fTime = PerfTimer::PerfTimeToSeconds(results.ullTimeCount); + double fBucketTime = timeSpan.GetIoBucketDurationInMilliseconds() / 1000.0; + UINT64 ullTotalBytesCount = 0; + UINT64 ullTotalIOCount = 0; + Histogram totalLatencyHistogram; + IoBucketizer totalIoBucketizer; + + _PrintSectionFieldNames(timeSpan); + + _PrintSectionBorderLine(timeSpan); + + for (unsigned int iThread = 0; iThread < results.vThreadResults.size(); ++iThread) + { + const ThreadResults& threadResults = results.vThreadResults[iThread]; + for (unsigned int iFile = 0; iFile < threadResults.vTargetResults.size(); iFile++) + { + const TargetResults& targetResults = threadResults.vTargetResults[iFile]; + + UINT64 ullBytesCount = 0; + UINT64 ullIOCount = 0; + + Histogram latencyHistogram; + IoBucketizer ioBucketizer; + + if ((section == _SectionEnum::WRITE) || (section == _SectionEnum::TOTAL)) + { + ullBytesCount += targetResults.ullWriteBytesCount; + ullIOCount += targetResults.ullWriteIOCount; + + if (timeSpan.GetMeasureLatency()) + { + latencyHistogram.Merge(targetResults.writeLatencyHistogram); + totalLatencyHistogram.Merge(targetResults.writeLatencyHistogram); + } + + if (timeSpan.GetCalculateIopsStdDev()) + { + ioBucketizer.Merge(targetResults.writeBucketizer); + totalIoBucketizer.Merge(targetResults.writeBucketizer); + } + } + + if ((section == _SectionEnum::READ) || (section == _SectionEnum::TOTAL)) + { + ullBytesCount += targetResults.ullReadBytesCount; + ullIOCount += targetResults.ullReadIOCount; + + if (timeSpan.GetMeasureLatency()) + { + latencyHistogram.Merge(targetResults.readLatencyHistogram); + totalLatencyHistogram.Merge(targetResults.readLatencyHistogram); + } + + if (timeSpan.GetCalculateIopsStdDev()) + { + ioBucketizer.Merge(targetResults.readBucketizer); + totalIoBucketizer.Merge(targetResults.readBucketizer); + } + } + + _Print("%6u | %15llu | %12llu | %10.2f | %10.2f", + iThread, + ullBytesCount, + ullIOCount, + (double)ullBytesCount / 1024 / 1024 / fTime, + (double)ullIOCount / fTime); + + if (timeSpan.GetMeasureLatency()) + { + _Print(" | %8.3f", latencyHistogram.GetAvg() / 1000); + } + + if (timeSpan.GetCalculateIopsStdDev()) + { + double iopsStdDev = ioBucketizer.GetStandardDeviationIOPS() / fBucketTime; + _Print(" | %10.2f", iopsStdDev); + } + + if (timeSpan.GetMeasureLatency()) + { + if (latencyHistogram.GetSampleSize() > 0) + { + double latStdDev = latencyHistogram.GetStandardDeviation() / 1000; + _Print(" | %8.3f", latStdDev); + } + else + { + _Print(" | N/A"); + } + } + + _Print(" | %s (", targetResults.sPath.c_str()); + + _DisplayFileSize(targetResults.ullFileSize); + _Print(")\n"); + + ullTotalBytesCount += ullBytesCount; + ullTotalIOCount += ullIOCount; + } + } + + _PrintSectionBorderLine(timeSpan); + + _Print("total: %15llu | %12llu | %10.2f | %10.2f", + ullTotalBytesCount, + ullTotalIOCount, + (double)ullTotalBytesCount / 1024 / 1024 / fTime, + (double)ullTotalIOCount / fTime); + + if (timeSpan.GetMeasureLatency()) + { + _Print(" | %8.3f", totalLatencyHistogram.GetAvg()/1000); + } + + if (timeSpan.GetCalculateIopsStdDev()) + { + double iopsStdDev = totalIoBucketizer.GetStandardDeviationIOPS() / fBucketTime; + _Print(" | %10.2f", iopsStdDev); + } + + if (timeSpan.GetMeasureLatency()) + { + if (totalLatencyHistogram.GetSampleSize() > 0) + { + double latStdDev = totalLatencyHistogram.GetStandardDeviation() / 1000; + _Print(" | %8.3f", latStdDev); + } + else + { + _Print(" | N/A"); + } + } + + _Print("\n"); + + /// CrystalDiskMark + if (section == _SectionEnum::TOTAL) + { + _totalScore = (int)(ullTotalBytesCount / 1000 / fTime); + if (timeSpan.GetMeasureLatency()) + { + _averageLatency = totalLatencyHistogram.GetAvg() / 1000; + } + } +} + +void ResultParser::_PrintLatencyPercentiles(const Results& results) +{ + //Print one chart for each target IF more than one target + unordered_map> perTargetReadHistogram; + unordered_map> perTargetWriteHistogram; + unordered_map> perTargetTotalHistogram; + + for (const auto& thread : results.vThreadResults) + { + for (const auto& target : thread.vTargetResults) + { + std::string path = target.sPath; + + perTargetReadHistogram[path].Merge(target.readLatencyHistogram); + + perTargetWriteHistogram[path].Merge(target.writeLatencyHistogram); + + perTargetTotalHistogram[path].Merge(target.readLatencyHistogram); + perTargetTotalHistogram[path].Merge(target.writeLatencyHistogram); + } + } + + //Skip if only one target + if (perTargetTotalHistogram.size() > 1) { + for (auto i : perTargetTotalHistogram) + { + std::string path = i.first; + _Print("\nLatency distribution: %s\n", path.c_str()); + _PrintLatencyChart(perTargetReadHistogram[path], + perTargetWriteHistogram[path], + perTargetTotalHistogram[path]); + } + } + + //Print one chart for the latencies aggregated across all targets + Histogram readLatencyHistogram; + Histogram writeLatencyHistogram; + Histogram totalLatencyHistogram; + + for (const auto& thread : results.vThreadResults) + { + for (const auto& target : thread.vTargetResults) + { + readLatencyHistogram.Merge(target.readLatencyHistogram); + + writeLatencyHistogram.Merge(target.writeLatencyHistogram); + + totalLatencyHistogram.Merge(target.writeLatencyHistogram); + totalLatencyHistogram.Merge(target.readLatencyHistogram); + } + } + + _Print("\nTotal latency distribution:\n"); + _PrintLatencyChart(readLatencyHistogram, writeLatencyHistogram, totalLatencyHistogram); +} + +void ResultParser::_PrintLatencyChart(const Histogram& readLatencyHistogram, + const Histogram& writeLatencyHistogram, + const Histogram& totalLatencyHistogram) +{ + bool fHasReads = readLatencyHistogram.GetSampleSize() > 0; + bool fHasWrites = writeLatencyHistogram.GetSampleSize() > 0; + + _Print(" %%-ile | Read (ms) | Write (ms) | Total (ms)\n"); + _Print("----------------------------------------------\n"); + + string readMin = + fHasReads ? + Util::DoubleToStringHelper(readLatencyHistogram.GetMin()/1000) : + "N/A"; + + string writeMin = + fHasWrites ? + Util::DoubleToStringHelper(writeLatencyHistogram.GetMin() / 1000) : + "N/A"; + + _Print(" min | %10s | %10s | %10.3lf\n", + readMin.c_str(), writeMin.c_str(), totalLatencyHistogram.GetMin()/1000); + + PercentileDescriptor percentiles[] = + { + { 0.25, "25th" }, + { 0.50, "50th" }, + { 0.75, "75th" }, + { 0.90, "90th" }, + { 0.95, "95th" }, + { 0.99, "99th" }, + { 0.999, "3-nines" }, + { 0.9999, "4-nines" }, + { 0.99999, "5-nines" }, + { 0.999999, "6-nines" }, + { 0.9999999, "7-nines" }, + { 0.99999999, "8-nines" }, + { 0.999999999, "9-nines" }, + }; + + for (auto p : percentiles) + { + string readPercentile = + fHasReads ? + Util::DoubleToStringHelper(readLatencyHistogram.GetPercentile(p.Percentile) / 1000) : + "N/A"; + + string writePercentile = + fHasWrites ? + Util::DoubleToStringHelper(writeLatencyHistogram.GetPercentile(p.Percentile) / 1000) : + "N/A"; + + _Print("%7s | %10s | %10s | %10.3lf\n", + p.Name.c_str(), + readPercentile.c_str(), + writePercentile.c_str(), + totalLatencyHistogram.GetPercentile(p.Percentile)/1000); + } + + string readMax = Util::DoubleToStringHelper(readLatencyHistogram.GetMax() / 1000); + string writeMax = Util::DoubleToStringHelper(writeLatencyHistogram.GetMax() / 1000); + + _Print(" max | %10s | %10s | %10.3lf\n", + fHasReads ? readMax.c_str() : "N/A", + fHasWrites ? writeMax.c_str() : "N/A", + totalLatencyHistogram.GetMax()/1000); +} + +string ResultParser::ParseProfile(const Profile& profile) +{ + _sResult.clear(); + _PrintProfile(profile); + return _sResult; +} + +void ResultParser::_PrintWaitStats(const Results &results) +{ + _Print("Wait Statistics\n"); + _Print("thread | completion wait | throttle wait - sleep | lookaside | 0 - 7+ complete per lookaside\n"); + _Print("-----------------------------------------------------------------------------------------------\n"); + for (unsigned int iThread = 0; iThread < results.vThreadResults.size(); ++iThread) + { + const ThreadResults& threadResults = results.vThreadResults[iThread]; + _Print( + "%6u | %15llu | %13llu - %6llu | %9llu | %llu %llu %llu %llu %llu %llu %llu %llu\n", + iThread, + threadResults.WaitStats.Wait, + threadResults.WaitStats.ThrottleWait, + threadResults.WaitStats.ThrottleSleep, + threadResults.WaitStats.Lookaside, + threadResults.WaitStats.LookasideCompletion[0], + threadResults.WaitStats.LookasideCompletion[1], + threadResults.WaitStats.LookasideCompletion[2], + threadResults.WaitStats.LookasideCompletion[3], + threadResults.WaitStats.LookasideCompletion[4], + threadResults.WaitStats.LookasideCompletion[5], + threadResults.WaitStats.LookasideCompletion[6], + threadResults.WaitStats.LookasideCompletion[7]); + } +} + +string ResultParser::ParseResults(const Profile& profile, const SystemInformation& system, vector vResults) +{ + _sResult.clear(); + + _PrintProfile(profile); + _PrintSystemInfo(system); + + for (size_t iResult = 0; iResult < vResults.size(); iResult++) + { + _Print("\nResults for timespan %d:\n", iResult + 1); + _Print("*******************************************************************************\n"); + + const Results& results = vResults[iResult]; + const TimeSpan& timeSpan = profile.GetTimeSpans()[iResult]; + + double fTime = PerfTimer::PerfTimeToSeconds(results.ullTimeCount); //test duration + + char szFloatBuffer[1024]; + + // There either is a fixed number of threads for all files to share (GetThreadCount() > 0) or a number of threads per file. + // In the latter case vThreadResults.size() == number of threads per file * file count + size_t ulThreadCnt = (timeSpan.GetThreadCount() > 0) ? timeSpan.GetThreadCount() : results.vThreadResults.size(); + + if (fTime < 0.0000001) + { + _Print("The test was interrupted before the measurements began. No results are displayed.\n"); + } + else + { + // TODO: parameters.bCreateFile; + + _Print("\n"); + sprintf_s(szFloatBuffer, sizeof(szFloatBuffer), "actual test time:\t%.2lfs\n", fTime); + _Print("%s", szFloatBuffer); + _Print("thread count:\t\t%u\n", ulThreadCnt); + + if (timeSpan.GetThreadCount() != 0 && timeSpan.GetRequestCount() != 0) { + _Print("request count:\t\t%u\n", timeSpan.GetRequestCount()); + } + + _PrintCpuUtilization(results, system); + _PrintEffectiveDistributions(results); + + _Print("\nTotal IO\n"); + _PrintSection(_SectionEnum::TOTAL, timeSpan, results); + + _Print("\nRead IO\n"); + _PrintSection(_SectionEnum::READ, timeSpan, results); + + _Print("\nWrite IO\n"); + _PrintSection(_SectionEnum::WRITE, timeSpan, results); + + if (timeSpan.GetMeasureLatency()) + { + _PrintLatencyPercentiles(results); + } + + //etw + if (results.fUseETW) + { + _DisplayETW(results.EtwMask, results.EtwEventCounters); + _DisplayETWSessionInfo(results.EtwSessionInfo); + } + + // wait stats + if (profile.GetVerboseStats()) + { + _Print("\n"); + _PrintWaitStats(results); + } + } + } + + if (vResults.size() > 1) + { + _Print("\n\nTotals:\n"); + _Print("*******************************************************************************\n\n"); + _Print("type | bytes | I/Os | MiB/s | I/O per s\n"); + _Print("-------------------------------------------------------------------------------\n"); + + + UINT64 cbTotalWritten = 0; + UINT64 cbTotalRead = 0; + UINT64 cTotalWriteIO = 0; + UINT64 cTotalReadIO = 0; + UINT64 cTotalTicks = 0; + for (auto pResults = vResults.begin(); pResults != vResults.end(); pResults++) + { + double time = PerfTimer::PerfTimeToSeconds(pResults->ullTimeCount); + if (time >= 0.0000001) // skip timespans that were interrupted + { + cTotalTicks += pResults->ullTimeCount; + auto vThreadResults = pResults->vThreadResults; + for (auto pThreadResults = vThreadResults.begin(); pThreadResults != vThreadResults.end(); pThreadResults++) + { + for (auto pTargetResults = pThreadResults->vTargetResults.begin(); pTargetResults != pThreadResults->vTargetResults.end(); pTargetResults++) + { + cbTotalRead += pTargetResults->ullReadBytesCount; + cbTotalWritten += pTargetResults->ullWriteBytesCount; + cTotalReadIO += pTargetResults->ullReadIOCount; + cTotalWriteIO += pTargetResults->ullWriteIOCount; + } + } + } + } + + double totalTime = PerfTimer::PerfTimeToSeconds(cTotalTicks); + + _Print("write | %15I64u | %12I64u | %10.2lf | %10.2lf\n", + cbTotalWritten, + cTotalWriteIO, + (double)cbTotalWritten / 1024 / 1024 / totalTime, + (double)cTotalWriteIO / totalTime); + + _Print("read | %15I64u | %12I64u | %10.2lf | %10.2lf\n", + cbTotalRead, + cTotalReadIO, + (double)cbTotalRead / 1024 / 1024 / totalTime, + (double)cTotalReadIO / totalTime); + _Print("-------------------------------------------------------------------------------\n"); + _Print("total | %15I64u | %12I64u | %10.2lf | %10.2lf\n\n", + cbTotalRead + cbTotalWritten, + cTotalReadIO + cTotalWriteIO, + (double)(cbTotalRead + cbTotalWritten) / 1024 / 1024 / totalTime, + (double)(cTotalReadIO + cTotalWriteIO) / totalTime); + + _Print("total test time:\t%.2lfs\n", totalTime); + } + + return _sResult; +} diff --git a/CristalDiskMark/source/diskspd22/SECURITY.md b/CristalDiskMark/source/diskspd22/SECURITY.md new file mode 100644 index 0000000..869fdfe --- /dev/null +++ b/CristalDiskMark/source/diskspd22/SECURITY.md @@ -0,0 +1,41 @@ + + +## Security + +Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/). + +If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/opensource/security/definition), please report it to us as described below. + +## Reporting Security Issues + +**Please do not report security vulnerabilities through public GitHub issues.** + +Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/opensource/security/create-report). + +If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/opensource/security/pgpkey). + +You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://aka.ms/opensource/security/msrc). + +Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue: + + * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) + * Full paths of source file(s) related to the manifestation of the issue + * The location of the affected source code (tag/branch/commit or direct URL) + * Any special configuration required to reproduce the issue + * Step-by-step instructions to reproduce the issue + * Proof-of-concept or exploit code (if possible) + * Impact of the issue, including how an attacker might exploit the issue + +This information will help us triage your report more quickly. + +If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/opensource/security/bounty) page for more details about our active programs. + +## Preferred Languages + +We prefer all communications to be in English. + +## Policy + +Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/opensource/security/cvd). + + diff --git a/CristalDiskMark/source/diskspd22/UnitTests/CmdLineParser/CmdLineParser.UnitTests.cpp b/CristalDiskMark/source/diskspd22/UnitTests/CmdLineParser/CmdLineParser.UnitTests.cpp new file mode 100644 index 0000000..036e18c --- /dev/null +++ b/CristalDiskMark/source/diskspd22/UnitTests/CmdLineParser/CmdLineParser.UnitTests.cpp @@ -0,0 +1,4771 @@ +/* + +DISKSPD + +Copyright(c) Microsoft Corporation +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#include "StdAfx.h" +#include "CmdLineParser.h" +#include "CmdLineParser.UnitTests.h" +#include + +using namespace WEX::TestExecution; +using namespace WEX::Logging; + +namespace UnitTests +{ + bool ModuleSetup() + { + return true; + } + + bool ModuleCleanup() + { + return true; + } + + bool CmdLineParserUnitTests::ClassSetup() + { + return true; + } + + bool CmdLineParserUnitTests::ClassCleanup() + { + return true; + } + + bool CmdLineParserUnitTests::MethodSetup() + { + return true; + } + + bool CmdLineParserUnitTests::MethodCleanup() + { + return true; + } + + void CmdLineParserUnitTests::Test_GetSizeInBytes() + { + CmdLineParser p; + UINT64 ullResult = 0; + VERIFY_IS_TRUE(p._GetSizeInBytes("0", ullResult, nullptr)); + VERIFY_IS_TRUE(ullResult == 0); + + VERIFY_IS_TRUE(p._GetSizeInBytes("1", ullResult, nullptr)); + VERIFY_IS_TRUE(ullResult == 1); + + VERIFY_IS_TRUE(p._GetSizeInBytes("2", ullResult, nullptr)); + VERIFY_IS_TRUE(ullResult == 2); + + VERIFY_IS_TRUE(p._GetSizeInBytes("10", ullResult, nullptr)); + VERIFY_IS_TRUE(ullResult == 10); + + VERIFY_IS_TRUE(p._GetSizeInBytes("4096", ullResult, nullptr)); + VERIFY_IS_TRUE(ullResult == 4096); + + VERIFY_IS_TRUE(p._GetSizeInBytes("123908798324", ullResult, nullptr)); + VERIFY_IS_TRUE(ullResult == 123908798324); + + // _GetSizeInBytes shouldn't modify ullResult on if the input string is incorrect + ullResult = 9; + VERIFY_IS_TRUE(p._GetSizeInBytes("10a", ullResult, nullptr) == false); + VERIFY_IS_TRUE(ullResult == 9); + + // block + VERIFY_IS_TRUE(p._GetSizeInBytes("1b", ullResult, nullptr)); + VERIFY_IS_TRUE(ullResult == p._dwBlockSize); + + VERIFY_IS_TRUE(p._GetSizeInBytes("3B", ullResult, nullptr)); + VERIFY_IS_TRUE(ullResult == 3 * p._dwBlockSize); + + VERIFY_IS_TRUE(p._GetSizeInBytes("30b", ullResult, nullptr)); + VERIFY_IS_TRUE(ullResult == 30 * p._dwBlockSize); + + VERIFY_IS_TRUE(p._GetSizeInBytes("30 b", ullResult, nullptr) == false); + VERIFY_IS_TRUE(p._GetSizeInBytes("30 B", ullResult, nullptr) == false); + + // KB + VERIFY_IS_TRUE(p._GetSizeInBytes("1K", ullResult, nullptr)); + VERIFY_IS_TRUE(ullResult == 1024); + + VERIFY_IS_TRUE(p._GetSizeInBytes("3K", ullResult, nullptr)); + VERIFY_IS_TRUE(ullResult == 3 * 1024); + + VERIFY_IS_TRUE(p._GetSizeInBytes("30K", ullResult, nullptr)); + VERIFY_IS_TRUE(ullResult == 30 * 1024); + + VERIFY_IS_TRUE(p._GetSizeInBytes("30 K", ullResult, nullptr) == false); + VERIFY_IS_TRUE(p._GetSizeInBytes("30KB", ullResult, nullptr) == false); + + // MB + VERIFY_IS_TRUE(p._GetSizeInBytes("1M", ullResult, nullptr)); + VERIFY_IS_TRUE(ullResult == 1024 * 1024); + + VERIFY_IS_TRUE(p._GetSizeInBytes("4M", ullResult, nullptr)); + VERIFY_IS_TRUE(ullResult == 4 * 1024 * 1024); + + VERIFY_IS_TRUE(p._GetSizeInBytes("50M", ullResult, nullptr)); + VERIFY_IS_TRUE(ullResult == 50 * 1024 * 1024); + + VERIFY_IS_TRUE(p._GetSizeInBytes("40 M", ullResult, nullptr) == false); + VERIFY_IS_TRUE(p._GetSizeInBytes("40MB", ullResult, nullptr) == false); + + // GB + VERIFY_IS_TRUE(p._GetSizeInBytes("1G", ullResult, nullptr)); + VERIFY_IS_TRUE(ullResult == 1024 * 1024 * 1024); + + VERIFY_IS_TRUE(p._GetSizeInBytes("6G", ullResult, nullptr)); + VERIFY_IS_TRUE(ullResult == (UINT64)6 * 1024 * 1024 * 1024); + + VERIFY_IS_TRUE(p._GetSizeInBytes("70G", ullResult, nullptr)); + VERIFY_IS_TRUE(ullResult == (UINT64)70 * 1024 * 1024 * 1024); + + VERIFY_IS_TRUE(p._GetSizeInBytes("70 G", ullResult, nullptr) == false); + VERIFY_IS_TRUE(p._GetSizeInBytes("70GB", ullResult, nullptr) == false); + + // TB + VERIFY_IS_TRUE(p._GetSizeInBytes("1T", ullResult, nullptr)); + VERIFY_IS_TRUE(ullResult == (UINT64)1024 * 1024 * 1024 * 1024); + + VERIFY_IS_TRUE(p._GetSizeInBytes("6T", ullResult, nullptr)); + VERIFY_IS_TRUE(ullResult == (UINT64)6 * 1024 * 1024 * 1024 * 1024); + + VERIFY_IS_TRUE(p._GetSizeInBytes("70T", ullResult, nullptr)); + VERIFY_IS_TRUE(ullResult == (UINT64)70 * 1024 * 1024 * 1024 * 1024); + + VERIFY_IS_TRUE(p._GetSizeInBytes("70 T", ullResult, nullptr) == false); + VERIFY_IS_TRUE(p._GetSizeInBytes("70TB", ullResult, nullptr) == false); + // check overflows + // MAXUINT64 == 18446744073709551615 + ullResult = 0; + VERIFY_IS_TRUE(p._GetSizeInBytes("18446744073709551615", ullResult, nullptr)); + VERIFY_IS_TRUE(ullResult == MAXUINT64); + + // MAXUINT64 + 1 + VERIFY_IS_TRUE(p._GetSizeInBytes("18446744073709551616", ullResult, nullptr) == false); + + // MAXUINT64 / 1024 = 18014398509481983 + ullResult = 0; + VERIFY_IS_TRUE(p._GetSizeInBytes("18014398509481983K", ullResult, nullptr)); + VERIFY_IS_TRUE(ullResult == (MAXUINT64 >> 10) << 10); + VERIFY_IS_TRUE(p._GetSizeInBytes("18014398509481984K", ullResult, nullptr) == false); + + // MAXUINT64 / 1024^2 = 17592186044415 + ullResult = 0; + VERIFY_IS_TRUE(p._GetSizeInBytes("17592186044415M", ullResult, nullptr)); + VERIFY_IS_TRUE(ullResult == (MAXUINT64 >> 20) << 20); + VERIFY_IS_TRUE(p._GetSizeInBytes("17592186044416M", ullResult, nullptr) == false); + + // MAXUINT64 / 1024^3 = 17179869183 + ullResult = 0; + VERIFY_IS_TRUE(p._GetSizeInBytes("17179869183G", ullResult, nullptr)); + VERIFY_IS_TRUE(ullResult == (MAXUINT64 >> 30) << 30); + VERIFY_IS_TRUE(p._GetSizeInBytes("17179869184G", ullResult, nullptr) == false); + + // block + p._dwBlockSize = 1024; + ullResult = 0; + VERIFY_IS_TRUE(p._GetSizeInBytes("18014398509481983b", ullResult, nullptr)); + VERIFY_IS_TRUE(ullResult == (MAXUINT64 >> 10) << 10); + VERIFY_IS_TRUE(p._GetSizeInBytes("18014398509481984b", ullResult, nullptr) == false); + } + + void CmdLineParserUnitTests::TestParseCmdLineAssignAffinity() + { + CmdLineParser p; + struct Synchronization s = {}; + + // base case + { + Profile profile; + const char *argv[] = { "foo", "-a", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == true); + + vector vSpans(profile.GetTimeSpans()); + VERIFY_ARE_EQUAL(vSpans.size(), (size_t)1); + VERIFY_IS_TRUE(vSpans[0].GetDisableAffinity() == false); + + const auto& vAffinity(vSpans[0].GetAffinityAssignments()); + VERIFY_IS_TRUE(vAffinity.empty()); + } + + // base case + { + Profile profile; + const char *argv[] = { "foo", "-ag", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == true); + + vector vSpans(profile.GetTimeSpans()); + VERIFY_ARE_EQUAL(vSpans.size(), (size_t)1); + VERIFY_IS_TRUE(vSpans[0].GetDisableAffinity() == false); + + const auto& vAffinity(vSpans[0].GetAffinityAssignments()); + VERIFY_IS_TRUE(vAffinity.empty()); + } + + // no group spec case + { + Profile profile; + const char *argv[] = { "foo", "-a1,4,6", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == true); + + vector vSpans(profile.GetTimeSpans()); + VERIFY_ARE_EQUAL(vSpans.size(), (size_t)1); + VERIFY_IS_TRUE(vSpans[0].GetDisableAffinity() == false); + + const auto& vAffinity(vSpans[0].GetAffinityAssignments()); + VERIFY_ARE_EQUAL(vAffinity.size(), (size_t)3); + VERIFY_ARE_EQUAL(vAffinity[0].wGroup, 0); + VERIFY_ARE_EQUAL(vAffinity[0].bProc, (BYTE)1); + VERIFY_ARE_EQUAL(vAffinity[1].wGroup, 0); + VERIFY_ARE_EQUAL(vAffinity[1].bProc, (BYTE)4); + VERIFY_ARE_EQUAL(vAffinity[2].wGroup, 0); + VERIFY_ARE_EQUAL(vAffinity[2].bProc, (BYTE)6); + } + + // single group spec + { + Profile profile; + const char *argv[] = { "foo", "-ag0,1,4,6", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == true); + + vector vSpans(profile.GetTimeSpans()); + VERIFY_ARE_EQUAL(vSpans.size(), (size_t)1); + VERIFY_IS_TRUE(vSpans[0].GetDisableAffinity() == false); + + const auto& vAffinity(vSpans[0].GetAffinityAssignments()); + VERIFY_ARE_EQUAL(vAffinity.size(), (size_t)3); + VERIFY_ARE_EQUAL(vAffinity[0].wGroup, 0); + VERIFY_ARE_EQUAL(vAffinity[0].bProc, (BYTE)1); + VERIFY_ARE_EQUAL(vAffinity[1].wGroup, 0); + VERIFY_ARE_EQUAL(vAffinity[1].bProc, (BYTE)4); + VERIFY_ARE_EQUAL(vAffinity[2].wGroup, 0); + VERIFY_ARE_EQUAL(vAffinity[2].bProc, (BYTE)6); + } + + // multiple group spec + { + Profile profile; + const char *argv[] = { "foo", "-ag0,1,4,6,g1,2,5,7", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == true); + + vector vSpans(profile.GetTimeSpans()); + VERIFY_ARE_EQUAL(vSpans.size(), (size_t)1); + VERIFY_IS_TRUE(vSpans[0].GetDisableAffinity() == false); + + const auto& vAffinity(vSpans[0].GetAffinityAssignments()); + VERIFY_ARE_EQUAL(vAffinity.size(), (size_t)6); + VERIFY_ARE_EQUAL(vAffinity[0].wGroup, 0); + VERIFY_ARE_EQUAL(vAffinity[0].bProc, (BYTE)1); + VERIFY_ARE_EQUAL(vAffinity[1].wGroup, 0); + VERIFY_ARE_EQUAL(vAffinity[1].bProc, (BYTE)4); + VERIFY_ARE_EQUAL(vAffinity[2].wGroup, 0); + VERIFY_ARE_EQUAL(vAffinity[2].bProc, (BYTE)6); + VERIFY_ARE_EQUAL(vAffinity[3].wGroup, 1); + VERIFY_ARE_EQUAL(vAffinity[3].bProc, (BYTE)2); + VERIFY_ARE_EQUAL(vAffinity[4].wGroup, 1); + VERIFY_ARE_EQUAL(vAffinity[4].bProc, (BYTE)5); + VERIFY_ARE_EQUAL(vAffinity[5].wGroup, 1); + VERIFY_ARE_EQUAL(vAffinity[5].bProc, (BYTE)7); + } + + // multiple group spec across two instances of -ag + { + Profile profile; + const char *argv[] = { "foo", "-ag0,1,4,6", "-ag1,2,5,7", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == true); + + vector vSpans(profile.GetTimeSpans()); + VERIFY_ARE_EQUAL(vSpans.size(), (size_t)1); + VERIFY_IS_TRUE(vSpans[0].GetDisableAffinity() == false); + + const auto& vAffinity(vSpans[0].GetAffinityAssignments()); + VERIFY_ARE_EQUAL(vAffinity.size(), (size_t)6); + VERIFY_ARE_EQUAL(vAffinity[0].wGroup, 0); + VERIFY_ARE_EQUAL(vAffinity[0].bProc, (BYTE)1); + VERIFY_ARE_EQUAL(vAffinity[1].wGroup, 0); + VERIFY_ARE_EQUAL(vAffinity[1].bProc, (BYTE)4); + VERIFY_ARE_EQUAL(vAffinity[2].wGroup, 0); + VERIFY_ARE_EQUAL(vAffinity[2].bProc, (BYTE)6); + VERIFY_ARE_EQUAL(vAffinity[3].wGroup, 1); + VERIFY_ARE_EQUAL(vAffinity[3].bProc, (BYTE)2); + VERIFY_ARE_EQUAL(vAffinity[4].wGroup, 1); + VERIFY_ARE_EQUAL(vAffinity[4].bProc, (BYTE)5); + VERIFY_ARE_EQUAL(vAffinity[5].wGroup, 1); + VERIFY_ARE_EQUAL(vAffinity[5].bProc, (BYTE)7); + } + + // now various syntax error cases + // just group spec + { + Profile profile; + const char *argv[] = { "foo", "-ag0", "testfile.dat" }; + VERIFY_IS_FALSE(p.ParseCmdLine(_countof(argv), argv, &profile, &s)); + } + + // multiple g + { + Profile profile; + const char *argv[] = { "foo", "-agg", "testfile.dat" }; + VERIFY_IS_FALSE(p.ParseCmdLine(_countof(argv), argv, &profile, &s)); + } + + // group with no number + { + Profile profile; + const char *argv[] = { "foo", "-ag,0,1,2", "testfile.dat" }; + VERIFY_IS_FALSE(p.ParseCmdLine(_countof(argv), argv, &profile, &s)); + } + + // trailing , + { + Profile profile; + const char *argv[] = { "foo", "-a1,", "testfile.dat" }; + VERIFY_IS_FALSE(p.ParseCmdLine(_countof(argv), argv, &profile, &s)); + } + + // trailing , in group spec form + { + Profile profile; + const char *argv[] = { "foo", "-ag1,0,", "testfile.dat" }; + VERIFY_IS_FALSE(p.ParseCmdLine(_countof(argv), argv, &profile, &s)); + } + + // trailing g in group spec form + { + Profile profile; + const char *argv[] = { "foo", "-ag1,0,g", "testfile.dat" }; + VERIFY_IS_FALSE(p.ParseCmdLine(_countof(argv), argv, &profile, &s)); + } + + // trailing group spec form + { + Profile profile; + const char *argv[] = { "foo", "-ag1,0,g2", "testfile.dat" }; + VERIFY_IS_FALSE(p.ParseCmdLine(_countof(argv), argv, &profile, &s)); + } + + // junk chars + { + Profile profile; + const char *argv[] = { "foo", "-ax", "testfile.dat" }; + VERIFY_IS_FALSE(p.ParseCmdLine(_countof(argv), argv, &profile, &s)); + } + + // out-of-range processor index (BYTE) + { + Profile profile; + const char *argv[] = { "foo", "-ag0,300", "testfile.dat" }; + VERIFY_IS_FALSE(p.ParseCmdLine(_countof(argv), argv, &profile, &s)); + } + + // out-of-range group index (WORD) + { + Profile profile; + const char *argv[] = { "foo", "-ag70000,1", "testfile.dat" }; + VERIFY_IS_FALSE(p.ParseCmdLine(_countof(argv), argv, &profile, &s)); + } + } + + void CmdLineParserUnitTests::TestParseCmdLine() + { + CmdLineParser p; + Profile profile; + struct Synchronization s = {}; + const char *argv[] = { "foo", "-b4K", "-w84", "-a1,4,6", "testfile.dat", "testfile2.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == true); + VERIFY_IS_TRUE(profile.GetVerbose() == false); + VERIFY_IS_TRUE(profile.GetProgress() == 0); + VERIFY_IS_TRUE(profile.GetCmdLine().compare("foo -b4K -w84 -a1,4,6 testfile.dat testfile2.dat") == 0); + VERIFY_IS_TRUE(profile.GetEtwEnabled() == false); + VERIFY_IS_TRUE(profile.GetEtwProcess() == false); + VERIFY_IS_TRUE(profile.GetEtwThread() == false); + VERIFY_IS_TRUE(profile.GetEtwImageLoad() == false); + VERIFY_IS_TRUE(profile.GetEtwDiskIO() == false); + VERIFY_IS_TRUE(profile.GetEtwMemoryPageFaults() == false); + VERIFY_IS_TRUE(profile.GetEtwMemoryHardFaults() == false); + VERIFY_IS_TRUE(profile.GetEtwNetwork() == false); + VERIFY_IS_TRUE(profile.GetEtwRegistry() == false); + VERIFY_IS_TRUE(profile.GetEtwUsePagedMemory() == false); + VERIFY_IS_TRUE(profile.GetEtwUsePerfTimer() == false); + VERIFY_IS_TRUE(profile.GetEtwUseSystemTimer() == false); + VERIFY_IS_TRUE(profile.GetEtwUseCyclesCounter() == false); + + vector vSpans(profile.GetTimeSpans()); + VERIFY_ARE_EQUAL(vSpans.size(), (size_t)1); + VERIFY_ARE_EQUAL(vSpans[0].GetDuration(), (UINT32)10); + VERIFY_ARE_EQUAL(vSpans[0].GetWarmup(), (UINT32)5); + VERIFY_ARE_EQUAL(vSpans[0].GetCooldown(), (UINT32)0); + VERIFY_ARE_EQUAL(vSpans[0].GetRandSeed(), (UINT32)0); + VERIFY_ARE_EQUAL(vSpans[0].GetThreadCount(), (DWORD)0); + VERIFY_ARE_EQUAL(vSpans[0].GetRequestCount(), (DWORD)0); + VERIFY_IS_TRUE(vSpans[0].GetDisableAffinity() == false); + VERIFY_IS_TRUE(vSpans[0].GetCompletionRoutines() == false); + VERIFY_IS_TRUE(vSpans[0].GetMeasureLatency() == false); + VERIFY_IS_TRUE(vSpans[0].GetRandomWriteData() == false); + + const auto& vAffinity(vSpans[0].GetAffinityAssignments()); + VERIFY_ARE_EQUAL(vAffinity.size(), (size_t)3); + VERIFY_ARE_EQUAL(vAffinity[0].wGroup, 0); + VERIFY_ARE_EQUAL(vAffinity[0].bProc, (BYTE)1); + VERIFY_ARE_EQUAL(vAffinity[1].wGroup, 0); + VERIFY_ARE_EQUAL(vAffinity[1].bProc, (BYTE)4); + VERIFY_ARE_EQUAL(vAffinity[2].wGroup, 0); + VERIFY_ARE_EQUAL(vAffinity[2].bProc, (BYTE)6); + + vector vTargets(vSpans[0].GetTargets()); + VERIFY_ARE_EQUAL(vTargets.size(), (size_t)2); + Target t(vTargets[0]); + + VERIFY_IS_TRUE(t.GetPath().compare("testfile.dat") == 0); + VERIFY_ARE_EQUAL(t.GetBlockSizeInBytes(), (DWORD)(4 * 1024)); + VERIFY_ARE_EQUAL(t.GetRequestCount(), (DWORD)2); + VERIFY_IS_TRUE(t.GetRandomRatio() == 0); + VERIFY_IS_TRUE(t.GetUseInterlockedSequential() == false); + VERIFY_ARE_EQUAL(t.GetBlockAlignmentInBytes(), t.GetBlockSizeInBytes()); + VERIFY_ARE_EQUAL(t.GetBaseFileOffsetInBytes(), 0); + VERIFY_IS_TRUE(t.GetUseParallelAsyncIO() == false); + VERIFY_IS_TRUE(t.GetCacheMode() == TargetCacheMode::Cached); + VERIFY_IS_TRUE(t.GetWriteThroughMode() == WriteThroughMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoMode() == MemoryMappedIoMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoFlushMode() == MemoryMappedIoFlushMode::Undefined); + VERIFY_ARE_EQUAL(t.GetThreadsPerFile(), (DWORD)1); + VERIFY_ARE_EQUAL(t.GetThreadStrideInBytes(), 0); + VERIFY_IS_TRUE(t.GetCreateFile() == false); + VERIFY_ARE_EQUAL(t.GetFileSize(), 0); + VERIFY_ARE_EQUAL(t.GetMaxFileSize(), 0); + VERIFY_ARE_EQUAL(t.GetWriteRatio(), (DWORD)84); + VERIFY_IS_TRUE(t.GetUseBurstSize() == false); + VERIFY_ARE_EQUAL(t.GetBurstSize(), (DWORD)0); + VERIFY_ARE_EQUAL(t.GetThinkTime(), (DWORD)0); + VERIFY_IS_TRUE(t.GetEnableThinkTime() == false); + VERIFY_IS_TRUE(t.GetSequentialScanHint() == false); + VERIFY_IS_TRUE(t.GetRandomAccessHint() == false); + VERIFY_IS_TRUE(t.GetTemporaryFileHint() == false); + VERIFY_IS_TRUE(t.GetUseLargePages() == false); + VERIFY_ARE_EQUAL(t.GetThroughputInBytesPerMillisecond(), (DWORD)0); + + t = vTargets[1]; + VERIFY_IS_TRUE(t.GetPath().compare("testfile2.dat") == 0); + VERIFY_ARE_EQUAL(t.GetBlockSizeInBytes(), (DWORD)(4 * 1024)); + VERIFY_ARE_EQUAL(t.GetRequestCount(), (DWORD)2); + VERIFY_IS_TRUE(t.GetRandomRatio() == 0); + VERIFY_IS_TRUE(t.GetUseInterlockedSequential() == false); + VERIFY_ARE_EQUAL(t.GetBlockAlignmentInBytes(), t.GetBlockSizeInBytes()); + VERIFY_ARE_EQUAL(t.GetBaseFileOffsetInBytes(), 0); + VERIFY_IS_TRUE(t.GetUseParallelAsyncIO() == false); + VERIFY_IS_TRUE(t.GetCacheMode() == TargetCacheMode::Cached); + VERIFY_IS_TRUE(t.GetWriteThroughMode() == WriteThroughMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoMode() == MemoryMappedIoMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoFlushMode() == MemoryMappedIoFlushMode::Undefined); + VERIFY_IS_TRUE(t.GetZeroWriteBuffers() == false); + VERIFY_ARE_EQUAL(t.GetThreadsPerFile(), (DWORD)1); + VERIFY_ARE_EQUAL(t.GetThreadStrideInBytes(), 0); + VERIFY_IS_TRUE(t.GetCreateFile() == false); + VERIFY_ARE_EQUAL(t.GetFileSize(), 0); + VERIFY_ARE_EQUAL(t.GetMaxFileSize(), 0); + VERIFY_ARE_EQUAL(t.GetWriteRatio(), (DWORD)84); + VERIFY_IS_TRUE(t.GetUseBurstSize() == false); + VERIFY_ARE_EQUAL(t.GetBurstSize(), (DWORD)0); + VERIFY_ARE_EQUAL(t.GetThinkTime(), (DWORD)0); + VERIFY_IS_TRUE(t.GetEnableThinkTime() == false); + VERIFY_IS_TRUE(t.GetSequentialScanHint() == false); + VERIFY_IS_TRUE(t.GetRandomAccessHint() == false); + VERIFY_IS_TRUE(t.GetTemporaryFileHint() == false); + VERIFY_IS_TRUE(t.GetUseLargePages() == false); + VERIFY_ARE_EQUAL(t.GetThroughputInBytesPerMillisecond(), (DWORD)0); + } + + void CmdLineParserUnitTests::TestParseCmdLineBlockSize() + { + CmdLineParser p; + Profile profile; + struct Synchronization s = {}; + const char *argv[] = { "foo", "-b128K", "-w84", "-a1,4,6", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == true); + VERIFY_IS_TRUE(profile.GetVerbose() == false); + VERIFY_IS_TRUE(profile.GetProgress() == 0); + VERIFY_IS_TRUE(profile.GetCmdLine().compare("foo -b128K -w84 -a1,4,6 testfile.dat") == 0); + VERIFY_IS_TRUE(profile.GetEtwEnabled() == false); + VERIFY_IS_TRUE(profile.GetEtwProcess() == false); + VERIFY_IS_TRUE(profile.GetEtwThread() == false); + VERIFY_IS_TRUE(profile.GetEtwImageLoad() == false); + VERIFY_IS_TRUE(profile.GetEtwDiskIO() == false); + VERIFY_IS_TRUE(profile.GetEtwMemoryPageFaults() == false); + VERIFY_IS_TRUE(profile.GetEtwMemoryHardFaults() == false); + VERIFY_IS_TRUE(profile.GetEtwNetwork() == false); + VERIFY_IS_TRUE(profile.GetEtwRegistry() == false); + VERIFY_IS_TRUE(profile.GetEtwUsePagedMemory() == false); + VERIFY_IS_TRUE(profile.GetEtwUsePerfTimer() == false); + VERIFY_IS_TRUE(profile.GetEtwUseSystemTimer() == false); + VERIFY_IS_TRUE(profile.GetEtwUseCyclesCounter() == false); + + vector vSpans(profile.GetTimeSpans()); + VERIFY_ARE_EQUAL(vSpans.size(), (size_t)1); + VERIFY_ARE_EQUAL(vSpans[0].GetDuration(), (UINT32)10); + VERIFY_ARE_EQUAL(vSpans[0].GetWarmup(), (UINT32)5); + VERIFY_ARE_EQUAL(vSpans[0].GetCooldown(), (UINT32)0); + VERIFY_ARE_EQUAL(vSpans[0].GetRandSeed(), (UINT32)0); + VERIFY_ARE_EQUAL(vSpans[0].GetThreadCount(), (DWORD)0); + VERIFY_ARE_EQUAL(vSpans[0].GetRequestCount(), (DWORD)0); + VERIFY_IS_TRUE(vSpans[0].GetDisableAffinity() == false); + VERIFY_IS_TRUE(vSpans[0].GetCompletionRoutines() == false); + VERIFY_IS_TRUE(vSpans[0].GetMeasureLatency() == false); + VERIFY_IS_TRUE(vSpans[0].GetRandomWriteData() == false); + + const auto& vAffinity(vSpans[0].GetAffinityAssignments()); + VERIFY_ARE_EQUAL(vAffinity.size(), (size_t)3); + VERIFY_ARE_EQUAL(vAffinity[0].wGroup, 0); + VERIFY_ARE_EQUAL(vAffinity[0].bProc, (BYTE)1); + VERIFY_ARE_EQUAL(vAffinity[1].wGroup, 0); + VERIFY_ARE_EQUAL(vAffinity[1].bProc, (BYTE)4); + VERIFY_ARE_EQUAL(vAffinity[2].wGroup, 0); + VERIFY_ARE_EQUAL(vAffinity[2].bProc, (BYTE)6); + + vector vTargets(vSpans[0].GetTargets()); + VERIFY_ARE_EQUAL(vTargets.size(), (size_t)1); + Target t(vTargets[0]); + + VERIFY_IS_TRUE(t.GetPath().compare("testfile.dat") == 0); + VERIFY_ARE_EQUAL(t.GetBlockSizeInBytes(), (DWORD)(128 * 1024)); + VERIFY_ARE_EQUAL(t.GetRequestCount(), (DWORD)2); + VERIFY_IS_TRUE(t.GetRandomRatio() == 0); + VERIFY_IS_TRUE(t.GetUseInterlockedSequential() == false); + VERIFY_ARE_EQUAL(t.GetBlockAlignmentInBytes(), t.GetBlockSizeInBytes()); + VERIFY_ARE_EQUAL(t.GetBaseFileOffsetInBytes(), 0); + VERIFY_IS_TRUE(t.GetUseParallelAsyncIO() == false); + VERIFY_IS_TRUE(t.GetCacheMode() == TargetCacheMode::Cached); + VERIFY_IS_TRUE(t.GetWriteThroughMode() == WriteThroughMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoMode() == MemoryMappedIoMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoFlushMode() == MemoryMappedIoFlushMode::Undefined); + VERIFY_IS_TRUE(t.GetZeroWriteBuffers() == false); + VERIFY_ARE_EQUAL(t.GetThreadsPerFile(), (DWORD)1); + VERIFY_ARE_EQUAL(t.GetThreadStrideInBytes(), 0); + VERIFY_IS_TRUE(t.GetCreateFile() == false); + VERIFY_ARE_EQUAL(t.GetFileSize(), 0); + VERIFY_ARE_EQUAL(t.GetMaxFileSize(), 0); + VERIFY_ARE_EQUAL(t.GetWriteRatio(), (DWORD)84); + VERIFY_IS_TRUE(t.GetUseBurstSize() == false); + VERIFY_ARE_EQUAL(t.GetBurstSize(), (DWORD)0); + VERIFY_ARE_EQUAL(t.GetThinkTime(), (DWORD)0); + VERIFY_IS_TRUE(t.GetEnableThinkTime() == false); + VERIFY_IS_TRUE(t.GetSequentialScanHint() == false); + VERIFY_IS_TRUE(t.GetRandomAccessHint() == false); + VERIFY_IS_TRUE(t.GetTemporaryFileHint() == false); + VERIFY_IS_TRUE(t.GetUseLargePages() == false); + VERIFY_ARE_EQUAL(t.GetThroughputInBytesPerMillisecond(), (DWORD)0); + } + + void CmdLineParserUnitTests::TestParseCmdLineGroupAffinity() + { + CmdLineParser p; + Profile profile; + struct Synchronization s = {}; + const char *argv[] = { "foo", "-b128K", "-w84", "-ag", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == true); + VERIFY_IS_TRUE(profile.GetVerbose() == false); + VERIFY_IS_TRUE(profile.GetProgress() == 0); + VERIFY_IS_TRUE(profile.GetCmdLine().compare("foo -b128K -w84 -ag testfile.dat") == 0); + VERIFY_IS_TRUE(profile.GetEtwEnabled() == false); + VERIFY_IS_TRUE(profile.GetEtwProcess() == false); + VERIFY_IS_TRUE(profile.GetEtwThread() == false); + VERIFY_IS_TRUE(profile.GetEtwImageLoad() == false); + VERIFY_IS_TRUE(profile.GetEtwDiskIO() == false); + VERIFY_IS_TRUE(profile.GetEtwMemoryPageFaults() == false); + VERIFY_IS_TRUE(profile.GetEtwMemoryHardFaults() == false); + VERIFY_IS_TRUE(profile.GetEtwNetwork() == false); + VERIFY_IS_TRUE(profile.GetEtwRegistry() == false); + VERIFY_IS_TRUE(profile.GetEtwUsePagedMemory() == false); + VERIFY_IS_TRUE(profile.GetEtwUsePerfTimer() == false); + VERIFY_IS_TRUE(profile.GetEtwUseSystemTimer() == false); + VERIFY_IS_TRUE(profile.GetEtwUseCyclesCounter() == false); + + vector vSpans(profile.GetTimeSpans()); + VERIFY_ARE_EQUAL(vSpans.size(), (size_t)1); + //TimeSpan span = vSpans[0]; + VERIFY_ARE_EQUAL(vSpans[0].GetDuration(), (UINT32)10); + VERIFY_ARE_EQUAL(vSpans[0].GetWarmup(), (UINT32)5); + VERIFY_ARE_EQUAL(vSpans[0].GetCooldown(), (UINT32)0); + VERIFY_ARE_EQUAL(vSpans[0].GetRandSeed(), (UINT32)0); + VERIFY_ARE_EQUAL(vSpans[0].GetThreadCount(), (DWORD)0); + VERIFY_ARE_EQUAL(vSpans[0].GetRequestCount(), (DWORD)0); + VERIFY_IS_TRUE(vSpans[0].GetDisableAffinity() == false); + VERIFY_IS_TRUE(vSpans[0].GetCompletionRoutines() == false); + VERIFY_IS_TRUE(vSpans[0].GetMeasureLatency() == false); + VERIFY_IS_TRUE(vSpans[0].GetRandomWriteData() == false); + + const auto& vAffinity(vSpans[0].GetAffinityAssignments()); + VERIFY_ARE_EQUAL(vAffinity.size(), (size_t)0); + + vector vTargets(vSpans[0].GetTargets()); + VERIFY_ARE_EQUAL(vTargets.size(), (size_t)1); + Target t(vTargets[0]); + + VERIFY_IS_TRUE(t.GetPath().compare("testfile.dat") == 0); + VERIFY_ARE_EQUAL(t.GetBlockSizeInBytes(), (DWORD)(128 * 1024)); + VERIFY_ARE_EQUAL(t.GetRequestCount(), (DWORD)2); + VERIFY_IS_TRUE(t.GetRandomRatio() == 0); + VERIFY_IS_TRUE(t.GetUseInterlockedSequential() == false); + VERIFY_ARE_EQUAL(t.GetBlockAlignmentInBytes(), t.GetBlockSizeInBytes()); + VERIFY_ARE_EQUAL(t.GetBaseFileOffsetInBytes(), 0); + VERIFY_IS_TRUE(t.GetUseParallelAsyncIO() == false); + VERIFY_IS_TRUE(t.GetCacheMode() == TargetCacheMode::Cached); + VERIFY_IS_TRUE(t.GetWriteThroughMode() == WriteThroughMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoMode() == MemoryMappedIoMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoFlushMode() == MemoryMappedIoFlushMode::Undefined); + VERIFY_IS_TRUE(t.GetZeroWriteBuffers() == false); + VERIFY_ARE_EQUAL(t.GetThreadsPerFile(), (DWORD)1); + VERIFY_ARE_EQUAL(t.GetThreadStrideInBytes(), 0); + VERIFY_IS_TRUE(t.GetCreateFile() == false); + VERIFY_ARE_EQUAL(t.GetFileSize(), 0); + VERIFY_ARE_EQUAL(t.GetMaxFileSize(), 0); + VERIFY_ARE_EQUAL(t.GetWriteRatio(), (DWORD)84); + VERIFY_IS_TRUE(t.GetUseBurstSize() == false); + VERIFY_ARE_EQUAL(t.GetBurstSize(), (DWORD)0); + VERIFY_ARE_EQUAL(t.GetThinkTime(), (DWORD)0); + VERIFY_IS_TRUE(t.GetEnableThinkTime() == false); + VERIFY_IS_TRUE(t.GetSequentialScanHint() == false); + VERIFY_IS_TRUE(t.GetRandomAccessHint() == false); + VERIFY_IS_TRUE(t.GetTemporaryFileHint() == false); + VERIFY_IS_TRUE(t.GetUseLargePages() == false); + VERIFY_ARE_EQUAL(t.GetThroughputInBytesPerMillisecond(), (DWORD)0); + } + + void CmdLineParserUnitTests::TestParseCmdLineBaseMaxTarget() + { + CmdLineParser p; + struct Synchronization s = {}; + + { + Profile profile; + const char *argv[] = { "foo", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == true); + VERIFY_IS_TRUE(profile.GetCmdLine().compare("foo testfile.dat") == 0); + + vector vSpans(profile.GetTimeSpans()); + VERIFY_ARE_EQUAL(vSpans.size(), (size_t)1); + + vector vTargets(vSpans[0].GetTargets()); + VERIFY_ARE_EQUAL(vTargets.size(), (size_t)1); + + // defaults = 0 + const auto& t(vTargets[0]); + VERIFY_ARE_EQUAL(t.GetBaseFileOffsetInBytes(), (UINT64) 0); + VERIFY_ARE_EQUAL(t.GetMaxFileSize(), (UINT64) 0); + } + + { + // base 5MiB + Profile profile; + const char *argv[] = { "foo", "-B5m", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == true); + VERIFY_IS_TRUE(profile.GetCmdLine().compare("foo -B5m testfile.dat") == 0); + + vector vSpans(profile.GetTimeSpans()); + VERIFY_ARE_EQUAL(vSpans.size(), (size_t)1); + + vector vTargets(vSpans[0].GetTargets()); + VERIFY_ARE_EQUAL(vTargets.size(), (size_t)1); + + const auto& t(vTargets[0]); + VERIFY_ARE_EQUAL(t.GetBaseFileOffsetInBytes(), (UINT64)(5 * 1024 * 1024)); + VERIFY_ARE_EQUAL(t.GetMaxFileSize(), (UINT64) 0); + } + + { + // base 5MiB, length 1MiB -> 6MiB + Profile profile; + const char *argv[] = { "foo", "-B5m:1m", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == true); + VERIFY_IS_TRUE(profile.GetCmdLine().compare("foo -B5m:1m testfile.dat") == 0); + + vector vSpans(profile.GetTimeSpans()); + VERIFY_ARE_EQUAL(vSpans.size(), (size_t)1); + + vector vTargets(vSpans[0].GetTargets()); + VERIFY_ARE_EQUAL(vTargets.size(), (size_t)1); + + const auto& t(vTargets[0]); + VERIFY_ARE_EQUAL(t.GetBaseFileOffsetInBytes(), (UINT64)(5 * 1024 * 1024)); + VERIFY_ARE_EQUAL(t.GetMaxFileSize(), (UINT64)(6 * 1024 * 1024)); + } + + { + // base 5MiB, max 6MiB + Profile profile; + const char *argv[] = { "foo", "-B5m", "-f6m", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == true); + VERIFY_IS_TRUE(profile.GetCmdLine().compare("foo -B5m -f6m testfile.dat") == 0); + + vector vSpans(profile.GetTimeSpans()); + VERIFY_ARE_EQUAL(vSpans.size(), (size_t)1); + + vector vTargets(vSpans[0].GetTargets()); + VERIFY_ARE_EQUAL(vTargets.size(), (size_t)1); + + const auto& t(vTargets[0]); + VERIFY_ARE_EQUAL(t.GetBaseFileOffsetInBytes(), (UINT64)(5 * 1024 * 1024)); + VERIFY_ARE_EQUAL(t.GetMaxFileSize(), (UINT64)(6 * 1024 * 1024)); + } + + { + // cannot specify -f/-Bb:l together + Profile profile; + const char *argv[] = { "foo", "-B5m:1m", "-f6m", "testfile.dat" }; + VERIFY_IS_FALSE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == true); + } + + { + // cannot specify -B twice (2x b:l) + Profile profile; + const char *argv[] = { "foo", "-B5m:1m", "-B5m:1m", "testfile.dat" }; + VERIFY_IS_FALSE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == true); + } + + { + // cannot specify -B twice (b:l and b) + Profile profile; + const char *argv[] = { "foo", "-B5m:1m", "-B5m", "testfile.dat" }; + VERIFY_IS_FALSE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == true); + } + + { + // cannot specify -B twice (b and b) + Profile profile; + const char *argv[] = { "foo", "-B5m", "-B5m", "testfile.dat" }; + VERIFY_IS_FALSE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == true); + } + + { + // cannot specify -f twice (f and f) + Profile profile; + const char *argv[] = { "foo", "-f5m", "-f6m", "testfile.dat" }; + VERIFY_IS_FALSE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == true); + } + + { + // cannot specify max twice (b:l and f) + Profile profile; + const char *argv[] = { "foo", "-B5m:1m", "-f6m", "testfile.dat" }; + VERIFY_IS_FALSE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == true); + } + + { + // junk after -Bbase + Profile profile; + const char *argv[] = { "foo", "-B5mx", "testfile.dat" }; + VERIFY_IS_FALSE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == true); + } + + { + // sep but no length + Profile profile; + const char *argv[] = { "foo", "-B5m:", "testfile.dat" }; + VERIFY_IS_FALSE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == true); + } + + { + // sep but junk length + Profile profile; + const char *argv[] = { "foo", "-B5m:j", "testfile.dat" }; + VERIFY_IS_FALSE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == true); + } + + { + // sep but bad length spec + Profile profile; + const char *argv[] = { "foo", "-B5m:1x", "testfile.dat" }; + VERIFY_IS_FALSE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == true); + } + + { + // sep but extra after length spec + Profile profile; + const char *argv[] = { "foo", "-B5m:1mx", "testfile.dat" }; + VERIFY_IS_FALSE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == true); + } + } + + void CmdLineParserUnitTests::TestParseCmdLineHintFlag() + { + CmdLineParser p; + struct Synchronization s = {}; + + { + Profile profile; + const char *argv[] = { "foo", "-b128K", "-w84", "-fs", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == true); + VERIFY_IS_TRUE(profile.GetCmdLine().compare("foo -b128K -w84 -fs testfile.dat") == 0); + VerifyParseCmdLineAccessHints(profile, false, true, false); + } + + { + Profile profile; + const char *argv[] = { "foo", "-b128K", "-w84", "-fr", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == true); + VERIFY_IS_TRUE(profile.GetCmdLine().compare("foo -b128K -w84 -fr testfile.dat") == 0); + VerifyParseCmdLineAccessHints(profile, true, false, false); + } + + { + Profile profile; + const char *argv[] = { "foo", "-b128K", "-w84", "-ft", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == true); + VERIFY_IS_TRUE(profile.GetCmdLine().compare("foo -b128K -w84 -ft testfile.dat") == 0); + VerifyParseCmdLineAccessHints(profile, false, false, true); + } + + { + Profile profile; + const char *argv[] = { "foo", "-b128K", "-w84", "-frst", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == true); + VERIFY_IS_TRUE(profile.GetCmdLine().compare("foo -b128K -w84 -frst testfile.dat") == 0); + VerifyParseCmdLineAccessHints(profile, true, true, true); + } + } + + void CmdLineParserUnitTests::VerifyParseCmdLineAccessHints(Profile &profile, bool RandomAccess, bool SequentialScan, bool TemporaryFile) + { + VERIFY_IS_TRUE(profile.GetVerbose() == false); + VERIFY_IS_TRUE(profile.GetProgress() == 0); + VERIFY_IS_TRUE(profile.GetEtwEnabled() == false); + VERIFY_IS_TRUE(profile.GetEtwProcess() == false); + VERIFY_IS_TRUE(profile.GetEtwThread() == false); + VERIFY_IS_TRUE(profile.GetEtwImageLoad() == false); + VERIFY_IS_TRUE(profile.GetEtwDiskIO() == false); + VERIFY_IS_TRUE(profile.GetEtwMemoryPageFaults() == false); + VERIFY_IS_TRUE(profile.GetEtwMemoryHardFaults() == false); + VERIFY_IS_TRUE(profile.GetEtwNetwork() == false); + VERIFY_IS_TRUE(profile.GetEtwRegistry() == false); + VERIFY_IS_TRUE(profile.GetEtwUsePagedMemory() == false); + VERIFY_IS_TRUE(profile.GetEtwUsePerfTimer() == false); + VERIFY_IS_TRUE(profile.GetEtwUseSystemTimer() == false); + VERIFY_IS_TRUE(profile.GetEtwUseCyclesCounter() == false); + + vector vSpans(profile.GetTimeSpans()); + VERIFY_ARE_EQUAL(vSpans.size(), (size_t)1); + VERIFY_ARE_EQUAL(vSpans[0].GetDuration(), (UINT32)10); + VERIFY_ARE_EQUAL(vSpans[0].GetWarmup(), (UINT32)5); + VERIFY_ARE_EQUAL(vSpans[0].GetCooldown(), (UINT32)0); + VERIFY_ARE_EQUAL(vSpans[0].GetRandSeed(), (UINT32)0); + VERIFY_ARE_EQUAL(vSpans[0].GetThreadCount(), (DWORD)0); + VERIFY_ARE_EQUAL(vSpans[0].GetRequestCount(), (DWORD)0); + VERIFY_IS_TRUE(vSpans[0].GetDisableAffinity() == false); + VERIFY_IS_TRUE(vSpans[0].GetCompletionRoutines() == false); + VERIFY_IS_TRUE(vSpans[0].GetMeasureLatency() == false); + VERIFY_IS_TRUE(vSpans[0].GetRandomWriteData() == false); + + const auto& vAffinity(vSpans[0].GetAffinityAssignments()); + VERIFY_ARE_EQUAL(vAffinity.size(), (size_t)0); + + vector vTargets(vSpans[0].GetTargets()); + VERIFY_ARE_EQUAL(vTargets.size(), (size_t)1); + Target t(vTargets[0]); + + VERIFY_IS_TRUE(t.GetPath().compare("testfile.dat") == 0); + VERIFY_ARE_EQUAL(t.GetBlockSizeInBytes(), (DWORD)(128 * 1024)); + VERIFY_ARE_EQUAL(t.GetRequestCount(), (DWORD)2); + VERIFY_IS_TRUE(t.GetRandomRatio() == 0); + VERIFY_IS_TRUE(t.GetUseInterlockedSequential() == false); + VERIFY_ARE_EQUAL(t.GetBlockAlignmentInBytes(), t.GetBlockSizeInBytes()); + VERIFY_ARE_EQUAL(t.GetBaseFileOffsetInBytes(), 0); + VERIFY_IS_TRUE(t.GetUseParallelAsyncIO() == false); + VERIFY_IS_TRUE(t.GetCacheMode() == TargetCacheMode::Cached); + VERIFY_IS_TRUE(t.GetWriteThroughMode() == WriteThroughMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoMode() == MemoryMappedIoMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoFlushMode() == MemoryMappedIoFlushMode::Undefined); + VERIFY_IS_TRUE(t.GetZeroWriteBuffers() == false); + VERIFY_ARE_EQUAL(t.GetThreadsPerFile(), (DWORD)1); + VERIFY_ARE_EQUAL(t.GetThreadStrideInBytes(), 0); + VERIFY_IS_TRUE(t.GetCreateFile() == false); + VERIFY_ARE_EQUAL(t.GetFileSize(), 0); + VERIFY_ARE_EQUAL(t.GetMaxFileSize(), 0); + VERIFY_ARE_EQUAL(t.GetWriteRatio(), (DWORD)84); + VERIFY_IS_TRUE(t.GetUseBurstSize() == false); + VERIFY_ARE_EQUAL(t.GetBurstSize(), (DWORD)0); + VERIFY_ARE_EQUAL(t.GetThinkTime(), (DWORD)0); + VERIFY_IS_TRUE(t.GetEnableThinkTime() == false); + VERIFY_IS_TRUE(t.GetSequentialScanHint() == SequentialScan); + VERIFY_IS_TRUE(t.GetRandomAccessHint() == RandomAccess); + VERIFY_IS_TRUE(t.GetTemporaryFileHint() == TemporaryFile); + VERIFY_IS_TRUE(t.GetUseLargePages() == false); + VERIFY_ARE_EQUAL(t.GetThroughputInBytesPerMillisecond(), (DWORD)0); + } + + void CmdLineParserUnitTests::TestParseCmdLineDisableAllCacheMode1() + { + CmdLineParser p; + Profile profile; + struct Synchronization s = {}; + const char *argv[] = { "foo", "-b128K", "-w84", "-h", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == true); + VERIFY_IS_TRUE(profile.GetCmdLine().compare("foo -b128K -w84 -h testfile.dat") == 0); + + VerifyParseCmdLineDisableAllCache(profile); + } + + void CmdLineParserUnitTests::TestParseCmdLineDisableAllCacheMode2() + { + CmdLineParser p; + Profile profile; + struct Synchronization s = {}; + const char *argv[] = { "foo", "-b128K", "-w84", "-Sh", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == true); + VERIFY_IS_TRUE(profile.GetCmdLine().compare("foo -b128K -w84 -Sh testfile.dat") == 0); + + VerifyParseCmdLineDisableAllCache(profile); + } + + void CmdLineParserUnitTests::VerifyParseCmdLineDisableAllCache(Profile &profile) + { + VERIFY_IS_TRUE(profile.GetVerbose() == false); + VERIFY_IS_TRUE(profile.GetProgress() == 0); + + VERIFY_IS_TRUE(profile.GetEtwEnabled() == false); + VERIFY_IS_TRUE(profile.GetEtwProcess() == false); + VERIFY_IS_TRUE(profile.GetEtwThread() == false); + VERIFY_IS_TRUE(profile.GetEtwImageLoad() == false); + VERIFY_IS_TRUE(profile.GetEtwDiskIO() == false); + VERIFY_IS_TRUE(profile.GetEtwMemoryPageFaults() == false); + VERIFY_IS_TRUE(profile.GetEtwMemoryHardFaults() == false); + VERIFY_IS_TRUE(profile.GetEtwNetwork() == false); + VERIFY_IS_TRUE(profile.GetEtwRegistry() == false); + VERIFY_IS_TRUE(profile.GetEtwUsePagedMemory() == false); + VERIFY_IS_TRUE(profile.GetEtwUsePerfTimer() == false); + VERIFY_IS_TRUE(profile.GetEtwUseSystemTimer() == false); + VERIFY_IS_TRUE(profile.GetEtwUseCyclesCounter() == false); + + vector vSpans(profile.GetTimeSpans()); + VERIFY_ARE_EQUAL(vSpans.size(), (size_t)1); + VERIFY_ARE_EQUAL(vSpans[0].GetDuration(), (UINT32)10); + VERIFY_ARE_EQUAL(vSpans[0].GetWarmup(), (UINT32)5); + VERIFY_ARE_EQUAL(vSpans[0].GetCooldown(), (UINT32)0); + VERIFY_ARE_EQUAL(vSpans[0].GetRandSeed(), (UINT32)0); + VERIFY_ARE_EQUAL(vSpans[0].GetThreadCount(), (DWORD)0); + VERIFY_ARE_EQUAL(vSpans[0].GetRequestCount(), (DWORD)0); + VERIFY_IS_TRUE(vSpans[0].GetDisableAffinity() == false); + VERIFY_IS_TRUE(vSpans[0].GetCompletionRoutines() == false); + VERIFY_IS_TRUE(vSpans[0].GetMeasureLatency() == false); + VERIFY_IS_TRUE(vSpans[0].GetRandomWriteData() == false); + + const auto& vAffinity(vSpans[0].GetAffinityAssignments()); + VERIFY_ARE_EQUAL(vAffinity.size(), (size_t)0); + + vector vTargets(vSpans[0].GetTargets()); + VERIFY_ARE_EQUAL(vTargets.size(), (size_t)1); + Target t(vTargets[0]); + + VERIFY_IS_TRUE(t.GetPath().compare("testfile.dat") == 0); + VERIFY_ARE_EQUAL(t.GetBlockSizeInBytes(), (DWORD)(128 * 1024)); + VERIFY_ARE_EQUAL(t.GetRequestCount(), (DWORD)2); + VERIFY_IS_TRUE(t.GetRandomRatio() == 0); + VERIFY_IS_TRUE(t.GetUseInterlockedSequential() == false); + VERIFY_ARE_EQUAL(t.GetBlockAlignmentInBytes(), t.GetBlockSizeInBytes()); + VERIFY_ARE_EQUAL(t.GetBaseFileOffsetInBytes(), 0); + VERIFY_IS_TRUE(t.GetUseParallelAsyncIO() == false); + VERIFY_IS_TRUE(t.GetCacheMode() == TargetCacheMode::DisableOSCache); + VERIFY_IS_TRUE(t.GetWriteThroughMode() == WriteThroughMode::On); + VERIFY_IS_TRUE(t.GetMemoryMappedIoMode() == MemoryMappedIoMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoFlushMode() == MemoryMappedIoFlushMode::Undefined); + VERIFY_IS_TRUE(t.GetZeroWriteBuffers() == false); + VERIFY_ARE_EQUAL(t.GetThreadsPerFile(), (DWORD)1); + VERIFY_ARE_EQUAL(t.GetThreadStrideInBytes(), 0); + VERIFY_IS_TRUE(t.GetCreateFile() == false); + VERIFY_ARE_EQUAL(t.GetFileSize(), 0); + VERIFY_ARE_EQUAL(t.GetMaxFileSize(), 0); + VERIFY_ARE_EQUAL(t.GetWriteRatio(), (DWORD)84); + VERIFY_IS_TRUE(t.GetUseBurstSize() == false); + VERIFY_ARE_EQUAL(t.GetBurstSize(), (DWORD)0); + VERIFY_ARE_EQUAL(t.GetThinkTime(), (DWORD)0); + VERIFY_IS_TRUE(t.GetEnableThinkTime() == false); + VERIFY_IS_TRUE(t.GetSequentialScanHint() == false); + VERIFY_IS_TRUE(t.GetRandomAccessHint() == false); + VERIFY_IS_TRUE(t.GetTemporaryFileHint() == false); + VERIFY_IS_TRUE(t.GetUseLargePages() == false); + VERIFY_ARE_EQUAL(t.GetThroughputInBytesPerMillisecond(), (DWORD)0); + } + + void CmdLineParserUnitTests::TestParseCmdLineConflictingCacheModes() + { + CmdLineParser p; + struct Synchronization s = {}; + + // conflict bu in either order + { + Profile profile; + const char *argv[] = { "foo", "-Sub", "testfile.dat" }; + VERIFY_IS_FALSE(p.ParseCmdLine(_countof(argv), argv, &profile, &s)); + } + + { + Profile profile; + const char *argv[] = { "foo", "-Sbu", "testfile.dat" }; + VERIFY_IS_FALSE(p.ParseCmdLine(_countof(argv), argv, &profile, &s)); + } + + // conflict ru + { + Profile profile; + const char *argv[] = { "foo", "-Sru", "testfile.dat" }; + VERIFY_IS_FALSE(p.ParseCmdLine(_countof(argv), argv, &profile, &s)); + } + + // conflict mu + { + Profile profile; + const char *argv[] = { "foo", "-Smu", "testfile.dat" }; + VERIFY_IS_FALSE(p.ParseCmdLine(_countof(argv), argv, &profile, &s)); + } + + // conflict with -h/-Sb, either order + { + Profile profile; + const char *argv[] = { "foo", "-Sb", "-h", "testfile.dat" }; + VERIFY_IS_FALSE(p.ParseCmdLine(_countof(argv), argv, &profile, &s)); + } + + { + Profile profile; + const char *argv[] = { "foo", "-h", "-Sb", "testfile.dat" }; + VERIFY_IS_FALSE(p.ParseCmdLine(_countof(argv), argv, &profile, &s)); + } + + // conflict with -h/-Sm + { + Profile profile; + const char *argv[] = { "foo", "-Sm", "-h", "testfile.dat" }; + VERIFY_IS_FALSE(p.ParseCmdLine(_countof(argv), argv, &profile, &s)); + } + + // multiple with -h/-Suw, either order + { + Profile profile; + const char *argv[] = { "foo", "-Suw", "-h", "testfile.dat" }; + VERIFY_IS_FALSE(p.ParseCmdLine(_countof(argv), argv, &profile, &s)); + } + + { + Profile profile; + const char *argv[] = { "foo", "-h", "-Suw", "testfile.dat" }; + VERIFY_IS_FALSE(p.ParseCmdLine(_countof(argv), argv, &profile, &s)); + } + + // multiple with -S/-Su + { + Profile profile; + const char *argv[] = { "foo", "-S", "-Su", "testfile.dat" }; + VERIFY_IS_FALSE(p.ParseCmdLine(_countof(argv), argv, &profile, &s)); + } + + // multiple with -Sb/-Sb (same) + { + Profile profile; + const char *argv[] = { "foo", "-Sb", "-Sb", "testfile.dat" }; + VERIFY_IS_FALSE(p.ParseCmdLine(_countof(argv), argv, &profile, &s)); + } + + // multiple with -Sm/-Sm + { + Profile profile; + const char *argv[] = { "foo", "-Sm", "-Sm", "testfile.dat" }; + VERIFY_IS_FALSE(p.ParseCmdLine(_countof(argv), argv, &profile, &s)); + } + + // invalid option + { + Profile profile; + const char *argv[] = { "foo", "-Sx", "testfile.dat" }; + VERIFY_IS_FALSE(p.ParseCmdLine(_countof(argv), argv, &profile, &s)); + } + } + + void CmdLineParserUnitTests::TestParseCmdLineDisableAffinity() + { + CmdLineParser p; + Profile profile; + struct Synchronization s = {}; + const char *argv[] = { "foo", "-b128K", "-w84", "-n", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == true); + VERIFY_IS_TRUE(profile.GetVerbose() == false); + VERIFY_IS_TRUE(profile.GetProgress() == 0); + VERIFY_IS_TRUE(profile.GetCmdLine().compare("foo -b128K -w84 -n testfile.dat") == 0); + VERIFY_IS_TRUE(profile.GetEtwEnabled() == false); + VERIFY_IS_TRUE(profile.GetEtwProcess() == false); + VERIFY_IS_TRUE(profile.GetEtwThread() == false); + VERIFY_IS_TRUE(profile.GetEtwImageLoad() == false); + VERIFY_IS_TRUE(profile.GetEtwDiskIO() == false); + VERIFY_IS_TRUE(profile.GetEtwMemoryPageFaults() == false); + VERIFY_IS_TRUE(profile.GetEtwMemoryHardFaults() == false); + VERIFY_IS_TRUE(profile.GetEtwNetwork() == false); + VERIFY_IS_TRUE(profile.GetEtwRegistry() == false); + VERIFY_IS_TRUE(profile.GetEtwUsePagedMemory() == false); + VERIFY_IS_TRUE(profile.GetEtwUsePerfTimer() == false); + VERIFY_IS_TRUE(profile.GetEtwUseSystemTimer() == false); + VERIFY_IS_TRUE(profile.GetEtwUseCyclesCounter() == false); + + vector vSpans(profile.GetTimeSpans()); + VERIFY_ARE_EQUAL(vSpans.size(), (size_t)1); + VERIFY_ARE_EQUAL(vSpans[0].GetDuration(), (UINT32)10); + VERIFY_ARE_EQUAL(vSpans[0].GetWarmup(), (UINT32)5); + VERIFY_ARE_EQUAL(vSpans[0].GetCooldown(), (UINT32)0); + VERIFY_ARE_EQUAL(vSpans[0].GetRandSeed(), (UINT32)0); + VERIFY_ARE_EQUAL(vSpans[0].GetThreadCount(), (DWORD)0); + VERIFY_ARE_EQUAL(vSpans[0].GetRequestCount(), (DWORD)0); + VERIFY_IS_TRUE(vSpans[0].GetDisableAffinity() == true); + VERIFY_IS_TRUE(vSpans[0].GetCompletionRoutines() == false); + VERIFY_IS_TRUE(vSpans[0].GetMeasureLatency() == false); + VERIFY_IS_TRUE(vSpans[0].GetRandomWriteData() == false); + + const auto& vAffinity(vSpans[0].GetAffinityAssignments()); + VERIFY_ARE_EQUAL(vAffinity.size(), (size_t)0); + + vector vTargets(vSpans[0].GetTargets()); + VERIFY_ARE_EQUAL(vTargets.size(), (size_t)1); + Target t(vTargets[0]); + + VERIFY_IS_TRUE(t.GetPath().compare("testfile.dat") == 0); + VERIFY_ARE_EQUAL(t.GetBlockSizeInBytes(), (DWORD)(128 * 1024)); + VERIFY_ARE_EQUAL(t.GetRequestCount(), (DWORD)2); + VERIFY_IS_TRUE(t.GetRandomRatio() == 0); + VERIFY_IS_TRUE(t.GetUseInterlockedSequential() == false); + VERIFY_ARE_EQUAL(t.GetBlockAlignmentInBytes(), t.GetBlockSizeInBytes()); + VERIFY_ARE_EQUAL(t.GetBaseFileOffsetInBytes(), 0); + VERIFY_IS_TRUE(t.GetUseParallelAsyncIO() == false); + VERIFY_IS_TRUE(t.GetCacheMode() == TargetCacheMode::Cached); + VERIFY_IS_TRUE(t.GetWriteThroughMode() == WriteThroughMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoMode() == MemoryMappedIoMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoFlushMode() == MemoryMappedIoFlushMode::Undefined); + VERIFY_IS_TRUE(t.GetZeroWriteBuffers() == false); + VERIFY_ARE_EQUAL(t.GetThreadsPerFile(), (DWORD)1); + VERIFY_ARE_EQUAL(t.GetThreadStrideInBytes(), 0); + VERIFY_IS_TRUE(t.GetCreateFile() == false); + VERIFY_ARE_EQUAL(t.GetFileSize(), 0); + VERIFY_ARE_EQUAL(t.GetMaxFileSize(), 0); + VERIFY_ARE_EQUAL(t.GetWriteRatio(), (DWORD)84); + VERIFY_IS_TRUE(t.GetUseBurstSize() == false); + VERIFY_ARE_EQUAL(t.GetBurstSize(), (DWORD)0); + VERIFY_ARE_EQUAL(t.GetThinkTime(), (DWORD)0); + VERIFY_IS_TRUE(t.GetEnableThinkTime() == false); + VERIFY_IS_TRUE(t.GetSequentialScanHint() == false); + VERIFY_IS_TRUE(t.GetRandomAccessHint() == false); + VERIFY_IS_TRUE(t.GetTemporaryFileHint() == false); + VERIFY_IS_TRUE(t.GetUseLargePages() == false); + VERIFY_ARE_EQUAL(t.GetThroughputInBytesPerMillisecond(), (DWORD)0); + } + + void CmdLineParserUnitTests::TestParseCmdLineDisableAffinityConflict() + { + CmdLineParser p; + Profile profile; + struct Synchronization s = {}; + const char *argv[] = { "foo", "-b128K", "-w84", "-n", "-a1,2", "testfile.dat" }; + + // -n cannot be used with -a + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == false); + } + + void CmdLineParserUnitTests::TestParseCmdLineVerbose() + { + CmdLineParser p; + Profile profile; + struct Synchronization s = {}; + const char *argv[] = { "foo", "-b128K", "-w84", "-v", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == true); + VERIFY_IS_TRUE(profile.GetVerbose() == true); + VERIFY_IS_TRUE(profile.GetProgress() == 0); + VERIFY_IS_TRUE(profile.GetCmdLine().compare("foo -b128K -w84 -v testfile.dat") == 0); + VERIFY_IS_TRUE(profile.GetEtwEnabled() == false); + VERIFY_IS_TRUE(profile.GetEtwProcess() == false); + VERIFY_IS_TRUE(profile.GetEtwThread() == false); + VERIFY_IS_TRUE(profile.GetEtwImageLoad() == false); + VERIFY_IS_TRUE(profile.GetEtwDiskIO() == false); + VERIFY_IS_TRUE(profile.GetEtwMemoryPageFaults() == false); + VERIFY_IS_TRUE(profile.GetEtwMemoryHardFaults() == false); + VERIFY_IS_TRUE(profile.GetEtwNetwork() == false); + VERIFY_IS_TRUE(profile.GetEtwRegistry() == false); + VERIFY_IS_TRUE(profile.GetEtwUsePagedMemory() == false); + VERIFY_IS_TRUE(profile.GetEtwUsePerfTimer() == false); + VERIFY_IS_TRUE(profile.GetEtwUseSystemTimer() == false); + VERIFY_IS_TRUE(profile.GetEtwUseCyclesCounter() == false); + + vector vSpans(profile.GetTimeSpans()); + VERIFY_ARE_EQUAL(vSpans.size(), (size_t)1); + VERIFY_ARE_EQUAL(vSpans[0].GetDuration(), (UINT32)10); + VERIFY_ARE_EQUAL(vSpans[0].GetWarmup(), (UINT32)5); + VERIFY_ARE_EQUAL(vSpans[0].GetCooldown(), (UINT32)0); + VERIFY_ARE_EQUAL(vSpans[0].GetRandSeed(), (UINT32)0); + VERIFY_ARE_EQUAL(vSpans[0].GetThreadCount(), (DWORD)0); + VERIFY_ARE_EQUAL(vSpans[0].GetRequestCount(), (DWORD)0); + VERIFY_IS_TRUE(vSpans[0].GetDisableAffinity() == false); + VERIFY_IS_TRUE(vSpans[0].GetCompletionRoutines() == false); + VERIFY_IS_TRUE(vSpans[0].GetMeasureLatency() == false); + VERIFY_IS_TRUE(vSpans[0].GetRandomWriteData() == false); + + const auto& vAffinity(vSpans[0].GetAffinityAssignments()); + VERIFY_ARE_EQUAL(vAffinity.size(), (size_t)0); + + vector vTargets(vSpans[0].GetTargets()); + VERIFY_ARE_EQUAL(vTargets.size(), (size_t)1); + Target t(vTargets[0]); + + VERIFY_IS_TRUE(t.GetPath().compare("testfile.dat") == 0); + VERIFY_ARE_EQUAL(t.GetBlockSizeInBytes(), (DWORD)(128 * 1024)); + VERIFY_ARE_EQUAL(t.GetRequestCount(), (DWORD)2); + VERIFY_IS_TRUE(t.GetRandomRatio() == 0); + VERIFY_IS_TRUE(t.GetUseInterlockedSequential() == false); + VERIFY_ARE_EQUAL(t.GetBlockAlignmentInBytes(), t.GetBlockSizeInBytes()); + VERIFY_ARE_EQUAL(t.GetBaseFileOffsetInBytes(), 0); + VERIFY_IS_TRUE(t.GetUseParallelAsyncIO() == false); + VERIFY_IS_TRUE(t.GetCacheMode() == TargetCacheMode::Cached); + VERIFY_IS_TRUE(t.GetWriteThroughMode() == WriteThroughMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoMode() == MemoryMappedIoMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoFlushMode() == MemoryMappedIoFlushMode::Undefined); + VERIFY_IS_TRUE(t.GetZeroWriteBuffers() == false); + VERIFY_ARE_EQUAL(t.GetThreadsPerFile(), (DWORD)1); + VERIFY_ARE_EQUAL(t.GetThreadStrideInBytes(), 0); + VERIFY_IS_TRUE(t.GetCreateFile() == false); + VERIFY_ARE_EQUAL(t.GetFileSize(), 0); + VERIFY_ARE_EQUAL(t.GetMaxFileSize(), 0); + VERIFY_ARE_EQUAL(t.GetWriteRatio(), (DWORD)84); + VERIFY_IS_TRUE(t.GetUseBurstSize() == false); + VERIFY_ARE_EQUAL(t.GetBurstSize(), (DWORD)0); + VERIFY_ARE_EQUAL(t.GetThinkTime(), (DWORD)0); + VERIFY_IS_TRUE(t.GetEnableThinkTime() == false); + VERIFY_IS_TRUE(t.GetSequentialScanHint() == false); + VERIFY_IS_TRUE(t.GetRandomAccessHint() == false); + VERIFY_IS_TRUE(t.GetTemporaryFileHint() == false); + VERIFY_IS_TRUE(t.GetUseLargePages() == false); + VERIFY_ARE_EQUAL(t.GetThroughputInBytesPerMillisecond(), (DWORD)0); + } + + void CmdLineParserUnitTests::TestParseCmdLineDisableOSCache() + { + CmdLineParser p; + Profile profile; + struct Synchronization s = {}; + const char *argv[] = { "foo", "-b128K", "-w84", "-S", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == true); + VERIFY_IS_TRUE(profile.GetVerbose() == false); + VERIFY_IS_TRUE(profile.GetProgress() == 0); + VERIFY_IS_TRUE(profile.GetCmdLine().compare("foo -b128K -w84 -S testfile.dat") == 0); + VERIFY_IS_TRUE(profile.GetEtwEnabled() == false); + VERIFY_IS_TRUE(profile.GetEtwProcess() == false); + VERIFY_IS_TRUE(profile.GetEtwThread() == false); + VERIFY_IS_TRUE(profile.GetEtwImageLoad() == false); + VERIFY_IS_TRUE(profile.GetEtwDiskIO() == false); + VERIFY_IS_TRUE(profile.GetEtwMemoryPageFaults() == false); + VERIFY_IS_TRUE(profile.GetEtwMemoryHardFaults() == false); + VERIFY_IS_TRUE(profile.GetEtwNetwork() == false); + VERIFY_IS_TRUE(profile.GetEtwRegistry() == false); + VERIFY_IS_TRUE(profile.GetEtwUsePagedMemory() == false); + VERIFY_IS_TRUE(profile.GetEtwUsePerfTimer() == false); + VERIFY_IS_TRUE(profile.GetEtwUseSystemTimer() == false); + VERIFY_IS_TRUE(profile.GetEtwUseCyclesCounter() == false); + + vector vSpans(profile.GetTimeSpans()); + VERIFY_ARE_EQUAL(vSpans.size(), (size_t)1); + VERIFY_ARE_EQUAL(vSpans[0].GetDuration(), (UINT32)10); + VERIFY_ARE_EQUAL(vSpans[0].GetWarmup(), (UINT32)5); + VERIFY_ARE_EQUAL(vSpans[0].GetCooldown(), (UINT32)0); + VERIFY_ARE_EQUAL(vSpans[0].GetRandSeed(), (UINT32)0); + VERIFY_ARE_EQUAL(vSpans[0].GetThreadCount(), (DWORD)0); + VERIFY_ARE_EQUAL(vSpans[0].GetRequestCount(), (DWORD)0); + VERIFY_IS_TRUE(vSpans[0].GetDisableAffinity() == false); + VERIFY_IS_TRUE(vSpans[0].GetCompletionRoutines() == false); + VERIFY_IS_TRUE(vSpans[0].GetMeasureLatency() == false); + VERIFY_IS_TRUE(vSpans[0].GetRandomWriteData() == false); + + const auto& vAffinity(vSpans[0].GetAffinityAssignments()); + VERIFY_ARE_EQUAL(vAffinity.size(), (size_t)0); + + vector vTargets(vSpans[0].GetTargets()); + VERIFY_ARE_EQUAL(vTargets.size(), (size_t)1); + Target t(vTargets[0]); + + VERIFY_IS_TRUE(t.GetPath().compare("testfile.dat") == 0); + VERIFY_ARE_EQUAL(t.GetBlockSizeInBytes(), (DWORD)(128 * 1024)); + VERIFY_ARE_EQUAL(t.GetRequestCount(), (DWORD)2); + VERIFY_IS_TRUE(t.GetRandomRatio() == 0); + VERIFY_IS_TRUE(t.GetUseInterlockedSequential() == false); + VERIFY_ARE_EQUAL(t.GetBlockAlignmentInBytes(), t.GetBlockSizeInBytes()); + VERIFY_ARE_EQUAL(t.GetBaseFileOffsetInBytes(), 0); + VERIFY_IS_TRUE(t.GetUseParallelAsyncIO() == false); + VERIFY_IS_TRUE(t.GetCacheMode() == TargetCacheMode::DisableOSCache); + VERIFY_IS_TRUE(t.GetWriteThroughMode() == WriteThroughMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoMode() == MemoryMappedIoMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoFlushMode() == MemoryMappedIoFlushMode::Undefined); + VERIFY_IS_TRUE(t.GetZeroWriteBuffers() == false); + VERIFY_ARE_EQUAL(t.GetThreadsPerFile(), (DWORD)1); + VERIFY_ARE_EQUAL(t.GetThreadStrideInBytes(), 0); + VERIFY_IS_TRUE(t.GetCreateFile() == false); + VERIFY_ARE_EQUAL(t.GetFileSize(), 0); + VERIFY_ARE_EQUAL(t.GetMaxFileSize(), 0); + VERIFY_ARE_EQUAL(t.GetWriteRatio(), (DWORD)84); + VERIFY_IS_TRUE(t.GetUseBurstSize() == false); + VERIFY_ARE_EQUAL(t.GetBurstSize(), (DWORD)0); + VERIFY_ARE_EQUAL(t.GetThinkTime(), (DWORD)0); + VERIFY_IS_TRUE(t.GetEnableThinkTime() == false); + VERIFY_IS_TRUE(t.GetSequentialScanHint() == false); + VERIFY_IS_TRUE(t.GetRandomAccessHint() == false); + VERIFY_IS_TRUE(t.GetTemporaryFileHint() == false); + VERIFY_IS_TRUE(t.GetUseLargePages() == false); + VERIFY_ARE_EQUAL(t.GetThroughputInBytesPerMillisecond(), (DWORD)0); + } + + void CmdLineParserUnitTests::TestParseCmdLineDisableLocalCache() + { + CmdLineParser p; + Profile profile; + struct Synchronization s = {}; + const char *argv[] = { "foo", "-b128K", "-w84", "-Sr", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == true); + VERIFY_IS_TRUE(profile.GetVerbose() == false); + VERIFY_IS_TRUE(profile.GetProgress() == 0); + VERIFY_IS_TRUE(profile.GetCmdLine().compare("foo -b128K -w84 -Sr testfile.dat") == 0); + VERIFY_IS_TRUE(profile.GetEtwEnabled() == false); + VERIFY_IS_TRUE(profile.GetEtwProcess() == false); + VERIFY_IS_TRUE(profile.GetEtwThread() == false); + VERIFY_IS_TRUE(profile.GetEtwImageLoad() == false); + VERIFY_IS_TRUE(profile.GetEtwDiskIO() == false); + VERIFY_IS_TRUE(profile.GetEtwMemoryPageFaults() == false); + VERIFY_IS_TRUE(profile.GetEtwMemoryHardFaults() == false); + VERIFY_IS_TRUE(profile.GetEtwNetwork() == false); + VERIFY_IS_TRUE(profile.GetEtwRegistry() == false); + VERIFY_IS_TRUE(profile.GetEtwUsePagedMemory() == false); + VERIFY_IS_TRUE(profile.GetEtwUsePerfTimer() == false); + VERIFY_IS_TRUE(profile.GetEtwUseSystemTimer() == false); + VERIFY_IS_TRUE(profile.GetEtwUseCyclesCounter() == false); + + vector vSpans(profile.GetTimeSpans()); + VERIFY_ARE_EQUAL(vSpans.size(), (size_t)1); + VERIFY_ARE_EQUAL(vSpans[0].GetDuration(), (UINT32)10); + VERIFY_ARE_EQUAL(vSpans[0].GetWarmup(), (UINT32)5); + VERIFY_ARE_EQUAL(vSpans[0].GetCooldown(), (UINT32)0); + VERIFY_ARE_EQUAL(vSpans[0].GetRandSeed(), (UINT32)0); + VERIFY_ARE_EQUAL(vSpans[0].GetThreadCount(), (DWORD)0); + VERIFY_ARE_EQUAL(vSpans[0].GetRequestCount(), (DWORD)0); + VERIFY_IS_TRUE(vSpans[0].GetDisableAffinity() == false); + VERIFY_IS_TRUE(vSpans[0].GetCompletionRoutines() == false); + VERIFY_IS_TRUE(vSpans[0].GetMeasureLatency() == false); + VERIFY_IS_TRUE(vSpans[0].GetRandomWriteData() == false); + + const auto& vAffinity(vSpans[0].GetAffinityAssignments()); + VERIFY_ARE_EQUAL(vAffinity.size(), (size_t)0); + + vector vTargets(vSpans[0].GetTargets()); + VERIFY_ARE_EQUAL(vTargets.size(), (size_t)1); + Target t(vTargets[0]); + + VERIFY_IS_TRUE(t.GetPath().compare("testfile.dat") == 0); + VERIFY_ARE_EQUAL(t.GetBlockSizeInBytes(), (DWORD)(128 * 1024)); + VERIFY_ARE_EQUAL(t.GetRequestCount(), (DWORD)2); + VERIFY_IS_TRUE(t.GetRandomRatio() == 0); + VERIFY_IS_TRUE(t.GetUseInterlockedSequential() == false); + VERIFY_ARE_EQUAL(t.GetBlockAlignmentInBytes(), t.GetBlockSizeInBytes()); + VERIFY_ARE_EQUAL(t.GetBaseFileOffsetInBytes(), 0); + VERIFY_IS_TRUE(t.GetUseParallelAsyncIO() == false); + VERIFY_IS_TRUE(t.GetCacheMode() == TargetCacheMode::DisableLocalCache); + VERIFY_IS_TRUE(t.GetWriteThroughMode() == WriteThroughMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoMode() == MemoryMappedIoMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoFlushMode() == MemoryMappedIoFlushMode::Undefined); + VERIFY_IS_TRUE(t.GetZeroWriteBuffers() == false); + VERIFY_ARE_EQUAL(t.GetThreadsPerFile(), (DWORD)1); + VERIFY_ARE_EQUAL(t.GetThreadStrideInBytes(), 0); + VERIFY_IS_TRUE(t.GetCreateFile() == false); + VERIFY_ARE_EQUAL(t.GetFileSize(), 0); + VERIFY_ARE_EQUAL(t.GetMaxFileSize(), 0); + VERIFY_ARE_EQUAL(t.GetWriteRatio(), (DWORD)84); + VERIFY_IS_TRUE(t.GetUseBurstSize() == false); + VERIFY_ARE_EQUAL(t.GetBurstSize(), (DWORD)0); + VERIFY_ARE_EQUAL(t.GetThinkTime(), (DWORD)0); + VERIFY_IS_TRUE(t.GetEnableThinkTime() == false); + VERIFY_IS_TRUE(t.GetSequentialScanHint() == false); + VERIFY_IS_TRUE(t.GetRandomAccessHint() == false); + VERIFY_IS_TRUE(t.GetTemporaryFileHint() == false); + VERIFY_IS_TRUE(t.GetUseLargePages() == false); + VERIFY_ARE_EQUAL(t.GetThroughputInBytesPerMillisecond(), (DWORD)0); + } + + void CmdLineParserUnitTests::TestParseCmdLineBufferedWriteThrough() + { + CmdLineParser p; + Profile profile; + struct Synchronization s = {}; + const char *argv[] = { "foo", "-b128K", "-w84", "-Sbw", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == true); + VERIFY_IS_TRUE(profile.GetVerbose() == false); + VERIFY_IS_TRUE(profile.GetProgress() == 0); + VERIFY_IS_TRUE(profile.GetCmdLine().compare("foo -b128K -w84 -Sbw testfile.dat") == 0); + VERIFY_IS_TRUE(profile.GetEtwEnabled() == false); + VERIFY_IS_TRUE(profile.GetEtwProcess() == false); + VERIFY_IS_TRUE(profile.GetEtwThread() == false); + VERIFY_IS_TRUE(profile.GetEtwImageLoad() == false); + VERIFY_IS_TRUE(profile.GetEtwDiskIO() == false); + VERIFY_IS_TRUE(profile.GetEtwMemoryPageFaults() == false); + VERIFY_IS_TRUE(profile.GetEtwMemoryHardFaults() == false); + VERIFY_IS_TRUE(profile.GetEtwNetwork() == false); + VERIFY_IS_TRUE(profile.GetEtwRegistry() == false); + VERIFY_IS_TRUE(profile.GetEtwUsePagedMemory() == false); + VERIFY_IS_TRUE(profile.GetEtwUsePerfTimer() == false); + VERIFY_IS_TRUE(profile.GetEtwUseSystemTimer() == false); + VERIFY_IS_TRUE(profile.GetEtwUseCyclesCounter() == false); + + vector vSpans(profile.GetTimeSpans()); + VERIFY_ARE_EQUAL(vSpans.size(), (size_t)1); + VERIFY_ARE_EQUAL(vSpans[0].GetDuration(), (UINT32)10); + VERIFY_ARE_EQUAL(vSpans[0].GetWarmup(), (UINT32)5); + VERIFY_ARE_EQUAL(vSpans[0].GetCooldown(), (UINT32)0); + VERIFY_ARE_EQUAL(vSpans[0].GetRandSeed(), (UINT32)0); + VERIFY_ARE_EQUAL(vSpans[0].GetThreadCount(), (DWORD)0); + VERIFY_ARE_EQUAL(vSpans[0].GetRequestCount(), (DWORD)0); + VERIFY_IS_TRUE(vSpans[0].GetDisableAffinity() == false); + VERIFY_IS_TRUE(vSpans[0].GetCompletionRoutines() == false); + VERIFY_IS_TRUE(vSpans[0].GetMeasureLatency() == false); + VERIFY_IS_TRUE(vSpans[0].GetRandomWriteData() == false); + + const auto& vAffinity(vSpans[0].GetAffinityAssignments()); + VERIFY_ARE_EQUAL(vAffinity.size(), (size_t)0); + + vector vTargets(vSpans[0].GetTargets()); + VERIFY_ARE_EQUAL(vTargets.size(), (size_t)1); + Target t(vTargets[0]); + + VERIFY_IS_TRUE(t.GetPath().compare("testfile.dat") == 0); + VERIFY_ARE_EQUAL(t.GetBlockSizeInBytes(), (DWORD)(128 * 1024)); + VERIFY_ARE_EQUAL(t.GetRequestCount(), (DWORD)2); + VERIFY_IS_TRUE(t.GetRandomRatio() == 0); + VERIFY_IS_TRUE(t.GetUseInterlockedSequential() == false); + VERIFY_ARE_EQUAL(t.GetBlockAlignmentInBytes(), t.GetBlockSizeInBytes()); + VERIFY_ARE_EQUAL(t.GetBaseFileOffsetInBytes(), 0); + VERIFY_IS_TRUE(t.GetUseParallelAsyncIO() == false); + VERIFY_IS_TRUE(t.GetCacheMode() == TargetCacheMode::Cached); + VERIFY_IS_TRUE(t.GetWriteThroughMode() == WriteThroughMode::On); + VERIFY_IS_TRUE(t.GetMemoryMappedIoMode() == MemoryMappedIoMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoFlushMode() == MemoryMappedIoFlushMode::Undefined); + VERIFY_IS_TRUE(t.GetZeroWriteBuffers() == false); + VERIFY_ARE_EQUAL(t.GetThreadsPerFile(), (DWORD)1); + VERIFY_ARE_EQUAL(t.GetThreadStrideInBytes(), 0); + VERIFY_IS_TRUE(t.GetCreateFile() == false); + VERIFY_ARE_EQUAL(t.GetFileSize(), 0); + VERIFY_ARE_EQUAL(t.GetMaxFileSize(), 0); + VERIFY_ARE_EQUAL(t.GetWriteRatio(), (DWORD)84); + VERIFY_IS_TRUE(t.GetUseBurstSize() == false); + VERIFY_ARE_EQUAL(t.GetBurstSize(), (DWORD)0); + VERIFY_ARE_EQUAL(t.GetThinkTime(), (DWORD)0); + VERIFY_IS_TRUE(t.GetEnableThinkTime() == false); + VERIFY_IS_TRUE(t.GetSequentialScanHint() == false); + VERIFY_IS_TRUE(t.GetRandomAccessHint() == false); + VERIFY_IS_TRUE(t.GetTemporaryFileHint() == false); + VERIFY_IS_TRUE(t.GetUseLargePages() == false); + VERIFY_ARE_EQUAL(t.GetThroughputInBytesPerMillisecond(), (DWORD)0); + } + + void CmdLineParserUnitTests::VerifyParseCmdLineMappedIO(Profile &profile, MemoryMappedIoFlushMode FlushMode) + { + VERIFY_IS_TRUE(profile.GetVerbose() == false); + VERIFY_IS_TRUE(profile.GetProgress() == 0); + + VERIFY_IS_TRUE(profile.GetEtwEnabled() == false); + VERIFY_IS_TRUE(profile.GetEtwProcess() == false); + VERIFY_IS_TRUE(profile.GetEtwThread() == false); + VERIFY_IS_TRUE(profile.GetEtwImageLoad() == false); + VERIFY_IS_TRUE(profile.GetEtwDiskIO() == false); + VERIFY_IS_TRUE(profile.GetEtwMemoryPageFaults() == false); + VERIFY_IS_TRUE(profile.GetEtwMemoryHardFaults() == false); + VERIFY_IS_TRUE(profile.GetEtwNetwork() == false); + VERIFY_IS_TRUE(profile.GetEtwRegistry() == false); + VERIFY_IS_TRUE(profile.GetEtwUsePagedMemory() == false); + VERIFY_IS_TRUE(profile.GetEtwUsePerfTimer() == false); + VERIFY_IS_TRUE(profile.GetEtwUseSystemTimer() == false); + VERIFY_IS_TRUE(profile.GetEtwUseCyclesCounter() == false); + + vector vSpans(profile.GetTimeSpans()); + VERIFY_ARE_EQUAL(vSpans.size(), (size_t)1); + VERIFY_ARE_EQUAL(vSpans[0].GetDuration(), (UINT32)10); + VERIFY_ARE_EQUAL(vSpans[0].GetWarmup(), (UINT32)5); + VERIFY_ARE_EQUAL(vSpans[0].GetCooldown(), (UINT32)0); + VERIFY_ARE_EQUAL(vSpans[0].GetRandSeed(), (UINT32)0); + VERIFY_ARE_EQUAL(vSpans[0].GetThreadCount(), (DWORD)0); + VERIFY_ARE_EQUAL(vSpans[0].GetRequestCount(), (DWORD)0); + VERIFY_IS_TRUE(vSpans[0].GetDisableAffinity() == false); + VERIFY_IS_TRUE(vSpans[0].GetCompletionRoutines() == false); + VERIFY_IS_TRUE(vSpans[0].GetMeasureLatency() == false); + VERIFY_IS_TRUE(vSpans[0].GetRandomWriteData() == false); + + const auto& vAffinity(vSpans[0].GetAffinityAssignments()); + VERIFY_ARE_EQUAL(vAffinity.size(), (size_t)0); + + vector vTargets(vSpans[0].GetTargets()); + VERIFY_ARE_EQUAL(vTargets.size(), (size_t)1); + Target t(vTargets[0]); + + VERIFY_IS_TRUE(t.GetPath().compare("testfile.dat") == 0); + VERIFY_ARE_EQUAL(t.GetBlockSizeInBytes(), (DWORD)(128 * 1024)); + VERIFY_ARE_EQUAL(t.GetRequestCount(), (DWORD)2); + VERIFY_IS_TRUE(t.GetRandomRatio() == 0); + VERIFY_IS_TRUE(t.GetUseInterlockedSequential() == false); + VERIFY_ARE_EQUAL(t.GetBlockAlignmentInBytes(), t.GetBlockSizeInBytes()); + VERIFY_ARE_EQUAL(t.GetBaseFileOffsetInBytes(), 0); + VERIFY_IS_TRUE(t.GetUseParallelAsyncIO() == false); + VERIFY_IS_TRUE(t.GetCacheMode() == TargetCacheMode::Cached); + VERIFY_IS_TRUE(t.GetWriteThroughMode() == WriteThroughMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoMode() == MemoryMappedIoMode::On); + VERIFY_IS_TRUE(t.GetMemoryMappedIoFlushMode() == FlushMode); + VERIFY_IS_TRUE(t.GetZeroWriteBuffers() == false); + VERIFY_ARE_EQUAL(t.GetThreadsPerFile(), (DWORD)1); + VERIFY_ARE_EQUAL(t.GetThreadStrideInBytes(), 0); + VERIFY_IS_TRUE(t.GetCreateFile() == false); + VERIFY_ARE_EQUAL(t.GetFileSize(), 0); + VERIFY_ARE_EQUAL(t.GetMaxFileSize(), 0); + VERIFY_ARE_EQUAL(t.GetWriteRatio(), (DWORD)84); + VERIFY_IS_TRUE(t.GetUseBurstSize() == false); + VERIFY_ARE_EQUAL(t.GetBurstSize(), (DWORD)0); + VERIFY_ARE_EQUAL(t.GetThinkTime(), (DWORD)0); + VERIFY_IS_TRUE(t.GetEnableThinkTime() == false); + VERIFY_IS_TRUE(t.GetSequentialScanHint() == false); + VERIFY_IS_TRUE(t.GetRandomAccessHint() == false); + VERIFY_IS_TRUE(t.GetTemporaryFileHint() == false); + VERIFY_IS_TRUE(t.GetUseLargePages() == false); + VERIFY_ARE_EQUAL(t.GetThroughputInBytesPerMillisecond(), (DWORD)0); + } + + void CmdLineParserUnitTests::TestParseCmdLineMappedIO() + { + { + CmdLineParser p; + Profile profile; + struct Synchronization s = {}; + const char *argv[] = { "foo", "-b128K", "-w84", "-Sm", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == true); + VERIFY_IS_TRUE(profile.GetCmdLine().compare("foo -b128K -w84 -Sm testfile.dat") == 0); + VerifyParseCmdLineMappedIO(profile, MemoryMappedIoFlushMode::Undefined); + } + + { + CmdLineParser p; + Profile profile; + struct Synchronization s = {}; + const char *argv[] = { "foo", "-b128K", "-w84", "-Sm", "-Nv", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == true); + VERIFY_IS_TRUE(profile.GetCmdLine().compare("foo -b128K -w84 -Sm -Nv testfile.dat") == 0); + VerifyParseCmdLineMappedIO(profile, MemoryMappedIoFlushMode::ViewOfFile); + } + + { + CmdLineParser p; + Profile profile; + struct Synchronization s = {}; + const char *argv[] = { "foo", "-b128K", "-w84", "-Sm", "-Nn", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == true); + VERIFY_IS_TRUE(profile.GetCmdLine().compare("foo -b128K -w84 -Sm -Nn testfile.dat") == 0); + VerifyParseCmdLineMappedIO(profile, MemoryMappedIoFlushMode::NonVolatileMemory); + } + + { + CmdLineParser p; + Profile profile; + struct Synchronization s = {}; + const char *argv[] = { "foo", "-b128K", "-w84", "-Sm", "-Ni", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == true); + VERIFY_IS_TRUE(profile.GetCmdLine().compare("foo -b128K -w84 -Sm -Ni testfile.dat") == 0); + VerifyParseCmdLineMappedIO(profile, MemoryMappedIoFlushMode::NonVolatileMemoryNoDrain); + } + } + + void CmdLineParserUnitTests::TestParseCmdLineUseCompletionRoutines() + { + CmdLineParser p; + Profile profile; + struct Synchronization s = {}; + const char *argv[] = { "foo", "-b128K", "-w84", "-x", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == true); + VERIFY_IS_TRUE(profile.GetVerbose() == false); + VERIFY_IS_TRUE(profile.GetProgress() == 0); + VERIFY_IS_TRUE(profile.GetCmdLine().compare("foo -b128K -w84 -x testfile.dat") == 0); + VERIFY_IS_TRUE(profile.GetEtwEnabled() == false); + VERIFY_IS_TRUE(profile.GetEtwProcess() == false); + VERIFY_IS_TRUE(profile.GetEtwThread() == false); + VERIFY_IS_TRUE(profile.GetEtwImageLoad() == false); + VERIFY_IS_TRUE(profile.GetEtwDiskIO() == false); + VERIFY_IS_TRUE(profile.GetEtwMemoryPageFaults() == false); + VERIFY_IS_TRUE(profile.GetEtwMemoryHardFaults() == false); + VERIFY_IS_TRUE(profile.GetEtwNetwork() == false); + VERIFY_IS_TRUE(profile.GetEtwRegistry() == false); + VERIFY_IS_TRUE(profile.GetEtwUsePagedMemory() == false); + VERIFY_IS_TRUE(profile.GetEtwUsePerfTimer() == false); + VERIFY_IS_TRUE(profile.GetEtwUseSystemTimer() == false); + VERIFY_IS_TRUE(profile.GetEtwUseCyclesCounter() == false); + + vector vSpans(profile.GetTimeSpans()); + VERIFY_ARE_EQUAL(vSpans.size(), (size_t)1); + VERIFY_ARE_EQUAL(vSpans[0].GetDuration(), (UINT32)10); + VERIFY_ARE_EQUAL(vSpans[0].GetWarmup(), (UINT32)5); + VERIFY_ARE_EQUAL(vSpans[0].GetCooldown(), (UINT32)0); + VERIFY_ARE_EQUAL(vSpans[0].GetRandSeed(), (UINT32)0); + VERIFY_ARE_EQUAL(vSpans[0].GetThreadCount(), (DWORD)0); + VERIFY_ARE_EQUAL(vSpans[0].GetRequestCount(), (DWORD)0); + VERIFY_IS_TRUE(vSpans[0].GetDisableAffinity() == false); + VERIFY_IS_TRUE(vSpans[0].GetCompletionRoutines() == true); + VERIFY_IS_TRUE(vSpans[0].GetMeasureLatency() == false); + VERIFY_IS_TRUE(vSpans[0].GetRandomWriteData() == false); + + const auto& vAffinity(vSpans[0].GetAffinityAssignments()); + VERIFY_ARE_EQUAL(vAffinity.size(), (size_t)0); + + vector vTargets(vSpans[0].GetTargets()); + VERIFY_ARE_EQUAL(vTargets.size(), (size_t)1); + Target t(vTargets[0]); + + VERIFY_IS_TRUE(t.GetPath().compare("testfile.dat") == 0); + VERIFY_ARE_EQUAL(t.GetBlockSizeInBytes(), (DWORD)(128 * 1024)); + VERIFY_ARE_EQUAL(t.GetRequestCount(), (DWORD)2); + VERIFY_IS_TRUE(t.GetRandomRatio() == 0); + VERIFY_IS_TRUE(t.GetUseInterlockedSequential() == false); + VERIFY_ARE_EQUAL(t.GetBlockAlignmentInBytes(), t.GetBlockSizeInBytes()); + VERIFY_ARE_EQUAL(t.GetBaseFileOffsetInBytes(), 0); + VERIFY_IS_TRUE(t.GetUseParallelAsyncIO() == false); + VERIFY_IS_TRUE(t.GetCacheMode() == TargetCacheMode::Cached); + VERIFY_IS_TRUE(t.GetWriteThroughMode() == WriteThroughMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoMode() == MemoryMappedIoMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoFlushMode() == MemoryMappedIoFlushMode::Undefined); + VERIFY_IS_TRUE(t.GetZeroWriteBuffers() == false); + VERIFY_ARE_EQUAL(t.GetThreadsPerFile(), (DWORD)1); + VERIFY_ARE_EQUAL(t.GetThreadStrideInBytes(), 0); + VERIFY_IS_TRUE(t.GetCreateFile() == false); + VERIFY_ARE_EQUAL(t.GetFileSize(), 0); + VERIFY_ARE_EQUAL(t.GetMaxFileSize(), 0); + VERIFY_ARE_EQUAL(t.GetWriteRatio(), (DWORD)84); + VERIFY_IS_TRUE(t.GetUseBurstSize() == false); + VERIFY_ARE_EQUAL(t.GetBurstSize(), (DWORD)0); + VERIFY_ARE_EQUAL(t.GetThinkTime(), (DWORD)0); + VERIFY_IS_TRUE(t.GetEnableThinkTime() == false); + VERIFY_IS_TRUE(t.GetSequentialScanHint() == false); + VERIFY_IS_TRUE(t.GetRandomAccessHint() == false); + VERIFY_IS_TRUE(t.GetTemporaryFileHint() == false); + VERIFY_IS_TRUE(t.GetUseLargePages() == false); + VERIFY_ARE_EQUAL(t.GetThroughputInBytesPerMillisecond(), (DWORD)0); + } + + void CmdLineParserUnitTests::TestParseCmdLineRandSeed() + { + CmdLineParser p; + Profile profile; + struct Synchronization s = {}; + const char *argv[] = { "foo", "-b128K", "-w84", "-z1234", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == true); + VERIFY_IS_TRUE(profile.GetVerbose() == false); + VERIFY_IS_TRUE(profile.GetProgress() == 0); + VERIFY_IS_TRUE(profile.GetCmdLine().compare("foo -b128K -w84 -z1234 testfile.dat") == 0); + VERIFY_IS_TRUE(profile.GetEtwEnabled() == false); + VERIFY_IS_TRUE(profile.GetEtwProcess() == false); + VERIFY_IS_TRUE(profile.GetEtwThread() == false); + VERIFY_IS_TRUE(profile.GetEtwImageLoad() == false); + VERIFY_IS_TRUE(profile.GetEtwDiskIO() == false); + VERIFY_IS_TRUE(profile.GetEtwMemoryPageFaults() == false); + VERIFY_IS_TRUE(profile.GetEtwMemoryHardFaults() == false); + VERIFY_IS_TRUE(profile.GetEtwNetwork() == false); + VERIFY_IS_TRUE(profile.GetEtwRegistry() == false); + VERIFY_IS_TRUE(profile.GetEtwUsePagedMemory() == false); + VERIFY_IS_TRUE(profile.GetEtwUsePerfTimer() == false); + VERIFY_IS_TRUE(profile.GetEtwUseSystemTimer() == false); + VERIFY_IS_TRUE(profile.GetEtwUseCyclesCounter() == false); + + vector vSpans(profile.GetTimeSpans()); + VERIFY_ARE_EQUAL(vSpans.size(), (size_t)1); + VERIFY_ARE_EQUAL(vSpans[0].GetDuration(), (UINT32)10); + VERIFY_ARE_EQUAL(vSpans[0].GetWarmup(), (UINT32)5); + VERIFY_ARE_EQUAL(vSpans[0].GetCooldown(), (UINT32)0); + VERIFY_ARE_EQUAL(vSpans[0].GetRandSeed(), (UINT32)1234); + VERIFY_ARE_EQUAL(vSpans[0].GetThreadCount(), (DWORD)0); + VERIFY_ARE_EQUAL(vSpans[0].GetRequestCount(), (DWORD)0); + VERIFY_IS_TRUE(vSpans[0].GetDisableAffinity() == false); + VERIFY_IS_TRUE(vSpans[0].GetCompletionRoutines() == false); + VERIFY_IS_TRUE(vSpans[0].GetMeasureLatency() == false); + VERIFY_IS_TRUE(vSpans[0].GetRandomWriteData() == false); + + const auto& vAffinity(vSpans[0].GetAffinityAssignments()); + VERIFY_ARE_EQUAL(vAffinity.size(), (size_t)0); + + vector vTargets(vSpans[0].GetTargets()); + VERIFY_ARE_EQUAL(vTargets.size(), (size_t)1); + Target t(vTargets[0]); + + VERIFY_IS_TRUE(t.GetPath().compare("testfile.dat") == 0); + VERIFY_ARE_EQUAL(t.GetBlockSizeInBytes(), (DWORD)(128 * 1024)); + VERIFY_ARE_EQUAL(t.GetRequestCount(), (DWORD)2); + VERIFY_IS_TRUE(t.GetRandomRatio() == 0); + VERIFY_IS_TRUE(t.GetUseInterlockedSequential() == false); + VERIFY_ARE_EQUAL(t.GetBlockAlignmentInBytes(), t.GetBlockSizeInBytes()); + VERIFY_ARE_EQUAL(t.GetBaseFileOffsetInBytes(), 0); + VERIFY_IS_TRUE(t.GetUseParallelAsyncIO() == false); + VERIFY_IS_TRUE(t.GetCacheMode() == TargetCacheMode::Cached); + VERIFY_IS_TRUE(t.GetWriteThroughMode() == WriteThroughMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoMode() == MemoryMappedIoMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoFlushMode() == MemoryMappedIoFlushMode::Undefined); + VERIFY_IS_TRUE(t.GetZeroWriteBuffers() == false); + VERIFY_ARE_EQUAL(t.GetThreadsPerFile(), (DWORD)1); + VERIFY_ARE_EQUAL(t.GetThreadStrideInBytes(), 0); + VERIFY_IS_TRUE(t.GetCreateFile() == false); + VERIFY_ARE_EQUAL(t.GetFileSize(), 0); + VERIFY_ARE_EQUAL(t.GetMaxFileSize(), 0); + VERIFY_ARE_EQUAL(t.GetWriteRatio(), (DWORD)84); + VERIFY_IS_TRUE(t.GetUseBurstSize() == false); + VERIFY_ARE_EQUAL(t.GetBurstSize(), (DWORD)0); + VERIFY_ARE_EQUAL(t.GetThinkTime(), (DWORD)0); + VERIFY_IS_TRUE(t.GetEnableThinkTime() == false); + VERIFY_IS_TRUE(t.GetSequentialScanHint() == false); + VERIFY_IS_TRUE(t.GetRandomAccessHint() == false); + VERIFY_IS_TRUE(t.GetTemporaryFileHint() == false); + VERIFY_IS_TRUE(t.GetUseLargePages() == false); + VERIFY_ARE_EQUAL(t.GetThroughputInBytesPerMillisecond(), (DWORD)0); + } + + void CmdLineParserUnitTests::TestParseCmdLineRandSeedGetTickCount() + { + CmdLineParser p; + Profile profile; + struct Synchronization s = {}; + const char *argv[] = { "foo", "-b128K", "-w84", "-z", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == true); + VERIFY_IS_TRUE(profile.GetVerbose() == false); + VERIFY_IS_TRUE(profile.GetProgress() == 0); + VERIFY_IS_TRUE(profile.GetCmdLine().compare("foo -b128K -w84 -z testfile.dat") == 0); + VERIFY_IS_TRUE(profile.GetEtwEnabled() == false); + VERIFY_IS_TRUE(profile.GetEtwProcess() == false); + VERIFY_IS_TRUE(profile.GetEtwThread() == false); + VERIFY_IS_TRUE(profile.GetEtwImageLoad() == false); + VERIFY_IS_TRUE(profile.GetEtwDiskIO() == false); + VERIFY_IS_TRUE(profile.GetEtwMemoryPageFaults() == false); + VERIFY_IS_TRUE(profile.GetEtwMemoryHardFaults() == false); + VERIFY_IS_TRUE(profile.GetEtwNetwork() == false); + VERIFY_IS_TRUE(profile.GetEtwRegistry() == false); + VERIFY_IS_TRUE(profile.GetEtwUsePagedMemory() == false); + VERIFY_IS_TRUE(profile.GetEtwUsePerfTimer() == false); + VERIFY_IS_TRUE(profile.GetEtwUseSystemTimer() == false); + VERIFY_IS_TRUE(profile.GetEtwUseCyclesCounter() == false); + + vector vSpans(profile.GetTimeSpans()); + VERIFY_ARE_EQUAL(vSpans.size(), (size_t)1); + VERIFY_ARE_EQUAL(vSpans[0].GetDuration(), (UINT32)10); + VERIFY_ARE_EQUAL(vSpans[0].GetWarmup(), (UINT32)5); + VERIFY_ARE_EQUAL(vSpans[0].GetCooldown(), (UINT32)0); + VERIFY_IS_TRUE(vSpans[0].GetRandSeed() != 0); + VERIFY_ARE_EQUAL(vSpans[0].GetThreadCount(), (DWORD)0); + VERIFY_ARE_EQUAL(vSpans[0].GetRequestCount(), (DWORD)0); + VERIFY_IS_TRUE(vSpans[0].GetDisableAffinity() == false); + VERIFY_IS_TRUE(vSpans[0].GetCompletionRoutines() == false); + VERIFY_IS_TRUE(vSpans[0].GetMeasureLatency() == false); + VERIFY_IS_TRUE(vSpans[0].GetRandomWriteData() == false); + + const auto& vAffinity(vSpans[0].GetAffinityAssignments()); + VERIFY_ARE_EQUAL(vAffinity.size(), (size_t)0); + + vector vTargets(vSpans[0].GetTargets()); + VERIFY_ARE_EQUAL(vTargets.size(), (size_t)1); + Target t(vTargets[0]); + + VERIFY_IS_TRUE(t.GetPath().compare("testfile.dat") == 0); + VERIFY_ARE_EQUAL(t.GetBlockSizeInBytes(), (DWORD)(128 * 1024)); + VERIFY_ARE_EQUAL(t.GetRequestCount(), (DWORD)2); + VERIFY_IS_TRUE(t.GetRandomRatio() == 0); + VERIFY_IS_TRUE(t.GetUseInterlockedSequential() == false); + VERIFY_ARE_EQUAL(t.GetBlockAlignmentInBytes(), t.GetBlockSizeInBytes()); + VERIFY_ARE_EQUAL(t.GetBaseFileOffsetInBytes(), 0); + VERIFY_IS_TRUE(t.GetUseParallelAsyncIO() == false); + VERIFY_IS_TRUE(t.GetCacheMode() == TargetCacheMode::Cached); + VERIFY_IS_TRUE(t.GetWriteThroughMode() == WriteThroughMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoMode() == MemoryMappedIoMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoFlushMode() == MemoryMappedIoFlushMode::Undefined); + VERIFY_IS_TRUE(t.GetZeroWriteBuffers() == false); + VERIFY_ARE_EQUAL(t.GetThreadsPerFile(), (DWORD)1); + VERIFY_ARE_EQUAL(t.GetThreadStrideInBytes(), 0); + VERIFY_IS_TRUE(t.GetCreateFile() == false); + VERIFY_ARE_EQUAL(t.GetFileSize(), 0); + VERIFY_ARE_EQUAL(t.GetMaxFileSize(), 0); + VERIFY_ARE_EQUAL(t.GetWriteRatio(), (DWORD)84); + VERIFY_IS_TRUE(t.GetUseBurstSize() == false); + VERIFY_ARE_EQUAL(t.GetBurstSize(), (DWORD)0); + VERIFY_ARE_EQUAL(t.GetThinkTime(), (DWORD)0); + VERIFY_IS_TRUE(t.GetEnableThinkTime() == false); + VERIFY_IS_TRUE(t.GetSequentialScanHint() == false); + VERIFY_IS_TRUE(t.GetRandomAccessHint() == false); + VERIFY_IS_TRUE(t.GetTemporaryFileHint() == false); + VERIFY_IS_TRUE(t.GetUseLargePages() == false); + VERIFY_ARE_EQUAL(t.GetThroughputInBytesPerMillisecond(), (DWORD)0); + } + + void CmdLineParserUnitTests::TestParseCmdLineWarmupAndCooldown() + { + CmdLineParser p; + Profile profile; + struct Synchronization s = {}; + const char *argv[] = { "foo", "-b128K", "-w84", "-C12", "-W345", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == true); + VERIFY_IS_TRUE(profile.GetVerbose() == false); + VERIFY_IS_TRUE(profile.GetProgress() == 0); + VERIFY_IS_TRUE(profile.GetCmdLine().compare("foo -b128K -w84 -C12 -W345 testfile.dat") == 0); + VERIFY_IS_TRUE(profile.GetEtwEnabled() == false); + VERIFY_IS_TRUE(profile.GetEtwProcess() == false); + VERIFY_IS_TRUE(profile.GetEtwThread() == false); + VERIFY_IS_TRUE(profile.GetEtwImageLoad() == false); + VERIFY_IS_TRUE(profile.GetEtwDiskIO() == false); + VERIFY_IS_TRUE(profile.GetEtwMemoryPageFaults() == false); + VERIFY_IS_TRUE(profile.GetEtwMemoryHardFaults() == false); + VERIFY_IS_TRUE(profile.GetEtwNetwork() == false); + VERIFY_IS_TRUE(profile.GetEtwRegistry() == false); + VERIFY_IS_TRUE(profile.GetEtwUsePagedMemory() == false); + VERIFY_IS_TRUE(profile.GetEtwUsePerfTimer() == false); + VERIFY_IS_TRUE(profile.GetEtwUseSystemTimer() == false); + VERIFY_IS_TRUE(profile.GetEtwUseCyclesCounter() == false); + + vector vSpans(profile.GetTimeSpans()); + VERIFY_ARE_EQUAL(vSpans.size(), (size_t)1); + VERIFY_ARE_EQUAL(vSpans[0].GetDuration(), (UINT32)10); + VERIFY_ARE_EQUAL(vSpans[0].GetWarmup(), (UINT32)345); + VERIFY_ARE_EQUAL(vSpans[0].GetCooldown(), (UINT32)12); + VERIFY_ARE_EQUAL(vSpans[0].GetRandSeed(), (UINT32)0); + VERIFY_ARE_EQUAL(vSpans[0].GetThreadCount(), (DWORD)0); + VERIFY_ARE_EQUAL(vSpans[0].GetRequestCount(), (DWORD)0); + VERIFY_IS_TRUE(vSpans[0].GetDisableAffinity() == false); + VERIFY_IS_TRUE(vSpans[0].GetCompletionRoutines() == false); + VERIFY_IS_TRUE(vSpans[0].GetMeasureLatency() == false); + VERIFY_IS_TRUE(vSpans[0].GetRandomWriteData() == false); + + const auto& vAffinity(vSpans[0].GetAffinityAssignments()); + VERIFY_ARE_EQUAL(vAffinity.size(), (size_t)0); + + vector vTargets(vSpans[0].GetTargets()); + VERIFY_ARE_EQUAL(vTargets.size(), (size_t)1); + Target t(vTargets[0]); + + VERIFY_IS_TRUE(t.GetPath().compare("testfile.dat") == 0); + VERIFY_ARE_EQUAL(t.GetBlockSizeInBytes(), (DWORD)(128 * 1024)); + VERIFY_ARE_EQUAL(t.GetRequestCount(), (DWORD)2); + VERIFY_IS_TRUE(t.GetRandomRatio() == 0); + VERIFY_IS_TRUE(t.GetUseInterlockedSequential() == false); + VERIFY_ARE_EQUAL(t.GetBlockAlignmentInBytes(), t.GetBlockSizeInBytes()); + VERIFY_ARE_EQUAL(t.GetBaseFileOffsetInBytes(), 0); + VERIFY_IS_TRUE(t.GetUseParallelAsyncIO() == false); + VERIFY_IS_TRUE(t.GetCacheMode() == TargetCacheMode::Cached); + VERIFY_IS_TRUE(t.GetWriteThroughMode() == WriteThroughMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoMode() == MemoryMappedIoMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoFlushMode() == MemoryMappedIoFlushMode::Undefined); + VERIFY_IS_TRUE(t.GetZeroWriteBuffers() == false); + VERIFY_ARE_EQUAL(t.GetThreadsPerFile(), (DWORD)1); + VERIFY_ARE_EQUAL(t.GetThreadStrideInBytes(), 0); + VERIFY_IS_TRUE(t.GetCreateFile() == false); + VERIFY_ARE_EQUAL(t.GetFileSize(), 0); + VERIFY_ARE_EQUAL(t.GetMaxFileSize(), 0); + VERIFY_ARE_EQUAL(t.GetWriteRatio(), (DWORD)84); + VERIFY_IS_TRUE(t.GetUseBurstSize() == false); + VERIFY_ARE_EQUAL(t.GetBurstSize(), (DWORD)0); + VERIFY_ARE_EQUAL(t.GetThinkTime(), (DWORD)0); + VERIFY_IS_TRUE(t.GetEnableThinkTime() == false); + VERIFY_IS_TRUE(t.GetSequentialScanHint() == false); + VERIFY_IS_TRUE(t.GetRandomAccessHint() == false); + VERIFY_IS_TRUE(t.GetTemporaryFileHint() == false); + VERIFY_IS_TRUE(t.GetUseLargePages() == false); + VERIFY_ARE_EQUAL(t.GetThroughputInBytesPerMillisecond(), (DWORD)0); + } + + void CmdLineParserUnitTests::TestParseCmdLineDurationAndProgress() + { + CmdLineParser p; + Profile profile; + struct Synchronization s = {}; + const char *argv[] = { "foo", "-b128K", "-w84", "-d12", "-P345", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == true); + VERIFY_IS_TRUE(profile.GetVerbose() == false); + VERIFY_IS_TRUE(profile.GetProgress() == 345); + VERIFY_IS_TRUE(profile.GetCmdLine().compare("foo -b128K -w84 -d12 -P345 testfile.dat") == 0); + VERIFY_IS_TRUE(profile.GetEtwEnabled() == false); + VERIFY_IS_TRUE(profile.GetEtwProcess() == false); + VERIFY_IS_TRUE(profile.GetEtwThread() == false); + VERIFY_IS_TRUE(profile.GetEtwImageLoad() == false); + VERIFY_IS_TRUE(profile.GetEtwDiskIO() == false); + VERIFY_IS_TRUE(profile.GetEtwMemoryPageFaults() == false); + VERIFY_IS_TRUE(profile.GetEtwMemoryHardFaults() == false); + VERIFY_IS_TRUE(profile.GetEtwNetwork() == false); + VERIFY_IS_TRUE(profile.GetEtwRegistry() == false); + VERIFY_IS_TRUE(profile.GetEtwUsePagedMemory() == false); + VERIFY_IS_TRUE(profile.GetEtwUsePerfTimer() == false); + VERIFY_IS_TRUE(profile.GetEtwUseSystemTimer() == false); + VERIFY_IS_TRUE(profile.GetEtwUseCyclesCounter() == false); + + vector vSpans(profile.GetTimeSpans()); + VERIFY_ARE_EQUAL(vSpans.size(), (size_t)1); + VERIFY_ARE_EQUAL(vSpans[0].GetDuration(), (UINT32)12); + VERIFY_ARE_EQUAL(vSpans[0].GetWarmup(), (UINT32)5); + VERIFY_ARE_EQUAL(vSpans[0].GetCooldown(), (UINT32)0); + VERIFY_ARE_EQUAL(vSpans[0].GetRandSeed(), (UINT32)0); + VERIFY_ARE_EQUAL(vSpans[0].GetThreadCount(), (DWORD)0); + VERIFY_ARE_EQUAL(vSpans[0].GetRequestCount(), (DWORD)0); + VERIFY_IS_TRUE(vSpans[0].GetDisableAffinity() == false); + VERIFY_IS_TRUE(vSpans[0].GetCompletionRoutines() == false); + VERIFY_IS_TRUE(vSpans[0].GetMeasureLatency() == false); + VERIFY_IS_TRUE(vSpans[0].GetRandomWriteData() == false); + + const auto& vAffinity(vSpans[0].GetAffinityAssignments()); + VERIFY_ARE_EQUAL(vAffinity.size(), (size_t)0); + + vector vTargets(vSpans[0].GetTargets()); + VERIFY_ARE_EQUAL(vTargets.size(), (size_t)1); + Target t(vTargets[0]); + + VERIFY_IS_TRUE(t.GetPath().compare("testfile.dat") == 0); + VERIFY_ARE_EQUAL(t.GetBlockSizeInBytes(), (DWORD)(128 * 1024)); + VERIFY_ARE_EQUAL(t.GetRequestCount(), (DWORD)2); + VERIFY_IS_TRUE(t.GetRandomRatio() == 0); + VERIFY_IS_TRUE(t.GetUseInterlockedSequential() == false); + VERIFY_ARE_EQUAL(t.GetBlockAlignmentInBytes(), t.GetBlockSizeInBytes()); + VERIFY_ARE_EQUAL(t.GetBaseFileOffsetInBytes(), 0); + VERIFY_IS_TRUE(t.GetUseParallelAsyncIO() == false); + VERIFY_IS_TRUE(t.GetCacheMode() == TargetCacheMode::Cached); + VERIFY_IS_TRUE(t.GetWriteThroughMode() == WriteThroughMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoMode() == MemoryMappedIoMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoFlushMode() == MemoryMappedIoFlushMode::Undefined); + VERIFY_IS_TRUE(t.GetZeroWriteBuffers() == false); + VERIFY_ARE_EQUAL(t.GetThreadsPerFile(), (DWORD)1); + VERIFY_ARE_EQUAL(t.GetThreadStrideInBytes(), 0); + VERIFY_IS_TRUE(t.GetCreateFile() == false); + VERIFY_ARE_EQUAL(t.GetFileSize(), 0); + VERIFY_ARE_EQUAL(t.GetMaxFileSize(), 0); + VERIFY_ARE_EQUAL(t.GetWriteRatio(), (DWORD)84); + VERIFY_IS_TRUE(t.GetUseBurstSize() == false); + VERIFY_ARE_EQUAL(t.GetBurstSize(), (DWORD)0); + VERIFY_ARE_EQUAL(t.GetThinkTime(), (DWORD)0); + VERIFY_IS_TRUE(t.GetEnableThinkTime() == false); + VERIFY_IS_TRUE(t.GetSequentialScanHint() == false); + VERIFY_IS_TRUE(t.GetRandomAccessHint() == false); + VERIFY_IS_TRUE(t.GetTemporaryFileHint() == false); + VERIFY_IS_TRUE(t.GetUseLargePages() == false); + VERIFY_ARE_EQUAL(t.GetThroughputInBytesPerMillisecond(), (DWORD)0); + } + + void CmdLineParserUnitTests::TestParseCmdLineUseParallelAsyncIO() + { + CmdLineParser p; + Profile profile; + struct Synchronization s = {}; + const char *argv[] = { "foo", "-b128K", "-w84", "-p", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == true); + VERIFY_IS_TRUE(profile.GetVerbose() == false); + VERIFY_IS_TRUE(profile.GetProgress() == 0); + VERIFY_IS_TRUE(profile.GetCmdLine().compare("foo -b128K -w84 -p testfile.dat") == 0); + VERIFY_IS_TRUE(profile.GetEtwEnabled() == false); + VERIFY_IS_TRUE(profile.GetEtwProcess() == false); + VERIFY_IS_TRUE(profile.GetEtwThread() == false); + VERIFY_IS_TRUE(profile.GetEtwImageLoad() == false); + VERIFY_IS_TRUE(profile.GetEtwDiskIO() == false); + VERIFY_IS_TRUE(profile.GetEtwMemoryPageFaults() == false); + VERIFY_IS_TRUE(profile.GetEtwMemoryHardFaults() == false); + VERIFY_IS_TRUE(profile.GetEtwNetwork() == false); + VERIFY_IS_TRUE(profile.GetEtwRegistry() == false); + VERIFY_IS_TRUE(profile.GetEtwUsePagedMemory() == false); + VERIFY_IS_TRUE(profile.GetEtwUsePerfTimer() == false); + VERIFY_IS_TRUE(profile.GetEtwUseSystemTimer() == false); + VERIFY_IS_TRUE(profile.GetEtwUseCyclesCounter() == false); + + vector vSpans(profile.GetTimeSpans()); + VERIFY_ARE_EQUAL(vSpans.size(), (size_t)1); + VERIFY_ARE_EQUAL(vSpans[0].GetDuration(), (UINT32)10); + VERIFY_ARE_EQUAL(vSpans[0].GetWarmup(), (UINT32)5); + VERIFY_ARE_EQUAL(vSpans[0].GetCooldown(), (UINT32)0); + VERIFY_ARE_EQUAL(vSpans[0].GetRandSeed(), (UINT32)0); + VERIFY_ARE_EQUAL(vSpans[0].GetThreadCount(), (DWORD)0); + VERIFY_ARE_EQUAL(vSpans[0].GetRequestCount(), (DWORD)0); + VERIFY_IS_TRUE(vSpans[0].GetDisableAffinity() == false); + VERIFY_IS_TRUE(vSpans[0].GetCompletionRoutines() == false); + VERIFY_IS_TRUE(vSpans[0].GetMeasureLatency() == false); + VERIFY_IS_TRUE(vSpans[0].GetRandomWriteData() == false); + + const auto& vAffinity(vSpans[0].GetAffinityAssignments()); + VERIFY_ARE_EQUAL(vAffinity.size(), (size_t)0); + + vector vTargets(vSpans[0].GetTargets()); + VERIFY_ARE_EQUAL(vTargets.size(), (size_t)1); + Target t(vTargets[0]); + + VERIFY_IS_TRUE(t.GetPath().compare("testfile.dat") == 0); + VERIFY_ARE_EQUAL(t.GetBlockSizeInBytes(), (DWORD)(128 * 1024)); + VERIFY_ARE_EQUAL(t.GetRequestCount(), (DWORD)2); + VERIFY_IS_TRUE(t.GetRandomRatio() == 0); + VERIFY_IS_TRUE(t.GetUseInterlockedSequential() == false); + VERIFY_ARE_EQUAL(t.GetBlockAlignmentInBytes(), t.GetBlockSizeInBytes()); + VERIFY_ARE_EQUAL(t.GetBaseFileOffsetInBytes(), 0); + VERIFY_IS_TRUE(t.GetUseParallelAsyncIO() == true); + VERIFY_IS_TRUE(t.GetCacheMode() == TargetCacheMode::Cached); + VERIFY_IS_TRUE(t.GetWriteThroughMode() == WriteThroughMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoMode() == MemoryMappedIoMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoFlushMode() == MemoryMappedIoFlushMode::Undefined); + VERIFY_IS_TRUE(t.GetZeroWriteBuffers() == false); + VERIFY_ARE_EQUAL(t.GetThreadsPerFile(), (DWORD)1); + VERIFY_ARE_EQUAL(t.GetThreadStrideInBytes(), 0); + VERIFY_IS_TRUE(t.GetCreateFile() == false); + VERIFY_ARE_EQUAL(t.GetFileSize(), 0); + VERIFY_ARE_EQUAL(t.GetMaxFileSize(), 0); + VERIFY_ARE_EQUAL(t.GetWriteRatio(), (DWORD)84); + VERIFY_IS_TRUE(t.GetUseBurstSize() == false); + VERIFY_ARE_EQUAL(t.GetBurstSize(), (DWORD)0); + VERIFY_ARE_EQUAL(t.GetThinkTime(), (DWORD)0); + VERIFY_IS_TRUE(t.GetEnableThinkTime() == false); + VERIFY_IS_TRUE(t.GetSequentialScanHint() == false); + VERIFY_IS_TRUE(t.GetRandomAccessHint() == false); + VERIFY_IS_TRUE(t.GetTemporaryFileHint() == false); + VERIFY_IS_TRUE(t.GetUseLargePages() == false); + VERIFY_ARE_EQUAL(t.GetThroughputInBytesPerMillisecond(), (DWORD)0); + } + + void CmdLineParserUnitTests::TestParseCmdLineUseLargePages() + { + CmdLineParser p; + Profile profile; + struct Synchronization s = {}; + const char *argv[] = { "foo", "-b128K", "-w84", "-l", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == true); + VERIFY_IS_TRUE(profile.GetVerbose() == false); + VERIFY_IS_TRUE(profile.GetProgress() == 0); + VERIFY_IS_TRUE(profile.GetCmdLine().compare("foo -b128K -w84 -l testfile.dat") == 0); + VERIFY_IS_TRUE(profile.GetEtwEnabled() == false); + VERIFY_IS_TRUE(profile.GetEtwProcess() == false); + VERIFY_IS_TRUE(profile.GetEtwThread() == false); + VERIFY_IS_TRUE(profile.GetEtwImageLoad() == false); + VERIFY_IS_TRUE(profile.GetEtwDiskIO() == false); + VERIFY_IS_TRUE(profile.GetEtwMemoryPageFaults() == false); + VERIFY_IS_TRUE(profile.GetEtwMemoryHardFaults() == false); + VERIFY_IS_TRUE(profile.GetEtwNetwork() == false); + VERIFY_IS_TRUE(profile.GetEtwRegistry() == false); + VERIFY_IS_TRUE(profile.GetEtwUsePagedMemory() == false); + VERIFY_IS_TRUE(profile.GetEtwUsePerfTimer() == false); + VERIFY_IS_TRUE(profile.GetEtwUseSystemTimer() == false); + VERIFY_IS_TRUE(profile.GetEtwUseCyclesCounter() == false); + + vector vSpans(profile.GetTimeSpans()); + VERIFY_ARE_EQUAL(vSpans.size(), (size_t)1); + VERIFY_ARE_EQUAL(vSpans[0].GetDuration(), (UINT32)10); + VERIFY_ARE_EQUAL(vSpans[0].GetWarmup(), (UINT32)5); + VERIFY_ARE_EQUAL(vSpans[0].GetCooldown(), (UINT32)0); + VERIFY_ARE_EQUAL(vSpans[0].GetRandSeed(), (UINT32)0); + VERIFY_ARE_EQUAL(vSpans[0].GetThreadCount(), (DWORD)0); + VERIFY_ARE_EQUAL(vSpans[0].GetRequestCount(), (DWORD)0); + VERIFY_IS_TRUE(vSpans[0].GetDisableAffinity() == false); + VERIFY_IS_TRUE(vSpans[0].GetCompletionRoutines() == false); + VERIFY_IS_TRUE(vSpans[0].GetMeasureLatency() == false); + VERIFY_IS_TRUE(vSpans[0].GetRandomWriteData() == false); + + const auto& vAffinity(vSpans[0].GetAffinityAssignments()); + VERIFY_ARE_EQUAL(vAffinity.size(), (size_t)0); + + vector vTargets(vSpans[0].GetTargets()); + VERIFY_ARE_EQUAL(vTargets.size(), (size_t)1); + Target t(vTargets[0]); + + VERIFY_IS_TRUE(t.GetPath().compare("testfile.dat") == 0); + VERIFY_ARE_EQUAL(t.GetBlockSizeInBytes(), (DWORD)(128 * 1024)); + VERIFY_ARE_EQUAL(t.GetRequestCount(), (DWORD)2); + VERIFY_IS_TRUE(t.GetRandomRatio() == 0); + VERIFY_IS_TRUE(t.GetUseInterlockedSequential() == false); + VERIFY_ARE_EQUAL(t.GetBlockAlignmentInBytes(), t.GetBlockSizeInBytes()); + VERIFY_ARE_EQUAL(t.GetBaseFileOffsetInBytes(), 0); + VERIFY_IS_TRUE(t.GetUseParallelAsyncIO() == false); + VERIFY_IS_TRUE(t.GetCacheMode() == TargetCacheMode::Cached); + VERIFY_IS_TRUE(t.GetWriteThroughMode() == WriteThroughMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoMode() == MemoryMappedIoMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoFlushMode() == MemoryMappedIoFlushMode::Undefined); + VERIFY_IS_TRUE(t.GetZeroWriteBuffers() == false); + VERIFY_ARE_EQUAL(t.GetThreadsPerFile(), (DWORD)1); + VERIFY_ARE_EQUAL(t.GetThreadStrideInBytes(), 0); + VERIFY_IS_TRUE(t.GetCreateFile() == false); + VERIFY_ARE_EQUAL(t.GetFileSize(), 0); + VERIFY_ARE_EQUAL(t.GetMaxFileSize(), 0); + VERIFY_ARE_EQUAL(t.GetWriteRatio(), (DWORD)84); + VERIFY_IS_TRUE(t.GetUseBurstSize() == false); + VERIFY_ARE_EQUAL(t.GetBurstSize(), (DWORD)0); + VERIFY_ARE_EQUAL(t.GetThinkTime(), (DWORD)0); + VERIFY_IS_TRUE(t.GetEnableThinkTime() == false); + VERIFY_IS_TRUE(t.GetSequentialScanHint() == false); + VERIFY_IS_TRUE(t.GetRandomAccessHint() == false); + VERIFY_IS_TRUE(t.GetTemporaryFileHint() == false); + VERIFY_IS_TRUE(t.GetUseLargePages() == true); + VERIFY_ARE_EQUAL(t.GetThroughputInBytesPerMillisecond(), (DWORD)0); + } + + void CmdLineParserUnitTests::TestParseCmdLineOverlappedCountAndBaseOffset() + { + CmdLineParser p; + Profile profile; + struct Synchronization s = {}; + const char *argv[] = { "foo", "-b128K", "-w84", "-o123", "-B512k", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == true); + VERIFY_IS_TRUE(profile.GetVerbose() == false); + VERIFY_IS_TRUE(profile.GetProgress() == 0); + VERIFY_IS_TRUE(profile.GetCmdLine().compare("foo -b128K -w84 -o123 -B512k testfile.dat") == 0); + VERIFY_IS_TRUE(profile.GetEtwEnabled() == false); + VERIFY_IS_TRUE(profile.GetEtwProcess() == false); + VERIFY_IS_TRUE(profile.GetEtwThread() == false); + VERIFY_IS_TRUE(profile.GetEtwImageLoad() == false); + VERIFY_IS_TRUE(profile.GetEtwDiskIO() == false); + VERIFY_IS_TRUE(profile.GetEtwMemoryPageFaults() == false); + VERIFY_IS_TRUE(profile.GetEtwMemoryHardFaults() == false); + VERIFY_IS_TRUE(profile.GetEtwNetwork() == false); + VERIFY_IS_TRUE(profile.GetEtwRegistry() == false); + VERIFY_IS_TRUE(profile.GetEtwUsePagedMemory() == false); + VERIFY_IS_TRUE(profile.GetEtwUsePerfTimer() == false); + VERIFY_IS_TRUE(profile.GetEtwUseSystemTimer() == false); + VERIFY_IS_TRUE(profile.GetEtwUseCyclesCounter() == false); + + vector vSpans(profile.GetTimeSpans()); + VERIFY_ARE_EQUAL(vSpans.size(), (size_t)1); + VERIFY_ARE_EQUAL(vSpans[0].GetDuration(), (UINT32)10); + VERIFY_ARE_EQUAL(vSpans[0].GetWarmup(), (UINT32)5); + VERIFY_ARE_EQUAL(vSpans[0].GetCooldown(), (UINT32)0); + VERIFY_ARE_EQUAL(vSpans[0].GetRandSeed(), (UINT32)0); + VERIFY_ARE_EQUAL(vSpans[0].GetThreadCount(), (DWORD)0); + VERIFY_ARE_EQUAL(vSpans[0].GetRequestCount(), (DWORD)0); + VERIFY_IS_TRUE(vSpans[0].GetDisableAffinity() == false); + VERIFY_IS_TRUE(vSpans[0].GetCompletionRoutines() == false); + VERIFY_IS_TRUE(vSpans[0].GetMeasureLatency() == false); + VERIFY_IS_TRUE(vSpans[0].GetRandomWriteData() == false); + + const auto& vAffinity(vSpans[0].GetAffinityAssignments()); + VERIFY_ARE_EQUAL(vAffinity.size(), (size_t)0); + + vector vTargets(vSpans[0].GetTargets()); + VERIFY_ARE_EQUAL(vTargets.size(), (size_t)1); + Target t(vTargets[0]); + + VERIFY_IS_TRUE(t.GetPath().compare("testfile.dat") == 0); + VERIFY_ARE_EQUAL(t.GetBlockSizeInBytes(), (DWORD)(128 * 1024)); + VERIFY_ARE_EQUAL(t.GetRequestCount(), (DWORD)123); + VERIFY_IS_TRUE(t.GetRandomRatio() == 0); + VERIFY_IS_TRUE(t.GetUseInterlockedSequential() == false); + VERIFY_ARE_EQUAL(t.GetBlockAlignmentInBytes(), t.GetBlockSizeInBytes()); + VERIFY_ARE_EQUAL(t.GetBaseFileOffsetInBytes(), 512 * 1024); + VERIFY_IS_TRUE(t.GetUseParallelAsyncIO() == false); + VERIFY_IS_TRUE(t.GetCacheMode() == TargetCacheMode::Cached); + VERIFY_IS_TRUE(t.GetWriteThroughMode() == WriteThroughMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoMode() == MemoryMappedIoMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoFlushMode() == MemoryMappedIoFlushMode::Undefined); + VERIFY_IS_TRUE(t.GetZeroWriteBuffers() == false); + VERIFY_ARE_EQUAL(t.GetThreadsPerFile(), (DWORD)1); + VERIFY_ARE_EQUAL(t.GetThreadStrideInBytes(), 0); + VERIFY_IS_TRUE(t.GetCreateFile() == false); + VERIFY_ARE_EQUAL(t.GetFileSize(), 0); + VERIFY_ARE_EQUAL(t.GetMaxFileSize(), 0); + VERIFY_ARE_EQUAL(t.GetWriteRatio(), (DWORD)84); + VERIFY_IS_TRUE(t.GetUseBurstSize() == false); + VERIFY_ARE_EQUAL(t.GetBurstSize(), (DWORD)0); + VERIFY_ARE_EQUAL(t.GetThinkTime(), (DWORD)0); + VERIFY_IS_TRUE(t.GetEnableThinkTime() == false); + VERIFY_IS_TRUE(t.GetSequentialScanHint() == false); + VERIFY_IS_TRUE(t.GetRandomAccessHint() == false); + VERIFY_IS_TRUE(t.GetTemporaryFileHint() == false); + VERIFY_IS_TRUE(t.GetUseLargePages() == false); + VERIFY_ARE_EQUAL(t.GetThroughputInBytesPerMillisecond(), (DWORD)0); + } + + void CmdLineParserUnitTests::TestParseCmdLineCreateFileAndMaxFileSize() + { + CmdLineParser p; + Profile profile; + struct Synchronization s = {}; + const char *argv[] = { "foo", "-b128K", "-w84", "-c23", "-f4M", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == true); + VERIFY_IS_TRUE(profile.GetVerbose() == false); + VERIFY_IS_TRUE(profile.GetProgress() == 0); + VERIFY_IS_TRUE(profile.GetCmdLine().compare("foo -b128K -w84 -c23 -f4M testfile.dat") == 0); + VERIFY_IS_TRUE(profile.GetEtwEnabled() == false); + VERIFY_IS_TRUE(profile.GetEtwProcess() == false); + VERIFY_IS_TRUE(profile.GetEtwThread() == false); + VERIFY_IS_TRUE(profile.GetEtwImageLoad() == false); + VERIFY_IS_TRUE(profile.GetEtwDiskIO() == false); + VERIFY_IS_TRUE(profile.GetEtwMemoryPageFaults() == false); + VERIFY_IS_TRUE(profile.GetEtwMemoryHardFaults() == false); + VERIFY_IS_TRUE(profile.GetEtwNetwork() == false); + VERIFY_IS_TRUE(profile.GetEtwRegistry() == false); + VERIFY_IS_TRUE(profile.GetEtwUsePagedMemory() == false); + VERIFY_IS_TRUE(profile.GetEtwUsePerfTimer() == false); + VERIFY_IS_TRUE(profile.GetEtwUseSystemTimer() == false); + VERIFY_IS_TRUE(profile.GetEtwUseCyclesCounter() == false); + + vector vSpans(profile.GetTimeSpans()); + VERIFY_ARE_EQUAL(vSpans.size(), (size_t)1); + VERIFY_ARE_EQUAL(vSpans[0].GetDuration(), (UINT32)10); + VERIFY_ARE_EQUAL(vSpans[0].GetWarmup(), (UINT32)5); + VERIFY_ARE_EQUAL(vSpans[0].GetCooldown(), (UINT32)0); + VERIFY_ARE_EQUAL(vSpans[0].GetRandSeed(), (UINT32)0); + VERIFY_ARE_EQUAL(vSpans[0].GetThreadCount(), (DWORD)0); + VERIFY_ARE_EQUAL(vSpans[0].GetRequestCount(), (DWORD)0); + VERIFY_IS_TRUE(vSpans[0].GetDisableAffinity() == false); + VERIFY_IS_TRUE(vSpans[0].GetCompletionRoutines() == false); + VERIFY_IS_TRUE(vSpans[0].GetMeasureLatency() == false); + VERIFY_IS_TRUE(vSpans[0].GetRandomWriteData() == false); + + const auto& vAffinity(vSpans[0].GetAffinityAssignments()); + VERIFY_ARE_EQUAL(vAffinity.size(), (size_t)0); + + vector vTargets(vSpans[0].GetTargets()); + VERIFY_ARE_EQUAL(vTargets.size(), (size_t)1); + Target t(vTargets[0]); + + VERIFY_IS_TRUE(t.GetPath().compare("testfile.dat") == 0); + VERIFY_ARE_EQUAL(t.GetBlockSizeInBytes(), (DWORD)(128 * 1024)); + VERIFY_ARE_EQUAL(t.GetRequestCount(), (DWORD)2); + VERIFY_IS_TRUE(t.GetRandomRatio() == 0); + VERIFY_IS_TRUE(t.GetUseInterlockedSequential() == false); + VERIFY_ARE_EQUAL(t.GetBlockAlignmentInBytes(), t.GetBlockSizeInBytes()); + VERIFY_ARE_EQUAL(t.GetBaseFileOffsetInBytes(), 0); + VERIFY_IS_TRUE(t.GetUseParallelAsyncIO() == false); + VERIFY_IS_TRUE(t.GetCacheMode() == TargetCacheMode::Cached); + VERIFY_IS_TRUE(t.GetWriteThroughMode() == WriteThroughMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoMode() == MemoryMappedIoMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoFlushMode() == MemoryMappedIoFlushMode::Undefined); + VERIFY_IS_TRUE(t.GetZeroWriteBuffers() == false); + VERIFY_ARE_EQUAL(t.GetThreadsPerFile(), (DWORD)1); + VERIFY_ARE_EQUAL(t.GetThreadStrideInBytes(), 0); + VERIFY_IS_TRUE(t.GetCreateFile() == true); + VERIFY_ARE_EQUAL(t.GetFileSize(), 23); + VERIFY_ARE_EQUAL(t.GetMaxFileSize(), (4 * 1024 * 1024)); + VERIFY_ARE_EQUAL(t.GetWriteRatio(), (DWORD)84); + VERIFY_IS_TRUE(t.GetUseBurstSize() == false); + VERIFY_ARE_EQUAL(t.GetBurstSize(), (DWORD)0); + VERIFY_ARE_EQUAL(t.GetThinkTime(), (DWORD)0); + VERIFY_IS_TRUE(t.GetEnableThinkTime() == false); + VERIFY_IS_TRUE(t.GetSequentialScanHint() == false); + VERIFY_IS_TRUE(t.GetRandomAccessHint() == false); + VERIFY_IS_TRUE(t.GetTemporaryFileHint() == false); + VERIFY_IS_TRUE(t.GetUseLargePages() == false); + VERIFY_ARE_EQUAL(t.GetThroughputInBytesPerMillisecond(), (DWORD)0); + } + + void CmdLineParserUnitTests::TestParseCmdLineBurstSizeAndThinkTime() + { + CmdLineParser p; + Profile profile; + struct Synchronization s = {}; + const char *argv[] = { "foo", "-b128K", "-w84", "-i23", "-j567", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == true); + VERIFY_IS_TRUE(profile.GetVerbose() == false); + VERIFY_IS_TRUE(profile.GetProgress() == 0); + VERIFY_IS_TRUE(profile.GetCmdLine().compare("foo -b128K -w84 -i23 -j567 testfile.dat") == 0); + VERIFY_IS_TRUE(profile.GetEtwEnabled() == false); + VERIFY_IS_TRUE(profile.GetEtwProcess() == false); + VERIFY_IS_TRUE(profile.GetEtwThread() == false); + VERIFY_IS_TRUE(profile.GetEtwImageLoad() == false); + VERIFY_IS_TRUE(profile.GetEtwDiskIO() == false); + VERIFY_IS_TRUE(profile.GetEtwMemoryPageFaults() == false); + VERIFY_IS_TRUE(profile.GetEtwMemoryHardFaults() == false); + VERIFY_IS_TRUE(profile.GetEtwNetwork() == false); + VERIFY_IS_TRUE(profile.GetEtwRegistry() == false); + VERIFY_IS_TRUE(profile.GetEtwUsePagedMemory() == false); + VERIFY_IS_TRUE(profile.GetEtwUsePerfTimer() == false); + VERIFY_IS_TRUE(profile.GetEtwUseSystemTimer() == false); + VERIFY_IS_TRUE(profile.GetEtwUseCyclesCounter() == false); + + vector vSpans(profile.GetTimeSpans()); + VERIFY_ARE_EQUAL(vSpans.size(), (size_t)1); + VERIFY_ARE_EQUAL(vSpans[0].GetDuration(), (UINT32)10); + VERIFY_ARE_EQUAL(vSpans[0].GetWarmup(), (UINT32)5); + VERIFY_ARE_EQUAL(vSpans[0].GetCooldown(), (UINT32)0); + VERIFY_ARE_EQUAL(vSpans[0].GetRandSeed(), (UINT32)0); + VERIFY_ARE_EQUAL(vSpans[0].GetThreadCount(), (DWORD)0); + VERIFY_ARE_EQUAL(vSpans[0].GetRequestCount(), (DWORD)0); + VERIFY_IS_TRUE(vSpans[0].GetDisableAffinity() == false); + VERIFY_IS_TRUE(vSpans[0].GetCompletionRoutines() == false); + VERIFY_IS_TRUE(vSpans[0].GetMeasureLatency() == false); + VERIFY_IS_TRUE(vSpans[0].GetRandomWriteData() == false); + + const auto& vAffinity(vSpans[0].GetAffinityAssignments()); + VERIFY_ARE_EQUAL(vAffinity.size(), (size_t)0); + + vector vTargets(vSpans[0].GetTargets()); + VERIFY_ARE_EQUAL(vTargets.size(), (size_t)1); + Target t(vTargets[0]); + + VERIFY_IS_TRUE(t.GetPath().compare("testfile.dat") == 0); + VERIFY_ARE_EQUAL(t.GetBlockSizeInBytes(), (DWORD)(128 * 1024)); + VERIFY_ARE_EQUAL(t.GetRequestCount(), (DWORD)2); + VERIFY_IS_TRUE(t.GetRandomRatio() == 0); + VERIFY_IS_TRUE(t.GetUseInterlockedSequential() == false); + VERIFY_ARE_EQUAL(t.GetBlockAlignmentInBytes(), t.GetBlockSizeInBytes()); + VERIFY_ARE_EQUAL(t.GetBaseFileOffsetInBytes(), 0); + VERIFY_IS_TRUE(t.GetUseParallelAsyncIO() == false); + VERIFY_IS_TRUE(t.GetCacheMode() == TargetCacheMode::Cached); + VERIFY_IS_TRUE(t.GetWriteThroughMode() == WriteThroughMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoMode() == MemoryMappedIoMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoFlushMode() == MemoryMappedIoFlushMode::Undefined); + VERIFY_IS_TRUE(t.GetZeroWriteBuffers() == false); + VERIFY_ARE_EQUAL(t.GetThreadsPerFile(), (DWORD)1); + VERIFY_ARE_EQUAL(t.GetThreadStrideInBytes(), 0); + VERIFY_IS_TRUE(t.GetCreateFile() == false); + VERIFY_ARE_EQUAL(t.GetFileSize(), 0); + VERIFY_ARE_EQUAL(t.GetMaxFileSize(), 0); + VERIFY_ARE_EQUAL(t.GetWriteRatio(), (DWORD)84); + VERIFY_IS_TRUE(t.GetUseBurstSize() == true); + VERIFY_ARE_EQUAL(t.GetBurstSize(), (DWORD)23); + VERIFY_ARE_EQUAL(t.GetThinkTime(), (DWORD)567); + VERIFY_IS_TRUE(t.GetEnableThinkTime() == true); + VERIFY_IS_TRUE(t.GetSequentialScanHint() == false); + VERIFY_IS_TRUE(t.GetRandomAccessHint() == false); + VERIFY_IS_TRUE(t.GetTemporaryFileHint() == false); + VERIFY_IS_TRUE(t.GetUseLargePages() == false); + VERIFY_ARE_EQUAL(t.GetThroughputInBytesPerMillisecond(), (DWORD)0); + } + + void CmdLineParserUnitTests::TestParseCmdLineTotalThreadCountAndThroughput() + { + CmdLineParser p; + Profile profile; + struct Synchronization s = {}; + const char *argv[] = { "foo", "-b128K", "-w84", "-F23", "-g567", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == true); + VERIFY_IS_TRUE(profile.GetVerbose() == false); + VERIFY_IS_TRUE(profile.GetProgress() == 0); + VERIFY_IS_TRUE(profile.GetCmdLine().compare("foo -b128K -w84 -F23 -g567 testfile.dat") == 0); + VERIFY_IS_TRUE(profile.GetEtwEnabled() == false); + VERIFY_IS_TRUE(profile.GetEtwProcess() == false); + VERIFY_IS_TRUE(profile.GetEtwThread() == false); + VERIFY_IS_TRUE(profile.GetEtwImageLoad() == false); + VERIFY_IS_TRUE(profile.GetEtwDiskIO() == false); + VERIFY_IS_TRUE(profile.GetEtwMemoryPageFaults() == false); + VERIFY_IS_TRUE(profile.GetEtwMemoryHardFaults() == false); + VERIFY_IS_TRUE(profile.GetEtwNetwork() == false); + VERIFY_IS_TRUE(profile.GetEtwRegistry() == false); + VERIFY_IS_TRUE(profile.GetEtwUsePagedMemory() == false); + VERIFY_IS_TRUE(profile.GetEtwUsePerfTimer() == false); + VERIFY_IS_TRUE(profile.GetEtwUseSystemTimer() == false); + VERIFY_IS_TRUE(profile.GetEtwUseCyclesCounter() == false); + + vector vSpans(profile.GetTimeSpans()); + VERIFY_ARE_EQUAL(vSpans.size(), (size_t)1); + VERIFY_ARE_EQUAL(vSpans[0].GetDuration(), (UINT32)10); + VERIFY_ARE_EQUAL(vSpans[0].GetWarmup(), (UINT32)5); + VERIFY_ARE_EQUAL(vSpans[0].GetCooldown(), (UINT32)0); + VERIFY_ARE_EQUAL(vSpans[0].GetRandSeed(), (UINT32)0); + VERIFY_ARE_EQUAL(vSpans[0].GetThreadCount(), (DWORD)23); + VERIFY_ARE_EQUAL(vSpans[0].GetRequestCount(), (DWORD)0); + VERIFY_IS_TRUE(vSpans[0].GetDisableAffinity() == false); + VERIFY_IS_TRUE(vSpans[0].GetCompletionRoutines() == false); + VERIFY_IS_TRUE(vSpans[0].GetMeasureLatency() == false); + VERIFY_IS_TRUE(vSpans[0].GetRandomWriteData() == false); + + const auto& vAffinity(vSpans[0].GetAffinityAssignments()); + VERIFY_ARE_EQUAL(vAffinity.size(), (size_t)0); + + vector vTargets(vSpans[0].GetTargets()); + VERIFY_ARE_EQUAL(vTargets.size(), (size_t)1); + Target t(vTargets[0]); + + VERIFY_IS_TRUE(t.GetPath().compare("testfile.dat") == 0); + VERIFY_ARE_EQUAL(t.GetBlockSizeInBytes(), (DWORD)(128 * 1024)); + VERIFY_ARE_EQUAL(t.GetRequestCount(), (DWORD)2); + VERIFY_IS_TRUE(t.GetRandomRatio() == 0); + VERIFY_IS_TRUE(t.GetUseInterlockedSequential() == false); + VERIFY_ARE_EQUAL(t.GetBlockAlignmentInBytes(), t.GetBlockSizeInBytes()); + VERIFY_ARE_EQUAL(t.GetBaseFileOffsetInBytes(), 0); + VERIFY_IS_TRUE(t.GetUseParallelAsyncIO() == false); + VERIFY_IS_TRUE(t.GetCacheMode() == TargetCacheMode::Cached); + VERIFY_IS_TRUE(t.GetWriteThroughMode() == WriteThroughMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoMode() == MemoryMappedIoMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoFlushMode() == MemoryMappedIoFlushMode::Undefined); + VERIFY_IS_TRUE(t.GetZeroWriteBuffers() == false); + VERIFY_ARE_EQUAL(t.GetThreadsPerFile(), (DWORD)1); + VERIFY_ARE_EQUAL(t.GetThreadStrideInBytes(), 0); + VERIFY_IS_TRUE(t.GetCreateFile() == false); + VERIFY_ARE_EQUAL(t.GetFileSize(), 0); + VERIFY_ARE_EQUAL(t.GetMaxFileSize(), 0); + VERIFY_ARE_EQUAL(t.GetWriteRatio(), (DWORD)84); + VERIFY_IS_TRUE(t.GetUseBurstSize() == false); + VERIFY_ARE_EQUAL(t.GetBurstSize(), (DWORD)0); + VERIFY_ARE_EQUAL(t.GetThinkTime(), (DWORD)0); + VERIFY_IS_TRUE(t.GetEnableThinkTime() == false); + VERIFY_IS_TRUE(t.GetSequentialScanHint() == false); + VERIFY_IS_TRUE(t.GetRandomAccessHint() == false); + VERIFY_IS_TRUE(t.GetTemporaryFileHint() == false); + VERIFY_IS_TRUE(t.GetUseLargePages() == false); + VERIFY_ARE_EQUAL(t.GetThroughputInBytesPerMillisecond(), (DWORD)567); + } + + void CmdLineParserUnitTests::TestParseCmdLineRandomIOAlignment() + { + CmdLineParser p; + Profile profile; + struct Synchronization s = {}; + const char *argv[] = { "foo", "-b128K", "-w84", "-r23M", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == true); + VERIFY_IS_TRUE(profile.GetVerbose() == false); + VERIFY_IS_TRUE(profile.GetProgress() == 0); + VERIFY_IS_TRUE(profile.GetCmdLine().compare("foo -b128K -w84 -r23M testfile.dat") == 0); + VERIFY_IS_TRUE(profile.GetEtwEnabled() == false); + VERIFY_IS_TRUE(profile.GetEtwProcess() == false); + VERIFY_IS_TRUE(profile.GetEtwThread() == false); + VERIFY_IS_TRUE(profile.GetEtwImageLoad() == false); + VERIFY_IS_TRUE(profile.GetEtwDiskIO() == false); + VERIFY_IS_TRUE(profile.GetEtwMemoryPageFaults() == false); + VERIFY_IS_TRUE(profile.GetEtwMemoryHardFaults() == false); + VERIFY_IS_TRUE(profile.GetEtwNetwork() == false); + VERIFY_IS_TRUE(profile.GetEtwRegistry() == false); + VERIFY_IS_TRUE(profile.GetEtwUsePagedMemory() == false); + VERIFY_IS_TRUE(profile.GetEtwUsePerfTimer() == false); + VERIFY_IS_TRUE(profile.GetEtwUseSystemTimer() == false); + VERIFY_IS_TRUE(profile.GetEtwUseCyclesCounter() == false); + + vector vSpans(profile.GetTimeSpans()); + VERIFY_ARE_EQUAL(vSpans.size(), (size_t)1); + VERIFY_ARE_EQUAL(vSpans[0].GetDuration(), (UINT32)10); + VERIFY_ARE_EQUAL(vSpans[0].GetWarmup(), (UINT32)5); + VERIFY_ARE_EQUAL(vSpans[0].GetCooldown(), (UINT32)0); + VERIFY_ARE_EQUAL(vSpans[0].GetRandSeed(), (UINT32)0); + VERIFY_ARE_EQUAL(vSpans[0].GetThreadCount(), (DWORD)0); + VERIFY_ARE_EQUAL(vSpans[0].GetRequestCount(), (DWORD)0); + VERIFY_IS_TRUE(vSpans[0].GetDisableAffinity() == false); + VERIFY_IS_TRUE(vSpans[0].GetCompletionRoutines() == false); + VERIFY_IS_TRUE(vSpans[0].GetMeasureLatency() == false); + VERIFY_IS_TRUE(vSpans[0].GetRandomWriteData() == false); + + const auto& vAffinity(vSpans[0].GetAffinityAssignments()); + VERIFY_ARE_EQUAL(vAffinity.size(), (size_t)0); + + vector vTargets(vSpans[0].GetTargets()); + VERIFY_ARE_EQUAL(vTargets.size(), (size_t)1); + Target t(vTargets[0]); + + VERIFY_IS_TRUE(t.GetPath().compare("testfile.dat") == 0); + VERIFY_ARE_EQUAL(t.GetBlockSizeInBytes(), (DWORD)(128 * 1024)); + VERIFY_ARE_EQUAL(t.GetRequestCount(), (DWORD)2); + VERIFY_IS_TRUE(t.GetRandomRatio() == 100); + VERIFY_IS_TRUE(t.GetUseInterlockedSequential() == false); + VERIFY_ARE_EQUAL(t.GetBlockAlignmentInBytes(), (23 * 1024 * 1024)); + VERIFY_ARE_EQUAL(t.GetBaseFileOffsetInBytes(), 0); + VERIFY_IS_TRUE(t.GetUseParallelAsyncIO() == false); + VERIFY_IS_TRUE(t.GetCacheMode() == TargetCacheMode::Cached); + VERIFY_IS_TRUE(t.GetWriteThroughMode() == WriteThroughMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoMode() == MemoryMappedIoMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoFlushMode() == MemoryMappedIoFlushMode::Undefined); + VERIFY_IS_TRUE(t.GetZeroWriteBuffers() == false); + VERIFY_ARE_EQUAL(t.GetThreadsPerFile(), (DWORD)1); + VERIFY_ARE_EQUAL(t.GetThreadStrideInBytes(), 0); + VERIFY_IS_TRUE(t.GetCreateFile() == false); + VERIFY_ARE_EQUAL(t.GetFileSize(), 0); + VERIFY_ARE_EQUAL(t.GetMaxFileSize(), 0); + VERIFY_ARE_EQUAL(t.GetWriteRatio(), (DWORD)84); + VERIFY_IS_TRUE(t.GetUseBurstSize() == false); + VERIFY_ARE_EQUAL(t.GetBurstSize(), (DWORD)0); + VERIFY_ARE_EQUAL(t.GetThinkTime(), (DWORD)0); + VERIFY_IS_TRUE(t.GetEnableThinkTime() == false); + VERIFY_IS_TRUE(t.GetSequentialScanHint() == false); + VERIFY_IS_TRUE(t.GetRandomAccessHint() == false); + VERIFY_IS_TRUE(t.GetTemporaryFileHint() == false); + VERIFY_IS_TRUE(t.GetUseLargePages() == false); + VERIFY_ARE_EQUAL(t.GetThroughputInBytesPerMillisecond(), (DWORD)0); + } + + void CmdLineParserUnitTests::TestParseCmdLineStrideSize() + { + CmdLineParser p; + Profile profile; + struct Synchronization s = {}; + const char *argv[] = { "foo", "-b128K", "-w84", "-s567K", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == true); + VERIFY_IS_TRUE(profile.GetVerbose() == false); + VERIFY_IS_TRUE(profile.GetProgress() == 0); + VERIFY_IS_TRUE(profile.GetCmdLine().compare("foo -b128K -w84 -s567K testfile.dat") == 0); + VERIFY_IS_TRUE(profile.GetEtwEnabled() == false); + VERIFY_IS_TRUE(profile.GetEtwProcess() == false); + VERIFY_IS_TRUE(profile.GetEtwThread() == false); + VERIFY_IS_TRUE(profile.GetEtwImageLoad() == false); + VERIFY_IS_TRUE(profile.GetEtwDiskIO() == false); + VERIFY_IS_TRUE(profile.GetEtwMemoryPageFaults() == false); + VERIFY_IS_TRUE(profile.GetEtwMemoryHardFaults() == false); + VERIFY_IS_TRUE(profile.GetEtwNetwork() == false); + VERIFY_IS_TRUE(profile.GetEtwRegistry() == false); + VERIFY_IS_TRUE(profile.GetEtwUsePagedMemory() == false); + VERIFY_IS_TRUE(profile.GetEtwUsePerfTimer() == false); + VERIFY_IS_TRUE(profile.GetEtwUseSystemTimer() == false); + VERIFY_IS_TRUE(profile.GetEtwUseCyclesCounter() == false); + + vector vSpans(profile.GetTimeSpans()); + VERIFY_ARE_EQUAL(vSpans.size(), (size_t)1); + VERIFY_ARE_EQUAL(vSpans[0].GetDuration(), (UINT32)10); + VERIFY_ARE_EQUAL(vSpans[0].GetWarmup(), (UINT32)5); + VERIFY_ARE_EQUAL(vSpans[0].GetCooldown(), (UINT32)0); + VERIFY_ARE_EQUAL(vSpans[0].GetRandSeed(), (UINT32)0); + VERIFY_ARE_EQUAL(vSpans[0].GetThreadCount(), (DWORD)0); + VERIFY_ARE_EQUAL(vSpans[0].GetRequestCount(), (DWORD)0); + VERIFY_IS_TRUE(vSpans[0].GetDisableAffinity() == false); + VERIFY_IS_TRUE(vSpans[0].GetCompletionRoutines() == false); + VERIFY_IS_TRUE(vSpans[0].GetMeasureLatency() == false); + VERIFY_IS_TRUE(vSpans[0].GetRandomWriteData() == false); + + const auto& vAffinity(vSpans[0].GetAffinityAssignments()); + VERIFY_ARE_EQUAL(vAffinity.size(), (size_t)0); + + vector vTargets(vSpans[0].GetTargets()); + VERIFY_ARE_EQUAL(vTargets.size(), (size_t)1); + Target t(vTargets[0]); + + VERIFY_IS_TRUE(t.GetPath().compare("testfile.dat") == 0); + VERIFY_ARE_EQUAL(t.GetBlockSizeInBytes(), (DWORD)(128 * 1024)); + VERIFY_ARE_EQUAL(t.GetRequestCount(), (DWORD)2); + VERIFY_IS_TRUE(t.GetRandomRatio() == 0); + VERIFY_IS_TRUE(t.GetUseInterlockedSequential() == false); + VERIFY_ARE_EQUAL(t.GetBlockAlignmentInBytes(), (567 * 1024)); + VERIFY_ARE_EQUAL(t.GetBaseFileOffsetInBytes(), 0); + VERIFY_IS_TRUE(t.GetUseParallelAsyncIO() == false); + VERIFY_IS_TRUE(t.GetCacheMode() == TargetCacheMode::Cached); + VERIFY_IS_TRUE(t.GetWriteThroughMode() == WriteThroughMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoMode() == MemoryMappedIoMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoFlushMode() == MemoryMappedIoFlushMode::Undefined); + VERIFY_IS_TRUE(t.GetZeroWriteBuffers() == false); + VERIFY_ARE_EQUAL(t.GetThreadsPerFile(), (DWORD)1); + VERIFY_ARE_EQUAL(t.GetThreadStrideInBytes(), 0); + VERIFY_IS_TRUE(t.GetCreateFile() == false); + VERIFY_ARE_EQUAL(t.GetFileSize(), 0); + VERIFY_ARE_EQUAL(t.GetMaxFileSize(), 0); + VERIFY_ARE_EQUAL(t.GetWriteRatio(), (DWORD)84); + VERIFY_IS_TRUE(t.GetUseBurstSize() == false); + VERIFY_ARE_EQUAL(t.GetBurstSize(), (DWORD)0); + VERIFY_ARE_EQUAL(t.GetThinkTime(), (DWORD)0); + VERIFY_IS_TRUE(t.GetEnableThinkTime() == false); + VERIFY_IS_TRUE(t.GetSequentialScanHint() == false); + VERIFY_IS_TRUE(t.GetRandomAccessHint() == false); + VERIFY_IS_TRUE(t.GetTemporaryFileHint() == false); + VERIFY_IS_TRUE(t.GetUseLargePages() == false); + VERIFY_ARE_EQUAL(t.GetThroughputInBytesPerMillisecond(), (DWORD)0); + } + + void CmdLineParserUnitTests::TestParseCmdLineThreadsPerFileAndThreadStride() + { + CmdLineParser p; + Profile profile; + struct Synchronization s = {}; + const char *argv[] = { "foo", "-b128K", "-w84", "-t23", "-T512K", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == true); + VERIFY_IS_TRUE(profile.GetVerbose() == false); + VERIFY_IS_TRUE(profile.GetProgress() == 0); + VERIFY_IS_TRUE(profile.GetCmdLine().compare("foo -b128K -w84 -t23 -T512K testfile.dat") == 0); + VERIFY_IS_TRUE(profile.GetEtwEnabled() == false); + VERIFY_IS_TRUE(profile.GetEtwProcess() == false); + VERIFY_IS_TRUE(profile.GetEtwThread() == false); + VERIFY_IS_TRUE(profile.GetEtwImageLoad() == false); + VERIFY_IS_TRUE(profile.GetEtwDiskIO() == false); + VERIFY_IS_TRUE(profile.GetEtwMemoryPageFaults() == false); + VERIFY_IS_TRUE(profile.GetEtwMemoryHardFaults() == false); + VERIFY_IS_TRUE(profile.GetEtwNetwork() == false); + VERIFY_IS_TRUE(profile.GetEtwRegistry() == false); + VERIFY_IS_TRUE(profile.GetEtwUsePagedMemory() == false); + VERIFY_IS_TRUE(profile.GetEtwUsePerfTimer() == false); + VERIFY_IS_TRUE(profile.GetEtwUseSystemTimer() == false); + VERIFY_IS_TRUE(profile.GetEtwUseCyclesCounter() == false); + + vector vSpans(profile.GetTimeSpans()); + VERIFY_ARE_EQUAL(vSpans.size(), (size_t)1); + VERIFY_ARE_EQUAL(vSpans[0].GetDuration(), (UINT32)10); + VERIFY_ARE_EQUAL(vSpans[0].GetWarmup(), (UINT32)5); + VERIFY_ARE_EQUAL(vSpans[0].GetCooldown(), (UINT32)0); + VERIFY_ARE_EQUAL(vSpans[0].GetRandSeed(), (UINT32)0); + VERIFY_ARE_EQUAL(vSpans[0].GetThreadCount(), (DWORD)0); + VERIFY_ARE_EQUAL(vSpans[0].GetRequestCount(), (DWORD)0); + VERIFY_IS_TRUE(vSpans[0].GetDisableAffinity() == false); + VERIFY_IS_TRUE(vSpans[0].GetCompletionRoutines() == false); + VERIFY_IS_TRUE(vSpans[0].GetMeasureLatency() == false); + VERIFY_IS_TRUE(vSpans[0].GetRandomWriteData() == false); + + const auto& vAffinity(vSpans[0].GetAffinityAssignments()); + VERIFY_ARE_EQUAL(vAffinity.size(), (size_t)0); + + vector vTargets(vSpans[0].GetTargets()); + VERIFY_ARE_EQUAL(vTargets.size(), (size_t)1); + Target t(vTargets[0]); + + VERIFY_IS_TRUE(t.GetPath().compare("testfile.dat") == 0); + VERIFY_ARE_EQUAL(t.GetBlockSizeInBytes(), (DWORD)(128 * 1024)); + VERIFY_ARE_EQUAL(t.GetRequestCount(), (DWORD)2); + VERIFY_IS_TRUE(t.GetRandomRatio() == 0); + VERIFY_IS_TRUE(t.GetUseInterlockedSequential() == false); + VERIFY_ARE_EQUAL(t.GetBlockAlignmentInBytes(), t.GetBlockSizeInBytes()); + VERIFY_ARE_EQUAL(t.GetBaseFileOffsetInBytes(), 0); + VERIFY_IS_TRUE(t.GetUseParallelAsyncIO() == false); + VERIFY_IS_TRUE(t.GetCacheMode() == TargetCacheMode::Cached); + VERIFY_IS_TRUE(t.GetWriteThroughMode() == WriteThroughMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoMode() == MemoryMappedIoMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoFlushMode() == MemoryMappedIoFlushMode::Undefined); + VERIFY_IS_TRUE(t.GetZeroWriteBuffers() == false); + VERIFY_ARE_EQUAL(t.GetThreadsPerFile(), (DWORD)23); + VERIFY_ARE_EQUAL(t.GetThreadStrideInBytes(), (512 * 1024)); + VERIFY_IS_TRUE(t.GetCreateFile() == false); + VERIFY_ARE_EQUAL(t.GetFileSize(), 0); + VERIFY_ARE_EQUAL(t.GetMaxFileSize(), 0); + VERIFY_ARE_EQUAL(t.GetWriteRatio(), (DWORD)84); + VERIFY_IS_TRUE(t.GetUseBurstSize() == false); + VERIFY_ARE_EQUAL(t.GetBurstSize(), (DWORD)0); + VERIFY_ARE_EQUAL(t.GetThinkTime(), (DWORD)0); + VERIFY_IS_TRUE(t.GetEnableThinkTime() == false); + VERIFY_IS_TRUE(t.GetSequentialScanHint() == false); + VERIFY_IS_TRUE(t.GetRandomAccessHint() == false); + VERIFY_IS_TRUE(t.GetTemporaryFileHint() == false); + VERIFY_IS_TRUE(t.GetUseLargePages() == false); + VERIFY_ARE_EQUAL(t.GetThroughputInBytesPerMillisecond(), (DWORD)0); + } + + void CmdLineParserUnitTests::TestParseCmdLineEtwUsePagedMemory() + { + CmdLineParser p; + Profile profile; + struct Synchronization s = {}; + const char *argv[] = { "foo", "-b128K", "-w84", "-ep", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == true); + VERIFY_IS_TRUE(profile.GetVerbose() == false); + VERIFY_IS_TRUE(profile.GetProgress() == 0); + VERIFY_IS_TRUE(profile.GetCmdLine().compare("foo -b128K -w84 -ep testfile.dat") == 0); + VERIFY_IS_TRUE(profile.GetEtwEnabled() == true); + VERIFY_IS_TRUE(profile.GetEtwProcess() == false); + VERIFY_IS_TRUE(profile.GetEtwThread() == false); + VERIFY_IS_TRUE(profile.GetEtwImageLoad() == false); + VERIFY_IS_TRUE(profile.GetEtwDiskIO() == false); + VERIFY_IS_TRUE(profile.GetEtwMemoryPageFaults() == false); + VERIFY_IS_TRUE(profile.GetEtwMemoryHardFaults() == false); + VERIFY_IS_TRUE(profile.GetEtwNetwork() == false); + VERIFY_IS_TRUE(profile.GetEtwRegistry() == false); + VERIFY_IS_TRUE(profile.GetEtwUsePagedMemory() == true); + VERIFY_IS_TRUE(profile.GetEtwUsePerfTimer() == false); + VERIFY_IS_TRUE(profile.GetEtwUseSystemTimer() == false); + VERIFY_IS_TRUE(profile.GetEtwUseCyclesCounter() == false); + + vector vSpans(profile.GetTimeSpans()); + VERIFY_ARE_EQUAL(vSpans.size(), (size_t)1); + VERIFY_ARE_EQUAL(vSpans[0].GetDuration(), (UINT32)10); + VERIFY_ARE_EQUAL(vSpans[0].GetWarmup(), (UINT32)5); + VERIFY_ARE_EQUAL(vSpans[0].GetCooldown(), (UINT32)0); + VERIFY_ARE_EQUAL(vSpans[0].GetRandSeed(), (UINT32)0); + VERIFY_ARE_EQUAL(vSpans[0].GetThreadCount(), (DWORD)0); + VERIFY_ARE_EQUAL(vSpans[0].GetRequestCount(), (DWORD)0); + VERIFY_IS_TRUE(vSpans[0].GetDisableAffinity() == false); + VERIFY_IS_TRUE(vSpans[0].GetCompletionRoutines() == false); + VERIFY_IS_TRUE(vSpans[0].GetMeasureLatency() == false); + VERIFY_IS_TRUE(vSpans[0].GetRandomWriteData() == false); + + const auto& vAffinity(vSpans[0].GetAffinityAssignments()); + VERIFY_ARE_EQUAL(vAffinity.size(), (size_t)0); + + vector vTargets(vSpans[0].GetTargets()); + VERIFY_ARE_EQUAL(vTargets.size(), (size_t)1); + Target t(vTargets[0]); + + VERIFY_IS_TRUE(t.GetPath().compare("testfile.dat") == 0); + VERIFY_ARE_EQUAL(t.GetBlockSizeInBytes(), (DWORD)(128 * 1024)); + VERIFY_ARE_EQUAL(t.GetRequestCount(), (DWORD)2); + VERIFY_IS_TRUE(t.GetRandomRatio() == 0); + VERIFY_IS_TRUE(t.GetUseInterlockedSequential() == false); + VERIFY_ARE_EQUAL(t.GetBlockAlignmentInBytes(), t.GetBlockSizeInBytes()); + VERIFY_ARE_EQUAL(t.GetBaseFileOffsetInBytes(), 0); + VERIFY_IS_TRUE(t.GetUseParallelAsyncIO() == false); + VERIFY_IS_TRUE(t.GetCacheMode() == TargetCacheMode::Cached); + VERIFY_IS_TRUE(t.GetWriteThroughMode() == WriteThroughMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoMode() == MemoryMappedIoMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoFlushMode() == MemoryMappedIoFlushMode::Undefined); + VERIFY_IS_TRUE(t.GetZeroWriteBuffers() == false); + VERIFY_ARE_EQUAL(t.GetThreadsPerFile(), (DWORD)1); + VERIFY_ARE_EQUAL(t.GetThreadStrideInBytes(), 0); + VERIFY_IS_TRUE(t.GetCreateFile() == false); + VERIFY_ARE_EQUAL(t.GetFileSize(), 0); + VERIFY_ARE_EQUAL(t.GetMaxFileSize(), 0); + VERIFY_ARE_EQUAL(t.GetWriteRatio(), (DWORD)84); + VERIFY_IS_TRUE(t.GetUseBurstSize() == false); + VERIFY_ARE_EQUAL(t.GetBurstSize(), (DWORD)0); + VERIFY_ARE_EQUAL(t.GetThinkTime(), (DWORD)0); + VERIFY_IS_TRUE(t.GetEnableThinkTime() == false); + VERIFY_IS_TRUE(t.GetSequentialScanHint() == false); + VERIFY_IS_TRUE(t.GetRandomAccessHint() == false); + VERIFY_IS_TRUE(t.GetTemporaryFileHint() == false); + VERIFY_IS_TRUE(t.GetUseLargePages() == false); + VERIFY_ARE_EQUAL(t.GetThroughputInBytesPerMillisecond(), (DWORD)0); + } + + void CmdLineParserUnitTests::TestParseCmdLineEtwPROCESS() + { + CmdLineParser p; + Profile profile; + struct Synchronization s = {}; + const char *argv[] = { "foo", "-b128K", "-w84", "-ePROCESS", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == true); + VERIFY_IS_TRUE(profile.GetVerbose() == false); + VERIFY_IS_TRUE(profile.GetProgress() == 0); + VERIFY_IS_TRUE(profile.GetCmdLine().compare("foo -b128K -w84 -ePROCESS testfile.dat") == 0); + VERIFY_IS_TRUE(profile.GetEtwEnabled() == true); + VERIFY_IS_TRUE(profile.GetEtwProcess() == true); + VERIFY_IS_TRUE(profile.GetEtwThread() == false); + VERIFY_IS_TRUE(profile.GetEtwImageLoad() == false); + VERIFY_IS_TRUE(profile.GetEtwDiskIO() == false); + VERIFY_IS_TRUE(profile.GetEtwMemoryPageFaults() == false); + VERIFY_IS_TRUE(profile.GetEtwMemoryHardFaults() == false); + VERIFY_IS_TRUE(profile.GetEtwNetwork() == false); + VERIFY_IS_TRUE(profile.GetEtwRegistry() == false); + VERIFY_IS_TRUE(profile.GetEtwUsePagedMemory() == false); + VERIFY_IS_TRUE(profile.GetEtwUsePerfTimer() == false); + VERIFY_IS_TRUE(profile.GetEtwUseSystemTimer() == false); + VERIFY_IS_TRUE(profile.GetEtwUseCyclesCounter() == false); + + vector vSpans(profile.GetTimeSpans()); + VERIFY_ARE_EQUAL(vSpans.size(), (size_t)1); + VERIFY_ARE_EQUAL(vSpans[0].GetDuration(), (UINT32)10); + VERIFY_ARE_EQUAL(vSpans[0].GetWarmup(), (UINT32)5); + VERIFY_ARE_EQUAL(vSpans[0].GetCooldown(), (UINT32)0); + VERIFY_ARE_EQUAL(vSpans[0].GetRandSeed(), (UINT32)0); + VERIFY_ARE_EQUAL(vSpans[0].GetThreadCount(), (DWORD)0); + VERIFY_ARE_EQUAL(vSpans[0].GetRequestCount(), (DWORD)0); + VERIFY_IS_TRUE(vSpans[0].GetDisableAffinity() == false); + VERIFY_IS_TRUE(vSpans[0].GetCompletionRoutines() == false); + VERIFY_IS_TRUE(vSpans[0].GetMeasureLatency() == false); + VERIFY_IS_TRUE(vSpans[0].GetRandomWriteData() == false); + + const auto& vAffinity(vSpans[0].GetAffinityAssignments()); + VERIFY_ARE_EQUAL(vAffinity.size(), (size_t)0); + + vector vTargets(vSpans[0].GetTargets()); + VERIFY_ARE_EQUAL(vTargets.size(), (size_t)1); + Target t(vTargets[0]); + + VERIFY_IS_TRUE(t.GetPath().compare("testfile.dat") == 0); + VERIFY_ARE_EQUAL(t.GetBlockSizeInBytes(), (DWORD)(128 * 1024)); + VERIFY_ARE_EQUAL(t.GetRequestCount(), (DWORD)2); + VERIFY_IS_TRUE(t.GetRandomRatio() == 0); + VERIFY_IS_TRUE(t.GetUseInterlockedSequential() == false); + VERIFY_ARE_EQUAL(t.GetBlockAlignmentInBytes(), t.GetBlockSizeInBytes()); + VERIFY_ARE_EQUAL(t.GetBaseFileOffsetInBytes(), 0); + VERIFY_IS_TRUE(t.GetUseParallelAsyncIO() == false); + VERIFY_IS_TRUE(t.GetCacheMode() == TargetCacheMode::Cached); + VERIFY_IS_TRUE(t.GetWriteThroughMode() == WriteThroughMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoMode() == MemoryMappedIoMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoFlushMode() == MemoryMappedIoFlushMode::Undefined); + VERIFY_IS_TRUE(t.GetZeroWriteBuffers() == false); + VERIFY_ARE_EQUAL(t.GetThreadsPerFile(), (DWORD)1); + VERIFY_ARE_EQUAL(t.GetThreadStrideInBytes(), 0); + VERIFY_IS_TRUE(t.GetCreateFile() == false); + VERIFY_ARE_EQUAL(t.GetFileSize(), 0); + VERIFY_ARE_EQUAL(t.GetMaxFileSize(), 0); + VERIFY_ARE_EQUAL(t.GetWriteRatio(), (DWORD)84); + VERIFY_IS_TRUE(t.GetUseBurstSize() == false); + VERIFY_ARE_EQUAL(t.GetBurstSize(), (DWORD)0); + VERIFY_ARE_EQUAL(t.GetThinkTime(), (DWORD)0); + VERIFY_IS_TRUE(t.GetEnableThinkTime() == false); + VERIFY_IS_TRUE(t.GetSequentialScanHint() == false); + VERIFY_IS_TRUE(t.GetRandomAccessHint() == false); + VERIFY_IS_TRUE(t.GetTemporaryFileHint() == false); + VERIFY_IS_TRUE(t.GetUseLargePages() == false); + VERIFY_ARE_EQUAL(t.GetThroughputInBytesPerMillisecond(), (DWORD)0); + } + + void CmdLineParserUnitTests::TestParseCmdLineEtwTHREAD() + { + CmdLineParser p; + Profile profile; + struct Synchronization s = {}; + const char *argv[] = { "foo", "-b128K", "-w84", "-eTHREAD", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == true); + VERIFY_IS_TRUE(profile.GetVerbose() == false); + VERIFY_IS_TRUE(profile.GetProgress() == 0); + VERIFY_IS_TRUE(profile.GetCmdLine().compare("foo -b128K -w84 -eTHREAD testfile.dat") == 0); + VERIFY_IS_TRUE(profile.GetEtwEnabled() == true); + VERIFY_IS_TRUE(profile.GetEtwProcess() == false); + VERIFY_IS_TRUE(profile.GetEtwThread() == true); + VERIFY_IS_TRUE(profile.GetEtwImageLoad() == false); + VERIFY_IS_TRUE(profile.GetEtwDiskIO() == false); + VERIFY_IS_TRUE(profile.GetEtwMemoryPageFaults() == false); + VERIFY_IS_TRUE(profile.GetEtwMemoryHardFaults() == false); + VERIFY_IS_TRUE(profile.GetEtwNetwork() == false); + VERIFY_IS_TRUE(profile.GetEtwRegistry() == false); + VERIFY_IS_TRUE(profile.GetEtwUsePagedMemory() == false); + VERIFY_IS_TRUE(profile.GetEtwUsePerfTimer() == false); + VERIFY_IS_TRUE(profile.GetEtwUseSystemTimer() == false); + VERIFY_IS_TRUE(profile.GetEtwUseCyclesCounter() == false); + + vector vSpans(profile.GetTimeSpans()); + VERIFY_ARE_EQUAL(vSpans.size(), (size_t)1); + VERIFY_ARE_EQUAL(vSpans[0].GetDuration(), (UINT32)10); + VERIFY_ARE_EQUAL(vSpans[0].GetWarmup(), (UINT32)5); + VERIFY_ARE_EQUAL(vSpans[0].GetCooldown(), (UINT32)0); + VERIFY_ARE_EQUAL(vSpans[0].GetRandSeed(), (UINT32)0); + VERIFY_ARE_EQUAL(vSpans[0].GetThreadCount(), (DWORD)0); + VERIFY_ARE_EQUAL(vSpans[0].GetRequestCount(), (DWORD)0); + VERIFY_IS_TRUE(vSpans[0].GetDisableAffinity() == false); + VERIFY_IS_TRUE(vSpans[0].GetCompletionRoutines() == false); + VERIFY_IS_TRUE(vSpans[0].GetMeasureLatency() == false); + VERIFY_IS_TRUE(vSpans[0].GetRandomWriteData() == false); + + const auto& vAffinity(vSpans[0].GetAffinityAssignments()); + VERIFY_ARE_EQUAL(vAffinity.size(), (size_t)0); + + vector vTargets(vSpans[0].GetTargets()); + VERIFY_ARE_EQUAL(vTargets.size(), (size_t)1); + Target t(vTargets[0]); + + VERIFY_IS_TRUE(t.GetPath().compare("testfile.dat") == 0); + VERIFY_ARE_EQUAL(t.GetBlockSizeInBytes(), (DWORD)(128 * 1024)); + VERIFY_ARE_EQUAL(t.GetRequestCount(), (DWORD)2); + VERIFY_IS_TRUE(t.GetRandomRatio() == 0); + VERIFY_IS_TRUE(t.GetUseInterlockedSequential() == false); + VERIFY_ARE_EQUAL(t.GetBlockAlignmentInBytes(), t.GetBlockSizeInBytes()); + VERIFY_ARE_EQUAL(t.GetBaseFileOffsetInBytes(), 0); + VERIFY_IS_TRUE(t.GetUseParallelAsyncIO() == false); + VERIFY_IS_TRUE(t.GetCacheMode() == TargetCacheMode::Cached); + VERIFY_IS_TRUE(t.GetWriteThroughMode() == WriteThroughMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoMode() == MemoryMappedIoMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoFlushMode() == MemoryMappedIoFlushMode::Undefined); + VERIFY_IS_TRUE(t.GetZeroWriteBuffers() == false); + VERIFY_ARE_EQUAL(t.GetThreadsPerFile(), (DWORD)1); + VERIFY_ARE_EQUAL(t.GetThreadStrideInBytes(), 0); + VERIFY_IS_TRUE(t.GetCreateFile() == false); + VERIFY_ARE_EQUAL(t.GetFileSize(), 0); + VERIFY_ARE_EQUAL(t.GetMaxFileSize(), 0); + VERIFY_ARE_EQUAL(t.GetWriteRatio(), (DWORD)84); + VERIFY_IS_TRUE(t.GetUseBurstSize() == false); + VERIFY_ARE_EQUAL(t.GetBurstSize(), (DWORD)0); + VERIFY_ARE_EQUAL(t.GetThinkTime(), (DWORD)0); + VERIFY_IS_TRUE(t.GetEnableThinkTime() == false); + VERIFY_IS_TRUE(t.GetSequentialScanHint() == false); + VERIFY_IS_TRUE(t.GetRandomAccessHint() == false); + VERIFY_IS_TRUE(t.GetTemporaryFileHint() == false); + VERIFY_IS_TRUE(t.GetUseLargePages() == false); + VERIFY_ARE_EQUAL(t.GetThroughputInBytesPerMillisecond(), (DWORD)0); + } + + void CmdLineParserUnitTests::TestParseCmdLineEtwIMAGE_LOAD() + { + CmdLineParser p; + Profile profile; + struct Synchronization s = {}; + const char *argv[] = { "foo", "-b128K", "-w84", "-eIMAGE_LOAD", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == true); + VERIFY_IS_TRUE(profile.GetVerbose() == false); + VERIFY_IS_TRUE(profile.GetProgress() == 0); + VERIFY_IS_TRUE(profile.GetCmdLine().compare("foo -b128K -w84 -eIMAGE_LOAD testfile.dat") == 0); + VERIFY_IS_TRUE(profile.GetEtwEnabled() == true); + VERIFY_IS_TRUE(profile.GetEtwProcess() == false); + VERIFY_IS_TRUE(profile.GetEtwThread() == false); + VERIFY_IS_TRUE(profile.GetEtwImageLoad() == true); + VERIFY_IS_TRUE(profile.GetEtwDiskIO() == false); + VERIFY_IS_TRUE(profile.GetEtwMemoryPageFaults() == false); + VERIFY_IS_TRUE(profile.GetEtwMemoryHardFaults() == false); + VERIFY_IS_TRUE(profile.GetEtwNetwork() == false); + VERIFY_IS_TRUE(profile.GetEtwRegistry() == false); + VERIFY_IS_TRUE(profile.GetEtwUsePagedMemory() == false); + VERIFY_IS_TRUE(profile.GetEtwUsePerfTimer() == false); + VERIFY_IS_TRUE(profile.GetEtwUseSystemTimer() == false); + VERIFY_IS_TRUE(profile.GetEtwUseCyclesCounter() == false); + + vector vSpans(profile.GetTimeSpans()); + VERIFY_ARE_EQUAL(vSpans.size(), (size_t)1); + VERIFY_ARE_EQUAL(vSpans[0].GetDuration(), (UINT32)10); + VERIFY_ARE_EQUAL(vSpans[0].GetWarmup(), (UINT32)5); + VERIFY_ARE_EQUAL(vSpans[0].GetCooldown(), (UINT32)0); + VERIFY_ARE_EQUAL(vSpans[0].GetRandSeed(), (UINT32)0); + VERIFY_ARE_EQUAL(vSpans[0].GetThreadCount(), (DWORD)0); + VERIFY_ARE_EQUAL(vSpans[0].GetRequestCount(), (DWORD)0); + VERIFY_IS_TRUE(vSpans[0].GetDisableAffinity() == false); + VERIFY_IS_TRUE(vSpans[0].GetCompletionRoutines() == false); + VERIFY_IS_TRUE(vSpans[0].GetMeasureLatency() == false); + VERIFY_IS_TRUE(vSpans[0].GetRandomWriteData() == false); + + const auto& vAffinity(vSpans[0].GetAffinityAssignments()); + VERIFY_ARE_EQUAL(vAffinity.size(), (size_t)0); + + vector vTargets(vSpans[0].GetTargets()); + VERIFY_ARE_EQUAL(vTargets.size(), (size_t)1); + Target t(vTargets[0]); + + VERIFY_IS_TRUE(t.GetPath().compare("testfile.dat") == 0); + VERIFY_ARE_EQUAL(t.GetBlockSizeInBytes(), (DWORD)(128 * 1024)); + VERIFY_ARE_EQUAL(t.GetRequestCount(), (DWORD)2); + VERIFY_IS_TRUE(t.GetRandomRatio() == 0); + VERIFY_IS_TRUE(t.GetUseInterlockedSequential() == false); + VERIFY_ARE_EQUAL(t.GetBlockAlignmentInBytes(), t.GetBlockSizeInBytes()); + VERIFY_ARE_EQUAL(t.GetBaseFileOffsetInBytes(), 0); + VERIFY_IS_TRUE(t.GetUseParallelAsyncIO() == false); + VERIFY_IS_TRUE(t.GetCacheMode() == TargetCacheMode::Cached); + VERIFY_IS_TRUE(t.GetWriteThroughMode() == WriteThroughMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoMode() == MemoryMappedIoMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoFlushMode() == MemoryMappedIoFlushMode::Undefined); + VERIFY_IS_TRUE(t.GetZeroWriteBuffers() == false); + VERIFY_ARE_EQUAL(t.GetThreadsPerFile(), (DWORD)1); + VERIFY_ARE_EQUAL(t.GetThreadStrideInBytes(), 0); + VERIFY_IS_TRUE(t.GetCreateFile() == false); + VERIFY_ARE_EQUAL(t.GetFileSize(), 0); + VERIFY_ARE_EQUAL(t.GetMaxFileSize(), 0); + VERIFY_ARE_EQUAL(t.GetWriteRatio(), (DWORD)84); + VERIFY_IS_TRUE(t.GetUseBurstSize() == false); + VERIFY_ARE_EQUAL(t.GetBurstSize(), (DWORD)0); + VERIFY_ARE_EQUAL(t.GetThinkTime(), (DWORD)0); + VERIFY_IS_TRUE(t.GetEnableThinkTime() == false); + VERIFY_IS_TRUE(t.GetSequentialScanHint() == false); + VERIFY_IS_TRUE(t.GetRandomAccessHint() == false); + VERIFY_IS_TRUE(t.GetTemporaryFileHint() == false); + VERIFY_IS_TRUE(t.GetUseLargePages() == false); + VERIFY_ARE_EQUAL(t.GetThroughputInBytesPerMillisecond(), (DWORD)0); + } + + void CmdLineParserUnitTests::TestParseCmdLineEtwDISK_IO() + { + CmdLineParser p; + Profile profile; + struct Synchronization s = {}; + const char *argv[] = { "foo", "-b128K", "-w84", "-eDISK_IO", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == true); + VERIFY_IS_TRUE(profile.GetVerbose() == false); + VERIFY_IS_TRUE(profile.GetProgress() == 0); + VERIFY_IS_TRUE(profile.GetCmdLine().compare("foo -b128K -w84 -eDISK_IO testfile.dat") == 0); + VERIFY_IS_TRUE(profile.GetEtwEnabled() == true); + VERIFY_IS_TRUE(profile.GetEtwProcess() == false); + VERIFY_IS_TRUE(profile.GetEtwThread() == false); + VERIFY_IS_TRUE(profile.GetEtwImageLoad() == false); + VERIFY_IS_TRUE(profile.GetEtwDiskIO() == true); + VERIFY_IS_TRUE(profile.GetEtwMemoryPageFaults() == false); + VERIFY_IS_TRUE(profile.GetEtwMemoryHardFaults() == false); + VERIFY_IS_TRUE(profile.GetEtwNetwork() == false); + VERIFY_IS_TRUE(profile.GetEtwRegistry() == false); + VERIFY_IS_TRUE(profile.GetEtwUsePagedMemory() == false); + VERIFY_IS_TRUE(profile.GetEtwUsePerfTimer() == false); + VERIFY_IS_TRUE(profile.GetEtwUseSystemTimer() == false); + VERIFY_IS_TRUE(profile.GetEtwUseCyclesCounter() == false); + + vector vSpans(profile.GetTimeSpans()); + VERIFY_ARE_EQUAL(vSpans.size(), (size_t)1); + VERIFY_ARE_EQUAL(vSpans[0].GetDuration(), (UINT32)10); + VERIFY_ARE_EQUAL(vSpans[0].GetWarmup(), (UINT32)5); + VERIFY_ARE_EQUAL(vSpans[0].GetCooldown(), (UINT32)0); + VERIFY_ARE_EQUAL(vSpans[0].GetRandSeed(), (UINT32)0); + VERIFY_ARE_EQUAL(vSpans[0].GetThreadCount(), (DWORD)0); + VERIFY_ARE_EQUAL(vSpans[0].GetRequestCount(), (DWORD)0); + VERIFY_IS_TRUE(vSpans[0].GetDisableAffinity() == false); + VERIFY_IS_TRUE(vSpans[0].GetCompletionRoutines() == false); + VERIFY_IS_TRUE(vSpans[0].GetMeasureLatency() == false); + VERIFY_IS_TRUE(vSpans[0].GetRandomWriteData() == false); + + const auto& vAffinity(vSpans[0].GetAffinityAssignments()); + VERIFY_ARE_EQUAL(vAffinity.size(), (size_t)0); + + vector vTargets(vSpans[0].GetTargets()); + VERIFY_ARE_EQUAL(vTargets.size(), (size_t)1); + Target t(vTargets[0]); + + VERIFY_IS_TRUE(t.GetPath().compare("testfile.dat") == 0); + VERIFY_ARE_EQUAL(t.GetBlockSizeInBytes(), (DWORD)(128 * 1024)); + VERIFY_ARE_EQUAL(t.GetRequestCount(), (DWORD)2); + VERIFY_IS_TRUE(t.GetRandomRatio() == 0); + VERIFY_IS_TRUE(t.GetUseInterlockedSequential() == false); + VERIFY_ARE_EQUAL(t.GetBlockAlignmentInBytes(), t.GetBlockSizeInBytes()); + VERIFY_ARE_EQUAL(t.GetBaseFileOffsetInBytes(), 0); + VERIFY_IS_TRUE(t.GetUseParallelAsyncIO() == false); + VERIFY_IS_TRUE(t.GetCacheMode() == TargetCacheMode::Cached); + VERIFY_IS_TRUE(t.GetWriteThroughMode() == WriteThroughMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoMode() == MemoryMappedIoMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoFlushMode() == MemoryMappedIoFlushMode::Undefined); + VERIFY_IS_TRUE(t.GetZeroWriteBuffers() == false); + VERIFY_ARE_EQUAL(t.GetThreadsPerFile(), (DWORD)1); + VERIFY_ARE_EQUAL(t.GetThreadStrideInBytes(), 0); + VERIFY_IS_TRUE(t.GetCreateFile() == false); + VERIFY_ARE_EQUAL(t.GetFileSize(), 0); + VERIFY_ARE_EQUAL(t.GetMaxFileSize(), 0); + VERIFY_ARE_EQUAL(t.GetWriteRatio(), (DWORD)84); + VERIFY_IS_TRUE(t.GetUseBurstSize() == false); + VERIFY_ARE_EQUAL(t.GetBurstSize(), (DWORD)0); + VERIFY_ARE_EQUAL(t.GetThinkTime(), (DWORD)0); + VERIFY_IS_TRUE(t.GetEnableThinkTime() == false); + VERIFY_IS_TRUE(t.GetSequentialScanHint() == false); + VERIFY_IS_TRUE(t.GetRandomAccessHint() == false); + VERIFY_IS_TRUE(t.GetTemporaryFileHint() == false); + VERIFY_IS_TRUE(t.GetUseLargePages() == false); + VERIFY_ARE_EQUAL(t.GetThroughputInBytesPerMillisecond(), (DWORD)0); + } + + void CmdLineParserUnitTests::TestParseCmdLineEtwNETWORK() + { + CmdLineParser p; + Profile profile; + struct Synchronization s = {}; + const char *argv[] = { "foo", "-b128K", "-w84", "-eNETWORK", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == true); + VERIFY_IS_TRUE(profile.GetVerbose() == false); + VERIFY_IS_TRUE(profile.GetProgress() == 0); + VERIFY_IS_TRUE(profile.GetCmdLine().compare("foo -b128K -w84 -eNETWORK testfile.dat") == 0); + VERIFY_IS_TRUE(profile.GetEtwEnabled() == true); + VERIFY_IS_TRUE(profile.GetEtwProcess() == false); + VERIFY_IS_TRUE(profile.GetEtwThread() == false); + VERIFY_IS_TRUE(profile.GetEtwImageLoad() == false); + VERIFY_IS_TRUE(profile.GetEtwDiskIO() == false); + VERIFY_IS_TRUE(profile.GetEtwMemoryPageFaults() == false); + VERIFY_IS_TRUE(profile.GetEtwMemoryHardFaults() == false); + VERIFY_IS_TRUE(profile.GetEtwNetwork() == true); + VERIFY_IS_TRUE(profile.GetEtwRegistry() == false); + VERIFY_IS_TRUE(profile.GetEtwUsePagedMemory() == false); + VERIFY_IS_TRUE(profile.GetEtwUsePerfTimer() == false); + VERIFY_IS_TRUE(profile.GetEtwUseSystemTimer() == false); + VERIFY_IS_TRUE(profile.GetEtwUseCyclesCounter() == false); + + vector vSpans(profile.GetTimeSpans()); + VERIFY_ARE_EQUAL(vSpans.size(), (size_t)1); + VERIFY_ARE_EQUAL(vSpans[0].GetDuration(), (UINT32)10); + VERIFY_ARE_EQUAL(vSpans[0].GetWarmup(), (UINT32)5); + VERIFY_ARE_EQUAL(vSpans[0].GetCooldown(), (UINT32)0); + VERIFY_ARE_EQUAL(vSpans[0].GetRandSeed(), (UINT32)0); + VERIFY_ARE_EQUAL(vSpans[0].GetThreadCount(), (DWORD)0); + VERIFY_ARE_EQUAL(vSpans[0].GetRequestCount(), (DWORD)0); + VERIFY_IS_TRUE(vSpans[0].GetDisableAffinity() == false); + VERIFY_IS_TRUE(vSpans[0].GetCompletionRoutines() == false); + VERIFY_IS_TRUE(vSpans[0].GetMeasureLatency() == false); + VERIFY_IS_TRUE(vSpans[0].GetRandomWriteData() == false); + + const auto& vAffinity(vSpans[0].GetAffinityAssignments()); + VERIFY_ARE_EQUAL(vAffinity.size(), (size_t)0); + + vector vTargets(vSpans[0].GetTargets()); + VERIFY_ARE_EQUAL(vTargets.size(), (size_t)1); + Target t(vTargets[0]); + + VERIFY_IS_TRUE(t.GetPath().compare("testfile.dat") == 0); + VERIFY_ARE_EQUAL(t.GetBlockSizeInBytes(), (DWORD)(128 * 1024)); + VERIFY_ARE_EQUAL(t.GetRequestCount(), (DWORD)2); + VERIFY_IS_TRUE(t.GetRandomRatio() == 0); + VERIFY_IS_TRUE(t.GetUseInterlockedSequential() == false); + VERIFY_ARE_EQUAL(t.GetBlockAlignmentInBytes(), t.GetBlockSizeInBytes()); + VERIFY_ARE_EQUAL(t.GetBaseFileOffsetInBytes(), 0); + VERIFY_IS_TRUE(t.GetUseParallelAsyncIO() == false); + VERIFY_IS_TRUE(t.GetCacheMode() == TargetCacheMode::Cached); + VERIFY_IS_TRUE(t.GetWriteThroughMode() == WriteThroughMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoMode() == MemoryMappedIoMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoFlushMode() == MemoryMappedIoFlushMode::Undefined); + VERIFY_IS_TRUE(t.GetZeroWriteBuffers() == false); + VERIFY_ARE_EQUAL(t.GetThreadsPerFile(), (DWORD)1); + VERIFY_ARE_EQUAL(t.GetThreadStrideInBytes(), 0); + VERIFY_IS_TRUE(t.GetCreateFile() == false); + VERIFY_ARE_EQUAL(t.GetFileSize(), 0); + VERIFY_ARE_EQUAL(t.GetMaxFileSize(), 0); + VERIFY_ARE_EQUAL(t.GetWriteRatio(), (DWORD)84); + VERIFY_IS_TRUE(t.GetUseBurstSize() == false); + VERIFY_ARE_EQUAL(t.GetBurstSize(), (DWORD)0); + VERIFY_ARE_EQUAL(t.GetThinkTime(), (DWORD)0); + VERIFY_IS_TRUE(t.GetEnableThinkTime() == false); + VERIFY_IS_TRUE(t.GetSequentialScanHint() == false); + VERIFY_IS_TRUE(t.GetRandomAccessHint() == false); + VERIFY_IS_TRUE(t.GetTemporaryFileHint() == false); + VERIFY_IS_TRUE(t.GetUseLargePages() == false); + VERIFY_ARE_EQUAL(t.GetThroughputInBytesPerMillisecond(), (DWORD)0); + } + + void CmdLineParserUnitTests::TestParseCmdLineEtwREGISTRY() + { + CmdLineParser p; + Profile profile; + struct Synchronization s = {}; + const char *argv[] = { "foo", "-b128K", "-w84", "-eREGISTRY", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == true); + VERIFY_IS_TRUE(profile.GetVerbose() == false); + VERIFY_IS_TRUE(profile.GetProgress() == 0); + VERIFY_IS_TRUE(profile.GetCmdLine().compare("foo -b128K -w84 -eREGISTRY testfile.dat") == 0); + VERIFY_IS_TRUE(profile.GetEtwEnabled() == true); + VERIFY_IS_TRUE(profile.GetEtwProcess() == false); + VERIFY_IS_TRUE(profile.GetEtwThread() == false); + VERIFY_IS_TRUE(profile.GetEtwImageLoad() == false); + VERIFY_IS_TRUE(profile.GetEtwDiskIO() == false); + VERIFY_IS_TRUE(profile.GetEtwMemoryPageFaults() == false); + VERIFY_IS_TRUE(profile.GetEtwMemoryHardFaults() == false); + VERIFY_IS_TRUE(profile.GetEtwNetwork() == false); + VERIFY_IS_TRUE(profile.GetEtwRegistry() == true); + VERIFY_IS_TRUE(profile.GetEtwUsePagedMemory() == false); + VERIFY_IS_TRUE(profile.GetEtwUsePerfTimer() == false); + VERIFY_IS_TRUE(profile.GetEtwUseSystemTimer() == false); + VERIFY_IS_TRUE(profile.GetEtwUseCyclesCounter() == false); + + vector vSpans(profile.GetTimeSpans()); + VERIFY_ARE_EQUAL(vSpans.size(), (size_t)1); + VERIFY_ARE_EQUAL(vSpans[0].GetDuration(), (UINT32)10); + VERIFY_ARE_EQUAL(vSpans[0].GetWarmup(), (UINT32)5); + VERIFY_ARE_EQUAL(vSpans[0].GetCooldown(), (UINT32)0); + VERIFY_ARE_EQUAL(vSpans[0].GetRandSeed(), (UINT32)0); + VERIFY_ARE_EQUAL(vSpans[0].GetThreadCount(), (DWORD)0); + VERIFY_ARE_EQUAL(vSpans[0].GetRequestCount(), (DWORD)0); + VERIFY_IS_TRUE(vSpans[0].GetDisableAffinity() == false); + VERIFY_IS_TRUE(vSpans[0].GetCompletionRoutines() == false); + VERIFY_IS_TRUE(vSpans[0].GetMeasureLatency() == false); + VERIFY_IS_TRUE(vSpans[0].GetRandomWriteData() == false); + + const auto& vAffinity(vSpans[0].GetAffinityAssignments()); + VERIFY_ARE_EQUAL(vAffinity.size(), (size_t)0); + + vector vTargets(vSpans[0].GetTargets()); + VERIFY_ARE_EQUAL(vTargets.size(), (size_t)1); + Target t(vTargets[0]); + + VERIFY_IS_TRUE(t.GetPath().compare("testfile.dat") == 0); + VERIFY_ARE_EQUAL(t.GetBlockSizeInBytes(), (DWORD)(128 * 1024)); + VERIFY_ARE_EQUAL(t.GetRequestCount(), (DWORD)2); + VERIFY_IS_TRUE(t.GetRandomRatio() == 0); + VERIFY_IS_TRUE(t.GetUseInterlockedSequential() == false); + VERIFY_ARE_EQUAL(t.GetBlockAlignmentInBytes(), t.GetBlockSizeInBytes()); + VERIFY_ARE_EQUAL(t.GetBaseFileOffsetInBytes(), 0); + VERIFY_IS_TRUE(t.GetUseParallelAsyncIO() == false); + VERIFY_IS_TRUE(t.GetCacheMode() == TargetCacheMode::Cached); + VERIFY_IS_TRUE(t.GetWriteThroughMode() == WriteThroughMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoMode() == MemoryMappedIoMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoFlushMode() == MemoryMappedIoFlushMode::Undefined); + VERIFY_IS_TRUE(t.GetZeroWriteBuffers() == false); + VERIFY_ARE_EQUAL(t.GetThreadsPerFile(), (DWORD)1); + VERIFY_ARE_EQUAL(t.GetThreadStrideInBytes(), 0); + VERIFY_IS_TRUE(t.GetCreateFile() == false); + VERIFY_ARE_EQUAL(t.GetFileSize(), 0); + VERIFY_ARE_EQUAL(t.GetMaxFileSize(), 0); + VERIFY_ARE_EQUAL(t.GetWriteRatio(), (DWORD)84); + VERIFY_IS_TRUE(t.GetUseBurstSize() == false); + VERIFY_ARE_EQUAL(t.GetBurstSize(), (DWORD)0); + VERIFY_ARE_EQUAL(t.GetThinkTime(), (DWORD)0); + VERIFY_IS_TRUE(t.GetEnableThinkTime() == false); + VERIFY_IS_TRUE(t.GetSequentialScanHint() == false); + VERIFY_IS_TRUE(t.GetRandomAccessHint() == false); + VERIFY_IS_TRUE(t.GetTemporaryFileHint() == false); + VERIFY_IS_TRUE(t.GetUseLargePages() == false); + VERIFY_ARE_EQUAL(t.GetThroughputInBytesPerMillisecond(), (DWORD)0); + } + + void CmdLineParserUnitTests::TestParseCmdLineEtwMEMORY_PAGE_FAULTS() + { + CmdLineParser p; + Profile profile; + struct Synchronization s = {}; + const char *argv[] = { "foo", "-b128K", "-w84", "-eMEMORY_PAGE_FAULTS", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == true); + VERIFY_IS_TRUE(profile.GetVerbose() == false); + VERIFY_IS_TRUE(profile.GetProgress() == 0); + VERIFY_IS_TRUE(profile.GetCmdLine().compare("foo -b128K -w84 -eMEMORY_PAGE_FAULTS testfile.dat") == 0); + VERIFY_IS_TRUE(profile.GetEtwEnabled() == true); + VERIFY_IS_TRUE(profile.GetEtwProcess() == false); + VERIFY_IS_TRUE(profile.GetEtwThread() == false); + VERIFY_IS_TRUE(profile.GetEtwImageLoad() == false); + VERIFY_IS_TRUE(profile.GetEtwDiskIO() == false); + VERIFY_IS_TRUE(profile.GetEtwMemoryPageFaults() == true); + VERIFY_IS_TRUE(profile.GetEtwMemoryHardFaults() == false); + VERIFY_IS_TRUE(profile.GetEtwNetwork() == false); + VERIFY_IS_TRUE(profile.GetEtwRegistry() == false); + VERIFY_IS_TRUE(profile.GetEtwUsePagedMemory() == false); + VERIFY_IS_TRUE(profile.GetEtwUsePerfTimer() == false); + VERIFY_IS_TRUE(profile.GetEtwUseSystemTimer() == false); + VERIFY_IS_TRUE(profile.GetEtwUseCyclesCounter() == false); + + vector vSpans(profile.GetTimeSpans()); + VERIFY_ARE_EQUAL(vSpans.size(), (size_t)1); + VERIFY_ARE_EQUAL(vSpans[0].GetDuration(), (UINT32)10); + VERIFY_ARE_EQUAL(vSpans[0].GetWarmup(), (UINT32)5); + VERIFY_ARE_EQUAL(vSpans[0].GetCooldown(), (UINT32)0); + VERIFY_ARE_EQUAL(vSpans[0].GetRandSeed(), (UINT32)0); + VERIFY_ARE_EQUAL(vSpans[0].GetThreadCount(), (DWORD)0); + VERIFY_ARE_EQUAL(vSpans[0].GetRequestCount(), (DWORD)0); + VERIFY_IS_TRUE(vSpans[0].GetDisableAffinity() == false); + VERIFY_IS_TRUE(vSpans[0].GetCompletionRoutines() == false); + VERIFY_IS_TRUE(vSpans[0].GetMeasureLatency() == false); + VERIFY_IS_TRUE(vSpans[0].GetRandomWriteData() == false); + + const auto& vAffinity(vSpans[0].GetAffinityAssignments()); + VERIFY_ARE_EQUAL(vAffinity.size(), (size_t)0); + + vector vTargets(vSpans[0].GetTargets()); + VERIFY_ARE_EQUAL(vTargets.size(), (size_t)1); + Target t(vTargets[0]); + + VERIFY_IS_TRUE(t.GetPath().compare("testfile.dat") == 0); + VERIFY_ARE_EQUAL(t.GetBlockSizeInBytes(), (DWORD)(128 * 1024)); + VERIFY_ARE_EQUAL(t.GetRequestCount(), (DWORD)2); + VERIFY_IS_TRUE(t.GetRandomRatio() == 0); + VERIFY_IS_TRUE(t.GetUseInterlockedSequential() == false); + VERIFY_ARE_EQUAL(t.GetBlockAlignmentInBytes(), t.GetBlockSizeInBytes()); + VERIFY_ARE_EQUAL(t.GetBaseFileOffsetInBytes(), 0); + VERIFY_IS_TRUE(t.GetUseParallelAsyncIO() == false); + VERIFY_IS_TRUE(t.GetCacheMode() == TargetCacheMode::Cached); + VERIFY_IS_TRUE(t.GetWriteThroughMode() == WriteThroughMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoMode() == MemoryMappedIoMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoFlushMode() == MemoryMappedIoFlushMode::Undefined); + VERIFY_IS_TRUE(t.GetZeroWriteBuffers() == false); + VERIFY_ARE_EQUAL(t.GetThreadsPerFile(), (DWORD)1); + VERIFY_ARE_EQUAL(t.GetThreadStrideInBytes(), 0); + VERIFY_IS_TRUE(t.GetCreateFile() == false); + VERIFY_ARE_EQUAL(t.GetFileSize(), 0); + VERIFY_ARE_EQUAL(t.GetMaxFileSize(), 0); + VERIFY_ARE_EQUAL(t.GetWriteRatio(), (DWORD)84); + VERIFY_IS_TRUE(t.GetUseBurstSize() == false); + VERIFY_ARE_EQUAL(t.GetBurstSize(), (DWORD)0); + VERIFY_ARE_EQUAL(t.GetThinkTime(), (DWORD)0); + VERIFY_IS_TRUE(t.GetEnableThinkTime() == false); + VERIFY_IS_TRUE(t.GetSequentialScanHint() == false); + VERIFY_IS_TRUE(t.GetRandomAccessHint() == false); + VERIFY_IS_TRUE(t.GetTemporaryFileHint() == false); + VERIFY_IS_TRUE(t.GetUseLargePages() == false); + VERIFY_ARE_EQUAL(t.GetThroughputInBytesPerMillisecond(), (DWORD)0); + } + + void CmdLineParserUnitTests::TestParseCmdLineEtwMEMORY_HARD_FAULTS() + { + CmdLineParser p; + Profile profile; + struct Synchronization s = {}; + const char *argv[] = { "foo", "-b128K", "-w84", "-eMEMORY_HARD_FAULTS", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == true); + VERIFY_IS_TRUE(profile.GetVerbose() == false); + VERIFY_IS_TRUE(profile.GetProgress() == 0); + VERIFY_IS_TRUE(profile.GetCmdLine().compare("foo -b128K -w84 -eMEMORY_HARD_FAULTS testfile.dat") == 0); + VERIFY_IS_TRUE(profile.GetEtwEnabled() == true); + VERIFY_IS_TRUE(profile.GetEtwProcess() == false); + VERIFY_IS_TRUE(profile.GetEtwThread() == false); + VERIFY_IS_TRUE(profile.GetEtwImageLoad() == false); + VERIFY_IS_TRUE(profile.GetEtwDiskIO() == false); + VERIFY_IS_TRUE(profile.GetEtwMemoryPageFaults() == false); + VERIFY_IS_TRUE(profile.GetEtwMemoryHardFaults() == true); + VERIFY_IS_TRUE(profile.GetEtwNetwork() == false); + VERIFY_IS_TRUE(profile.GetEtwRegistry() == false); + VERIFY_IS_TRUE(profile.GetEtwUsePagedMemory() == false); + VERIFY_IS_TRUE(profile.GetEtwUsePerfTimer() == false); + VERIFY_IS_TRUE(profile.GetEtwUseSystemTimer() == false); + VERIFY_IS_TRUE(profile.GetEtwUseCyclesCounter() == false); + + vector vSpans(profile.GetTimeSpans()); + VERIFY_ARE_EQUAL(vSpans.size(), (size_t)1); + VERIFY_ARE_EQUAL(vSpans[0].GetDuration(), (UINT32)10); + VERIFY_ARE_EQUAL(vSpans[0].GetWarmup(), (UINT32)5); + VERIFY_ARE_EQUAL(vSpans[0].GetCooldown(), (UINT32)0); + VERIFY_ARE_EQUAL(vSpans[0].GetRandSeed(), (UINT32)0); + VERIFY_ARE_EQUAL(vSpans[0].GetThreadCount(), (DWORD)0); + VERIFY_ARE_EQUAL(vSpans[0].GetRequestCount(), (DWORD)0); + VERIFY_IS_TRUE(vSpans[0].GetDisableAffinity() == false); + VERIFY_IS_TRUE(vSpans[0].GetCompletionRoutines() == false); + VERIFY_IS_TRUE(vSpans[0].GetMeasureLatency() == false); + VERIFY_IS_TRUE(vSpans[0].GetRandomWriteData() == false); + + const auto& vAffinity(vSpans[0].GetAffinityAssignments()); + VERIFY_ARE_EQUAL(vAffinity.size(), (size_t)0); + + vector vTargets(vSpans[0].GetTargets()); + VERIFY_ARE_EQUAL(vTargets.size(), (size_t)1); + Target t(vTargets[0]); + + VERIFY_IS_TRUE(t.GetPath().compare("testfile.dat") == 0); + VERIFY_ARE_EQUAL(t.GetBlockSizeInBytes(), (DWORD)(128 * 1024)); + VERIFY_ARE_EQUAL(t.GetRequestCount(), (DWORD)2); + VERIFY_IS_TRUE(t.GetRandomRatio() == 0); + VERIFY_IS_TRUE(t.GetUseInterlockedSequential() == false); + VERIFY_ARE_EQUAL(t.GetBlockAlignmentInBytes(), t.GetBlockSizeInBytes()); + VERIFY_ARE_EQUAL(t.GetBaseFileOffsetInBytes(), 0); + VERIFY_IS_TRUE(t.GetUseParallelAsyncIO() == false); + VERIFY_IS_TRUE(t.GetCacheMode() == TargetCacheMode::Cached); + VERIFY_IS_TRUE(t.GetWriteThroughMode() == WriteThroughMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoMode() == MemoryMappedIoMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoFlushMode() == MemoryMappedIoFlushMode::Undefined); + VERIFY_IS_TRUE(t.GetZeroWriteBuffers() == false); + VERIFY_ARE_EQUAL(t.GetThreadsPerFile(), (DWORD)1); + VERIFY_ARE_EQUAL(t.GetThreadStrideInBytes(), 0); + VERIFY_IS_TRUE(t.GetCreateFile() == false); + VERIFY_ARE_EQUAL(t.GetFileSize(), 0); + VERIFY_ARE_EQUAL(t.GetMaxFileSize(), 0); + VERIFY_ARE_EQUAL(t.GetWriteRatio(), (DWORD)84); + VERIFY_IS_TRUE(t.GetUseBurstSize() == false); + VERIFY_ARE_EQUAL(t.GetBurstSize(), (DWORD)0); + VERIFY_ARE_EQUAL(t.GetThinkTime(), (DWORD)0); + VERIFY_IS_TRUE(t.GetEnableThinkTime() == false); + VERIFY_IS_TRUE(t.GetSequentialScanHint() == false); + VERIFY_IS_TRUE(t.GetRandomAccessHint() == false); + VERIFY_IS_TRUE(t.GetTemporaryFileHint() == false); + VERIFY_IS_TRUE(t.GetUseLargePages() == false); + VERIFY_ARE_EQUAL(t.GetThroughputInBytesPerMillisecond(), (DWORD)0); + } + + void CmdLineParserUnitTests::TestParseCmdLineEtwUsePerfTimer() + { + CmdLineParser p; + Profile profile; + struct Synchronization s = {}; + const char *argv[] = { "foo", "-b128K", "-w84", "-eq", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == true); + VERIFY_IS_TRUE(profile.GetVerbose() == false); + VERIFY_IS_TRUE(profile.GetProgress() == 0); + VERIFY_IS_TRUE(profile.GetCmdLine().compare("foo -b128K -w84 -eq testfile.dat") == 0); + VERIFY_IS_TRUE(profile.GetEtwEnabled() == true); + VERIFY_IS_TRUE(profile.GetEtwProcess() == false); + VERIFY_IS_TRUE(profile.GetEtwThread() == false); + VERIFY_IS_TRUE(profile.GetEtwImageLoad() == false); + VERIFY_IS_TRUE(profile.GetEtwDiskIO() == false); + VERIFY_IS_TRUE(profile.GetEtwMemoryPageFaults() == false); + VERIFY_IS_TRUE(profile.GetEtwMemoryHardFaults() == false); + VERIFY_IS_TRUE(profile.GetEtwNetwork() == false); + VERIFY_IS_TRUE(profile.GetEtwRegistry() == false); + VERIFY_IS_TRUE(profile.GetEtwUsePagedMemory() == false); + VERIFY_IS_TRUE(profile.GetEtwUsePerfTimer() == true); + VERIFY_IS_TRUE(profile.GetEtwUseSystemTimer() == false); + VERIFY_IS_TRUE(profile.GetEtwUseCyclesCounter() == false); + + vector vSpans(profile.GetTimeSpans()); + VERIFY_ARE_EQUAL(vSpans.size(), (size_t)1); + VERIFY_ARE_EQUAL(vSpans[0].GetDuration(), (UINT32)10); + VERIFY_ARE_EQUAL(vSpans[0].GetWarmup(), (UINT32)5); + VERIFY_ARE_EQUAL(vSpans[0].GetCooldown(), (UINT32)0); + VERIFY_ARE_EQUAL(vSpans[0].GetRandSeed(), (UINT32)0); + VERIFY_ARE_EQUAL(vSpans[0].GetThreadCount(), (DWORD)0); + VERIFY_ARE_EQUAL(vSpans[0].GetRequestCount(), (DWORD)0); + VERIFY_IS_TRUE(vSpans[0].GetDisableAffinity() == false); + VERIFY_IS_TRUE(vSpans[0].GetCompletionRoutines() == false); + VERIFY_IS_TRUE(vSpans[0].GetMeasureLatency() == false); + VERIFY_IS_TRUE(vSpans[0].GetRandomWriteData() == false); + + const auto& vAffinity(vSpans[0].GetAffinityAssignments()); + VERIFY_ARE_EQUAL(vAffinity.size(), (size_t)0); + + vector vTargets(vSpans[0].GetTargets()); + VERIFY_ARE_EQUAL(vTargets.size(), (size_t)1); + Target t(vTargets[0]); + + VERIFY_IS_TRUE(t.GetPath().compare("testfile.dat") == 0); + VERIFY_ARE_EQUAL(t.GetBlockSizeInBytes(), (DWORD)(128 * 1024)); + VERIFY_ARE_EQUAL(t.GetRequestCount(), (DWORD)2); + VERIFY_IS_TRUE(t.GetRandomRatio() == 0); + VERIFY_IS_TRUE(t.GetUseInterlockedSequential() == false); + VERIFY_ARE_EQUAL(t.GetBlockAlignmentInBytes(), t.GetBlockSizeInBytes()); + VERIFY_ARE_EQUAL(t.GetBaseFileOffsetInBytes(), 0); + VERIFY_IS_TRUE(t.GetUseParallelAsyncIO() == false); + VERIFY_IS_TRUE(t.GetCacheMode() == TargetCacheMode::Cached); + VERIFY_IS_TRUE(t.GetWriteThroughMode() == WriteThroughMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoMode() == MemoryMappedIoMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoFlushMode() == MemoryMappedIoFlushMode::Undefined); + VERIFY_IS_TRUE(t.GetZeroWriteBuffers() == false); + VERIFY_ARE_EQUAL(t.GetThreadsPerFile(), (DWORD)1); + VERIFY_ARE_EQUAL(t.GetThreadStrideInBytes(), 0); + VERIFY_IS_TRUE(t.GetCreateFile() == false); + VERIFY_ARE_EQUAL(t.GetFileSize(), 0); + VERIFY_ARE_EQUAL(t.GetMaxFileSize(), 0); + VERIFY_ARE_EQUAL(t.GetWriteRatio(), (DWORD)84); + VERIFY_IS_TRUE(t.GetUseBurstSize() == false); + VERIFY_ARE_EQUAL(t.GetBurstSize(), (DWORD)0); + VERIFY_ARE_EQUAL(t.GetThinkTime(), (DWORD)0); + VERIFY_IS_TRUE(t.GetEnableThinkTime() == false); + VERIFY_IS_TRUE(t.GetSequentialScanHint() == false); + VERIFY_IS_TRUE(t.GetRandomAccessHint() == false); + VERIFY_IS_TRUE(t.GetTemporaryFileHint() == false); + VERIFY_IS_TRUE(t.GetUseLargePages() == false); + VERIFY_ARE_EQUAL(t.GetThroughputInBytesPerMillisecond(), (DWORD)0); + } + + void CmdLineParserUnitTests::TestParseCmdLineEtwUseSystemTimer() + { + CmdLineParser p; + Profile profile; + struct Synchronization s = {}; + const char *argv[] = { "foo", "-b128K", "-w84", "-es", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == true); + VERIFY_IS_TRUE(profile.GetVerbose() == false); + VERIFY_IS_TRUE(profile.GetProgress() == 0); + VERIFY_IS_TRUE(profile.GetCmdLine().compare("foo -b128K -w84 -es testfile.dat") == 0); + VERIFY_IS_TRUE(profile.GetEtwEnabled() == true); + VERIFY_IS_TRUE(profile.GetEtwProcess() == false); + VERIFY_IS_TRUE(profile.GetEtwThread() == false); + VERIFY_IS_TRUE(profile.GetEtwImageLoad() == false); + VERIFY_IS_TRUE(profile.GetEtwDiskIO() == false); + VERIFY_IS_TRUE(profile.GetEtwMemoryPageFaults() == false); + VERIFY_IS_TRUE(profile.GetEtwMemoryHardFaults() == false); + VERIFY_IS_TRUE(profile.GetEtwNetwork() == false); + VERIFY_IS_TRUE(profile.GetEtwRegistry() == false); + VERIFY_IS_TRUE(profile.GetEtwUsePagedMemory() == false); + VERIFY_IS_TRUE(profile.GetEtwUsePerfTimer() == false); + VERIFY_IS_TRUE(profile.GetEtwUseSystemTimer() == true); + VERIFY_IS_TRUE(profile.GetEtwUseCyclesCounter() == false); + + vector vSpans(profile.GetTimeSpans()); + VERIFY_ARE_EQUAL(vSpans.size(), (size_t)1); + VERIFY_ARE_EQUAL(vSpans[0].GetDuration(), (UINT32)10); + VERIFY_ARE_EQUAL(vSpans[0].GetWarmup(), (UINT32)5); + VERIFY_ARE_EQUAL(vSpans[0].GetCooldown(), (UINT32)0); + VERIFY_ARE_EQUAL(vSpans[0].GetRandSeed(), (UINT32)0); + VERIFY_ARE_EQUAL(vSpans[0].GetThreadCount(), (DWORD)0); + VERIFY_ARE_EQUAL(vSpans[0].GetRequestCount(), (DWORD)0); + VERIFY_IS_TRUE(vSpans[0].GetDisableAffinity() == false); + VERIFY_IS_TRUE(vSpans[0].GetCompletionRoutines() == false); + VERIFY_IS_TRUE(vSpans[0].GetMeasureLatency() == false); + VERIFY_IS_TRUE(vSpans[0].GetRandomWriteData() == false); + + const auto& vAffinity(vSpans[0].GetAffinityAssignments()); + VERIFY_ARE_EQUAL(vAffinity.size(), (size_t)0); + + vector vTargets(vSpans[0].GetTargets()); + VERIFY_ARE_EQUAL(vTargets.size(), (size_t)1); + Target t(vTargets[0]); + + VERIFY_IS_TRUE(t.GetPath().compare("testfile.dat") == 0); + VERIFY_ARE_EQUAL(t.GetBlockSizeInBytes(), (DWORD)(128 * 1024)); + VERIFY_ARE_EQUAL(t.GetRequestCount(), (DWORD)2); + VERIFY_IS_TRUE(t.GetRandomRatio() == 0); + VERIFY_IS_TRUE(t.GetUseInterlockedSequential() == false); + VERIFY_ARE_EQUAL(t.GetBlockAlignmentInBytes(), t.GetBlockSizeInBytes()); + VERIFY_ARE_EQUAL(t.GetBaseFileOffsetInBytes(), 0); + VERIFY_IS_TRUE(t.GetUseParallelAsyncIO() == false); + VERIFY_IS_TRUE(t.GetCacheMode() == TargetCacheMode::Cached); + VERIFY_IS_TRUE(t.GetWriteThroughMode() == WriteThroughMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoMode() == MemoryMappedIoMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoFlushMode() == MemoryMappedIoFlushMode::Undefined); + VERIFY_IS_TRUE(t.GetZeroWriteBuffers() == false); + VERIFY_ARE_EQUAL(t.GetThreadsPerFile(), (DWORD)1); + VERIFY_ARE_EQUAL(t.GetThreadStrideInBytes(), 0); + VERIFY_IS_TRUE(t.GetCreateFile() == false); + VERIFY_ARE_EQUAL(t.GetFileSize(), 0); + VERIFY_ARE_EQUAL(t.GetMaxFileSize(), 0); + VERIFY_ARE_EQUAL(t.GetWriteRatio(), (DWORD)84); + VERIFY_IS_TRUE(t.GetUseBurstSize() == false); + VERIFY_ARE_EQUAL(t.GetBurstSize(), (DWORD)0); + VERIFY_ARE_EQUAL(t.GetThinkTime(), (DWORD)0); + VERIFY_IS_TRUE(t.GetEnableThinkTime() == false); + VERIFY_IS_TRUE(t.GetSequentialScanHint() == false); + VERIFY_IS_TRUE(t.GetRandomAccessHint() == false); + VERIFY_IS_TRUE(t.GetTemporaryFileHint() == false); + VERIFY_IS_TRUE(t.GetUseLargePages() == false); + VERIFY_ARE_EQUAL(t.GetThroughputInBytesPerMillisecond(), (DWORD)0); + } + + void CmdLineParserUnitTests::TestParseCmdLineEtwUseCycleCount() + { + CmdLineParser p; + Profile profile; + struct Synchronization s = {}; + const char *argv[] = { "foo", "-b128K", "-w84", "-ec", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == true); + VERIFY_IS_TRUE(profile.GetVerbose() == false); + VERIFY_IS_TRUE(profile.GetProgress() == 0); + VERIFY_IS_TRUE(profile.GetCmdLine().compare("foo -b128K -w84 -ec testfile.dat") == 0); + VERIFY_IS_TRUE(profile.GetEtwEnabled() == true); + VERIFY_IS_TRUE(profile.GetEtwProcess() == false); + VERIFY_IS_TRUE(profile.GetEtwThread() == false); + VERIFY_IS_TRUE(profile.GetEtwImageLoad() == false); + VERIFY_IS_TRUE(profile.GetEtwDiskIO() == false); + VERIFY_IS_TRUE(profile.GetEtwMemoryPageFaults() == false); + VERIFY_IS_TRUE(profile.GetEtwMemoryHardFaults() == false); + VERIFY_IS_TRUE(profile.GetEtwNetwork() == false); + VERIFY_IS_TRUE(profile.GetEtwRegistry() == false); + VERIFY_IS_TRUE(profile.GetEtwUsePagedMemory() == false); + VERIFY_IS_TRUE(profile.GetEtwUsePerfTimer() == false); + VERIFY_IS_TRUE(profile.GetEtwUseSystemTimer() == false); + VERIFY_IS_TRUE(profile.GetEtwUseCyclesCounter() == true); + + vector vSpans(profile.GetTimeSpans()); + VERIFY_ARE_EQUAL(vSpans.size(), (size_t)1); + VERIFY_ARE_EQUAL(vSpans[0].GetDuration(), (UINT32)10); + VERIFY_ARE_EQUAL(vSpans[0].GetWarmup(), (UINT32)5); + VERIFY_ARE_EQUAL(vSpans[0].GetCooldown(), (UINT32)0); + VERIFY_ARE_EQUAL(vSpans[0].GetRandSeed(), (UINT32)0); + VERIFY_ARE_EQUAL(vSpans[0].GetThreadCount(), (DWORD)0); + VERIFY_ARE_EQUAL(vSpans[0].GetRequestCount(), (DWORD)0); + VERIFY_IS_TRUE(vSpans[0].GetDisableAffinity() == false); + VERIFY_IS_TRUE(vSpans[0].GetCompletionRoutines() == false); + VERIFY_IS_TRUE(vSpans[0].GetMeasureLatency() == false); + VERIFY_IS_TRUE(vSpans[0].GetRandomWriteData() == false); + + const auto& vAffinity(vSpans[0].GetAffinityAssignments()); + VERIFY_ARE_EQUAL(vAffinity.size(), (size_t)0); + + vector vTargets(vSpans[0].GetTargets()); + VERIFY_ARE_EQUAL(vTargets.size(), (size_t)1); + Target t(vTargets[0]); + + VERIFY_IS_TRUE(t.GetPath().compare("testfile.dat") == 0); + VERIFY_ARE_EQUAL(t.GetBlockSizeInBytes(), (DWORD)(128 * 1024)); + VERIFY_ARE_EQUAL(t.GetRequestCount(), (DWORD)2); + VERIFY_IS_TRUE(t.GetRandomRatio() == 0); + VERIFY_IS_TRUE(t.GetUseInterlockedSequential() == false); + VERIFY_ARE_EQUAL(t.GetBlockAlignmentInBytes(), t.GetBlockSizeInBytes()); + VERIFY_ARE_EQUAL(t.GetBaseFileOffsetInBytes(), 0); + VERIFY_IS_TRUE(t.GetUseParallelAsyncIO() == false); + VERIFY_IS_TRUE(t.GetCacheMode() == TargetCacheMode::Cached); + VERIFY_IS_TRUE(t.GetWriteThroughMode() == WriteThroughMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoMode() == MemoryMappedIoMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoFlushMode() == MemoryMappedIoFlushMode::Undefined); + VERIFY_IS_TRUE(t.GetZeroWriteBuffers() == false); + VERIFY_ARE_EQUAL(t.GetThreadsPerFile(), (DWORD)1); + VERIFY_ARE_EQUAL(t.GetThreadStrideInBytes(), 0); + VERIFY_IS_TRUE(t.GetCreateFile() == false); + VERIFY_ARE_EQUAL(t.GetFileSize(), 0); + VERIFY_ARE_EQUAL(t.GetMaxFileSize(), 0); + VERIFY_ARE_EQUAL(t.GetWriteRatio(), (DWORD)84); + VERIFY_IS_TRUE(t.GetUseBurstSize() == false); + VERIFY_ARE_EQUAL(t.GetBurstSize(), (DWORD)0); + VERIFY_ARE_EQUAL(t.GetThinkTime(), (DWORD)0); + VERIFY_IS_TRUE(t.GetEnableThinkTime() == false); + VERIFY_IS_TRUE(t.GetSequentialScanHint() == false); + VERIFY_IS_TRUE(t.GetRandomAccessHint() == false); + VERIFY_IS_TRUE(t.GetTemporaryFileHint() == false); + VERIFY_IS_TRUE(t.GetUseLargePages() == false); + VERIFY_ARE_EQUAL(t.GetThroughputInBytesPerMillisecond(), (DWORD)0); + } + + void CmdLineParserUnitTests::TestParseCmdLineIOPriority() + { + CmdLineParser p; + Profile profile; + struct Synchronization s = {}; + const char *argv[] = { "foo", "-b128K", "-w84", "-I2", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == true); + VERIFY_IS_TRUE(profile.GetVerbose() == false); + VERIFY_IS_TRUE(profile.GetProgress() == 0); + VERIFY_IS_TRUE(profile.GetCmdLine().compare("foo -b128K -w84 -I2 testfile.dat") == 0); + VERIFY_IS_TRUE(profile.GetEtwEnabled() == false); + VERIFY_IS_TRUE(profile.GetEtwProcess() == false); + VERIFY_IS_TRUE(profile.GetEtwThread() == false); + VERIFY_IS_TRUE(profile.GetEtwImageLoad() == false); + VERIFY_IS_TRUE(profile.GetEtwDiskIO() == false); + VERIFY_IS_TRUE(profile.GetEtwMemoryPageFaults() == false); + VERIFY_IS_TRUE(profile.GetEtwMemoryHardFaults() == false); + VERIFY_IS_TRUE(profile.GetEtwNetwork() == false); + VERIFY_IS_TRUE(profile.GetEtwRegistry() == false); + VERIFY_IS_TRUE(profile.GetEtwUsePagedMemory() == false); + VERIFY_IS_TRUE(profile.GetEtwUsePerfTimer() == false); + VERIFY_IS_TRUE(profile.GetEtwUseSystemTimer() == false); + VERIFY_IS_TRUE(profile.GetEtwUseCyclesCounter() == false); + + vector vSpans(profile.GetTimeSpans()); + VERIFY_ARE_EQUAL(vSpans.size(), (size_t)1); + VERIFY_ARE_EQUAL(vSpans[0].GetDuration(), (UINT32)10); + VERIFY_ARE_EQUAL(vSpans[0].GetWarmup(), (UINT32)5); + VERIFY_ARE_EQUAL(vSpans[0].GetCooldown(), (UINT32)0); + VERIFY_ARE_EQUAL(vSpans[0].GetRandSeed(), (UINT32)0); + VERIFY_ARE_EQUAL(vSpans[0].GetThreadCount(), (DWORD)0); + VERIFY_ARE_EQUAL(vSpans[0].GetRequestCount(), (DWORD)0); + VERIFY_IS_TRUE(vSpans[0].GetDisableAffinity() == false); + VERIFY_IS_TRUE(vSpans[0].GetCompletionRoutines() == false); + VERIFY_IS_TRUE(vSpans[0].GetMeasureLatency() == false); + VERIFY_IS_TRUE(vSpans[0].GetRandomWriteData() == false); + + const auto& vAffinity(vSpans[0].GetAffinityAssignments()); + VERIFY_ARE_EQUAL(vAffinity.size(), (size_t)0); + + vector vTargets(vSpans[0].GetTargets()); + VERIFY_ARE_EQUAL(vTargets.size(), (size_t)1); + Target t(vTargets[0]); + + VERIFY_IS_TRUE(t.GetPath().compare("testfile.dat") == 0); + VERIFY_ARE_EQUAL(t.GetBlockSizeInBytes(), (DWORD)(128 * 1024)); + VERIFY_ARE_EQUAL(t.GetRequestCount(), (DWORD)2); + VERIFY_IS_TRUE(t.GetRandomRatio() == 0); + VERIFY_IS_TRUE(t.GetUseInterlockedSequential() == false); + VERIFY_ARE_EQUAL(t.GetBlockAlignmentInBytes(), t.GetBlockSizeInBytes()); + VERIFY_ARE_EQUAL(t.GetBaseFileOffsetInBytes(), 0); + VERIFY_IS_TRUE(t.GetUseParallelAsyncIO() == false); + VERIFY_IS_TRUE(t.GetCacheMode() == TargetCacheMode::Cached); + VERIFY_IS_TRUE(t.GetWriteThroughMode() == WriteThroughMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoMode() == MemoryMappedIoMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoFlushMode() == MemoryMappedIoFlushMode::Undefined); + VERIFY_IS_TRUE(t.GetZeroWriteBuffers() == false); + VERIFY_ARE_EQUAL(t.GetThreadsPerFile(), (DWORD)1); + VERIFY_ARE_EQUAL(t.GetThreadStrideInBytes(), 0); + VERIFY_IS_TRUE(t.GetCreateFile() == false); + VERIFY_ARE_EQUAL(t.GetFileSize(), 0); + VERIFY_ARE_EQUAL(t.GetMaxFileSize(), 0); + VERIFY_ARE_EQUAL(t.GetWriteRatio(), (DWORD)84); + VERIFY_IS_TRUE(t.GetUseBurstSize() == false); + VERIFY_ARE_EQUAL(t.GetBurstSize(), (DWORD)0); + VERIFY_ARE_EQUAL(t.GetThinkTime(), (DWORD)0); + VERIFY_IS_TRUE(t.GetEnableThinkTime() == false); + VERIFY_IS_TRUE(t.GetSequentialScanHint() == false); + VERIFY_IS_TRUE(t.GetRandomAccessHint() == false); + VERIFY_IS_TRUE(t.GetTemporaryFileHint() == false); + VERIFY_IS_TRUE(t.GetUseLargePages() == false); + VERIFY_IS_TRUE(t.GetIOPriorityHint() == IoPriorityHintLow); + VERIFY_ARE_EQUAL(t.GetThroughputInBytesPerMillisecond(), (DWORD)0); + } + + void CmdLineParserUnitTests::TestParseCmdLineMeasureLatency() + { + CmdLineParser p; + Profile profile; + struct Synchronization s = {}; + const char *argv[] = { "foo", "-b128K", "-w84", "-L", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == true); + VERIFY_IS_TRUE(profile.GetVerbose() == false); + VERIFY_IS_TRUE(profile.GetProgress() == 0); + VERIFY_IS_TRUE(profile.GetCmdLine().compare("foo -b128K -w84 -L testfile.dat") == 0); + VERIFY_IS_TRUE(profile.GetEtwEnabled() == false); + VERIFY_IS_TRUE(profile.GetEtwProcess() == false); + VERIFY_IS_TRUE(profile.GetEtwThread() == false); + VERIFY_IS_TRUE(profile.GetEtwImageLoad() == false); + VERIFY_IS_TRUE(profile.GetEtwDiskIO() == false); + VERIFY_IS_TRUE(profile.GetEtwMemoryPageFaults() == false); + VERIFY_IS_TRUE(profile.GetEtwMemoryHardFaults() == false); + VERIFY_IS_TRUE(profile.GetEtwNetwork() == false); + VERIFY_IS_TRUE(profile.GetEtwRegistry() == false); + VERIFY_IS_TRUE(profile.GetEtwUsePagedMemory() == false); + VERIFY_IS_TRUE(profile.GetEtwUsePerfTimer() == false); + VERIFY_IS_TRUE(profile.GetEtwUseSystemTimer() == false); + VERIFY_IS_TRUE(profile.GetEtwUseCyclesCounter() == false); + + vector vSpans(profile.GetTimeSpans()); + VERIFY_ARE_EQUAL(vSpans.size(), (size_t)1); + VERIFY_ARE_EQUAL(vSpans[0].GetDuration(), (UINT32)10); + VERIFY_ARE_EQUAL(vSpans[0].GetWarmup(), (UINT32)5); + VERIFY_ARE_EQUAL(vSpans[0].GetCooldown(), (UINT32)0); + VERIFY_ARE_EQUAL(vSpans[0].GetRandSeed(), (UINT32)0); + VERIFY_ARE_EQUAL(vSpans[0].GetThreadCount(), (DWORD)0); + VERIFY_ARE_EQUAL(vSpans[0].GetRequestCount(), (DWORD)0); + VERIFY_IS_TRUE(vSpans[0].GetDisableAffinity() == false); + VERIFY_IS_TRUE(vSpans[0].GetCompletionRoutines() == false); + VERIFY_IS_TRUE(vSpans[0].GetMeasureLatency() == true); + VERIFY_IS_TRUE(vSpans[0].GetRandomWriteData() == false); + + const auto& vAffinity(vSpans[0].GetAffinityAssignments()); + VERIFY_ARE_EQUAL(vAffinity.size(), (size_t)0); + + vector vTargets(vSpans[0].GetTargets()); + VERIFY_ARE_EQUAL(vTargets.size(), (size_t)1); + Target t(vTargets[0]); + + VERIFY_IS_TRUE(t.GetPath().compare("testfile.dat") == 0); + VERIFY_ARE_EQUAL(t.GetBlockSizeInBytes(), (DWORD)(128 * 1024)); + VERIFY_ARE_EQUAL(t.GetRequestCount(), (DWORD)2); + VERIFY_IS_TRUE(t.GetRandomRatio() == 0); + VERIFY_IS_TRUE(t.GetUseInterlockedSequential() == false); + VERIFY_ARE_EQUAL(t.GetBlockAlignmentInBytes(), t.GetBlockSizeInBytes()); + VERIFY_ARE_EQUAL(t.GetBaseFileOffsetInBytes(), 0); + VERIFY_IS_TRUE(t.GetUseParallelAsyncIO() == false); + VERIFY_IS_TRUE(t.GetCacheMode() == TargetCacheMode::Cached); + VERIFY_IS_TRUE(t.GetWriteThroughMode() == WriteThroughMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoMode() == MemoryMappedIoMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoFlushMode() == MemoryMappedIoFlushMode::Undefined); + VERIFY_IS_TRUE(t.GetZeroWriteBuffers() == false); + VERIFY_ARE_EQUAL(t.GetThreadsPerFile(), (DWORD)1); + VERIFY_ARE_EQUAL(t.GetThreadStrideInBytes(), 0); + VERIFY_IS_TRUE(t.GetCreateFile() == false); + VERIFY_ARE_EQUAL(t.GetFileSize(), 0); + VERIFY_ARE_EQUAL(t.GetMaxFileSize(), 0); + VERIFY_ARE_EQUAL(t.GetWriteRatio(), (DWORD)84); + VERIFY_IS_TRUE(t.GetUseBurstSize() == false); + VERIFY_ARE_EQUAL(t.GetBurstSize(), (DWORD)0); + VERIFY_ARE_EQUAL(t.GetThinkTime(), (DWORD)0); + VERIFY_IS_TRUE(t.GetEnableThinkTime() == false); + VERIFY_IS_TRUE(t.GetSequentialScanHint() == false); + VERIFY_IS_TRUE(t.GetRandomAccessHint() == false); + VERIFY_IS_TRUE(t.GetTemporaryFileHint() == false); + VERIFY_IS_TRUE(t.GetUseLargePages() == false); + VERIFY_ARE_EQUAL(t.GetThroughputInBytesPerMillisecond(), (DWORD)0); + } + + void CmdLineParserUnitTests::TestParseCmdLineZeroWriteBuffers() + { + CmdLineParser p; + Profile profile; + struct Synchronization s = {}; + const char *argv[] = { "foo", "-b128K", "-w84", "-Z", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == true); + VERIFY_IS_TRUE(profile.GetVerbose() == false); + VERIFY_IS_TRUE(profile.GetProgress() == 0); + VERIFY_IS_TRUE(profile.GetCmdLine().compare("foo -b128K -w84 -Z testfile.dat") == 0); + VERIFY_IS_TRUE(profile.GetEtwEnabled() == false); + VERIFY_IS_TRUE(profile.GetEtwProcess() == false); + VERIFY_IS_TRUE(profile.GetEtwThread() == false); + VERIFY_IS_TRUE(profile.GetEtwImageLoad() == false); + VERIFY_IS_TRUE(profile.GetEtwDiskIO() == false); + VERIFY_IS_TRUE(profile.GetEtwMemoryPageFaults() == false); + VERIFY_IS_TRUE(profile.GetEtwMemoryHardFaults() == false); + VERIFY_IS_TRUE(profile.GetEtwNetwork() == false); + VERIFY_IS_TRUE(profile.GetEtwRegistry() == false); + VERIFY_IS_TRUE(profile.GetEtwUsePagedMemory() == false); + VERIFY_IS_TRUE(profile.GetEtwUsePerfTimer() == false); + VERIFY_IS_TRUE(profile.GetEtwUseSystemTimer() == false); + VERIFY_IS_TRUE(profile.GetEtwUseCyclesCounter() == false); + + vector vSpans(profile.GetTimeSpans()); + VERIFY_ARE_EQUAL(vSpans.size(), (size_t)1); + VERIFY_ARE_EQUAL(vSpans[0].GetDuration(), (UINT32)10); + VERIFY_ARE_EQUAL(vSpans[0].GetWarmup(), (UINT32)5); + VERIFY_ARE_EQUAL(vSpans[0].GetCooldown(), (UINT32)0); + VERIFY_ARE_EQUAL(vSpans[0].GetRandSeed(), (UINT32)0); + VERIFY_ARE_EQUAL(vSpans[0].GetThreadCount(), (DWORD)0); + VERIFY_ARE_EQUAL(vSpans[0].GetRequestCount(), (DWORD)0); + VERIFY_IS_TRUE(vSpans[0].GetDisableAffinity() == false); + VERIFY_IS_TRUE(vSpans[0].GetCompletionRoutines() == false); + VERIFY_IS_TRUE(vSpans[0].GetMeasureLatency() == false); + VERIFY_IS_TRUE(vSpans[0].GetRandomWriteData() == false); + + const auto& vAffinity(vSpans[0].GetAffinityAssignments()); + VERIFY_ARE_EQUAL(vAffinity.size(), (size_t)0); + + vector vTargets(vSpans[0].GetTargets()); + VERIFY_ARE_EQUAL(vTargets.size(), (size_t)1); + Target t(vTargets[0]); + + VERIFY_IS_TRUE(t.GetPath().compare("testfile.dat") == 0); + VERIFY_ARE_EQUAL(t.GetBlockSizeInBytes(), (DWORD)(128 * 1024)); + VERIFY_ARE_EQUAL(t.GetRequestCount(), (DWORD)2); + VERIFY_IS_TRUE(t.GetRandomRatio() == 0); + VERIFY_IS_TRUE(t.GetUseInterlockedSequential() == false); + VERIFY_ARE_EQUAL(t.GetBlockAlignmentInBytes(), t.GetBlockSizeInBytes()); + VERIFY_ARE_EQUAL(t.GetBaseFileOffsetInBytes(), 0); + VERIFY_IS_TRUE(t.GetUseParallelAsyncIO() == false); + VERIFY_IS_TRUE(t.GetCacheMode() == TargetCacheMode::Cached); + VERIFY_IS_TRUE(t.GetWriteThroughMode() == WriteThroughMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoMode() == MemoryMappedIoMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoFlushMode() == MemoryMappedIoFlushMode::Undefined); + VERIFY_IS_TRUE(t.GetZeroWriteBuffers() == true); + VERIFY_ARE_EQUAL(t.GetThreadsPerFile(), (DWORD)1); + VERIFY_ARE_EQUAL(t.GetThreadStrideInBytes(), 0); + VERIFY_IS_TRUE(t.GetCreateFile() == false); + VERIFY_ARE_EQUAL(t.GetFileSize(), 0); + VERIFY_ARE_EQUAL(t.GetMaxFileSize(), 0); + VERIFY_ARE_EQUAL(t.GetWriteRatio(), (DWORD)84); + VERIFY_IS_TRUE(t.GetUseBurstSize() == false); + VERIFY_ARE_EQUAL(t.GetBurstSize(), (DWORD)0); + VERIFY_ARE_EQUAL(t.GetThinkTime(), (DWORD)0); + VERIFY_IS_TRUE(t.GetEnableThinkTime() == false); + VERIFY_IS_TRUE(t.GetSequentialScanHint() == false); + VERIFY_IS_TRUE(t.GetRandomAccessHint() == false); + VERIFY_IS_TRUE(t.GetTemporaryFileHint() == false); + VERIFY_IS_TRUE(t.GetUseLargePages() == false); + VERIFY_ARE_EQUAL(t.GetThroughputInBytesPerMillisecond(), (DWORD)0); + VERIFY_ARE_EQUAL(t.GetRandomDataWriteBufferSize(), 0); + VERIFY_ARE_EQUAL(t.GetRandomDataWriteBufferSourcePath(), ""); + } + + void CmdLineParserUnitTests::TestParseCmdLineRandomWriteBuffers() + { + CmdLineParser p; + Profile profile; + struct Synchronization s = {}; + const char *argv[] = { "foo", "-b128K", "-w84", "-Zr", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == true); + VERIFY_IS_TRUE(profile.GetVerbose() == false); + VERIFY_IS_TRUE(profile.GetProgress() == 0); + VERIFY_IS_TRUE(profile.GetCmdLine().compare("foo -b128K -w84 -Zr testfile.dat") == 0); + VERIFY_IS_TRUE(profile.GetEtwEnabled() == false); + VERIFY_IS_TRUE(profile.GetEtwProcess() == false); + VERIFY_IS_TRUE(profile.GetEtwThread() == false); + VERIFY_IS_TRUE(profile.GetEtwImageLoad() == false); + VERIFY_IS_TRUE(profile.GetEtwDiskIO() == false); + VERIFY_IS_TRUE(profile.GetEtwMemoryPageFaults() == false); + VERIFY_IS_TRUE(profile.GetEtwMemoryHardFaults() == false); + VERIFY_IS_TRUE(profile.GetEtwNetwork() == false); + VERIFY_IS_TRUE(profile.GetEtwRegistry() == false); + VERIFY_IS_TRUE(profile.GetEtwUsePagedMemory() == false); + VERIFY_IS_TRUE(profile.GetEtwUsePerfTimer() == false); + VERIFY_IS_TRUE(profile.GetEtwUseSystemTimer() == false); + VERIFY_IS_TRUE(profile.GetEtwUseCyclesCounter() == false); + + vector vSpans(profile.GetTimeSpans()); + VERIFY_ARE_EQUAL(vSpans.size(), (size_t)1); + VERIFY_ARE_EQUAL(vSpans[0].GetDuration(), (UINT32)10); + VERIFY_ARE_EQUAL(vSpans[0].GetWarmup(), (UINT32)5); + VERIFY_ARE_EQUAL(vSpans[0].GetCooldown(), (UINT32)0); + VERIFY_ARE_EQUAL(vSpans[0].GetRandSeed(), (UINT32)0); + VERIFY_ARE_EQUAL(vSpans[0].GetThreadCount(), (DWORD)0); + VERIFY_ARE_EQUAL(vSpans[0].GetRequestCount(), (DWORD)0); + VERIFY_IS_TRUE(vSpans[0].GetDisableAffinity() == false); + VERIFY_IS_TRUE(vSpans[0].GetCompletionRoutines() == false); + VERIFY_IS_TRUE(vSpans[0].GetMeasureLatency() == false); + VERIFY_IS_TRUE(vSpans[0].GetRandomWriteData() == true); + + const auto& vAffinity(vSpans[0].GetAffinityAssignments()); + VERIFY_ARE_EQUAL(vAffinity.size(), (size_t)0); + + vector vTargets(vSpans[0].GetTargets()); + VERIFY_ARE_EQUAL(vTargets.size(), (size_t)1); + Target t(vTargets[0]); + + VERIFY_IS_TRUE(t.GetPath().compare("testfile.dat") == 0); + VERIFY_ARE_EQUAL(t.GetBlockSizeInBytes(), (DWORD)(128 * 1024)); + VERIFY_ARE_EQUAL(t.GetRequestCount(), (DWORD)2); + VERIFY_IS_TRUE(t.GetRandomRatio() == 0); + VERIFY_IS_TRUE(t.GetUseInterlockedSequential() == false); + VERIFY_ARE_EQUAL(t.GetBlockAlignmentInBytes(), t.GetBlockSizeInBytes()); + VERIFY_ARE_EQUAL(t.GetBaseFileOffsetInBytes(), 0); + VERIFY_IS_TRUE(t.GetUseParallelAsyncIO() == false); + VERIFY_IS_TRUE(t.GetCacheMode() == TargetCacheMode::Cached); + VERIFY_IS_TRUE(t.GetWriteThroughMode() == WriteThroughMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoMode() == MemoryMappedIoMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoFlushMode() == MemoryMappedIoFlushMode::Undefined); + VERIFY_IS_TRUE(t.GetZeroWriteBuffers() == false); + VERIFY_ARE_EQUAL(t.GetThreadsPerFile(), (DWORD)1); + VERIFY_ARE_EQUAL(t.GetThreadStrideInBytes(), 0); + VERIFY_IS_TRUE(t.GetCreateFile() == false); + VERIFY_ARE_EQUAL(t.GetFileSize(), 0); + VERIFY_ARE_EQUAL(t.GetMaxFileSize(), 0); + VERIFY_ARE_EQUAL(t.GetWriteRatio(), (DWORD)84); + VERIFY_IS_TRUE(t.GetUseBurstSize() == false); + VERIFY_ARE_EQUAL(t.GetBurstSize(), (DWORD)0); + VERIFY_ARE_EQUAL(t.GetThinkTime(), (DWORD)0); + VERIFY_IS_TRUE(t.GetEnableThinkTime() == false); + VERIFY_IS_TRUE(t.GetSequentialScanHint() == false); + VERIFY_IS_TRUE(t.GetRandomAccessHint() == false); + VERIFY_IS_TRUE(t.GetTemporaryFileHint() == false); + VERIFY_IS_TRUE(t.GetUseLargePages() == false); + VERIFY_ARE_EQUAL(t.GetThroughputInBytesPerMillisecond(), (DWORD)0); + VERIFY_ARE_EQUAL(t.GetRandomDataWriteBufferSize(), 0); + VERIFY_ARE_EQUAL(t.GetRandomDataWriteBufferSourcePath(), ""); + } + + void CmdLineParserUnitTests::TestGetRandomDataWriteBufferData() + { + CmdLineParser p; + UINT64 cb; + string sPath; + + p._GetRandomDataWriteBufferData("11332", cb, sPath); + VERIFY_ARE_EQUAL(cb, 11332); + VERIFY_IS_TRUE(sPath == ""); + + cb = 0; + sPath = ""; + p._GetRandomDataWriteBufferData("11332,", cb, sPath); + VERIFY_ARE_EQUAL(cb, 11332); + VERIFY_IS_TRUE(sPath == ""); + + cb = 0; + sPath = ""; + p._GetRandomDataWriteBufferData("11332,x:\\foo\\bar", cb, sPath); + VERIFY_ARE_EQUAL(cb, 11332); + VERIFY_IS_TRUE(sPath == "x:\\foo\\bar"); + + cb = 0; + sPath = ""; + p._GetRandomDataWriteBufferData("2M", cb, sPath); + VERIFY_ARE_EQUAL(cb, 2 * 1024 * 1024); + VERIFY_IS_TRUE(sPath == ""); + + cb = 0; + sPath = ""; + p._GetRandomDataWriteBufferData("2M,x:\\foo\\bar", cb, sPath); + VERIFY_ARE_EQUAL(cb, 2 * 1024 * 1024); + VERIFY_IS_TRUE(sPath == "x:\\foo\\bar"); + } + + void CmdLineParserUnitTests::TestParseCmdLineWriteBufferContentRandomNoFilePath() + { + CmdLineParser p; + Profile profile; + struct Synchronization s = {}; + const char *argv[] = { "foo", "-b128K", "-w84", "-Z2M", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == true); + + vector vSpans(profile.GetTimeSpans()); + vector vTargets(vSpans[0].GetTargets()); + VERIFY_ARE_EQUAL(vTargets.size(), (size_t)1); + Target t(vTargets[0]); + + VERIFY_IS_FALSE(t.GetZeroWriteBuffers()); + VERIFY_ARE_EQUAL(t.GetRandomDataWriteBufferSize(), (size_t)(2 * 1024 * 1024)); + VERIFY_IS_TRUE(t.GetRandomDataWriteBufferSourcePath() == ""); + } + + void CmdLineParserUnitTests::TestParseCmdLineWriteBufferContentRandomWithFilePath() + { + CmdLineParser p; + Profile profile; + struct Synchronization s = {}; + const char *argv[] = { "foo", "-b128K", "-w84", "-Z3M,x:\\foo\\bar.baz", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == true); + + vector vSpans(profile.GetTimeSpans()); + vector vTargets(vSpans[0].GetTargets()); + VERIFY_ARE_EQUAL(vTargets.size(), (size_t)1); + Target t(vTargets[0]); + + VERIFY_IS_FALSE(t.GetZeroWriteBuffers()); + VERIFY_ARE_EQUAL(t.GetRandomDataWriteBufferSize(), (size_t)(3 * 1024 * 1024)); + VERIFY_IS_TRUE(t.GetRandomDataWriteBufferSourcePath() == "x:\\foo\\bar.baz"); + } + + void CmdLineParserUnitTests::TestParseCmdLineInterlockedSequential() + { + CmdLineParser p; + Profile profile; + struct Synchronization s = {}; + const char *argv[] = { "foo", "-b128K", "-w84", "-si", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == true); + VERIFY_IS_TRUE(profile.GetVerbose() == false); + VERIFY_IS_TRUE(profile.GetProgress() == 0); + VERIFY_IS_TRUE(profile.GetCmdLine().compare("foo -b128K -w84 -si testfile.dat") == 0); + VERIFY_IS_TRUE(profile.GetEtwEnabled() == false); + VERIFY_IS_TRUE(profile.GetEtwProcess() == false); + VERIFY_IS_TRUE(profile.GetEtwThread() == false); + VERIFY_IS_TRUE(profile.GetEtwImageLoad() == false); + VERIFY_IS_TRUE(profile.GetEtwDiskIO() == false); + VERIFY_IS_TRUE(profile.GetEtwMemoryPageFaults() == false); + VERIFY_IS_TRUE(profile.GetEtwMemoryHardFaults() == false); + VERIFY_IS_TRUE(profile.GetEtwNetwork() == false); + VERIFY_IS_TRUE(profile.GetEtwRegistry() == false); + VERIFY_IS_TRUE(profile.GetEtwUsePagedMemory() == false); + VERIFY_IS_TRUE(profile.GetEtwUsePerfTimer() == false); + VERIFY_IS_TRUE(profile.GetEtwUseSystemTimer() == false); + VERIFY_IS_TRUE(profile.GetEtwUseCyclesCounter() == false); + + vector vSpans(profile.GetTimeSpans()); + VERIFY_ARE_EQUAL(vSpans.size(), (size_t)1); + VERIFY_ARE_EQUAL(vSpans[0].GetDuration(), (UINT32)10); + VERIFY_ARE_EQUAL(vSpans[0].GetWarmup(), (UINT32)5); + VERIFY_ARE_EQUAL(vSpans[0].GetCooldown(), (UINT32)0); + VERIFY_ARE_EQUAL(vSpans[0].GetRandSeed(), (UINT32)0); + VERIFY_ARE_EQUAL(vSpans[0].GetThreadCount(), (DWORD)0); + VERIFY_ARE_EQUAL(vSpans[0].GetRequestCount(), (DWORD)0); + VERIFY_IS_TRUE(vSpans[0].GetDisableAffinity() == false); + VERIFY_IS_TRUE(vSpans[0].GetCompletionRoutines() == false); + VERIFY_IS_TRUE(vSpans[0].GetMeasureLatency() == false); + VERIFY_IS_TRUE(vSpans[0].GetRandomWriteData() == false); + + const auto& vAffinity(vSpans[0].GetAffinityAssignments()); + VERIFY_ARE_EQUAL(vAffinity.size(), (size_t)0); + + vector vTargets(vSpans[0].GetTargets()); + VERIFY_ARE_EQUAL(vTargets.size(), (size_t)1); + Target t(vTargets[0]); + + VERIFY_IS_TRUE(t.GetPath().compare("testfile.dat") == 0); + VERIFY_ARE_EQUAL(t.GetBlockSizeInBytes(), (DWORD)(128 * 1024)); + VERIFY_ARE_EQUAL(t.GetRequestCount(), (DWORD)2); + VERIFY_IS_TRUE(t.GetRandomRatio() == 0); + VERIFY_IS_TRUE(t.GetUseInterlockedSequential() == true); + VERIFY_ARE_EQUAL(t.GetBlockAlignmentInBytes(), t.GetBlockSizeInBytes()); + VERIFY_ARE_EQUAL(t.GetBaseFileOffsetInBytes(), 0); + VERIFY_IS_TRUE(t.GetUseParallelAsyncIO() == false); + VERIFY_IS_TRUE(t.GetCacheMode() == TargetCacheMode::Cached); + VERIFY_IS_TRUE(t.GetWriteThroughMode() == WriteThroughMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoMode() == MemoryMappedIoMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoFlushMode() == MemoryMappedIoFlushMode::Undefined); + VERIFY_IS_TRUE(t.GetZeroWriteBuffers() == false); + VERIFY_ARE_EQUAL(t.GetThreadsPerFile(), (DWORD)1); + VERIFY_ARE_EQUAL(t.GetThreadStrideInBytes(), 0); + VERIFY_IS_TRUE(t.GetCreateFile() == false); + VERIFY_ARE_EQUAL(t.GetFileSize(), 0); + VERIFY_ARE_EQUAL(t.GetMaxFileSize(), 0); + VERIFY_ARE_EQUAL(t.GetWriteRatio(), (DWORD)84); + VERIFY_IS_TRUE(t.GetUseBurstSize() == false); + VERIFY_ARE_EQUAL(t.GetBurstSize(), (DWORD)0); + VERIFY_ARE_EQUAL(t.GetThinkTime(), (DWORD)0); + VERIFY_IS_TRUE(t.GetEnableThinkTime() == false); + VERIFY_IS_TRUE(t.GetSequentialScanHint() == false); + VERIFY_IS_TRUE(t.GetRandomAccessHint() == false); + VERIFY_IS_TRUE(t.GetTemporaryFileHint() == false); + VERIFY_IS_TRUE(t.GetUseLargePages() == false); + VERIFY_ARE_EQUAL(t.GetThroughputInBytesPerMillisecond(), (DWORD)0); + } + + void CmdLineParserUnitTests::TestParseCmdLineInterlockedSequentialWithStride() + { + CmdLineParser p; + Profile profile; + struct Synchronization s = {}; + const char *argv[] = { "foo", "-b128K", "-w84", "-si567K", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == true); + VERIFY_IS_TRUE(profile.GetVerbose() == false); + VERIFY_IS_TRUE(profile.GetProgress() == 0); + VERIFY_IS_TRUE(profile.GetCmdLine().compare("foo -b128K -w84 -si567K testfile.dat") == 0); + VERIFY_IS_TRUE(profile.GetEtwEnabled() == false); + VERIFY_IS_TRUE(profile.GetEtwProcess() == false); + VERIFY_IS_TRUE(profile.GetEtwThread() == false); + VERIFY_IS_TRUE(profile.GetEtwImageLoad() == false); + VERIFY_IS_TRUE(profile.GetEtwDiskIO() == false); + VERIFY_IS_TRUE(profile.GetEtwMemoryPageFaults() == false); + VERIFY_IS_TRUE(profile.GetEtwMemoryHardFaults() == false); + VERIFY_IS_TRUE(profile.GetEtwNetwork() == false); + VERIFY_IS_TRUE(profile.GetEtwRegistry() == false); + VERIFY_IS_TRUE(profile.GetEtwUsePagedMemory() == false); + VERIFY_IS_TRUE(profile.GetEtwUsePerfTimer() == false); + VERIFY_IS_TRUE(profile.GetEtwUseSystemTimer() == false); + VERIFY_IS_TRUE(profile.GetEtwUseCyclesCounter() == false); + + vector vSpans(profile.GetTimeSpans()); + VERIFY_ARE_EQUAL(vSpans.size(), (size_t)1); + VERIFY_ARE_EQUAL(vSpans[0].GetDuration(), (UINT32)10); + VERIFY_ARE_EQUAL(vSpans[0].GetWarmup(), (UINT32)5); + VERIFY_ARE_EQUAL(vSpans[0].GetCooldown(), (UINT32)0); + VERIFY_ARE_EQUAL(vSpans[0].GetRandSeed(), (UINT32)0); + VERIFY_ARE_EQUAL(vSpans[0].GetThreadCount(), (DWORD)0); + VERIFY_ARE_EQUAL(vSpans[0].GetRequestCount(), (DWORD)0); + VERIFY_IS_TRUE(vSpans[0].GetDisableAffinity() == false); + VERIFY_IS_TRUE(vSpans[0].GetCompletionRoutines() == false); + VERIFY_IS_TRUE(vSpans[0].GetMeasureLatency() == false); + VERIFY_IS_TRUE(vSpans[0].GetRandomWriteData() == false); + + const auto& vAffinity(vSpans[0].GetAffinityAssignments()); + VERIFY_ARE_EQUAL(vAffinity.size(), (size_t)0); + + vector vTargets(vSpans[0].GetTargets()); + VERIFY_ARE_EQUAL(vTargets.size(), (size_t)1); + Target t(vTargets[0]); + + VERIFY_IS_TRUE(t.GetPath().compare("testfile.dat") == 0); + VERIFY_ARE_EQUAL(t.GetBlockSizeInBytes(), (DWORD)(128 * 1024)); + VERIFY_ARE_EQUAL(t.GetRequestCount(), (DWORD)2); + VERIFY_IS_TRUE(t.GetRandomRatio() == 0); + VERIFY_IS_TRUE(t.GetUseInterlockedSequential() == true); + VERIFY_ARE_EQUAL(t.GetBlockAlignmentInBytes(), (567 * 1024)); + VERIFY_ARE_EQUAL(t.GetBaseFileOffsetInBytes(), 0); + VERIFY_IS_TRUE(t.GetUseParallelAsyncIO() == false); + VERIFY_IS_TRUE(t.GetCacheMode() == TargetCacheMode::Cached); + VERIFY_IS_TRUE(t.GetWriteThroughMode() == WriteThroughMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoMode() == MemoryMappedIoMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoFlushMode() == MemoryMappedIoFlushMode::Undefined); + VERIFY_IS_TRUE(t.GetZeroWriteBuffers() == false); + VERIFY_ARE_EQUAL(t.GetThreadsPerFile(), (DWORD)1); + VERIFY_ARE_EQUAL(t.GetThreadStrideInBytes(), 0); + VERIFY_IS_TRUE(t.GetCreateFile() == false); + VERIFY_ARE_EQUAL(t.GetFileSize(), 0); + VERIFY_ARE_EQUAL(t.GetMaxFileSize(), 0); + VERIFY_ARE_EQUAL(t.GetWriteRatio(), (DWORD)84); + VERIFY_IS_TRUE(t.GetUseBurstSize() == false); + VERIFY_ARE_EQUAL(t.GetBurstSize(), (DWORD)0); + VERIFY_ARE_EQUAL(t.GetThinkTime(), (DWORD)0); + VERIFY_IS_TRUE(t.GetEnableThinkTime() == false); + VERIFY_IS_TRUE(t.GetSequentialScanHint() == false); + VERIFY_IS_TRUE(t.GetRandomAccessHint() == false); + VERIFY_IS_TRUE(t.GetTemporaryFileHint() == false); + VERIFY_IS_TRUE(t.GetUseLargePages() == false); + VERIFY_ARE_EQUAL(t.GetThroughputInBytesPerMillisecond(), (DWORD)0); + } + + void CmdLineParserUnitTests::TestParseCmdLineTotalThreadCountAndTotalRequestCount() + { + CmdLineParser p; + Profile profile; + struct Synchronization s = {}; + const char *argv[] = { "foo", "-b128K", "-w84", "-F23", "-O8", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == true); + VERIFY_IS_TRUE(profile.GetVerbose() == false); + VERIFY_IS_TRUE(profile.GetProgress() == 0); + VERIFY_IS_TRUE(profile.GetCmdLine().compare("foo -b128K -w84 -F23 -O8 testfile.dat") == 0); + VERIFY_IS_TRUE(profile.GetEtwEnabled() == false); + VERIFY_IS_TRUE(profile.GetEtwProcess() == false); + VERIFY_IS_TRUE(profile.GetEtwThread() == false); + VERIFY_IS_TRUE(profile.GetEtwImageLoad() == false); + VERIFY_IS_TRUE(profile.GetEtwDiskIO() == false); + VERIFY_IS_TRUE(profile.GetEtwMemoryPageFaults() == false); + VERIFY_IS_TRUE(profile.GetEtwMemoryHardFaults() == false); + VERIFY_IS_TRUE(profile.GetEtwNetwork() == false); + VERIFY_IS_TRUE(profile.GetEtwRegistry() == false); + VERIFY_IS_TRUE(profile.GetEtwUsePagedMemory() == false); + VERIFY_IS_TRUE(profile.GetEtwUsePerfTimer() == false); + VERIFY_IS_TRUE(profile.GetEtwUseSystemTimer() == false); + VERIFY_IS_TRUE(profile.GetEtwUseCyclesCounter() == false); + + vector vSpans(profile.GetTimeSpans()); + VERIFY_ARE_EQUAL(vSpans.size(), (size_t)1); + VERIFY_ARE_EQUAL(vSpans[0].GetDuration(), (UINT32)10); + VERIFY_ARE_EQUAL(vSpans[0].GetWarmup(), (UINT32)5); + VERIFY_ARE_EQUAL(vSpans[0].GetCooldown(), (UINT32)0); + VERIFY_ARE_EQUAL(vSpans[0].GetRandSeed(), (UINT32)0); + VERIFY_ARE_EQUAL(vSpans[0].GetThreadCount(), (DWORD)23); + VERIFY_ARE_EQUAL(vSpans[0].GetRequestCount(), (DWORD)8); + VERIFY_IS_TRUE(vSpans[0].GetDisableAffinity() == false); + VERIFY_IS_TRUE(vSpans[0].GetCompletionRoutines() == false); + VERIFY_IS_TRUE(vSpans[0].GetMeasureLatency() == false); + VERIFY_IS_TRUE(vSpans[0].GetRandomWriteData() == false); + + const auto& vAffinity(vSpans[0].GetAffinityAssignments()); + VERIFY_ARE_EQUAL(vAffinity.size(), (size_t)0); + + vector vTargets(vSpans[0].GetTargets()); + VERIFY_ARE_EQUAL(vTargets.size(), (size_t)1); + Target t(vTargets[0]); + + VERIFY_IS_TRUE(t.GetPath().compare("testfile.dat") == 0); + VERIFY_ARE_EQUAL(t.GetBlockSizeInBytes(), (DWORD)(128 * 1024)); + VERIFY_ARE_EQUAL(t.GetRequestCount(), (DWORD)2); + VERIFY_IS_TRUE(t.GetRandomRatio() == 0); + VERIFY_IS_TRUE(t.GetUseInterlockedSequential() == false); + VERIFY_ARE_EQUAL(t.GetBlockAlignmentInBytes(), t.GetBlockSizeInBytes()); + VERIFY_ARE_EQUAL(t.GetBaseFileOffsetInBytes(), 0); + VERIFY_IS_TRUE(t.GetUseParallelAsyncIO() == false); + VERIFY_IS_TRUE(t.GetCacheMode() == TargetCacheMode::Cached); + VERIFY_IS_TRUE(t.GetWriteThroughMode() == WriteThroughMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoMode() == MemoryMappedIoMode::Off); + VERIFY_IS_TRUE(t.GetMemoryMappedIoFlushMode() == MemoryMappedIoFlushMode::Undefined); + VERIFY_IS_TRUE(t.GetZeroWriteBuffers() == false); + VERIFY_ARE_EQUAL(t.GetThreadsPerFile(), (DWORD)1); + VERIFY_ARE_EQUAL(t.GetThreadStrideInBytes(), 0); + VERIFY_IS_TRUE(t.GetCreateFile() == false); + VERIFY_ARE_EQUAL(t.GetFileSize(), 0); + VERIFY_ARE_EQUAL(t.GetMaxFileSize(), 0); + VERIFY_ARE_EQUAL(t.GetWriteRatio(), (DWORD)84); + VERIFY_IS_TRUE(t.GetUseBurstSize() == false); + VERIFY_ARE_EQUAL(t.GetBurstSize(), (DWORD)0); + VERIFY_ARE_EQUAL(t.GetThinkTime(), (DWORD)0); + VERIFY_IS_TRUE(t.GetEnableThinkTime() == false); + VERIFY_IS_TRUE(t.GetSequentialScanHint() == false); + VERIFY_IS_TRUE(t.GetRandomAccessHint() == false); + VERIFY_IS_TRUE(t.GetTemporaryFileHint() == false); + VERIFY_IS_TRUE(t.GetUseLargePages() == false); + VERIFY_ARE_EQUAL(t.GetThroughputInBytesPerMillisecond(), (DWORD)0); + } + + void CmdLineParserUnitTests::TestParseCmdLineThroughput() + { + CmdLineParser p; + struct Synchronization s = {}; + + { + Profile profile; + const char *argv[] = { "foo", "-b128K", "-g10i", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == true); + VERIFY_ARE_EQUAL(profile.GetTimeSpans()[0].GetTargets()[0].GetThroughputInBytesPerMillisecond(), (DWORD)((128*1024*10)/1000)); + VERIFY_IS_TRUE(profile.GetTimeSpans()[0].GetTargets()[0].GetThroughputIOPS() == 10); + } + { + Profile profile; + const char *argv[] = { "foo", "-b128K", "-g1024", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == true); + VERIFY_IS_TRUE(profile.GetTimeSpans()[0].GetTargets()[0].GetThroughputInBytesPerMillisecond() == 1024); + VERIFY_IS_TRUE(profile.GetTimeSpans()[0].GetTargets()[0].GetThroughputIOPS() == 0); + } + + // Invalid cases: valid unit on wrong side, no digits, zeroes, bad unit + + { + Profile profile; + const char *argv[] = { "foo", "-b128K", "-gi100", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == false); + } + { + Profile profile; + const char *argv[] = { "foo", "-b128K", "-g0", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == false); + } + { + Profile profile; + const char *argv[] = { "foo", "-b128K", "-g0i", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == false); + } + { + Profile profile; + const char *argv[] = { "foo", "-b128K", "-g", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == false); + } + { + Profile profile; + const char *argv[] = { "foo", "-b128K", "-gi", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == false); + } + { + Profile profile; + const char *argv[] = { "foo", "-b128K", "-g100x", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == false); + } + } + + void CmdLineParserUnitTests::TestParseCmdLineRandomSequentialMixed() + { + // Coverage for -rs and combinations of conflicts with -r/-s/-rs + + CmdLineParser p; + struct Synchronization s = {}; + + // + // -rs cases + // + + // Isolated + + { + Profile profile; + const char *argv[] = { "foo", "-rs50", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == true); + VERIFY_ARE_EQUAL(profile.GetTimeSpans()[0].GetTargets()[0].GetRandomRatio(), (UINT32) 50); + } + + // Combined with -r, in any order + + { + Profile profile; + const char *argv[] = { "foo", "-rs50", "-r8k", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == true); + VERIFY_ARE_EQUAL(profile.GetTimeSpans()[0].GetTargets()[0].GetRandomRatio(), (UINT32) 50); + VERIFY_ARE_EQUAL(profile.GetTimeSpans()[0].GetTargets()[0].GetBlockAlignmentInBytes(), 8*1024); + } + { + Profile profile; + const char *argv[] = { "foo", "-r8k", "-rs50", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == true); + VERIFY_ARE_EQUAL(profile.GetTimeSpans()[0].GetTargets()[0].GetRandomRatio(), (UINT32) 50); + VERIFY_ARE_EQUAL(profile.GetTimeSpans()[0].GetTargets()[0].GetBlockAlignmentInBytes(), 8*1024); + } + + // Combined with -r, in any order (don't care block size) + // While the -r in this order has no effect and could be flagged as an error, we don't currently parse to this level + + { + Profile profile; + const char *argv[] = { "foo", "-rs50", "-r", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == true); + VERIFY_ARE_EQUAL(profile.GetTimeSpans()[0].GetTargets()[0].GetRandomRatio(), (UINT32) 50); + } + { + Profile profile; + const char *argv[] = { "foo", "-r", "-rs50", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == true); + VERIFY_ARE_EQUAL(profile.GetTimeSpans()[0].GetTargets()[0].GetRandomRatio(), (UINT32) 50); + } + + // Now for conflict cases + + // Combined with -s in any order + + { + Profile profile; + const char *argv[] = { "foo", "-rs50", "-s8k", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == false); + } + { + Profile profile; + const char *argv[] = { "foo", "-s8k", "-rs50", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == false); + } + + // Combined with -s in any order + + { + Profile profile; + const char *argv[] = { "foo", "-rs50", "-s", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == false); + } + { + Profile profile; + const char *argv[] = { "foo", "-s", "-rs50", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == false); + } + + // -r/-s conflict + + { + Profile profile; + const char *argv[] = { "foo", "-r", "-s", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == false); + } + { + Profile profile; + const char *argv[] = { "foo", "-s", "-r", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == false); + } + + // 3-way conflict + // If it were more important, we could/should enumerate the orderings + { + Profile profile; + const char *argv[] = { "foo", "-rs50", "-s", "-r", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == false); + } + { + Profile profile; + const char *argv[] = { "foo", "-s", "-rs50", "-r", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == false); + } + { + Profile profile; + const char *argv[] = { "foo", "-s", "-r", "-rs50", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == false); + } + + // 3-way with -s + { + Profile profile; + const char *argv[] = { "foo", "-rs50", "-s8k", "-r", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == false); + } + { + Profile profile; + const char *argv[] = { "foo", "-s8k", "-rs50", "-r", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == false); + } + { + Profile profile; + const char *argv[] = { "foo", "-s8k", "-r", "-rs50", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == false); + } + + // 3-way with -r + { + Profile profile; + const char *argv[] = { "foo", "-rs50", "-s", "-r8k", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == false); + } + { + Profile profile; + const char *argv[] = { "foo", "-s", "-rs50", "-r8k", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == false); + } + { + Profile profile; + const char *argv[] = { "foo", "-s", "-r8k", "-rs50", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == false); + } + + // Duplicated specs + { + Profile profile; + const char *argv[] = { "foo", "-s", "-s8k", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == false); + } + { + Profile profile; + const char *argv[] = { "foo", "-s8k", "-s", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == false); + } + { + Profile profile; + const char *argv[] = { "foo", "-s", "-s", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == false); + } + { + Profile profile; + const char *argv[] = { "foo", "-s8k", "-s8k", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == false); + } + { + Profile profile; + const char *argv[] = { "foo", "-r", "-r8k", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == false); + } + { + Profile profile; + const char *argv[] = { "foo", "-r8k", "-r", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == false); + } + { + Profile profile; + const char *argv[] = { "foo", "-r", "-r", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == false); + } + { + Profile profile; + const char *argv[] = { "foo", "-r8k", "-r8k", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == false); + } + { + Profile profile; + const char *argv[] = { "foo", "-r8k", "-r4k", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == false); + } + + // Bounds checks: -rs100 is OK w/wo random alignment and -rs0 is rejected + { + Profile profile; + const char *argv[] = { "foo", "-rs100", "-r", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == true); + } + { + Profile profile; + const char *argv[] = { "foo", "-rs100", "-r8k", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == true); + } + { + Profile profile; + const char *argv[] = { "foo", "-r", "-rs100", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == true); + } + { + Profile profile; + const char *argv[] = { "foo", "-r8k", "-rs100", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == true); + } + { + Profile profile; + const char *argv[] = { "foo", "-rs0", "-r", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == false); + } + { + Profile profile; + const char *argv[] = { "foo", "-rs0", "-r8k", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == false); + } + { + Profile profile; + const char *argv[] = { "foo", "-rs0", "-s", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == false); + } + { + Profile profile; + const char *argv[] = { "foo", "-rs0", "-s8k", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s) == false); + } + } + + void CmdLineParserUnitTests::TestParseCmdLineTargetDistribution() + { + // coverage for parsing of cmdline target distributions (percent/absolute) + + CmdLineParser p; + struct Synchronization s = {}; + + // + // Positive cases - these match the ResultParser UTs + // + + { + Profile profile; + const char *argv[] = { "foo", "-rdpct10/10:10/10:0/10", "-r", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s)); + + auto t = profile.GetTimeSpans()[0].GetTargets()[0]; // manage object lifetime so target is not destroyed + auto dt = t.GetDistributionType(); + auto& v = t.GetDistributionRange(); + + VERIFY_ARE_EQUAL(dt, DistributionType::Percent); + VERIFY_ARE_EQUAL(v[0]._src, (UINT64) 0); + VERIFY_ARE_EQUAL(v[0]._span, (UINT64) 10); + VERIFY_ARE_EQUAL(v[0]._dst.first, (UINT64) 0); + VERIFY_ARE_EQUAL(v[0]._dst.second, (UINT64) 10); + VERIFY_ARE_EQUAL(v[1]._src, (UINT64) 10); /// + VERIFY_ARE_EQUAL(v[1]._span, (UINT64) 10); + VERIFY_ARE_EQUAL(v[1]._dst.first, (UINT64) 10); + VERIFY_ARE_EQUAL(v[1]._dst.second, (UINT64) 10); + VERIFY_ARE_EQUAL(v[2]._src, (UINT64) 20); /// + VERIFY_ARE_EQUAL(v[2]._span, (UINT64) 0); + VERIFY_ARE_EQUAL(v[2]._dst.first, (UINT64) 20); + VERIFY_ARE_EQUAL(v[2]._dst.second, (UINT64) 10); + VERIFY_ARE_EQUAL(v[3]._src, (UINT64) 20); /// + VERIFY_ARE_EQUAL(v[3]._span, (UINT64) 80); + VERIFY_ARE_EQUAL(v[3]._dst.first, (UINT64) 30); + VERIFY_ARE_EQUAL(v[3]._dst.second, (UINT64) 70); + } + { + Profile profile; + const char *argv[] = { "foo", "-rdabs10/1G:10/1G:0/100G", "-r", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s)); + + auto t = profile.GetTimeSpans()[0].GetTargets()[0]; + auto dt = t.GetDistributionType(); + auto& v = t.GetDistributionRange(); + + VERIFY_ARE_EQUAL(dt, DistributionType::Absolute); + VERIFY_ARE_EQUAL(v[0]._src, (UINT64) 0); + VERIFY_ARE_EQUAL(v[0]._span, (UINT64) 10); + VERIFY_ARE_EQUAL(v[0]._dst.first, (UINT64) 0); + VERIFY_ARE_EQUAL(v[0]._dst.second, (UINT64) 1*GB); + VERIFY_ARE_EQUAL(v[1]._src, (UINT64) 10); /// + VERIFY_ARE_EQUAL(v[1]._span, (UINT64) 10); + VERIFY_ARE_EQUAL(v[1]._dst.first, (UINT64) 1*GB); + VERIFY_ARE_EQUAL(v[1]._dst.second, (UINT64) 1*GB); + VERIFY_ARE_EQUAL(v[2]._src, (UINT64) 20); /// + VERIFY_ARE_EQUAL(v[2]._span, (UINT64) 0); + VERIFY_ARE_EQUAL(v[2]._dst.first, (UINT64) 2*GB); + VERIFY_ARE_EQUAL(v[2]._dst.second, (UINT64) 100*GB); + VERIFY_ARE_EQUAL(v[3]._src, (UINT64) 20); /// + VERIFY_ARE_EQUAL(v[3]._span, (UINT64) 80); + VERIFY_ARE_EQUAL(v[3]._dst.first, (UINT64) 102*GB); + VERIFY_ARE_EQUAL(v[3]._dst.second, (UINT64) 0); + } + + // valid with mixed load + { + Profile profile; + const char *argv[] = { "foo", "-rdpct90/10", "-rs50", "-r8k", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s)); + } + + // + // Negative cases + // + + // not valid with sequential load + { + Profile profile; + const char *argv[] = { "foo", "-rdpct90/10", "-s", "testfile.dat" }; + VERIFY_IS_FALSE(p.ParseCmdLine(_countof(argv), argv, &profile, &s)); + } + { + Profile profile; + const char *argv[] = { "foo", "-rdpct90/10", "testfile.dat" }; + VERIFY_IS_FALSE(p.ParseCmdLine(_countof(argv), argv, &profile, &s)); + } + + // no/invalid distribution + { + Profile profile; + const char *argv[] = { "foo", "-rd", "-r", "testfile.dat" }; + VERIFY_IS_FALSE(p.ParseCmdLine(_countof(argv), argv, &profile, &s)); + } + { + Profile profile; + const char *argv[] = { "foo", "-rdfoo", "-r", "testfile.dat" }; + VERIFY_IS_FALSE(p.ParseCmdLine(_countof(argv), argv, &profile, &s)); + } + { + Profile profile; + const char *argv[] = { "foo", "-rdfoo10/1G:10/1G:0/100G", "-r", "testfile.dat" }; + VERIFY_IS_FALSE(p.ParseCmdLine(_countof(argv), argv, &profile, &s)); + } + + // bad ints in first pos + { + Profile profile; + const char *argv[] = { "foo", "-rdpctBAD", "-r", "testfile.dat" }; + VERIFY_IS_FALSE(p.ParseCmdLine(_countof(argv), argv, &profile, &s)); + } + { + Profile profile; + const char *argv[] = { "foo", "-rdabsBAD", "-r", "testfile.dat" }; + VERIFY_IS_FALSE(p.ParseCmdLine(_countof(argv), argv, &profile, &s)); + } + + // good int, no sep + { + Profile profile; + const char *argv[] = { "foo", "-rdpct10", "-r", "testfile.dat" }; + VERIFY_IS_FALSE(p.ParseCmdLine(_countof(argv), argv, &profile, &s)); + } + { + Profile profile; + const char *argv[] = { "foo", "-rdabs10", "-r", "testfile.dat" }; + VERIFY_IS_FALSE(p.ParseCmdLine(_countof(argv), argv, &profile, &s)); + } + + // good int, bad sep + { + Profile profile; + const char *argv[] = { "foo", "-rdpct10[", "-r", "testfile.dat" }; + VERIFY_IS_FALSE(p.ParseCmdLine(_countof(argv), argv, &profile, &s)); + } + { + Profile profile; + const char *argv[] = { "foo", "-rdabs10[", "-r", "testfile.dat" }; + VERIFY_IS_FALSE(p.ParseCmdLine(_countof(argv), argv, &profile, &s)); + } + + // good int, good sep, no int + { + Profile profile; + const char *argv[] = { "foo", "-rdpct10/", "-r", "testfile.dat" }; + VERIFY_IS_FALSE(p.ParseCmdLine(_countof(argv), argv, &profile, &s)); + } + { + Profile profile; + const char *argv[] = { "foo", "-rdabs10/", "-r", "testfile.dat" }; + VERIFY_IS_FALSE(p.ParseCmdLine(_countof(argv), argv, &profile, &s)); + } + + // good int, good sep, bad int + { + Profile profile; + const char *argv[] = { "foo", "-rdpct10/BAD", "-r", "testfile.dat" }; + VERIFY_IS_FALSE(p.ParseCmdLine(_countof(argv), argv, &profile, &s)); + } + { + Profile profile; + const char *argv[] = { "foo", "-rdabs10/BAD", "-r", "testfile.dat" }; + VERIFY_IS_FALSE(p.ParseCmdLine(_countof(argv), argv, &profile, &s)); + } + + // good int, good sep, good int, bad sep + { + Profile profile; + const char *argv[] = { "foo", "-rdpct10/10[", "-r", "testfile.dat" }; + VERIFY_IS_FALSE(p.ParseCmdLine(_countof(argv), argv, &profile, &s)); + } + { + Profile profile; + const char *argv[] = { "foo", "-rdabs10/10g[", "-r", "testfile.dat" }; // detail - abs range > blocksize in order to be OK + VERIFY_IS_FALSE(p.ParseCmdLine(_countof(argv), argv, &profile, &s)); + } + + // good int, good sep, good int, good sep, no int + { + Profile profile; + const char *argv[] = { "foo", "-rdpct10/10:", "-r", "testfile.dat" }; + VERIFY_IS_FALSE(p.ParseCmdLine(_countof(argv), argv, &profile, &s)); + } + { + Profile profile; + const char *argv[] = { "foo", "-rdabs10/10g:", "-r", "testfile.dat" }; // detail - abs range > blocksize in order to be OK + VERIFY_IS_FALSE(p.ParseCmdLine(_countof(argv), argv, &profile, &s)); + } + + // good int, good sep, good int, good sep, bad int + { + Profile profile; + const char *argv[] = { "foo", "-rdpct10/10:BAD", "-r", "testfile.dat" }; + VERIFY_IS_FALSE(p.ParseCmdLine(_countof(argv), argv, &profile, &s)); + } + { + Profile profile; + const char *argv[] = { "foo", "-rdabs10/10g:BAD", "-r", "testfile.dat" }; // detail - abs range > blocksize in order to be OK + VERIFY_IS_FALSE(p.ParseCmdLine(_countof(argv), argv, &profile, &s)); + } + + // + // Negative cases for IO% + // + + // a single pct cannot be > 100, and cannot sum > 100 + { + Profile profile; + const char *argv[] = { "foo", "-rdpct101/10", "-r", "testfile.dat" }; + VERIFY_IS_FALSE(p.ParseCmdLine(_countof(argv), argv, &profile, &s)); + } + { + Profile profile; + const char *argv[] = { "foo", "-rdpct60/10:60/10", "-r", "testfile.dat" }; + VERIFY_IS_FALSE(p.ParseCmdLine(_countof(argv), argv, &profile, &s)); + } + { + Profile profile; + const char *argv[] = { "foo", "-rdabs101/10g", "-r", "testfile.dat" }; + VERIFY_IS_FALSE(p.ParseCmdLine(_countof(argv), argv, &profile, &s)); + } + { + Profile profile; + const char *argv[] = { "foo", "-rdabs60/10g:60/10g", "-r", "testfile.dat" }; + VERIFY_IS_FALSE(p.ParseCmdLine(_countof(argv), argv, &profile, &s)); + } + + // target% cannot be covered before IO% is covered + { + Profile profile; + const char *argv[] = { "foo", "-rdpct10/50:10/50", "-r", "testfile.dat" }; + VERIFY_IS_FALSE(p.ParseCmdLine(_countof(argv), argv, &profile, &s)); + } + + // target% cannot be > 100 + { + Profile profile; + const char *argv[] = { "foo", "-rdpct10/50:10/60", "-r", "testfile.dat" }; + VERIFY_IS_FALSE(p.ParseCmdLine(_countof(argv), argv, &profile, &s)); + } + + // + // Negative cases for Target%/Size + // + + // a target%/size cannot be zero (first/second positions) + { + Profile profile; + const char *argv[] = { "foo", "-rdpct10/0", "-r", "testfile.dat" }; + VERIFY_IS_FALSE(p.ParseCmdLine(_countof(argv), argv, &profile, &s)); + } + { + Profile profile; + const char *argv[] = { "foo", "-rdpct60/10:10/0", "-r", "testfile.dat" }; + VERIFY_IS_FALSE(p.ParseCmdLine(_countof(argv), argv, &profile, &s)); + } + { + Profile profile; + const char *argv[] = { "foo", "-rdabs10/0", "-r", "testfile.dat" }; + VERIFY_IS_FALSE(p.ParseCmdLine(_countof(argv), argv, &profile, &s)); + } + { + Profile profile; + const char *argv[] = { "foo", "-rdabs60/10g:10/0", "-r", "testfile.dat" }; + VERIFY_IS_FALSE(p.ParseCmdLine(_countof(argv), argv, &profile, &s)); + } + + // + // Negative cases for abs + // + + // abs range must be >= blocksize + { + Profile profile; + const char *argv[] = { "foo", "-rdabs10/10", "-r", "testfile.dat" }; + VERIFY_IS_FALSE(p.ParseCmdLine(_countof(argv), argv, &profile, &s)); + } + } + + void CmdLineParserUnitTests::TestParseCmdLineResultOutput() + { + // Cases for combinations of -R[p][text|xml] + + CmdLineParser p; + struct Synchronization s = {}; + + char *aType[] = { "text", "xml" }; + vector vType(aType, &aType[0] + _countof(aType)); + char *aProfile[] = { "-R", "-Rp" }; + vector vProfile(aProfile, &aProfile[0] + _countof(aProfile)); + + // combinations of p/text|xml OK + for (auto ty : vType) + { + for (auto pr : vProfile) + { + string str = pr; + str += ty; + + Profile profile; + const char *argv[] = { "foo", str.c_str(), "testfile.dat" }; + fprintf(stderr, "case: %s\n", str.c_str()); + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s)); + + if (pr[2] == 'p') + { + VERIFY_IS_TRUE(profile.GetProfileOnly()); + } + else + { + VERIFY_IS_FALSE(profile.GetProfileOnly()); + } + + if (*ty == 't') + { + VERIFY_ARE_EQUAL(ResultsFormat::Text, profile.GetResultsFormat()); + } + else + { + VERIFY_ARE_EQUAL(ResultsFormat::Xml, profile.GetResultsFormat()); + } + } + } + } + + void CmdLineParserUnitTests::TestParseCmdLineTargetPosition() + { + // coverage for positioning of targets and parameters + + CmdLineParser p; + struct Synchronization s = {}; + + // in order - this obviously duplicates all the other normal cases but, to + // document it in place against the negative cases, repeat. + { + Profile profile; + const char *argv[] = { "foo", "-r", "testfile.dat" }; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s)); + } + { + Profile profile; + const char *argv[] = { "foo", "-r", "testfile.dat" , "testfile2.dat"}; + VERIFY_IS_TRUE(p.ParseCmdLine(_countof(argv), argv, &profile, &s)); + } + + // out of order - parameter follows one or more targets + { + Profile profile; + const char *argv[] = { "foo", "testfile.dat" , "-r"}; + VERIFY_IS_FALSE(p.ParseCmdLine(_countof(argv), argv, &profile, &s)); + } + { + Profile profile; + const char *argv[] = { "foo", "testfile.dat" , "testfile2.dat", "-r"}; + VERIFY_IS_FALSE(p.ParseCmdLine(_countof(argv), argv, &profile, &s)); + } + + // out of order - in between + { + Profile profile; + const char *argv[] = { "foo", "testfile.dat" , "-r", "testfile2.dat"}; + VERIFY_IS_FALSE(p.ParseCmdLine(_countof(argv), argv, &profile, &s)); + } + } +} \ No newline at end of file diff --git a/CristalDiskMark/source/diskspd22/UnitTests/CmdLineParser/CmdLineParser.UnitTests.h b/CristalDiskMark/source/diskspd22/UnitTests/CmdLineParser/CmdLineParser.UnitTests.h new file mode 100644 index 0000000..d31cae4 --- /dev/null +++ b/CristalDiskMark/source/diskspd22/UnitTests/CmdLineParser/CmdLineParser.UnitTests.h @@ -0,0 +1,117 @@ +/* + +DISKSPD + +Copyright(c) Microsoft Corporation +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#pragma once +#include "WexTestClass.h" + +namespace UnitTests +{ + BEGIN_MODULE() + MODULE_PROPERTY(L"Feature", L"CmdLineParser") + END_MODULE() + + MODULE_SETUP(ModuleSetup); + MODULE_CLEANUP(ModuleCleanup); + + class CmdLineParserUnitTests : public WEX::TestClass + { + private: + void VerifyParseCmdLineDisableAllCache(Profile &profile); + void VerifyParseCmdLineMappedIO(Profile &profile, MemoryMappedIoFlushMode FlushMode); + void VerifyParseCmdLineAccessHints(Profile &profile, bool RandomAccess, bool SequentialScan, bool TemporaryFile); + + public: + TEST_CLASS(CmdLineParserUnitTests) + + TEST_CLASS_SETUP(ClassSetup); + TEST_CLASS_CLEANUP(ClassCleanup); + + TEST_METHOD_SETUP(MethodSetup); + TEST_METHOD_CLEANUP(MethodCleanup); + + TEST_METHOD(Test_GetSizeInBytes); + TEST_METHOD(TestGetRandomDataWriteBufferData); + TEST_METHOD(TestParseCmdLine); + TEST_METHOD(TestParseCmdLineAssignAffinity); + TEST_METHOD(TestParseCmdLineBlockSize); + TEST_METHOD(TestParseCmdLineBufferedWriteThrough); + TEST_METHOD(TestParseCmdLineBurstSizeAndThinkTime); + TEST_METHOD(TestParseCmdLineConflictingCacheModes); + TEST_METHOD(TestParseCmdLineCreateFileAndMaxFileSize); + TEST_METHOD(TestParseCmdLineDisableAffinity); + TEST_METHOD(TestParseCmdLineDisableAffinityConflict); + TEST_METHOD(TestParseCmdLineDisableAllCacheMode1); + TEST_METHOD(TestParseCmdLineDisableAllCacheMode2); + TEST_METHOD(TestParseCmdLineDisableLocalCache); + TEST_METHOD(TestParseCmdLineDisableOSCache); + TEST_METHOD(TestParseCmdLineDurationAndProgress); + TEST_METHOD(TestParseCmdLineEtwDISK_IO); + TEST_METHOD(TestParseCmdLineEtwIMAGE_LOAD); + TEST_METHOD(TestParseCmdLineEtwMEMORY_HARD_FAULTS); + TEST_METHOD(TestParseCmdLineEtwMEMORY_PAGE_FAULTS); + TEST_METHOD(TestParseCmdLineEtwNETWORK); + TEST_METHOD(TestParseCmdLineEtwPROCESS); + TEST_METHOD(TestParseCmdLineEtwREGISTRY); + TEST_METHOD(TestParseCmdLineEtwTHREAD); + TEST_METHOD(TestParseCmdLineEtwUseCycleCount); + TEST_METHOD(TestParseCmdLineEtwUsePagedMemory); + TEST_METHOD(TestParseCmdLineEtwUsePerfTimer); + TEST_METHOD(TestParseCmdLineEtwUseSystemTimer); + TEST_METHOD(TestParseCmdLineGroupAffinity); + TEST_METHOD(TestParseCmdLineHintFlag); + TEST_METHOD(TestParseCmdLineBaseMaxTarget); + TEST_METHOD(TestParseCmdLineInterlockedSequential); + TEST_METHOD(TestParseCmdLineInterlockedSequentialWithStride); + TEST_METHOD(TestParseCmdLineIOPriority); + TEST_METHOD(TestParseCmdLineMappedIO); + TEST_METHOD(TestParseCmdLineMeasureLatency); + TEST_METHOD(TestParseCmdLineOverlappedCountAndBaseOffset); + TEST_METHOD(TestParseCmdLineRandomIOAlignment); + TEST_METHOD(TestParseCmdLineRandomSequentialMixed); + TEST_METHOD(TestParseCmdLineRandomWriteBuffers); + TEST_METHOD(TestParseCmdLineRandSeed); + TEST_METHOD(TestParseCmdLineRandSeedGetTickCount); + TEST_METHOD(TestParseCmdLineResultOutput); + TEST_METHOD(TestParseCmdLineStrideSize); + TEST_METHOD(TestParseCmdLineTargetDistribution); + TEST_METHOD(TestParseCmdLineTargetPosition); + TEST_METHOD(TestParseCmdLineThreadsPerFileAndThreadStride); + TEST_METHOD(TestParseCmdLineThroughput); + TEST_METHOD(TestParseCmdLineTotalThreadCountAndThroughput); + TEST_METHOD(TestParseCmdLineTotalThreadCountAndTotalRequestCount); + TEST_METHOD(TestParseCmdLineUseCompletionRoutines); + TEST_METHOD(TestParseCmdLineUseLargePages); + TEST_METHOD(TestParseCmdLineUseParallelAsyncIO); + TEST_METHOD(TestParseCmdLineVerbose); + TEST_METHOD(TestParseCmdLineWarmupAndCooldown); + TEST_METHOD(TestParseCmdLineWriteBufferContentRandomNoFilePath); + TEST_METHOD(TestParseCmdLineWriteBufferContentRandomWithFilePath); + TEST_METHOD(TestParseCmdLineZeroWriteBuffers); + }; +} diff --git a/CristalDiskMark/source/diskspd22/UnitTests/CmdLineParser/CmdLineParser.rc b/CristalDiskMark/source/diskspd22/UnitTests/CmdLineParser/CmdLineParser.rc new file mode 100644 index 0000000..53d2e74 --- /dev/null +++ b/CristalDiskMark/source/diskspd22/UnitTests/CmdLineParser/CmdLineParser.rc @@ -0,0 +1,17 @@ +#include +#include "Version.h" + +#include + +#define VER_FILETYPE VFT_APP +#define VER_FILESUBTYPE VFT2_UNKNOWN +#define VER_FILEDESCRIPTION_STR "DiskSpd Storage Performance Tool" +#define VER_INTERNALNAME_STR "CmdLineParser.UnitTests.dll" + +#undef VER_PRODUCTVERSION +#define VER_PRODUCTVERSION DISKSPD_MAJOR,DISKSPD_MINOR,DISKSPD_BUILD,DISKSPD_QFE + +#undef VER_PRODUCTVERSION_STR +#define VER_PRODUCTVERSION_STR DISKSPD_NUMERIC_VERSION_STRING + +#include "common.ver" diff --git a/CristalDiskMark/source/diskspd22/UnitTests/CmdLineParser/stdafx.h b/CristalDiskMark/source/diskspd22/UnitTests/CmdLineParser/stdafx.h new file mode 100644 index 0000000..883be10 --- /dev/null +++ b/CristalDiskMark/source/diskspd22/UnitTests/CmdLineParser/stdafx.h @@ -0,0 +1,33 @@ +/* + +DISKSPD + +Copyright(c) Microsoft Corporation +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#pragma once + +#include + diff --git a/CristalDiskMark/source/diskspd22/UnitTests/Common/Common.UnitTests.cpp b/CristalDiskMark/source/diskspd22/UnitTests/Common/Common.UnitTests.cpp new file mode 100644 index 0000000..316cc34 --- /dev/null +++ b/CristalDiskMark/source/diskspd22/UnitTests/Common/Common.UnitTests.cpp @@ -0,0 +1,1229 @@ +/* + +DISKSPD + +Copyright(c) Microsoft Corporation +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#include "StdAfx.h" +#include "Common.UnitTests.h" +#include "Common.h" +#include + +using namespace WEX::TestExecution; +using namespace WEX::Logging; + +namespace UnitTests +{ + void PerfTimerUnitTests::Test_Freq() + { + VERIFY_IS_TRUE(PerfTimer::TIMER_FREQ > 0); + } + + void PerfTimerUnitTests::Test_GetTime() + { + VERIFY_IS_TRUE(PerfTimer::GetTime() > 0); + } + + void PerfTimerUnitTests::Test_PerfTimeToSeconds() + { + double d = PerfTimer::PerfTimeToSeconds(PerfTimer::TIMER_FREQ); + printf("tos %f %a ==? %f %a\n", d, d, 1.0, 1.0); + VERIFY_IS_TRUE(d == 1.0); + } + + void PerfTimerUnitTests::Test_PerfTimeToMilliseconds() + { + double d = PerfTimer::PerfTimeToMilliseconds(PerfTimer::TIMER_FREQ); + printf("toms %f %a ==? %f %a\n", d, d, 1000.0, 1000.0); + VERIFY_IS_TRUE(d == 1000.0); + } + + void PerfTimerUnitTests::Test_PerfTimeToMicroseconds() + { + double d = PerfTimer::PerfTimeToMicroseconds(PerfTimer::TIMER_FREQ); + printf("tous %f %a ==? %f %a\n", d, d, 1000000.0, 1000000.0); + VERIFY_IS_TRUE(d == 1000000.0); + } + + void PerfTimerUnitTests::Test_SecondsToPerfTime() + { + UINT64 u = PerfTimer::SecondsToPerfTime(1.0); + VERIFY_IS_TRUE(u == PerfTimer::TIMER_FREQ); + } + + void PerfTimerUnitTests::Test_MillisecondsToPerfTime() + { + UINT64 u = PerfTimer::MillisecondsToPerfTime(1000.0); + VERIFY_IS_TRUE(u == PerfTimer::TIMER_FREQ); + } + + void PerfTimerUnitTests::Test_MicrosecondsToPerfTime() + { + UINT64 u = PerfTimer::MicrosecondsToPerfTime(1000000.0); + VERIFY_IS_TRUE(u == PerfTimer::TIMER_FREQ); + } + + void HistogramUnitTests::Test_Empty() + { + Histogram h; + VERIFY_ARE_EQUAL(h.GetSampleSize(), (unsigned)0); + } + + void HistogramUnitTests::Test_Add() + { + Histogram h; + h.Add(42); + VERIFY_ARE_EQUAL(h.GetSampleSize(), (unsigned)1); + VERIFY_ARE_EQUAL(h.GetSampleBuckets(), (unsigned)1); + + h.Add(42); + VERIFY_ARE_EQUAL(h.GetSampleSize(), (unsigned)2); + VERIFY_ARE_EQUAL(h.GetSampleBuckets(), (unsigned)1); + + h.Add(0); + VERIFY_ARE_EQUAL(h.GetSampleSize(), (unsigned)3); + VERIFY_ARE_EQUAL(h.GetSampleBuckets(), (unsigned)2); + + // seal/reset count + (void) h.GetMin(); + VERIFY_ARE_EQUAL(h.GetSampleSize(), (unsigned)3); + VERIFY_ARE_EQUAL(h.GetSampleBuckets(), (unsigned)2); + + h.Add(0); + VERIFY_ARE_EQUAL(h.GetSampleSize(), (unsigned)1); + VERIFY_ARE_EQUAL(h.GetSampleBuckets(), (unsigned)1); + + (void) h.GetMin(); + VERIFY_ARE_EQUAL(h.GetSampleSize(), (unsigned)1); + VERIFY_ARE_EQUAL(h.GetSampleBuckets(), (unsigned)1); + } + + void HistogramUnitTests::Test_Clear() + { + Histogram h; + h.Add(42); + h.Clear(); + VERIFY_ARE_EQUAL(h.GetSampleSize(), (unsigned)0); + } + + void HistogramUnitTests::Test_MinMax() + { + // use unsigned here for the sake of a compact empty "min" + // signed would be ~0 as negative int + Histogram h; + h.Add(1); + h.Add(3); + VERIFY_ARE_EQUAL(h.GetMin(), (unsigned)1); + VERIFY_ARE_EQUAL(h.GetMax(), (unsigned)3); + VERIFY_ARE_EQUAL(h.GetSampleSize(), (unsigned)2); + + // seal/reset + h.Add(2); + VERIFY_ARE_EQUAL(h.GetMin(), (unsigned)2); + VERIFY_ARE_EQUAL(h.GetMax(), (unsigned)2); + VERIFY_ARE_EQUAL(h.GetSampleSize(), (unsigned)1); + + // empty case + h.Clear(); + VERIFY_ARE_EQUAL(h.GetMin(), (unsigned)0); + VERIFY_ARE_EQUAL(h.GetMax(), (unsigned)0); + } + + void HistogramUnitTests::Test_GetPercentile() + { + Histogram h; + h.Add(1); + h.Add(2); + h.Add(3); + VERIFY_ARE_EQUAL(h.GetSampleSize(), (unsigned)3); + VERIFY_ARE_EQUAL(h.GetPercentile(0.0), 1); + VERIFY_ARE_EQUAL(h.GetPercentile(0.5), 2); + VERIFY_ARE_EQUAL(h.GetPercentile(1.0), 3); + VERIFY_ARE_EQUAL(h.GetSampleSize(), (unsigned)3); + + // single sample buckets + for (int i = 1; i < 100; i++) + { + h.Add(i); + } + // double query at same val, forward, back and again + // stresses iterator save correctness + VERIFY_ARE_EQUAL(h.GetSampleSize(), (unsigned)99); + VERIFY_ARE_EQUAL(h.GetPercentile(0.0), 1); + VERIFY_ARE_EQUAL(h.GetPercentile(0.5), 50); + VERIFY_ARE_EQUAL(h.GetPercentile(0.5), 50); + VERIFY_ARE_EQUAL(h.GetPercentile(0.6), 60); + VERIFY_ARE_EQUAL(h.GetPercentile(0.1), 10); + VERIFY_ARE_EQUAL(h.GetPercentile(0.5), 50); + VERIFY_ARE_EQUAL(h.GetPercentile(0.5), 50); + VERIFY_ARE_EQUAL(h.GetPercentile(0.6), 60); + VERIFY_ARE_EQUAL(h.GetPercentile(1.0), 99); + VERIFY_ARE_EQUAL(h.GetSampleSize(), (unsigned)99); + + // multiple sample buckets - all same (2) + for (int i = 1; i < 100; i++) + { + h.Add(i); + h.Add(i); + } + // double query at same val, forward, back and again + // stresses iterator save correctness + VERIFY_ARE_EQUAL(h.GetSampleSize(), (unsigned)198); + VERIFY_ARE_EQUAL(h.GetPercentile(0.0), 1); + VERIFY_ARE_EQUAL(h.GetPercentile(0.5), 50); + VERIFY_ARE_EQUAL(h.GetPercentile(0.5), 50); + VERIFY_ARE_EQUAL(h.GetPercentile(0.6), 60); + VERIFY_ARE_EQUAL(h.GetPercentile(0.1), 10); + VERIFY_ARE_EQUAL(h.GetPercentile(0.5), 50); + VERIFY_ARE_EQUAL(h.GetPercentile(0.5), 50); + VERIFY_ARE_EQUAL(h.GetPercentile(0.6), 60); + VERIFY_ARE_EQUAL(h.GetPercentile(1.0), 99); + VERIFY_ARE_EQUAL(h.GetSampleSize(), (unsigned)198); + + // multiple sample buckets - extra weights on low end shift things lower + for (int i = 1; i < 100; i++) + { + h.Add(i); + + if (i < 50) + { + h.Add(i); + } + } + // double query at same val, forward, back and again + // stresses iterator save correctness + VERIFY_ARE_EQUAL(h.GetSampleSize(), (unsigned)148); + VERIFY_ARE_EQUAL(h.GetPercentile(0.0), 1); + VERIFY_ARE_EQUAL(h.GetPercentile(0.5), 37); + VERIFY_ARE_EQUAL(h.GetPercentile(0.5), 37); + VERIFY_ARE_EQUAL(h.GetPercentile(0.6), 45); + VERIFY_ARE_EQUAL(h.GetPercentile(0.1), 8); + VERIFY_ARE_EQUAL(h.GetPercentile(0.5), 37); + VERIFY_ARE_EQUAL(h.GetPercentile(0.5), 37); + VERIFY_ARE_EQUAL(h.GetPercentile(0.6), 45); + VERIFY_ARE_EQUAL(h.GetPercentile(1.0), 99); + VERIFY_ARE_EQUAL(h.GetSampleSize(), (unsigned)148); + } + + void HistogramUnitTests::Test_GetMean() + { + Histogram h; + h.Add(2); + h.Add(4); + VERIFY_ARE_EQUAL(h.GetMean(), 3); + } + + void HistogramUnitTests::Test_Merge() + { + Histogram h1; + h1.Add(1); + + Histogram h2; + h2.Add(2); + + h1.Merge(h2); + + VERIFY_ARE_EQUAL(h1.GetSampleSize(), (unsigned)2); + } + + void IoBucketizerUnitTests::Test_Empty() + { + IoBucketizer b; + VERIFY_ARE_EQUAL(b.GetNumberOfValidBuckets(), (size_t)0); + } + + void IoBucketizerUnitTests::Test_Add() + { + IoBucketizer b; + b.Initialize(10, 4); + + b.Add(5, 1); + b.Add(8, 2); + VERIFY_ARE_EQUAL(b.GetNumberOfValidBuckets(), (size_t)1); + + b.Add(15, 3); + VERIFY_ARE_EQUAL(b.GetNumberOfValidBuckets(), (size_t)2); + + b.Add(18, 5); + VERIFY_ARE_EQUAL(b.GetNumberOfValidBuckets(), (size_t)2); + + b.Add(45, 4); + VERIFY_ARE_EQUAL(b.GetNumberOfValidBuckets(), (size_t)4); + + VERIFY_ARE_EQUAL(b.GetIoBucketCount(0), (unsigned int)2); + VERIFY_ARE_EQUAL(b.GetIoBucketMinDurationUsec(0), 1L); + VERIFY_ARE_EQUAL(b.GetIoBucketMaxDurationUsec(0), 2L); + VERIFY_ARE_EQUAL(b.GetIoBucketAvgDurationUsec(0), 1.5L); + VERIFY_ARE_EQUAL(b.GetIoBucketDurationStdDevUsec(0), 0.5L); + VERIFY_ARE_EQUAL(b.GetIoBucketCount(1), (unsigned int)2); + VERIFY_ARE_EQUAL(b.GetIoBucketMinDurationUsec(1), 3L); + VERIFY_ARE_EQUAL(b.GetIoBucketMaxDurationUsec(1), 5L); + VERIFY_ARE_EQUAL(b.GetIoBucketAvgDurationUsec(1), 4L); + VERIFY_ARE_EQUAL(b.GetIoBucketDurationStdDevUsec(1), 1L); + VERIFY_ARE_EQUAL(b.GetIoBucketCount(2), (unsigned int)0); + VERIFY_ARE_EQUAL(b.GetIoBucketMinDurationUsec(2), 0); + VERIFY_ARE_EQUAL(b.GetIoBucketMaxDurationUsec(2), 0); + VERIFY_ARE_EQUAL(b.GetIoBucketAvgDurationUsec(2), 0); + VERIFY_ARE_EQUAL(b.GetIoBucketDurationStdDevUsec(2), 0); + VERIFY_ARE_EQUAL(b.GetIoBucketCount(3), (unsigned int)0); + VERIFY_ARE_EQUAL(b.GetIoBucketMinDurationUsec(3), 0); + VERIFY_ARE_EQUAL(b.GetIoBucketMaxDurationUsec(3), 0); + VERIFY_ARE_EQUAL(b.GetIoBucketAvgDurationUsec(3), 0); + VERIFY_ARE_EQUAL(b.GetIoBucketDurationStdDevUsec(3), 0); + } + + void IoBucketizerUnitTests::Test_Merge() + { + IoBucketizer b1; + IoBucketizer b2; + b1.Initialize(10, 3); + b2.Initialize(10, 3); + + // b1 buckets: 2,0,1 + b1.Add(0, 0); + b1.Add(1, 0); + b1.Add(20, 0); + b1.Add(30, 0); + + VERIFY_ARE_EQUAL(b1.GetNumberOfValidBuckets(), (size_t)3); + VERIFY_ARE_EQUAL(b1.GetIoBucketCount(0), (unsigned int)2); + VERIFY_ARE_EQUAL(b1.GetIoBucketCount(1), (unsigned int)0); + VERIFY_ARE_EQUAL(b1.GetIoBucketCount(2), (unsigned int)1); + + // b2 buckets: 1,3 + b2.Add(0, 0); + b2.Add(10, 0); + b2.Add(11, 0); + b2.Add(12, 0); + + VERIFY_ARE_EQUAL(b2.GetNumberOfValidBuckets(), (size_t)2); + VERIFY_ARE_EQUAL(b2.GetIoBucketCount(0), (unsigned int)1); + VERIFY_ARE_EQUAL(b2.GetIoBucketCount(1), (unsigned int)3); + + b1.Merge(b2); + + // Merged buckets: 3,3,1 + VERIFY_ARE_EQUAL(b1.GetNumberOfValidBuckets(), (size_t)3); + VERIFY_ARE_EQUAL(b1.GetIoBucketCount(0), (unsigned int)3); + VERIFY_ARE_EQUAL(b1.GetIoBucketCount(1), (unsigned int)3); + VERIFY_ARE_EQUAL(b1.GetIoBucketCount(2), (unsigned int)1); + + // Source unchanged. + VERIFY_ARE_EQUAL(b2.GetNumberOfValidBuckets(), (size_t)2); + VERIFY_ARE_EQUAL(b2.GetIoBucketCount(0), (unsigned int)1); + VERIFY_ARE_EQUAL(b2.GetIoBucketCount(1), (unsigned int)3); + + // Merge into empty bucketizer + IoBucketizer b3; + + // Its empty. + VERIFY_ARE_EQUAL(b3.GetNumberOfValidBuckets(), (size_t)0); + + b3.Merge(b1); + + // Merged buckets: 3,3,1 + VERIFY_ARE_EQUAL(b3.GetNumberOfValidBuckets(), (size_t)3); + VERIFY_ARE_EQUAL(b3.GetIoBucketCount(0), (unsigned int)3); + VERIFY_ARE_EQUAL(b3.GetIoBucketCount(1), (unsigned int)3); + VERIFY_ARE_EQUAL(b3.GetIoBucketCount(2), (unsigned int)1); + } + + void IoBucketizerUnitTests::Test_GetStandardDeviation() + { + IoBucketizer b; + b.Initialize(10, 2); + + // b buckets: 1,2 + b.Add(0, 0); + b.Add(10, 0); + b.Add(11, 0); + b.Add(20, 0); + + // Standard deviation from valid buckets (the first two) is STDDEV(1,2) = 0.5 + VERIFY_ARE_EQUAL(b.GetStandardDeviationIOPS(), 0.5L); + } + + void ProfileUnitTests::Test_GetXmlEmptyProfile() + { + Profile profile; + string sXml = profile.GetXml(0); + //printf("'%s'\n", sXml.c_str()); + VERIFY_IS_TRUE(sXml == "\n" + " 0\n" + " text\n" + " false\n" + " \n" + " \n" + "\n"); + } + + void ProfileUnitTests::Test_GetXmlPrecreateFilesUseMaxSize() + { + Profile profile; + profile.SetPrecreateFiles(PrecreateFiles::UseMaxSize); + string sXml = profile.GetXml(0); + //printf("'%s'\n", sXml.c_str()); + VERIFY_IS_TRUE(sXml == "\n" + " 0\n" + " text\n" + " false\n" + " UseMaxSize\n" + " \n" + " \n" + "\n"); + } + + void ProfileUnitTests::Test_GetXmlPrecreateFilesOnlyFilesWithConstantSizes() + { + Profile profile; + profile.SetPrecreateFiles(PrecreateFiles::OnlyFilesWithConstantSizes); + string sXml = profile.GetXml(0); + //printf("'%s'\n", sXml.c_str()); + VERIFY_IS_TRUE(sXml == "\n" + " 0\n" + " text\n" + " false\n" + " CreateOnlyFilesWithConstantSizes\n" + " \n" + " \n" + "\n"); + } + + void ProfileUnitTests::Test_GetXmlPrecreateFilesOnlyFilesWithConstantOrZeroSizes() + { + Profile profile; + profile.SetPrecreateFiles(PrecreateFiles::OnlyFilesWithConstantOrZeroSizes); + string sXml = profile.GetXml(0); + //printf("'%s'\n", sXml.c_str()); + VERIFY_IS_TRUE(sXml == "\n" + " 0\n" + " text\n" + " false\n" + " CreateOnlyFilesWithConstantOrZeroSizes\n" + " \n" + " \n" + "\n"); + } + + void ProfileUnitTests::Test_MarkFilesAsCreated() + { + Target target1; + target1.SetPath("file1.txt"); + + Target target2; + target2.SetPath("file2.txt"); + + Target target3; + target3.SetPath("file1.txt"); + + Target target4; + target4.SetPath("file3.txt"); + + Target target5; + target5.SetPath("file2.txt"); + + Target target6; + target6.SetPath("file2.txt"); + + TimeSpan timeSpan1; + timeSpan1.AddTarget(target1); + timeSpan1.AddTarget(target2); + + TimeSpan timeSpan2; + timeSpan2.AddTarget(target3); + timeSpan2.AddTarget(target4); + timeSpan2.AddTarget(target5); + timeSpan2.AddTarget(target6); + + Profile profile; + profile.AddTimeSpan(timeSpan1); + profile.AddTimeSpan(timeSpan2); + + vector vFiles; + vFiles.push_back("file1.txt"); + vFiles.push_back("file2.txt"); + + VERIFY_IS_FALSE(profile._vTimeSpans[0]._vTargets[0]._fPrecreated); + VERIFY_IS_FALSE(profile._vTimeSpans[0]._vTargets[1]._fPrecreated); + VERIFY_IS_FALSE(profile._vTimeSpans[1]._vTargets[0]._fPrecreated); + VERIFY_IS_FALSE(profile._vTimeSpans[1]._vTargets[1]._fPrecreated); + VERIFY_IS_FALSE(profile._vTimeSpans[1]._vTargets[2]._fPrecreated); + VERIFY_IS_FALSE(profile._vTimeSpans[1]._vTargets[3]._fPrecreated); + + profile.MarkFilesAsPrecreated(vFiles); + VERIFY_IS_TRUE(profile._vTimeSpans[0]._vTargets[0]._fPrecreated); + VERIFY_IS_TRUE(profile._vTimeSpans[0]._vTargets[1]._fPrecreated); + VERIFY_IS_TRUE(profile._vTimeSpans[1]._vTargets[0]._fPrecreated); + VERIFY_IS_FALSE(profile._vTimeSpans[1]._vTargets[1]._fPrecreated); + VERIFY_IS_TRUE(profile._vTimeSpans[1]._vTargets[2]._fPrecreated); + VERIFY_IS_TRUE(profile._vTimeSpans[1]._vTargets[3]._fPrecreated); + } + + void ProfileUnitTests::Test_Validate() + { + TimeSpan timeSpan; + Target target; + + target.SetBaseFileOffsetInBytes(1000); + target.SetBlockAlignmentInBytes(500); + target.SetBlockSizeInBytes(1000); + target.SetThreadStrideInBytes(5000); + timeSpan.AddTarget(target); + + Profile profile; + profile.AddTimeSpan(timeSpan); + + // thread stride errors if only one thread used (default) + // both the single spec assumption and full should behave the same + VERIFY_IS_FALSE(profile.Validate(true)); + VERIFY_IS_FALSE(profile.Validate(false)); + + profile._vTimeSpans[0].SetThreadCount(2); + VERIFY_IS_TRUE(profile.Validate(true)); + VERIFY_IS_TRUE(profile.Validate(false)); + + // now turning on interlocked sequential, fail since thread stride is set + profile._vTimeSpans[0]._vTargets[0].SetUseInterlockedSequential(true); + VERIFY_IS_FALSE(profile.Validate(true)); + VERIFY_IS_FALSE(profile.Validate(false)); + + profile._vTimeSpans[0]._vTargets[0].SetThreadStrideInBytes(0); + VERIFY_IS_TRUE(profile.Validate(true)); + VERIFY_IS_TRUE(profile.Validate(false)); + } + + void ProfileUnitTests::Test_ValidateSystem() + { + // processor topology validation for affinity assignments + // 2 group, 2 procs/group + SystemInformation system; + system.processorTopology._vProcessorGroupInformation.clear(); + system.processorTopology._vProcessorGroupInformation.emplace_back((WORD)0, (BYTE)2, (BYTE)2, (KAFFINITY)0x3); + system.processorTopology._vProcessorGroupInformation.emplace_back((WORD)1, (BYTE)2, (BYTE)2, (KAFFINITY)0x3); + + TimeSpan timeSpan; + Profile profile; + + // assign to each proc + profile.ClearTimeSpans(); + timeSpan.ClearAffinityAssignment(); + timeSpan.AddAffinityAssignment(0, 0); + timeSpan.AddAffinityAssignment(0, 1); + timeSpan.AddAffinityAssignment(1, 0); + timeSpan.AddAffinityAssignment(1, 1); + profile.AddTimeSpan(timeSpan); + VERIFY_IS_TRUE(profile.Validate(true, &system)); + + // shrink active mask + system.processorTopology._vProcessorGroupInformation.clear(); + system.processorTopology._vProcessorGroupInformation.emplace_back((WORD)0, (BYTE)2, (BYTE)2, (KAFFINITY)0x1); + system.processorTopology._vProcessorGroupInformation.emplace_back((WORD)1, (BYTE)2, (BYTE)2, (KAFFINITY)0x1); + + // fail assignment to inactive procs + VERIFY_IS_FALSE(profile.Validate(true, &system)); + + // shrink procs, still fail + system.processorTopology._vProcessorGroupInformation.clear(); + system.processorTopology._vProcessorGroupInformation.emplace_back((WORD)0, (BYTE)1, (BYTE)1, (KAFFINITY)0x1); + system.processorTopology._vProcessorGroupInformation.emplace_back((WORD)1, (BYTE)1, (BYTE)1, (KAFFINITY)0x1); + + // now fail + VERIFY_IS_FALSE(profile.Validate(true, &system)); + + // assign to low procs, and succeed + profile.ClearTimeSpans(); + timeSpan.ClearAffinityAssignment(); + timeSpan.AddAffinityAssignment(0, 0); + timeSpan.AddAffinityAssignment(1, 0); + profile.AddTimeSpan(timeSpan); + VERIFY_IS_TRUE(profile.Validate(true, &system)); + + // shrink groups + system.processorTopology._vProcessorGroupInformation.clear(); + system.processorTopology._vProcessorGroupInformation.emplace_back((WORD)0, (BYTE)1, (BYTE)1, (KAFFINITY)0x1); + + // now fail + VERIFY_IS_FALSE(profile.Validate(true, &system)); + + // assign to low proc, and succeed + profile.ClearTimeSpans(); + timeSpan.ClearAffinityAssignment(); + timeSpan.AddAffinityAssignment(0, 0); + profile.AddTimeSpan(timeSpan); + VERIFY_IS_TRUE(profile.Validate(true, &system)); + + // assign to invalid group + profile.ClearTimeSpans(); + timeSpan.ClearAffinityAssignment(); + timeSpan.AddAffinityAssignment(1, 0); + profile.AddTimeSpan(timeSpan); + VERIFY_IS_FALSE(profile.Validate(true, &system)); + } + + void TargetUnitTests::TestGetSetRandomDataWriteBufferSize() + { + Target t; + VERIFY_ARE_EQUAL(t.GetRandomDataWriteBufferSize(), 0); + t.SetRandomDataWriteBufferSize(1234); + VERIFY_ARE_EQUAL(t.GetRandomDataWriteBufferSize(), 1234); + } + + void TargetUnitTests::TestGetSetRandomDataWriteBufferSourcePath() + { + Target t; + VERIFY_ARE_EQUAL(t.GetRandomDataWriteBufferSourcePath(), ""); + t.SetRandomDataWriteBufferSourcePath("x:\\foo\\bar.dat"); + VERIFY_ARE_EQUAL(t.GetRandomDataWriteBufferSourcePath(), "x:\\foo\\bar.dat"); + } + + void TargetUnitTests::Test_TargetGetXmlWriteBufferContentSequential() + { + Target target; + string sXml = target.GetXml(0); + VERIFY_IS_TRUE(sXml == "\n" + " \n" + " 65536\n" + " 0\n" + " false\n" + " false\n" + " false\n" + " false\n" + " \n" + " sequential\n" + " \n" + " false\n" + " 65536\n" + " false\n" + " 0\n" + " 0\n" + " 2\n" + " 0\n" + " 0\n" + " 1\n" + " 3\n" + " 1\n" + "\n"); + } + + void TargetUnitTests::Test_TargetGetXmlWriteBufferContentZero() + { + Target target; + target.SetZeroWriteBuffers(true); + string sXml = target.GetXml(0); + VERIFY_IS_TRUE(sXml == "\n" + " \n" + " 65536\n" + " 0\n" + " false\n" + " false\n" + " false\n" + " false\n" + " \n" + " zero\n" + " \n" + " false\n" + " 65536\n" + " false\n" + " 0\n" + " 0\n" + " 2\n" + " 0\n" + " 0\n" + " 1\n" + " 3\n" + " 1\n" + "\n"); + } + + void TargetUnitTests::Test_TargetGetXmlWriteBufferContentRandomNoFilePath() + { + Target target; + target.SetRandomDataWriteBufferSize(224433); + string sXml = target.GetXml(0); + VERIFY_IS_TRUE(sXml == "\n" + " \n" + " 65536\n" + " 0\n" + " false\n" + " false\n" + " false\n" + " false\n" + " \n" + " random\n" + " \n" + " 224433\n" + " \n" + " \n" + " false\n" + " 65536\n" + " false\n" + " 0\n" + " 0\n" + " 2\n" + " 0\n" + " 0\n" + " 1\n" + " 3\n" + " 1\n" + "\n"); + } + + void TargetUnitTests::Test_TargetGetXmlWriteBufferContentRandomWithFilePath() + { + Target target; + target.SetRandomDataWriteBufferSize(224433); + target.SetRandomDataWriteBufferSourcePath("x:\\foo\\bar.baz"); + string sXml = target.GetXml(0); + VERIFY_IS_TRUE(sXml == "\n" + " \n" + " 65536\n" + " 0\n" + " false\n" + " false\n" + " false\n" + " false\n" + " \n" + " random\n" + " \n" + " 224433\n" + " x:\\foo\\bar.baz\n" + " \n" + " \n" + " false\n" + " 65536\n" + " false\n" + " 0\n" + " 0\n" + " 2\n" + " 0\n" + " 0\n" + " 1\n" + " 3\n" + " 1\n" + "\n"); + } + + void TargetUnitTests::Test_TargetGetXmlDisableAllCache() + { + Target target; + target.SetCacheMode(TargetCacheMode::DisableOSCache); + target.SetWriteThroughMode(WriteThroughMode::On); + string sXml = target.GetXml(0); + VERIFY_IS_TRUE(sXml == "\n" + " \n" + " 65536\n" + " 0\n" + " false\n" + " false\n" + " false\n" + " false\n" + " true\n" + " true\n" + " \n" + " sequential\n" + " \n" + " false\n" + " 65536\n" + " false\n" + " 0\n" + " 0\n" + " 2\n" + " 0\n" + " 0\n" + " 1\n" + " 3\n" + " 1\n" + "\n"); + } + + void TargetUnitTests::Test_TargetGetXmlDisableLocalCache() + { + Target target; + target.SetCacheMode(TargetCacheMode::DisableLocalCache); + string sXml = target.GetXml(0); + VERIFY_IS_TRUE(sXml == "\n" + " \n" + " 65536\n" + " 0\n" + " false\n" + " false\n" + " false\n" + " false\n" + " true\n" + " \n" + " sequential\n" + " \n" + " false\n" + " 65536\n" + " false\n" + " 0\n" + " 0\n" + " 2\n" + " 0\n" + " 0\n" + " 1\n" + " 3\n" + " 1\n" + "\n"); + } + + void TargetUnitTests::Test_TargetGetXmlDisableOSCache() + { + Target target; + target.SetCacheMode(TargetCacheMode::DisableOSCache); + string sXml = target.GetXml(0); + VERIFY_IS_TRUE(sXml == "\n" + " \n" + " 65536\n" + " 0\n" + " false\n" + " false\n" + " false\n" + " false\n" + " true\n" + " \n" + " sequential\n" + " \n" + " false\n" + " 65536\n" + " false\n" + " 0\n" + " 0\n" + " 2\n" + " 0\n" + " 0\n" + " 1\n" + " 3\n" + " 1\n" + "\n"); + } + + void TargetUnitTests::Test_TargetGetXmlBufferedWriteThrough() + { + Target target; + target.SetWriteThroughMode(WriteThroughMode::On); + string sXml = target.GetXml(0); + VERIFY_IS_TRUE(sXml == "\n" + " \n" + " 65536\n" + " 0\n" + " false\n" + " false\n" + " false\n" + " false\n" + " true\n" + " \n" + " sequential\n" + " \n" + " false\n" + " 65536\n" + " false\n" + " 0\n" + " 0\n" + " 2\n" + " 0\n" + " 0\n" + " 1\n" + " 3\n" + " 1\n" + "\n"); + } + + void TargetUnitTests::Test_TargetGetXmlMemoryMappedIo() + { + Target target; + target.SetMemoryMappedIoMode(MemoryMappedIoMode::On); + string sXml = target.GetXml(0); + VERIFY_IS_TRUE(sXml == "\n" + " \n" + " 65536\n" + " 0\n" + " false\n" + " false\n" + " false\n" + " false\n" + " true\n" + " \n" + " sequential\n" + " \n" + " false\n" + " 65536\n" + " false\n" + " 0\n" + " 0\n" + " 2\n" + " 0\n" + " 0\n" + " 1\n" + " 3\n" + " 1\n" + "\n"); + } + + void TargetUnitTests::Test_TargetGetXmlMemoryMappedIoFlushModeViewOfFile() + { + Target target; + target.SetMemoryMappedIoMode(MemoryMappedIoMode::On); + target.SetMemoryMappedIoFlushMode(MemoryMappedIoFlushMode::ViewOfFile); + string sXml = target.GetXml(0); + VERIFY_IS_TRUE(sXml == "\n" + " \n" + " 65536\n" + " 0\n" + " false\n" + " false\n" + " false\n" + " false\n" + " true\n" + " ViewOfFile\n" + " \n" + " sequential\n" + " \n" + " false\n" + " 65536\n" + " false\n" + " 0\n" + " 0\n" + " 2\n" + " 0\n" + " 0\n" + " 1\n" + " 3\n" + " 1\n" + "\n"); + } + + void TargetUnitTests::Test_TargetGetXmlMemoryMappedIoFlushModeNonVolatileMemory() + { + Target target; + target.SetMemoryMappedIoMode(MemoryMappedIoMode::On); + target.SetMemoryMappedIoFlushMode(MemoryMappedIoFlushMode::NonVolatileMemory); + string sXml = target.GetXml(0); + VERIFY_IS_TRUE(sXml == "\n" + " \n" + " 65536\n" + " 0\n" + " false\n" + " false\n" + " false\n" + " false\n" + " true\n" + " NonVolatileMemory\n" + " \n" + " sequential\n" + " \n" + " false\n" + " 65536\n" + " false\n" + " 0\n" + " 0\n" + " 2\n" + " 0\n" + " 0\n" + " 1\n" + " 3\n" + " 1\n" + "\n"); + } + + void TargetUnitTests::Test_TargetGetXmlMemoryMappedIoFlushModeNonVolatileMemoryNoDrain() + { + Target target; + target.SetMemoryMappedIoMode(MemoryMappedIoMode::On); + target.SetMemoryMappedIoFlushMode(MemoryMappedIoFlushMode::NonVolatileMemoryNoDrain); + string sXml = target.GetXml(0); + VERIFY_IS_TRUE(sXml == "\n" + " \n" + " 65536\n" + " 0\n" + " false\n" + " false\n" + " false\n" + " false\n" + " true\n" + " NonVolatileMemoryNoDrain\n" + " \n" + " sequential\n" + " \n" + " false\n" + " 65536\n" + " false\n" + " 0\n" + " 0\n" + " 2\n" + " 0\n" + " 0\n" + " 1\n" + " 3\n" + " 1\n" + "\n"); + } + + void TargetUnitTests::Test_TargetGetXmlRandomAccessHint() + { + Target target; + target.SetRandomAccessHint(true); + string sXml = target.GetXml(0); + VERIFY_IS_TRUE(sXml == "\n" + " \n" + " 65536\n" + " 0\n" + " false\n" + " true\n" + " false\n" + " false\n" + " \n" + " sequential\n" + " \n" + " false\n" + " 65536\n" + " false\n" + " 0\n" + " 0\n" + " 2\n" + " 0\n" + " 0\n" + " 1\n" + " 3\n" + " 1\n" + "\n"); + } + + void TargetUnitTests::Test_TargetGetXmlSequentialScanHint() + { + Target target; + target.SetSequentialScanHint(true); + string sXml = target.GetXml(0); + VERIFY_IS_TRUE(sXml == "\n" + " \n" + " 65536\n" + " 0\n" + " true\n" + " false\n" + " false\n" + " false\n" + " \n" + " sequential\n" + " \n" + " false\n" + " 65536\n" + " false\n" + " 0\n" + " 0\n" + " 2\n" + " 0\n" + " 0\n" + " 1\n" + " 3\n" + " 1\n" + "\n"); + } + + void TargetUnitTests::Test_TargetGetXmlCombinedAccessHint() + { + Target target; + target.SetSequentialScanHint(true); + target.SetTemporaryFileHint(true); + string sXml = target.GetXml(0); + VERIFY_IS_TRUE(sXml == "\n" + " \n" + " 65536\n" + " 0\n" + " true\n" + " false\n" + " true\n" + " false\n" + " \n" + " sequential\n" + " \n" + " false\n" + " 65536\n" + " false\n" + " 0\n" + " 0\n" + " 2\n" + " 0\n" + " 0\n" + " 1\n" + " 3\n" + " 1\n" + "\n"); + } + + void TargetUnitTests::Test_AllocateAndFillRandomDataWriteBuffer() + { + Random r; + Target t; + VERIFY_IS_FALSE(t.AllocateAndFillRandomDataWriteBuffer(&r)); + VERIFY_ARE_EQUAL(t._pRandomDataWriteBuffer, nullptr); + + size_t cb = 12345; + t.SetRandomDataWriteBufferSize(cb); + VERIFY_IS_TRUE(t.AllocateAndFillRandomDataWriteBuffer(&r)); + VERIFY_IS_TRUE(t._pRandomDataWriteBuffer != nullptr); + // see if the test crashes if we try to write to every byte of the buffer + + for (size_t i = 0; i < cb; i++) + { + t._pRandomDataWriteBuffer[i] = (i % 256); + } + + for (size_t i = 0; i < cb; i++) + { + if (t._pRandomDataWriteBuffer[i] != (i % 256)) + { + // don't call VERIFY_ARE_EQUAL on each item because it prints to the screen and makes the test take + // too long + VERIFY_IS_TRUE(false); + } + } + } + + void TargetUnitTests::Test_AllocateAndFillRandomDataWriteBufferFromFile() + { + char szTempDirPath[MAX_PATH] = {}; + DWORD cch = GetTempPathA(_countof(szTempDirPath), szTempDirPath); + VERIFY_IS_TRUE(cch != 0); + string sTempFilePath(szTempDirPath); + sTempFilePath += "diskspd-random-data-file.dat"; + DeleteFileA(sTempFilePath.c_str()); + + printf("path: '%s'\n", sTempFilePath.c_str()); + FILE *pFile; + fopen_s(&pFile, sTempFilePath.c_str(), "wb"); + VERIFY_IS_TRUE(pFile != nullptr); + char buffer[256]; + for (int i = 0; i < 256; i++) + { + buffer[i] = static_cast(0xFF - i); + } + VERIFY_ARE_EQUAL(fwrite(buffer, sizeof(buffer), 1, pFile), (size_t)1); + fclose(pFile); + pFile = nullptr; + + Random r; + Target t; + size_t cbBuffer = 1024 * 1024; + t.SetRandomDataWriteBufferSize(cbBuffer); + t.SetRandomDataWriteBufferSourcePath(sTempFilePath.c_str()); + VERIFY_IS_TRUE(t.AllocateAndFillRandomDataWriteBuffer(&r)); + VERIFY_IS_TRUE(t._pRandomDataWriteBuffer != nullptr); + for (size_t i = 0; i < cbBuffer; i++) + { + if (t._pRandomDataWriteBuffer[i] != (0xFF - (i % 256))) + { + // don't call VERIFY_ARE_EQUAL on each item because it prints to the screen and makes the test take + // too long + VERIFY_IS_TRUE(false); + } + } + + DeleteFileA(sTempFilePath.c_str()); + } + + void ThreadParametersUnitTests::Test_AllocateAndFillBufferForTarget() + { + TimeSpan ts; + Target t; + Random r; + t.SetBlockSizeInBytes(12345); + t.SetRequestCount(12); + ThreadParameters tp; + tp.pTimeSpan = &ts; + tp.pRand = &r; + VERIFY_IS_TRUE(tp.AllocateAndFillBufferForTarget(t)); + + // see if the test crashes if we try to write to every byte of the buffer + size_t cb = t.GetBlockSizeInBytes() * t.GetRequestCount(); + for (size_t i = 0; i < cb; i++) + { + tp.vpDataBuffers[0][i] = (i % 256); + } + + for (size_t i = 0; i < cb; i++) + { + if (tp.vpDataBuffers[0][i] != (i % 256)) + { + // don't call VERIFY_ARE_EQUAL on each item because it prints to the screen and makes the test take + // too long + VERIFY_IS_TRUE(false); + } + } + } + + void TopologyUnitTests::Test_MaskCount() + { + ULONG kaff_bits = sizeof(KAFFINITY) * 8; + + // a complete enumeration could be interesting, but a nibble is enough to test the algorithm. + // take the given mask and its width (ordinal distance to the upper 1), shift it through the + // range of KAFFINITY to verify the popcnt is correct at all positions + // + // note that unique masks have msb/lsb set for all combinations of the interior bits. we don't + // test "10" (0x2) as a mask, because it's not unique - its the same as the first shift-up of + // "1" (0x1), etc. + + struct { + KAFFINITY mask; + ULONG width; + ULONG bits; + } tests[] = { // msb ... lsb + { 0x1, 1, 1 }, // 1 + { 0x3, 2, 2 }, // 11 + { 0x5, 3, 2 }, // 101 + { 0x7, 3, 3 }, // 111 + { 0x9, 4, 2 }, // 1001 + { 0xb, 4, 3 }, // 1011 + { 0xd, 4, 3 }, // 1101 + { 0xf, 4, 4 } // 1111 + }; + + for (const auto &test : tests) + { + KAFFINITY mask = test.mask; + for (ULONG i = 0; i < kaff_bits - test.width; i++) + { + VERIFY_ARE_EQUAL(ProcessorTopology::MaskCount(mask), test.bits); + mask <<= 1; + } + } + + // ... and a few explicit true/false + VERIFY_ARE_NOT_EQUAL(ProcessorTopology::MaskCount(0x0), (ULONG)1); + VERIFY_ARE_NOT_EQUAL(ProcessorTopology::MaskCount(0x3), (ULONG)0); + VERIFY_ARE_NOT_EQUAL(ProcessorTopology::MaskCount(0x5), (ULONG)3); + + VERIFY_ARE_EQUAL(ProcessorTopology::MaskCount(0x0), (ULONG)0); + VERIFY_ARE_EQUAL(ProcessorTopology::MaskCount(0x3), (ULONG)2); + VERIFY_ARE_EQUAL(ProcessorTopology::MaskCount(0x5), (ULONG)2); + + VERIFY_ARE_EQUAL(ProcessorTopology::MaskCount(0xffff), (ULONG)16); + VERIFY_ARE_EQUAL(ProcessorTopology::MaskCount(0xfeef), (ULONG)14); + VERIFY_ARE_EQUAL(ProcessorTopology::MaskCount(0xfeef00ff), (ULONG)22); + VERIFY_ARE_EQUAL(ProcessorTopology::MaskCount(0xfe0000ff), (ULONG)15); + VERIFY_ARE_EQUAL(ProcessorTopology::MaskCount(0x7e0000ff), (ULONG)14); + } +} diff --git a/CristalDiskMark/source/diskspd22/UnitTests/Common/Common.UnitTests.h b/CristalDiskMark/source/diskspd22/UnitTests/Common/Common.UnitTests.h new file mode 100644 index 0000000..31d26a0 --- /dev/null +++ b/CristalDiskMark/source/diskspd22/UnitTests/Common/Common.UnitTests.h @@ -0,0 +1,130 @@ +/* + +DISKSPD + +Copyright(c) Microsoft Corporation +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#pragma once +#include "WexTestClass.h" + +namespace UnitTests +{ + BEGIN_MODULE() + MODULE_PROPERTY(L"Feature", L"Common") + END_MODULE() + + class PerfTimerUnitTests : public WEX::TestClass + { + public: + TEST_CLASS(PerfTimerUnitTests); + TEST_METHOD(Test_Freq); + TEST_METHOD(Test_GetTime); + TEST_METHOD(Test_PerfTimeToSeconds); + TEST_METHOD(Test_PerfTimeToMilliseconds); + TEST_METHOD(Test_PerfTimeToMicroseconds); + TEST_METHOD(Test_SecondsToPerfTime); + TEST_METHOD(Test_MillisecondsToPerfTime); + TEST_METHOD(Test_MicrosecondsToPerfTime); + }; + + class HistogramUnitTests : public WEX::TestClass + { + public: + TEST_CLASS(HistogramUnitTests); + TEST_METHOD(Test_Empty); + TEST_METHOD(Test_Add); + TEST_METHOD(Test_Clear); + TEST_METHOD(Test_MinMax); + TEST_METHOD(Test_GetPercentile); + TEST_METHOD(Test_GetMean); + TEST_METHOD(Test_Merge); + }; + + class IoBucketizerUnitTests : public WEX::TestClass + { + public: + TEST_CLASS(IoBucketizerUnitTests); + TEST_METHOD(Test_Empty); + TEST_METHOD(Test_Add); + TEST_METHOD(Test_Merge); + TEST_METHOD(Test_GetStandardDeviation); + }; + + class ProfileUnitTests : public WEX::TestClass + { + public: + TEST_CLASS(ProfileUnitTests); + TEST_METHOD(Test_GetXmlEmptyProfile); + TEST_METHOD(Test_GetXmlPrecreateFilesUseMaxSize); + TEST_METHOD(Test_GetXmlPrecreateFilesOnlyFilesWithConstantSizes); + TEST_METHOD(Test_GetXmlPrecreateFilesOnlyFilesWithConstantOrZeroSizes); + TEST_METHOD(Test_MarkFilesAsCreated); + TEST_METHOD(Test_Validate); + TEST_METHOD(Test_ValidateSystem); + }; + + class TargetUnitTests : public WEX::TestClass + { + public: + TEST_CLASS(TargetUnitTests); + TEST_METHOD(TestGetSetRandomDataWriteBufferSize); + TEST_METHOD(TestGetSetRandomDataWriteBufferSourcePath); + TEST_METHOD(Test_TargetGetXmlWriteBufferContentSequential); + TEST_METHOD(Test_TargetGetXmlWriteBufferContentZero); + TEST_METHOD(Test_TargetGetXmlWriteBufferContentRandomNoFilePath); + TEST_METHOD(Test_TargetGetXmlWriteBufferContentRandomWithFilePath); + TEST_METHOD(Test_TargetGetXmlDisableAllCache); + TEST_METHOD(Test_TargetGetXmlDisableLocalCache); + TEST_METHOD(Test_TargetGetXmlDisableOSCache); + TEST_METHOD(Test_TargetGetXmlBufferedWriteThrough); + TEST_METHOD(Test_TargetGetXmlMemoryMappedIo); + TEST_METHOD(Test_TargetGetXmlMemoryMappedIoFlushModeViewOfFile); + TEST_METHOD(Test_TargetGetXmlMemoryMappedIoFlushModeNonVolatileMemory); + TEST_METHOD(Test_TargetGetXmlMemoryMappedIoFlushModeNonVolatileMemoryNoDrain); + TEST_METHOD(Test_TargetGetXmlRandomAccessHint); + TEST_METHOD(Test_TargetGetXmlSequentialScanHint); + TEST_METHOD(Test_TargetGetXmlCombinedAccessHint); + TEST_METHOD(Test_AllocateAndFillRandomDataWriteBuffer); + TEST_METHOD(Test_AllocateAndFillRandomDataWriteBufferFromFile); + }; + + class ThreadParametersUnitTests : public WEX::TestClass + { + public: + TEST_CLASS(ThreadParametersUnitTests); + TEST_METHOD(Test_AllocateAndFillBufferForTarget); + }; + + class TopologyUnitTests : public WEX::TestClass + { + public: + TEST_CLASS(TopologyUnitTests); + TEST_METHOD(Test_MaskCount); + }; +} + +// TODO: ThreadParameters::GetWriteBuffer +// TODO: Target::GetRandomDataWriteBuffer(); diff --git a/CristalDiskMark/source/diskspd22/UnitTests/Common/Common.rc b/CristalDiskMark/source/diskspd22/UnitTests/Common/Common.rc new file mode 100644 index 0000000..0c601ae --- /dev/null +++ b/CristalDiskMark/source/diskspd22/UnitTests/Common/Common.rc @@ -0,0 +1,17 @@ +#include +#include "Version.h" + +#include + +#define VER_FILETYPE VFT_APP +#define VER_FILESUBTYPE VFT2_UNKNOWN +#define VER_FILEDESCRIPTION_STR "DiskSpd Storage Performance Tool" +#define VER_INTERNALNAME_STR "Common.UnitTests.dll" + +#undef VER_PRODUCTVERSION +#define VER_PRODUCTVERSION DISKSPD_MAJOR,DISKSPD_MINOR,DISKSPD_BUILD,DISKSPD_QFE + +#undef VER_PRODUCTVERSION_STR +#define VER_PRODUCTVERSION_STR DISKSPD_NUMERIC_VERSION_STRING + +#include "common.ver" diff --git a/CristalDiskMark/source/diskspd22/UnitTests/Common/stdafx.h b/CristalDiskMark/source/diskspd22/UnitTests/Common/stdafx.h new file mode 100644 index 0000000..883be10 --- /dev/null +++ b/CristalDiskMark/source/diskspd22/UnitTests/Common/stdafx.h @@ -0,0 +1,33 @@ +/* + +DISKSPD + +Copyright(c) Microsoft Corporation +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#pragma once + +#include + diff --git a/CristalDiskMark/source/diskspd22/UnitTests/IORequestGenerator/IORequestGenerator.UnitTests.cpp b/CristalDiskMark/source/diskspd22/UnitTests/IORequestGenerator/IORequestGenerator.UnitTests.cpp new file mode 100644 index 0000000..0fe43ac --- /dev/null +++ b/CristalDiskMark/source/diskspd22/UnitTests/IORequestGenerator/IORequestGenerator.UnitTests.cpp @@ -0,0 +1,1327 @@ +/* + +DISKSPD + +Copyright(c) Microsoft Corporation +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#include "StdAfx.h" +#include "IORequestGenerator.UnitTests.h" +#include "Common.h" +#include "IORequestGenerator.h" +#include + +using namespace WEX::TestExecution; +using namespace WEX::Logging; + +namespace UnitTests +{ + void IORequestGeneratorUnitTests::Test_GetFilesToPrecreate1() + { + Target target1; + target1.SetPath("file1.txt"); + target1.SetFileSize(100); + + Target target2; + target2.SetPath("file2.txt"); + + Target target3; + target3.SetPath("file1.txt"); + target3.SetFileSize(150); + + Target target4; + target4.SetPath("file2.txt"); + target4.SetFileSize(200); + + Target target5; + target5.SetPath("file3.txt"); + + Target target6; + target6.SetPath("file4.txt"); + target6.SetFileSize(300); + + Target target7; + target7.SetPath("file4.txt"); + target7.SetFileSize(300); + + Target target8; + target8.SetPath("file5.txt"); + target8.SetFileSize(300); + + Target target9; + target9.SetPath("file5.txt"); + target9.SetFileSize(300); + target9.SetZeroWriteBuffers(true); + + TimeSpan timeSpan1; + TimeSpan timeSpan2; + timeSpan1.AddTarget(target1); + timeSpan1.AddTarget(target2); + timeSpan2.AddTarget(target3); + timeSpan2.AddTarget(target4); + timeSpan2.AddTarget(target5); + timeSpan2.AddTarget(target6); + timeSpan2.AddTarget(target7); + timeSpan2.AddTarget(target8); + timeSpan2.AddTarget(target9); + + Profile profile; + profile.AddTimeSpan(timeSpan1); + profile.AddTimeSpan(timeSpan2); + + { + profile.SetPrecreateFiles(PrecreateFiles::UseMaxSize); + IORequestGenerator io; + vector v = io._GetFilesToPrecreate(profile); + VERIFY_ARE_EQUAL(v.size(), (size_t)3); + + VERIFY_ARE_EQUAL(v[0].sPath, "file1.txt"); + VERIFY_ARE_EQUAL(v[0].fZeroWriteBuffers, false); + VERIFY_ARE_EQUAL(v[0].ullFileSize, 150); + + VERIFY_ARE_EQUAL(v[1].sPath, "file2.txt"); + VERIFY_ARE_EQUAL(v[1].fZeroWriteBuffers, false); + VERIFY_ARE_EQUAL(v[1].ullFileSize, 200); + + VERIFY_ARE_EQUAL(v[2].sPath, "file4.txt"); + VERIFY_ARE_EQUAL(v[2].fZeroWriteBuffers, false); + VERIFY_ARE_EQUAL(v[2].ullFileSize, 300); + } + + { + profile.SetPrecreateFiles(PrecreateFiles::OnlyFilesWithConstantSizes); + IORequestGenerator io; + vector v = io._GetFilesToPrecreate(profile); + VERIFY_ARE_EQUAL(v.size(), (size_t)1); + + VERIFY_ARE_EQUAL(v[0].sPath, "file4.txt"); + VERIFY_ARE_EQUAL(v[0].fZeroWriteBuffers, false); + VERIFY_ARE_EQUAL(v[0].ullFileSize, 300); + } + + { + profile.SetPrecreateFiles(PrecreateFiles::OnlyFilesWithConstantOrZeroSizes); + IORequestGenerator io; + vector v = io._GetFilesToPrecreate(profile); + VERIFY_ARE_EQUAL(v.size(), (size_t)2); + + VERIFY_ARE_EQUAL(v[0].sPath, "file2.txt"); + VERIFY_ARE_EQUAL(v[0].fZeroWriteBuffers, false); + VERIFY_ARE_EQUAL(v[0].ullFileSize, 200); + + VERIFY_ARE_EQUAL(v[1].sPath, "file4.txt"); + VERIFY_ARE_EQUAL(v[1].fZeroWriteBuffers, false); + VERIFY_ARE_EQUAL(v[1].ullFileSize, 300); + } + + } + + void IORequestGeneratorUnitTests::Test_GetFilesToPrecreate2() + { + Target target1; + target1.SetPath("file1.txt"); + target1.SetFileSize(100); + + Target target2; + target2.SetPath("file2.txt"); + target2.SetFileSize(160); + + Target target3; + target3.SetPath("file1.txt"); + target3.SetFileSize(150); + + Target target4; + target4.SetPath("file2.txt"); + target4.SetFileSize(200); + + + TimeSpan timeSpan1; + TimeSpan timeSpan2; + timeSpan1.AddTarget(target1); + timeSpan1.AddTarget(target2); + timeSpan2.AddTarget(target3); + timeSpan2.AddTarget(target4); + + Profile profile; + profile.AddTimeSpan(timeSpan1); + profile.AddTimeSpan(timeSpan2); + + profile.SetPrecreateFiles(PrecreateFiles::UseMaxSize); + IORequestGenerator io; + vector v = io._GetFilesToPrecreate(profile); + VERIFY_ARE_EQUAL(v.size(), (size_t)2); + + VERIFY_ARE_EQUAL(v[0].sPath, "file1.txt"); + VERIFY_ARE_EQUAL(v[0].fZeroWriteBuffers, false); + VERIFY_ARE_EQUAL(v[0].ullFileSize, 150); + + VERIFY_ARE_EQUAL(v[1].sPath, "file2.txt"); + VERIFY_ARE_EQUAL(v[1].fZeroWriteBuffers, false); + VERIFY_ARE_EQUAL(v[1].ullFileSize, 200); + } + + void IORequestGeneratorUnitTests::Test_GetFilesToPrecreateConstantSizes() + { + Target target1; + target1.SetPath("file1.txt"); + + Target target2; + target2.SetPath("file1.txt"); + target2.SetFileSize(160); + + TimeSpan timeSpan1; + timeSpan1.AddTarget(target1); + timeSpan1.AddTarget(target2); + + Profile profile; + profile.AddTimeSpan(timeSpan1); + + profile.SetPrecreateFiles(PrecreateFiles::OnlyFilesWithConstantSizes); + IORequestGenerator io; + vector v = io._GetFilesToPrecreate(profile); + VERIFY_ARE_EQUAL(v.size(), (size_t)0); + } + + void IORequestGeneratorUnitTests::Test_GetFilesToPrecreateConstantOrZeroSizes() + { + Target target1; + target1.SetPath("file1.txt"); + + Target target2; + target2.SetPath("file1.txt"); + target2.SetFileSize(160); + + TimeSpan timeSpan1; + timeSpan1.AddTarget(target1); + timeSpan1.AddTarget(target2); + + Profile profile; + profile.AddTimeSpan(timeSpan1); + + profile.SetPrecreateFiles(PrecreateFiles::OnlyFilesWithConstantOrZeroSizes); + IORequestGenerator io; + vector v = io._GetFilesToPrecreate(profile); + VERIFY_ARE_EQUAL(v.size(), (size_t)1); + VERIFY_ARE_EQUAL(v[0].sPath, "file1.txt"); + VERIFY_ARE_EQUAL(v[0].fZeroWriteBuffers, false); + VERIFY_ARE_EQUAL(v[0].ullFileSize, 160); + } + + void IORequestGeneratorUnitTests::Test_GetFilesToPrecreateUseMaxSize() + { + Target target1; + target1.SetPath("file1.txt"); + + Target target2; + target2.SetPath("file1.txt"); + + TimeSpan timeSpan1; + timeSpan1.AddTarget(target1); + timeSpan1.AddTarget(target2); + + Profile profile; + profile.AddTimeSpan(timeSpan1); + + profile.SetPrecreateFiles(PrecreateFiles::UseMaxSize); + IORequestGenerator io; + vector v = io._GetFilesToPrecreate(profile); + VERIFY_ARE_EQUAL(v.size(), (size_t)0); + } + + void IORequestGeneratorUnitTests::Test_GetNextFileOffsetRandom() + { + Target target; + target.SetBaseFileOffsetInBytes(1000); + target.SetBlockAlignmentInBytes(500); + target.SetBlockSizeInBytes(1000); + target.SetRandomRatio(100); + + Random r; + ThreadParameters tp; + tp.pRand = &r; + tp.vTargets.push_back(target); + + TimeSpan timespan; + tp.pTimeSpan = ×pan; + + ThreadTargetState tts(&tp, 0, 3000); + IORequest ior(tp.pRand); + + ULARGE_INTEGER nextOffset; + + for( int i = 0; i < 10; ++i ) + { + tts.NextIORequest(ior); + nextOffset.LowPart = ior.GetOverlapped()->Offset; + nextOffset.HighPart = ior.GetOverlapped()->OffsetHigh; + + VERIFY_IS_GREATER_THAN_OR_EQUAL(nextOffset.QuadPart, 1000); + VERIFY_IS_LESS_THAN_OR_EQUAL(nextOffset.QuadPart, 2000); + VERIFY_ARE_EQUAL(nextOffset.QuadPart % 500, 0); + } + } + + void IORequestGeneratorUnitTests::Test_GetNextFileOffsetSequential() + { + Target target; + target.SetBaseFileOffsetInBytes(1000); + target.SetBlockAlignmentInBytes(500); + target.SetBlockSizeInBytes(1000); + + Random r; + ThreadParameters tp; + tp.pRand = &r; + tp.vTargets.push_back(target); + + TimeSpan timespan; + tp.pTimeSpan = ×pan; + + ThreadTargetState tts(&tp, 0, 3000); + IORequest ior(tp.pRand); + + ULARGE_INTEGER nextOffset; + + tts.NextIORequest(ior); + nextOffset.LowPart = ior.GetOverlapped()->Offset; + nextOffset.HighPart = ior.GetOverlapped()->OffsetHigh; + VERIFY_ARE_EQUAL(nextOffset.QuadPart, 1000); + tts.NextIORequest(ior); + nextOffset.LowPart = ior.GetOverlapped()->Offset; + nextOffset.HighPart = ior.GetOverlapped()->OffsetHigh; + VERIFY_ARE_EQUAL(nextOffset.QuadPart, 1500); + tts.NextIORequest(ior); + nextOffset.LowPart = ior.GetOverlapped()->Offset; + nextOffset.HighPart = ior.GetOverlapped()->OffsetHigh; + VERIFY_ARE_EQUAL(nextOffset.QuadPart, 2000); + tts.NextIORequest(ior); + nextOffset.LowPart = ior.GetOverlapped()->Offset; + nextOffset.HighPart = ior.GetOverlapped()->OffsetHigh; + VERIFY_ARE_EQUAL(nextOffset.QuadPart, 1000); + } + + void IORequestGeneratorUnitTests::Test_GetNextFileOffsetInterlockedSequential() + { + Target target; + target.SetBaseFileOffsetInBytes(1000); + target.SetBlockAlignmentInBytes(500); + target.SetBlockSizeInBytes(1000); + target.SetUseInterlockedSequential(true); + + Random r; + ThreadParameters tp1; + ThreadParameters tp2; + tp1.pRand = &r; + tp2.pRand = &r; + + UINT64 sharedIndex = 0; + tp1.pullSharedSequentialOffsets = &sharedIndex; + tp2.pullSharedSequentialOffsets = &sharedIndex; + + tp1.vTargets.push_back(target); + tp2.vTargets.push_back(target); + + TimeSpan timespan; + timespan.SetThreadCount(2); + + tp1.pTimeSpan = ×pan; + tp2.pTimeSpan = ×pan; + + ThreadTargetState tts1(&tp1, 0, 3000); + ThreadTargetState tts2(&tp2, 0, 3000); + IORequest ior(tp1.pRand); + + ULARGE_INTEGER nextOffset; + + // begin at base + // thread 2 jumps in and continues the pattern (despite FIRST_OFFSET) + // note that blocksize is 1000, so we loop back at 2000 + tts1.NextIORequest(ior); + nextOffset.LowPart = ior.GetOverlapped()->Offset; + nextOffset.HighPart = ior.GetOverlapped()->OffsetHigh; + VERIFY_ARE_EQUAL(nextOffset.QuadPart, 1000); + tts1.NextIORequest(ior); + nextOffset.LowPart = ior.GetOverlapped()->Offset; + nextOffset.HighPart = ior.GetOverlapped()->OffsetHigh; + VERIFY_ARE_EQUAL(nextOffset.QuadPart, 1500); + tts2.NextIORequest(ior); + nextOffset.LowPart = ior.GetOverlapped()->Offset; + nextOffset.HighPart = ior.GetOverlapped()->OffsetHigh; + VERIFY_ARE_EQUAL(nextOffset.QuadPart, 2000); + tts1.NextIORequest(ior); + nextOffset.LowPart = ior.GetOverlapped()->Offset; + nextOffset.HighPart = ior.GetOverlapped()->OffsetHigh; + VERIFY_ARE_EQUAL(nextOffset.QuadPart, 1000); + tts2.NextIORequest(ior); + nextOffset.LowPart = ior.GetOverlapped()->Offset; + nextOffset.HighPart = ior.GetOverlapped()->OffsetHigh; + VERIFY_ARE_EQUAL(nextOffset.QuadPart, 1500); + } + + void IORequestGeneratorUnitTests::Test_GetNextFileOffsetParallelAsyncIO() + { + Target target; + target.SetBaseFileOffsetInBytes(1000); + target.SetBlockAlignmentInBytes(500); + target.SetBlockSizeInBytes(1000); + target.SetUseParallelAsyncIO(true); + + Random r; + ThreadParameters tp; + tp.pRand = &r; + tp.vTargets.push_back(target); + + TimeSpan timespan; + tp.pTimeSpan = ×pan; + + ThreadTargetState tts(&tp, 0, 3000); + IORequest ior(tp.pRand); + + ULARGE_INTEGER nextOffset; + + { + UINT64 aOff[] = { 1000, 1500, 2000, 1000, 1500 }; + vector vOff(aOff, aOff + _countof(aOff)); + + tts.InitializeParallelAsyncIORequest(ior); + tts.NextIORequest(ior); + for (auto off : vOff) + { + nextOffset.LowPart = ior.GetOverlapped()->Offset; + nextOffset.HighPart = ior.GetOverlapped()->OffsetHigh; + VERIFY_ARE_EQUAL(nextOffset.QuadPart, off, L"case 1"); + tts.NextIORequest(ior); + } + } + } + + void IORequestGeneratorUnitTests::Test_GetThreadBaseFileOffset() + { + Random r; + ThreadParameters tp; + Target target; + + tp.pRand = &r; + target.SetBaseFileOffsetInBytes(1000); + target.SetBlockAlignmentInBytes(500); + target.SetBlockSizeInBytes(1000); + tp.vTargets.push_back(target); + tp.vTargets.push_back(target); + + UINT64 startingOffset; + + // normal sequential - both threads, each file at base + tp.vTargets[0].SetRandomRatio(0); + tp.vTargets[1].SetRandomRatio(0); + + tp.ulThreadNo = 0; + tp.ulRelativeThreadNo = 0; + startingOffset = tp.vTargets[0].GetThreadBaseFileOffsetInBytes(tp.ulRelativeThreadNo); + VERIFY_ARE_EQUAL(startingOffset, 1000, L"sequential"); + startingOffset = tp.vTargets[1].GetThreadBaseFileOffsetInBytes(tp.ulRelativeThreadNo); + VERIFY_ARE_EQUAL(startingOffset, 1000, L"sequential"); + + tp.ulThreadNo = 1; + tp.ulRelativeThreadNo = 1; + startingOffset = tp.vTargets[0].GetThreadBaseFileOffsetInBytes(tp.ulRelativeThreadNo); + VERIFY_ARE_EQUAL(startingOffset, 1000, L"sequential"); + startingOffset = tp.vTargets[1].GetThreadBaseFileOffsetInBytes(tp.ulRelativeThreadNo); + VERIFY_ARE_EQUAL(startingOffset, 1000, L"sequential"); + + // interlocked seq - both threads, each file at base + tp.vTargets[0].SetUseInterlockedSequential(true); + tp.vTargets[1].SetUseInterlockedSequential(true); + + tp.ulThreadNo = 0; + tp.ulRelativeThreadNo = 0; + startingOffset = tp.vTargets[0].GetThreadBaseFileOffsetInBytes(tp.ulRelativeThreadNo); + VERIFY_ARE_EQUAL(startingOffset, 1000, L"interlocked sequential"); + startingOffset = tp.vTargets[1].GetThreadBaseFileOffsetInBytes(tp.ulRelativeThreadNo); + VERIFY_ARE_EQUAL(startingOffset, 1000, L"interlocked sequential"); + + tp.ulThreadNo = 1; + tp.ulRelativeThreadNo = 1; + startingOffset = tp.vTargets[0].GetThreadBaseFileOffsetInBytes(tp.ulRelativeThreadNo); + VERIFY_ARE_EQUAL(startingOffset, 1000, L"interlocked sequential"); + startingOffset = tp.vTargets[1].GetThreadBaseFileOffsetInBytes(tp.ulRelativeThreadNo); + VERIFY_ARE_EQUAL(startingOffset, 1000, L"interlocked sequential"); + + tp.vTargets[0].SetUseInterlockedSequential(false); + tp.vTargets[1].SetUseInterlockedSequential(false); + + // parallel async seq - both threads, each file at base + tp.vTargets[0].SetUseParallelAsyncIO(true); + tp.vTargets[1].SetUseParallelAsyncIO(true); + + tp.ulThreadNo = 0; + tp.ulRelativeThreadNo = 0; + startingOffset = tp.vTargets[0].GetThreadBaseFileOffsetInBytes(tp.ulRelativeThreadNo); + VERIFY_ARE_EQUAL(startingOffset, 1000, L"parasync sequential"); + startingOffset = tp.vTargets[1].GetThreadBaseFileOffsetInBytes(tp.ulRelativeThreadNo); + VERIFY_ARE_EQUAL(startingOffset, 1000, L"parasync sequential"); + + tp.ulThreadNo = 1; + tp.ulRelativeThreadNo = 1; + startingOffset = tp.vTargets[0].GetThreadBaseFileOffsetInBytes(tp.ulRelativeThreadNo); + VERIFY_ARE_EQUAL(startingOffset, 1000, L"parasync sequential"); + startingOffset = tp.vTargets[1].GetThreadBaseFileOffsetInBytes(tp.ulRelativeThreadNo); + VERIFY_ARE_EQUAL(startingOffset, 1000, L"parasync sequential"); + } + + void IORequestGeneratorUnitTests::Test_GetThreadBaseFileOffsetWithStride() + { + Random r; + ThreadParameters tp; + Target target; + + tp.pRand = &r; + target.SetBaseFileOffsetInBytes(1000); + target.SetBlockAlignmentInBytes(500); + target.SetBlockSizeInBytes(1000); + target.SetThreadStrideInBytes(5000); + tp.vTargets.push_back(target); + target.SetThreadStrideInBytes(50000); + tp.vTargets.push_back(target); + + UINT64 startingOffset; + + // normal sequential - first at base, second with stride + tp.vTargets[0].SetRandomRatio(0); + tp.vTargets[1].SetRandomRatio(0); + + tp.ulThreadNo = 0; + tp.ulRelativeThreadNo = 0; + startingOffset = tp.vTargets[0].GetThreadBaseFileOffsetInBytes(tp.ulRelativeThreadNo); + VERIFY_ARE_EQUAL(startingOffset, 1000, L"sequential"); + startingOffset = tp.vTargets[1].GetThreadBaseFileOffsetInBytes(tp.ulRelativeThreadNo); + VERIFY_ARE_EQUAL(startingOffset, 1000, L"sequential"); + + tp.ulThreadNo = 1; + tp.ulRelativeThreadNo = 1; + startingOffset = tp.vTargets[0].GetThreadBaseFileOffsetInBytes(tp.ulRelativeThreadNo); + VERIFY_ARE_EQUAL(startingOffset, 6000, L"sequential"); + startingOffset = tp.vTargets[1].GetThreadBaseFileOffsetInBytes(tp.ulRelativeThreadNo); + VERIFY_ARE_EQUAL(startingOffset, 51000, L"sequential"); + + // note: unaffected by ulThreadNo + tp.ulRelativeThreadNo = 2; + startingOffset = tp.vTargets[0].GetThreadBaseFileOffsetInBytes(tp.ulRelativeThreadNo); + VERIFY_ARE_EQUAL(startingOffset, 11000, L"sequential"); + startingOffset = tp.vTargets[1].GetThreadBaseFileOffsetInBytes(tp.ulRelativeThreadNo); + VERIFY_ARE_EQUAL(startingOffset, 101000, L"sequential"); + + // parallel async seq - first at base, second with stride + tp.vTargets[0].SetUseParallelAsyncIO(true); + tp.vTargets[1].SetUseParallelAsyncIO(true); + + tp.ulThreadNo = 0; + tp.ulRelativeThreadNo = 0; + startingOffset = tp.vTargets[0].GetThreadBaseFileOffsetInBytes(tp.ulRelativeThreadNo); + VERIFY_ARE_EQUAL(startingOffset, 1000, L"parasync sequential"); + startingOffset = tp.vTargets[1].GetThreadBaseFileOffsetInBytes(tp.ulRelativeThreadNo); + VERIFY_ARE_EQUAL(startingOffset, 1000, L"parasync sequential"); + + tp.ulThreadNo = 1; + tp.ulRelativeThreadNo = 1; + startingOffset = tp.vTargets[0].GetThreadBaseFileOffsetInBytes(tp.ulRelativeThreadNo); + VERIFY_ARE_EQUAL(startingOffset, 6000, L"parasync sequential"); + startingOffset = tp.vTargets[1].GetThreadBaseFileOffsetInBytes(tp.ulRelativeThreadNo); + VERIFY_ARE_EQUAL(startingOffset, 51000, L"parasync sequential"); + + // note: unaffected by ulThreadNo + tp.ulRelativeThreadNo = 2; + startingOffset = tp.vTargets[0].GetThreadBaseFileOffsetInBytes(tp.ulRelativeThreadNo); + VERIFY_ARE_EQUAL(startingOffset, 11000, L"parasync sequential"); + startingOffset = tp.vTargets[1].GetThreadBaseFileOffsetInBytes(tp.ulRelativeThreadNo); + VERIFY_ARE_EQUAL(startingOffset, 101000, L"parasync sequential"); + + // interlocked seq - both threads, each file at base + tp.vTargets[0].SetUseInterlockedSequential(true); + tp.vTargets[1].SetUseInterlockedSequential(true); + + // note that thread stride is not permitted with interlocked seq + // this is handled in profile validation + tp.vTargets[0].SetThreadStrideInBytes(0); + tp.vTargets[1].SetThreadStrideInBytes(0); + + tp.ulThreadNo = 0; + tp.ulRelativeThreadNo = 0; + startingOffset = tp.vTargets[0].GetThreadBaseFileOffsetInBytes(tp.ulRelativeThreadNo); + VERIFY_ARE_EQUAL(startingOffset, 1000, L"interlocked sequential"); + startingOffset = tp.vTargets[1].GetThreadBaseFileOffsetInBytes(tp.ulRelativeThreadNo); + VERIFY_ARE_EQUAL(startingOffset, 1000, L"interlocked sequential"); + + tp.ulThreadNo = 1; + tp.ulRelativeThreadNo = 1; + startingOffset = tp.vTargets[0].GetThreadBaseFileOffsetInBytes(tp.ulRelativeThreadNo); + VERIFY_ARE_EQUAL(startingOffset, 1000, L"interlocked sequential"); + startingOffset = tp.vTargets[1].GetThreadBaseFileOffsetInBytes(tp.ulRelativeThreadNo); + VERIFY_ARE_EQUAL(startingOffset, 1000, L"interlocked sequential"); + } + + void IORequestGeneratorUnitTests::Test_SequentialWithStrideInterleaved() + { + // this ut handles the case where -T < -s + + Target target; + target.SetThreadStrideInBytes(250); + target.SetBlockAlignmentInBytes(500); + target.SetBlockSizeInBytes(1000); + + Random r; + ThreadParameters tp; + tp.pRand = &r; + tp.vTargets.push_back(target); + + // this is equivalent to -c3000 -T250 -s500 -b1000 + + ThreadTargetState tts(&tp, 0, 3000); + IORequest ior(tp.pRand); + + ULARGE_INTEGER nextOffset; + + // relative thread zero should loop back to base + tp.ulThreadNo = 0; + tp.ulRelativeThreadNo = 0; + { + UINT64 aOff[] = { 0, 500, 1000, 1500, 2000, 0, 500 }; + vector vOff(aOff, aOff + _countof(aOff)); + + tts.NextIORequest(ior); + for (auto off : vOff) + { + nextOffset.LowPart = ior.GetOverlapped()->Offset; + nextOffset.HighPart = ior.GetOverlapped()->OffsetHigh; + VERIFY_ARE_EQUAL(nextOffset.QuadPart, off, L"case 1"); + tts.NextIORequest(ior); + } + } + + // relative thread one should loop back directly to initial offset + // it will also detect and handle not issuing an IO spanning eof. + tp.ulThreadNo = 1; + tp.ulRelativeThreadNo = 1; + tts.Reset(); + { + UINT64 aOff[] = { 250, 750, 1250, 1750, 250, 750 }; + vector vOff(aOff, aOff + _countof(aOff)); + + tts.NextIORequest(ior); + for (auto off : vOff) + { + nextOffset.LowPart = ior.GetOverlapped()->Offset; + nextOffset.HighPart = ior.GetOverlapped()->OffsetHigh; + VERIFY_ARE_EQUAL(nextOffset.QuadPart, off, L"case 2"); + tts.NextIORequest(ior); + } + } + + // increasing the stride, relative thread one will loop back to an earlier offset + // before returning to its initial offset + tp.vTargets[0].SetThreadStrideInBytes(750); + tts.Reset(); + { + UINT64 aOff[] = { 750, 1250, 1750, 250, 750, 1250 }; + vector vOff(aOff, aOff + _countof(aOff)); + + tts.NextIORequest(ior); + for (auto off : vOff) + { + nextOffset.LowPart = ior.GetOverlapped()->Offset; + nextOffset.HighPart = ior.GetOverlapped()->OffsetHigh; + VERIFY_ARE_EQUAL(nextOffset.QuadPart, off, L"case 3"); + tts.NextIORequest(ior); + } + } + } + + void IORequestGeneratorUnitTests::Test_SequentialWithStride() + { + // this ut handles the case where -T > -s + + Target target; + target.SetThreadStrideInBytes(500); + target.SetBlockAlignmentInBytes(250); + target.SetBlockSizeInBytes(1000); + + Random r; + ThreadParameters tp; + tp.pRand = &r; + tp.vTargets.push_back(target); + + // this is equivalent to -c3000 -T500 -s250 -b1000 + + ThreadTargetState tts(&tp, 0, 3000); + IORequest ior(tp.pRand); + + ULARGE_INTEGER nextOffset; + + // relative thread zero should loop back to base + tp.ulThreadNo = 0; + tp.ulRelativeThreadNo = 0; + { + UINT64 aOff[] = { 0, 250, 500, 750, 1000, 1250, 1500, 1750, 2000, 0, 250, 500, 750, 1000, 1250, 1500, 1750, 2000 }; + vector vOff(aOff, aOff + _countof(aOff)); + + tts.NextIORequest(ior); + for (auto off : vOff) + { + nextOffset.LowPart = ior.GetOverlapped()->Offset; + nextOffset.HighPart = ior.GetOverlapped()->OffsetHigh; + VERIFY_ARE_EQUAL(nextOffset.QuadPart, off, L"case 1"); + tts.NextIORequest(ior); + } + } + + // relative thread one should also loop back to base + tp.ulThreadNo = 1; + tp.ulRelativeThreadNo = 1; + tts.Reset(); + { + UINT64 aOff[] = { 500, 750, 1000, 1250, 1500, 1750, 2000, 0, 250, 500, 750, 1000, 1250, 1500, 1750, 2000 }; + vector vOff(aOff, aOff + _countof(aOff)); + + tts.NextIORequest(ior); + for (auto off : vOff) + { + nextOffset.LowPart = ior.GetOverlapped()->Offset; + nextOffset.HighPart = ior.GetOverlapped()->OffsetHigh; + VERIFY_ARE_EQUAL(nextOffset.QuadPart, off, L"case 2"); + tts.NextIORequest(ior); + } + } + } + + void IORequestGeneratorUnitTests::Test_SequentialWithStrideUneven() + { + // this ut handles the case where -T > -s and -T is not a multiple of -s + // threads io offsets are disjoint + + Target target; + target.SetThreadStrideInBytes(500); + target.SetBlockAlignmentInBytes(200); + target.SetBlockSizeInBytes(200); + + Random r; + ThreadParameters tp; + tp.pRand = &r; + tp.vTargets.push_back(target); + + // this is equivalent to -c3000 -T500 -s200 -b200 + + ThreadTargetState tts(&tp, 0, 3000); + IORequest ior(tp.pRand); + + ULARGE_INTEGER nextOffset; + + // relative thread zero should loop back to base + tp.ulThreadNo = 0; + tp.ulRelativeThreadNo = 0; + { + UINT64 aOff[] = { 0, 200, 400, 600, 800, 1000, 1200, 1400, 1600, 1800, 2000, 2200, 2400, 2600, 2800, 0, 200, 400 }; + vector vOff(aOff, aOff + _countof(aOff)); + + tts.NextIORequest(ior); + for (auto off : vOff) + { + nextOffset.LowPart = ior.GetOverlapped()->Offset; + nextOffset.HighPart = ior.GetOverlapped()->OffsetHigh; + VERIFY_ARE_EQUAL(nextOffset.QuadPart, off, L"case 1"); + tts.NextIORequest(ior); + } + } + + // relative thread one should also loop back to base + tp.ulThreadNo = 1; + tp.ulRelativeThreadNo = 1; + tts.Reset(); + { + UINT64 aOff[] = { 500, 700, 900, 1100, 1300, 1500, 1700, 1900, 2100, 2300, 2500, 2700, 100, 300, 500, 700, 900 }; + vector vOff(aOff, aOff + _countof(aOff)); + + tts.NextIORequest(ior); + for (auto off : vOff) + { + nextOffset.LowPart = ior.GetOverlapped()->Offset; + nextOffset.HighPart = ior.GetOverlapped()->OffsetHigh; + VERIFY_ARE_EQUAL(nextOffset.QuadPart, off, L"case 2"); + tts.NextIORequest(ior); + } + } + } + + void IORequestGeneratorUnitTests::Test_ThreadTargetStateInit() + { + // this ut validates that a constructed ThreadTargetState + // has an initialized IO type, and that it will then agree + // with the first generated IO's type for homegenous/mixed + // write mixes. + + Target target; + target.SetThreadStrideInBytes(500); + target.SetBlockAlignmentInBytes(200); + target.SetBlockSizeInBytes(200); + + Random r; + ThreadParameters tp; + tp.pRand = &r; + tp.vTargets.push_back(target); + + UINT32 writeMix[] = { 0, 50, 100 }; + vector vwriteMix(writeMix, writeMix + _countof(writeMix)); + + for (auto w : vwriteMix) + { + target.SetWriteRatio(w); + + // Validate that ThreadTargetState defines last IO type in all running modes + + VERIFY_ARE_EQUAL(target.GetIOMode(), IOMode::Sequential); + { + ThreadTargetState tts(&tp, 0, 3000); + VERIFY_ARE_NOT_EQUAL(tts._lastIO, IOOperation::Unknown); + IORequest ior(tp.pRand); + VERIFY_ARE_EQUAL(tts._lastIO, ior.GetIoType()); + } + // nothing to undo + + target.SetUseInterlockedSequential(true); + VERIFY_ARE_EQUAL(target.GetIOMode(), IOMode::InterlockedSequential); + { + ThreadTargetState tts(&tp, 0, 3000); + VERIFY_ARE_NOT_EQUAL(tts._lastIO, IOOperation::Unknown); + IORequest ior(tp.pRand); + VERIFY_ARE_EQUAL(tts._lastIO, ior.GetIoType()); + } + target.SetUseInterlockedSequential(false); + + target.SetRandomRatio(50); + VERIFY_ARE_EQUAL(target.GetIOMode(), IOMode::Mixed); + { + ThreadTargetState tts(&tp, 0, 3000); + VERIFY_ARE_NOT_EQUAL(tts._lastIO, IOOperation::Unknown); + IORequest ior(tp.pRand); + VERIFY_ARE_EQUAL(tts._lastIO, ior.GetIoType()); + } + target.SetRandomRatio(0); + + target.SetRandomRatio(100); + VERIFY_ARE_EQUAL(target.GetIOMode(), IOMode::Random); + { + ThreadTargetState tts(&tp, 0, 3000); + VERIFY_ARE_NOT_EQUAL(tts._lastIO, IOOperation::Unknown); + IORequest ior(tp.pRand); + VERIFY_ARE_EQUAL(tts._lastIO, ior.GetIoType()); + } + target.SetRandomRatio(0); + + target.SetUseParallelAsyncIO(true); + VERIFY_ARE_EQUAL(target.GetIOMode(), IOMode::ParallelAsync); + { + ThreadTargetState tts(&tp, 0, 3000); + VERIFY_ARE_NOT_EQUAL(tts._lastIO, IOOperation::Unknown); + IORequest ior(tp.pRand); + VERIFY_ARE_EQUAL(tts._lastIO, ior.GetIoType()); + } + target.SetUseParallelAsyncIO(false); + } + } + + void IORequestGeneratorUnitTests::Test_ThreadTargetStateEffectiveDistPct() + { + // this ut validates that a constructed ThreadTargetState + // has a properly laid out effective distribution given + // the specified percent distribution on the target. + // + // basic cases: + // hole + // degenerate span (covers no offsets) + // rollover to next (degenerate is not last in dist) + // apply to last (degenerate is last in dist) + + Target target; + target.SetBlockAlignmentInBytes(4*KB); + target.SetBlockSizeInBytes(4*KB); + + Random r; + ThreadParameters tp; + tp.pRand = &r; + + vector v; + + // -rdpct10/10:10/10:0/10 + tail + // this is the same distribution in the cmdlineparser UT + v.emplace_back(0, 10, make_pair(0, 10)); + v.emplace_back(10, 10, make_pair(10, 10)); + v.emplace_back(20, 0, make_pair(20, 10)); // zero IO% length hole + v.emplace_back(20, 80, make_pair(30, 70)); + target.SetDistributionRange(v, DistributionType::Percent); + tp.vTargets.push_back(target); + + { + ThreadTargetState tts(&tp, 0, 100*KB); + vector& ev = tts._vDistributionRange; + + VERIFY_ARE_EQUAL(tts._ioDistributionSpan, (UINT32) 100); + VERIFY_ARE_EQUAL(tts._vDistributionRange.size(), (size_t) 3); + VERIFY_ARE_EQUAL(ev[0]._src, (UINT64) 0); + VERIFY_ARE_EQUAL(ev[0]._span, (UINT64) 10); + VERIFY_ARE_EQUAL(ev[0]._dst.first, (UINT64) 0); + VERIFY_ARE_EQUAL(ev[0]._dst.second, (UINT64) 8*KB); + VERIFY_ARE_EQUAL(ev[1]._src, (UINT64) 10); /// + VERIFY_ARE_EQUAL(ev[1]._span, (UINT64) 10); + VERIFY_ARE_EQUAL(ev[1]._dst.first, (UINT64) 8*KB); + VERIFY_ARE_EQUAL(ev[1]._dst.second, (UINT64) 12*KB); // note length + // note hole removed + VERIFY_ARE_EQUAL(ev[2]._src, (UINT64) 20); /// + VERIFY_ARE_EQUAL(ev[2]._span, (UINT64) 80); + VERIFY_ARE_EQUAL(ev[2]._dst.first, (UINT64) 28*KB); + VERIFY_ARE_EQUAL(ev[2]._dst.second, (UINT64) 72*KB); + tp.vTargets.clear(); + v.clear(); + } + + // + // Degenerate span cases + // + + // -rdpct10/10:10/10:10/1 + tail + // this creates the degenerate - non-degenerate case where + // the non-degenerate must round up. + v.emplace_back(0, 10, make_pair(0, 10)); + v.emplace_back(10, 10, make_pair(10, 10)); + v.emplace_back(20, 10, make_pair(20, 1)); // degenerate < alignment + v.emplace_back(30, 70, make_pair(21, 79)); + target.SetDistributionRange(v, DistributionType::Percent); + tp.vTargets.push_back(target); + + { + ThreadTargetState tts(&tp, 0, 100*KB); + vector& ev = tts._vDistributionRange; + + VERIFY_ARE_EQUAL(tts._ioDistributionSpan, (UINT32) 100); + VERIFY_ARE_EQUAL(tts._vDistributionRange.size(), (size_t) 4); + VERIFY_ARE_EQUAL(ev[0]._src, (UINT64) 0); + VERIFY_ARE_EQUAL(ev[0]._span, (UINT64) 10); + VERIFY_ARE_EQUAL(ev[0]._dst.first, (UINT64) 0); + VERIFY_ARE_EQUAL(ev[0]._dst.second, (UINT64) 8*KB); + VERIFY_ARE_EQUAL(ev[1]._src, (UINT64) 10); /// + VERIFY_ARE_EQUAL(ev[1]._span, (UINT64) 10); + VERIFY_ARE_EQUAL(ev[1]._dst.first, (UINT64) 8*KB); + VERIFY_ARE_EQUAL(ev[1]._dst.second, (UINT64) 12*KB); + VERIFY_ARE_EQUAL(ev[2]._src, (UINT64) 20); /// degenerate + VERIFY_ARE_EQUAL(ev[2]._span, (UINT64) 10); + VERIFY_ARE_EQUAL(ev[2]._dst.first, (UINT64) 20*KB); + VERIFY_ARE_EQUAL(ev[2]._dst.second, (UINT64) 4*KB); + VERIFY_ARE_EQUAL(ev[3]._src, (UINT64) 30); /// + VERIFY_ARE_EQUAL(ev[3]._span, (UINT64) 70); + VERIFY_ARE_EQUAL(ev[3]._dst.first, (UINT64) 24*KB); + VERIFY_ARE_EQUAL(ev[3]._dst.second, (UINT64) 76*KB); + tp.vTargets.clear(); + v.clear(); + } + + // -rdpct10/96:10/3:80/1 + // tail is degenerate and needs to roll to last + v.emplace_back(0, 10, make_pair(0, 96)); + v.emplace_back(10, 10, make_pair(96, 3)); + v.emplace_back(20, 80, make_pair(99, 1)); // degenerate tail + target.SetDistributionRange(v, DistributionType::Percent); + tp.vTargets.push_back(target); + + { + ThreadTargetState tts(&tp, 0, 100*KB); + vector& ev = tts._vDistributionRange; + + VERIFY_ARE_EQUAL(tts._ioDistributionSpan, (UINT32) 100); + VERIFY_ARE_EQUAL(tts._vDistributionRange.size(), (size_t) 2); + VERIFY_ARE_EQUAL(ev[0]._src, (UINT64) 0); + VERIFY_ARE_EQUAL(ev[0]._span, (UINT64) 10); + VERIFY_ARE_EQUAL(ev[0]._dst.first, (UINT64) 0); + VERIFY_ARE_EQUAL(ev[0]._dst.second, (UINT64) 96*KB); + VERIFY_ARE_EQUAL(ev[1]._src, (UINT64) 10); /// + VERIFY_ARE_EQUAL(ev[1]._span, (UINT64) 90); + VERIFY_ARE_EQUAL(ev[1]._dst.first, (UINT64) 96*KB); + VERIFY_ARE_EQUAL(ev[1]._dst.second, (UINT64) 4*KB); + tp.vTargets.clear(); + v.clear(); + } + + // -rdpct10/5:10/1:80/94 + // the degenerate cannot immediately combine with its non-degenerate predecessor, so rolls over + // however, since the predecessor is smaller, it prefers to combine in that direction + v.emplace_back(0, 10, make_pair(0, 5)); + v.emplace_back(10, 10, make_pair(5, 1)); + v.emplace_back(20, 80, make_pair(6, 94)); // non-degenerate tail + target.SetDistributionRange(v, DistributionType::Percent); + tp.vTargets.push_back(target); + + { + ThreadTargetState tts(&tp, 0, 100*KB); + vector& ev = tts._vDistributionRange; + + VERIFY_ARE_EQUAL(tts._ioDistributionSpan, (UINT32) 100); + VERIFY_ARE_EQUAL(tts._vDistributionRange.size(), (size_t) 2); + VERIFY_ARE_EQUAL(ev[0]._src, (UINT64) 0); + VERIFY_ARE_EQUAL(ev[0]._span, (UINT64) 20); + VERIFY_ARE_EQUAL(ev[0]._dst.first, (UINT64) 0); + VERIFY_ARE_EQUAL(ev[0]._dst.second, (UINT64) 4*KB); + VERIFY_ARE_EQUAL(ev[1]._src, (UINT64) 20); /// + VERIFY_ARE_EQUAL(ev[1]._span, (UINT64) 80); + VERIFY_ARE_EQUAL(ev[1]._dst.first, (UINT64) 4*KB); + VERIFY_ARE_EQUAL(ev[1]._dst.second, (UINT64) 96*KB); + tp.vTargets.clear(); + v.clear(); + } + + // -rdpct10/1:10/1 + // first two are degenerate and combine, tail rounds up and consumes rest + v.emplace_back(0, 10, make_pair(0, 1)); + v.emplace_back(10, 10, make_pair(1, 1)); + v.emplace_back(20, 80, make_pair(2, 98)); // non-degenerate tail + target.SetDistributionRange(v, DistributionType::Percent); + tp.vTargets.push_back(target); + + { + ThreadTargetState tts(&tp, 0, 100*KB); + vector& ev = tts._vDistributionRange; + + VERIFY_ARE_EQUAL(tts._ioDistributionSpan, (UINT32) 100); + VERIFY_ARE_EQUAL(tts._vDistributionRange.size(), (size_t) 2); + VERIFY_ARE_EQUAL(ev[0]._src, (UINT64) 0); + VERIFY_ARE_EQUAL(ev[0]._span, (UINT64) 20); + VERIFY_ARE_EQUAL(ev[0]._dst.first, (UINT64) 0); + VERIFY_ARE_EQUAL(ev[0]._dst.second, (UINT64) 4*KB); + VERIFY_ARE_EQUAL(ev[1]._src, (UINT64) 20); /// + VERIFY_ARE_EQUAL(ev[1]._span, (UINT64) 80); + VERIFY_ARE_EQUAL(ev[1]._dst.first, (UINT64) 4*KB); + VERIFY_ARE_EQUAL(ev[1]._dst.second, (UINT64) 96*KB); + tp.vTargets.clear(); + v.clear(); + } + + // repeated 10/1 + // This stresses the combination logic + // The first four should successively combine in a [0, 4KiB) range, the fifth + // will land in a new [4KiB,8KiB) range. + // + for (int n = 1; n <= 5; ++n) + { + int m; + for (m = 0; m < n; ++m) + { + v.emplace_back(m*10, 10, make_pair(m*1, 1)); + } + v.emplace_back(m*10, 100 - m*10, make_pair(m, 100 - m)); // non-degenerate tail + target.SetDistributionRange(v, DistributionType::Percent); + tp.vTargets.push_back(target); + + // Fifth case is three ranges; handle seperately. May be worth wrestling down + // how to combine these to allow us to sweep n further, but for now this is fine. + if (n == 5) + { + ThreadTargetState tts(&tp, 0, 100*KB); + vector& ev = tts._vDistributionRange; + + VERIFY_ARE_EQUAL(tts._ioDistributionSpan, (UINT32) 100); + VERIFY_ARE_EQUAL(tts._vDistributionRange.size(), (size_t) 3); + VERIFY_ARE_EQUAL(ev[0]._src, (UINT64) 0); + VERIFY_ARE_EQUAL(ev[0]._span, (UINT64) 40); + VERIFY_ARE_EQUAL(ev[0]._dst.first, (UINT64) 0); + VERIFY_ARE_EQUAL(ev[0]._dst.second, (UINT64) 4*KB); + VERIFY_ARE_EQUAL(ev[1]._src, (UINT64) 40); /// + VERIFY_ARE_EQUAL(ev[1]._span, (UINT64) 10); + VERIFY_ARE_EQUAL(ev[1]._dst.first, (UINT64) 4*KB); + VERIFY_ARE_EQUAL(ev[1]._dst.second, (UINT64) 4*KB); + VERIFY_ARE_EQUAL(ev[2]._src, (UINT64) 50); /// + VERIFY_ARE_EQUAL(ev[2]._span, (UINT64) 50); + VERIFY_ARE_EQUAL(ev[2]._dst.first, (UINT64) 8*KB); + VERIFY_ARE_EQUAL(ev[2]._dst.second, (UINT64) 92*KB); + tp.vTargets.clear(); + v.clear(); + break; + } + + { + ThreadTargetState tts(&tp, 0, 100*KB); + vector& ev = tts._vDistributionRange; + + VERIFY_ARE_EQUAL(tts._ioDistributionSpan, (UINT32) 100); + VERIFY_ARE_EQUAL(tts._vDistributionRange.size(), (size_t) 2); + VERIFY_ARE_EQUAL(ev[0]._src, (UINT64) 0); + VERIFY_ARE_EQUAL(ev[0]._span, (UINT64) m*10); + VERIFY_ARE_EQUAL(ev[0]._dst.first, (UINT64) 0); + VERIFY_ARE_EQUAL(ev[0]._dst.second, (UINT64) 4*KB); + VERIFY_ARE_EQUAL(ev[1]._src, (UINT64) m*10); /// + VERIFY_ARE_EQUAL(ev[1]._span, (UINT64) 100 - m*10); + VERIFY_ARE_EQUAL(ev[1]._dst.first, (UINT64) 4*KB); + VERIFY_ARE_EQUAL(ev[1]._dst.second, (UINT64) 96*KB); + tp.vTargets.clear(); + v.clear(); + } + } + } + + void IORequestGeneratorUnitTests::Test_ThreadTargetStateEffectiveDistAbs() + { + // this ut validates that a constructed ThreadTargetState + // has a properly laid out effective distribution given + // the specified absolute distribution on the target. + + Target target; + target.SetBlockAlignmentInBytes(4*KB); + target.SetBlockSizeInBytes(4*KB); + + Random r; + ThreadParameters tp; + + vector v; + + // -rdabs10/1G:10/1G:0/100G, again producing tail - with autoscale (0) + // this is the same distribution in the cmdlineparser UT + // aligned tail range + v.emplace_back(0,10, make_pair(0, 1*GB)); + v.emplace_back(10,10, make_pair(1*GB, 1*GB)); + v.emplace_back(20,0, make_pair(2*GB, 100*GB)); + v.emplace_back(20,80, make_pair(102*GB, 0)); + target.SetDistributionRange(v, DistributionType::Absolute); + tp.vTargets.push_back(target); + + { + ThreadTargetState tts(&tp, 0, 200*GB); + vector& ev = tts._vDistributionRange; + + VERIFY_ARE_EQUAL(tts._ioDistributionSpan, (UINT32) 100); + VERIFY_ARE_EQUAL(tts._vDistributionRange.size(), (size_t) 3); + VERIFY_ARE_EQUAL(ev[0]._src, (UINT64) 0); + VERIFY_ARE_EQUAL(ev[0]._span, (UINT64) 10); + VERIFY_ARE_EQUAL(ev[0]._dst.first, (UINT64) 0); + VERIFY_ARE_EQUAL(ev[0]._dst.second, (UINT64) 1*GB); + VERIFY_ARE_EQUAL(ev[1]._src, (UINT64) 10); /// + VERIFY_ARE_EQUAL(ev[1]._span, (UINT64) 10); + VERIFY_ARE_EQUAL(ev[1]._dst.first, (UINT64) 1*GB); + VERIFY_ARE_EQUAL(ev[1]._dst.second, (UINT64) 1*GB); // note length + // note hole removed + VERIFY_ARE_EQUAL(ev[2]._src, (UINT64) 20); /// + VERIFY_ARE_EQUAL(ev[2]._span, (UINT64) 80); + VERIFY_ARE_EQUAL(ev[2]._dst.first, (UINT64) 102*GB); + VERIFY_ARE_EQUAL(ev[2]._dst.second, (UINT64) 98*GB); + tp.vTargets.clear(); + v.clear(); + } + + // -rdabs10/1G:10/1G:0/100G:20/1T + // trim - distribution exceeds target size, end is in last range so no IO% trim + // note same distribution aside from hardening the tail (no autoscale) to a large value + v.emplace_back(0,10, make_pair(0, 1*GB)); + v.emplace_back(10,10, make_pair(1*GB, 1*GB)); + v.emplace_back(20,0, make_pair(2*GB, 100*GB)); + v.emplace_back(20,80, make_pair(102*GB, 1*TB)); + target.SetDistributionRange(v, DistributionType::Absolute); + tp.vTargets.push_back(target); + + { + ThreadTargetState tts(&tp, 0, 200*GB); + vector& ev = tts._vDistributionRange; + + VERIFY_ARE_EQUAL(tts._ioDistributionSpan, (UINT32) 100); + VERIFY_ARE_EQUAL(tts._vDistributionRange.size(), (size_t) 3); + VERIFY_ARE_EQUAL(ev[0]._src, (UINT64) 0); + VERIFY_ARE_EQUAL(ev[0]._span, (UINT64) 10); + VERIFY_ARE_EQUAL(ev[0]._dst.first, (UINT64) 0); + VERIFY_ARE_EQUAL(ev[0]._dst.second, (UINT64) 1*GB); + VERIFY_ARE_EQUAL(ev[1]._src, (UINT64) 10); /// + VERIFY_ARE_EQUAL(ev[1]._span, (UINT64) 10); + VERIFY_ARE_EQUAL(ev[1]._dst.first, (UINT64) 1*GB); + VERIFY_ARE_EQUAL(ev[1]._dst.second, (UINT64) 1*GB); // note length + // note hole removed + VERIFY_ARE_EQUAL(ev[2]._src, (UINT64) 20); /// + VERIFY_ARE_EQUAL(ev[2]._span, (UINT64) 80); + VERIFY_ARE_EQUAL(ev[2]._dst.first, (UINT64) 102*GB); + VERIFY_ARE_EQUAL(ev[2]._dst.second, (UINT64) 98*GB); + tp.vTargets.clear(); + v.clear(); + } + + // -rdabs10/100G:10/100G + // trim - distribution exceeds target size (autoscale tail); target end aligned to last range start + // drop the IO% of the trailing range + v.emplace_back(0,10, make_pair(0, 100*GB)); + v.emplace_back(10,10, make_pair(100*GB, 100*GB)); + v.emplace_back(20,80, make_pair(200*GB, 0)); + target.SetDistributionRange(v, DistributionType::Absolute); + tp.vTargets.push_back(target); + + { + ThreadTargetState tts(&tp, 0, 200*GB); + vector& ev = tts._vDistributionRange; + + VERIFY_ARE_EQUAL(tts._vDistributionRange.size(), (size_t) 2); + VERIFY_ARE_EQUAL(tts._ioDistributionSpan, (UINT32) 20); + VERIFY_ARE_EQUAL(ev[0]._src, (UINT64) 0); + VERIFY_ARE_EQUAL(ev[0]._span, (UINT64) 10); + VERIFY_ARE_EQUAL(ev[0]._dst.first, (UINT64) 0); + VERIFY_ARE_EQUAL(ev[0]._dst.second, (UINT64) 100*GB); + VERIFY_ARE_EQUAL(ev[1]._src, (UINT64) 10); /// + VERIFY_ARE_EQUAL(ev[1]._span, (UINT64) 10); + VERIFY_ARE_EQUAL(ev[1]._dst.first, (UINT64) 100*GB); + VERIFY_ARE_EQUAL(ev[1]._dst.second, (UINT64) 100*GB); // note length + tp.vTargets.clear(); + v.clear(); + } + + // -rdabs10/100G:10/200G + // trim - distribution exceeds target size (autoscale tail); last range beyond target end + // drop the IO% of the trailing range + v.emplace_back(0,10, make_pair(0, 100*GB)); + v.emplace_back(10,10, make_pair(100*GB, 200*GB)); + v.emplace_back(20,80, make_pair(300*GB, 0)); + target.SetDistributionRange(v, DistributionType::Absolute); + tp.vTargets.push_back(target); + + { + ThreadTargetState tts(&tp, 0, 200*GB); + vector& ev = tts._vDistributionRange; + + VERIFY_ARE_EQUAL(tts._vDistributionRange.size(), (size_t) 2); + VERIFY_ARE_EQUAL(tts._ioDistributionSpan, (UINT32) 20); + VERIFY_ARE_EQUAL(ev[0]._src, (UINT64) 0); + VERIFY_ARE_EQUAL(ev[0]._span, (UINT64) 10); + VERIFY_ARE_EQUAL(ev[0]._dst.first, (UINT64) 0); + VERIFY_ARE_EQUAL(ev[0]._dst.second, (UINT64) 100*GB); + VERIFY_ARE_EQUAL(ev[1]._src, (UINT64) 10); /// + VERIFY_ARE_EQUAL(ev[1]._span, (UINT64) 10); + VERIFY_ARE_EQUAL(ev[1]._dst.first, (UINT64) 100*GB); + VERIFY_ARE_EQUAL(ev[1]._dst.second, (UINT64) 100*GB); // note length + tp.vTargets.clear(); + v.clear(); + } + + // + // Unaligned intervals + // + + target.SetBlockAlignmentInBytes(3*KB); + target.SetBlockSizeInBytes(3*KB); + + // -rdabs10/10K:10/10K + // not naturally aligned to target, but is naturally aligned to interval (!) + // 0-10k and 10k-90k - IO all the way to 100K (97K + 3K) is OK + v.emplace_back(0,10, make_pair(0, 10*KB)); + v.emplace_back(10,10, make_pair(10*KB, 90*KB)); + v.emplace_back(20,80, make_pair(300*GB, 0)); + target.SetDistributionRange(v, DistributionType::Absolute); + tp.vTargets.push_back(target); + + { + ThreadTargetState tts(&tp, 0, 100*KB); + vector& ev = tts._vDistributionRange; + + VERIFY_ARE_EQUAL(tts._vDistributionRange.size(), (size_t) 2); + VERIFY_ARE_EQUAL(tts._ioDistributionSpan, (UINT32) 20); + VERIFY_ARE_EQUAL(ev[0]._src, (UINT64) 0); + VERIFY_ARE_EQUAL(ev[0]._span, (UINT64) 10); + VERIFY_ARE_EQUAL(ev[0]._dst.first, (UINT64) 0); + VERIFY_ARE_EQUAL(ev[0]._dst.second, (UINT64) 10*KB); + VERIFY_ARE_EQUAL(ev[1]._src, (UINT64) 10); /// + VERIFY_ARE_EQUAL(ev[1]._span, (UINT64) 10); + VERIFY_ARE_EQUAL(ev[1]._dst.first, (UINT64) 10*KB); + VERIFY_ARE_EQUAL(ev[1]._dst.second, (UINT64) 90*KB); // note length + tp.vTargets.clear(); + v.clear(); + } + + // -rdabs10/10K:10/1G + // previous distribution, target ends in last range (same result, trimmed) + v.emplace_back(0,10, make_pair(0, 10*KB)); + v.emplace_back(10,10, make_pair(10*KB, 90*KB)); + v.emplace_back(20,80, make_pair(300*GB, 0)); + target.SetDistributionRange(v, DistributionType::Absolute); + tp.vTargets.push_back(target); + + { + ThreadTargetState tts(&tp, 0, 100*KB); + vector& ev = tts._vDistributionRange; + + VERIFY_ARE_EQUAL(tts._vDistributionRange.size(), (size_t) 2); + VERIFY_ARE_EQUAL(tts._ioDistributionSpan, (UINT32) 20); + VERIFY_ARE_EQUAL(ev[0]._src, (UINT64) 0); + VERIFY_ARE_EQUAL(ev[0]._span, (UINT64) 10); + VERIFY_ARE_EQUAL(ev[0]._dst.first, (UINT64) 0); + VERIFY_ARE_EQUAL(ev[0]._dst.second, (UINT64) 10*KB); + VERIFY_ARE_EQUAL(ev[1]._src, (UINT64) 10); /// + VERIFY_ARE_EQUAL(ev[1]._span, (UINT64) 10); + VERIFY_ARE_EQUAL(ev[1]._dst.first, (UINT64) 10*KB); + VERIFY_ARE_EQUAL(ev[1]._dst.second, (UINT64) 90*KB); // note length + tp.vTargets.clear(); + v.clear(); + } + + // -rdabs10/98k + // autoscale tail cannot issue IO, so distribution is not extended + v.emplace_back(0,10, make_pair(0, 98*KB)); + v.emplace_back(10,90, make_pair(98*KB, 0)); + target.SetDistributionRange(v, DistributionType::Absolute); + tp.vTargets.push_back(target); + + { + ThreadTargetState tts(&tp, 0, 100*KB); + vector& ev = tts._vDistributionRange; + + VERIFY_ARE_EQUAL(tts._vDistributionRange.size(), (size_t) 1); + VERIFY_ARE_EQUAL(tts._ioDistributionSpan, (UINT32) 10); + VERIFY_ARE_EQUAL(ev[0]._src, (UINT64) 0); + VERIFY_ARE_EQUAL(ev[0]._span, (UINT64) 10); + VERIFY_ARE_EQUAL(ev[0]._dst.first, (UINT64) 0); + VERIFY_ARE_EQUAL(ev[0]._dst.second, (UINT64) 98*KB); + tp.vTargets.clear(); + v.clear(); + } + + // -rdabs10/96k + // autoscale tail can issue single IO @ 96K + v.emplace_back(0,10, make_pair(0, 96*KB)); + v.emplace_back(10,90, make_pair(96*KB, 0)); + target.SetDistributionRange(v, DistributionType::Absolute); + tp.vTargets.push_back(target); + + { + ThreadTargetState tts(&tp, 0, 100*KB); + vector& ev = tts._vDistributionRange; + + VERIFY_ARE_EQUAL(tts._vDistributionRange.size(), (size_t) 2); + VERIFY_ARE_EQUAL(tts._ioDistributionSpan, (UINT32) 100); + VERIFY_ARE_EQUAL(ev[0]._src, (UINT64) 0); + VERIFY_ARE_EQUAL(ev[0]._span, (UINT64) 10); + VERIFY_ARE_EQUAL(ev[0]._dst.first, (UINT64) 0); + VERIFY_ARE_EQUAL(ev[0]._dst.second, (UINT64) 96*KB); + VERIFY_ARE_EQUAL(ev[1]._src, (UINT64) 10); + VERIFY_ARE_EQUAL(ev[1]._span, (UINT64) 90); + VERIFY_ARE_EQUAL(ev[1]._dst.first, (UINT64) 96*KB); + VERIFY_ARE_EQUAL(ev[1]._dst.second, (UINT64) 4*KB); + tp.vTargets.clear(); + v.clear(); + } + } +} \ No newline at end of file diff --git a/CristalDiskMark/source/diskspd22/UnitTests/IORequestGenerator/IORequestGenerator.UnitTests.h b/CristalDiskMark/source/diskspd22/UnitTests/IORequestGenerator/IORequestGenerator.UnitTests.h new file mode 100644 index 0000000..abfe1a3 --- /dev/null +++ b/CristalDiskMark/source/diskspd22/UnitTests/IORequestGenerator/IORequestGenerator.UnitTests.h @@ -0,0 +1,64 @@ +/* + +DISKSPD + +Copyright(c) Microsoft Corporation +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#pragma once +#include "WexTestClass.h" + +namespace UnitTests +{ + BEGIN_MODULE() + MODULE_PROPERTY(L"Feature", L"IORequestGenerator") + END_MODULE() + + class IORequestGeneratorUnitTests : public WEX::TestClass + { + public: + TEST_CLASS(IORequestGeneratorUnitTests); + TEST_METHOD(Test_GetFilesToPrecreate1); + TEST_METHOD(Test_GetFilesToPrecreate2); + TEST_METHOD(Test_GetFilesToPrecreateConstantSizes); + TEST_METHOD(Test_GetFilesToPrecreateConstantOrZeroSizes); + TEST_METHOD(Test_GetFilesToPrecreateUseMaxSize); + + TEST_METHOD(Test_GetNextFileOffsetRandom); + TEST_METHOD(Test_GetNextFileOffsetSequential); + TEST_METHOD(Test_GetNextFileOffsetInterlockedSequential); + TEST_METHOD(Test_GetNextFileOffsetParallelAsyncIO); + TEST_METHOD(Test_SequentialWithStride); + TEST_METHOD(Test_SequentialWithStrideInterleaved); + TEST_METHOD(Test_SequentialWithStrideUneven); + + TEST_METHOD(Test_GetThreadBaseFileOffset); + TEST_METHOD(Test_GetThreadBaseFileOffsetWithStride); + + TEST_METHOD(Test_ThreadTargetStateInit); + TEST_METHOD(Test_ThreadTargetStateEffectiveDistPct); + TEST_METHOD(Test_ThreadTargetStateEffectiveDistAbs); + }; +} \ No newline at end of file diff --git a/CristalDiskMark/source/diskspd22/UnitTests/IORequestGenerator/IORequestGenerator.rc b/CristalDiskMark/source/diskspd22/UnitTests/IORequestGenerator/IORequestGenerator.rc new file mode 100644 index 0000000..bcbe27b --- /dev/null +++ b/CristalDiskMark/source/diskspd22/UnitTests/IORequestGenerator/IORequestGenerator.rc @@ -0,0 +1,17 @@ +#include +#include "Version.h" + +#include + +#define VER_FILETYPE VFT_APP +#define VER_FILESUBTYPE VFT2_UNKNOWN +#define VER_FILEDESCRIPTION_STR "DiskSpd Storage Performance Tool" +#define VER_INTERNALNAME_STR "IORequestGenerator.UnitTests.dll" + +#undef VER_PRODUCTVERSION +#define VER_PRODUCTVERSION DISKSPD_MAJOR,DISKSPD_MINOR,DISKSPD_BUILD,DISKSPD_QFE + +#undef VER_PRODUCTVERSION_STR +#define VER_PRODUCTVERSION_STR DISKSPD_NUMERIC_VERSION_STRING + +#include "common.ver" diff --git a/CristalDiskMark/source/diskspd22/UnitTests/IORequestGenerator/stdafx.h b/CristalDiskMark/source/diskspd22/UnitTests/IORequestGenerator/stdafx.h new file mode 100644 index 0000000..883be10 --- /dev/null +++ b/CristalDiskMark/source/diskspd22/UnitTests/IORequestGenerator/stdafx.h @@ -0,0 +1,33 @@ +/* + +DISKSPD + +Copyright(c) Microsoft Corporation +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#pragma once + +#include + diff --git a/CristalDiskMark/source/diskspd22/UnitTests/ResultParser/ResultParser.UnitTests.cpp b/CristalDiskMark/source/diskspd22/UnitTests/ResultParser/ResultParser.UnitTests.cpp new file mode 100644 index 0000000..d5e2934 --- /dev/null +++ b/CristalDiskMark/source/diskspd22/UnitTests/ResultParser/ResultParser.UnitTests.cpp @@ -0,0 +1,965 @@ +/* + +DISKSPD + +Copyright(c) Microsoft Corporation +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#include "StdAfx.h" +#include "ResultParser.UnitTests.h" +#include "Common.h" +#include "resultparser.h" +#include +#include + +using namespace WEX::TestExecution; +using namespace WEX::Logging; +using namespace std; + +namespace UnitTests +{ + void ResultParserUnitTests::Test_ParseResults() + { + Profile profile; + TimeSpan timeSpan; + ResultParser parser; + + Results results; + results.fUseETW = false; + double fTime = 120.0; + results.ullTimeCount = PerfTimer::SecondsToPerfTime(fTime); + + SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION systemProcessorInfo = {}; + systemProcessorInfo.UserTime.QuadPart = static_cast(fTime * 30 * 100000); + systemProcessorInfo.IdleTime.QuadPart = static_cast(fTime * 45 * 100000); + systemProcessorInfo.KernelTime.QuadPart = static_cast(fTime * 70 * 100000); + results.vSystemProcessorPerfInfo.push_back(systemProcessorInfo); + + TargetResults targetResults; + targetResults.sPath = "testfile1.dat"; + targetResults.ullFileSize = 10 * 1024 * 1024; + targetResults.ullReadBytesCount = 4 * 1024 * 1024; + targetResults.ullReadIOCount = 6; + targetResults.ullWriteBytesCount = 2 * 1024 * 1024; + targetResults.ullWriteIOCount = 10; + targetResults.ullBytesCount = targetResults.ullReadBytesCount + targetResults.ullWriteBytesCount; + targetResults.ullIOCount = targetResults.ullReadIOCount + targetResults.ullWriteIOCount; + + // TODO: Histogram readLatencyHistogram; + // TODO: Histogram writeLatencyHistogram; + + // TODO: IoBucketizer writeBucketizer; + + timeSpan.SetCalculateIopsStdDev(true); + targetResults.readBucketizer.Initialize(1000, timeSpan.GetDuration()); + for (size_t i = 0; i < timeSpan.GetDuration(); i++) + { + // add an io halfway through the bucket's time interval + targetResults.readBucketizer.Add(i * 1000 + 500, 100); + } + + ThreadResults threadResults; + threadResults.vTargetResults.push_back(targetResults); + results.vThreadResults.push_back(threadResults); + + vector vResults; + vResults.push_back(results); + + // just throw away the computername - for the ut, it's as useful (and simpler) + // to verify a static null as anything else. + SystemInformation system; + system.sComputerName.clear(); + system.ResetTime(); + + // and power plan + system.sActivePolicyName.clear(); + system.sActivePolicyGuid.clear(); + + system.processorTopology._ulProcessorCount = 1; + system.processorTopology._ubPerformanceEfficiencyClass = 0; + system.processorTopology._fSMT = false; + + system.processorTopology._vProcessorGroupInformation.clear(); + system.processorTopology._vProcessorGroupInformation.emplace_back((WORD)0, (BYTE)1, (BYTE)1, (KAFFINITY)0x1); + + ProcessorNumaInformation node; + node._nodeNumber = 0; + node._vProcessorMasks.emplace_back((WORD)0, (KAFFINITY)0x1); + system.processorTopology._vProcessorNumaInformation.clear(); + system.processorTopology._vProcessorNumaInformation.push_back(node); + + ProcessorSocketInformation socket; + socket._vProcessorMasks.emplace_back((WORD)0, (KAFFINITY)0x1); + system.processorTopology._vProcessorSocketInformation.clear(); + system.processorTopology._vProcessorSocketInformation.push_back(socket); + + system.processorTopology._vProcessorCoreInformation.clear(); + system.processorTopology._vProcessorCoreInformation.emplace_back((WORD)0, (KAFFINITY)0x1, (BYTE)0); + + // finally, add the timespan to the profile and dump. + profile.AddTimeSpan(timeSpan); + + string sResults = parser.ParseResults(profile, system, vResults); + + // stringify random text, quoting "'s and adding newline/preserving tabs + // gc some.txt |% { write-host $("`"{0}\n`"" -f $($_ -replace "`"","\`"" -replace "`t","\t")) } + + const char *pcszExpectedOutput = "\n" + "Command Line: \n" + "\n" + "Input parameters:\n" + "\n" + "\ttimespan: 1\n" + "\t-------------\n" + "\tduration: 10s\n" + "\twarm up time: 5s\n" + "\tcool down time: 0s\n" + "\tgathering IOPS at intervals of 1000ms\n" + "\trandom seed: 0\n" + "\n" + "System information:\n\n" + "\tcomputer name: \n" + "\tstart time: \n" + "\n" + "\tcpu count:\t\t1\n" + "\tcore count:\t\t1\n" + "\tgroup count:\t\t1\n" + "\tnode count:\t\t1\n" + "\tsocket count:\t\t1\n" + "\theterogeneous cores:\tn\n" + "\n" + "\tactive power scheme:\t\n" + "\n" + "Results for timespan 1:\n" + "*******************************************************************************\n" + "\n" + "actual test time:\t120.00s\n" + "thread count:\t\t1\n" + "\n" + "CPU | Usage | User | Kernel | Idle\n" + "----------------------------------------\n" + " 0| 55.00%| 30.00%| 25.00%| 45.00%\n" + "----------------------------------------\n" + "avg.| 55.00%| 30.00%| 25.00%| 45.00%\n" + "\n" + "Total IO\n" + "thread | bytes | I/Os | MiB/s | I/O per s | IopsStdDev | file\n" + "-------------------------------------------------------------------------------------------\n" + " 0 | 6291456 | 16 | 0.05 | 0.13 | 0.00 | testfile1.dat (10MiB)\n" + "-------------------------------------------------------------------------------------------\n" + "total: 6291456 | 16 | 0.05 | 0.13 | 0.00\n" + "\n" + "Read IO\n" + "thread | bytes | I/Os | MiB/s | I/O per s | IopsStdDev | file\n" + "-------------------------------------------------------------------------------------------\n" + " 0 | 4194304 | 6 | 0.03 | 0.05 | 0.00 | testfile1.dat (10MiB)\n" + "-------------------------------------------------------------------------------------------\n" + "total: 4194304 | 6 | 0.03 | 0.05 | 0.00\n" + "\n" + "Write IO\n" + "thread | bytes | I/Os | MiB/s | I/O per s | IopsStdDev | file\n" + "-------------------------------------------------------------------------------------------\n" + " 0 | 2097152 | 10 | 0.02 | 0.08 | 0.00 | testfile1.dat (10MiB)\n" + "-------------------------------------------------------------------------------------------\n" + "total: 2097152 | 10 | 0.02 | 0.08 | 0.00\n"; + VERIFY_ARE_EQUAL(sResults, pcszExpectedOutput); + } + + void ResultParserUnitTests::Test_ParseProfile() + { + Profile profile; + ResultParser parser; + TimeSpan timeSpan; + Target target; + + timeSpan.AddTarget(target); + profile.AddTimeSpan(timeSpan); + + string s = parser.ParseProfile(profile); + const char *pszExpectedResult = "\nCommand Line: \n" + "\n" + "Input parameters:\n" + "\n" + "\ttimespan: 1\n" + "\t-------------\n" + "\tduration: 10s\n" + "\twarm up time: 5s\n" + "\tcool down time: 0s\n" + "\trandom seed: 0\n" + "\tpath: ''\n" + "\t\tthink time: 0ms\n" + "\t\tburst size: 0\n" + "\t\tusing software cache\n" + "\t\tusing hardware write cache, writethrough off\n" + "\t\tperforming read test\n" + "\t\tblock size: 64KiB\n" + "\t\tusing sequential I/O (stride: 64KiB)\n" + "\t\tnumber of outstanding I/O operations per thread: 2\n" + "\t\tthreads per file: 1\n" + "\t\tusing I/O Completion Ports\n" + "\t\tIO priority: normal\n\n"; + + VERIFY_ARE_EQUAL(strlen(pszExpectedResult), s.length()); + VERIFY_IS_TRUE(!strcmp(pszExpectedResult, s.c_str())); + } + + void ResultParserUnitTests::Test_PrintTarget() + { + ResultParser parser; + Target target; + + parser._PrintTarget(target, false, true, false); + const char *pszExpectedResult = "\tpath: ''\n" \ + "\t\tthink time: 0ms\n" + "\t\tburst size: 0\n" + "\t\tusing software cache\n" + "\t\tusing hardware write cache, writethrough off\n" + "\t\tperforming read test\n" + "\t\tblock size: 64KiB\n" + "\t\tusing sequential I/O (stride: 64KiB)\n" + "\t\tnumber of outstanding I/O operations per thread: 2\n" + "\t\tIO priority: normal\n"; + VERIFY_ARE_EQUAL(parser._sResult, pszExpectedResult); + + parser._sResult.clear(); + target.SetThreadStrideInBytes(100 * 1024); + parser._PrintTarget(target, false, true, false); + pszExpectedResult = "\tpath: ''\n" \ + "\t\tthink time: 0ms\n" + "\t\tburst size: 0\n" + "\t\tusing software cache\n" + "\t\tusing hardware write cache, writethrough off\n" + "\t\tperforming read test\n" + "\t\tblock size: 64KiB\n" + "\t\tusing sequential I/O (stride: 64KiB)\n" + "\t\tnumber of outstanding I/O operations per thread: 2\n" + "\t\tthread stride size: 100KiB\n" + "\t\tIO priority: normal\n"; + VERIFY_ARE_EQUAL(parser._sResult, pszExpectedResult); + target.SetThreadStrideInBytes(0); + + parser._sResult.clear(); + target.SetMaxFileSize(2000 * 1024); + parser._PrintTarget(target, false, true, false); + pszExpectedResult = "\tpath: ''\n" \ + "\t\tthink time: 0ms\n" + "\t\tburst size: 0\n" + "\t\tusing software cache\n" + "\t\tusing hardware write cache, writethrough off\n" + "\t\tperforming read test\n" + "\t\tblock size: 64KiB\n" + "\t\tusing sequential I/O (stride: 64KiB)\n" + "\t\tnumber of outstanding I/O operations per thread: 2\n" + "\t\tmax file size: 1.95MiB\n" + "\t\tIO priority: normal\n"; + VERIFY_ARE_EQUAL(parser._sResult, pszExpectedResult); + target.SetMaxFileSize(0); + + parser._sResult.clear(); + target.SetBaseFileOffsetInBytes(2 * 1024 * 1024); + parser._PrintTarget(target, false, true, false); + pszExpectedResult = "\tpath: ''\n" \ + "\t\tthink time: 0ms\n" + "\t\tburst size: 0\n" + "\t\tusing software cache\n" + "\t\tusing hardware write cache, writethrough off\n" + "\t\tperforming read test\n" + "\t\tblock size: 64KiB\n" + "\t\tusing sequential I/O (stride: 64KiB)\n" + "\t\tnumber of outstanding I/O operations per thread: 2\n" + "\t\tbase file offset: 2MiB\n" + "\t\tIO priority: normal\n"; + VERIFY_ARE_EQUAL(parser._sResult, pszExpectedResult); + target.SetBaseFileOffsetInBytes(0); + + parser._sResult.clear(); + target.SetThroughput(1000); + parser._PrintTarget(target, false, true, false); + pszExpectedResult = "\tpath: ''\n" \ + "\t\tthink time: 0ms\n" + "\t\tburst size: 0\n" + "\t\tusing software cache\n" + "\t\tusing hardware write cache, writethrough off\n" + "\t\tperforming read test\n" + "\t\tblock size: 64KiB\n" + "\t\tusing sequential I/O (stride: 64KiB)\n" + "\t\tnumber of outstanding I/O operations per thread: 2\n" + "\t\tIO priority: normal\n" + "\t\tthroughput rate-limited to 1000 B/ms\n"; + VERIFY_ARE_EQUAL(parser._sResult, pszExpectedResult); + target.SetThroughput(0); + + parser._sResult.clear(); + target.SetThroughputIOPS(1000); + parser._PrintTarget(target, false, true, false); + pszExpectedResult = "\tpath: ''\n" \ + "\t\tthink time: 0ms\n" + "\t\tburst size: 0\n" + "\t\tusing software cache\n" + "\t\tusing hardware write cache, writethrough off\n" + "\t\tperforming read test\n" + "\t\tblock size: 64KiB\n" + "\t\tusing sequential I/O (stride: 64KiB)\n" + "\t\tnumber of outstanding I/O operations per thread: 2\n" + "\t\tIO priority: normal\n" + "\t\tthroughput rate-limited to 1000 IOPS\n"; + VERIFY_ARE_EQUAL(parser._sResult, pszExpectedResult); + target.SetThroughputIOPS(0); + + parser._sResult.clear(); + target.SetWriteRatio(30); + parser._PrintTarget(target, false, true, false); + pszExpectedResult = "\tpath: ''\n" \ + "\t\tthink time: 0ms\n" + "\t\tburst size: 0\n" + "\t\tusing software cache\n" + "\t\tusing hardware write cache, writethrough off\n" + "\t\tperforming mix test (read/write ratio: 70/30)\n" + "\t\tblock size: 64KiB\n" + "\t\tusing sequential I/O (stride: 64KiB)\n" + "\t\tnumber of outstanding I/O operations per thread: 2\n" + "\t\tIO priority: normal\n"; + VERIFY_ARE_EQUAL(parser._sResult, pszExpectedResult); + target.SetWriteRatio(0); + + parser._sResult.clear(); + target.SetRandomDataWriteBufferSize(12341234); + parser._PrintTarget(target, false, true, false); + pszExpectedResult = "\tpath: ''\n" \ + "\t\tthink time: 0ms\n" + "\t\tburst size: 0\n" + "\t\tusing software cache\n" + "\t\tusing hardware write cache, writethrough off\n" + "\t\twrite buffer size: 11.77MiB\n" + "\t\twrite buffer source: random fill\n" + "\t\tperforming read test\n" + "\t\tblock size: 64KiB\n" + "\t\tusing sequential I/O (stride: 64KiB)\n" + "\t\tnumber of outstanding I/O operations per thread: 2\n" + "\t\tIO priority: normal\n"; + VERIFY_ARE_EQUAL(parser._sResult, pszExpectedResult); + + parser._sResult.clear(); + target.SetRandomDataWriteBufferSourcePath("x:\\foo\\bar.dat"); + target.SetRandomRatio(100); + parser._PrintTarget(target, false, true, false); + pszExpectedResult = "\tpath: ''\n" \ + "\t\tthink time: 0ms\n" + "\t\tburst size: 0\n" + "\t\tusing software cache\n" + "\t\tusing hardware write cache, writethrough off\n" + "\t\twrite buffer size: 11.77MiB\n" + "\t\twrite buffer source: 'x:\\foo\\bar.dat'\n" + "\t\tperforming read test\n" + "\t\tblock size: 64KiB\n" + "\t\tusing random I/O (alignment: 64KiB)\n" + "\t\tnumber of outstanding I/O operations per thread: 2\n" + "\t\tIO priority: normal\n"; + VERIFY_ARE_EQUAL(parser._sResult, pszExpectedResult); + target.SetRandomDataWriteBufferSize(0); + target.SetRandomDataWriteBufferSourcePath(""); + + parser._sResult.clear(); + target.SetCacheMode(TargetCacheMode::DisableOSCache); + parser._PrintTarget(target, false, true, false); + pszExpectedResult = "\tpath: ''\n" \ + "\t\tthink time: 0ms\n" + "\t\tburst size: 0\n" + "\t\tsoftware cache disabled\n" + "\t\tusing hardware write cache, writethrough off\n" + "\t\tperforming read test\n" + "\t\tblock size: 64KiB\n" + "\t\tusing random I/O (alignment: 64KiB)\n" + "\t\tnumber of outstanding I/O operations per thread: 2\n" + "\t\tIO priority: normal\n"; + VERIFY_ARE_EQUAL(parser._sResult, pszExpectedResult); + + parser._sResult.clear(); + target.SetCacheMode(TargetCacheMode::DisableOSCache); + target.SetWriteThroughMode(WriteThroughMode::On); + parser._PrintTarget(target, false, true, false); + pszExpectedResult = "\tpath: ''\n" \ + "\t\tthink time: 0ms\n" + "\t\tburst size: 0\n" + "\t\tsoftware cache disabled\n" + "\t\thardware write cache disabled, writethrough on\n" + "\t\tperforming read test\n" + "\t\tblock size: 64KiB\n" + "\t\tusing random I/O (alignment: 64KiB)\n" + "\t\tnumber of outstanding I/O operations per thread: 2\n" + "\t\tIO priority: normal\n"; + VERIFY_ARE_EQUAL(parser._sResult, pszExpectedResult); + + parser._sResult.clear(); + target.SetCacheMode(TargetCacheMode::Cached); + target.SetWriteThroughMode(WriteThroughMode::On); + parser._PrintTarget(target, false, true, false); + pszExpectedResult = "\tpath: ''\n" \ + "\t\tthink time: 0ms\n" + "\t\tburst size: 0\n" + "\t\tusing software cache\n" + "\t\thardware and software write caches disabled, writethrough on\n" + "\t\tperforming read test\n" + "\t\tblock size: 64KiB\n" + "\t\tusing random I/O (alignment: 64KiB)\n" + "\t\tnumber of outstanding I/O operations per thread: 2\n" + "\t\tIO priority: normal\n"; + VERIFY_ARE_EQUAL(parser._sResult, pszExpectedResult); + target.SetWriteThroughMode(WriteThroughMode::Undefined); + + parser._sResult.clear(); + target.SetCacheMode(TargetCacheMode::DisableLocalCache); + parser._PrintTarget(target, false, true, false); + pszExpectedResult = "\tpath: ''\n" \ + "\t\tthink time: 0ms\n" + "\t\tburst size: 0\n" + "\t\tlocal software cache disabled, remote cache enabled\n" + "\t\tusing hardware write cache, writethrough off\n" + "\t\tperforming read test\n" + "\t\tblock size: 64KiB\n" + "\t\tusing random I/O (alignment: 64KiB)\n" + "\t\tnumber of outstanding I/O operations per thread: 2\n" + "\t\tIO priority: normal\n"; + VERIFY_ARE_EQUAL(parser._sResult, pszExpectedResult); + + parser._sResult.clear(); + target.SetCacheMode(TargetCacheMode::Cached); + target.SetMemoryMappedIoMode(MemoryMappedIoMode::On); + parser._PrintTarget(target, false, true, false); + pszExpectedResult = "\tpath: ''\n" \ + "\t\tthink time: 0ms\n" + "\t\tburst size: 0\n" + "\t\tusing software cache\n" + "\t\tusing hardware write cache, writethrough off\n" + "\t\tmemory mapped I/O enabled\n" + "\t\tperforming read test\n" + "\t\tblock size: 64KiB\n" + "\t\tusing random I/O (alignment: 64KiB)\n" + "\t\tnumber of outstanding I/O operations per thread: 2\n" + "\t\tIO priority: normal\n"; + VERIFY_ARE_EQUAL(parser._sResult, pszExpectedResult); + + parser._sResult.clear(); + target.SetMemoryMappedIoFlushMode(MemoryMappedIoFlushMode::ViewOfFile); + parser._PrintTarget(target, false, true, false); + pszExpectedResult = "\tpath: ''\n" \ + "\t\tthink time: 0ms\n" + "\t\tburst size: 0\n" + "\t\tusing software cache\n" + "\t\tusing hardware write cache, writethrough off\n" + "\t\tmemory mapped I/O enabled, flush mode: FlushViewOfFile\n" + "\t\tperforming read test\n" + "\t\tblock size: 64KiB\n" + "\t\tusing random I/O (alignment: 64KiB)\n" + "\t\tnumber of outstanding I/O operations per thread: 2\n" + "\t\tIO priority: normal\n"; + VERIFY_ARE_EQUAL(parser._sResult, pszExpectedResult); + + parser._sResult.clear(); + target.SetMemoryMappedIoFlushMode(MemoryMappedIoFlushMode::NonVolatileMemory); + parser._PrintTarget(target, false, true, false); + pszExpectedResult = "\tpath: ''\n" \ + "\t\tthink time: 0ms\n" + "\t\tburst size: 0\n" + "\t\tusing software cache\n" + "\t\tusing hardware write cache, writethrough off\n" + "\t\tmemory mapped I/O enabled, flush mode: FlushNonVolatileMemory\n" + "\t\tperforming read test\n" + "\t\tblock size: 64KiB\n" + "\t\tusing random I/O (alignment: 64KiB)\n" + "\t\tnumber of outstanding I/O operations per thread: 2\n" + "\t\tIO priority: normal\n"; + VERIFY_ARE_EQUAL(parser._sResult, pszExpectedResult); + + parser._sResult.clear(); + target.SetMemoryMappedIoFlushMode(MemoryMappedIoFlushMode::NonVolatileMemoryNoDrain); + parser._PrintTarget(target, false, true, false); + pszExpectedResult = "\tpath: ''\n" \ + "\t\tthink time: 0ms\n" + "\t\tburst size: 0\n" + "\t\tusing software cache\n" + "\t\tusing hardware write cache, writethrough off\n" + "\t\tmemory mapped I/O enabled, flush mode: FlushNonVolatileMemory with no drain\n" + "\t\tperforming read test\n" + "\t\tblock size: 64KiB\n" + "\t\tusing random I/O (alignment: 64KiB)\n" + "\t\tnumber of outstanding I/O operations per thread: 2\n" + "\t\tIO priority: normal\n"; + VERIFY_ARE_EQUAL(parser._sResult, pszExpectedResult); + + parser._sResult.clear(); + target.SetMemoryMappedIoMode(MemoryMappedIoMode::Off); + target.SetMemoryMappedIoFlushMode(MemoryMappedIoFlushMode::Undefined); + target.SetCacheMode(TargetCacheMode::DisableLocalCache); + target.SetTemporaryFileHint(true); + parser._PrintTarget(target, false, true, false); + pszExpectedResult = "\tpath: ''\n" \ + "\t\tthink time: 0ms\n" + "\t\tburst size: 0\n" + "\t\tlocal software cache disabled, remote cache enabled\n" + "\t\tusing hardware write cache, writethrough off\n" + "\t\tperforming read test\n" + "\t\tblock size: 64KiB\n" + "\t\tusing random I/O (alignment: 64KiB)\n" + "\t\tnumber of outstanding I/O operations per thread: 2\n" + "\t\tusing FILE_ATTRIBUTE_TEMPORARY hint\n" + "\t\tIO priority: normal\n"; + VERIFY_ARE_EQUAL(parser._sResult, pszExpectedResult); + + parser._sResult.clear(); + target.SetRandomAccessHint(true); + parser._PrintTarget(target, false, true, false); + pszExpectedResult = "\tpath: ''\n" \ + "\t\tthink time: 0ms\n" + "\t\tburst size: 0\n" + "\t\tlocal software cache disabled, remote cache enabled\n" + "\t\tusing hardware write cache, writethrough off\n" + "\t\tperforming read test\n" + "\t\tblock size: 64KiB\n" + "\t\tusing random I/O (alignment: 64KiB)\n" + "\t\tnumber of outstanding I/O operations per thread: 2\n" + "\t\tusing FILE_FLAG_RANDOM_ACCESS hint\n" + "\t\tusing FILE_ATTRIBUTE_TEMPORARY hint\n" + "\t\tIO priority: normal\n"; + VERIFY_ARE_EQUAL(parser._sResult, pszExpectedResult); + + parser._sResult.clear(); + target.SetRandomAccessHint(false); + target.SetTemporaryFileHint(false); + target.SetSequentialScanHint(true); + parser._PrintTarget(target, false, true, false); + pszExpectedResult = "\tpath: ''\n" \ + "\t\tthink time: 0ms\n" + "\t\tburst size: 0\n" + "\t\tlocal software cache disabled, remote cache enabled\n" + "\t\tusing hardware write cache, writethrough off\n" + "\t\tperforming read test\n" + "\t\tblock size: 64KiB\n" + "\t\tusing random I/O (alignment: 64KiB)\n" + "\t\tnumber of outstanding I/O operations per thread: 2\n" + "\t\tusing FILE_FLAG_SEQUENTIAL_SCAN hint\n" + "\t\tIO priority: normal\n"; + VERIFY_ARE_EQUAL(parser._sResult, pszExpectedResult); + } + + void ResultParserUnitTests::Test_PrintTargetDistributionPct() + { + ResultParser parser; + Target target; + + vector v; + + // these match the CmdLineParser UTs + + // -rdpct10/10:10/10:0/10, though we need to produce the tail here + v.emplace_back(0, 10, make_pair(0, 10)); + v.emplace_back(10, 10, make_pair(10, 10)); + v.emplace_back(20, 0, make_pair(20, 10)); // zero IO% length hole + v.emplace_back(20, 80, make_pair(30, 70)); + target.SetDistributionRange(v, DistributionType::Percent); + + parser._PrintTarget(target, false, true, false); + const char *pszExpectedResult = "\tpath: ''\n" \ + "\t\tthink time: 0ms\n" + "\t\tburst size: 0\n" + "\t\tusing software cache\n" + "\t\tusing hardware write cache, writethrough off\n" + "\t\tperforming read test\n" + "\t\tblock size: 64KiB\n" + "\t\tusing sequential I/O (stride: 64KiB)\n" + "\t\tnumber of outstanding I/O operations per thread: 2\n" + "\t\tIO priority: normal\n" + "\t\tIO Distribution:\n" + "\t\t 10% of IO => [ 0% - 10%) of target\n" + "\t\t 10% of IO => [10% - 20%) of target\n" + "\t\t 0% of IO => [20% - 30%) of target\n" + "\t\t 80% of IO => [30% - 100%) of target\n"; + VERIFY_ARE_EQUAL(parser._sResult, pszExpectedResult); + v.clear(); + parser._sResult.clear(); + } + + void ResultParserUnitTests::Test_PrintTargetDistributionAbs() + { + ResultParser parser; + Target target; + + vector v; + + // these match the CmdLineParser UTs + + // -rdabs10/1G:10/1G:0/100G, again producing tail + v.emplace_back(0,10, make_pair(0, 1*GB)); + v.emplace_back(10,10, make_pair(1*GB, 1*GB)); + v.emplace_back(20,0, make_pair(2*GB, 100*GB)); + v.emplace_back(20,80, make_pair(102*GB, 0)); + target.SetDistributionRange(v, DistributionType::Absolute); + + parser._PrintTarget(target, false, true, false); + const char *pszExpectedResult = "\tpath: ''\n" \ + "\t\tthink time: 0ms\n" + "\t\tburst size: 0\n" + "\t\tusing software cache\n" + "\t\tusing hardware write cache, writethrough off\n" + "\t\tperforming read test\n" + "\t\tblock size: 64KiB\n" + "\t\tusing sequential I/O (stride: 64KiB)\n" + "\t\tnumber of outstanding I/O operations per thread: 2\n" + "\t\tIO priority: normal\n" + "\t\tIO Distribution:\n" + "\t\t 10% of IO => [ 0 - 1GiB)\n" + "\t\t 10% of IO => [ 1GiB - 2GiB)\n" + "\t\t 0% of IO => [ 2GiB - 102GiB)\n" + "\t\t 80% of IO => [ 102GiB - end)\n"; + VERIFY_ARE_EQUAL(parser._sResult, pszExpectedResult); + v.clear(); + parser._sResult.clear(); + } + + void ResultParserUnitTests::Test_PrintEffectiveDistributionPct() + { + // the first matches the corresponding IORequestGenerator effdist UT + ResultParser parser; + + Target target; + target.SetBlockAlignmentInBytes(4*KB); + target.SetBlockSizeInBytes(4*KB); + + Random r; + ThreadParameters tp; + tp.pRand = &r; + + vector v; + + // -rdpct10/10:10/10:0/10 + tail + // this is the same distribution in the cmdlineparser UT + v.emplace_back(0, 10, make_pair(0, 10)); + v.emplace_back(10, 10, make_pair(10, 10)); + v.emplace_back(20, 0, make_pair(20, 10)); // zero IO% length hole + v.emplace_back(20, 80, make_pair(30, 70)); + target.SetDistributionRange(v, DistributionType::Percent); + tp.vTargets.push_back(target); + + { + ThreadTargetState tts(&tp, 0, 100*KB); + + Results results; + ThreadResults threadResults; + TargetResults targetResults; + + targetResults.sPath = "testfile.dat"; + targetResults.vDistributionRange = tts._vDistributionRange; + + threadResults.vTargetResults.push_back(targetResults); + results.vThreadResults.push_back(threadResults); + + parser._PrintEffectiveDistributions(results); + + const char* pcszResults = "\nEffective IO Distributions\n" \ + "--------------------------\n" + "target: testfile.dat [thread: 0]\n" + " 10% of IO => [ 0 - 8KiB)\n" + " 10% of IO => [ 8KiB - 20KiB)\n" + " 80% of IO => [ 28KiB - 100KiB)\n"; + VERIFY_ARE_EQUAL(pcszResults, parser._sResult); + + parser._sResult.clear(); + } + + // + // Tests of distribution deduplication. + // + + // now repeat, duplicating the thread result for a second thread + + { + ThreadTargetState tts(&tp, 0, 100*KB); + + Results results; + ThreadResults threadResults; + TargetResults targetResults; + + targetResults.sPath = "testfile.dat"; + targetResults.vDistributionRange = tts._vDistributionRange; + + threadResults.vTargetResults.push_back(targetResults); + results.vThreadResults.push_back(threadResults); + results.vThreadResults.push_back(threadResults); + + parser._PrintEffectiveDistributions(results); + + const char* pcszResults = "\nEffective IO Distributions\n" \ + "--------------------------\n" + "target: testfile.dat [thread: 0 1]\n" + " 10% of IO => [ 0 - 8KiB)\n" + " 10% of IO => [ 8KiB - 20KiB)\n" + " 80% of IO => [ 28KiB - 100KiB)\n"; + VERIFY_ARE_EQUAL(pcszResults, parser._sResult); + + parser._sResult.clear(); + } + + // now repeat, for a third thread - ellision + + { + ThreadTargetState tts(&tp, 0, 100*KB); + + Results results; + ThreadResults threadResults; + TargetResults targetResults; + + targetResults.sPath = "testfile.dat"; + targetResults.vDistributionRange = tts._vDistributionRange; + + threadResults.vTargetResults.push_back(targetResults); + results.vThreadResults.push_back(threadResults); + results.vThreadResults.push_back(threadResults); + results.vThreadResults.push_back(threadResults); + + parser._PrintEffectiveDistributions(results); + + const char* pcszResults = "\nEffective IO Distributions\n" \ + "--------------------------\n" + "target: testfile.dat [thread: 0 - 2]\n" + " 10% of IO => [ 0 - 8KiB)\n" + " 10% of IO => [ 8KiB - 20KiB)\n" + " 80% of IO => [ 28KiB - 100KiB)\n"; + VERIFY_ARE_EQUAL(pcszResults, parser._sResult); + + parser._sResult.clear(); + } + + // now repeat, moving the third thread to a different target + + { + ThreadTargetState tts(&tp, 0, 100*KB); + + Results results; + ThreadResults threadResults; + TargetResults targetResults; + + targetResults.vDistributionRange = tts._vDistributionRange; + + targetResults.sPath = "testfile.dat"; + threadResults.vTargetResults.push_back(targetResults); + results.vThreadResults.push_back(threadResults); + results.vThreadResults.push_back(threadResults); + + targetResults.sPath = "testfile2.dat"; + threadResults.vTargetResults.clear(); + threadResults.vTargetResults.push_back(targetResults); + results.vThreadResults.push_back(threadResults); + + parser._PrintEffectiveDistributions(results); + + const char* pcszResults = "\nEffective IO Distributions\n" \ + "--------------------------\n" + "target: testfile.dat [thread: 0 1]\n" + "target: testfile2.dat [thread: 2]\n" + " 10% of IO => [ 0 - 8KiB)\n" + " 10% of IO => [ 8KiB - 20KiB)\n" + " 80% of IO => [ 28KiB - 100KiB)\n"; + VERIFY_ARE_EQUAL(pcszResults, parser._sResult); + + parser._sResult.clear(); + } + + // now repeat, four threads on the first target, three contiguous and one not + // the thread on the second target is used to create the gap - ellision will occur + // and the fourth thread will stand alone + + { + ThreadTargetState tts(&tp, 0, 100*KB); + + Results results; + ThreadResults threadResults; + TargetResults targetResults; + + targetResults.vDistributionRange = tts._vDistributionRange; + + targetResults.sPath = "testfile.dat"; + threadResults.vTargetResults.push_back(targetResults); + results.vThreadResults.push_back(threadResults); + results.vThreadResults.push_back(threadResults); + results.vThreadResults.push_back(threadResults); + + threadResults.vTargetResults.clear(); + targetResults.sPath = "testfile2.dat"; + threadResults.vTargetResults.push_back(targetResults); + results.vThreadResults.push_back(threadResults); + + threadResults.vTargetResults.clear(); + targetResults.sPath = "testfile.dat"; + threadResults.vTargetResults.push_back(targetResults); + results.vThreadResults.push_back(threadResults); + + parser._PrintEffectiveDistributions(results); + + const char* pcszResults = "\nEffective IO Distributions\n" \ + "--------------------------\n" + "target: testfile.dat [thread: 0 - 2 4]\n" + "target: testfile2.dat [thread: 3]\n" + " 10% of IO => [ 0 - 8KiB)\n" + " 10% of IO => [ 8KiB - 20KiB)\n" + " 80% of IO => [ 28KiB - 100KiB)\n"; + VERIFY_ARE_EQUAL(pcszResults, parser._sResult); + + parser._sResult.clear(); + } + + // two distinct distributions which share the same IO% + + { + ThreadTargetState tts1(&tp, 0, 100*KB); + ThreadTargetState tts2(&tp, 0, 1*MB); + + Results results; + ThreadResults threadResults; + TargetResults targetResults; + + targetResults.vDistributionRange = tts1._vDistributionRange; + targetResults.sPath = "testfile.dat"; + threadResults.vTargetResults.push_back(targetResults); + results.vThreadResults.push_back(threadResults); + + threadResults.vTargetResults.clear(); + + targetResults.vDistributionRange = tts2._vDistributionRange; + targetResults.sPath = "testfile2.dat"; + threadResults.vTargetResults.push_back(targetResults); + results.vThreadResults.push_back(threadResults); + + parser._PrintEffectiveDistributions(results); + + const char* pcszResults = "\nEffective IO Distributions\n" \ + "--------------------------\n" + "target: testfile.dat [thread: 0]\n" + " 10% of IO => [ 0 - 8KiB)\n" + " 10% of IO => [ 8KiB - 20KiB)\n" + " 80% of IO => [ 28KiB - 100KiB)\n" + "target: testfile2.dat [thread: 1]\n" + " 10% of IO => [ 0 - 100KiB)\n" + " 10% of IO => [ 100KiB - 204KiB)\n" + " 80% of IO => [ 304KiB - 1MiB)\n"; + VERIFY_ARE_EQUAL(pcszResults, parser._sResult); + + parser._sResult.clear(); + } + + tp.vTargets.clear(); + v.clear(); + } + + void ResultParserUnitTests::Test_PrintEffectiveDistributionAbs() + { + // the first matches the corresponding IORequestGenerator effdist UT + ResultParser parser; + + Target target; + target.SetBlockAlignmentInBytes(4*KB); + target.SetBlockSizeInBytes(4*KB); + + Random r; + ThreadParameters tp; + + vector v; + + // -rdabs10/1G:10/1G:0/100G, again producing tail - with autoscale (0) + // this is the same distribution in the cmdlineparser UT + // aligned tail range + v.emplace_back(0,10, make_pair(0, 1*GB)); + v.emplace_back(10,10, make_pair(1*GB, 1*GB)); + v.emplace_back(20,0, make_pair(2*GB, 100*GB)); + v.emplace_back(20,80, make_pair(102*GB, 0)); + target.SetDistributionRange(v, DistributionType::Absolute); + tp.vTargets.push_back(target); + + { + ThreadTargetState tts(&tp, 0, 200*GB); + + Results results; + ThreadResults threadResults; + TargetResults targetResults; + + targetResults.sPath = "testfile.dat"; + targetResults.vDistributionRange = tts._vDistributionRange; + + threadResults.vTargetResults.push_back(targetResults); + results.vThreadResults.push_back(threadResults); + + parser._PrintEffectiveDistributions(results); + + const char* pcszResults = "\nEffective IO Distributions\n" \ + "--------------------------\n" + "target: testfile.dat [thread: 0]\n" + " 10% of IO => [ 0 - 1GiB)\n" + " 10% of IO => [ 1GiB - 2GiB)\n" + " 80% of IO => [ 102GiB - 200GiB)\n"; + VERIFY_ARE_EQUAL(pcszResults, parser._sResult); + + tp.vTargets.clear(); + v.clear(); + parser._sResult.clear(); + } + + // -rdabs10/50k:20/10k:30/1G on 100KiB target - autoscale tail, but trimmed on last spec'd range + // this results in logical truncation since the covered ranges are only 60% of IO%, a case which + // is specific to absolute distributions. + v.emplace_back(0, 10, make_pair(0, 50*KB)); + v.emplace_back(10, 20, make_pair(50*KB, 10*KB)); + v.emplace_back(30, 30, make_pair(60*KB, 1*GB)); + v.emplace_back(60, 40, make_pair(1*GB + 60*KB, 0)); + target.SetDistributionRange(v, DistributionType::Absolute); + tp.vTargets.push_back(target); + + { + ThreadTargetState tts(&tp, 0, 100*KB); + + Results results; + ThreadResults threadResults; + TargetResults targetResults; + + targetResults.sPath = "testfile.dat"; + targetResults.vDistributionRange = tts._vDistributionRange; + + threadResults.vTargetResults.push_back(targetResults); + results.vThreadResults.push_back(threadResults); + + parser._PrintEffectiveDistributions(results); + + const char* pcszResults = "\nEffective IO Distributions\n" \ + "--------------------------\n" + "target: testfile.dat [thread: 0]\n" + " 16.7% of IO => [ 0 - 50KiB)\n" + " 33.3% of IO => [ 50KiB - 60KiB)\n" + " 50.0% of IO => [ 60KiB - 100KiB)\n"; + VERIFY_ARE_EQUAL(pcszResults, parser._sResult); + + tp.vTargets.clear(); + v.clear(); + parser._sResult.clear(); + } + } +} \ No newline at end of file diff --git a/CristalDiskMark/source/diskspd22/UnitTests/ResultParser/ResultParser.UnitTests.h b/CristalDiskMark/source/diskspd22/UnitTests/ResultParser/ResultParser.UnitTests.h new file mode 100644 index 0000000..d909d56 --- /dev/null +++ b/CristalDiskMark/source/diskspd22/UnitTests/ResultParser/ResultParser.UnitTests.h @@ -0,0 +1,52 @@ +/* + +DISKSPD + +Copyright(c) Microsoft Corporation +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#pragma once +#include "WexTestClass.h" + +namespace UnitTests +{ + BEGIN_MODULE() + MODULE_PROPERTY(L"Feature", L"ResultParser") + END_MODULE() + + class ResultParserUnitTests : public WEX::TestClass + { + public: + TEST_CLASS(ResultParserUnitTests); + TEST_METHOD(Test_ParseResults); + TEST_METHOD(Test_ParseProfile); + TEST_METHOD(Test_PrintTarget); + TEST_METHOD(Test_PrintTargetDistributionPct); + TEST_METHOD(Test_PrintTargetDistributionAbs); + TEST_METHOD(Test_PrintEffectiveDistributionPct); + TEST_METHOD(Test_PrintEffectiveDistributionAbs); + }; +} + diff --git a/CristalDiskMark/source/diskspd22/UnitTests/ResultParser/ResultParser.rc b/CristalDiskMark/source/diskspd22/UnitTests/ResultParser/ResultParser.rc new file mode 100644 index 0000000..63e9e63 --- /dev/null +++ b/CristalDiskMark/source/diskspd22/UnitTests/ResultParser/ResultParser.rc @@ -0,0 +1,17 @@ +#include +#include "Version.h" + +#include + +#define VER_FILETYPE VFT_APP +#define VER_FILESUBTYPE VFT2_UNKNOWN +#define VER_FILEDESCRIPTION_STR "DiskSpd Storage Performance Tool" +#define VER_INTERNALNAME_STR "ResultParser.UnitTests.dll" + +#undef VER_PRODUCTVERSION +#define VER_PRODUCTVERSION DISKSPD_MAJOR,DISKSPD_MINOR,DISKSPD_BUILD,DISKSPD_QFE + +#undef VER_PRODUCTVERSION_STR +#define VER_PRODUCTVERSION_STR DISKSPD_NUMERIC_VERSION_STRING + +#include "common.ver" diff --git a/CristalDiskMark/source/diskspd22/UnitTests/ResultParser/stdafx.h b/CristalDiskMark/source/diskspd22/UnitTests/ResultParser/stdafx.h new file mode 100644 index 0000000..883be10 --- /dev/null +++ b/CristalDiskMark/source/diskspd22/UnitTests/ResultParser/stdafx.h @@ -0,0 +1,33 @@ +/* + +DISKSPD + +Copyright(c) Microsoft Corporation +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#pragma once + +#include + diff --git a/CristalDiskMark/source/diskspd22/UnitTests/XmlProfileParser/XmlProfileParser.UnitTests.cpp b/CristalDiskMark/source/diskspd22/UnitTests/XmlProfileParser/XmlProfileParser.UnitTests.cpp new file mode 100644 index 0000000..116de8d --- /dev/null +++ b/CristalDiskMark/source/diskspd22/UnitTests/XmlProfileParser/XmlProfileParser.UnitTests.cpp @@ -0,0 +1,1672 @@ +/* + +DISKSPD + +Copyright(c) Microsoft Corporation +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#include "StdAfx.h" +#include "XmlProfileParser.UnitTests.h" +#include + +using namespace WEX::TestExecution; +using namespace WEX::Logging; +using namespace std; + +namespace UnitTests +{ + bool ModuleSetup() + { + return true; + } + + bool ModuleCleanup() + { + return true; + } + + bool XmlProfileParserUnitTests::ClassSetup() + { + bool fOk = true; + _hModule = GetModuleHandle(L"XmlProfileParser.UnitTests.dll"); + char szTempDirPath[MAX_PATH] = {}; + DWORD cch = GetTempPathA(_countof(szTempDirPath), szTempDirPath); + if (cch != 0) + { + _sTempFilePath = szTempDirPath; + _sTempFilePath += "DiskSpdXmlProfileParser.xml"; + //printf("deleting %s\n", _sTempFilePath.c_str()); + DeleteFileA(_sTempFilePath.c_str()); + } + else + { + fOk = false; + } + return fOk; + } + + bool XmlProfileParserUnitTests::ClassCleanup() + { + return true; + } + + bool XmlProfileParserUnitTests::MethodSetup() + { + return true; + } + + bool XmlProfileParserUnitTests::MethodCleanup() + { + DeleteFileA(_sTempFilePath.c_str()); + return true; + } + + void XmlProfileParserUnitTests::Test_ParseFile() + { + FILE *pFile; + fopen_s(&pFile, _sTempFilePath.c_str(), "wb"); + VERIFY_IS_TRUE(pFile != nullptr); + fprintf(pFile, "\n" + "\n" + " true\n" + " 15\n" + " \n" + " \n" + " 10\n" + " 20\n" + " 30\n" + " 40\n" + " 50\n" + " true\n" + " true\n" + " true\n" + " \n" + " \n" + " testfile.dat\n" + " 100\n" + " 123\n" + " 234\n" + " 333\n" + " true\n" + " true\n" + " true\n" + " 3344\n" + " 4433\n" + " 56\n" + " 561\n" + " 84\n" + " 86\n" + " 88\n" + " true\n" + " true\n" + " true\n" + " 60\n" + " \n" + " \n" + " testfile2.dat\n" + " 200\n" + " 85\n" + " 2\n" + " 2222\n" + " true\n" + " \n" + " \n" + " testfile3.dat\n" + " 200\n" + " 85\n" + " 2\n" + " 2222\n" + " true\n" + " true\n" + " true\n" + " \n" + " \n" + " testfile4.dat\n" + " 200\n" + " 85\n" + " 2\n" + " 2222\n" + " true\n" + " true\n" + " true\n" + " \n" + " \n" + " \n" + " \n" + " 10\n" + " 20\n" + " 30\n" + " 40\n" + " 50\n" + " true\n" + " true\n" + " \n" + " \n" + " testfile.dat\n" + " 100\n" + " 84\n" + " true\n" + " \n" + " \n" + " testfile1.dat\n" + " 100\n" + " 84\n" + " true\n" + " ViewOfFile" + " \n" + " \n" + " testfile2.dat\n" + " 100\n" + " 84\n" + " true\n" + " NonVolatileMemory" + " \n" + " \n" + " testfile3.dat\n" + " 100\n" + " 84\n" + " true\n" + " NonVolatileMemoryNoDrain" + " \n" + " \n" + " \n" + " \n" + "\n"); +/* + VERIFY_IS_TRUE(t.GetSequentialScanHint() == false); + VERIFY_IS_TRUE(t.GetRandomAccessHint() == false); + VERIFY_IS_TRUE(t.GetUseLargePages() == false);*/ + fclose(pFile); + + XmlProfileParser p; + Profile profile; + VERIFY_IS_TRUE(p.ParseFile(_sTempFilePath.c_str(), &profile, nullptr, _hModule)); + // note: many conflicts, this ut is a broad blend of specific element parsing, NOT a valid profile + VERIFY_IS_FALSE(profile.Validate(false)); + VERIFY_IS_TRUE(profile.GetVerbose() == true); + VERIFY_IS_TRUE(profile.GetProgress() == 15); +// TODO: VERIFY_IS_TRUE(profile.GetCmdLine().compare("foo -b4K -w84 -a1,4,6 testfile.dat testfile2.dat") == 0); + VERIFY_IS_TRUE(profile.GetEtwEnabled() == false); + VERIFY_IS_TRUE(profile.GetEtwProcess() == false); + VERIFY_IS_TRUE(profile.GetEtwThread() == false); + VERIFY_IS_TRUE(profile.GetEtwImageLoad() == false); + VERIFY_IS_TRUE(profile.GetEtwDiskIO() == false); + VERIFY_IS_TRUE(profile.GetEtwMemoryPageFaults() == false); + VERIFY_IS_TRUE(profile.GetEtwMemoryHardFaults() == false); + VERIFY_IS_TRUE(profile.GetEtwNetwork() == false); + VERIFY_IS_TRUE(profile.GetEtwRegistry() == false); + VERIFY_IS_TRUE(profile.GetEtwUsePagedMemory() == false); + VERIFY_IS_TRUE(profile.GetEtwUsePerfTimer() == false); + VERIFY_IS_TRUE(profile.GetEtwUseSystemTimer() == false); + VERIFY_IS_TRUE(profile.GetEtwUseCyclesCounter() == false); + + vector vSpans(profile.GetTimeSpans()); + VERIFY_ARE_EQUAL(vSpans.size(), (size_t)2); + VERIFY_ARE_EQUAL(vSpans[0].GetDuration(), (UINT32)10); + VERIFY_ARE_EQUAL(vSpans[0].GetWarmup(), (UINT32)20); + VERIFY_ARE_EQUAL(vSpans[0].GetCooldown(), (UINT32)30); + VERIFY_ARE_EQUAL(vSpans[0].GetRandSeed(), (UINT32)40); + VERIFY_ARE_EQUAL(vSpans[0].GetThreadCount(), (DWORD)50); + VERIFY_ARE_EQUAL(vSpans[0].GetRequestCount(), (DWORD)0); + VERIFY_IS_TRUE(vSpans[0].GetDisableAffinity() == true); + VERIFY_IS_TRUE(vSpans[0].GetCompletionRoutines() == true); + VERIFY_IS_TRUE(vSpans[0].GetMeasureLatency() == true); + + vector vTargets(vSpans[0].GetTargets()); + VERIFY_ARE_EQUAL(vTargets.size(), (size_t)4); + Target t(vTargets[0]); + + VERIFY_IS_TRUE(t.GetPath().compare("testfile.dat") == 0); + VERIFY_ARE_EQUAL(t.GetBlockSizeInBytes(), (DWORD)(100)); + VERIFY_ARE_EQUAL(t.GetRequestCount(), (DWORD)123); + VERIFY_IS_TRUE(t.GetRandomRatio() == 100); + VERIFY_IS_TRUE(t.GetUseInterlockedSequential() == false); + VERIFY_ARE_EQUAL(t.GetBlockAlignmentInBytes(), 234); + VERIFY_ARE_EQUAL(t.GetBaseFileOffsetInBytes(), 333); + VERIFY_IS_TRUE(t.GetUseParallelAsyncIO() == true); + VERIFY_IS_TRUE(t.GetCacheMode() == TargetCacheMode::DisableOSCache); + VERIFY_IS_TRUE(t.GetMemoryMappedIoMode() == MemoryMappedIoMode::Off); + VERIFY_IS_TRUE(t.GetWriteThroughMode() == WriteThroughMode::On); + VERIFY_IS_TRUE(t.GetZeroWriteBuffers() == false); + VERIFY_ARE_EQUAL(t.GetThreadsPerFile(), (DWORD)3344); + VERIFY_ARE_EQUAL(t.GetThreadStrideInBytes(), 4433); + VERIFY_IS_TRUE(t.GetCreateFile() == true); + VERIFY_ARE_EQUAL(t.GetFileSize(), 56); + VERIFY_ARE_EQUAL(t.GetMaxFileSize(), 561); + VERIFY_ARE_EQUAL(t.GetWriteRatio(), (DWORD)84); + VERIFY_IS_TRUE(t.GetUseBurstSize() == true); + VERIFY_ARE_EQUAL(t.GetBurstSize(), (DWORD)86); + VERIFY_ARE_EQUAL(t.GetThinkTime(), (DWORD)88); + VERIFY_IS_TRUE(t.GetEnableThinkTime() == true); + VERIFY_IS_TRUE(t.GetSequentialScanHint() == true); + VERIFY_IS_TRUE(t.GetRandomAccessHint() == true); + VERIFY_IS_TRUE(t.GetTemporaryFileHint() == false); + VERIFY_IS_TRUE(t.GetUseLargePages() == true); + VERIFY_IS_TRUE(t.GetIOPriorityHint() == IoPriorityHintNormal); + VERIFY_ARE_EQUAL(t.GetThroughputInBytesPerMillisecond(), (DWORD)60); + + t = vTargets[1]; + VERIFY_IS_TRUE(t.GetPath().compare("testfile2.dat") == 0); + VERIFY_ARE_EQUAL(t.GetBlockSizeInBytes(), (DWORD)(200)); + VERIFY_ARE_EQUAL(t.GetRequestCount(), (DWORD)2); + VERIFY_IS_TRUE(t.GetRandomRatio() == 0); + VERIFY_IS_TRUE(t.GetUseInterlockedSequential() == true); + VERIFY_ARE_EQUAL(t.GetBlockAlignmentInBytes(), 2222); + VERIFY_ARE_EQUAL(t.GetBaseFileOffsetInBytes(), 0); + VERIFY_IS_TRUE(t.GetUseParallelAsyncIO() == false); + VERIFY_IS_TRUE(t.GetCacheMode() == TargetCacheMode::Cached); + VERIFY_IS_TRUE(t.GetMemoryMappedIoMode() == MemoryMappedIoMode::Off); + VERIFY_IS_TRUE(t.GetWriteThroughMode() == WriteThroughMode::Off); + VERIFY_IS_TRUE(t.GetZeroWriteBuffers() == false); + VERIFY_ARE_EQUAL(t.GetThreadsPerFile(), (DWORD)1); + VERIFY_ARE_EQUAL(t.GetThreadStrideInBytes(), 0); + VERIFY_IS_TRUE(t.GetCreateFile() == false); + VERIFY_ARE_EQUAL(t.GetFileSize(), 0); + VERIFY_ARE_EQUAL(t.GetMaxFileSize(), 0); + VERIFY_ARE_EQUAL(t.GetWriteRatio(), (DWORD)85); + VERIFY_IS_TRUE(t.GetUseBurstSize() == false); + VERIFY_ARE_EQUAL(t.GetBurstSize(), (DWORD)0); + VERIFY_ARE_EQUAL(t.GetThinkTime(), (DWORD)0); + VERIFY_IS_TRUE(t.GetEnableThinkTime() == false); + VERIFY_IS_TRUE(t.GetSequentialScanHint() == false); + VERIFY_IS_TRUE(t.GetRandomAccessHint() == false); + VERIFY_IS_TRUE(t.GetTemporaryFileHint() == false); + VERIFY_IS_TRUE(t.GetUseLargePages() == false); + VERIFY_IS_TRUE(t.GetIOPriorityHint() == IoPriorityHintLow); + VERIFY_IS_TRUE(profile.GetPrecreateFiles() == PrecreateFiles::None); + + // verify DisableLocalCache + t = vTargets[2]; + VERIFY_IS_TRUE(t.GetPath().compare("testfile3.dat") == 0); + VERIFY_ARE_EQUAL(t.GetBlockSizeInBytes(), (DWORD)(200)); + VERIFY_ARE_EQUAL(t.GetRequestCount(), (DWORD)2); + VERIFY_IS_TRUE(t.GetRandomRatio() == 0); + VERIFY_IS_TRUE(t.GetUseInterlockedSequential() == true); + VERIFY_ARE_EQUAL(t.GetBlockAlignmentInBytes(), 2222); + VERIFY_ARE_EQUAL(t.GetBaseFileOffsetInBytes(), 0); + VERIFY_IS_TRUE(t.GetUseParallelAsyncIO() == false); + VERIFY_IS_TRUE(t.GetCacheMode() == TargetCacheMode::DisableLocalCache); + VERIFY_IS_TRUE(t.GetMemoryMappedIoMode() == MemoryMappedIoMode::Off); + VERIFY_IS_TRUE(t.GetWriteThroughMode() == WriteThroughMode::Off); + VERIFY_IS_TRUE(t.GetZeroWriteBuffers() == false); + VERIFY_ARE_EQUAL(t.GetThreadsPerFile(), (DWORD)1); + VERIFY_ARE_EQUAL(t.GetThreadStrideInBytes(), 0); + VERIFY_IS_TRUE(t.GetCreateFile() == false); + VERIFY_ARE_EQUAL(t.GetFileSize(), 0); + VERIFY_ARE_EQUAL(t.GetMaxFileSize(), 0); + VERIFY_ARE_EQUAL(t.GetWriteRatio(), (DWORD)85); + VERIFY_IS_TRUE(t.GetUseBurstSize() == false); + VERIFY_ARE_EQUAL(t.GetBurstSize(), (DWORD)0); + VERIFY_ARE_EQUAL(t.GetThinkTime(), (DWORD)0); + VERIFY_IS_TRUE(t.GetEnableThinkTime() == false); + VERIFY_IS_TRUE(t.GetSequentialScanHint() == false); + VERIFY_IS_TRUE(t.GetRandomAccessHint() == false); + VERIFY_IS_TRUE(t.GetTemporaryFileHint() == true); + VERIFY_IS_TRUE(t.GetUseLargePages() == false); + VERIFY_IS_TRUE(t.GetIOPriorityHint() == IoPriorityHintLow); + VERIFY_IS_TRUE(profile.GetPrecreateFiles() == PrecreateFiles::None); + + // verify DisableAllCache + t = vTargets[3]; + VERIFY_IS_TRUE(t.GetPath().compare("testfile4.dat") == 0); + VERIFY_ARE_EQUAL(t.GetBlockSizeInBytes(), (DWORD)(200)); + VERIFY_ARE_EQUAL(t.GetRequestCount(), (DWORD)2); + VERIFY_IS_TRUE(t.GetRandomRatio() == 0); + VERIFY_IS_TRUE(t.GetUseInterlockedSequential() == true); + VERIFY_ARE_EQUAL(t.GetBlockAlignmentInBytes(), 2222); + VERIFY_ARE_EQUAL(t.GetBaseFileOffsetInBytes(), 0); + VERIFY_IS_TRUE(t.GetUseParallelAsyncIO() == false); + VERIFY_IS_TRUE(t.GetCacheMode() == TargetCacheMode::DisableOSCache); + VERIFY_IS_TRUE(t.GetMemoryMappedIoMode() == MemoryMappedIoMode::Off); + VERIFY_IS_TRUE(t.GetWriteThroughMode() == WriteThroughMode::On); + VERIFY_IS_TRUE(t.GetZeroWriteBuffers() == false); + VERIFY_ARE_EQUAL(t.GetThreadsPerFile(), (DWORD)1); + VERIFY_ARE_EQUAL(t.GetThreadStrideInBytes(), 0); + VERIFY_IS_TRUE(t.GetCreateFile() == false); + VERIFY_ARE_EQUAL(t.GetFileSize(), 0); + VERIFY_ARE_EQUAL(t.GetMaxFileSize(), 0); + VERIFY_ARE_EQUAL(t.GetWriteRatio(), (DWORD)85); + VERIFY_IS_TRUE(t.GetUseBurstSize() == false); + VERIFY_ARE_EQUAL(t.GetBurstSize(), (DWORD)0); + VERIFY_ARE_EQUAL(t.GetThinkTime(), (DWORD)0); + VERIFY_IS_TRUE(t.GetEnableThinkTime() == false); + VERIFY_IS_TRUE(t.GetSequentialScanHint() == false); + VERIFY_IS_TRUE(t.GetRandomAccessHint() == false); + VERIFY_IS_TRUE(t.GetTemporaryFileHint() == true); + VERIFY_IS_TRUE(t.GetUseLargePages() == false); + VERIFY_IS_TRUE(t.GetIOPriorityHint() == IoPriorityHintLow); + VERIFY_IS_TRUE(profile.GetPrecreateFiles() == PrecreateFiles::None); + + VERIFY_ARE_EQUAL(vSpans[1].GetDuration(), (UINT32)10); + VERIFY_ARE_EQUAL(vSpans[1].GetWarmup(), (UINT32)20); + VERIFY_ARE_EQUAL(vSpans[1].GetCooldown(), (UINT32)30); + VERIFY_ARE_EQUAL(vSpans[1].GetRandSeed(), (UINT32)40); + VERIFY_ARE_EQUAL(vSpans[1].GetThreadCount(), (DWORD)50); + VERIFY_ARE_EQUAL(vSpans[1].GetRequestCount(), (DWORD)0); + VERIFY_IS_TRUE(vSpans[1].GetDisableAffinity() == true); + VERIFY_IS_TRUE(vSpans[1].GetMeasureLatency() == true); + + vTargets = vSpans[1].GetTargets(); + VERIFY_ARE_EQUAL(vTargets.size(), (size_t)4); + + t = vTargets[0]; + VERIFY_IS_TRUE(t.GetPath().compare("testfile.dat") == 0); + VERIFY_ARE_EQUAL(t.GetBlockSizeInBytes(), (DWORD)(100)); + VERIFY_ARE_EQUAL(t.GetWriteRatio(), (DWORD)84); + VERIFY_IS_TRUE(t.GetMemoryMappedIoMode() == MemoryMappedIoMode::On); + + // verify FlushViewOfFile + t = vTargets[1]; + VERIFY_IS_TRUE(t.GetPath().compare("testfile1.dat") == 0); + VERIFY_ARE_EQUAL(t.GetBlockSizeInBytes(), (DWORD)(100)); + VERIFY_ARE_EQUAL(t.GetWriteRatio(), (DWORD)84); + VERIFY_IS_TRUE(t.GetMemoryMappedIoMode() == MemoryMappedIoMode::On); + VERIFY_IS_TRUE(t.GetMemoryMappedIoFlushMode() == MemoryMappedIoFlushMode::ViewOfFile); + + // verify RtlFlushNonVolatileMemory + t = vTargets[2]; + VERIFY_IS_TRUE(t.GetPath().compare("testfile2.dat") == 0); + VERIFY_ARE_EQUAL(t.GetBlockSizeInBytes(), (DWORD)(100)); + VERIFY_ARE_EQUAL(t.GetWriteRatio(), (DWORD)84); + VERIFY_IS_TRUE(t.GetMemoryMappedIoMode() == MemoryMappedIoMode::On); + VERIFY_IS_TRUE(t.GetMemoryMappedIoFlushMode() == MemoryMappedIoFlushMode::NonVolatileMemory); + + // verify RtlFlushNonVolatileMemoryNoDrain + t = vTargets[3]; + VERIFY_IS_TRUE(t.GetPath().compare("testfile3.dat") == 0); + VERIFY_ARE_EQUAL(t.GetBlockSizeInBytes(), (DWORD)(100)); + VERIFY_ARE_EQUAL(t.GetWriteRatio(), (DWORD)84); + VERIFY_IS_TRUE(t.GetMemoryMappedIoMode() == MemoryMappedIoMode::On); + VERIFY_IS_TRUE(t.GetMemoryMappedIoFlushMode() == MemoryMappedIoFlushMode::NonVolatileMemoryNoDrain); + } + + void XmlProfileParserUnitTests::Test_ParseFilePrecreateFilesUseMaxSize() + { + FILE *pFile; + fopen_s(&pFile, _sTempFilePath.c_str(), "wb"); + VERIFY_IS_TRUE(pFile != nullptr); + fprintf(pFile, "\n" + "\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " UseMaxSize\n" + "\n"); + fclose(pFile); + + XmlProfileParser p; + Profile profile; + VERIFY_IS_TRUE(p.ParseFile(_sTempFilePath.c_str(), &profile, nullptr, _hModule)); + VERIFY_IS_TRUE(profile.Validate(false)); + VERIFY_IS_TRUE(profile.GetPrecreateFiles() == PrecreateFiles::UseMaxSize); + } + + void XmlProfileParserUnitTests::Test_ParseFilePrecreateFilesOnlyFilesWithConstantSizes() + { + FILE *pFile; + fopen_s(&pFile, _sTempFilePath.c_str(), "wb"); + VERIFY_IS_TRUE(pFile != nullptr); + fprintf(pFile, "\n" + "\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " CreateOnlyFilesWithConstantSizes\n" + "\n"); + fclose(pFile); + + XmlProfileParser p; + Profile profile; + VERIFY_IS_TRUE(p.ParseFile(_sTempFilePath.c_str(), &profile, nullptr, _hModule)); + VERIFY_IS_TRUE(profile.Validate(false)); + VERIFY_IS_TRUE(profile.GetPrecreateFiles() == PrecreateFiles::OnlyFilesWithConstantSizes); + } + + void XmlProfileParserUnitTests::Test_ParseFilePrecreateFilesOnlyFilesWithConstantOrZeroSizes() + { + FILE *pFile; + fopen_s(&pFile, _sTempFilePath.c_str(), "wb"); + VERIFY_IS_TRUE(pFile != nullptr); + fprintf(pFile, "\n" + "\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " CreateOnlyFilesWithConstantOrZeroSizes\n" + "\n"); + fclose(pFile); + + XmlProfileParser p; + Profile profile; + VERIFY_IS_TRUE(p.ParseFile(_sTempFilePath.c_str(), &profile, nullptr, _hModule)); + VERIFY_IS_TRUE(profile.Validate(false)); + VERIFY_IS_TRUE(profile.GetPrecreateFiles() == PrecreateFiles::OnlyFilesWithConstantOrZeroSizes); + } + + void XmlProfileParserUnitTests::Test_ParseFileWriteBufferContentSequential() + { + FILE *pFile; + fopen_s(&pFile, _sTempFilePath.c_str(), "wb"); + VERIFY_IS_TRUE(pFile != nullptr); + fprintf(pFile, "\n" + "\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " sequential\n" + " \n" + " \n" + " \n" + " \n" + " \n" + "\n"); + fclose(pFile); + + XmlProfileParser p; + Profile profile; + VERIFY_IS_TRUE(p.ParseFile(_sTempFilePath.c_str(), &profile, nullptr, _hModule)); + VERIFY_IS_TRUE(profile.Validate(false)); + vector vTimespans(profile.GetTimeSpans()); + VERIFY_ARE_EQUAL(vTimespans.size(), (size_t)1); + vector vTargets(vTimespans[0].GetTargets()); + VERIFY_ARE_EQUAL(vTargets.size(), (size_t)1); + Target t = vTargets[0]; + VERIFY_IS_TRUE(t.GetZeroWriteBuffers() == false); + VERIFY_ARE_EQUAL(t.GetRandomDataWriteBufferSize(), 0); + VERIFY_IS_TRUE(t.GetRandomDataWriteBufferSourcePath() == ""); + } + + void XmlProfileParserUnitTests::Test_ParseGroupAffinity() + { + // normal case + { + FILE *pFile; + fopen_s(&pFile, _sTempFilePath.c_str(), "wb"); + VERIFY_IS_TRUE(pFile != nullptr); + fprintf(pFile, "\n" + "\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "\n"); + fclose(pFile); + + XmlProfileParser p; + Profile profile; + VERIFY_IS_TRUE(p.ParseFile(_sTempFilePath.c_str(), &profile, nullptr, _hModule)); + VERIFY_IS_TRUE(profile.Validate(false)); + vector vTimespans(profile.GetTimeSpans()); + VERIFY_ARE_EQUAL(vTimespans.size(), (size_t)1); + + const auto& vAffinity(vTimespans[0].GetAffinityAssignments()); + VERIFY_ARE_EQUAL(vAffinity.size(), (size_t)2); + VERIFY_ARE_EQUAL(vAffinity[0].wGroup, 0); + VERIFY_ARE_EQUAL(vAffinity[0].bProc, (BYTE)2); + VERIFY_ARE_EQUAL(vAffinity[1].wGroup, 1); + VERIFY_ARE_EQUAL(vAffinity[1].bProc, (BYTE)32); + } + + // out-of-range processor index (BYTE) + { + FILE *pFile; + fopen_s(&pFile, _sTempFilePath.c_str(), "wb"); + VERIFY_IS_TRUE(pFile != nullptr); + fprintf(pFile, "\n" + "\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "\n"); + fclose(pFile); + + XmlProfileParser p; + Profile profile; + VERIFY_IS_FALSE(p.ParseFile(_sTempFilePath.c_str(), &profile, nullptr, _hModule)); + } + + // out-of-range group index (WORD) + { + FILE *pFile; + fopen_s(&pFile, _sTempFilePath.c_str(), "wb"); + VERIFY_IS_TRUE(pFile != nullptr); + fprintf(pFile, "\n" + "\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "\n"); + fclose(pFile); + + XmlProfileParser p; + Profile profile; + VERIFY_IS_FALSE(p.ParseFile(_sTempFilePath.c_str(), &profile, nullptr, _hModule)); + } + } + + void XmlProfileParserUnitTests::Test_ParseNonGroupAffinity() + { + FILE *pFile; + fopen_s(&pFile, _sTempFilePath.c_str(), "wb"); + VERIFY_IS_TRUE(pFile != nullptr); + fprintf(pFile, "\n" + "\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " 1\n" + " 31\n" + " \n" + " \n" + " \n" + "\n"); + fclose(pFile); + + XmlProfileParser p; + Profile profile; + VERIFY_IS_TRUE(p.ParseFile(_sTempFilePath.c_str(), &profile, nullptr, _hModule)); + VERIFY_IS_TRUE(profile.Validate(false)); + vector vTimespans(profile.GetTimeSpans()); + VERIFY_ARE_EQUAL(vTimespans.size(), (size_t)1); + + // Old style, group is wired to zero. + const auto& vAffinity(vTimespans[0].GetAffinityAssignments()); + VERIFY_ARE_EQUAL(vAffinity.size(), (size_t)2); + VERIFY_ARE_EQUAL(vAffinity[0].wGroup, 0); + VERIFY_ARE_EQUAL(vAffinity[0].bProc, (BYTE)1); + VERIFY_ARE_EQUAL(vAffinity[1].wGroup, 0); + VERIFY_ARE_EQUAL(vAffinity[1].bProc, (BYTE)31); + } + + void XmlProfileParserUnitTests::Test_ParseFileWriteBufferContentZero() + { + FILE *pFile; + fopen_s(&pFile, _sTempFilePath.c_str(), "wb"); + VERIFY_IS_TRUE(pFile != nullptr); + fprintf(pFile, "\n" + "\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " zero\n" + " \n" + " \n" + " \n" + " \n" + " \n" + "\n"); + fclose(pFile); + + XmlProfileParser p; + Profile profile; + VERIFY_IS_TRUE(p.ParseFile(_sTempFilePath.c_str(), &profile, nullptr, _hModule)); + VERIFY_IS_TRUE(profile.Validate(false)); + vector vTimespans(profile.GetTimeSpans()); + VERIFY_ARE_EQUAL(vTimespans.size(), (size_t)1); + vector vTargets(vTimespans[0].GetTargets()); + VERIFY_ARE_EQUAL(vTargets.size(), (size_t)1); + Target t = vTargets[0]; + VERIFY_IS_TRUE(t.GetZeroWriteBuffers() == true); + VERIFY_ARE_EQUAL(t.GetRandomDataWriteBufferSize(), 0); + VERIFY_IS_TRUE(t.GetRandomDataWriteBufferSourcePath() == ""); + } + + void XmlProfileParserUnitTests::Test_ParseFileWriteBufferContentRandom() + { + FILE *pFile; + fopen_s(&pFile, _sTempFilePath.c_str(), "wb"); + VERIFY_IS_TRUE(pFile != nullptr); + fprintf(pFile, "\n" + "\n" + " \n" + " \n" + " true" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "\n"); + fclose(pFile); + + XmlProfileParser p; + Profile profile; + VERIFY_IS_TRUE(p.ParseFile(_sTempFilePath.c_str(), &profile, nullptr, _hModule)); + VERIFY_IS_TRUE(profile.Validate(false)); + vector vTimespans(profile.GetTimeSpans()); + VERIFY_ARE_EQUAL(vTimespans.size(), (size_t)1); + VERIFY_IS_TRUE(vTimespans[0].GetRandomWriteData() == true); + vector vTargets(vTimespans[0].GetTargets()); + VERIFY_ARE_EQUAL(vTargets.size(), (size_t)1); + Target t = vTargets[0]; + VERIFY_IS_TRUE(t.GetZeroWriteBuffers() == false); + VERIFY_ARE_EQUAL(t.GetRandomDataWriteBufferSize(), 0); + VERIFY_IS_TRUE(t.GetRandomDataWriteBufferSourcePath() == ""); + } + + void XmlProfileParserUnitTests::Test_ParseFileWriteBufferContentRandomNoFilePath() + { + FILE *pFile; + fopen_s(&pFile, _sTempFilePath.c_str(), "wb"); + VERIFY_IS_TRUE(pFile != nullptr); + fprintf(pFile, "\n" + "\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " random\n" + " \n" + " 223311\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "\n"); + fclose(pFile); + + XmlProfileParser p; + Profile profile; + VERIFY_IS_TRUE(p.ParseFile(_sTempFilePath.c_str(), &profile, nullptr, _hModule)); + VERIFY_IS_TRUE(profile.Validate(false)); + vector vTimespans(profile.GetTimeSpans()); + VERIFY_ARE_EQUAL(vTimespans.size(), (size_t)1); + vector vTargets(vTimespans[0].GetTargets()); + VERIFY_ARE_EQUAL(vTargets.size(), (size_t)1); + Target t = vTargets[0]; + VERIFY_IS_TRUE(t.GetZeroWriteBuffers() == false); + VERIFY_ARE_EQUAL(t.GetRandomDataWriteBufferSize(), 223311); + VERIFY_IS_TRUE(t.GetRandomDataWriteBufferSourcePath() == ""); + } + + void XmlProfileParserUnitTests::Test_ParseFileWriteBufferContentRandomWithFilePath() + { + FILE *pFile; + fopen_s(&pFile, _sTempFilePath.c_str(), "wb"); + VERIFY_IS_TRUE(pFile != nullptr); + fprintf(pFile, "\n" + "\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " random\n" + " \n" + " 223311\n" + " x:\\foo\\bar.dat\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "\n"); + fclose(pFile); + + XmlProfileParser p; + Profile profile; + VERIFY_IS_TRUE(p.ParseFile(_sTempFilePath.c_str(), &profile, nullptr, _hModule)); + VERIFY_IS_TRUE(profile.Validate(false)); + vector vTimespans(profile.GetTimeSpans()); + VERIFY_ARE_EQUAL(vTimespans.size(), (size_t)1); + vector vTargets(vTimespans[0].GetTargets()); + VERIFY_ARE_EQUAL(vTargets.size(), (size_t)1); + Target t = vTargets[0]; + VERIFY_IS_TRUE(t.GetZeroWriteBuffers() == false); + VERIFY_ARE_EQUAL(t.GetRandomDataWriteBufferSize(), 223311); + VERIFY_IS_TRUE(t.GetRandomDataWriteBufferSourcePath() == "x:\\foo\\bar.dat"); + } + + void XmlProfileParserUnitTests::Test_ParseFileGlobalRequestCount() + { + FILE *pFile; + fopen_s(&pFile, _sTempFilePath.c_str(), "wb"); + VERIFY_IS_TRUE(pFile != nullptr); + fprintf(pFile, "\n" + "\n" + " \n" + " \n" + " 4\n" + " 6\n" + " \n" + " \n" + " \n" + " 100\n" + " \n" + " \n" + " 0\n" + " 200\n" + " \n" + " \n" + " 1\n" + " 50\n" + " \n" + " \n" + " 2\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " 100\n" + " \n" + " \n" + " \n" + " \n" + "\n"); + fclose(pFile); + + XmlProfileParser p; + Profile profile; + VERIFY_IS_TRUE(p.ParseFile(_sTempFilePath.c_str(), &profile, nullptr, _hModule)); + VERIFY_IS_TRUE(profile.Validate(false)); + vector vTimespans(profile.GetTimeSpans()); + VERIFY_ARE_EQUAL(vTimespans.size(), (size_t)1); + VERIFY_ARE_EQUAL(vTimespans[0].GetThreadCount(), (DWORD)4); + VERIFY_ARE_EQUAL(vTimespans[0].GetRequestCount(), (DWORD)6); + vector vTargets(vTimespans[0].GetTargets()); + VERIFY_ARE_EQUAL(vTargets.size(), (size_t)2); + VERIFY_ARE_EQUAL(vTargets[0].GetWeight(), (UINT32)100); + vector vThreadTargets(vTargets[0].GetThreadTargets()); + VERIFY_ARE_EQUAL(vThreadTargets.size(), (size_t)3); + VERIFY_ARE_EQUAL(vThreadTargets[0].GetThread(), (UINT32)0); + VERIFY_ARE_EQUAL(vThreadTargets[0].GetWeight(), (UINT32)200); + VERIFY_ARE_EQUAL(vThreadTargets[1].GetThread(), (UINT32)1); + VERIFY_ARE_EQUAL(vThreadTargets[1].GetWeight(), (UINT32)50); + VERIFY_ARE_EQUAL(vThreadTargets[2].GetThread(), (UINT32)2); + VERIFY_ARE_EQUAL(vThreadTargets[2].GetWeight(), (UINT32)0); + VERIFY_ARE_EQUAL(vTargets[1].GetWeight(), (UINT32)100); + VERIFY_ARE_EQUAL(vTargets[1].GetThreadTargets().size(), (size_t)0); + } + + void XmlProfileParserUnitTests::Test_ParseThroughput() + { + const PCHAR xmlDoc = "\n" + "\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " %s\n" + " %s\n" + " \n" + " \n" + " \n" + " \n" + "\n"; + XmlProfileParser p; + FILE *pFile = nullptr; + + // + // Positive varations - units & default + // + + { + Profile profile; + fopen_s(&pFile, _sTempFilePath.c_str(), "wb"); + VERIFY_IS_TRUE(pFile != nullptr); + fprintf(pFile, xmlDoc, "131072", " unit=\"IOPS\"", "10"); + fclose(pFile); + pFile = nullptr; + + VERIFY_IS_TRUE(p.ParseFile(_sTempFilePath.c_str(), &profile, nullptr, _hModule)); + VERIFY_IS_TRUE(profile.Validate(false)); + VERIFY_ARE_EQUAL(profile.GetTimeSpans()[0].GetTargets()[0].GetThroughputInBytesPerMillisecond(), (DWORD)((128*1024*10)/1000)); + } + + { + Profile profile; + fopen_s(&pFile, _sTempFilePath.c_str(), "wb"); + VERIFY_IS_TRUE(pFile != nullptr); + fprintf(pFile, xmlDoc, "131072", " unit=\"BPMS\"", "1500"); + fclose(pFile); + pFile = nullptr; + + VERIFY_IS_TRUE(p.ParseFile(_sTempFilePath.c_str(), &profile, nullptr, _hModule)); + VERIFY_IS_TRUE(profile.Validate(false)); + VERIFY_ARE_EQUAL(profile.GetTimeSpans()[0].GetTargets()[0].GetThroughputInBytesPerMillisecond(), (DWORD)1500); + } + + { + Profile profile; + fopen_s(&pFile, _sTempFilePath.c_str(), "wb"); + VERIFY_IS_TRUE(pFile != nullptr); + fprintf(pFile, xmlDoc, "131072", "", "1024"); + fclose(pFile); + pFile = nullptr; + + VERIFY_IS_TRUE(p.ParseFile(_sTempFilePath.c_str(), &profile, nullptr, _hModule)); + VERIFY_IS_TRUE(profile.Validate(false)); + VERIFY_ARE_EQUAL(profile.GetTimeSpans()[0].GetTargets()[0].GetThroughputInBytesPerMillisecond(), (DWORD)1024); + } + + // + // Negative variations - bad units / good units with bad data + // + + { + Profile profile; + fopen_s(&pFile, _sTempFilePath.c_str(), "wb"); + VERIFY_IS_TRUE(pFile != nullptr); + fprintf(pFile, xmlDoc, "131072", " unit=\"FRUIT\"", "1500"); + fclose(pFile); + pFile = nullptr; + + VERIFY_IS_FALSE(p.ParseFile(_sTempFilePath.c_str(), &profile, nullptr, _hModule)); + } + + { + Profile profile; + fopen_s(&pFile, _sTempFilePath.c_str(), "wb"); + VERIFY_IS_TRUE(pFile != nullptr); + fprintf(pFile, xmlDoc, "131072", " unit=\"IOPS\"", "FRUIT"); + fclose(pFile); + pFile = nullptr; + + VERIFY_IS_FALSE(p.ParseFile(_sTempFilePath.c_str(), &profile, nullptr, _hModule)); + } + + { + Profile profile; + fopen_s(&pFile, _sTempFilePath.c_str(), "wb"); + VERIFY_IS_TRUE(pFile != nullptr); + fprintf(pFile, xmlDoc, "131072", " unit=\"BPMS\"", "FRUIT"); + fclose(pFile); + pFile = nullptr; + + VERIFY_IS_FALSE(p.ParseFile(_sTempFilePath.c_str(), &profile, nullptr, _hModule)); + } + + { + Profile profile; + fopen_s(&pFile, _sTempFilePath.c_str(), "wb"); + VERIFY_IS_TRUE(pFile != nullptr); + fprintf(pFile, xmlDoc, "131072", "", "FRUIT"); + fclose(pFile); + pFile = nullptr; + + VERIFY_IS_FALSE(p.ParseFile(_sTempFilePath.c_str(), &profile, nullptr, _hModule)); + } + } + + void XmlProfileParserUnitTests::Test_ParseRandomSequentialMixed() + { + const PCHAR xmlDoc = "\n" + "\n" + " \n" + " \n" + " \n" + " \n" + " \n" + "%s" // insert conflicts + " %s" // Random/RandomRatio + " \n" + " \n" + " \n" + " \n" + "\n"; + XmlProfileParser p; + FILE *pFile = nullptr; + + // Positive cases + + // Isolated + + { + Profile profile; + fopen_s(&pFile, _sTempFilePath.c_str(), "wb"); + VERIFY_IS_TRUE(pFile != nullptr); + fprintf(pFile, xmlDoc, "", "Ratio", "50", "Ratio"); + fclose(pFile); + pFile = nullptr; + + VERIFY_IS_TRUE(p.ParseFile(_sTempFilePath.c_str(), &profile, nullptr, _hModule)); + VERIFY_IS_TRUE(profile.Validate(false)); + VERIFY_ARE_EQUAL(profile.GetTimeSpans()[0].GetTargets()[0].GetRandomRatio(), (UINT32) 50); + } + + // With + + { + Profile profile; + fopen_s(&pFile, _sTempFilePath.c_str(), "wb"); + VERIFY_IS_TRUE(pFile != nullptr); + fprintf(pFile, xmlDoc, "8192", "Ratio", "50", "Ratio"); + fclose(pFile); + pFile = nullptr; + + VERIFY_IS_TRUE(p.ParseFile(_sTempFilePath.c_str(), &profile, nullptr, _hModule)); + VERIFY_IS_TRUE(profile.Validate(false)); + VERIFY_ARE_EQUAL(profile.GetTimeSpans()[0].GetTargets()[0].GetRandomRatio(), (UINT32) 50); + } + + // Negative, bounds validation + + { + Profile profile; + fopen_s(&pFile, _sTempFilePath.c_str(), "wb"); + VERIFY_IS_TRUE(pFile != nullptr); + fprintf(pFile, xmlDoc, "", "Ratio", "0", "Ratio"); + fclose(pFile); + pFile = nullptr; + + VERIFY_IS_FALSE(p.ParseFile(_sTempFilePath.c_str(), &profile, nullptr, _hModule)); + } + { + Profile profile; + fopen_s(&pFile, _sTempFilePath.c_str(), "wb"); + VERIFY_IS_TRUE(pFile != nullptr); + fprintf(pFile, xmlDoc, "", "Ratio", "100", "Ratio"); + fclose(pFile); + pFile = nullptr; + + VERIFY_IS_FALSE(p.ParseFile(_sTempFilePath.c_str(), &profile, nullptr, _hModule)); + } + { + Profile profile; + fopen_s(&pFile, _sTempFilePath.c_str(), "wb"); + VERIFY_IS_TRUE(pFile != nullptr); + fprintf(pFile, xmlDoc, "", "Ratio", "-100", "Ratio"); + fclose(pFile); + pFile = nullptr; + + VERIFY_IS_FALSE(p.ParseFile(_sTempFilePath.c_str(), &profile, nullptr, _hModule)); + } + { + Profile profile; + fopen_s(&pFile, _sTempFilePath.c_str(), "wb"); + VERIFY_IS_TRUE(pFile != nullptr); + fprintf(pFile, xmlDoc, "", "Ratio", "200", "Ratio"); + fclose(pFile); + pFile = nullptr; + + VERIFY_IS_FALSE(p.ParseFile(_sTempFilePath.c_str(), &profile, nullptr, _hModule)); + } + { + Profile profile; + fopen_s(&pFile, _sTempFilePath.c_str(), "wb"); + VERIFY_IS_TRUE(pFile != nullptr); + fprintf(pFile, xmlDoc, "", "Ratio", "junk", "Ratio"); + fclose(pFile); + pFile = nullptr; + + VERIFY_IS_FALSE(p.ParseFile(_sTempFilePath.c_str(), &profile, nullptr, _hModule)); + } + + // Negative, sequential conflict with RandomRatio + { + Profile profile; + fopen_s(&pFile, _sTempFilePath.c_str(), "wb"); + VERIFY_IS_TRUE(pFile != nullptr); + fprintf(pFile, xmlDoc, "8192", "Ratio", "50", "Ratio"); + fclose(pFile); + pFile = nullptr; + + VERIFY_IS_FALSE(p.ParseFile(_sTempFilePath.c_str(), &profile, nullptr, _hModule)); + } + + // Negative, sequential conflict with Random + { + Profile profile; + fopen_s(&pFile, _sTempFilePath.c_str(), "wb"); + VERIFY_IS_TRUE(pFile != nullptr); + fprintf(pFile, xmlDoc, "8192", "", "8192", ""); + fclose(pFile); + pFile = nullptr; + + VERIFY_IS_FALSE(p.ParseFile(_sTempFilePath.c_str(), &profile, nullptr, _hModule)); + } + } + + // Template document for running distribution tests - type tags bracketing a type-specific insert + static const PCHAR xmlDistDoc = "\n" + "\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " 65536\n" + " \n" + " <%s>\n" // type + " %s" // ranges + " \n" // type + " " + " \n" + " \n" + " \n" + " \n" + "\n"; + + void XmlProfileParserUnitTests::ValidateDistribution( + const PWCHAR desc, + boolean expectedParse, + boolean expectedValidate, + DistributionType type, + PCHAR xmlDoc, + const RangePair *insert, + const DistQuad *dist + ) + { + Profile profile; + XmlProfileParser p; + FILE *pFile = nullptr; + string xmlInsert; + + // Construct XML range list + for (UINT32 i = 0; i < insert->size; i++) + { + xmlInsert += "range[i].io); + xmlInsert += "\">"; + xmlInsert += to_string(insert->range[i].target); + xmlInsert += "\n"; + } + + // Bracketing typename - xmlDoc is assumed to be of the form ...[insert here]... + PCHAR typeName = nullptr; + + switch (type) + { + case DistributionType::Absolute: + typeName = "Absolute"; + break; + + case DistributionType::Percent: + typeName = "Percent"; + break; + + default: + assert(false); + break; + } + + // Generate content into temporary file and parse/validate + // Emit the description at parse validation for documentation in the output + fopen_s(&pFile, _sTempFilePath.c_str(), "wb"); + VERIFY_IS_TRUE(pFile != nullptr); + fprintf(pFile, xmlDoc, typeName, xmlInsert.c_str(), typeName); + fclose(pFile); + + if (!expectedParse) + { + VERIFY_IS_FALSE(p.ParseFile(_sTempFilePath.c_str(), &profile, nullptr, _hModule), desc); + return; // done + } + + VERIFY_IS_TRUE(p.ParseFile(_sTempFilePath.c_str(), &profile, nullptr, _hModule), desc); + + if (!expectedValidate) + { + VERIFY_IS_FALSE(profile.Validate(false)); + return; // done + } + + VERIFY_IS_TRUE(profile.Validate(false)); + auto t = profile.GetTimeSpans()[0].GetTargets()[0]; + auto dt = t.GetDistributionType(); + auto& v = t.GetDistributionRange(); + + VERIFY_ARE_EQUAL(type, dt); + VERIFY_ARE_EQUAL(dist->size, v.size()); + for (size_t i = 0; i < v.size(); ++i) + { + VERIFY_ARE_EQUAL(v[i]._src, dist->range[i].ioBase); + VERIFY_ARE_EQUAL(v[i]._span, dist->range[i].ioSpan); + VERIFY_ARE_EQUAL(v[i]._dst.first, dist->range[i].targetBase); + VERIFY_ARE_EQUAL(v[i]._dst.second, dist->range[i].targetSpan); + } + } + + void XmlProfileParserUnitTests::Test_ParseDistributionAbsolute() + { + // + // Positive cases - first matches the ResultParser UT + // + + { + // -rdabs10/1g:10/1g:0/100g + // hole + tail + const RangePair insert = { + 3, + {{10, 1*GB}, + {10, 1*GB}, + {0, 100*GB}} + }; + const DistQuad dist = { + 4, + {{0, 10, 0, 1*GB}, + {10, 10, 1*GB, 1*GB}, + {20, 0, 2*GB, 100*GB}, + {20, 80, 102*GB, 0}} + }; + + ValidateDistribution(L"Case 1", true, true, DistributionType::Absolute, xmlDistDoc, &insert, &dist); + } + + // + // Negative cases + // + + { + // -rdabs10/10 (note lack of units/small) + // same negative case in cmdlineparser + const RangePair insert = { + 1, + {{10, 10}} + }; + + ValidateDistribution(L"Case 2", true, false, DistributionType::Absolute, xmlDistDoc, &insert, nullptr); + } + { + // zero target not at end + const RangePair insert = { + 3, + {{10, 1*GB}, + {10, 0}, + {80, 1*GB}} + }; + + ValidateDistribution(L"Case 3", true, false, DistributionType::Absolute, xmlDistDoc, &insert, nullptr); + } + { + // -rdabs10/10G:80/10G:20:10G + // IO% overflow + const RangePair insert = { + 3, + {{10, 10*GB}, + {80, 10*GB}, + {20, 10*GB}} + }; + + ValidateDistribution(L"Case 4", true, false, DistributionType::Absolute, xmlDistDoc, &insert, nullptr); + } + } + + void XmlProfileParserUnitTests::Test_ParseDistributionPercent() + { + // + // Positive cases - first matches the ResultParser UT + // + + { + // -rdpct10/10:10/10:0/10 + // hole + tail + const RangePair insert = { + 3, + {{10, 10}, + {10, 10}, + {0, 10}} + }; + const DistQuad dist = { + 4, + {{0, 10, 0, 10}, + {10, 10, 10, 10}, + {20, 0, 20, 10}, + {20, 80, 30, 70}} + }; + + ValidateDistribution(L"Case 1", true, true, DistributionType::Percent, xmlDistDoc, &insert, &dist); + } + + // + // Negative cases + // + + { + // zero target not at end - fails parse (before validate) + const RangePair insert = { + 3, + {{10, 10}, + {10, 0}, + {80, 10}} + }; + + ValidateDistribution(L"Case 2", false, false, DistributionType::Percent, xmlDistDoc, &insert, nullptr); + } + { + // zero target at end - fails parse (before validate) + const RangePair insert = { + 2, + {{10, 10}, + {90, 0}} + }; + + ValidateDistribution(L"Case 3", false, false, DistributionType::Percent, xmlDistDoc, &insert, nullptr); + } + { + // IO% overflow / Target% OK + const RangePair insert = { + 3, + {{10, 10}, + {80, 10}, + {20, 80}} + }; + + ValidateDistribution(L"Case 4", true, false, DistributionType::Percent, xmlDistDoc, &insert, nullptr); + } + { + // IO% 100% / Target% incomplete + const RangePair insert = { + 3, + {{10, 10}, + {80, 10}, + {10, 10}} + }; + + ValidateDistribution(L"Case 5", true, false, DistributionType::Percent, xmlDistDoc, &insert, nullptr); + } + { + // IO% incomplete / Target% 100% + const RangePair insert = { + 3, + {{10, 10}, + {10, 80}, + {10, 10}} + }; + + ValidateDistribution(L"Case 6", true, false, DistributionType::Percent, xmlDistDoc, &insert, nullptr); + } + } + + void XmlProfileParserUnitTests::Test_ParseTemplateTargets() + { + const PCHAR xmlDocPre = \ + "\n" + "\n" + " \n"; + + const PCHAR xmlDocPost = \ + " \n" + "\n"; + + const PCHAR xmlTimeSpanPre = \ + "\n" + " \n"; + + const PCHAR xmlTimeSpanPost = \ + " \n" + "\n"; + + const PCHAR xmlTarget = \ + "\n" + " %s\n" + "\n"; + + XmlProfileParser p; + FILE *pFile = nullptr; + + // Non template baseline - null ptr pass for subst + + { + Profile profile; + fopen_s(&pFile, _sTempFilePath.c_str(), "wb"); + VERIFY_IS_TRUE(pFile != nullptr); + fprintf(pFile, xmlDocPre); + fprintf(pFile, xmlTimeSpanPre); + fprintf(pFile, xmlTarget, "foo.bin"); + fprintf(pFile, xmlTimeSpanPost); + fprintf(pFile, xmlDocPost); + fclose(pFile); + pFile = nullptr; + + VERIFY_IS_TRUE(p.ParseFile(_sTempFilePath.c_str(), &profile, nullptr, _hModule)); + VERIFY_IS_TRUE(profile.Validate(false)); + VERIFY_IS_TRUE(!strcmp(profile.GetTimeSpans()[0].GetTargets()[0].GetPath().c_str(), "foo.bin")); + } + + // Non template baseline - empty pass for subst + + { + Profile profile; + fopen_s(&pFile, _sTempFilePath.c_str(), "wb"); + VERIFY_IS_TRUE(pFile != nullptr); + fprintf(pFile, xmlDocPre); + fprintf(pFile, xmlTimeSpanPre); + fprintf(pFile, xmlTarget, "foo.bin"); + fprintf(pFile, xmlTimeSpanPost); + fprintf(pFile, xmlDocPost); + fclose(pFile); + pFile = nullptr; + + vector vTargets; + + VERIFY_IS_TRUE(p.ParseFile(_sTempFilePath.c_str(), &profile, &vTargets, _hModule)); + VERIFY_IS_TRUE(profile.Validate(false)); + VERIFY_IS_TRUE(!strcmp(profile.GetTimeSpans()[0].GetTargets()[0].GetPath().c_str(), "foo.bin")); + } + + // Template - 1 template, bad formats which will not parse (and will parse independent of subst) + + { + + char *cStrs[] = { "*", "*foo", "*1foo", "**1", "*-1" }; + + for (auto s : cStrs) + { + Profile profile; + fopen_s(&pFile, _sTempFilePath.c_str(), "wb"); + VERIFY_IS_TRUE(pFile != nullptr); + fprintf(pFile, xmlDocPre); + fprintf(pFile, xmlTimeSpanPre); + fprintf(pFile, xmlTarget, s); + fprintf(pFile, xmlTimeSpanPost); + fprintf(pFile, xmlDocPost); + fclose(pFile); + pFile = nullptr; + + vector vTargets; + + VERIFY_IS_FALSE(p.ParseFile(_sTempFilePath.c_str(), &profile, &vTargets, _hModule)); + } + } + + // Template - 1 template, unsubst, will fail execution validation since !profile only + + { + Profile profile; + fopen_s(&pFile, _sTempFilePath.c_str(), "wb"); + VERIFY_IS_TRUE(pFile != nullptr); + fprintf(pFile, xmlDocPre); + fprintf(pFile, xmlTimeSpanPre); + fprintf(pFile, xmlTarget, "*1"); + fprintf(pFile, xmlTimeSpanPost); + fprintf(pFile, xmlDocPost); + fclose(pFile); + pFile = nullptr; + + vector vTargets; + + VERIFY_IS_TRUE(p.ParseFile(_sTempFilePath.c_str(), &profile, &vTargets, _hModule)); + VERIFY_IS_FALSE(profile.Validate(false)); + VERIFY_IS_TRUE(!strcmp(profile.GetTimeSpans()[0].GetTargets()[0].GetPath().c_str(), "*1")); + } + + // Template - 1 timespan 1 template, unsubst, will pass execution validation since profile only + + { + Profile profile; + fopen_s(&pFile, _sTempFilePath.c_str(), "wb"); + VERIFY_IS_TRUE(pFile != nullptr); + fprintf(pFile, xmlDocPre); + fprintf(pFile, xmlTimeSpanPre); + fprintf(pFile, xmlTarget, "*1"); + fprintf(pFile, xmlTimeSpanPost); + fprintf(pFile, xmlDocPost); + fclose(pFile); + pFile = nullptr; + + vector vTargets; + + VERIFY_IS_TRUE(p.ParseFile(_sTempFilePath.c_str(), &profile, &vTargets, _hModule)); + profile.SetProfileOnly(true); + VERIFY_IS_TRUE(profile.Validate(false)); + VERIFY_IS_TRUE(!strcmp(profile.GetTimeSpans()[0].GetTargets()[0].GetPath().c_str(), "*1")); + } + + // Template - 1 timespan 1 template 1 subst - will pass execution validation + + { + Profile profile; + fopen_s(&pFile, _sTempFilePath.c_str(), "wb"); + VERIFY_IS_TRUE(pFile != nullptr); + fprintf(pFile, xmlDocPre); + fprintf(pFile, xmlTimeSpanPre); + fprintf(pFile, xmlTarget, "*1"); + fprintf(pFile, xmlTimeSpanPost); + fprintf(pFile, xmlDocPost); + fclose(pFile); + pFile = nullptr; + + vector vTargets; + vTargets.emplace_back(); + vTargets[0].SetPath("foo.bin"); + + VERIFY_IS_TRUE(p.ParseFile(_sTempFilePath.c_str(), &profile, &vTargets, _hModule)); + VERIFY_IS_TRUE(profile.Validate(false)); + VERIFY_IS_TRUE(!strcmp(profile.GetTimeSpans()[0].GetTargets()[0].GetPath().c_str(), "foo.bin")); + } + + // Template - 1 timespan 1 template 2 subst - will fail parse due to unused subst + + { + Profile profile; + fopen_s(&pFile, _sTempFilePath.c_str(), "wb"); + VERIFY_IS_TRUE(pFile != nullptr); + fprintf(pFile, xmlDocPre); + fprintf(pFile, xmlTimeSpanPre); + fprintf(pFile, xmlTarget, "*1"); + fprintf(pFile, xmlTimeSpanPost); + fprintf(pFile, xmlDocPost); + fclose(pFile); + pFile = nullptr; + + vector vTargets; + vTargets.emplace_back(); + vTargets[0].SetPath("foo.bin"); + vTargets.emplace_back(); + vTargets[1].SetPath("bar.bin"); + + VERIFY_IS_FALSE(p.ParseFile(_sTempFilePath.c_str(), &profile, &vTargets, _hModule)); + } + + // 1 timespan 2 same template 1 subst + + { + Profile profile; + fopen_s(&pFile, _sTempFilePath.c_str(), "wb"); + VERIFY_IS_TRUE(pFile != nullptr); + fprintf(pFile, xmlDocPre); + fprintf(pFile, xmlTimeSpanPre); + fprintf(pFile, xmlTarget, "*1"); + fprintf(pFile, xmlTarget, "*1"); + fprintf(pFile, xmlTimeSpanPost); + fprintf(pFile, xmlDocPost); + fclose(pFile); + pFile = nullptr; + + vector vTargets; + vTargets.emplace_back(); + vTargets[0].SetPath("foo.bin"); + + VERIFY_IS_TRUE(p.ParseFile(_sTempFilePath.c_str(), &profile, &vTargets, _hModule)); + VERIFY_IS_TRUE(profile.Validate(false)); + VERIFY_IS_TRUE(!strcmp(profile.GetTimeSpans()[0].GetTargets()[0].GetPath().c_str(), "foo.bin")); + VERIFY_IS_TRUE(!strcmp(profile.GetTimeSpans()[0].GetTargets()[1].GetPath().c_str(), "foo.bin")); + } + + // 1 timespan 2 template 2 subst + + { + Profile profile; + fopen_s(&pFile, _sTempFilePath.c_str(), "wb"); + VERIFY_IS_TRUE(pFile != nullptr); + fprintf(pFile, xmlDocPre); + fprintf(pFile, xmlTimeSpanPre); + fprintf(pFile, xmlTarget, "*1"); + fprintf(pFile, xmlTarget, "*2"); + fprintf(pFile, xmlTimeSpanPost); + fprintf(pFile, xmlDocPost); + fclose(pFile); + pFile = nullptr; + + vector vTargets; + vTargets.emplace_back(); + vTargets[0].SetPath("foo.bin"); + vTargets.emplace_back(); + vTargets[1].SetPath("bar.bin"); + + VERIFY_IS_TRUE(p.ParseFile(_sTempFilePath.c_str(), &profile, &vTargets, _hModule)); + VERIFY_IS_TRUE(profile.Validate(false)); + VERIFY_IS_TRUE(!strcmp(profile.GetTimeSpans()[0].GetTargets()[0].GetPath().c_str(), "foo.bin")); + VERIFY_IS_TRUE(!strcmp(profile.GetTimeSpans()[0].GetTargets()[1].GetPath().c_str(), "bar.bin")); + } + + // 1 timespan 2 template 1 subst - will fail since second template does not have a subst + + { + Profile profile; + fopen_s(&pFile, _sTempFilePath.c_str(), "wb"); + VERIFY_IS_TRUE(pFile != nullptr); + fprintf(pFile, xmlDocPre); + fprintf(pFile, xmlTimeSpanPre); + fprintf(pFile, xmlTarget, "*1"); + fprintf(pFile, xmlTarget, "*2"); + fprintf(pFile, xmlTimeSpanPost); + fprintf(pFile, xmlDocPost); + fclose(pFile); + pFile = nullptr; + + vector vTargets; + vTargets.emplace_back(); + vTargets[0].SetPath("foo.bin"); + + VERIFY_IS_FALSE(p.ParseFile(_sTempFilePath.c_str(), &profile, &vTargets, _hModule)); + } + + // 2 timespan same template 1 subst + + { + Profile profile; + fopen_s(&pFile, _sTempFilePath.c_str(), "wb"); + VERIFY_IS_TRUE(pFile != nullptr); + fprintf(pFile, xmlDocPre); + fprintf(pFile, xmlTimeSpanPre); + fprintf(pFile, xmlTarget, "*1"); + fprintf(pFile, xmlTimeSpanPost); + fprintf(pFile, xmlTimeSpanPre); + fprintf(pFile, xmlTarget, "*1"); + fprintf(pFile, xmlTimeSpanPost); + fprintf(pFile, xmlDocPost); + fclose(pFile); + pFile = nullptr; + + vector vTargets; + vTargets.emplace_back(); + vTargets[0].SetPath("foo.bin"); + + VERIFY_IS_TRUE(p.ParseFile(_sTempFilePath.c_str(), &profile, &vTargets, _hModule)); + VERIFY_IS_TRUE(profile.Validate(false)); + VERIFY_IS_TRUE(!strcmp(profile.GetTimeSpans()[0].GetTargets()[0].GetPath().c_str(), "foo.bin")); + VERIFY_IS_TRUE(!strcmp(profile.GetTimeSpans()[1].GetTargets()[0].GetPath().c_str(), "foo.bin")); + } + + // 2 timespan 1 template/ea 2 subst + + { + Profile profile; + fopen_s(&pFile, _sTempFilePath.c_str(), "wb"); + VERIFY_IS_TRUE(pFile != nullptr); + fprintf(pFile, xmlDocPre); + fprintf(pFile, xmlTimeSpanPre); + fprintf(pFile, xmlTarget, "*1"); + fprintf(pFile, xmlTimeSpanPost); + fprintf(pFile, xmlTimeSpanPre); + fprintf(pFile, xmlTarget, "*2"); + fprintf(pFile, xmlTimeSpanPost); + fprintf(pFile, xmlDocPost); + fclose(pFile); + pFile = nullptr; + + vector vTargets; + vTargets.emplace_back(); + vTargets[0].SetPath("foo.bin"); + vTargets.emplace_back(); + vTargets[1].SetPath("bar.bin"); + + VERIFY_IS_TRUE(p.ParseFile(_sTempFilePath.c_str(), &profile, &vTargets, _hModule)); + VERIFY_IS_TRUE(profile.Validate(false)); + VERIFY_IS_TRUE(!strcmp(profile.GetTimeSpans()[0].GetTargets()[0].GetPath().c_str(), "foo.bin")); + VERIFY_IS_TRUE(!strcmp(profile.GetTimeSpans()[1].GetTargets()[0].GetPath().c_str(), "bar.bin")); + } + } +} \ No newline at end of file diff --git a/CristalDiskMark/source/diskspd22/UnitTests/XmlProfileParser/XmlProfileParser.UnitTests.h b/CristalDiskMark/source/diskspd22/UnitTests/XmlProfileParser/XmlProfileParser.UnitTests.h new file mode 100644 index 0000000..31eaafc --- /dev/null +++ b/CristalDiskMark/source/diskspd22/UnitTests/XmlProfileParser/XmlProfileParser.UnitTests.h @@ -0,0 +1,116 @@ +/* + +DISKSPD + +Copyright(c) Microsoft Corporation +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#pragma once +#include "WexTestClass.h" +#include "XmlProfileParser.h" +#include +using namespace std; + +namespace UnitTests +{ + BEGIN_MODULE() + MODULE_PROPERTY(L"Feature", L"XmlProfileParser") + END_MODULE() + + MODULE_SETUP(ModuleSetup); + MODULE_CLEANUP(ModuleCleanup); + + class XmlProfileParserUnitTests : public WEX::TestClass + { + public: + TEST_CLASS(XmlProfileParserUnitTests) + + TEST_CLASS_SETUP(ClassSetup); + TEST_CLASS_CLEANUP(ClassCleanup); + + TEST_METHOD_SETUP(MethodSetup); + TEST_METHOD_CLEANUP(MethodCleanup); + + TEST_METHOD(Test_ParseDistributionAbsolute); + TEST_METHOD(Test_ParseDistributionPercent); + TEST_METHOD(Test_ParseFile); + TEST_METHOD(Test_ParseFileGlobalRequestCount); + TEST_METHOD(Test_ParseFilePrecreateFilesOnlyFilesWithConstantOrZeroSizes); + TEST_METHOD(Test_ParseFilePrecreateFilesOnlyFilesWithConstantSizes); + TEST_METHOD(Test_ParseFilePrecreateFilesUseMaxSize); + TEST_METHOD(Test_ParseFileWriteBufferContentRandom); + TEST_METHOD(Test_ParseFileWriteBufferContentRandomNoFilePath); + TEST_METHOD(Test_ParseFileWriteBufferContentRandomWithFilePath); + TEST_METHOD(Test_ParseFileWriteBufferContentSequential); + TEST_METHOD(Test_ParseFileWriteBufferContentZero); + TEST_METHOD(Test_ParseGroupAffinity); + TEST_METHOD(Test_ParseNonGroupAffinity); + TEST_METHOD(Test_ParseRandomSequentialMixed); + TEST_METHOD(Test_ParseTemplateTargets); + TEST_METHOD(Test_ParseThroughput); + + // + // Utility wrapping the specification and validation of a given distribution. + // + // Note that % and abs distributions are represented in the same way, only + // differing in the relative scale of the target spans. + // + + #pragma warning(push) + #pragma warning(disable:4200) // zero length array + + typedef struct { + UINT32 size; + struct { + UINT32 io; + UINT64 target; + } range[]; + } RangePair; + + typedef struct { + UINT32 size; + struct{ + UINT32 ioBase, ioSpan; + UINT64 targetBase, targetSpan; + } range[]; + } DistQuad; + + #pragma warning(pop) + + void ValidateDistribution( + const PWCHAR desc, + boolean expectedParseResult, + boolean expectedValidate, + DistributionType type, + PCHAR xmlDoc, + const RangePair *insert, + const DistQuad *dist + ); + + private: + string _sTempFilePath; + HMODULE _hModule; + }; +} diff --git a/CristalDiskMark/source/diskspd22/UnitTests/XmlProfileParser/XmlProfileParser.rc b/CristalDiskMark/source/diskspd22/UnitTests/XmlProfileParser/XmlProfileParser.rc new file mode 100644 index 0000000..b13c31b --- /dev/null +++ b/CristalDiskMark/source/diskspd22/UnitTests/XmlProfileParser/XmlProfileParser.rc @@ -0,0 +1,19 @@ +#include +#include "Version.h" + +DISKSPD.XSD HTML "..\\XmlProfileParser\\diskspd.xsd" + +#include + +#define VER_FILETYPE VFT_APP +#define VER_FILESUBTYPE VFT2_UNKNOWN +#define VER_FILEDESCRIPTION_STR "DiskSpd Storage Performance Tool" +#define VER_INTERNALNAME_STR "XmlProfileParser.UnitTests.dll" + +#undef VER_PRODUCTVERSION +#define VER_PRODUCTVERSION DISKSPD_MAJOR,DISKSPD_MINOR,DISKSPD_BUILD,DISKSPD_QFE + +#undef VER_PRODUCTVERSION_STR +#define VER_PRODUCTVERSION_STR DISKSPD_NUMERIC_VERSION_STRING + +#include "common.ver" diff --git a/CristalDiskMark/source/diskspd22/UnitTests/XmlProfileParser/stdafx.h b/CristalDiskMark/source/diskspd22/UnitTests/XmlProfileParser/stdafx.h new file mode 100644 index 0000000..a79da8d --- /dev/null +++ b/CristalDiskMark/source/diskspd22/UnitTests/XmlProfileParser/stdafx.h @@ -0,0 +1,32 @@ +/* + +DISKSPD + +Copyright(c) Microsoft Corporation +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#pragma once + +#include \ No newline at end of file diff --git a/CristalDiskMark/source/diskspd22/UnitTests/XmlResultParser/XmlResultParser.UnitTests.cpp b/CristalDiskMark/source/diskspd22/UnitTests/XmlResultParser/XmlResultParser.UnitTests.cpp new file mode 100644 index 0000000..2accbde --- /dev/null +++ b/CristalDiskMark/source/diskspd22/UnitTests/XmlResultParser/XmlResultParser.UnitTests.cpp @@ -0,0 +1,464 @@ +/* + +DISKSPD + +Copyright(c) Microsoft Corporation +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#include "StdAfx.h" +#include "XmlResultParser.UnitTests.h" +#include "Common.h" +#include "xmlresultparser.h" +#include +#include + +using namespace WEX::TestExecution; +using namespace WEX::Logging; +using namespace std; + +namespace UnitTests +{ + void XmlResultParserUnitTests::Test_ParseResults() + { + Profile profile; + TimeSpan timeSpan; + Target target; + XmlResultParser parser; + + Results results; + results.fUseETW = false; + double fTime = 120.0; + results.ullTimeCount = PerfTimer::SecondsToPerfTime(fTime); + + // First group has 1 active cpu + // 30% user, 45% idle, 25% non-idle kernel (45% + 25% = 70%) + SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION systemProcessorInfo = { 0 }; + systemProcessorInfo.UserTime.QuadPart = static_cast(fTime * 30 * 100000); + systemProcessorInfo.IdleTime.QuadPart = static_cast(fTime * 45 * 100000); + systemProcessorInfo.KernelTime.QuadPart = static_cast(fTime * 70 * 100000); + results.vSystemProcessorPerfInfo.push_back(systemProcessorInfo); + + // Second group has 2 active + // 100% idle + systemProcessorInfo.UserTime.QuadPart = static_cast(fTime * 0 * 100000); + systemProcessorInfo.IdleTime.QuadPart = static_cast(fTime * 100 * 100000); + systemProcessorInfo.KernelTime.QuadPart = static_cast(fTime * 100 * 100000); + results.vSystemProcessorPerfInfo.push_back(systemProcessorInfo); + results.vSystemProcessorPerfInfo.push_back(systemProcessorInfo); + + // TODO: multiple target cases, full profile/result variations + target.SetPath("testfile1.dat"); + target.SetCacheMode(TargetCacheMode::DisableOSCache); + target.SetWriteThroughMode(WriteThroughMode::On); + target.SetThroughputIOPS(1000); + + timeSpan.AddTarget(target); + timeSpan.SetCalculateIopsStdDev(true); + + TargetResults targetResults; + targetResults.sPath = "testfile1.dat"; + targetResults.ullFileSize = 10 * 1024 * 1024; + targetResults.ullReadBytesCount = 4 * 1024 * 1024; + targetResults.ullReadIOCount = 6; + targetResults.ullWriteBytesCount = 2 * 1024 * 1024; + targetResults.ullWriteIOCount = 10; + targetResults.ullBytesCount = targetResults.ullReadBytesCount + targetResults.ullWriteBytesCount; + targetResults.ullIOCount = targetResults.ullReadIOCount + targetResults.ullWriteIOCount; + + // TODO: Histogram readLatencyHistogram; + // TODO: Histogram writeLatencyHistogram; + // TODO: IoBucketizer writeBucketizer; + + targetResults.readBucketizer.Initialize(1000, timeSpan.GetDuration()); + for (size_t i = 0; i < timeSpan.GetDuration(); i++) + { + // add an io halfway through the bucket's time interval + targetResults.readBucketizer.Add(i*1000 + 500, 0); + } + + ThreadResults threadResults; + threadResults.vTargetResults.push_back(targetResults); + results.vThreadResults.push_back(threadResults); + + vector vResults; + vResults.push_back(results); + + // Just throw away the computername, pp and reset the timestamp - for the ut, it's + // as useful (and simpler) to verify statics as anything else. Reconstruct the + // processor topo to a fixed example as well. Note that the performance + // efficiency class must be placed since it is calculated on the fly during + // the actual GLPIEx enumeration. If we could shim GLPIEx ... + SystemInformation system; + system.ResetTime(); + system.sComputerName.clear(); + system.sActivePolicyName.clear(); + system.sActivePolicyGuid.clear(); + + system.processorTopology._ulProcessorCount = 3; + system.processorTopology._ubPerformanceEfficiencyClass = 1; + system.processorTopology._fSMT = true; + + system.processorTopology._vProcessorGroupInformation.clear(); + system.processorTopology._vProcessorGroupInformation.emplace_back((WORD)0, (BYTE)1, (BYTE)1, (KAFFINITY)0x1); + system.processorTopology._vProcessorGroupInformation.emplace_back((WORD)1, (BYTE)4, (BYTE)2, (KAFFINITY)0x3); + + ProcessorNumaInformation node; + node._nodeNumber = 0; + node._vProcessorMasks.emplace_back((WORD)0, (KAFFINITY)0x1); + node._vProcessorMasks.emplace_back((WORD)1, (KAFFINITY)0x3); + system.processorTopology._vProcessorNumaInformation.clear(); + system.processorTopology._vProcessorNumaInformation.push_back(node); + + ProcessorSocketInformation socket; + socket._vProcessorMasks.emplace_back((WORD)0, (KAFFINITY)0x1); + socket._vProcessorMasks.emplace_back((WORD)1, (KAFFINITY)0x3); + system.processorTopology._vProcessorSocketInformation.clear(); + system.processorTopology._vProcessorSocketInformation.push_back(socket); + + system.processorTopology._vProcessorCoreInformation.clear(); + system.processorTopology._vProcessorCoreInformation.emplace_back((WORD)0, (KAFFINITY)0x1, (BYTE)0); + system.processorTopology._vProcessorCoreInformation.emplace_back((WORD)1, (KAFFINITY)0x3, (BYTE)1); + + // finally, add the timespan to the profile and dump. + profile.AddTimeSpan(timeSpan); + + string sResults = parser.ParseResults(profile, system, vResults); + + // stringify random text, quoting "'s and adding newline/preserving tabs + // gc some.txt |% { write-host $("`"{0}\n`"" -f $($_ -replace "`"","\`"" -replace "`t","\t")) } + + const char *pcszExpectedOutput = \ + "\n" + " \n" + " \n" + " \n" + " " DISKSPD_NUMERIC_VERSION_STRING "\n" + " " DISKSPD_DATE_VERSION_STRING "\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " 0\n" + " text\n" + " false\n" + " \n" + " \n" + " false\n" + " false\n" + " true\n" + " false\n" + " 10\n" + " 5\n" + " 0\n" + " 0\n" + " 0\n" + " 1000\n" + " 0\n" + " \n" + " \n" + " testfile1.dat\n" + " 65536\n" + " 0\n" + " false\n" + " false\n" + " false\n" + " false\n" + " true\n" + " true\n" + " \n" + " sequential\n" + " \n" + " false\n" + " 65536\n" + " false\n" + " 0\n" + " 0\n" + " 2\n" + " 0\n" + " 1000\n" + " 1\n" + " 3\n" + " 1\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " 120.00\n" + " 1\n" + " 0\n" + " 3\n" + " \n" + " \n" + " 0\n" + " 0\n" + " 0\n" + " 0\n" + " 0\n" + " 0\n" + " 55.00\n" + " 30.00\n" + " 25.00\n" + " 45.00\n" + " \n" + " \n" + " 0\n" + " 0\n" + " 1\n" + " 0\n" + " 1\n" + " 0\n" + " 0.00\n" + " 0.00\n" + " 0.00\n" + " 100.00\n" + " \n" + " \n" + " 0\n" + " 0\n" + " 1\n" + " 0\n" + " 1\n" + " 1\n" + " 0.00\n" + " 0.00\n" + " 0.00\n" + " 100.00\n" + " \n" + " \n" + " 18.33\n" + " 10.00\n" + " 8.33\n" + " 81.67\n" + " \n" + " \n" + " \n" + " 0.000\n" + " 0.000\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " 0\n" + " \n" + " testfile1.dat\n" + " 6291456\n" + " 10485760\n" + " 16\n" + " 4194304\n" + " 6\n" + " 2097152\n" + " 10\n" + " \n" + " 0.000\n" + " 0.000\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + ""; + +#if 0 + HANDLE h; + DWORD written; + h = CreateFileW(L"g:\\xmlresult-received.txt", GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + WriteFile(h, sResults.c_str(), (DWORD)sResults.length(), &written, NULL); + VERIFY_ARE_EQUAL(sResults.length(), written); + CloseHandle(h); + + h = CreateFileW(L"g:\\xmlresult-expected.txt", GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + WriteFile(h, pcszExpectedOutput, (DWORD)strlen(pcszExpectedOutput), &written, NULL); + VERIFY_ARE_EQUAL((DWORD)strlen(pcszExpectedOutput), written); + CloseHandle(h); + + printf("--\n%s\n", sResults.c_str()); + printf("-------------------------------------------------\n"); + printf("--\n%s\n", pcszExpectedOutput); +#endif + + VERIFY_ARE_EQUAL(0, strcmp(sResults.c_str(), pcszExpectedOutput)); + } + + void XmlResultParserUnitTests::Test_ParseProfile() + { + Profile profile; + XmlResultParser parser; + TimeSpan timeSpan; + Target target; + + timeSpan.AddTarget(target); + profile.AddTimeSpan(timeSpan); + + string s = parser.ParseProfile(profile); + const char *pcszExpectedOutput = "\n" + " 0\n" + " text\n" + " false\n" + " \n" + " \n" + " false\n" + " false\n" + " false\n" + " false\n" + " 10\n" + " 5\n" + " 0\n" + " 0\n" + " 0\n" + " 1000\n" + " 0\n" + " \n" + " \n" + " \n" + " 65536\n" + " 0\n" + " false\n" + " false\n" + " false\n" + " false\n" + " \n" + " sequential\n" + " \n" + " false\n" + " 65536\n" + " false\n" + " 0\n" + " 0\n" + " 2\n" + " 0\n" + " 0\n" + " 1\n" + " 3\n" + " 1\n" + " \n" + " \n" + " \n" + " \n" + "\n"; + + //VERIFY_ARE_EQUAL(pcszExpectedOutput, s.c_str()); + VERIFY_ARE_EQUAL(strlen(pcszExpectedOutput), s.length()); + VERIFY_IS_TRUE(!strcmp(pcszExpectedOutput, s.c_str())); + } + + void XmlResultParserUnitTests::Test_ParseTargetProfile() + { + Target target; + string sResults; + char pszExpectedOutput[4096]; + int nWritten; + + const char *pcszOutputTemplate = \ + "\n" + " testfile1.dat\n" + " 65536\n" + " 0\n" + " false\n" + " false\n" + " false\n" + " false\n" + " true\n" + " true\n" + " \n" + " sequential\n" + " \n" + " false\n" + " 65536\n" + " false\n" + " 0\n" + " 0\n" + " 2\n" + " 0\n" + " %s\n" // 2 param + " 1\n" + " 3\n" + " 1\n" + "\n"; + + target.SetPath("testfile1.dat"); + target.SetCacheMode(TargetCacheMode::DisableOSCache); + target.SetWriteThroughMode(WriteThroughMode::On); + + // Base case - no limit + + nWritten = sprintf_s(pszExpectedOutput, sizeof(pszExpectedOutput), + pcszOutputTemplate, "", "0"); + VERIFY_IS_GREATER_THAN(nWritten, 0); + sResults = target.GetXml(0); + VERIFY_ARE_EQUAL(sResults, pszExpectedOutput); + + // IOPS - with units + + target.SetThroughputIOPS(1000); + nWritten = sprintf_s(pszExpectedOutput, sizeof(pszExpectedOutput), + pcszOutputTemplate, " unit=\"IOPS\"", "1000"); + VERIFY_IS_GREATER_THAN(nWritten, 0); + sResults = target.GetXml(0); + VERIFY_ARE_EQUAL(sResults, pszExpectedOutput); + + // BPMS - not specified with units in output + + target.SetThroughput(1000); + nWritten = sprintf_s(pszExpectedOutput, sizeof(pszExpectedOutput), + pcszOutputTemplate, "", "1000"); + VERIFY_IS_GREATER_THAN(nWritten, 0); + sResults = target.GetXml(0); + VERIFY_ARE_EQUAL(sResults, pszExpectedOutput); + } +} \ No newline at end of file diff --git a/CristalDiskMark/source/diskspd22/UnitTests/XmlResultParser/XmlResultParser.UnitTests.h b/CristalDiskMark/source/diskspd22/UnitTests/XmlResultParser/XmlResultParser.UnitTests.h new file mode 100644 index 0000000..acebf22 --- /dev/null +++ b/CristalDiskMark/source/diskspd22/UnitTests/XmlResultParser/XmlResultParser.UnitTests.h @@ -0,0 +1,47 @@ +/* + +DISKSPD + +Copyright(c) Microsoft Corporation +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#pragma once +#include "WexTestClass.h" + +namespace UnitTests +{ + BEGIN_MODULE() + MODULE_PROPERTY(L"Feature", L"XmlResultParser") + END_MODULE() + + class XmlResultParserUnitTests : public WEX::TestClass + { + public: + TEST_CLASS(XmlResultParserUnitTests); + TEST_METHOD(Test_ParseResults); + TEST_METHOD(Test_ParseProfile); + TEST_METHOD(Test_ParseTargetProfile); + }; +} \ No newline at end of file diff --git a/CristalDiskMark/source/diskspd22/UnitTests/XmlResultParser/XmlResultParser.rc b/CristalDiskMark/source/diskspd22/UnitTests/XmlResultParser/XmlResultParser.rc new file mode 100644 index 0000000..286016e --- /dev/null +++ b/CristalDiskMark/source/diskspd22/UnitTests/XmlResultParser/XmlResultParser.rc @@ -0,0 +1,17 @@ +#include +#include "Version.h" + +#include + +#define VER_FILETYPE VFT_APP +#define VER_FILESUBTYPE VFT2_UNKNOWN +#define VER_FILEDESCRIPTION_STR "DiskSpd Storage Performance Tool" +#define VER_INTERNALNAME_STR "XmlResultParser.UnitTests.dll" + +#undef VER_PRODUCTVERSION +#define VER_PRODUCTVERSION DISKSPD_MAJOR,DISKSPD_MINOR,DISKSPD_BUILD,DISKSPD_QFE + +#undef VER_PRODUCTVERSION_STR +#define VER_PRODUCTVERSION_STR DISKSPD_NUMERIC_VERSION_STRING + +#include "common.ver" diff --git a/CristalDiskMark/source/diskspd22/UnitTests/XmlResultParser/stdafx.h b/CristalDiskMark/source/diskspd22/UnitTests/XmlResultParser/stdafx.h new file mode 100644 index 0000000..a79da8d --- /dev/null +++ b/CristalDiskMark/source/diskspd22/UnitTests/XmlResultParser/stdafx.h @@ -0,0 +1,32 @@ +/* + +DISKSPD + +Copyright(c) Microsoft Corporation +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#pragma once + +#include \ No newline at end of file diff --git a/CristalDiskMark/source/diskspd22/XmlProfileParser/XmlProfileParser.cpp b/CristalDiskMark/source/diskspd22/XmlProfileParser/XmlProfileParser.cpp new file mode 100644 index 0000000..be75dc6 --- /dev/null +++ b/CristalDiskMark/source/diskspd22/XmlProfileParser/XmlProfileParser.cpp @@ -0,0 +1,1533 @@ +/* + +DISKSPD + +Copyright(c) Microsoft Corporation +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#include "XmlProfileParser.h" +#include +#include +#include +#include + +HRESULT ReportXmlError( + const char *pszName, + IXMLDOMParseError *pXMLError + ) +{ + long line; + long linePos; + long errorCode = E_FAIL; + CComBSTR bReason; + BSTR bstr; + HRESULT hr; + + hr = pXMLError->get_line(&line); + if (FAILED(hr)) + { + line = 0; + } + hr = pXMLError->get_linepos(&linePos); + if (FAILED(hr)) + { + linePos = 0; + } + hr = pXMLError->get_errorCode(&errorCode); + if (FAILED(hr)) + { + errorCode = E_FAIL; + } + hr = pXMLError->get_reason(&bstr); + if (SUCCEEDED(hr)) + { + bReason.Attach(bstr); + } + + fprintf(stderr, + "ERROR: failed to load %s, line %lu, line position %lu, errorCode %08x\nERROR: reason: %S\n", + pszName, line, linePos, errorCode, (PWCHAR)bReason); + + return errorCode; +} + +bool XmlProfileParser::ParseFile(const char *pszPath, Profile *pProfile, vector *pvSubstTargets, HMODULE hModule) +{ + assert(pszPath != nullptr); + assert(pProfile != nullptr); + + // import schema from the named resource + HRSRC hSchemaXmlResource = FindResource(hModule, L"DISKSPD.XSD", RT_HTML); + assert(hSchemaXmlResource != NULL); + HGLOBAL hSchemaXml = LoadResource(hModule, hSchemaXmlResource); + assert(hSchemaXml != NULL); + LPVOID pSchemaXml = LockResource(hSchemaXml); + assert(pSchemaXml != NULL); + + // convert from utf-8 produced by the xsd authoring tool to utf-16 + int cchSchemaXml = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)pSchemaXml, -1, NULL, 0); + vector vWideSchemaXml(cchSchemaXml); + int dwcchWritten = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)pSchemaXml, -1, vWideSchemaXml.data(), cchSchemaXml); + UNREFERENCED_PARAMETER(dwcchWritten); + assert(dwcchWritten == cchSchemaXml); + // ... and finally, packed in a bstr for the loadXml interface + CComBSTR bSchemaXml(vWideSchemaXml.data()); + + bool fComInitialized = false; + HRESULT hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED); + if (SUCCEEDED(hr)) + { + fComInitialized = true; + CComPtr spXmlDoc = nullptr; + CComPtr spXmlSchema = nullptr; + CComPtr spXmlSchemaColl = nullptr; + CComPtr spXmlParseError = nullptr; + + // create com objects and decorate + hr = CoCreateInstance(__uuidof(DOMDocument60), nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&spXmlSchema)); + if (SUCCEEDED(hr)) + { + hr = spXmlSchema->put_async(VARIANT_FALSE); + } + if (SUCCEEDED(hr)) + { + hr = spXmlSchema->setProperty(CComBSTR("ProhibitDTD"), CComVariant(VARIANT_FALSE)); + } + if (SUCCEEDED(hr)) + { + hr = CoCreateInstance(__uuidof(XMLSchemaCache60), nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&spXmlSchemaColl)); + } + if (SUCCEEDED(hr)) + { + hr = spXmlSchemaColl->put_validateOnLoad(VARIANT_TRUE); + } + if (SUCCEEDED(hr)) + { + hr = CoCreateInstance(__uuidof(DOMDocument60), nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&spXmlDoc)); + } + if (SUCCEEDED(hr)) + { + hr = spXmlDoc->put_async(VARIANT_FALSE); + } + if (SUCCEEDED(hr)) + { + hr = spXmlDoc->put_validateOnParse(VARIANT_TRUE); + } + if (SUCCEEDED(hr)) + { + VARIANT_BOOL fvIsOk; + hr = spXmlSchema->loadXML(bSchemaXml, &fvIsOk); + if (FAILED(hr) || fvIsOk != VARIANT_TRUE) + { + hr = spXmlSchema->get_parseError(&spXmlParseError); + if (SUCCEEDED(hr)) + { + ReportXmlError("schema", spXmlParseError); + } + hr = E_FAIL; + } + } + if (SUCCEEDED(hr)) + { + CComVariant vXmlSchema(spXmlSchema); + CComBSTR bNull(""); + hr = spXmlSchemaColl->add(bNull, vXmlSchema); + } + if (SUCCEEDED(hr)) + { + CComVariant vSchemaCache(spXmlSchemaColl); + hr = spXmlDoc->putref_schemas(vSchemaCache); + } + if (SUCCEEDED(hr)) + { + VARIANT_BOOL fvIsOk; + CComVariant vPath(pszPath); + hr = spXmlDoc->load(vPath, &fvIsOk); + if (FAILED(hr) || fvIsOk != VARIANT_TRUE) + { + hr = spXmlDoc->get_parseError(&spXmlParseError); + if (SUCCEEDED(hr)) + { + ReportXmlError("profile", spXmlParseError); + } + hr = E_FAIL; + } + } + + // + // XML has now passed basic schema validation. Bulld the target substitutions and parse the profile. + // + + vector> vSubsts; + + if (pvSubstTargets) + { + for (auto target : *pvSubstTargets) + { + vSubsts.emplace_back(make_pair(target.GetPath(), false)); + } + } + + if (SUCCEEDED(hr)) + { + bool b; + hr = _GetBool(spXmlDoc, "//Profile/Verbose", &b); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + pProfile->SetVerbose(b); + } + } + + if (SUCCEEDED(hr)) + { + bool b; + hr = _GetBool(spXmlDoc, "//Profile/VerboseStats", &b); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + pProfile->SetVerboseStats(b); + } + } + + if (SUCCEEDED(hr)) + { + DWORD i; + hr = _GetDWORD(spXmlDoc, "//Profile/ExperimentFlags", &i); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + g_ExperimentFlags = i; + } + } + + if (SUCCEEDED(hr)) + { + DWORD i; + hr = _GetDWORD(spXmlDoc, "//Profile/Progress", &i); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + pProfile->SetProgress(i); + } + } + + if (SUCCEEDED(hr)) + { + string sResultFormat; + hr = _GetString(spXmlDoc, "//Profile/ResultFormat", &sResultFormat); + if (SUCCEEDED(hr) && (hr != S_FALSE) && sResultFormat == "xml") + { + pProfile->SetResultsFormat(ResultsFormat::Xml); + } + } + + if (SUCCEEDED(hr)) + { + string sCreateFiles; + hr = _GetString(spXmlDoc, "//Profile/PrecreateFiles", &sCreateFiles); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + if (sCreateFiles == "UseMaxSize") + { + pProfile->SetPrecreateFiles(PrecreateFiles::UseMaxSize); + } + else if (sCreateFiles == "CreateOnlyFilesWithConstantSizes") + { + pProfile->SetPrecreateFiles(PrecreateFiles::OnlyFilesWithConstantSizes); + } + else if (sCreateFiles == "CreateOnlyFilesWithConstantOrZeroSizes") + { + pProfile->SetPrecreateFiles(PrecreateFiles::OnlyFilesWithConstantOrZeroSizes); + } + else + { + hr = E_INVALIDARG; + } + } + } + + if (SUCCEEDED(hr)) + { + hr = _ParseEtw(spXmlDoc, pProfile); + } + + if (SUCCEEDED(hr)) + { + hr = _ParseTimeSpans(spXmlDoc, pProfile, vSubsts); + } + + // + // Error on unused substitutions - user should ensure these match up. + // + // Note that no (zero) substitutions are OK at the point of parsing, which allows + // for -Rp forms on template profiles. Validation for executed profiles will occur + // later during common validation. + // + // Generate an error for each unused substitution. + // + + if (SUCCEEDED(hr)) + { + for (size_t i = 1; i <= vSubsts.size(); ++i) + { + if (!vSubsts[i - 1].second) + { + fprintf(stderr, "ERROR: unused template target substitution _%u -> %s - check profile\n", (int) i, vSubsts[i - 1].first.c_str()); + hr = E_INVALIDARG; + } + } + } + } + + if (fComInitialized) + { + CoUninitialize(); + } + + return SUCCEEDED(hr); +} + +HRESULT XmlProfileParser::_ParseEtw(IXMLDOMDocument2 *pXmlDoc, Profile *pProfile) +{ + bool fEtwProcess; + HRESULT hr = _GetBool(pXmlDoc, "//Profile/ETW/Process", &fEtwProcess); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + pProfile->SetEtwEnabled(true); + pProfile->SetEtwProcess(fEtwProcess); + } + + if (SUCCEEDED(hr)) + { + bool fEtwThread; + hr = _GetBool(pXmlDoc, "//Profile/ETW/Thread", &fEtwThread); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + pProfile->SetEtwEnabled(true); + pProfile->SetEtwThread(fEtwThread); + } + } + + if (SUCCEEDED(hr)) + { + bool fEtwImageLoad; + hr = _GetBool(pXmlDoc, "//Profile/ETW/ImageLoad", &fEtwImageLoad); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + pProfile->SetEtwEnabled(true); + pProfile->SetEtwImageLoad(fEtwImageLoad); + } + } + + if (SUCCEEDED(hr)) + { + bool fEtwDiskIO; + hr = _GetBool(pXmlDoc, "//Profile/ETW/DiskIO", &fEtwDiskIO); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + pProfile->SetEtwEnabled(true); + pProfile->SetEtwDiskIO(fEtwDiskIO); + } + } + + if (SUCCEEDED(hr)) + { + bool fEtwMemoryPageFaults; + hr = _GetBool(pXmlDoc, "//Profile/ETW/MemoryPageFaults", &fEtwMemoryPageFaults); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + pProfile->SetEtwEnabled(true); + pProfile->SetEtwMemoryPageFaults(fEtwMemoryPageFaults); + } + } + + if (SUCCEEDED(hr)) + { + bool fEtwMemoryHardFaults; + hr = _GetBool(pXmlDoc, "//Profile/ETW/MemoryHardFaults", &fEtwMemoryHardFaults); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + pProfile->SetEtwEnabled(true); + pProfile->SetEtwMemoryHardFaults(fEtwMemoryHardFaults); + } + } + + if (SUCCEEDED(hr)) + { + bool fEtwNetwork; + hr = _GetBool(pXmlDoc, "//Profile/ETW/Network", &fEtwNetwork); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + pProfile->SetEtwEnabled(true); + pProfile->SetEtwNetwork(fEtwNetwork); + } + } + + if (SUCCEEDED(hr)) + { + bool fEtwRegistry; + hr = _GetBool(pXmlDoc, "//Profile/ETW/Registry", &fEtwRegistry); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + pProfile->SetEtwEnabled(true); + pProfile->SetEtwRegistry(fEtwRegistry); + } + } + + if (SUCCEEDED(hr)) + { + bool fEtwUsePagedMemory; + hr = _GetBool(pXmlDoc, "//Profile/ETW/UsePagedMemory", &fEtwUsePagedMemory); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + pProfile->SetEtwEnabled(true); + pProfile->SetEtwUsePagedMemory(fEtwUsePagedMemory); + } + } + + if (SUCCEEDED(hr)) + { + bool fEtwUsePerfTimer; + hr = _GetBool(pXmlDoc, "//Profile/ETW/UsePerfTimer", &fEtwUsePerfTimer); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + pProfile->SetEtwEnabled(true); + pProfile->SetEtwUsePerfTimer(fEtwUsePerfTimer); + } + } + + if (SUCCEEDED(hr)) + { + bool fEtwUseSystemTimer; + hr = _GetBool(pXmlDoc, "//Profile/ETW/UseSystemTimer", &fEtwUseSystemTimer); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + pProfile->SetEtwEnabled(true); + pProfile->SetEtwUseSystemTimer(fEtwUseSystemTimer); + } + } + + if (SUCCEEDED(hr)) + { + bool fEtwUseCyclesCounter; + hr = _GetBool(pXmlDoc, "//Profile/ETW/UseCyclesCounter", &fEtwUseCyclesCounter); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + pProfile->SetEtwEnabled(true); + pProfile->SetEtwUseCyclesCounter(fEtwUseCyclesCounter); + } + } + + return hr; +} + +HRESULT XmlProfileParser::_ParseTimeSpans(IXMLDOMDocument2 *pXmlDoc, Profile *pProfile, vector>& vSubsts) +{ + CComPtr spNodeList = nullptr; + CComVariant query("//Profile/TimeSpans/TimeSpan"); + HRESULT hr = pXmlDoc->selectNodes(query.bstrVal, &spNodeList); + if (SUCCEEDED(hr)) + { + long cNodes; + hr = spNodeList->get_length(&cNodes); + if (SUCCEEDED(hr)) + { + for (int i = 0; i < cNodes; i++) + { + CComPtr spNode = nullptr; + hr = spNodeList->get_item(i, &spNode); + if (SUCCEEDED(hr)) + { + TimeSpan timeSpan; + hr = _ParseTimeSpan(spNode, &timeSpan, vSubsts); + if (SUCCEEDED(hr)) + { + pProfile->AddTimeSpan(timeSpan); + } + } + } + } + } + + return hr; +} + +HRESULT XmlProfileParser::_ParseTimeSpan(IXMLDOMNode *pXmlNode, TimeSpan *pTimeSpan, vector>& vSubsts) +{ + UINT32 ulDuration; + HRESULT hr = _GetUINT32(pXmlNode, "Duration", &ulDuration); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + pTimeSpan->SetDuration(ulDuration); + } + + if (SUCCEEDED(hr)) + { + UINT32 ulWarmup; + hr = _GetUINT32(pXmlNode, "Warmup", &ulWarmup); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + pTimeSpan->SetWarmup(ulWarmup); + } + } + + if (SUCCEEDED(hr)) + { + UINT32 ulCooldown; + hr = _GetUINT32(pXmlNode, "Cooldown", &ulCooldown); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + pTimeSpan->SetCooldown(ulCooldown); + } + } + + if (SUCCEEDED(hr)) + { + UINT32 ulRandSeed; + hr = _GetUINT32(pXmlNode, "RandSeed", &ulRandSeed); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + pTimeSpan->SetRandSeed(ulRandSeed); + } + } + + if (SUCCEEDED(hr)) + { + bool fRandomWriteData; + hr = _GetBool(pXmlNode, "RandomWriteData", &fRandomWriteData); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + pTimeSpan->SetRandomWriteData(fRandomWriteData); + } + } + + if (SUCCEEDED(hr)) + { + UINT32 ulThreadCount; + hr = _GetUINT32(pXmlNode, "ThreadCount", &ulThreadCount); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + pTimeSpan->SetThreadCount(ulThreadCount); + } + } + + if (SUCCEEDED(hr)) + { + UINT32 ulRequestCount; + hr = _GetUINT32(pXmlNode, "RequestCount", &ulRequestCount); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + pTimeSpan->SetRequestCount(ulRequestCount); + } + } + + if (SUCCEEDED(hr)) + { + bool fDisableAffinity; + hr = _GetBool(pXmlNode, "DisableAffinity", &fDisableAffinity); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + pTimeSpan->SetDisableAffinity(fDisableAffinity); + } + } + + if (SUCCEEDED(hr)) + { + bool fCompletionRoutines; + hr = _GetBool(pXmlNode, "CompletionRoutines", &fCompletionRoutines); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + pTimeSpan->SetCompletionRoutines(fCompletionRoutines); + } + } + + if (SUCCEEDED(hr)) + { + bool fMeasureLatency; + hr = _GetBool(pXmlNode, "MeasureLatency", &fMeasureLatency); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + pTimeSpan->SetMeasureLatency(fMeasureLatency); + } + } + + if (SUCCEEDED(hr)) + { + bool fCalculateIopsStdDev; + hr = _GetBool(pXmlNode, "CalculateIopsStdDev", &fCalculateIopsStdDev); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + pTimeSpan->SetCalculateIopsStdDev(fCalculateIopsStdDev); + } + } + + if (SUCCEEDED(hr)) + { + UINT32 ulIoBucketDuration; + hr = _GetUINT32(pXmlNode, "IoBucketDuration", &ulIoBucketDuration); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + pTimeSpan->SetIoBucketDurationInMilliseconds(ulIoBucketDuration); + } + } + + // Look for downlevel non-group aware assignment + if (SUCCEEDED(hr)) + { + hr = _ParseAffinityAssignment(pXmlNode, pTimeSpan); + } + + // Look for uplevel group aware assignment. + if (SUCCEEDED(hr)) + { + hr = _ParseAffinityGroupAssignment(pXmlNode, pTimeSpan); + } + + if (SUCCEEDED(hr)) + { + hr = _ParseTargets(pXmlNode, pTimeSpan, vSubsts); + } + + return hr; +} + +HRESULT XmlProfileParser::_SubstTarget(Target *pTarget, vector>& vSubsts) +{ + auto& sPath = pTarget->GetPath(); + + if (sPath.length() >= 1 && sPath[0] == TEMPLATE_TARGET_PREFIX) + { + auto str = sPath.c_str(); + char *strend; + ULONG i; + + // + // Note that we will parse all template targets for correctness but allow empty substuttion lists + // to pass through. If this profile will be executed, validation of paths will catch unsubst template targets + // + // strtoul will accept signed integers (e.g., -1), so we need to add our explicit assertion that this is indeed a digit. + // + + i = strtoul(str + 1, &strend, 10); + + if (i == 0 || *strend != '\0' || !isdigit(*(str + 1))) + { + fprintf(stderr, "ERROR: template path '%s' is not a valid path reference - must be %c - check profile\n", str, TEMPLATE_TARGET_PREFIX); + return E_INVALIDARG; + } + + if (vSubsts.size() != 0) + { + if (i > vSubsts.size()) + { + fprintf(stderr, "ERROR: template path '%s' does not have a specified substitution - check profile\n", str); + return E_INVALIDARG; + } + + // + // Substitute this target, indicating this substitution was used (for validation). + // Note 1 based count and 0 based index. + // + + pTarget->SetPath(vSubsts[i - 1].first); + vSubsts[i - 1].second = true; + } + } + + return S_OK; +} + +HRESULT XmlProfileParser::_ParseTargets(IXMLDOMNode *pXmlNode, TimeSpan *pTimeSpan, vector>& vSubsts) +{ + CComVariant query("Targets/Target"); + CComPtr spNodeList = nullptr; + HRESULT hr = pXmlNode->selectNodes(query.bstrVal, &spNodeList); + if (SUCCEEDED(hr)) + { + long cNodes; + hr = spNodeList->get_length(&cNodes); + if (SUCCEEDED(hr)) + { + for (int i = 0; i < cNodes; i++) + { + CComPtr spNode = nullptr; + hr = spNodeList->get_item(i, &spNode); + if (SUCCEEDED(hr)) + { + Target target; + hr = _ParseTarget(spNode, &target); + if (SUCCEEDED(hr)) + { + hr = _SubstTarget(&target, vSubsts); + } + if (SUCCEEDED(hr)) + { + pTimeSpan->AddTarget(target); + } + } + + if (!SUCCEEDED(hr)) + { + break; + } + } + } + } + return hr; +} + +HRESULT XmlProfileParser::_ParseRandomDataSource(IXMLDOMNode *pXmlNode, Target *pTarget) +{ + CComPtr spNodeList = nullptr; + CComVariant query("RandomDataSource"); + HRESULT hr = pXmlNode->selectNodes(query.bstrVal, &spNodeList); + if (SUCCEEDED(hr)) + { + long cNodes; + hr = spNodeList->get_length(&cNodes); + if (SUCCEEDED(hr) && (cNodes == 1)) + { + CComPtr spNode = nullptr; + hr = spNodeList->get_item(0, &spNode); + if (SUCCEEDED(hr)) + { + UINT64 cb; + hr = _GetUINT64(spNode, "SizeInBytes", &cb); + if (SUCCEEDED(hr) && (S_FALSE != hr)) + { + pTarget->SetRandomDataWriteBufferSize(cb); + + string sPath; + hr = _GetString(spNode, "FilePath", &sPath); + if (SUCCEEDED(hr) && (S_FALSE != hr)) + { + pTarget->SetRandomDataWriteBufferSourcePath(sPath); + } + } + } + } + } + return hr; +} + +HRESULT XmlProfileParser::_ParseWriteBufferContent(IXMLDOMNode *pXmlNode, Target *pTarget) +{ + CComPtr spNodeList = nullptr; + CComVariant query("WriteBufferContent"); + HRESULT hr = pXmlNode->selectNodes(query.bstrVal, &spNodeList); + if (SUCCEEDED(hr)) + { + long cNodes; + hr = spNodeList->get_length(&cNodes); + if (SUCCEEDED(hr) && (cNodes == 1)) + { + CComPtr spNode = nullptr; + hr = spNodeList->get_item(0, &spNode); + if (SUCCEEDED(hr)) + { + string sPattern; + hr = _GetString(spNode, "Pattern", &sPattern); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + if (sPattern == "sequential") + { + // that's the default option - do nothing + } + else if (sPattern == "zero") + { + pTarget->SetZeroWriteBuffers(true); + } + else if (sPattern == "random") + { + hr = _ParseRandomDataSource(spNode, pTarget); + } + else + { + hr = E_INVALIDARG; + } + } + } + } + } + return hr; +} + +HRESULT XmlProfileParser::_ParseTarget(IXMLDOMNode *pXmlNode, Target *pTarget) +{ + // For enforcement of sequential/random conflicts. + // This is simplified for the XML since we control parse order. + bool fSequential = false; + + string sPath; + HRESULT hr = _GetString(pXmlNode, "Path", &sPath); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + pTarget->SetPath(sPath); + } + + if (SUCCEEDED(hr)) + { + DWORD dwBlockSize; + hr = _GetDWORD(pXmlNode, "BlockSize", &dwBlockSize); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + pTarget->SetBlockSizeInBytes(dwBlockSize); + } + } + + if (SUCCEEDED(hr)) + { + bool fInterlockedSequential; + hr = _GetBool(pXmlNode, "InterlockedSequential", &fInterlockedSequential); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + pTarget->SetUseInterlockedSequential(fInterlockedSequential); + } + } + + if (SUCCEEDED(hr)) + { + UINT64 ullBaseFileOffset; + hr = _GetUINT64(pXmlNode, "BaseFileOffset", &ullBaseFileOffset); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + pTarget->SetBaseFileOffsetInBytes(ullBaseFileOffset); + } + } + + if (SUCCEEDED(hr)) + { + bool fBool; + hr = _GetBool(pXmlNode, "SequentialScan", &fBool); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + pTarget->SetSequentialScanHint(fBool); + } + } + + if (SUCCEEDED(hr)) + { + bool fBool; + hr = _GetBool(pXmlNode, "RandomAccess", &fBool); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + pTarget->SetRandomAccessHint(fBool); + } + } + + if (SUCCEEDED(hr)) + { + bool fBool; + hr = _GetBool(pXmlNode, "TemporaryFile", &fBool); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + pTarget->SetTemporaryFileHint(fBool); + } + } + + if (SUCCEEDED(hr)) + { + bool fUseLargePages; + hr = _GetBool(pXmlNode, "UseLargePages", &fUseLargePages); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + pTarget->SetUseLargePages(fUseLargePages); + } + } + + if (SUCCEEDED(hr)) + { + DWORD dwRequestCount; + hr = _GetDWORD(pXmlNode, "RequestCount", &dwRequestCount); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + pTarget->SetRequestCount(dwRequestCount); + } + } + + if (SUCCEEDED(hr)) + { + UINT64 ullStrideSize; + hr = _GetUINT64(pXmlNode, "StrideSize", &ullStrideSize); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + pTarget->SetBlockAlignmentInBytes(ullStrideSize); + fSequential = true; + } + } + + if (SUCCEEDED(hr)) + { + UINT64 ullRandom; + hr = _GetUINT64(pXmlNode, "Random", &ullRandom); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + // conflict with sequential + if (fSequential) + { + fprintf(stderr, "sequential conflicts with \n"); + hr = HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER); + } + else + { + pTarget->SetRandomRatio(100); + pTarget->SetBlockAlignmentInBytes(ullRandom); + } + } + } + + // now override default of 100% random? + if (SUCCEEDED(hr)) + { + UINT32 ulRandomRatio; + hr = _GetUINT32(pXmlNode, "RandomRatio", &ulRandomRatio); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + // conflict with sequential + if (fSequential) + { + fprintf(stderr, "sequential conflicts with \n"); + hr = HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER); + } + else + { + pTarget->SetRandomRatio(ulRandomRatio); + } + } + } + + if (SUCCEEDED(hr)) + { + bool fBool; + hr = _GetBool(pXmlNode, "DisableOSCache", &fBool); + if (SUCCEEDED(hr) && (hr != S_FALSE) && fBool) + { + pTarget->SetCacheMode(TargetCacheMode::DisableOSCache); + } + } + + if (SUCCEEDED(hr)) + { + bool fBool; + hr = _GetBool(pXmlNode, "MemoryMappedIo", &fBool); + if (SUCCEEDED(hr) && (hr != S_FALSE) && fBool) + { + pTarget->SetMemoryMappedIoMode(MemoryMappedIoMode::On); + } + } + + if (SUCCEEDED(hr)) + { + bool fBool; + hr = _GetBool(pXmlNode, "DisableAllCache", &fBool); + if (SUCCEEDED(hr) && (hr != S_FALSE) && fBool) + { + pTarget->SetCacheMode(TargetCacheMode::DisableOSCache); + pTarget->SetWriteThroughMode(WriteThroughMode::On); + } + } + + if (SUCCEEDED(hr)) + { + bool fBool; + hr = _GetBool(pXmlNode, "DisableLocalCache", &fBool); + if (SUCCEEDED(hr) && (hr != S_FALSE) && fBool) + { + pTarget->SetCacheMode(TargetCacheMode::DisableLocalCache); + } + } + + if (SUCCEEDED(hr)) + { + bool fBool; + hr = _GetBool(pXmlNode, "WriteThrough", &fBool); + if (SUCCEEDED(hr) && (hr != S_FALSE) && fBool) + { + pTarget->SetWriteThroughMode(WriteThroughMode::On); + } + } + + if (SUCCEEDED(hr)) + { + string sFlushType; + hr = _GetString(pXmlNode, "FlushType", &sFlushType); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + if (sFlushType == "ViewOfFile") + { + pTarget->SetMemoryMappedIoFlushMode(MemoryMappedIoFlushMode::ViewOfFile); + } + else if (sFlushType == "NonVolatileMemory") + { + pTarget->SetMemoryMappedIoFlushMode(MemoryMappedIoFlushMode::NonVolatileMemory); + } + else if (sFlushType == "NonVolatileMemoryNoDrain") + { + pTarget->SetMemoryMappedIoFlushMode(MemoryMappedIoFlushMode::NonVolatileMemoryNoDrain); + } + else + { + hr = E_INVALIDARG; + } + } + } + + if (SUCCEEDED(hr)) + { + hr = _ParseWriteBufferContent(pXmlNode, pTarget); + } + + if (SUCCEEDED(hr)) + { + DWORD dwBurstSize; + hr = _GetDWORD(pXmlNode, "BurstSize", &dwBurstSize); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + pTarget->SetBurstSize(dwBurstSize); + pTarget->SetUseBurstSize(true); + } + } + + if (SUCCEEDED(hr)) + { + DWORD dwThinkTime; + hr = _GetDWORD(pXmlNode, "ThinkTime", &dwThinkTime); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + pTarget->SetThinkTime(dwThinkTime); + pTarget->SetEnableThinkTime(true); + } + } + + if (SUCCEEDED(hr)) + { + hr = _ParseThroughput(pXmlNode, pTarget); + } + + if (SUCCEEDED(hr)) + { + DWORD dwThreadsPerFile; + hr = _GetDWORD(pXmlNode, "ThreadsPerFile", &dwThreadsPerFile); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + pTarget->SetThreadsPerFile(dwThreadsPerFile); + } + } + + if (SUCCEEDED(hr)) + { + UINT64 ullFileSize; + hr = _GetUINT64(pXmlNode, "FileSize", &ullFileSize); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + pTarget->SetFileSize(ullFileSize); + pTarget->SetCreateFile(true); + } + } + + if (SUCCEEDED(hr)) + { + UINT64 ullMaxFileSize; + hr = _GetUINT64(pXmlNode, "MaxFileSize", &ullMaxFileSize); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + pTarget->SetMaxFileSize(ullMaxFileSize); + } + } + + if (SUCCEEDED(hr)) + { + UINT32 ulWriteRatio; + hr = _GetUINT32(pXmlNode, "WriteRatio", &ulWriteRatio); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + pTarget->SetWriteRatio(ulWriteRatio); + } + } + + if (SUCCEEDED(hr)) + { + bool fParallelAsyncIO; + hr = _GetBool(pXmlNode, "ParallelAsyncIO", &fParallelAsyncIO); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + pTarget->SetUseParallelAsyncIO(fParallelAsyncIO); + } + } + + if (SUCCEEDED(hr)) + { + UINT64 ullThreadStride; + hr = _GetUINT64(pXmlNode, "ThreadStride", &ullThreadStride); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + pTarget->SetThreadStrideInBytes(ullThreadStride); + } + } + + if (SUCCEEDED(hr)) + { + UINT32 ulIOPriority; + hr = _GetUINT32(pXmlNode, "IOPriority", &ulIOPriority); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + PRIORITY_HINT hint[] = { IoPriorityHintVeryLow, IoPriorityHintLow, IoPriorityHintNormal }; + pTarget->SetIOPriorityHint(hint[ulIOPriority - 1]); + } + } + + if (SUCCEEDED(hr)) + { + UINT32 ulWeight; + hr = _GetUINT32(pXmlNode, "Weight", &ulWeight); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + pTarget->SetWeight(ulWeight); + } + } + + // + // Note: XSD validation ensures only one type of distribution is specified, but it as simple + // here to probe for each. + // + + if (SUCCEEDED(hr)) + { + hr = _ParseDistribution(pXmlNode, pTarget); + } + + if (SUCCEEDED(hr)) + { + hr = _ParseThreadTargets(pXmlNode, pTarget); + } + return hr; +} + +HRESULT XmlProfileParser::_ParseThroughput(IXMLDOMNode *pXmlNode, Target *pTarget) +{ + CComPtr spNode = nullptr; + CComVariant query("Throughput"); + HRESULT hr = pXmlNode->selectSingleNode(query.bstrVal, &spNode); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + // get value + UINT32 value = 0; + + BSTR bstrText; + hr = spNode->get_text(&bstrText); + if (SUCCEEDED(hr)) + { + value = (UINT32) _wtoi64((wchar_t *)bstrText); // XSD constrains s.t. cast is safe + SysFreeString(bstrText); + } + else + { + return hr; + } + + // get unit - bpms default + bool isBpms = true; + + CComPtr spNamedNodeMap = nullptr; + CComBSTR attr("unit"); + hr = spNode->get_attributes(&spNamedNodeMap); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + CComPtr spAttrNode = nullptr; + HRESULT hr = spNamedNodeMap->getNamedItem(attr, &spAttrNode); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + BSTR bstrText; + hr = spAttrNode->get_text(&bstrText); + if (SUCCEEDED(hr)) + { + isBpms = wcscmp((wchar_t *)bstrText, L"IOPS"); + SysFreeString(bstrText); + } + } + } + + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + if (isBpms) + { + pTarget->SetThroughput(value); + } + else + { + // NOTE: this depends on parse order s.t. blocksize is available + pTarget->SetThroughputIOPS(value); + } + } + } + return hr; +} + +HRESULT XmlProfileParser::_ParseThreadTargets(IXMLDOMNode *pXmlNode, Target *pTarget) +{ + CComVariant query("ThreadTargets/ThreadTarget"); + CComPtr spNodeList = nullptr; + HRESULT hr = pXmlNode->selectNodes(query.bstrVal, &spNodeList); + if (SUCCEEDED(hr)) + { + long cNodes; + hr = spNodeList->get_length(&cNodes); + if (SUCCEEDED(hr)) + { + for (int i = 0; i < cNodes; i++) + { + CComPtr spNode = nullptr; + hr = spNodeList->get_item(i, &spNode); + if (SUCCEEDED(hr)) + { + ThreadTarget threadTarget; + _ParseThreadTarget(spNode, &threadTarget); + pTarget->AddThreadTarget(threadTarget); + } + } + } + } + return hr; +} + +HRESULT XmlProfileParser::_ParseThreadTarget(IXMLDOMNode *pXmlNode, ThreadTarget *pThreadTarget) +{ + UINT32 ulThread; + HRESULT hr = _GetUINT32(pXmlNode, "Thread", &ulThread); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + pThreadTarget->SetThread(ulThread); + } + + if (SUCCEEDED(hr)) + { + UINT32 ulWeight; + hr = _GetUINT32(pXmlNode, "Weight", &ulWeight); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + pThreadTarget->SetWeight(ulWeight); + } + } + return hr; +} + +struct { + char* xPath; + DistributionType t; +} distributionTypes[] = { + { "Distribution/Absolute/Range", DistributionType::Absolute }, + { "Distribution/Percent/Range", DistributionType::Percent } +}; + +HRESULT XmlProfileParser::_ParseDistribution(IXMLDOMNode *pXmlNode, Target *pTarget) +{ + HRESULT hr = S_OK; + + for (auto& type : distributionTypes) + { + CComPtr spNodeList = nullptr; + CComVariant query(type.xPath); + hr = pXmlNode->selectNodes(query.bstrVal, &spNodeList); + if (SUCCEEDED(hr)) + { + long cNodes; + hr = spNodeList->get_length(&cNodes); + if (SUCCEEDED(hr) && cNodes != 0) + { + UINT64 targetBase = 0, targetSpan; + UINT32 ioBase = 0, ioSpan; + vector v; + + for (int i = 0; i < cNodes; i++) + { + // target span from the element + // note that this is the same 64bit int for both distribution types, + // it is the interpretation at the time the effective is calculated + // that makes the distinction. XSD covers range validations. + CComPtr spNode = nullptr; + hr = spNodeList->get_item(i, &spNode); + if (SUCCEEDED(hr)) + { + BSTR bstrText; + hr = spNode->get_text(&bstrText); + if (SUCCEEDED(hr)) + { + targetSpan = _wtoi64((wchar_t *)bstrText); + SysFreeString(bstrText); + } + } + + if (SUCCEEDED(hr)) + { + // io span from the attribute + CComPtr spNamedNodeMap = nullptr; + CComBSTR attr("IO"); + hr = spNode->get_attributes(&spNamedNodeMap); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + CComPtr spAttrNode = nullptr; + HRESULT hr = spNamedNodeMap->getNamedItem(attr, &spAttrNode); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + BSTR bstrText; + hr = spAttrNode->get_text(&bstrText); + if (SUCCEEDED(hr)) + { + ioSpan = _wtoi((wchar_t *)bstrText); + SysFreeString(bstrText); + } + } + } + } + + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + v.emplace_back(ioBase, ioSpan, + make_pair(targetBase, targetSpan)); + ioBase += ioSpan; + targetBase += targetSpan; + } + // failed during parse + else + { + break; + } + + // + // Note that we are aware here whether we got to 100% IO specification. + // This validation is delayed to the common path for XML/cmdline. + // + } + + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + pTarget->SetDistributionRange(v, type.t); + } + + // if we parsed into the element, we are done (success or failure) - only one type is possible. + return hr; + } + } + } + + return hr; +} + +// Compatibility with the old, non-group aware affinity assignment. Preserved to allow downlevel XML profiles +// to run without modification. +// Any assignment done through this method will only assign within group 0, and is equivalent to the non-group +// specification -a#,#,# (contrast to -ag#,#,#,...). While not strictly equivalent to the old non-group aware +// behavior, this should be acceptably good-enough. +// +// The XML result parser no longer emits this form. + +HRESULT XmlProfileParser::_ParseAffinityAssignment(IXMLDOMNode *pXmlNode, TimeSpan *pTimeSpan) +{ + CComPtr spNodeList = nullptr; + CComVariant query("Affinity/AffinityAssignment"); + HRESULT hr = pXmlNode->selectNodes(query.bstrVal, &spNodeList); + if (SUCCEEDED(hr)) + { + long cNodes; + hr = spNodeList->get_length(&cNodes); + if (SUCCEEDED(hr)) + { + for (int i = 0; i < cNodes; i++) + { + CComPtr spNode = nullptr; + hr = spNodeList->get_item(i, &spNode); + if (SUCCEEDED(hr)) + { + BSTR bstrText; + hr = spNode->get_text(&bstrText); + if (SUCCEEDED(hr)) + { + pTimeSpan->AddAffinityAssignment((WORD)0, (BYTE)_wtoi((wchar_t *)bstrText)); + SysFreeString(bstrText); + } + } + } + } + } + return hr; +} + +// Group aware affinity assignment. This is the only form emitted by the XML result parser. + +HRESULT XmlProfileParser::_ParseAffinityGroupAssignment(IXMLDOMNode *pXmlNode, TimeSpan *pTimeSpan) +{ + CComPtr spNodeList = nullptr; + CComVariant query("Affinity/AffinityGroupAssignment"); + + HRESULT hr = pXmlNode->selectNodes(query.bstrVal, &spNodeList); + if (SUCCEEDED(hr)) + { + long cNodes; + hr = spNodeList->get_length(&cNodes); + if (SUCCEEDED(hr)) + { + for (int i = 0; i < cNodes; i++) + { + CComPtr spNode = nullptr; + hr = spNodeList->get_item(i, &spNode); + if (SUCCEEDED(hr)) + { + UINT32 dwGroup = 0, dwProc = 0; + hr = _GetUINT32Attr(spNode, "Group", &dwGroup); + if (SUCCEEDED(hr)) + { + _GetUINT32Attr(spNode, "Processor", &dwProc); + } + if (SUCCEEDED(hr)) + { + if (dwProc > MAXBYTE) + { + fprintf(stderr, "ERROR: profile specifies group assignment to core %u, out of range\n", dwProc); + hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA); + } + if (dwGroup > MAXWORD) + { + fprintf(stderr, "ERROR: profile specifies group assignment group %u, out of range\n", dwGroup); + hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA); + } + + if (SUCCEEDED(hr)) { + pTimeSpan->AddAffinityAssignment((WORD)dwGroup, (BYTE)dwProc); + } + + } + } + } + } + } + return hr; +} + +HRESULT XmlProfileParser::_GetUINT32(IXMLDOMNode *pXmlNode, const char *pszQuery, UINT32 *pulValue) const +{ + CComPtr spNode = nullptr; + CComVariant query(pszQuery); + HRESULT hr = pXmlNode->selectSingleNode(query.bstrVal, &spNode); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + BSTR bstrText; + hr = spNode->get_text(&bstrText); + if (SUCCEEDED(hr)) + { + *pulValue = _wtoi((wchar_t *)bstrText); // TODO: make sure it works on large unsigned ints + SysFreeString(bstrText); + } + } + return hr; +} + +HRESULT XmlProfileParser::_GetUINT32Attr(IXMLDOMNode *pXmlNode, const char *pszAttr, UINT32 *pulValue) const +{ + CComPtr spNamedNodeMap = nullptr; + CComBSTR attr(pszAttr); + HRESULT hr = pXmlNode->get_attributes(&spNamedNodeMap); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + CComPtr spNode = nullptr; + HRESULT hr = spNamedNodeMap->getNamedItem(attr, &spNode); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + BSTR bstrText; + hr = spNode->get_text(&bstrText); + if (SUCCEEDED(hr)) + { + *pulValue = _wtoi((wchar_t *)bstrText); // TODO: make sure it works on large unsigned ints + SysFreeString(bstrText); + } + } + } + return hr; +} + +HRESULT XmlProfileParser::_GetString(IXMLDOMNode *pXmlNode, const char *pszQuery, string *psValue) const +{ + CComPtr spNode = nullptr; + CComVariant query(pszQuery); + HRESULT hr = pXmlNode->selectSingleNode(query.bstrVal, &spNode); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + BSTR bstrText; + hr = spNode->get_text(&bstrText); + if (SUCCEEDED(hr)) + { + // TODO: use wstring? + char path[MAX_PATH] = {}; + WideCharToMultiByte(CP_UTF8, 0 /*dwFlags*/, (wchar_t *)bstrText, static_cast(wcslen((wchar_t *)bstrText)), path, sizeof(path)-1, 0 /*lpDefaultChar*/, 0 /*lpUsedDefaultChar*/); + *psValue = string(path); + } + SysFreeString(bstrText); + } + return hr; +} + +HRESULT XmlProfileParser::_GetUINT64(IXMLDOMNode *pXmlNode, const char *pszQuery, UINT64 *pullValue) const +{ + CComPtr spNode = nullptr; + CComVariant query(pszQuery); + HRESULT hr = pXmlNode->selectSingleNode(query.bstrVal, &spNode); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + BSTR bstrText; + hr = spNode->get_text(&bstrText); + if (SUCCEEDED(hr)) + { + *pullValue = _wtoi64((wchar_t *)bstrText); + } + SysFreeString(bstrText); + } + return hr; +} + +HRESULT XmlProfileParser::_GetDWORD(IXMLDOMNode *pXmlNode, const char *pszQuery, DWORD *pdwValue) const +{ + UINT32 value = 0; + HRESULT hr = _GetUINT32(pXmlNode, pszQuery, &value); + if (SUCCEEDED(hr)) + { + *pdwValue = value; + } + return hr; +} + +HRESULT XmlProfileParser::_GetBool(IXMLDOMNode *pXmlNode, const char *pszQuery, bool *pfValue) const +{ + HRESULT hr = S_OK; + CComPtr spNode = nullptr; + CComVariant query(pszQuery); + hr = pXmlNode->selectSingleNode(query.bstrVal, &spNode); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + BSTR bstrText; + hr = spNode->get_text(&bstrText); + if (SUCCEEDED(hr)) + { + *pfValue = (_wcsicmp(L"true", (wchar_t *)bstrText) == 0); + SysFreeString(bstrText); + } + } + return hr; +} \ No newline at end of file diff --git a/CristalDiskMark/source/diskspd22/XmlProfileParser/diskspd.xsd b/CristalDiskMark/source/diskspd22/XmlProfileParser/diskspd.xsd new file mode 100644 index 0000000..f32eab3 --- /dev/null +++ b/CristalDiskMark/source/diskspd22/XmlProfileParser/diskspd.xsd @@ -0,0 +1,400 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/CristalDiskMark/source/diskspd22/XmlResultParser/XmlResultParser.cpp b/CristalDiskMark/source/diskspd22/XmlResultParser/XmlResultParser.cpp new file mode 100644 index 0000000..aeb0042 --- /dev/null +++ b/CristalDiskMark/source/diskspd22/XmlResultParser/XmlResultParser.cpp @@ -0,0 +1,620 @@ +/* + +DISKSPD + +Copyright(c) Microsoft Corporation +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#include "xmlresultparser.h" + +// TODO: refactor to a single function shared with the ResultParser +char printBuffer[4096] = {}; + +/// for CrystalDiskMark +int XmlResultParser::GetTotalScore() +{ + return 0; +} + +double XmlResultParser::GetAverageLatency() +{ + return 0.0; +} + +void XmlResultParser::_PrintV(const char *format, va_list listArg) +{ + _sResult.append(_indent, ' '); + vsprintf_s(printBuffer, _countof(printBuffer), format, listArg); + _sResult += printBuffer; +} + +void XmlResultParser::_Print(const char *format, ...) +{ + assert(nullptr != format); + va_list listArg; + va_start(listArg, format); + + _PrintV(format, listArg); + va_end(listArg); +} + +void XmlResultParser::_PrintInc(const char *format, ...) +{ + assert(nullptr != format); + va_list listArg; + va_start(listArg, format); + + // Print & Increment Indent + // e.g., + + _PrintV(format, listArg); + _indent += 2; + va_end(listArg); +} + +void XmlResultParser::_PrintDec(const char *format, ...) +{ + assert(nullptr != format); + va_list listArg; + va_start(listArg, format); + + // Decrement Indent & Print + // e.g., + + _indent -= 2; + _PrintV(format, listArg); + va_end(listArg); +} + +void XmlResultParser::_PrintTargetResults(const TargetResults& results) +{ + // TODO: results.readBucketizer; + // TODO: results.writeBucketizer; + + _Print("%s\n", results.sPath.c_str()); + _Print("%I64u\n", results.ullBytesCount); + _Print("%I64u\n", results.ullFileSize); + _Print("%I64u\n", results.ullIOCount); + _Print("%I64u\n", results.ullReadBytesCount); + _Print("%I64u\n", results.ullReadIOCount); + _Print("%I64u\n", results.ullWriteBytesCount); + _Print("%I64u\n", results.ullWriteIOCount); + + if (results.vDistributionRange.size()) + { + _PrintInc("\n"); + _PrintInc("\n"); + + // + // Render hole(s) in effective distribution. Keep track of the expected base + // of the next range and render a hole (IO = 0) over the gap as needed. + // + + UINT64 expectBase = 0; + for (auto& r : results.vDistributionRange) + { + if (r._dst.first != expectBase) + { + _Print("%I64u\n", 0, r._dst.first - expectBase); + } + + _Print("%I64u\n", r._span, r._dst.second); + expectBase = r._dst.first + r._dst.second; + } + + _PrintDec("\n"); + _PrintDec("\n"); + } +} + +void XmlResultParser::_PrintTargetLatency(const TargetResults& results) +{ + if (results.readLatencyHistogram.GetSampleSize() > 0) + { + _Print("%.3f\n", results.readLatencyHistogram.GetAvg() / 1000); + _Print("%.3f\n", results.readLatencyHistogram.GetStandardDeviation() / 1000); + } + if (results.writeLatencyHistogram.GetSampleSize() > 0) + { + _Print("%.3f\n", results.writeLatencyHistogram.GetAvg() / 1000); + _Print("%.3f\n", results.writeLatencyHistogram.GetStandardDeviation() / 1000); + } + Histogram totalLatencyHistogram; + totalLatencyHistogram.Merge(results.readLatencyHistogram); + totalLatencyHistogram.Merge(results.writeLatencyHistogram); + if (totalLatencyHistogram.GetSampleSize() > 0) + { + _Print("%.3f\n", totalLatencyHistogram.GetAvg() / 1000); + _Print("%.3f\n", totalLatencyHistogram.GetStandardDeviation() / 1000); + } +} + +void XmlResultParser::_PrintTargetIops(const IoBucketizer& readBucketizer, const IoBucketizer& writeBucketizer, UINT32 bucketTimeInMs) +{ + _PrintInc("\n"); + + IoBucketizer totalIoBucketizer; + totalIoBucketizer.Merge(readBucketizer); + totalIoBucketizer.Merge(writeBucketizer); + + if (readBucketizer.GetNumberOfValidBuckets() > 0) + { + _Print("%.3f\n", readBucketizer.GetStandardDeviationIOPS() / (bucketTimeInMs / 1000.0)); + } + if (writeBucketizer.GetNumberOfValidBuckets() > 0) + { + _Print("%.3f\n", writeBucketizer.GetStandardDeviationIOPS() / (bucketTimeInMs / 1000.0)); + } + if (totalIoBucketizer.GetNumberOfValidBuckets() > 0) + { + _Print("%.3f\n", totalIoBucketizer.GetStandardDeviationIOPS() / (bucketTimeInMs / 1000.0)); + } + _PrintIops(readBucketizer, writeBucketizer, bucketTimeInMs); + _PrintDec("\n"); +} + +void XmlResultParser::_PrintETWSessionInfo(struct ETWSessionInfo sessionInfo) +{ + _PrintInc("\n"); + _Print("%lu\n", sessionInfo.ulBufferSize); + _Print("%lu\n", sessionInfo.ulMinimumBuffers); + _Print("%lu\n", sessionInfo.ulMaximumBuffers); + _Print("%lu", sessionInfo.ulFreeBuffers); + _Print("%lu\n", sessionInfo.ulBuffersWritten); + _Print("%lu\n", sessionInfo.ulFlushTimer); + _Print("%d\n", sessionInfo.lAgeLimit); + + _Print("%lu\n", sessionInfo.ulNumberOfBuffers); + _Print("%lu\n", sessionInfo.ulEventsLost); + _Print("%lu\n", sessionInfo.ulLogBuffersLost); + _Print("%lu\n", sessionInfo.ulRealTimeBuffersLost); + _PrintDec("\n"); +} + +void XmlResultParser::_PrintETW(struct ETWMask ETWMask, struct ETWEventCounters EtwEventCounters) +{ + _PrintInc("\n"); + if (ETWMask.bDiskIO) + { + _PrintInc("\n"); + _Print("%I64u\n", EtwEventCounters.ullIORead); + _Print("%I64u\n", EtwEventCounters.ullIOWrite); + _PrintDec("\n"); + } + if (ETWMask.bImageLoad) + { + _Print("%I64u\n", EtwEventCounters.ullImageLoad); + } + if (ETWMask.bMemoryPageFaults) + { + _PrintInc("\n"); + _Print("%I64u\n", EtwEventCounters.ullMMCopyOnWrite); + _Print("%I64u\n", EtwEventCounters.ullMMDemandZeroFault); + _Print("%I64u\n", EtwEventCounters.ullMMGuardPageFault); + _Print("%I64u\n", EtwEventCounters.ullMMHardPageFault); + _Print("%I64u\n", EtwEventCounters.ullMMTransitionFault); + _PrintDec("\n"); + } + if (ETWMask.bMemoryHardFaults && !ETWMask.bMemoryPageFaults) + { + _Print("%I64u\n", EtwEventCounters.ullMMHardPageFault); + } + if (ETWMask.bNetwork) + { + _PrintInc("\n"); + _Print("%I64u\n", EtwEventCounters.ullNetAccept); + _Print("%I64u\n", EtwEventCounters.ullNetConnect); + _Print("%I64u\n", EtwEventCounters.ullNetDisconnect); + _Print("%I64u\n", EtwEventCounters.ullNetReconnect); + _Print("%I64u\n", EtwEventCounters.ullNetRetransmit); + _Print("%I64u\n", EtwEventCounters.ullNetTcpSend); + _Print("%I64u\n", EtwEventCounters.ullNetTcpReceive); + _Print("%I64u\n", EtwEventCounters.ullNetUdpSend); + _Print("%I64u\n", EtwEventCounters.ullNetUdpReceive); + _PrintDec("\n"); + } + if (ETWMask.bProcess) + { + _PrintInc("\n"); + _Print("%I64u\n", EtwEventCounters.ullProcessStart); + _Print("%I64u\n", EtwEventCounters.ullProcessEnd); + _PrintDec("\n"); + } + if (ETWMask.bRegistry) + { + _PrintInc("\n"); + _Print("%I64u\n", EtwEventCounters.ullRegCreate); + _Print("%I64u\n", EtwEventCounters.ullRegDelete); + _Print("%I64u\n", EtwEventCounters.ullRegDeleteValue); + _Print("%I64u\n", EtwEventCounters.ullRegEnumerateKey); + _Print("%I64u\n", EtwEventCounters.ullRegEnumerateValueKey); + _Print("%I64u\n", EtwEventCounters.ullRegFlush); + _Print("%I64u\n", EtwEventCounters.ullRegOpen); + _Print("%I64u\n", EtwEventCounters.ullRegQuery); + _Print("%I64u\n", EtwEventCounters.ullRegQueryMultipleValue); + _Print("%I64u\n", EtwEventCounters.ullRegQueryValue); + _Print("%I64u\n", EtwEventCounters.ullRegSetInformation); + _Print("%I64u\n", EtwEventCounters.ullRegSetValue); + _PrintDec("\n"); + } + if (ETWMask.bThread) + { + _PrintInc("\n"); + _Print("%I64u\n", EtwEventCounters.ullThreadStart); + _Print("%I64u\n", EtwEventCounters.ullThreadEnd); + _PrintDec("\n"); + } + _PrintDec("\n"); +} + +void XmlResultParser::_PrintCpuUtilization(const Results& results, const SystemInformation& system) +{ + const auto& topo = system.processorTopology; + size_t procCount = results.vSystemProcessorPerfInfo.size(); + size_t baseProc = 0; + BYTE efficiencyClass = 0; + BYTE processorCore = 0; + + _PrintInc("\n"); + + double busyTime = 0; + double totalIdleTime = 0; + double totalUserTime = 0; + double totalKrnlTime = 0; + + for (const auto& group : topo._vProcessorGroupInformation) { + + // Sanity assert - results are sized to the sum of active processors + assert(baseProc + group._activeProcessorCount <= procCount); + + for (BYTE processor = 0; processor < group._activeProcessorCount; processor++) { + + long long fTime = results.vSystemProcessorPerfInfo[baseProc + processor].KernelTime.QuadPart + + results.vSystemProcessorPerfInfo[baseProc + processor].UserTime.QuadPart; + + double idleTime = 100.0 * results.vSystemProcessorPerfInfo[baseProc + processor].IdleTime.QuadPart / fTime; + double krnlTime = 100.0 * results.vSystemProcessorPerfInfo[baseProc + processor].KernelTime.QuadPart / fTime; + double userTime = 100.0 * results.vSystemProcessorPerfInfo[baseProc + processor].UserTime.QuadPart / fTime; + double usedTime = (krnlTime - idleTime) + userTime; + + _PrintInc("\n"); + _Print("%d\n", topo.GetSocketOfProcessor(group._groupNumber, processor)); + _Print("%d\n", topo.GetNumaOfProcessor(group._groupNumber, processor)); + _Print("%d\n", group._groupNumber); + processorCore = topo.GetCoreOfProcessor(group._groupNumber, processor, efficiencyClass); + _Print("%d\n", processorCore); + _Print("%d\n", efficiencyClass); + _Print("%d\n", processor); + _Print("%.2f\n", usedTime); + _Print("%.2f\n", userTime); + _Print("%.2f\n", krnlTime - idleTime); + _Print("%.2f\n", idleTime); + _PrintDec("\n"); + + busyTime += usedTime; + totalIdleTime += idleTime; + totalUserTime += userTime; + totalKrnlTime += krnlTime; + } + + baseProc += group._activeProcessorCount; + } + + assert(baseProc == procCount); + + _PrintInc("\n"); + _Print("%.2f\n", busyTime / procCount); + _Print("%.2f\n", totalUserTime / procCount); + _Print("%.2f\n", (totalKrnlTime - totalIdleTime) / procCount); + _Print("%.2f\n", totalIdleTime / procCount); + _PrintDec("\n"); + + _PrintDec("\n"); +} + +// emit the iops time series (this obviates needing perfmon counters, in common cases, and provides file level data) +void XmlResultParser::_PrintIops(const IoBucketizer& readBucketizer, const IoBucketizer& writeBucketizer, UINT32 bucketTimeInMs) +{ + bool done = false; + for (size_t i = 0; !done; i++) + { + done = true; + + double r = 0.0; + double r_min = 0.0; + double r_max = 0.0; + double r_avg = 0.0; + double r_stddev = 0.0; + + double w = 0.0; + double w_min = 0.0; + double w_max = 0.0; + double w_avg = 0.0; + double w_stddev = 0.0; + + if (readBucketizer.GetNumberOfValidBuckets() > i) + { + r = readBucketizer.GetIoBucketCount(i) / (bucketTimeInMs / 1000.0); + r_min = readBucketizer.GetIoBucketMinDurationUsec(i) / 1000.0; + r_max = readBucketizer.GetIoBucketMaxDurationUsec(i) / 1000.0; + r_avg = readBucketizer.GetIoBucketAvgDurationUsec(i) / 1000.0; + r_stddev = readBucketizer.GetIoBucketDurationStdDevUsec(i) / 1000.0; + done = false; + } + if (writeBucketizer.GetNumberOfValidBuckets() > i) + { + w = writeBucketizer.GetIoBucketCount(i) / (bucketTimeInMs / 1000.0); + w_min = writeBucketizer.GetIoBucketMinDurationUsec(i) / 1000.0; + w_max = writeBucketizer.GetIoBucketMaxDurationUsec(i) / 1000.0; + w_avg = writeBucketizer.GetIoBucketAvgDurationUsec(i) / 1000.0; + w_stddev = writeBucketizer.GetIoBucketDurationStdDevUsec(i) / 1000.0; + done = false; + } + if (!done) + { + _Print("\n", + bucketTimeInMs*(i + 1), r, w, r + w, + r_min, r_max, r_avg, r_stddev, + w_min, w_max, w_avg, w_stddev); + } + } +} + +void XmlResultParser::_PrintOverallIops(const Results& results, UINT32 bucketTimeInMs) +{ + IoBucketizer readBucketizer; + IoBucketizer writeBucketizer; + + for (const auto& thread : results.vThreadResults) + { + for (const auto& target : thread.vTargetResults) + { + readBucketizer.Merge(target.readBucketizer); + writeBucketizer.Merge(target.writeBucketizer); + } + } + + _PrintTargetIops(readBucketizer, writeBucketizer, bucketTimeInMs); +} + +void XmlResultParser::_PrintLatencyPercentiles(const Results& results) +{ + Histogram readLatencyHistogram; + Histogram writeLatencyHistogram; + Histogram totalLatencyHistogram; + + for (const auto& thread : results.vThreadResults) + { + for (const auto& target : thread.vTargetResults) + { + readLatencyHistogram.Merge(target.readLatencyHistogram); + + writeLatencyHistogram.Merge(target.writeLatencyHistogram); + + totalLatencyHistogram.Merge(target.writeLatencyHistogram); + totalLatencyHistogram.Merge(target.readLatencyHistogram); + } + } + + _PrintInc("\n", + readLatencyHistogram.GetSampleBuckets(), + writeLatencyHistogram.GetSampleBuckets(), + totalLatencyHistogram.GetSampleBuckets()); + + if (readLatencyHistogram.GetSampleSize() > 0) + { + _Print("%.3f\n", readLatencyHistogram.GetAvg() / 1000); + _Print("%.3f\n", readLatencyHistogram.GetStandardDeviation() / 1000); + } + if (writeLatencyHistogram.GetSampleSize() > 0) + { + _Print("%.3f\n", writeLatencyHistogram.GetAvg() / 1000); + _Print("%.3f\n", writeLatencyHistogram.GetStandardDeviation() / 1000); + } + if (totalLatencyHistogram.GetSampleSize() > 0) + { + _Print("%.3f\n", totalLatencyHistogram.GetAvg() / 1000); + _Print("%.3f\n", totalLatencyHistogram.GetStandardDeviation() / 1000); + } + + _PrintInc("\n"); + _Print("0\n"); + if (readLatencyHistogram.GetSampleSize() > 0) + { + _Print("%.3f\n", readLatencyHistogram.GetMin() / 1000); + } + if (writeLatencyHistogram.GetSampleSize() > 0) + { + _Print("%.3f\n", writeLatencyHistogram.GetMin() / 1000); + } + if (totalLatencyHistogram.GetSampleSize() > 0) + { + _Print("%.3f\n", totalLatencyHistogram.GetMin() / 1000); + } + _PrintDec("\n"); + + // Construct vector of percentiles and decimal precision to squelch trailing zeroes. This is more + // detailed than summary text output, and does not contain the decorated names (15th, etc.) + + vector> vPercentiles; + for (int p = 1; p <= 99; p++) + { + vPercentiles.push_back(make_pair(0, p)); + } + + vPercentiles.push_back(make_pair(1, 99.9)); + vPercentiles.push_back(make_pair(2, 99.99)); + vPercentiles.push_back(make_pair(3, 99.999)); + vPercentiles.push_back(make_pair(4, 99.9999)); + vPercentiles.push_back(make_pair(5, 99.99999)); + vPercentiles.push_back(make_pair(6, 99.999999)); + vPercentiles.push_back(make_pair(7, 99.9999999)); + + for (auto p : vPercentiles) + { + _PrintInc("\n"); + _Print("%.*f\n", p.first, p.second); + if (readLatencyHistogram.GetSampleSize() > 0) + { + _Print("%.3f\n", readLatencyHistogram.GetPercentile(p.second / 100) / 1000); + } + if (writeLatencyHistogram.GetSampleSize() > 0) + { + _Print("%.3f\n", writeLatencyHistogram.GetPercentile(p.second / 100) / 1000); + } + if (totalLatencyHistogram.GetSampleSize() > 0) + { + _Print("%.3f\n", totalLatencyHistogram.GetPercentile(p.second / 100) / 1000); + } + _PrintDec("\n"); + } + + _PrintInc("\n"); + _Print("100\n"); + if (readLatencyHistogram.GetSampleSize() > 0) + { + _Print("%.3f\n", readLatencyHistogram.GetMax() / 1000); + } + if (writeLatencyHistogram.GetSampleSize() > 0) + { + _Print("%.3f\n", writeLatencyHistogram.GetMax() / 1000); + } + if (totalLatencyHistogram.GetSampleSize() > 0) + { + _Print("%.3f\n", totalLatencyHistogram.GetMax() / 1000); + } + _PrintDec("\n"); + _PrintDec("\n"); +} + +string XmlResultParser::ParseProfile(const Profile& profile) +{ + _sResult = profile.GetXml(0); + return _sResult; +} + +void XmlResultParser::_PrintWaitStats(const ThreadResults &threadResult) +{ + _PrintInc("\n"); + _Print("%llu\n", threadResult.WaitStats.Wait); + _Print("%llu\n", threadResult.WaitStats.ThrottleWait); + _Print("%llu\n", threadResult.WaitStats.ThrottleSleep); + _Print("%llu\n", threadResult.WaitStats.Lookaside); + _Print("%llu %llu %llu %llu %llu %llu %llu %llu\n", + threadResult.WaitStats.LookasideCompletion[0], + threadResult.WaitStats.LookasideCompletion[1], + threadResult.WaitStats.LookasideCompletion[2], + threadResult.WaitStats.LookasideCompletion[3], + threadResult.WaitStats.LookasideCompletion[4], + threadResult.WaitStats.LookasideCompletion[5], + threadResult.WaitStats.LookasideCompletion[6], + threadResult.WaitStats.LookasideCompletion[7]); + _PrintDec("\n"); +} + +string XmlResultParser::ParseResults(const Profile& profile, const SystemInformation& system, vector vResults) +{ + _sResult.clear(); + + _PrintInc("\n"); + + _sResult += system.GetXml(_indent); + _sResult += profile.GetXml(_indent); + for (size_t iResults = 0; iResults < vResults.size(); iResults++) + { + const Results& results = vResults[iResults]; + const TimeSpan& timeSpan = profile.GetTimeSpans()[iResults]; + + _PrintInc("\n"); + + double fTime = PerfTimer::PerfTimeToSeconds(results.ullTimeCount); //test duration + if (fTime >= 0.0000001) + { + // There either is a fixed number of threads for all files to share (GetThreadCount() > 0) or a number of threads per file. + // In the latter case vThreadResults.size() == number of threads per file * file count + size_t ulThreadCnt = (timeSpan.GetThreadCount() > 0) ? timeSpan.GetThreadCount() : results.vThreadResults.size(); + + _Print("%.2f\n", fTime); + _Print("%u\n", ulThreadCnt); + _Print("%u\n", timeSpan.GetRequestCount()); + _Print("%u\n", system.processorTopology._ulProcessorCount); + + _PrintCpuUtilization(results, system); + + if (timeSpan.GetMeasureLatency()) + { + _PrintLatencyPercentiles(results); + } + + if (timeSpan.GetCalculateIopsStdDev()) + { + _PrintOverallIops(results, timeSpan.GetIoBucketDurationInMilliseconds()); + } + + if (results.fUseETW) + { + _PrintETW(results.EtwMask, results.EtwEventCounters); + _PrintETWSessionInfo(results.EtwSessionInfo); + } + + for (size_t iThread = 0; iThread < results.vThreadResults.size(); iThread++) + { + const ThreadResults& threadResults = results.vThreadResults[iThread]; + _PrintInc("\n"); + _Print("%u\n", iThread); + for (const auto& targetResults : threadResults.vTargetResults) + { + _PrintInc("\n"); + _PrintTargetResults(targetResults); + if (timeSpan.GetMeasureLatency()) + { + _PrintTargetLatency(targetResults); + } + if (timeSpan.GetCalculateIopsStdDev()) + { + _PrintTargetIops(targetResults.readBucketizer, targetResults.writeBucketizer, timeSpan.GetIoBucketDurationInMilliseconds()); + } + _PrintDec("\n"); + } + if (profile.GetVerboseStats()) + { + _PrintWaitStats(threadResults); + } + _PrintDec("\n"); + } + } + else + { + _Print("The test was interrupted before the measurements began. No results are displayed.\n"); + } + + _PrintDec("\n"); + } + + _PrintDec(""); + return _sResult; +} diff --git a/CristalDiskMark/source/diskspd22/diskspd.wprp b/CristalDiskMark/source/diskspd22/diskspd.wprp new file mode 100644 index 0000000..5f01e79 --- /dev/null +++ b/CristalDiskMark/source/diskspd22/diskspd.wprp @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/CristalDiskMark/source/diskspd22/diskspd_vs/CmdLineParser/CmdLineParser.vcxproj b/CristalDiskMark/source/diskspd22/diskspd_vs/CmdLineParser/CmdLineParser.vcxproj new file mode 100644 index 0000000..bfab1a4 --- /dev/null +++ b/CristalDiskMark/source/diskspd22/diskspd_vs/CmdLineParser/CmdLineParser.vcxproj @@ -0,0 +1,272 @@ + + + + + Debug + ARM + + + Debug + ARM64 + + + Debug + Win32 + + + Debug + x64 + + + Release + ARM + + + Release + ARM64 + + + Release + Win32 + + + Release + x64 + + + + {0EF5CE78-8E92-4A1B-A255-0F544AADA291} + CmdLineParser + 10.0 + + + + StaticLibrary + true + MultiByte + v143 + + + StaticLibrary + true + MultiByte + v143 + + + StaticLibrary + true + MultiByte + v143 + + + StaticLibrary + true + MultiByte + v143 + + + StaticLibrary + false + true + MultiByte + v143 + + + StaticLibrary + false + true + MultiByte + v143 + + + StaticLibrary + false + true + MultiByte + v143 + + + StaticLibrary + false + true + MultiByte + v143 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + $(SolutionDir)\..\Common;$(IncludePath) + + + $(SolutionDir)\..\Common;$(IncludePath) + + + $(SolutionDir)\..\Common;$(IncludePath) + + + $(SolutionDir)\..\Common;$(IncludePath) + + + $(SolutionDir)\..\Common;$(IncludePath) + + + $(SolutionDir)\..\Common;$(IncludePath) + + + $(SolutionDir)\..\Common;$(IncludePath) + + + $(SolutionDir)\..\Common;$(IncludePath) + + + + Level3 + Disabled + true + false + true + + + true + + + + + Level3 + Disabled + true + false + true + + + true + + + + + Level3 + Disabled + true + false + true + + + true + + + + + Level3 + Disabled + true + false + true + + + true + + + + + Level3 + MaxSpeed + true + true + true + true + _MBCS;NDEBUG;%(PreprocessorDefinitions) + MultiThreaded + + + true + true + true + + + + + Level3 + MaxSpeed + true + true + true + true + _MBCS;NDEBUG;%(PreprocessorDefinitions) + MultiThreaded + + + true + true + true + + + + + Level3 + MaxSpeed + true + true + true + true + _MBCS;NDEBUG;_ARM64_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1;%(ClCompile.PreprocessorDefinitions) + MultiThreaded + + + true + true + true + + + + + Level3 + MaxSpeed + true + true + true + true + _MBCS;NDEBUG;_ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1;%(ClCompile.PreprocessorDefinitions) + MultiThreaded + + + true + true + true + + + + + + + + + + + + \ No newline at end of file diff --git a/CristalDiskMark/source/diskspd22/diskspd_vs/CmdRequestCreator/CmdRequestCreator.vcxproj b/CristalDiskMark/source/diskspd22/diskspd_vs/CmdRequestCreator/CmdRequestCreator.vcxproj new file mode 100644 index 0000000..359f3a7 --- /dev/null +++ b/CristalDiskMark/source/diskspd22/diskspd_vs/CmdRequestCreator/CmdRequestCreator.vcxproj @@ -0,0 +1,300 @@ + + + + + Debug + ARM + + + Debug + ARM64 + + + Debug + Win32 + + + Debug + x64 + + + Release + ARM + + + Release + ARM64 + + + Release + Win32 + + + Release + x64 + + + + {D238F8AA-DE12-49E7-B4A7-9B69579A69C0} + CmdRequestCreator + 10.0 + + + + Application + true + MultiByte + v143 + + + Application + true + MultiByte + v143 + + + Application + true + MultiByte + v143 + + + Application + true + MultiByte + v143 + + + Application + false + true + MultiByte + v143 + + + Application + false + true + MultiByte + v143 + + + Application + false + true + MultiByte + v143 + + + Application + false + true + MultiByte + v143 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + $(SolutionDir)\..\Common;$(IncludePath) + diskspd + + + $(SolutionDir)\..\Common;$(IncludePath) + diskspd + false + + + $(SolutionDir)\..\Common;$(IncludePath) + diskspd + false + + + $(SolutionDir)\..\Common;$(IncludePath) + diskspd + false + + + $(SolutionDir)\..\Common;$(IncludePath) + DiskSpd32 + + + $(SolutionDir)\..\Common;$(IncludePath) + DiskSpd64 + + + $(SolutionDir)\..\Common;$(IncludePath) + DiskSpdA64 + + + $(SolutionDir)\..\Common;$(IncludePath) + DiskSpdA32 + + + + Level3 + Disabled + true + false + true + + + true + $(SolutionDir)$(Configuration)\xmlprofileparser.lib;$(SolutionDir)$(Configuration)\iorequestgenerator.lib;$(SolutionDir)$(Configuration)\resultparser.lib;$(SolutionDir)$(Configuration)\xmlresultparser.lib;$(SolutionDir)$(Configuration)\common.lib;powrprof.lib;msxml6.lib;%(AdditionalDependencies) + + + + + Level3 + Disabled + true + false + true + + + true + $(SolutionDir)$(Platform)\$(Configuration)\xmlprofileparser.lib;$(SolutionDir)$(Platform)\$(Configuration)\iorequestgenerator.lib;$(SolutionDir)$(Platform)\$(Configuration)\resultparser.lib;$(SolutionDir)$(Platform)\$(Configuration)\xmlresultparser.lib;$(SolutionDir)$(Platform)\$(Configuration)\common.lib;powrprof.lib;msxml6.lib;%(AdditionalDependencies) + + + + + Level3 + Disabled + true + false + true + + + true + $(SolutionDir)$(Platform)\$(Configuration)\xmlprofileparser.lib;$(SolutionDir)$(Platform)\$(Configuration)\iorequestgenerator.lib;$(SolutionDir)$(Platform)\$(Configuration)\resultparser.lib;$(SolutionDir)$(Platform)\$(Configuration)\xmlresultparser.lib;$(SolutionDir)$(Platform)\$(Configuration)\common.lib;powrprof.lib;msxml6.lib;%(AdditionalDependencies) + + + + + Level3 + Disabled + true + false + true + + + true + $(SolutionDir)$(Platform)\$(Configuration)\xmlprofileparser.lib;$(SolutionDir)$(Platform)\$(Configuration)\iorequestgenerator.lib;$(SolutionDir)$(Platform)\$(Configuration)\resultparser.lib;$(SolutionDir)$(Platform)\$(Configuration)\xmlresultparser.lib;$(SolutionDir)$(Platform)\$(Configuration)\common.lib;powrprof.lib;msxml6.lib;%(AdditionalDependencies) + + + + + Level3 + MaxSpeed + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + true + true + MultiThreaded + + + true + true + true + $(SolutionDir)$(Configuration)\xmlprofileparser.lib;$(SolutionDir)$(Configuration)\iorequestgenerator.lib;$(SolutionDir)$(Configuration)\resultparser.lib;$(SolutionDir)$(Configuration)\xmlresultparser.lib;$(SolutionDir)$(Configuration)\common.lib;powrprof.lib;msxml6.lib;%(AdditionalDependencies) + + + + + Level3 + MaxSpeed + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + true + true + MultiThreaded + + + true + true + true + $(SolutionDir)$(Platform)\$(Configuration)\xmlprofileparser.lib;$(SolutionDir)$(Platform)\$(Configuration)\iorequestgenerator.lib;$(SolutionDir)$(Platform)\$(Configuration)\resultparser.lib;$(SolutionDir)$(Platform)\$(Configuration)\xmlresultparser.lib;$(SolutionDir)$(Platform)\$(Configuration)\common.lib;powrprof.lib;msxml6.lib;%(AdditionalDependencies) + + + + + Level3 + MaxSpeed + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + true + true + MultiThreaded + + + true + true + true + $(SolutionDir)$(Platform)\$(Configuration)\xmlprofileparser.lib;$(SolutionDir)$(Platform)\$(Configuration)\iorequestgenerator.lib;$(SolutionDir)$(Platform)\$(Configuration)\resultparser.lib;$(SolutionDir)$(Platform)\$(Configuration)\xmlresultparser.lib;$(SolutionDir)$(Platform)\$(Configuration)\common.lib;powrprof.lib;msxml6.lib;%(AdditionalDependencies) + + + + + Level3 + MaxSpeed + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + true + true + MultiThreaded + + + true + true + true + $(SolutionDir)$(Platform)\$(Configuration)\xmlprofileparser.lib;$(SolutionDir)$(Platform)\$(Configuration)\iorequestgenerator.lib;$(SolutionDir)$(Platform)\$(Configuration)\resultparser.lib;$(SolutionDir)$(Platform)\$(Configuration)\xmlresultparser.lib;$(SolutionDir)$(Platform)\$(Configuration)\common.lib;powrprof.lib;msxml6.lib;%(AdditionalDependencies) + + + + + {0ef5ce78-8e92-4a1b-a255-0f544aada291} + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/CristalDiskMark/source/diskspd22/diskspd_vs/Common/Common.vcxproj b/CristalDiskMark/source/diskspd22/diskspd_vs/Common/Common.vcxproj new file mode 100644 index 0000000..0b9fa4f --- /dev/null +++ b/CristalDiskMark/source/diskspd22/diskspd_vs/Common/Common.vcxproj @@ -0,0 +1,248 @@ + + + + + Debug + ARM + + + Debug + ARM64 + + + Debug + Win32 + + + Debug + x64 + + + Release + ARM + + + Release + ARM64 + + + Release + Win32 + + + Release + x64 + + + + {B253AB42-F482-417A-82CE-EDAFCD26F366} + Common + 10.0 + + + + StaticLibrary + true + MultiByte + v143 + + + StaticLibrary + true + MultiByte + v143 + + + StaticLibrary + true + MultiByte + v143 + + + StaticLibrary + true + MultiByte + v143 + + + StaticLibrary + false + true + MultiByte + v143 + + + StaticLibrary + false + true + MultiByte + v143 + + + StaticLibrary + false + true + MultiByte + v143 + + + StaticLibrary + false + true + MultiByte + v143 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Level3 + Disabled + true + false + true + + + true + + + + + Level3 + Disabled + true + false + true + + + true + + + + + Level3 + Disabled + true + false + true + + + true + + + + + Level3 + Disabled + true + false + true + + + true + + + + + Level3 + MaxSpeed + true + true + true + true + MultiThreaded + + + true + true + true + + + + + Level3 + MaxSpeed + true + true + true + true + MultiThreaded + + + true + true + true + + + + + Level3 + MaxSpeed + true + true + true + true + MultiThreaded + + + true + true + true + + + + + Level3 + MaxSpeed + true + true + true + true + MultiThreaded + + + true + true + true + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/CristalDiskMark/source/diskspd22/diskspd_vs/IORequestGenerator/IORequestGenerator.vcxproj b/CristalDiskMark/source/diskspd22/diskspd_vs/IORequestGenerator/IORequestGenerator.vcxproj new file mode 100644 index 0000000..9f6d9bb --- /dev/null +++ b/CristalDiskMark/source/diskspd22/diskspd_vs/IORequestGenerator/IORequestGenerator.vcxproj @@ -0,0 +1,278 @@ + + + + + Debug + ARM + + + Debug + ARM64 + + + Debug + Win32 + + + Debug + x64 + + + Release + ARM + + + Release + ARM64 + + + Release + Win32 + + + Release + x64 + + + + {62DB1E99-FBA0-45FD-9355-423059BA03B8} + IORequestGenerator + 10.0 + + + + StaticLibrary + true + MultiByte + v143 + + + StaticLibrary + true + MultiByte + v143 + + + StaticLibrary + true + MultiByte + v143 + + + StaticLibrary + true + MultiByte + v143 + + + StaticLibrary + false + true + MultiByte + v143 + + + StaticLibrary + false + true + MultiByte + v143 + + + StaticLibrary + false + true + MultiByte + v143 + + + StaticLibrary + false + true + MultiByte + v143 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + $(SolutionDir)\..\Common;$(IncludePath) + + + $(SolutionDir)\..\Common;$(IncludePath) + + + $(SolutionDir)\..\Common;$(IncludePath) + + + $(SolutionDir)\..\Common;$(IncludePath) + + + $(SolutionDir)\..\Common;$(IncludePath) + + + $(SolutionDir)\..\Common;$(IncludePath) + + + $(SolutionDir)\..\Common;$(IncludePath) + + + $(SolutionDir)\..\Common;$(IncludePath) + + + + Level3 + Disabled + true + false + true + + + true + + + + + Level3 + Disabled + true + false + true + + + true + + + + + Level3 + Disabled + true + false + true + + + true + + + + + Level3 + Disabled + true + false + true + + + true + + + + + Level3 + MaxSpeed + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + true + true + MultiThreaded + + + true + true + true + + + + + Level3 + MaxSpeed + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + true + true + MultiThreaded + + + true + true + true + + + + + Level3 + MaxSpeed + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + true + true + MultiThreaded + + + true + true + true + + + + + Level3 + MaxSpeed + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + true + true + MultiThreaded + + + true + true + true + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/CristalDiskMark/source/diskspd22/diskspd_vs/ResultParser/ResultParser.vcxproj b/CristalDiskMark/source/diskspd22/diskspd_vs/ResultParser/ResultParser.vcxproj new file mode 100644 index 0000000..dbe59a0 --- /dev/null +++ b/CristalDiskMark/source/diskspd22/diskspd_vs/ResultParser/ResultParser.vcxproj @@ -0,0 +1,272 @@ + + + + + Debug + ARM + + + Debug + ARM64 + + + Debug + Win32 + + + Debug + x64 + + + Release + ARM + + + Release + ARM64 + + + Release + Win32 + + + Release + x64 + + + + {F6C211DC-B076-4716-BCDC-D7DE88973B66} + ResultParser + 10.0 + + + + StaticLibrary + true + MultiByte + v143 + + + StaticLibrary + true + MultiByte + v143 + + + StaticLibrary + true + MultiByte + v143 + + + StaticLibrary + true + MultiByte + v143 + + + StaticLibrary + false + true + MultiByte + v143 + + + StaticLibrary + false + true + MultiByte + v143 + + + StaticLibrary + false + true + MultiByte + v143 + + + StaticLibrary + false + true + MultiByte + v143 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + $(SolutionDir)\..\Common;$(IncludePath) + + + $(SolutionDir)\..\Common;$(IncludePath) + + + $(SolutionDir)\..\Common;$(IncludePath) + + + $(SolutionDir)\..\Common;$(IncludePath) + + + $(SolutionDir)\..\Common;$(IncludePath) + + + $(SolutionDir)\..\Common;$(IncludePath) + + + $(SolutionDir)\..\Common;$(IncludePath) + + + $(SolutionDir)\..\Common;$(IncludePath) + + + + Level3 + Disabled + true + false + true + + + true + + + + + Level3 + Disabled + true + false + true + + + true + + + + + Level3 + Disabled + true + false + true + + + true + + + + + Level3 + Disabled + true + false + true + + + true + + + + + Level3 + MaxSpeed + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + true + true + MultiThreaded + + + true + true + true + + + + + Level3 + MaxSpeed + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + true + true + MultiThreaded + + + true + true + true + + + + + Level3 + MaxSpeed + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + true + true + MultiThreaded + + + true + true + true + + + + + Level3 + MaxSpeed + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + true + true + MultiThreaded + + + true + true + true + + + + + + + + + + + + \ No newline at end of file diff --git a/CristalDiskMark/source/diskspd22/diskspd_vs/UnitTests.sln b/CristalDiskMark/source/diskspd22/diskspd_vs/UnitTests.sln new file mode 100644 index 0000000..3c1cb90 --- /dev/null +++ b/CristalDiskMark/source/diskspd22/diskspd_vs/UnitTests.sln @@ -0,0 +1,81 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.27130.2010 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CmdLineParser", "UnitTests\CmdLineParser\CmdLineParser.vcxproj", "{54186266-8BA1-438C-AE76-AD64503CA6E9}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Common", "UnitTests\Common\Common.vcxproj", "{BA9F561C-B103-48C9-A7C8-CE2B6BD89511}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "IORequestGenerator", "UnitTests\IORequestGenerator\IORequestGenerator.vcxproj", "{13683A8B-2641-4287-9D66-A87834885057}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "XmlProfileParser", "UnitTests\XmlProfileParser\XmlProfileParser.vcxproj", "{B20AA8CF-ADFB-487C-B8F9-DBD3037F53AD}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "XmlResultParser", "UnitTests\XmlResultParser\XmlResultParser.vcxproj", "{D52F964B-C636-4DCC-AA7E-EE83A7AC41AD}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ResultParser", "UnitTests\ResultParser\ResultParser.vcxproj", "{471E64C7-2C65-4E16-A82D-4BF22AE690DD}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {54186266-8BA1-438C-AE76-AD64503CA6E9}.Debug|x64.ActiveCfg = Debug|x64 + {54186266-8BA1-438C-AE76-AD64503CA6E9}.Debug|x64.Build.0 = Debug|x64 + {54186266-8BA1-438C-AE76-AD64503CA6E9}.Debug|x86.ActiveCfg = Debug|Win32 + {54186266-8BA1-438C-AE76-AD64503CA6E9}.Debug|x86.Build.0 = Debug|Win32 + {54186266-8BA1-438C-AE76-AD64503CA6E9}.Release|x64.ActiveCfg = Release|x64 + {54186266-8BA1-438C-AE76-AD64503CA6E9}.Release|x64.Build.0 = Release|x64 + {54186266-8BA1-438C-AE76-AD64503CA6E9}.Release|x86.ActiveCfg = Release|Win32 + {54186266-8BA1-438C-AE76-AD64503CA6E9}.Release|x86.Build.0 = Release|Win32 + {BA9F561C-B103-48C9-A7C8-CE2B6BD89511}.Debug|x64.ActiveCfg = Debug|x64 + {BA9F561C-B103-48C9-A7C8-CE2B6BD89511}.Debug|x64.Build.0 = Debug|x64 + {BA9F561C-B103-48C9-A7C8-CE2B6BD89511}.Debug|x86.ActiveCfg = Debug|Win32 + {BA9F561C-B103-48C9-A7C8-CE2B6BD89511}.Debug|x86.Build.0 = Debug|Win32 + {BA9F561C-B103-48C9-A7C8-CE2B6BD89511}.Release|x64.ActiveCfg = Release|x64 + {BA9F561C-B103-48C9-A7C8-CE2B6BD89511}.Release|x64.Build.0 = Release|x64 + {BA9F561C-B103-48C9-A7C8-CE2B6BD89511}.Release|x86.ActiveCfg = Release|Win32 + {BA9F561C-B103-48C9-A7C8-CE2B6BD89511}.Release|x86.Build.0 = Release|Win32 + {13683A8B-2641-4287-9D66-A87834885057}.Debug|x64.ActiveCfg = Debug|x64 + {13683A8B-2641-4287-9D66-A87834885057}.Debug|x64.Build.0 = Debug|x64 + {13683A8B-2641-4287-9D66-A87834885057}.Debug|x86.ActiveCfg = Debug|Win32 + {13683A8B-2641-4287-9D66-A87834885057}.Debug|x86.Build.0 = Debug|Win32 + {13683A8B-2641-4287-9D66-A87834885057}.Release|x64.ActiveCfg = Release|x64 + {13683A8B-2641-4287-9D66-A87834885057}.Release|x64.Build.0 = Release|x64 + {13683A8B-2641-4287-9D66-A87834885057}.Release|x86.ActiveCfg = Release|Win32 + {13683A8B-2641-4287-9D66-A87834885057}.Release|x86.Build.0 = Release|Win32 + {B20AA8CF-ADFB-487C-B8F9-DBD3037F53AD}.Debug|x64.ActiveCfg = Debug|x64 + {B20AA8CF-ADFB-487C-B8F9-DBD3037F53AD}.Debug|x64.Build.0 = Debug|x64 + {B20AA8CF-ADFB-487C-B8F9-DBD3037F53AD}.Debug|x86.ActiveCfg = Debug|Win32 + {B20AA8CF-ADFB-487C-B8F9-DBD3037F53AD}.Debug|x86.Build.0 = Debug|Win32 + {B20AA8CF-ADFB-487C-B8F9-DBD3037F53AD}.Release|x64.ActiveCfg = Release|x64 + {B20AA8CF-ADFB-487C-B8F9-DBD3037F53AD}.Release|x64.Build.0 = Release|x64 + {B20AA8CF-ADFB-487C-B8F9-DBD3037F53AD}.Release|x86.ActiveCfg = Release|Win32 + {B20AA8CF-ADFB-487C-B8F9-DBD3037F53AD}.Release|x86.Build.0 = Release|Win32 + {D52F964B-C636-4DCC-AA7E-EE83A7AC41AD}.Debug|x64.ActiveCfg = Debug|x64 + {D52F964B-C636-4DCC-AA7E-EE83A7AC41AD}.Debug|x64.Build.0 = Debug|x64 + {D52F964B-C636-4DCC-AA7E-EE83A7AC41AD}.Debug|x86.ActiveCfg = Debug|Win32 + {D52F964B-C636-4DCC-AA7E-EE83A7AC41AD}.Debug|x86.Build.0 = Debug|Win32 + {D52F964B-C636-4DCC-AA7E-EE83A7AC41AD}.Release|x64.ActiveCfg = Release|x64 + {D52F964B-C636-4DCC-AA7E-EE83A7AC41AD}.Release|x64.Build.0 = Release|x64 + {D52F964B-C636-4DCC-AA7E-EE83A7AC41AD}.Release|x86.ActiveCfg = Release|Win32 + {D52F964B-C636-4DCC-AA7E-EE83A7AC41AD}.Release|x86.Build.0 = Release|Win32 + {471E64C7-2C65-4E16-A82D-4BF22AE690DD}.Debug|x64.ActiveCfg = Debug|x64 + {471E64C7-2C65-4E16-A82D-4BF22AE690DD}.Debug|x64.Build.0 = Debug|x64 + {471E64C7-2C65-4E16-A82D-4BF22AE690DD}.Debug|x86.ActiveCfg = Debug|Win32 + {471E64C7-2C65-4E16-A82D-4BF22AE690DD}.Debug|x86.Build.0 = Debug|Win32 + {471E64C7-2C65-4E16-A82D-4BF22AE690DD}.Release|x64.ActiveCfg = Release|x64 + {471E64C7-2C65-4E16-A82D-4BF22AE690DD}.Release|x64.Build.0 = Release|x64 + {471E64C7-2C65-4E16-A82D-4BF22AE690DD}.Release|x86.ActiveCfg = Release|Win32 + {471E64C7-2C65-4E16-A82D-4BF22AE690DD}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {FB4A98A9-4B75-40C4-B6F2-145D57FC54C4} + EndGlobalSection +EndGlobal diff --git a/CristalDiskMark/source/diskspd22/diskspd_vs/UnitTests/CmdLineParser/CmdLineParser.vcxproj b/CristalDiskMark/source/diskspd22/diskspd_vs/UnitTests/CmdLineParser/CmdLineParser.vcxproj new file mode 100644 index 0000000..65f478b --- /dev/null +++ b/CristalDiskMark/source/diskspd22/diskspd_vs/UnitTests/CmdLineParser/CmdLineParser.vcxproj @@ -0,0 +1,174 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + + + + + + + + + + + 15.0 + {54186266-8BA1-438C-AE76-AD64503CA6E9} + Win32Proj + CmdLineParser + 10.0 + + + + DynamicLibrary + true + v143 + Unicode + + + DynamicLibrary + false + v143 + true + Unicode + + + DynamicLibrary + true + v143 + Unicode + + + DynamicLibrary + false + v143 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + $(ProjectName).UnitTests + $(SolutionDir)..\Common;$(WindowsSDKDir)\Testing\Development\inc;$(IncludePath) + $(WindowsSDKDir)\Testing\Development\lib\$(PlatformTarget);$(LibraryPath) + + + true + $(ProjectName).UnitTests + $(SolutionDir)..\Common;$(WindowsSDKDir)\Testing\Development\inc;$(IncludePath) + $(WindowsSDKDir)\Testing\Development\lib\$(PlatformTarget);$(LibraryPath) + + + false + $(ProjectName).UnitTests + $(SolutionDir)..\Common;$(WindowsSDKDir)\Testing\Development\inc;$(IncludePath) + $(WindowsSDKDir)\Testing\Development\lib\$(PlatformTarget);$(LibraryPath) + + + false + $(ProjectName).UnitTests + $(SolutionDir)..\Common;$(WindowsSDKDir)\Testing\Development\inc;$(IncludePath) + $(WindowsSDKDir)\Testing\Development\lib\$(PlatformTarget);$(LibraryPath) + + + + Level3 + Disabled + true + false + + + Windows + true + Common.lib;CmdLineParser.lib;XmlProfileParser.lib;powrprof.lib;%(AdditionalDependencies) + $(OutDir);%(AdditionalLibraryDirectories) + + + + + Level3 + Disabled + true + false + + + Windows + true + Common.lib;CmdLineParser.lib;XmlProfileParser.lib;powrprof.lib;%(AdditionalDependencies) + $(OutDir);%(AdditionalLibraryDirectories) + + + + + Level3 + MaxSpeed + true + true + true + false + + + Windows + true + true + true + Common.lib;CmdLineParser.lib;XmlProfileParser.lib;powrprof.lib;%(AdditionalDependencies) + $(OutDir);%(AdditionalLibraryDirectories) + + + + + Level3 + MaxSpeed + true + true + true + false + + + Windows + true + true + true + Common.lib;CmdLineParser.lib;XmlProfileParser.lib;powrprof.lib;%(AdditionalDependencies) + $(OutDir);%(AdditionalLibraryDirectories) + + + + + + \ No newline at end of file diff --git a/CristalDiskMark/source/diskspd22/diskspd_vs/UnitTests/Common/Common.vcxproj b/CristalDiskMark/source/diskspd22/diskspd_vs/UnitTests/Common/Common.vcxproj new file mode 100644 index 0000000..3451a51 --- /dev/null +++ b/CristalDiskMark/source/diskspd22/diskspd_vs/UnitTests/Common/Common.vcxproj @@ -0,0 +1,174 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + + + + + + + + + + + 15.0 + {BA9F561C-B103-48C9-A7C8-CE2B6BD89511} + Win32Proj + Common + 10.0 + + + + DynamicLibrary + true + v143 + Unicode + + + DynamicLibrary + false + v143 + true + Unicode + + + DynamicLibrary + true + v143 + Unicode + + + DynamicLibrary + false + v143 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + $(ProjectName).UnitTests + $(SolutionDir)..\Common;$(WindowsSDKDir)\Testing\Development\inc;$(IncludePath) + $(WindowsSDKDir)\Testing\Development\lib\$(PlatformTarget);$(LibraryPath) + + + true + $(ProjectName).UnitTests + $(SolutionDir)..\Common;$(WindowsSDKDir)\Testing\Development\inc;$(IncludePath) + $(WindowsSDKDir)\Testing\Development\lib\$(PlatformTarget);$(LibraryPath) + + + false + $(ProjectName).UnitTests + $(SolutionDir)..\Common;$(WindowsSDKDir)\Testing\Development\inc;$(IncludePath) + $(WindowsSDKDir)\Testing\Development\lib\$(PlatformTarget);$(LibraryPath) + + + false + $(ProjectName).UnitTests + $(SolutionDir)..\Common;$(WindowsSDKDir)\Testing\Development\inc;$(IncludePath) + $(WindowsSDKDir)\Testing\Development\lib\$(PlatformTarget);$(LibraryPath) + + + + Level3 + Disabled + true + false + + + Windows + true + $(OutDir);%(AdditionalLibraryDirectories) + Common.lib;powrprof.lib;%(AdditionalDependencies) + + + + + Level3 + Disabled + true + false + + + Windows + true + $(OutDir);%(AdditionalLibraryDirectories) + Common.lib;powrprof.lib;%(AdditionalDependencies) + + + + + Level3 + MaxSpeed + true + true + true + false + + + Windows + true + true + true + $(OutDir);%(AdditionalLibraryDirectories) + Common.lib;powrprof.lib;%(AdditionalDependencies) + + + + + Level3 + MaxSpeed + true + true + true + false + + + Windows + true + true + true + $(OutDir);%(AdditionalLibraryDirectories) + Common.lib;powrprof.lib;%(AdditionalDependencies) + + + + + + \ No newline at end of file diff --git a/CristalDiskMark/source/diskspd22/diskspd_vs/UnitTests/IORequestGenerator/IORequestGenerator.vcxproj b/CristalDiskMark/source/diskspd22/diskspd_vs/UnitTests/IORequestGenerator/IORequestGenerator.vcxproj new file mode 100644 index 0000000..aadbf24 --- /dev/null +++ b/CristalDiskMark/source/diskspd22/diskspd_vs/UnitTests/IORequestGenerator/IORequestGenerator.vcxproj @@ -0,0 +1,174 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + + + + + + + + + + + 15.0 + {13683A8B-2641-4287-9D66-A87834885057} + Win32Proj + IORequestGenerator + 10.0 + + + + DynamicLibrary + true + v143 + Unicode + + + DynamicLibrary + false + v143 + true + Unicode + + + DynamicLibrary + true + v143 + Unicode + + + DynamicLibrary + false + v143 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + $(ProjectName).UnitTests + $(SolutionDir)..\Common;$(WindowsSDKDir)\Testing\Development\inc;$(IncludePath) + $(WindowsSDKDir)\Testing\Development\lib\$(PlatformTarget);$(LibraryPath) + + + true + $(ProjectName).UnitTests + $(SolutionDir)..\Common;$(WindowsSDKDir)\Testing\Development\inc;$(IncludePath) + $(WindowsSDKDir)\Testing\Development\lib\$(PlatformTarget);$(LibraryPath) + + + false + $(ProjectName).UnitTests + $(SolutionDir)..\Common;$(WindowsSDKDir)\Testing\Development\inc;$(IncludePath) + $(WindowsSDKDir)\Testing\Development\lib\$(PlatformTarget);$(LibraryPath) + + + false + $(ProjectName).UnitTests + $(SolutionDir)..\Common;$(WindowsSDKDir)\Testing\Development\inc;$(IncludePath) + $(WindowsSDKDir)\Testing\Development\lib\$(PlatformTarget);$(LibraryPath) + + + + Level3 + Disabled + true + false + + + Windows + true + $(OutDir);%(AdditionalLibraryDirectories) + Common.lib;IORequestGenerator.lib;powrprof.lib;%(AdditionalDependencies) + + + + + Level3 + Disabled + true + false + + + Windows + true + $(OutDir);%(AdditionalLibraryDirectories) + Common.lib;IORequestGenerator.lib;powrprof.lib;%(AdditionalDependencies) + + + + + Level3 + MaxSpeed + true + true + true + false + + + Windows + true + true + true + $(OutDir);%(AdditionalLibraryDirectories) + Common.lib;IORequestGenerator.lib;powrprof.lib;%(AdditionalDependencies) + + + + + Level3 + MaxSpeed + true + true + true + false + + + Windows + true + true + true + $(OutDir);%(AdditionalLibraryDirectories) + Common.lib;IORequestGenerator.lib;powrprof.lib;%(AdditionalDependencies) + + + + + + \ No newline at end of file diff --git a/CristalDiskMark/source/diskspd22/diskspd_vs/UnitTests/ResultParser/ResultParser.vcxproj b/CristalDiskMark/source/diskspd22/diskspd_vs/UnitTests/ResultParser/ResultParser.vcxproj new file mode 100644 index 0000000..b8d4b9d --- /dev/null +++ b/CristalDiskMark/source/diskspd22/diskspd_vs/UnitTests/ResultParser/ResultParser.vcxproj @@ -0,0 +1,174 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + + + + + + + + + + + 15.0 + {471E64C7-2C65-4E16-A82D-4BF22AE690DD} + Win32Proj + ResultParser + 10.0 + + + + DynamicLibrary + true + v143 + Unicode + + + DynamicLibrary + false + v143 + true + Unicode + + + DynamicLibrary + true + v143 + Unicode + + + DynamicLibrary + false + v143 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + $(ProjectName).UnitTests + $(SolutionDir)..\Common;$(WindowsSDKDir)\Testing\Development\inc;$(IncludePath) + $(WindowsSDKDir)\Testing\Development\lib\$(PlatformTarget);$(LibraryPath) + + + true + $(ProjectName).UnitTests + $(SolutionDir)..\Common;$(WindowsSDKDir)\Testing\Development\inc;$(IncludePath) + $(WindowsSDKDir)\Testing\Development\lib\$(PlatformTarget);$(LibraryPath) + + + false + $(ProjectName).UnitTests + $(SolutionDir)..\Common;$(WindowsSDKDir)\Testing\Development\inc;$(IncludePath) + $(WindowsSDKDir)\Testing\Development\lib\$(PlatformTarget);$(LibraryPath) + + + false + $(ProjectName).UnitTests + $(SolutionDir)..\Common;$(WindowsSDKDir)\Testing\Development\inc;$(IncludePath) + $(WindowsSDKDir)\Testing\Development\lib\$(PlatformTarget);$(LibraryPath) + + + + Level3 + Disabled + true + false + + + Windows + true + $(OutDir);%(AdditionalLibraryDirectories) + Common.lib;ResultParser.lib;powrprof.lib;%(AdditionalDependencies) + + + + + Level3 + Disabled + true + false + + + Windows + true + $(OutDir);%(AdditionalLibraryDirectories) + Common.lib;ResultParser.lib;powrprof.lib;%(AdditionalDependencies) + + + + + Level3 + MaxSpeed + true + true + true + false + + + Windows + true + true + true + $(OutDir);%(AdditionalLibraryDirectories) + Common.lib;ResultParser.lib;powrprof.lib;%(AdditionalDependencies) + + + + + Level3 + MaxSpeed + true + true + true + false + + + Windows + true + true + true + $(OutDir);%(AdditionalLibraryDirectories) + Common.lib;ResultParser.lib;powrprof.lib;%(AdditionalDependencies) + + + + + + \ No newline at end of file diff --git a/CristalDiskMark/source/diskspd22/diskspd_vs/UnitTests/XmlProfileParser/XmlProfileParser.vcxproj b/CristalDiskMark/source/diskspd22/diskspd_vs/UnitTests/XmlProfileParser/XmlProfileParser.vcxproj new file mode 100644 index 0000000..77e2919 --- /dev/null +++ b/CristalDiskMark/source/diskspd22/diskspd_vs/UnitTests/XmlProfileParser/XmlProfileParser.vcxproj @@ -0,0 +1,174 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + + + + + + + + + + + 15.0 + {B20AA8CF-ADFB-487C-B8F9-DBD3037F53AD} + Win32Proj + XmlProfileParser + 10.0 + + + + DynamicLibrary + true + v143 + Unicode + + + DynamicLibrary + false + v143 + true + Unicode + + + DynamicLibrary + true + v143 + Unicode + + + DynamicLibrary + false + v143 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + $(ProjectName).UnitTests + $(SolutionDir)..\Common;$(WindowsSDKDir)\Testing\Development\inc;$(IncludePath) + $(WindowsSDKDir)\Testing\Development\lib\$(PlatformTarget);$(LibraryPath) + + + true + $(ProjectName).UnitTests + $(SolutionDir)..\Common;$(WindowsSDKDir)\Testing\Development\inc;$(IncludePath) + $(WindowsSDKDir)\Testing\Development\lib\$(PlatformTarget);$(LibraryPath) + + + false + $(ProjectName).UnitTests + $(SolutionDir)..\Common;$(WindowsSDKDir)\Testing\Development\inc;$(IncludePath) + $(WindowsSDKDir)\Testing\Development\lib\$(PlatformTarget);$(LibraryPath) + + + false + $(ProjectName).UnitTests + $(SolutionDir)..\Common;$(WindowsSDKDir)\Testing\Development\inc;$(IncludePath) + $(WindowsSDKDir)\Testing\Development\lib\$(PlatformTarget);$(LibraryPath) + + + + Level3 + Disabled + true + false + + + Windows + true + $(OutDir);%(AdditionalLibraryDirectories) + Common.lib;XmlProfileParser.lib;powrprof.lib;%(AdditionalDependencies) + + + + + Level3 + Disabled + true + false + + + Windows + true + $(OutDir);%(AdditionalLibraryDirectories) + Common.lib;XmlProfileParser.lib;powrprof.lib;%(AdditionalDependencies) + + + + + Level3 + MaxSpeed + true + true + true + false + + + Windows + true + true + true + $(OutDir);%(AdditionalLibraryDirectories) + Common.lib;XmlProfileParser.lib;powrprof.lib;%(AdditionalDependencies) + + + + + Level3 + MaxSpeed + true + true + true + false + + + Windows + true + true + true + $(OutDir);%(AdditionalLibraryDirectories) + Common.lib;XmlProfileParser.lib;powrprof.lib;%(AdditionalDependencies) + + + + + + \ No newline at end of file diff --git a/CristalDiskMark/source/diskspd22/diskspd_vs/UnitTests/XmlResultParser/XmlResultParser.vcxproj b/CristalDiskMark/source/diskspd22/diskspd_vs/UnitTests/XmlResultParser/XmlResultParser.vcxproj new file mode 100644 index 0000000..9ff39df --- /dev/null +++ b/CristalDiskMark/source/diskspd22/diskspd_vs/UnitTests/XmlResultParser/XmlResultParser.vcxproj @@ -0,0 +1,174 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + + + + + + + + + + + 15.0 + {D52F964B-C636-4DCC-AA7E-EE83A7AC41AD} + Win32Proj + XmlResultParser + 10.0 + + + + DynamicLibrary + true + v143 + Unicode + + + DynamicLibrary + false + v143 + true + Unicode + + + DynamicLibrary + true + v143 + Unicode + + + DynamicLibrary + false + v143 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + $(ProjectName).UnitTests + $(SolutionDir)..\Common;$(WindowsSDKDir)\Testing\Development\inc;$(IncludePath) + $(WindowsSDKDir)\Testing\Development\lib\$(PlatformTarget);$(LibraryPath) + + + true + $(ProjectName).UnitTests + $(SolutionDir)..\Common;$(WindowsSDKDir)\Testing\Development\inc;$(IncludePath) + $(WindowsSDKDir)\Testing\Development\lib\$(PlatformTarget);$(LibraryPath) + + + false + $(ProjectName).UnitTests + $(SolutionDir)..\Common;$(WindowsSDKDir)\Testing\Development\inc;$(IncludePath) + $(WindowsSDKDir)\Testing\Development\lib\$(PlatformTarget);$(LibraryPath) + + + false + $(ProjectName).UnitTests + $(SolutionDir)..\Common;$(WindowsSDKDir)\Testing\Development\inc;$(IncludePath) + $(WindowsSDKDir)\Testing\Development\lib\$(PlatformTarget);$(LibraryPath) + + + + Level3 + Disabled + true + false + + + Windows + true + $(OutDir);%(AdditionalLibraryDirectories) + Common.lib;XmlResultParser.lib;powrprof.lib;%(AdditionalDependencies) + + + + + Level3 + Disabled + true + false + + + Windows + true + $(OutDir);%(AdditionalLibraryDirectories) + Common.lib;XmlResultParser.lib;powrprof.lib;%(AdditionalDependencies) + + + + + Level3 + MaxSpeed + true + true + true + false + + + Windows + true + true + true + $(OutDir);%(AdditionalLibraryDirectories) + Common.lib;XmlResultParser.lib;powrprof.lib;%(AdditionalDependencies) + + + + + Level3 + MaxSpeed + true + true + true + false + + + Windows + true + true + true + $(OutDir);%(AdditionalLibraryDirectories) + Common.lib;XmlResultParser.lib;powrprof.lib;%(AdditionalDependencies) + + + + + + \ No newline at end of file diff --git a/CristalDiskMark/source/diskspd22/diskspd_vs/XmlProfileParser/XmlProfileParser.vcxproj b/CristalDiskMark/source/diskspd22/diskspd_vs/XmlProfileParser/XmlProfileParser.vcxproj new file mode 100644 index 0000000..f2e66f9 --- /dev/null +++ b/CristalDiskMark/source/diskspd22/diskspd_vs/XmlProfileParser/XmlProfileParser.vcxproj @@ -0,0 +1,275 @@ + + + + + Debug + ARM + + + Debug + ARM64 + + + Debug + Win32 + + + Debug + x64 + + + Release + ARM + + + Release + ARM64 + + + Release + Win32 + + + Release + x64 + + + + {EFF06674-B068-45F1-9661-DB9363B025B3} + XmlProfileParser + 10.0 + + + + StaticLibrary + true + Unicode + v143 + + + StaticLibrary + true + Unicode + v143 + + + StaticLibrary + true + Unicode + v143 + + + StaticLibrary + true + Unicode + v143 + + + StaticLibrary + false + true + Unicode + v143 + + + StaticLibrary + false + true + Unicode + v143 + + + StaticLibrary + false + true + Unicode + v143 + + + StaticLibrary + false + true + Unicode + v143 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + $(SolutionDir)\..\Common;$(IncludePath) + + + $(SolutionDir)\..\Common;$(IncludePath) + + + $(SolutionDir)\..\Common;$(IncludePath) + + + $(SolutionDir)\..\Common;$(IncludePath) + + + $(SolutionDir)\..\Common;$(IncludePath) + + + $(SolutionDir)\..\Common;$(IncludePath) + + + $(SolutionDir)\..\Common;$(IncludePath) + + + $(SolutionDir)\..\Common;$(IncludePath) + + + + Level3 + Disabled + true + false + true + + + true + + + + + Level3 + Disabled + true + false + true + + + true + + + + + Level3 + Disabled + true + false + true + + + true + + + + + Level3 + Disabled + true + false + true + + + true + + + + + Level3 + MaxSpeed + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + true + true + MultiThreaded + + + true + true + true + + + + + Level3 + MaxSpeed + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + true + true + MultiThreaded + + + true + true + true + + + + + Level3 + MaxSpeed + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + true + true + MultiThreaded + + + true + true + true + + + + + Level3 + MaxSpeed + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + true + true + MultiThreaded + + + true + true + true + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/CristalDiskMark/source/diskspd22/diskspd_vs/XmlResultParser/XmlResultParser.vcxproj b/CristalDiskMark/source/diskspd22/diskspd_vs/XmlResultParser/XmlResultParser.vcxproj new file mode 100644 index 0000000..dab830f --- /dev/null +++ b/CristalDiskMark/source/diskspd22/diskspd_vs/XmlResultParser/XmlResultParser.vcxproj @@ -0,0 +1,301 @@ + + + + + Debug + ARM + + + Debug + ARM64 + + + Debug + Win32 + + + Debug + x64 + + + Release + ARM + + + Release + ARM64 + + + Release + Win32 + + + Release + x64 + + + + {60A28E9C-C245-4D99-9C1C-EC911031743F} + Win32Proj + XmlResultParser + 10.0 + + + + StaticLibrary + true + MultiByte + v143 + + + StaticLibrary + true + MultiByte + v143 + + + StaticLibrary + true + MultiByte + v143 + + + StaticLibrary + true + MultiByte + v143 + + + StaticLibrary + false + true + MultiByte + v143 + + + StaticLibrary + false + true + MultiByte + v143 + + + StaticLibrary + false + true + MultiByte + v143 + + + StaticLibrary + false + true + MultiByte + v143 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + $(SolutionDir)\..\Common;$(IncludePath) + + + $(SolutionDir)\..\Common;$(IncludePath) + + + $(SolutionDir)\..\Common;$(IncludePath) + + + $(SolutionDir)\..\Common;$(IncludePath) + + + $(SolutionDir)\..\Common;$(IncludePath) + + + $(SolutionDir)\..\Common;$(IncludePath) + + + $(SolutionDir)\..\Common;$(IncludePath) + + + $(SolutionDir)\..\Common;$(IncludePath) + + + + + + Level3 + Disabled + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + true + false + true + + + Windows + true + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + true + false + true + + + Windows + true + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + true + false + true + + + Windows + true + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + true + false + true + + + Windows + true + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + true + true + MultiThreaded + + + Windows + true + true + true + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + true + true + MultiThreaded + + + Windows + true + true + true + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + true + true + MultiThreaded + + + Windows + true + true + true + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + true + true + MultiThreaded + + + Windows + true + true + true + + + + + + + + + + + + \ No newline at end of file diff --git a/CristalDiskMark/source/diskspd22/diskspd_vs/diskspd.sln b/CristalDiskMark/source/diskspd22/diskspd_vs/diskspd.sln new file mode 100644 index 0000000..9d2e9b7 --- /dev/null +++ b/CristalDiskMark/source/diskspd22/diskspd_vs/diskspd.sln @@ -0,0 +1,159 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.13.35913.81 d17.13 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CmdLineParser", "CmdLineParser\CmdLineParser.vcxproj", "{0EF5CE78-8E92-4A1B-A255-0F544AADA291}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CmdRequestCreator", "CmdRequestCreator\CmdRequestCreator.vcxproj", "{D238F8AA-DE12-49E7-B4A7-9B69579A69C0}" + ProjectSection(ProjectDependencies) = postProject + {B253AB42-F482-417A-82CE-EDAFCD26F366} = {B253AB42-F482-417A-82CE-EDAFCD26F366} + {EFF06674-B068-45F1-9661-DB9363B025B3} = {EFF06674-B068-45F1-9661-DB9363B025B3} + {0EF5CE78-8E92-4A1B-A255-0F544AADA291} = {0EF5CE78-8E92-4A1B-A255-0F544AADA291} + {62DB1E99-FBA0-45FD-9355-423059BA03B8} = {62DB1E99-FBA0-45FD-9355-423059BA03B8} + {60A28E9C-C245-4D99-9C1C-EC911031743F} = {60A28E9C-C245-4D99-9C1C-EC911031743F} + {F6C211DC-B076-4716-BCDC-D7DE88973B66} = {F6C211DC-B076-4716-BCDC-D7DE88973B66} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "IORequestGenerator", "IORequestGenerator\IORequestGenerator.vcxproj", "{62DB1E99-FBA0-45FD-9355-423059BA03B8}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ResultParser", "ResultParser\ResultParser.vcxproj", "{F6C211DC-B076-4716-BCDC-D7DE88973B66}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "XmlProfileParser", "XmlProfileParser\XmlProfileParser.vcxproj", "{EFF06674-B068-45F1-9661-DB9363B025B3}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Common", "Common\Common.vcxproj", "{B253AB42-F482-417A-82CE-EDAFCD26F366}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "XmlResultParser", "XmlResultParser\XmlResultParser.vcxproj", "{60A28E9C-C245-4D99-9C1C-EC911031743F}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|ARM = Debug|ARM + Debug|ARM64 = Debug|ARM64 + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|ARM = Release|ARM + Release|ARM64 = Release|ARM64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {0EF5CE78-8E92-4A1B-A255-0F544AADA291}.Debug|ARM.ActiveCfg = Debug|ARM + {0EF5CE78-8E92-4A1B-A255-0F544AADA291}.Debug|ARM.Build.0 = Debug|ARM + {0EF5CE78-8E92-4A1B-A255-0F544AADA291}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {0EF5CE78-8E92-4A1B-A255-0F544AADA291}.Debug|ARM64.Build.0 = Debug|ARM64 + {0EF5CE78-8E92-4A1B-A255-0F544AADA291}.Debug|Win32.ActiveCfg = Debug|Win32 + {0EF5CE78-8E92-4A1B-A255-0F544AADA291}.Debug|Win32.Build.0 = Debug|Win32 + {0EF5CE78-8E92-4A1B-A255-0F544AADA291}.Debug|x64.ActiveCfg = Debug|x64 + {0EF5CE78-8E92-4A1B-A255-0F544AADA291}.Debug|x64.Build.0 = Debug|x64 + {0EF5CE78-8E92-4A1B-A255-0F544AADA291}.Release|ARM.ActiveCfg = Release|ARM + {0EF5CE78-8E92-4A1B-A255-0F544AADA291}.Release|ARM.Build.0 = Release|ARM + {0EF5CE78-8E92-4A1B-A255-0F544AADA291}.Release|ARM64.ActiveCfg = Release|ARM64 + {0EF5CE78-8E92-4A1B-A255-0F544AADA291}.Release|ARM64.Build.0 = Release|ARM64 + {0EF5CE78-8E92-4A1B-A255-0F544AADA291}.Release|Win32.ActiveCfg = Release|Win32 + {0EF5CE78-8E92-4A1B-A255-0F544AADA291}.Release|Win32.Build.0 = Release|Win32 + {0EF5CE78-8E92-4A1B-A255-0F544AADA291}.Release|x64.ActiveCfg = Release|x64 + {0EF5CE78-8E92-4A1B-A255-0F544AADA291}.Release|x64.Build.0 = Release|x64 + {D238F8AA-DE12-49E7-B4A7-9B69579A69C0}.Debug|ARM.ActiveCfg = Debug|ARM + {D238F8AA-DE12-49E7-B4A7-9B69579A69C0}.Debug|ARM.Build.0 = Debug|ARM + {D238F8AA-DE12-49E7-B4A7-9B69579A69C0}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {D238F8AA-DE12-49E7-B4A7-9B69579A69C0}.Debug|ARM64.Build.0 = Debug|ARM64 + {D238F8AA-DE12-49E7-B4A7-9B69579A69C0}.Debug|Win32.ActiveCfg = Debug|Win32 + {D238F8AA-DE12-49E7-B4A7-9B69579A69C0}.Debug|Win32.Build.0 = Debug|Win32 + {D238F8AA-DE12-49E7-B4A7-9B69579A69C0}.Debug|x64.ActiveCfg = Debug|x64 + {D238F8AA-DE12-49E7-B4A7-9B69579A69C0}.Debug|x64.Build.0 = Debug|x64 + {D238F8AA-DE12-49E7-B4A7-9B69579A69C0}.Release|ARM.ActiveCfg = Release|ARM + {D238F8AA-DE12-49E7-B4A7-9B69579A69C0}.Release|ARM.Build.0 = Release|ARM + {D238F8AA-DE12-49E7-B4A7-9B69579A69C0}.Release|ARM64.ActiveCfg = Release|ARM64 + {D238F8AA-DE12-49E7-B4A7-9B69579A69C0}.Release|ARM64.Build.0 = Release|ARM64 + {D238F8AA-DE12-49E7-B4A7-9B69579A69C0}.Release|Win32.ActiveCfg = Release|Win32 + {D238F8AA-DE12-49E7-B4A7-9B69579A69C0}.Release|Win32.Build.0 = Release|Win32 + {D238F8AA-DE12-49E7-B4A7-9B69579A69C0}.Release|x64.ActiveCfg = Release|x64 + {D238F8AA-DE12-49E7-B4A7-9B69579A69C0}.Release|x64.Build.0 = Release|x64 + {62DB1E99-FBA0-45FD-9355-423059BA03B8}.Debug|ARM.ActiveCfg = Debug|ARM + {62DB1E99-FBA0-45FD-9355-423059BA03B8}.Debug|ARM.Build.0 = Debug|ARM + {62DB1E99-FBA0-45FD-9355-423059BA03B8}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {62DB1E99-FBA0-45FD-9355-423059BA03B8}.Debug|ARM64.Build.0 = Debug|ARM64 + {62DB1E99-FBA0-45FD-9355-423059BA03B8}.Debug|Win32.ActiveCfg = Debug|Win32 + {62DB1E99-FBA0-45FD-9355-423059BA03B8}.Debug|Win32.Build.0 = Debug|Win32 + {62DB1E99-FBA0-45FD-9355-423059BA03B8}.Debug|x64.ActiveCfg = Debug|x64 + {62DB1E99-FBA0-45FD-9355-423059BA03B8}.Debug|x64.Build.0 = Debug|x64 + {62DB1E99-FBA0-45FD-9355-423059BA03B8}.Release|ARM.ActiveCfg = Release|ARM + {62DB1E99-FBA0-45FD-9355-423059BA03B8}.Release|ARM.Build.0 = Release|ARM + {62DB1E99-FBA0-45FD-9355-423059BA03B8}.Release|ARM64.ActiveCfg = Release|ARM64 + {62DB1E99-FBA0-45FD-9355-423059BA03B8}.Release|ARM64.Build.0 = Release|ARM64 + {62DB1E99-FBA0-45FD-9355-423059BA03B8}.Release|Win32.ActiveCfg = Release|Win32 + {62DB1E99-FBA0-45FD-9355-423059BA03B8}.Release|Win32.Build.0 = Release|Win32 + {62DB1E99-FBA0-45FD-9355-423059BA03B8}.Release|x64.ActiveCfg = Release|x64 + {62DB1E99-FBA0-45FD-9355-423059BA03B8}.Release|x64.Build.0 = Release|x64 + {F6C211DC-B076-4716-BCDC-D7DE88973B66}.Debug|ARM.ActiveCfg = Debug|ARM + {F6C211DC-B076-4716-BCDC-D7DE88973B66}.Debug|ARM.Build.0 = Debug|ARM + {F6C211DC-B076-4716-BCDC-D7DE88973B66}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {F6C211DC-B076-4716-BCDC-D7DE88973B66}.Debug|ARM64.Build.0 = Debug|ARM64 + {F6C211DC-B076-4716-BCDC-D7DE88973B66}.Debug|Win32.ActiveCfg = Debug|Win32 + {F6C211DC-B076-4716-BCDC-D7DE88973B66}.Debug|Win32.Build.0 = Debug|Win32 + {F6C211DC-B076-4716-BCDC-D7DE88973B66}.Debug|x64.ActiveCfg = Debug|x64 + {F6C211DC-B076-4716-BCDC-D7DE88973B66}.Debug|x64.Build.0 = Debug|x64 + {F6C211DC-B076-4716-BCDC-D7DE88973B66}.Release|ARM.ActiveCfg = Release|ARM + {F6C211DC-B076-4716-BCDC-D7DE88973B66}.Release|ARM.Build.0 = Release|ARM + {F6C211DC-B076-4716-BCDC-D7DE88973B66}.Release|ARM64.ActiveCfg = Release|ARM64 + {F6C211DC-B076-4716-BCDC-D7DE88973B66}.Release|ARM64.Build.0 = Release|ARM64 + {F6C211DC-B076-4716-BCDC-D7DE88973B66}.Release|Win32.ActiveCfg = Release|Win32 + {F6C211DC-B076-4716-BCDC-D7DE88973B66}.Release|Win32.Build.0 = Release|Win32 + {F6C211DC-B076-4716-BCDC-D7DE88973B66}.Release|x64.ActiveCfg = Release|x64 + {F6C211DC-B076-4716-BCDC-D7DE88973B66}.Release|x64.Build.0 = Release|x64 + {EFF06674-B068-45F1-9661-DB9363B025B3}.Debug|ARM.ActiveCfg = Debug|ARM + {EFF06674-B068-45F1-9661-DB9363B025B3}.Debug|ARM.Build.0 = Debug|ARM + {EFF06674-B068-45F1-9661-DB9363B025B3}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {EFF06674-B068-45F1-9661-DB9363B025B3}.Debug|ARM64.Build.0 = Debug|ARM64 + {EFF06674-B068-45F1-9661-DB9363B025B3}.Debug|Win32.ActiveCfg = Debug|Win32 + {EFF06674-B068-45F1-9661-DB9363B025B3}.Debug|Win32.Build.0 = Debug|Win32 + {EFF06674-B068-45F1-9661-DB9363B025B3}.Debug|x64.ActiveCfg = Debug|x64 + {EFF06674-B068-45F1-9661-DB9363B025B3}.Debug|x64.Build.0 = Debug|x64 + {EFF06674-B068-45F1-9661-DB9363B025B3}.Release|ARM.ActiveCfg = Release|ARM + {EFF06674-B068-45F1-9661-DB9363B025B3}.Release|ARM.Build.0 = Release|ARM + {EFF06674-B068-45F1-9661-DB9363B025B3}.Release|ARM64.ActiveCfg = Release|ARM64 + {EFF06674-B068-45F1-9661-DB9363B025B3}.Release|ARM64.Build.0 = Release|ARM64 + {EFF06674-B068-45F1-9661-DB9363B025B3}.Release|Win32.ActiveCfg = Release|Win32 + {EFF06674-B068-45F1-9661-DB9363B025B3}.Release|Win32.Build.0 = Release|Win32 + {EFF06674-B068-45F1-9661-DB9363B025B3}.Release|x64.ActiveCfg = Release|x64 + {EFF06674-B068-45F1-9661-DB9363B025B3}.Release|x64.Build.0 = Release|x64 + {B253AB42-F482-417A-82CE-EDAFCD26F366}.Debug|ARM.ActiveCfg = Debug|ARM + {B253AB42-F482-417A-82CE-EDAFCD26F366}.Debug|ARM.Build.0 = Debug|ARM + {B253AB42-F482-417A-82CE-EDAFCD26F366}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {B253AB42-F482-417A-82CE-EDAFCD26F366}.Debug|ARM64.Build.0 = Debug|ARM64 + {B253AB42-F482-417A-82CE-EDAFCD26F366}.Debug|Win32.ActiveCfg = Debug|Win32 + {B253AB42-F482-417A-82CE-EDAFCD26F366}.Debug|Win32.Build.0 = Debug|Win32 + {B253AB42-F482-417A-82CE-EDAFCD26F366}.Debug|x64.ActiveCfg = Debug|x64 + {B253AB42-F482-417A-82CE-EDAFCD26F366}.Debug|x64.Build.0 = Debug|x64 + {B253AB42-F482-417A-82CE-EDAFCD26F366}.Release|ARM.ActiveCfg = Release|ARM + {B253AB42-F482-417A-82CE-EDAFCD26F366}.Release|ARM.Build.0 = Release|ARM + {B253AB42-F482-417A-82CE-EDAFCD26F366}.Release|ARM64.ActiveCfg = Release|ARM64 + {B253AB42-F482-417A-82CE-EDAFCD26F366}.Release|ARM64.Build.0 = Release|ARM64 + {B253AB42-F482-417A-82CE-EDAFCD26F366}.Release|Win32.ActiveCfg = Release|Win32 + {B253AB42-F482-417A-82CE-EDAFCD26F366}.Release|Win32.Build.0 = Release|Win32 + {B253AB42-F482-417A-82CE-EDAFCD26F366}.Release|x64.ActiveCfg = Release|x64 + {B253AB42-F482-417A-82CE-EDAFCD26F366}.Release|x64.Build.0 = Release|x64 + {60A28E9C-C245-4D99-9C1C-EC911031743F}.Debug|ARM.ActiveCfg = Debug|ARM + {60A28E9C-C245-4D99-9C1C-EC911031743F}.Debug|ARM.Build.0 = Debug|ARM + {60A28E9C-C245-4D99-9C1C-EC911031743F}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {60A28E9C-C245-4D99-9C1C-EC911031743F}.Debug|ARM64.Build.0 = Debug|ARM64 + {60A28E9C-C245-4D99-9C1C-EC911031743F}.Debug|Win32.ActiveCfg = Debug|Win32 + {60A28E9C-C245-4D99-9C1C-EC911031743F}.Debug|Win32.Build.0 = Debug|Win32 + {60A28E9C-C245-4D99-9C1C-EC911031743F}.Debug|x64.ActiveCfg = Debug|x64 + {60A28E9C-C245-4D99-9C1C-EC911031743F}.Debug|x64.Build.0 = Debug|x64 + {60A28E9C-C245-4D99-9C1C-EC911031743F}.Release|ARM.ActiveCfg = Release|ARM + {60A28E9C-C245-4D99-9C1C-EC911031743F}.Release|ARM.Build.0 = Release|ARM + {60A28E9C-C245-4D99-9C1C-EC911031743F}.Release|ARM64.ActiveCfg = Release|ARM64 + {60A28E9C-C245-4D99-9C1C-EC911031743F}.Release|ARM64.Build.0 = Release|ARM64 + {60A28E9C-C245-4D99-9C1C-EC911031743F}.Release|Win32.ActiveCfg = Release|Win32 + {60A28E9C-C245-4D99-9C1C-EC911031743F}.Release|Win32.Build.0 = Release|Win32 + {60A28E9C-C245-4D99-9C1C-EC911031743F}.Release|x64.ActiveCfg = Release|x64 + {60A28E9C-C245-4D99-9C1C-EC911031743F}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {D8A6AD59-8AE6-4175-B290-FC85D63D3503} + EndGlobalSection +EndGlobal diff --git a/CristalDiskMark/source/diskspd2_0_15a/CmdLineParser/CmdLineParser.cpp b/CristalDiskMark/source/diskspd2_0_15a/CmdLineParser/CmdLineParser.cpp new file mode 100644 index 0000000..a1b88ae --- /dev/null +++ b/CristalDiskMark/source/diskspd2_0_15a/CmdLineParser/CmdLineParser.cpp @@ -0,0 +1,1120 @@ +/* + +DISKSPD + +Copyright(c) Microsoft Corporation +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#include "CmdLineParser.h" +#include "Common.h" +#include "..\XmlProfileParser\XmlProfileParser.h" +#include +#include +#include + +CmdLineParser::CmdLineParser() : + _dwBlockSize(64 * 1024), + _ulWriteRatio(0), + _hEventStarted(nullptr), + _hEventFinished(nullptr) +{ +} + + +CmdLineParser::~CmdLineParser() +{ +} + +// Get size in bytes from a string (it can end with K, M, G for KB, MB, GB and b for block) +bool CmdLineParser::_GetSizeInBytes(const char *pszSize, UINT64& ullSize) const +{ + bool fOk = true; + UINT64 ullResult = 0; + bool fLastCharacterFound = false; + for (char ch = *pszSize; fOk && (ch != '\0'); ch = *(++pszSize)) + { + if (fLastCharacterFound) + { + fOk = false; + } + else if ((ch >= '0') && (ch <= '9')) + { + if (ullResult <= (MAXUINT64 - (ch - '0')) / 10) + { + ullResult = ((ullResult * 10) + (ch - '0')); + } + else + { + fOk = false; + } + + } + else + { + ch = static_cast(toupper(ch)); + if ((ch == 'B') || (ch == 'K') || (ch == 'M') || (ch == 'G')) + { + UINT64 ullMultiplier = 0; + if (ch == 'B') { ullMultiplier = _dwBlockSize; } + else if (ch == 'K') { ullMultiplier = 1024; } + else if (ch == 'M') { ullMultiplier = 1024 * 1024; } + else if (ch == 'G') { ullMultiplier = 1024 * 1024 * 1024; } + + if (ullResult <= MAXUINT64 / ullMultiplier) + { + ullResult = ullResult * ullMultiplier; + fLastCharacterFound = true; + } + else + { + // overflow + fOk = false; + } + } + else + { + fOk = false; + fprintf(stderr, "Invalid size specifier '%c'. Valid ones are: K - KB, M - MB, G - GB, B - block\n", ch); + } + } + } + + if (fOk) + { + ullSize = ullResult; + } + return fOk; +} + +bool CmdLineParser::_GetRandomDataWriteBufferData(const string& sArg, UINT64& cb, string& sPath) +{ + bool fOk = true; + size_t iComma = sArg.find(','); + if (iComma == sArg.npos) + { + fOk = _GetSizeInBytes(sArg.c_str(), cb); + sPath = ""; + } + else + { + fOk = _GetSizeInBytes(sArg.substr(0, iComma).c_str(), cb); + sPath = sArg.substr(iComma + 1); + } + return fOk; +} + +void CmdLineParser::_DisplayUsageInfo(const char *pszFilename) const +{ + // ISSUE-REVIEW: this formats badly in the default 80 column command prompt + printf("\n"); + printf("Usage: %s [options] target1 [ target2 [ target3 ...] ]\n", pszFilename); + printf("version %s (%s)\n", DISKSPD_NUMERIC_VERSION_STRING, DISKSPD_DATE_VERSION_STRING); + printf("\n"); + printf("Available targets:\n"); + printf(" file_path\n"); + printf(" #\n"); + printf(" :\n"); + printf("\n"); + printf("Available options:\n"); + printf(" -? display usage information\n"); + printf(" -a#[,#[...]] advanced CPU affinity - affinitize threads to CPUs provided after -a in a round-robin\n"); + printf(" manner within current Processor Group (CPU count starts with 0); the same CPU can\n"); + printf(" be listed more than once and the number of CPUs can be different than the number\n"); + printf(" of files or threads\n"); + printf(" [default: round-robin within the current Processor Group starting at CPU 0,\n"); + printf(" use -n to disable default affinity]\n"); + printf(" -ag group affinity - affinitize threads in a round-robin manner across Processor\n"); + printf(" Groups, starting at group 0\n"); + printf(" -b[K|M|G] block size in bytes or KiB/MiB/GiB [default=64K]\n"); + printf(" -B[K|M|G|b] base target offset in bytes or KiB/MiB/GiB/blocks [default=0]\n"); + printf(" (offset from the beginning of the file)\n"); + printf(" -c[K|M|G|b] create files of the given size.\n"); + printf(" Size can be stated in bytes or KiB/MiB/GiB/blocks\n"); + printf(" -C cool down time - duration of the test after measurements finished [default=0s].\n"); + printf(" -D Capture IOPs statistics in intervals of ; these are per-thread\n"); + printf(" per-target: text output provides IOPs standard deviation, XML provides the full\n"); + printf(" IOPs time series in addition. [default=1000, 1 second].\n"); + printf(" -d duration (in seconds) to run test [default=10s]\n"); + printf(" -f[K|M|G|b] target size - use only the first bytes or KiB/MiB/GiB/blocks of the file/disk/partition,\n"); + printf(" for example to test only the first sectors of a disk\n"); + printf(" -fr open file with the FILE_FLAG_RANDOM_ACCESS hint\n"); + printf(" -fs open file with the FILE_FLAG_SEQUENTIAL_SCAN hint\n"); + printf(" -F total number of threads (conflicts with -t)\n"); + printf(" -g throughput per-thread per-target throttled to given bytes per millisecond\n"); + printf(" note that this can not be specified when using completion routines\n"); + printf(" [default inactive]\n"); + printf(" -h disable both software caching and hardware write caching. Equivalent to\n"); + printf(" FILE_FLAG_NO_BUFFERING and FILE_FLAG_WRITE_THROUGH\n"); + printf(" [default: caching is enabled, also see -S]\n"); + printf(" -i number of IOs per burst; see -j [default: inactive]\n"); + printf(" -j interval in between issuing IO bursts; see -i [default: inactive]\n"); + printf(" -I Set IO priority to . Available values are: 1-very low, 2-low, 3-normal (default)\n"); + printf(" -l Use large pages for IO buffers\n"); + printf(" -L measure latency statistics\n"); + printf(" -n disable default affinity (-a)\n"); + printf(" -o number of outstanding I/O requests per target per thread\n"); + printf(" (1=synchronous I/O, unless more than 1 thread is specified with -F)\n"); + printf(" [default=2]\n"); + printf(" -p start parallel sequential I/O operations with the same offset\n"); + printf(" (ignored if -r is specified, makes sense only with -o2 or greater)\n"); + printf(" -P enable printing a progress dot after each [default=65536]\n"); + printf(" completed I/O operations, counted separately by each thread \n"); + printf(" -r[K|M|G|b] random I/O aligned to in bytes/KiB/MiB/GiB/blocks (overrides -s)\n"); + printf(" -R output format. Default is text.\n"); + printf(" -s[i][K|M|G|b] sequential stride size, offset between subsequent I/O operations\n"); + printf(" [default access=non-interlocked sequential, default stride=block size]\n"); + printf(" In non-interlocked mode, threads do not coordinate, so the pattern of offsets\n"); + printf(" as seen by the target will not be truly sequential. Under -si the threads\n"); + printf(" manipulate a shared offset with InterlockedIncrement, which may reduce throughput,\n"); + printf(" but promotes a more sequential pattern.\n"); + printf(" (ignored if -r specified, -si conflicts with -T and -p)\n"); + printf(" -S disable software caching, equivalent to FILE_FLAG_NO_BUFFERING\n"); + printf(" [default: caching is enabled, also see -h]\n"); + printf(" -t number of threads per target (conflicts with -F)\n"); + printf(" -T[K|M|G|b] starting stride between I/O operations performed on the same target by different threads\n"); + printf(" [default=0] (starting offset = base file offset + (thread number * )\n"); + printf(" makes sense only with #threads > 1\n"); + printf(" -v verbose mode\n"); + printf(" -w percentage of write requests (-w and -w0 are equivalent and result in a read-only workload).\n"); + printf(" absence of this switch indicates 100%% reads\n"); + printf(" IMPORTANT: a write test will destroy existing data without a warning\n"); + printf(" -W warm up time - duration of the test before measurements start [default=5s]\n"); + printf(" -x use completion routines instead of I/O Completion Ports\n"); + printf(" -X use an XML file for configuring the workload. Cannot be used with other parameters.\n"); + printf(" -z[seed] set random seed [with no -z, seed=0; with plain -z, seed is based on system run time]\n"); + printf("\n"); + printf("Write buffers:\n"); + printf(" -Z zero buffers used for write tests\n"); + printf(" -Z[K|M|G|b] use a buffer filled with random data as a source for write operations.\n"); + printf(" -Z[K|M|G|b], use a buffer filled with data from as a source for write operations.\n"); + printf("\n"); + printf(" By default, the write buffers are filled with a repeating pattern (0, 1, 2, ..., 255, 0, 1, ...)\n"); + printf("\n"); + printf("Synchronization:\n"); + printf(" -ys signals event before starting the actual run (no warmup)\n"); + printf(" (creates a notification event if does not exist)\n"); + printf(" -yf signals event after the actual run finishes (no cooldown)\n"); + printf(" (creates a notification event if does not exist)\n"); + printf(" -yr waits on event before starting the run (including warmup)\n"); + printf(" (creates a notification event if does not exist)\n"); + printf(" -yp stops the run when event is set; CTRL+C is bound to this event\n"); + printf(" (creates a notification event if does not exist)\n"); + printf(" -ye sets event and quits\n"); + printf("\n"); + printf("Event Tracing:\n"); + printf(" -e Use query perf timer (qpc), cycle count, or system timer respectively.\n"); + printf(" [default = q, query perf timer (qpc)]\n"); + printf(" -ep use paged memory for the NT Kernel Logger [default=non-paged memory]\n"); + printf(" -ePROCESS process start & end\n"); + printf(" -eTHREAD thread start & end\n"); + printf(" -eIMAGE_LOAD image load\n"); + printf(" -eDISK_IO physical disk IO\n"); + printf(" -eMEMORY_PAGE_FAULTS all page faults\n"); + printf(" -eMEMORY_HARD_FAULTS hard faults only\n"); + printf(" -eNETWORK TCP/IP, UDP/IP send & receive\n"); + printf(" -eREGISTRY registry calls\n"); + printf("\n\n"); + printf("Examples:\n\n"); + printf("Create 8192KB file and run read test on it for 1 second:\n\n"); + printf(" %s -c8192K -d1 testfile.dat\n", pszFilename); + printf("\n"); + printf("Set block size to 4KB, create 2 threads per file, 32 overlapped (outstanding)\n"); + printf("I/O operations per thread, disable all caching mechanisms and run block-aligned random\n"); + printf("access read test lasting 10 seconds:\n\n"); + printf(" %s -b4K -t2 -r -o32 -d10 -h testfile.dat\n\n", pszFilename); + printf("Create two 1GB files, set block size to 4KB, create 2 threads per file, affinitize threads\n"); + printf("to CPUs 0 and 1 (each file will have threads affinitized to both CPUs) and run read test\n"); + printf("lasting 10 seconds:\n\n"); + printf(" %s -c1G -b4K -t2 -d10 -a0,1 testfile1.dat testfile2.dat\n", pszFilename); + + printf("\n"); +} + +bool CmdLineParser::_ParseETWParameter(const char *arg, Profile *pProfile) +{ + assert(nullptr != arg); + assert(0 != *arg); + + bool fOk = true; + pProfile->SetEtwEnabled(true); + if (*(arg + 1) != '\0') + { + const char *c = arg + 1; + if (*c == 'p') + { + pProfile->SetEtwUsePagedMemory(true); + } + else if (*c == 'q') + { + pProfile->SetEtwUsePerfTimer(true); + } + else if (*c == 's') + { + pProfile->SetEtwUseSystemTimer(true); //default + } + else if (*c == 'c') + { + pProfile->SetEtwUseCyclesCounter(true); + } + else if (strcmp(c, "PROCESS") == 0) //process start & end + { + pProfile->SetEtwProcess(true); + } + else if (strcmp(c, "THREAD") == 0) //thread start & end + { + pProfile->SetEtwThread(true); + } + else if (strcmp(c, "IMAGE_LOAD") == 0) //image load + { + pProfile->SetEtwImageLoad(true); + } + else if (strcmp(c, "DISK_IO") == 0) //physical disk IO + { + pProfile->SetEtwDiskIO(true); + } + else if (strcmp(c, "MEMORY_PAGE_FAULTS") == 0) //all page faults + { + pProfile->SetEtwMemoryPageFaults(true); + } + else if (strcmp(c, "MEMORY_HARD_FAULTS") == 0) //hard faults only + { + pProfile->SetEtwMemoryHardFaults(true); + } + else if (strcmp(c, "NETWORK") == 0) //tcpip send & receive + { + pProfile->SetEtwNetwork(true); + } + else if (strcmp(c, "REGISTRY") == 0) //registry calls + { + pProfile->SetEtwRegistry(true); + } + else + { + fOk = false; + } + } + else + { + fOk = false; + } + + return fOk; +} + +bool CmdLineParser::_ParseAffinity(const char *arg, TimeSpan *pTimeSpan) +{ + bool fOk = true; + + assert(nullptr != arg); + assert('\0' != *arg); + + const char *c = arg + 1; + if (*c == '\0') + { + // simple affinity (-a) is turned on by default, do nothing + return false; + } + + if (*c == 'g') + { + pTimeSpan->SetGroupAffinity(true); + return true; + } + + // TODO: will treat ,, as ,0, + // more complex affinity (-a#[,#[,#...]]) + int nCpu = 0; + while (fOk && (*c != '\0')) + { + if ((*c >= '0') && (*c <= '9')) + { + nCpu = 10 * nCpu + (*c - '0'); + } + else if (*c == ',') + { + pTimeSpan->AddAffinityAssignment(nCpu); + nCpu = 0; + } + else + { + fOk = false; + fprintf(stderr, "error parsing affinity (invalid character: %c)\n", *c); + } + c++; + } + if (fOk) + { + pTimeSpan->AddAffinityAssignment(nCpu); + } + + return fOk; +} + +bool CmdLineParser::_ReadParametersFromCmdLine(const int argc, const char *argv[], Profile *pProfile, struct Synchronization *synch) +{ + /* Process any command-line options */ + int nParamCnt = argc - 1; + const char** args = argv + 1; + + // create targets + vector vTargets; + int iFirstFile = -1; + for (int i = 1; i < argc; i++) + { + if (argv[i][0] != '-' && argv[i][0] != '/') + { + iFirstFile = i; + Target target; + target.SetPath(argv[i]); + vTargets.push_back(target); + } + } + + // find block size (other parameters may be stated in terms of blocks) + for (int x = 1; x < argc; ++x) + { + if ((nullptr != argv[x]) && (('-' == argv[x][0]) || ('/' == argv[x][0])) && ('b' == argv[x][1]) && ('\0' != argv[x][2])) + { + _dwBlockSize = 0; + UINT64 ullBlockSize; + if (_GetSizeInBytes(&argv[x][2], ullBlockSize)) + { + for (auto i = vTargets.begin(); i != vTargets.end(); i++) + { + // TODO: UINT64->DWORD + i->SetBlockSizeInBytes((DWORD)ullBlockSize); + } + } + else + { + fprintf(stderr, "Invalid block size passed to -b\n"); + exit(1); + } + _dwBlockSize = (DWORD)ullBlockSize; + break; + } + } + + TimeSpan timeSpan; + bool bExit = false; + while (nParamCnt) + { + const char* arg = *args; + bool fError = false; + + // check if it is a parameter or already path + if ('-' != *arg && '/' != *arg) + { + break; + } + + // skip '-' or '/' + ++arg; + + if ('\0' == *arg) + { + fprintf(stderr, "Invalid option\n"); + exit(1); + } + + switch (*arg) + { + case '?': + _DisplayUsageInfo(argv[0]); + exit(0); + + case 'A': /// CrystalDiskMark Process ID + extern DWORD pid; + pid = (DWORD)strtoul(arg + 1, NULL, 10); + break; + + case 'a': //affinity + //-a1,2,3,4 (assign threads to cpus 1,2,3,4 (round robin)) + if (!_ParseAffinity(arg, &timeSpan)) + { + fError = true; + } + break; + + case 'b': //block size + // nop - block size has been taken care of before the loop + break; + + case 'B': //base file offset (offset from the beggining of the file), cannot be used with 'random' + if (*(arg + 1) != '\0') + { + UINT64 cb; + if (_GetSizeInBytes(arg + 1, cb)) + { + for (auto i = vTargets.begin(); i != vTargets.end(); i++) + { + i->SetBaseFileOffsetInBytes(cb); + } + } + else + { + fprintf(stderr, "Invalid base file offset passed to -B\n"); + fError = true; + } + } + else + { + fError = true; + } + break; + + case 'c': //create file of the given size + if (*(arg + 1) != '\0') + { + UINT64 cb; + if (_GetSizeInBytes(arg + 1, cb)) + { + for (auto i = vTargets.begin(); i != vTargets.end(); i++) + { + i->SetFileSize(cb); + i->SetCreateFile(true); + } + } + else + { + fprintf(stderr, "Invalid file size passed to -c\n"); + fError = true; + } + } + else + { + fError = true; + } + break; + + case 'C': //cool down time + { + int c = atoi(arg + 1); + if (c >= 0) + { + timeSpan.SetCooldown(c); + } + else + { + fError = true; + } + } + break; + + case 'd': //duration + { + int x = atoi(arg + 1); + if (x > 0) + { + timeSpan.SetDuration(x); + } + else + { + fError = true; + } + } + break; + + case 'D': //standard deviation + { + timeSpan.SetCalculateIopsStdDev(true); + + int x = atoi(arg + 1); + if (x > 0) + { + timeSpan.SetIoBucketDurationInMilliseconds(x); + } + } + break; + + case 'e': //etw + if (!_ParseETWParameter(arg, pProfile)) + { + fError = true; + } + break; + + case 'f': + if ('r' == *(arg + 1)) + { + for (auto i = vTargets.begin(); i != vTargets.end(); i++) + { + i->SetRandomAccessHint(true); + } + } + else if ('s' == *(arg + 1)) + { + for (auto i = vTargets.begin(); i != vTargets.end(); i++) + { + i->SetSequentialScanHint(true); + } + } + else + { + if (*(arg + 1) != '\0') + { + UINT64 cb; + if (_GetSizeInBytes(arg + 1, cb)) + { + for (auto i = vTargets.begin(); i != vTargets.end(); i++) + { + i->SetMaxFileSize(cb); + } + } + else + { + fprintf(stderr, "Invalid max file size passed to -f\n"); + fError = true; + } + } + else + { + fError = true; + } + } + break; + + case 'F': //total number of threads + { + int c = atoi(arg + 1); + if (c > 0) + { + timeSpan.SetThreadCount(c); + } + else + { + fError = true; + } + } + break; + + case 'g': //throughput in bytes per millisecond + { + int c = atoi(arg + 1); + if (c > 0) + { + for (auto i = vTargets.begin(); i != vTargets.end(); i++) + { + i->SetThroughput(c); + } + } + else + { + fError = true; + } + } + break; + + case 'h': //disable both software and hardware caching + for (auto i = vTargets.begin(); i != vTargets.end(); i++) + { + i->SetDisableAllCache(true); + } + break; + + case 'i': //number of IOs to issue before think time + { + int c = atoi(arg + 1); + if (c > 0) + { + for (auto i = vTargets.begin(); i != vTargets.end(); i++) + { + i->SetBurstSize(c); + i->SetUseBurstSize(true); + } + } + else + { + fError = true; + } + } + break; + + case 'j': //time to wait between bursts of IOs + { + int c = atoi(arg + 1); + if (c > 0) + { + for (auto i = vTargets.begin(); i != vTargets.end(); i++) + { + i->SetThinkTime(c); + i->SetEnableThinkTime(true); + } + } + else + { + fError = true; + } + } + break; + + case 'I': //io priority + { + int x = atoi(arg + 1); + if (x > 0 && x < 4) + { + PRIORITY_HINT hint[] = { IoPriorityHintVeryLow, IoPriorityHintLow, IoPriorityHintNormal }; + for (auto i = vTargets.begin(); i != vTargets.end(); i++) + { + i->SetIOPriorityHint(hint[x - 1]); + } + } + else + { + fError = true; + } + } + break; + + case 'l': //large pages + for (auto i = vTargets.begin(); i != vTargets.end(); i++) + { + i->SetUseLargePages(true); + } + break; + + case 'L': //measure latency + timeSpan.SetMeasureLatency(true); + break; + + case 'n': //disable affinity (by default simple affinity is turned on) + timeSpan.SetDisableAffinity(true); + break; + + case 'o': //request count (1==synchronous) + { + int c = atoi(arg + 1); + if (c > 0) + { + for (auto i = vTargets.begin(); i != vTargets.end(); i++) + { + i->SetRequestCount(c); + } + } + else + { + fError = true; + } + } + break; + + case 'p': //start async IO operations with the same offset + //makes sense only for -o2 and greater + for (auto i = vTargets.begin(); i != vTargets.end(); i++) + { + i->SetUseParallelAsyncIO(true); + } + break; + + case 'P': //show progress every x IO operations + { + int c = atoi(arg + 1); + if (c < 1) + { + c = 65536; + } + pProfile->SetProgress(c); + } + break; + + case 'r': //random access + { + UINT64 cb = _dwBlockSize; + if (*(arg + 1) != '\0') + { + if (!_GetSizeInBytes(arg + 1, cb) || (cb == 0)) + { + fprintf(stderr, "Invalid alignment passed to -r\n"); + fError = true; + } + } + if (!fError) + { + for (auto i = vTargets.begin(); i != vTargets.end(); i++) + { + i->SetUseRandomAccessPattern(true); + i->SetBlockAlignmentInBytes(cb); + } + } + } + break; + + case 'R': //custom result parser + if (0 != *(arg + 1)) + { + const char* pszArg = arg + 1; + if (strcmp(pszArg, "xml") == 0) + { + pProfile->SetResultsFormat(ResultsFormat::Xml); + } + else if (strcmp(pszArg, "text") != 0) + { + fError = true; + fprintf(stderr, "Invalid results format: '%s'.\n", pszArg); + } + } + else + { + fError = true; + } + break; + + case 's': //stride size + { + int idx = 1; + + if ('i' == *(arg + idx)) + { + // do interlocked sequential mode + // ISSUE-REVIEW: this does nothing if -r is specified + // ISSUE-REVIEW: this does nothing if -p is specified + // ISSUE-REVIEW: this does nothing if we are single-threaded + for (auto i = vTargets.begin(); i != vTargets.end(); i++) + { + i->SetUseInterlockedSequential(true); + } + + idx++; + } + + if (*(arg + idx) != '\0') + { + UINT64 cb; + if (_GetSizeInBytes(arg + idx, cb)) + { + for (auto i = vTargets.begin(); i != vTargets.end(); i++) + { + i->SetBlockAlignmentInBytes(cb); + } + } + else + { + fprintf(stderr, "Invalid stride size passed to -s\n"); + fError = true; + } + } + } + break; + + case 'S': //disable OS caching (software buffering) + //IMPORTANT: File access must begin at byte offsets within the file that are integer multiples of the volume's sector size. + // File access must be for numbers of bytes that are integer multiples of the volume's sector size. For example, if the sector + // size is 512 bytes, an application can request reads and writes of 512, 1024, or 2048 bytes, but not of 335, 981, or 7171 bytes. + // Buffer addresses for read and write operations should be sector aligned (aligned on addresses in memory that are integer + // multiples of the volume's sector size). Depending on the disk, this requirement may not be enforced. + for (auto i = vTargets.begin(); i != vTargets.end(); i++) + { + i->SetDisableOSCache(true); + } + break; + + case 't': //number of threads per file + { + int c = atoi(arg + 1); + if (c > 0) + { + for (auto i = vTargets.begin(); i != vTargets.end(); i++) + { + i->SetThreadsPerFile(c); + } + } + else + { + fError = true; + } + } + break; + + case 'T': //offsets between threads reading the same file + { + UINT64 cb; + if (_GetSizeInBytes(arg + 1, cb) && (cb > 0)) + { + for (auto i = vTargets.begin(); i != vTargets.end(); i++) + { + i->SetThreadStrideInBytes(cb); + } + } + else + { + fprintf(stderr, "Invalid offset passed to -T\n"); + fError = true; + } + } + break; + + case 'v': //verbose mode + pProfile->SetVerbose(true); + break; + + case 'w': //write test [default=read] + { + int c = -1; + if (*(arg + 1) == '\0') + { + c = _ulWriteRatio; + } + else + { + c = atoi(arg + 1); + if (c < 0 || c > 100) + { + c = -1; + fError = true; + } + } + if (c != -1) + { + for (auto i = vTargets.begin(); i != vTargets.end(); i++) + { + i->SetWriteRatio(c); + } + } + } + break; + + case 'W': //warm up time + { + int c = atoi(arg + 1); + if (c >= 0) + { + timeSpan.SetWarmup(c); + } + else + { + fError = true; + } + } + break; + + case 'x': //completion routines + timeSpan.SetCompletionRoutines(true); + break; + + case 'y': //external synchronization + switch (*(arg + 1)) + { + + case 's': + _hEventStarted = CreateEvent(NULL, TRUE, FALSE, arg + 2); + if (NULL == _hEventStarted) + { + fprintf(stderr, "Error creating/opening start notification event: '%s'\n", arg + 2); + exit(1); // TODO: this class shouldn't terminate the process + } + break; + + case 'f': + _hEventFinished = CreateEvent(NULL, TRUE, FALSE, arg + 2); + if (NULL == _hEventFinished) + { + fprintf(stderr, "Error creating/opening finish notification event: '%s'\n", arg + 2); + exit(1); // TODO: this class shouldn't terminate the process + } + break; + + case 'r': + synch->hStartEvent = CreateEvent(NULL, TRUE, FALSE, arg + 2); + if (NULL == synch->hStartEvent) + { + fprintf(stderr, "Error creating/opening wait-for-start event: '%s'\n", arg + 2); + exit(1); // TODO: this class shouldn't terminate the process + } + break; + + case 'p': + synch->hStopEvent = CreateEvent(NULL, TRUE, FALSE, arg + 2); + if (NULL == synch->hStopEvent) + { + fprintf(stderr, "Error creating/opening force-stop event: '%s'\n", arg + 2); + exit(1); // TODO: this class shouldn't terminate the process + } + break; + + case 'e': + { + HANDLE hEvent = OpenEvent(EVENT_MODIFY_STATE, FALSE, arg + 2); + if (NULL == hEvent) + { + fprintf(stderr, "Error opening event '%s'\n", arg + 2); + exit(1); // TODO: this class shouldn't terminate the process + } + if (!SetEvent(hEvent)) + { + fprintf(stderr, "Error setting event '%s'\n", arg + 2); + exit(1); // TODO: this class shouldn't terminate the process + } + CloseHandle(hEvent); + printf("Succesfully set event: '%s'\n", arg + 2); + bExit = true; + break; + } + + default: + fError = true; + } + + case 'z': //random seed + if (*(arg + 1) == '\0') + { + /// GetTickCount64 -> GetTickCount + timeSpan.SetRandSeed(GetTickCount()); + } + else + { + int c = atoi(arg + 1); + if (c >= 0) + { + timeSpan.SetRandSeed(c); + } + else + { + fError = true; + } + } + break; + + case 'Z': //zero write buffers + if (*(arg + 1) == '\0') + { + for (auto i = vTargets.begin(); i != vTargets.end(); i++) + { + i->SetZeroWriteBuffers(true); + } + } + else + { + UINT64 cb = 0; + string sPath; + if (_GetRandomDataWriteBufferData(string(arg + 1), cb, sPath) && (cb > 0)) + { + for (auto i = vTargets.begin(); i != vTargets.end(); i++) + { + i->SetRandomDataWriteBufferSize(cb); + i->SetRandomDataWriteBufferSourcePath(sPath); + } + } + else + { + fprintf(stderr, "Invalid size passed to -Z\n"); + fError = true; + } + } + break; + + default: + fprintf(stderr, "Invalid option: '%s'\n", arg); + exit(1); // TODO: this class shouldn't terminate the process + } + + if (fError) + { + fprintf(stderr, "Incorrectly provided option: '%s'\n", arg); + exit(1); // TODO: this class shouldn't terminate the process + } + + --nParamCnt; + ++args; + } + + // + // exit if a user specified an action which was already satisfied and doesn't require running test + // + if (bExit) + { + printf("Now exiting...\n"); + exit(1); // TODO: this class shouldn't terminate the process + } + + if (vTargets.size() < 1) + { + fprintf(stderr, "You need to provide at least one filename\n"); + return false; + } + + for (auto i = vTargets.begin(); i != vTargets.end(); i++) + { + timeSpan.AddTarget(*i); + } + pProfile->AddTimeSpan(timeSpan); + + return true; +} + +bool CmdLineParser::_ReadParametersFromXmlFile(const char *pszPath, Profile *pProfile) +{ + XmlProfileParser parser; + return parser.ParseFile(pszPath, pProfile); +} + +bool CmdLineParser::ParseCmdLine(const int argc, const char *argv[], Profile *pProfile, struct Synchronization *synch) +{ + assert(nullptr != argv); + assert(nullptr != pProfile); + assert(NULL != synch); + + if (argc < 2) + { + _DisplayUsageInfo(argv[0]); + return false; + } + + string sCmdLine; + for (int i = 0; i < argc - 1; i++) + { + sCmdLine += argv[i]; + sCmdLine += ' '; + } + if (argc > 0) + { + sCmdLine += argv[argc - 1]; + } + pProfile->SetCmdLine(sCmdLine); + + //check if parameters should be read from an xml file + bool fOk = true; + bool fCmdLine; + + if (argc == 2 && (argv[1][0] == '-' || argv[1][0] == '/') && argv[1][1] == 'X' && argv[1][2] != '\0') + { + fOk = _ReadParametersFromXmlFile(argv[1] + 2, pProfile); + fCmdLine = false; + } + else + { + fOk = _ReadParametersFromCmdLine(argc, argv, pProfile, synch); + fCmdLine = true; + } + + // check additional restrictions and conditions on the passed parameters. + // note that on the cmdline, all targets receive the same parameters so + // that their mutual consistency only needs to be checked once. + if (fOk) + { + fOk = pProfile->Validate(fCmdLine); + } + + return fOk; +} \ No newline at end of file diff --git a/CristalDiskMark/source/diskspd2_0_15a/CmdLineParser/CmdLineParser.h b/CristalDiskMark/source/diskspd2_0_15a/CmdLineParser/CmdLineParser.h new file mode 100644 index 0000000..1c7f593 --- /dev/null +++ b/CristalDiskMark/source/diskspd2_0_15a/CmdLineParser/CmdLineParser.h @@ -0,0 +1,64 @@ +/* + +DISKSPD + +Copyright(c) Microsoft Corporation +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#pragma once +#include "Common.h" + +namespace UnitTests { class CmdLineParserUnitTests; } + +class CmdLineParser +{ +public: + CmdLineParser(); + ~CmdLineParser(); + + bool ParseCmdLine(const int argc, const char *argv[], Profile *pProfile, struct Synchronization *synch); + +private: + bool _ReadParametersFromCmdLine(const int argc, const char *argv[], Profile *pProfile, struct Synchronization *synch); + bool _ReadParametersFromXmlFile(const char *pszPath, Profile *pProfile); + + bool _ParseETWParameter(const char *arg, Profile *pProfile); + bool _ParseAffinity(const char *arg, TimeSpan *pTimeSpan); + + void _DisplayUsageInfo(const char *pszFilename) const; + bool _GetSizeInBytes(const char *pszSize, UINT64& ullSize) const; + bool _GetRandomDataWriteBufferData(const string& sArg, UINT64& cb, string& sPath); + + // variables that used to be global + DWORD _dwBlockSize; // block size; other parameters may be stated in blocks + // so the block size is needed to process them + + UINT32 _ulWriteRatio; // default percentage of write requests + + HANDLE _hEventStarted; // event signalled to notify that the actual (measured) test is to be started + HANDLE _hEventFinished; // event signalled to notify that the actual test has finished + + friend class UnitTests::CmdLineParserUnitTests; +}; diff --git a/CristalDiskMark/source/diskspd2_0_15a/CmdRequestCreator/CmdRequestCreator.cpp b/CristalDiskMark/source/diskspd2_0_15a/CmdRequestCreator/CmdRequestCreator.cpp new file mode 100644 index 0000000..65aac96 --- /dev/null +++ b/CristalDiskMark/source/diskspd2_0_15a/CmdRequestCreator/CmdRequestCreator.cpp @@ -0,0 +1,219 @@ +/* + +DISKSPD + +Copyright(c) Microsoft Corporation +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +// CmdRequestCreator.cpp : Defines the entry point for the console application. +// + +#include "CmdRequestCreator.h" +#include +#include +#include +#include "common.h" +#include "errors.h" +#include "..\CmdLineParser\CmdLineParser.h" +#include "..\XmlProfileParser\XmlProfileParser.h" +#include "..\IORequestGenerator\IORequestGenerator.h" +#include "..\ResultParser\ResultParser.h" +#include "..\XmlResultParser\XmlResultParser.h" + +/*****************************************************************************/ +// global variables +static HANDLE g_hAbortEvent = NULL; // handle to the 'abort' event + // it allows stopping I/O Request Generator in the middle of its work + // the results of its work will be passed to the Results Parser +static HANDLE g_hEventStarted = NULL; // event signalled to notify that the actual (measured) test is to be started +static HANDLE g_hEventFinished = NULL; // event signalled to notify that the actual test has finished + +/*****************************************************************************/ +// wrapper for printf. printf cannot be used directly, because IORequestGenerator.dll +// may be consumed by gui app which doesn't have stdout +void WINAPI PrintOut(const char *format, va_list args) +{ + vprintf(format, args); +} + +/*****************************************************************************/ +// wrapper for fprintf. fprintf cannot be used directly, because IORequestGenerator.dll +// may be consumed by gui app which doesn't have stdout +void WINAPI PrintError(const char *format, va_list args) +{ + vfprintf(stderr, format, args); +} + +/*****************************************************************************/ +BOOL WINAPI ctrlCRoutine(DWORD dwCtrlType) +{ + if( CTRL_C_EVENT == dwCtrlType ) + { + printf("\n*** Interrupted by Ctrl-C. Stopping I/O Request Generator. ***\n"); + if( !SetEvent(g_hAbortEvent) ) + { + fprintf(stderr, "Warning: Setting abort event failed (error code: %u)\n", GetLastError()); + } + SetConsoleCtrlHandler(ctrlCRoutine, FALSE); + + //indicate that the signal has been handled + return TRUE; + } + else + { + return FALSE; + } +} + +/*****************************************************************************/ +void TestStarted() +{ + if( (NULL != g_hEventStarted) && !SetEvent(g_hEventStarted) ) + { + fprintf(stderr, "Warning: Setting test start notification event failed (error code: %u)\n", GetLastError()); + } +} + +/*****************************************************************************/ +void TestFinished() +{ + if( (NULL != g_hEventFinished) && !SetEvent(g_hEventFinished) ) + { + fprintf(stderr, "Warning: Setting test finish notification event failed (error code: %u)\n", GetLastError()); + } +} + +DWORD pid = 0; + +/*****************************************************************************/ +int __cdecl main(int argc, const char* argv[]) +{ + /// for CrystalDiskMark + int totalScore = 0; + double averageLatency = 0.0; + + // + // parse cmd line parameters + // + struct Synchronization synch; //sychronization structure + synch.ulStructSize = sizeof(synch); + synch.hStopEvent = NULL; + synch.hStartEvent = NULL; + + CmdLineParser cmdLineParser; + Profile profile; + if (!cmdLineParser.ParseCmdLine(argc, argv, &profile, &synch)) + { + return ERROR_PARSE_CMD_LINE; + } + + synch.pfnCallbackTestStarted = TestStarted; + synch.pfnCallbackTestFinished = TestFinished; + + // + // create abort event if stop event is not explicitly provided by the user (otherwise use the stop event) + // + + if (NULL == synch.hStopEvent) + { + synch.hStopEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + if( NULL == synch.hStopEvent ) + { + fprintf(stderr, "Unable to create an abort event for CTRL+C\n"); + //FUTURE EXTENSION: change error code + return 5; + } + } + g_hAbortEvent = synch.hStopEvent; // set abort event to either stop event provided by user or the just created event + + // + // capture ctrl+c + // + if( !SetConsoleCtrlHandler(ctrlCRoutine, TRUE) ) + { + fprintf(stderr, "Unable to set CTRL+C routine\n"); + //FUTURE EXTENSION: change error code + return 6; + } + + // + // call IO request generator + // + ResultParser resultParser; + XmlResultParser xmlResultParser; + IResultParser *pResultParser = nullptr; + if (profile.GetResultsFormat() == ResultsFormat::Xml) + { + pResultParser = &xmlResultParser; + } + else + { + pResultParser = &resultParser; + } + + IORequestGenerator ioGenerator; + if (!ioGenerator.GenerateRequests(profile, *pResultParser, (PRINTF)PrintOut, (PRINTF)PrintError, (PRINTF)PrintOut, &synch, &totalScore, &averageLatency)) + { + fprintf(stderr, "Error generating I/O requests\n"); + return 7; + } + + if( NULL != synch.hStartEvent ) + { + CloseHandle(synch.hStartEvent); + } + if( NULL != synch.hStopEvent ) + { + CloseHandle(synch.hStopEvent); + } + if( g_hEventStarted ) + { + CloseHandle(g_hEventStarted); + } + if( NULL != g_hEventFinished ) + { + CloseHandle(g_hEventFinished); + } + + /// for CrystalDiskMark + CHAR name[32]; + snprintf(name, 32, "CrystalDiskMark%08X", pid); + auto size = 8; + + HANDLE hSharedMemory = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, NULL, size, name); + if (hSharedMemory != NULL) + { + auto pMemory = (double*)MapViewOfFile(hSharedMemory, FILE_MAP_ALL_ACCESS, NULL, NULL, size); + if (pMemory != NULL) + { + *pMemory = averageLatency; + UnmapViewOfFile(pMemory); + CloseHandle(hSharedMemory); + } + } + // fprintf(stderr, "%f", averageLatency); + + return totalScore; +} \ No newline at end of file diff --git a/CristalDiskMark/source/diskspd2_0_15a/CmdRequestCreator/CmdRequestCreator.h b/CristalDiskMark/source/diskspd2_0_15a/CmdRequestCreator/CmdRequestCreator.h new file mode 100644 index 0000000..f8d2937 --- /dev/null +++ b/CristalDiskMark/source/diskspd2_0_15a/CmdRequestCreator/CmdRequestCreator.h @@ -0,0 +1,38 @@ +/* + +DISKSPD + +Copyright(c) Microsoft Corporation +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + +#pragma once + +#include +#include \ No newline at end of file diff --git a/CristalDiskMark/source/diskspd2_0_15a/CmdRequestCreator/errors.h b/CristalDiskMark/source/diskspd2_0_15a/CmdRequestCreator/errors.h new file mode 100644 index 0000000..f11b5ca --- /dev/null +++ b/CristalDiskMark/source/diskspd2_0_15a/CmdRequestCreator/errors.h @@ -0,0 +1,38 @@ +/* + +DISKSPD + +Copyright(c) Microsoft Corporation +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#ifndef __DISKSPD_ERRORS_H +#define __DISKSPD_ERRORS_H + +#define ERROR_LOAD_LIBRARY 1 //error during LoadLibrary call +#define ERROR_GET_PROC_ADDRESS 2 //error during GetProcAddress +#define ERROR_PARSE_CMD_LINE 3 //error parsing cmd line parameters +#define ERROR_WAIT_FOR_START_SIGNAL 4 //error waiting for a signal to start work + +#endif \ No newline at end of file diff --git a/CristalDiskMark/source/diskspd2_0_15a/Common/Common.cpp b/CristalDiskMark/source/diskspd2_0_15a/Common/Common.cpp new file mode 100644 index 0000000..2d0c2fc --- /dev/null +++ b/CristalDiskMark/source/diskspd2_0_15a/Common/Common.cpp @@ -0,0 +1,685 @@ +/* + +DISKSPD + +Copyright(c) Microsoft Corporation +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#include "Common.h" + +UINT64 PerfTimer::GetTime() +{ + LARGE_INTEGER li; + QueryPerformanceCounter(&li); + return li.QuadPart; +} + +UINT64 PerfTimer::_GetPerfTimerFreq() +{ + LARGE_INTEGER li; + QueryPerformanceFrequency(&li); + return li.QuadPart; +} + +const UINT64 PerfTimer::TIMER_FREQ = _GetPerfTimerFreq(); + +double PerfTimer::PerfTimeToMicroseconds(const double perfTime) +{ + return perfTime / (TIMER_FREQ / 1000000.0); +} + +double PerfTimer::PerfTimeToMilliseconds(const double perfTime) +{ + return PerfTimeToMicroseconds(perfTime) / 1000; +} + +double PerfTimer::PerfTimeToSeconds(const double perfTime) +{ + return PerfTimeToMilliseconds(perfTime) / 1000; +} + +double PerfTimer::PerfTimeToMicroseconds(const UINT64 perfTime) +{ + return PerfTimeToMicroseconds(static_cast(perfTime)); +} + +double PerfTimer::PerfTimeToMilliseconds(const UINT64 perfTime) +{ + return PerfTimeToMilliseconds(static_cast(perfTime)); +} + +double PerfTimer::PerfTimeToSeconds(const UINT64 perfTime) +{ + return PerfTimeToSeconds(static_cast(perfTime)); +} + +UINT64 PerfTimer::MicrosecondsToPerfTime(const double microseconds) +{ + return static_cast(TIMER_FREQ * (microseconds / 1000000.0)); +} + +UINT64 PerfTimer::MillisecondsToPerfTime(const double milliseconds) +{ + return static_cast(TIMER_FREQ * (milliseconds / 1000.0)); +} + +UINT64 PerfTimer::SecondsToPerfTime(const double seconds) +{ + return static_cast(TIMER_FREQ * seconds); +} + +string Util::DoubleToStringHelper(const double d) +{ + char szFloatBuffer[100]; + sprintf_s(szFloatBuffer, _countof(szFloatBuffer), "%10.3lf", d); + + return string(szFloatBuffer); +} + +string Target::GetXml() const +{ + char buffer[4096]; + string sXml("\n"); + sXml += "" + _sPath + "\n"; + + sprintf_s(buffer, _countof(buffer), "%u\n", _dwBlockSize); + sXml += buffer; + + sprintf_s(buffer, _countof(buffer), "%I64u\n", _ullBaseFileOffset); + sXml += buffer; + + sXml += _fSequentialScanHint ? "true\n" : "false\n"; + sXml += _fRandomAccessHint ? "true\n" : "false\n"; + sXml += _fUseLargePages ? "true\n" : "false\n"; + sXml += _fDisableAllCache ? "true\n" : "false\n"; + // normalize cache controls - disabling the OS cache is included if all caches are disabled, + // so specifying it twice is not neccesary (this generates a warning on the cmdline) + if (!_fDisableAllCache) + { + sXml += _fDisableOSCache ? "true\n" : "false\n"; + } + + sXml += "\n"; + if (_fZeroWriteBuffers) + { + sXml += "zero\n"; + } + else if (_cbRandomDataWriteBuffer == 0) + { + sXml += "sequential\n"; + } + else + { + sXml += "random\n"; + sXml += "\n"; + sprintf_s(buffer, _countof(buffer), "%I64u\n", _cbRandomDataWriteBuffer); + sXml += buffer; + if (_sRandomDataWriteBufferSourcePath != "") + { + sXml += "" + _sRandomDataWriteBufferSourcePath + "\n"; + } + sXml += "\n"; + } + sXml += "\n"; + + sXml += _fParallelAsyncIO ? "true\n" : "false\n"; + + if (_fUseBurstSize) + { + sprintf_s(buffer, _countof(buffer), "%u\n", _dwBurstSize); + sXml += buffer; + } + + if (_fThinkTime) + { + sprintf_s(buffer, _countof(buffer), "%u\n", _dwThinkTime); + sXml += buffer; + } + + if (_fCreateFile) + { + sprintf_s(buffer, _countof(buffer), "%I64u\n", _ullFileSize); + sXml += buffer; + } + + // If XML contains , is ignored + if (_fUseRandomAccessPattern) + { + sprintf_s(buffer, _countof(buffer), "%I64u\n", GetBlockAlignmentInBytes()); + sXml += buffer; + } + else + { + sprintf_s(buffer, _countof(buffer), "%I64u\n", GetBlockAlignmentInBytes()); + sXml += buffer; + + sXml += _fInterlockedSequential ? + "true\n" : + "false\n"; + } + + sprintf_s(buffer, _countof(buffer), "%I64u\n", _ullThreadStride); + sXml += buffer; + + sprintf_s(buffer, _countof(buffer), "%I64u\n", _ullMaxFileSize); + sXml += buffer; + + sprintf_s(buffer, _countof(buffer), "%u\n", _dwRequestCount); + sXml += buffer; + + sprintf_s(buffer, _countof(buffer), "%u\n", _ulWriteRatio); + sXml += buffer; + + sprintf_s(buffer, _countof(buffer), "%u\n", _dwThroughputBytesPerMillisecond); + sXml += buffer; + + sprintf_s(buffer, _countof(buffer), "%u\n", _dwThreadsPerFile); + sXml += buffer; + + if (_ioPriorityHint == IoPriorityHintVeryLow) + { + sXml += "1\n"; + } + else if (_ioPriorityHint == IoPriorityHintLow) + { + sXml += "2\n"; + } + else if (_ioPriorityHint == IoPriorityHintNormal) + { + sXml += "3\n"; + } + else + { + sXml += "* UNSUPPORTED *\n"; + } + + sXml += "\n"; + + + return sXml; +} + +bool Target::_FillRandomDataWriteBuffer() +{ + assert(_pRandomDataWriteBuffer != nullptr); + bool fOk = true; + size_t cb = static_cast(GetRandomDataWriteBufferSize()); + if (GetRandomDataWriteBufferSourcePath() == "") + { + // fill buffer with random data + for (size_t i = 0; i < cb; i++) + { + _pRandomDataWriteBuffer[i] = (rand() % 256); + } + } + else + { + // fill buffer from file + HANDLE hFile = CreateFile(GetRandomDataWriteBufferSourcePath().c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, 0, nullptr); + if (hFile != INVALID_HANDLE_VALUE) + { + UINT64 cbLeftToRead = GetRandomDataWriteBufferSize(); + BYTE *pBuffer = _pRandomDataWriteBuffer; + bool fReadSuccess = true; + while (fReadSuccess && cbLeftToRead > 0) + { + DWORD cbToRead = static_cast(min(64 * 1024, cbLeftToRead)); + DWORD cbRead; + fReadSuccess = ((ReadFile(hFile, pBuffer, cbToRead, &cbRead, nullptr) == TRUE) && (cbRead > 0)); + pBuffer += cbRead; + } + + // if the file is smaller than the buffer, repeat its content + BYTE *pSource = _pRandomDataWriteBuffer; + const BYTE *pPastEnd = pSource + GetRandomDataWriteBufferSize(); + while (pBuffer < pPastEnd) + { + *pBuffer++ = *pSource++; + } + CloseHandle(hFile); + } + else + { + fOk = false; + // TODO: print error message? + } + } + return fOk; +} + +bool Target::AllocateAndFillRandomDataWriteBuffer() +{ + assert(_pRandomDataWriteBuffer == nullptr); + bool fOk = true; + size_t cb = static_cast(GetRandomDataWriteBufferSize()); + assert(cb > 0); + + // TODO: make sure the size if <= max value for size_t + /// CrystalDiskMark 4 does not support Large Page + if (false && GetUseLargePages()) + { + /// size_t cbMinLargePage = GetLargePageMinimum(); + /// size_t cbRoundedSize = (cb + cbMinLargePage - 1) & ~(cbMinLargePage - 1); + /// _pRandomDataWriteBuffer = (BYTE *)VirtualAlloc(nullptr, cbRoundedSize, MEM_COMMIT | MEM_RESERVE | MEM_LARGE_PAGES, PAGE_EXECUTE_READWRITE); + } + else + { + _pRandomDataWriteBuffer = (BYTE *)VirtualAlloc(nullptr, cb, MEM_COMMIT, PAGE_READWRITE); + } + + fOk = (_pRandomDataWriteBuffer != nullptr); + if (fOk) + { + fOk = _FillRandomDataWriteBuffer(); + } + return fOk; +} + +void Target::FreeRandomDataWriteBuffer() +{ + if (nullptr != _pRandomDataWriteBuffer) + { + VirtualFree(_pRandomDataWriteBuffer, 0, MEM_RELEASE); + _pRandomDataWriteBuffer = nullptr; + } +} + +BYTE* Target::GetRandomDataWriteBuffer() +{ + size_t cbBuffer = static_cast(GetRandomDataWriteBufferSize()); + size_t cbBlock = GetBlockSizeInBytes(); + + // leave enough bytes in the buffer for one block + size_t randomOffset = rand() % (cbBuffer - (cbBlock - 1)); + + bool fUnbufferedIO = (GetDisableOSCache() || GetDisableAllCache()); + if (fUnbufferedIO) + { + // for unbuffered IO, offset in the buffer needs to be DWORD-aligned + const size_t cbAlignment = 4; + randomOffset -= (randomOffset % cbAlignment); + } + + BYTE *pBuffer = reinterpret_cast(reinterpret_cast(_pRandomDataWriteBuffer)+randomOffset); + + // unbuffered IO needs aligned addresses + assert(!fUnbufferedIO || (reinterpret_cast(pBuffer) % 4 == 0)); + + assert(pBuffer >= _pRandomDataWriteBuffer); + assert(pBuffer <= _pRandomDataWriteBuffer + GetRandomDataWriteBufferSize() - GetBlockSizeInBytes()); + + return pBuffer; +} + +string TimeSpan::GetXml() const +{ + string sXml("\n"); + char buffer[4096]; + + sXml += _fCompletionRoutines ? "true\n" : "false\n"; + sXml += _fMeasureLatency ? "true\n" : "false\n"; + sXml += _fCalculateIopsStdDev ? "true\n" : "false\n"; + sXml += _fDisableAffinity ? "true\n" : "false\n"; + sXml += _fGroupAffinity ? "true\n" : "false\n"; + + sprintf_s(buffer, _countof(buffer), "%u\n", _ulDuration); + sXml += buffer; + + sprintf_s(buffer, _countof(buffer), "%u\n", _ulWarmUp); + sXml += buffer; + + sprintf_s(buffer, _countof(buffer), "%u\n", _ulCoolDown); + sXml += buffer; + + sprintf_s(buffer, _countof(buffer), "%u\n", _dwThreadCount); + sXml += buffer; + + sprintf_s(buffer, _countof(buffer), "%u\n", _ulIoBucketDurationInMilliseconds); + sXml += buffer; + + sprintf_s(buffer, _countof(buffer), "%u\n", _ulRandSeed); + sXml += buffer; + + if (_vAffinity.size() > 0) + { + sXml += "\n"; + for (auto a : _vAffinity) + { + sprintf_s(buffer, _countof(buffer), "%u\n", a); + sXml += buffer; + } + sXml += "\n"; + } + + sXml += "\n"; + for (const auto& target : _vTargets) + { + sXml += target.GetXml(); + } + sXml += "\n"; + sXml += "\n"; + return sXml; +} + +void TimeSpan::MarkFilesAsPrecreated(const vector vFiles) +{ + for (auto sFile : vFiles) + { + for (auto pTarget = _vTargets.begin(); pTarget != _vTargets.end(); pTarget++) + { + if (sFile == pTarget->GetPath()) + { + pTarget->SetPrecreated(true); + } + } + } +} + +string Profile::GetXml() const +{ + string sXml("\n"); + char buffer[4096]; + + sprintf_s(buffer, _countof(buffer), "%u\n", _dwProgress); + sXml += buffer; + + if (_resultsFormat == ResultsFormat::Text) + { + sXml += "text\n"; + } + else if (_resultsFormat == ResultsFormat::Xml) + { + sXml += "xml\n"; + } + else + { + sXml += "* UNSUPPORTED *\n"; + } + + sXml += _fVerbose ? "true\n" : "false\n"; + if (_precreateFiles == PrecreateFiles::UseMaxSize) + { + sXml += "UseMaxSize\n"; + } + else if (_precreateFiles == PrecreateFiles::OnlyFilesWithConstantSizes) + { + sXml += "CreateOnlyFilesWithConstantSizes\n"; + } + else if (_precreateFiles == PrecreateFiles::OnlyFilesWithConstantOrZeroSizes) + { + sXml += "CreateOnlyFilesWithConstantOrZeroSizes\n"; + } + + if (_fEtwEnabled) + { + sXml += _fEtwProcess ? "true\n" : "false\n"; + sXml += _fEtwThread ? "true\n" : "false\n"; + sXml += _fEtwImageLoad ? "true\n" : "false\n"; + sXml += _fEtwDiskIO ? "true\n" : "false\n"; + sXml += _fEtwMemoryPageFaults ? "true\n" : "false\n"; + sXml += _fEtwMemoryHardFaults ? "true\n" : "false\n"; + sXml += _fEtwNetwork ? "true\n" : "false\n"; + sXml += _fEtwRegistry ? "true\n" : "false\n"; + sXml += _fEtwUsePagedMemory ? "true\n" : "false\n"; + sXml += _fEtwUsePerfTimer ? "true\n" : "false\n"; + sXml += _fEtwUseSystemTimer ? "true\n" : "false\n"; + sXml += _fEtwUseCyclesCounter ? "true\n" : "false\n"; + } + + sXml += "\n"; + for (const auto& timespan : _vTimeSpans) + { + sXml += timespan.GetXml(); + } + sXml += "\n"; + sXml += "\n"; + return sXml; +} + +void Profile::MarkFilesAsPrecreated(const vector vFiles) +{ + for (auto pTimeSpan = _vTimeSpans.begin(); pTimeSpan != _vTimeSpans.end(); pTimeSpan++) + { + pTimeSpan->MarkFilesAsPrecreated(vFiles); + } +} + +bool Profile::Validate(bool fSingleSpec) const +{ + bool fOk = true; + for (const auto& timeSpan : GetTimeSpans()) + { + if (timeSpan.GetDisableAffinity() && timeSpan.GetAffinityAssignments().size() > 0) + { + fprintf(stderr, "ERROR: -n and -a parameters cannot be used together\n"); + fOk = false; + } + + for (const auto& target : timeSpan.GetTargets()) + { + const bool targetHasMultipleThreads = (timeSpan.GetThreadCount() > 1) || (target.GetThreadsPerFile() > 1); + + if (timeSpan.GetThreadCount() > 0 && target.GetThreadsPerFile() > 1) + { + fprintf(stderr, "ERROR: -F and -t parameters cannot be used together\n"); + fOk = false; + } + + if (target.GetDisableAllCache() && target.GetDisableOSCache()) + { + fprintf(stderr, "WARNING: -S is included in the effect of -h, specifying both is not required\n"); + } + + if (target.GetThroughputInBytesPerMillisecond() > 0 && timeSpan.GetCompletionRoutines()) + { + fprintf(stderr, "ERROR: -g throughput control cannot be used with -x completion routines\n"); + fOk = false; + } + + // If burst size is specified think time must be specified and If think time is specified burst size should be non zero + if ((target.GetThinkTime() == 0 && target.GetBurstSize() > 0) || (target.GetThinkTime() > 0 && target.GetBurstSize() == 0)) + { + fprintf(stderr, "ERROR: need to specify -j with -i\n"); + fOk = false; + } + + // FIXME: we can no longer do this check, because the target no longer + // contains a property that uniquely identifies the case where "-s" or + // was passed. +#if 0 + if (target.GetUseRandomAccessPattern() && target.GetEnableCustomStrideSize()) + { + fprintf(stderr, "WARNING: -s is ignored if -r is provided\n"); + } +#endif + if (target.GetUseRandomAccessPattern()) + { + if (target.GetThreadStrideInBytes() > 0) + { + fprintf(stderr, "ERROR: -T conflicts with -r\n"); + fOk = false; + // although ullThreadStride==0 is a valid value, it's interpreted as "not provided" for this warning + } + + if (target.GetUseInterlockedSequential()) + { + fprintf(stderr, "ERROR: -si conflicts with -r\n"); + fOk = false; + } + + if (target.GetUseParallelAsyncIO()) + { + fprintf(stderr, "ERROR: -p conflicts with -r\n"); + fOk = false; + } + } + else + { + if (target.GetUseParallelAsyncIO() && target.GetRequestCount() == 1) + { + fprintf(stderr, "WARNING: -p does not have effect unless outstanding I/O count (-o) is > 1\n"); + } + + if (timeSpan.GetRandSeed() > 0) + { + fprintf(stderr, "WARNING: -z is ignored if -r is not provided\n"); + // although ulRandSeed==0 is a valid value, it's interpreted as "not provided" for this warning + } + + if (target.GetUseInterlockedSequential()) + { + if (target.GetThreadStrideInBytes() > 0) + { + fprintf(stderr, "ERROR: -si conflicts with -T\n"); + fOk = false; + } + + if (target.GetUseParallelAsyncIO()) + { + fprintf(stderr, "ERROR: -si conflicts with -p\n"); + fOk = false; + } + + if (!targetHasMultipleThreads) + { + fprintf(stderr, "WARNING: single-threaded test, -si ignored\n"); + } + } + else + { + if (targetHasMultipleThreads && !target.GetThreadStrideInBytes()) + { + fprintf(stderr, "WARNING: target access pattern will not be sequential, consider -si\n"); + } + + if (!targetHasMultipleThreads && target.GetThreadStrideInBytes()) + { + fprintf(stderr, "ERROR: -T has no effect unless multiple threads per target are used\n"); + fOk = false; + } + } + } + + if (target.GetRandomDataWriteBufferSize() > 0) + { + if (target.GetRandomDataWriteBufferSize() < target.GetBlockSizeInBytes()) + { + fprintf(stderr, "ERROR: custom write buffer (-Z) is smaller than the block size. Write buffer size: %I64u block size: %u\n", + target.GetRandomDataWriteBufferSize(), + target.GetBlockSizeInBytes()); + fOk = false; + } + } + + // in the cases where there is only a single configuration specified for each target (e.g., cmdline), + // currently there are no validations specific to individual targets (e.g., pre-existing files) + // so we can stop validation now. this allows us to only warn/error once, as opposed to repeating + // it for each target. + if (fSingleSpec) + { + break; + } + } + } + return fOk; +} + +bool ThreadParameters::AllocateAndFillBufferForTarget(const Target& target) +{ + bool fOk = true; + BYTE *pDataBuffer = nullptr; + size_t cbDataBuffer = target.GetBlockSizeInBytes() * target.GetRequestCount(); + + /// CrystalDiskMark 4 does not support Large Page + if (false && target.GetUseLargePages()) + { + /// size_t cbMinLargePage = GetLargePageMinimum(); + /// size_t cbRoundedSize = (cbDataBuffer + cbMinLargePage - 1) & ~(cbMinLargePage - 1); + /// pDataBuffer = (BYTE *)VirtualAlloc(nullptr, cbRoundedSize, MEM_COMMIT | MEM_RESERVE | MEM_LARGE_PAGES, PAGE_EXECUTE_READWRITE); + } + else + { + pDataBuffer = (BYTE *)VirtualAlloc(nullptr, cbDataBuffer, MEM_COMMIT, PAGE_READWRITE); + } + + fOk = (pDataBuffer != nullptr); + + //fill buffer (useful only for write tests) + if (fOk && target.GetWriteRatio() > 0) + { + if (target.GetZeroWriteBuffers()) + { + memset(pDataBuffer, 0, cbDataBuffer); + } + else + { + for (size_t i = 0; i < cbDataBuffer; i++) + { + pDataBuffer[i] = (BYTE)(i % 256); + } + } + } + + if (fOk) + { + vpDataBuffers.push_back(pDataBuffer); + } + + return fOk; +} + +BYTE* ThreadParameters::GetReadBuffer(size_t iTarget, size_t iRequest) +{ + return vpDataBuffers[iTarget] + (iRequest * vTargets[iTarget].GetBlockSizeInBytes()); +} + +BYTE* ThreadParameters::GetWriteBuffer(size_t iTarget, size_t iRequest) +{ + BYTE *pBuffer = nullptr; + + Target& target(vTargets[iTarget]); + size_t cb = static_cast(target.GetRandomDataWriteBufferSize()); + if (cb == 0) + { + pBuffer = vpDataBuffers[iTarget] + (iRequest * vTargets[iTarget].GetBlockSizeInBytes()); + } + else + { + pBuffer = target.GetRandomDataWriteBuffer(); + } + return pBuffer; +} + +DWORD ThreadParameters::GetTotalRequestCount() const +{ + DWORD cRequests = 0; + + for (const auto& t : vTargets) + { + cRequests += t.GetRequestCount(); + } + + return cRequests; +} diff --git a/CristalDiskMark/source/diskspd2_0_15a/Common/Common.h b/CristalDiskMark/source/diskspd2_0_15a/Common/Common.h new file mode 100644 index 0000000..c6705b6 --- /dev/null +++ b/CristalDiskMark/source/diskspd2_0_15a/Common/Common.h @@ -0,0 +1,814 @@ +/* + +DISKSPD + +Copyright(c) Microsoft Corporation +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#pragma once + +#include +#include +#include //ntdll.dll +#include +#include "Histogram.h" +#include "IoBucketizer.h" + +using namespace std; + +/// structures used for passing the input parameters + +// versioning material. for simplicity in consumption, please ensure that the date string +// parses via the System.Datetime constructor as follows (in Powershell): +// +// [datetime] "string" +// +// this should result in a valid System.Datetime object, rendered like: +// +// Monday, June 16, 2014 12:00:00 AM + +#define DISKSPD_RELEASE_TAG "" +#define DISKSPD_NUMERIC_VERSION_STRING "2.0.15" DISKSPD_RELEASE_TAG +#define DISKSPD_DATE_VERSION_STRING "2015/01/09" + +typedef void (WINAPI *PRINTF)(const char*, va_list); //function used for displaying formatted data (printf style) + +struct ETWEventCounters +{ + UINT64 ullIORead; // Read + UINT64 ullIOWrite; // Write + UINT64 ullMMTransitionFault; // Transition fault + UINT64 ullMMDemandZeroFault; // Demand Zero fault + UINT64 ullMMCopyOnWrite; // Copy on Write + UINT64 ullMMGuardPageFault; // Guard Page fault + UINT64 ullMMHardPageFault; // Hard page fault + UINT64 ullNetTcpSend; // Send + UINT64 ullNetTcpReceive; // Receive + UINT64 ullNetUdpSend; // Send + UINT64 ullNetUdpReceive; // Receive + UINT64 ullNetConnect; // Connect + UINT64 ullNetDisconnect; // Disconnect + UINT64 ullNetRetransmit; // ReTransmit + UINT64 ullNetAccept; // Accept + UINT64 ullNetReconnect; // ReConnect + UINT64 ullRegCreate; // NtCreateKey + UINT64 ullRegOpen; // NtOpenKey + UINT64 ullRegDelete; // NtDeleteKey + UINT64 ullRegQuery; // NtQueryKey + UINT64 ullRegSetValue; // NtSetValueKey + UINT64 ullRegDeleteValue; // NtDeleteValueKey + UINT64 ullRegQueryValue; // NtQueryValueKey + UINT64 ullRegEnumerateKey; // NtEnumerateKey + UINT64 ullRegEnumerateValueKey; // NtEnumerateValueKey + UINT64 ullRegQueryMultipleValue; // NtQueryMultipleValueKey + UINT64 ullRegSetInformation; // NtSetInformationKey + UINT64 ullRegFlush; // NtFlushKey + UINT64 ullRegKcbDmp; // KcbDump/create + UINT64 ullThreadStart; + UINT64 ullThreadEnd; + UINT64 ullProcessStart; + UINT64 ullProcessEnd; + UINT64 ullImageLoad; +}; + + +// structure containing informations about ETW session +struct ETWSessionInfo +{ + ULONG ulBufferSize; + ULONG ulMinimumBuffers; + ULONG ulMaximumBuffers; + ULONG ulFreeBuffers; + ULONG ulBuffersWritten; + ULONG ulFlushTimer; + LONG lAgeLimit; + ULONG ulNumberOfBuffers; + ULONG ulEventsLost; + ULONG ulLogBuffersLost; + ULONG ulRealTimeBuffersLost; +}; + +// structure containing parameters concerning ETW session provided by user +struct ETWMask +{ + BOOL bProcess; + BOOL bThread; + BOOL bImageLoad; + BOOL bDiskIO; + BOOL bMemoryPageFaults; + BOOL bMemoryHardFaults; + BOOL bNetwork; + BOOL bRegistry; + BOOL bUsePagedMemory; + BOOL bUsePerfTimer; + BOOL bUseSystemTimer; + BOOL bUseCyclesCounter; +}; + +namespace UnitTests +{ + class PerfTimerUnitTests; + class ProfileUnitTests; + class TargetUnitTests; +} + +class PerfTimer +{ +public: + + static UINT64 GetTime(); + + static double PerfTimeToMicroseconds(const double); + static double PerfTimeToMilliseconds(const double); + static double PerfTimeToSeconds(const double); + static double PerfTimeToMicroseconds(const UINT64); + static double PerfTimeToMilliseconds(const UINT64); + static double PerfTimeToSeconds(const UINT64); + + static UINT64 MicrosecondsToPerfTime(const double); + static UINT64 MillisecondsToPerfTime(const double); + static UINT64 SecondsToPerfTime(const double); + +private: + + static const UINT64 TIMER_FREQ; + static UINT64 _GetPerfTimerFreq(); + + friend class UnitTests::PerfTimerUnitTests; +}; + +struct PercentileDescriptor +{ + double Percentile; + string Name; +}; + +class Util +{ +public: + static string DoubleToStringHelper(const double); + template static T QuotientCeiling(T dividend, T divisor) + { + return (dividend + divisor - 1) / divisor; + } +}; + +// To keep track of which type of IO was issued +enum class IOOperation +{ + ReadIO = 1, + WriteIO +}; + +class TargetResults +{ +public: + TargetResults() : + ullFileSize(0), + ullBytesCount(0), + ullIOCount(0), + ullReadBytesCount(0), + ullReadIOCount(0), + ullWriteBytesCount(0), + ullWriteIOCount(0) + { + + } + + void Add(DWORD dwBytesTransferred, + IOOperation type, + PUINT64 pullIoStartTime, + PUINT64 pullSpanStartTime, + bool fMeasureLatency, + bool fCalculateIopsStdDev + ) + { + float fDurationMsec = 0; + UINT64 ullEndTime = 0; + // assume it is worthwhile to stay off of the time query path unless needed (micro-overhead) + if (fMeasureLatency || fCalculateIopsStdDev) + { + ullEndTime = PerfTimer::GetTime(); + } + + if (fMeasureLatency) + { + UINT64 ullDuration = ullEndTime - *pullIoStartTime; + fDurationMsec = static_cast(PerfTimer::PerfTimeToMicroseconds(ullDuration)); + + if (type == IOOperation::ReadIO) + { + readLatencyHistogram.Add(fDurationMsec); + } + else + { + writeLatencyHistogram.Add(fDurationMsec); + } + } + + UINT64 ullRelativeCompletionTime = 0; + if (fCalculateIopsStdDev) + { + ullRelativeCompletionTime = ullEndTime - *pullSpanStartTime; + + if (type == IOOperation::ReadIO) + { + readBucketizer.Add(ullRelativeCompletionTime); + } + else + { + writeBucketizer.Add(ullRelativeCompletionTime); + } + } + + if (type == IOOperation::ReadIO) + { + ullReadBytesCount += dwBytesTransferred; // update read bytes counter + ullReadIOCount++; // update completed read I/O operations counter + } + else + { + ullWriteBytesCount += dwBytesTransferred; // update write bytes counter + ullWriteIOCount++; // update completed write I/O operations counter + } + + ullBytesCount += dwBytesTransferred; // update bytes counter + ullIOCount++; // update completed I/O operations counter + } + + string sPath; + UINT64 ullFileSize; //size of the file + UINT64 ullBytesCount; //number of accessed bytes + UINT64 ullIOCount; //number of performed I/O operations + UINT64 ullReadBytesCount; //number of bytes read + UINT64 ullReadIOCount; //number of performed Read I/O operations + UINT64 ullWriteBytesCount; //number of bytes written + UINT64 ullWriteIOCount; //number of performed Write I/O operations + + Histogram readLatencyHistogram; + Histogram writeLatencyHistogram; + + IoBucketizer readBucketizer; + IoBucketizer writeBucketizer; +}; + +class ThreadResults +{ +public: + vector vTargetResults; +}; + +class Results +{ +public: + bool fUseETW; + struct ETWEventCounters EtwEventCounters; + struct ETWMask EtwMask; + struct ETWSessionInfo EtwSessionInfo; + vector vThreadResults; + UINT64 ullTimeCount; + vector vSystemProcessorPerfInfo; +}; + +typedef void (*CALLBACK_TEST_STARTED)(); //callback function to notify that the measured test is about to start +typedef void (*CALLBACK_TEST_FINISHED)(); //callback function to notify that the measured test has just finished + +class SystemInformation +{ +public: + string sComputerName; + + SystemInformation() + { + char buffer[64]; + DWORD cb = _countof(buffer); + BOOL fResult; + +#pragma prefast(suppress:38020, "Yes, we're aware this is an ANSI API in a UNICODE project") + fResult = GetComputerNameExA(ComputerNamePhysicalDnsHostname, buffer, &cb); + if (fResult) + { + sComputerName = buffer; + } + } + + string SystemInformation::GetXml() const + { + string sXml("\n"); + + // identify computer which ran the test + sXml += ""; + sXml += sComputerName; + sXml += "\n"; + + // identify tool version which performed the test + sXml += "\n"; + sXml += "" DISKSPD_NUMERIC_VERSION_STRING "\n"; + sXml += "" DISKSPD_DATE_VERSION_STRING "\n"; + sXml += "\n"; + + sXml += "\n"; + + return sXml; + } +}; + +struct Synchronization +{ + ULONG ulStructSize; //size of the structure that the caller is aware of (to easier achieve backward compatibility in a future) + HANDLE hStopEvent; //an event to be signalled if the scenario is to be stop before time ellapses + HANDLE hStartEvent; //an event for signalling start + CALLBACK_TEST_STARTED pfnCallbackTestStarted; //a function to be called if the measured test is about to start + CALLBACK_TEST_FINISHED pfnCallbackTestFinished; //a function to be called as soon as the measrued test finishes +}; + +#define STRUCT_SYNCHRONIZATION_SUPPORTS(pSynch, Field) ( \ + (NULL != (pSynch)) && \ + ((pSynch)->ulStructSize >= offsetof(struct Synchronization, Field) + sizeof((pSynch)->Field)) \ + ) + +class Target +{ +public: + + Target() : + _dwBlockSize(64 * 1024), + _dwRequestCount(2), + _ullBlockAlignment(64 * 1024), + _fBlockAlignmentValid(false), + _fUseRandomAccessPattern(false), + _ullBaseFileOffset(0), + _fParallelAsyncIO(false), + _fInterlockedSequential(false), + _fDisableOSCache(false), + _fDisableAllCache(false), + _fZeroWriteBuffers(false), + _dwThreadsPerFile(1), + _ullThreadStride(0), + _fCreateFile(false), + _fPrecreated(false), + _ullFileSize(0), + _ullMaxFileSize(0), + _ulWriteRatio(0), + _fUseBurstSize(false), + _dwBurstSize(0), + _dwThinkTime(0), + _fThinkTime(false), + _fSequentialScanHint(false), + _fRandomAccessHint(false), + _fUseLargePages(false), + _ioPriorityHint(IoPriorityHintNormal), + _dwThroughputBytesPerMillisecond(0), + _cbRandomDataWriteBuffer(0), + _sRandomDataWriteBufferSourcePath(), + _pRandomDataWriteBuffer(nullptr) + { + } + + void SetPath(string sPath) { _sPath = sPath; } + string GetPath() const { return _sPath; } + + void SetBlockSizeInBytes(DWORD dwBlockSize) { _dwBlockSize = dwBlockSize; } + DWORD GetBlockSizeInBytes() const { return _dwBlockSize; } + + void SetBlockAlignmentInBytes(UINT64 ullBlockAlignment) + { + _ullBlockAlignment = ullBlockAlignment; + _fBlockAlignmentValid = true; + } + + UINT64 GetBlockAlignmentInBytes() const + { + return _fBlockAlignmentValid ? _ullBlockAlignment : _dwBlockSize; + } + + void SetUseRandomAccessPattern(bool fUseRandomAccessPattern) { _fUseRandomAccessPattern = fUseRandomAccessPattern; } + bool GetUseRandomAccessPattern() const { return _fUseRandomAccessPattern; } + + void SetBaseFileOffsetInBytes(UINT64 ullBaseFileOffset) { _ullBaseFileOffset = ullBaseFileOffset; } + UINT64 GetBaseFileOffsetInBytes() const { return _ullBaseFileOffset; } + + void SetSequentialScanHint(bool fSequentialScanHint) { _fSequentialScanHint = fSequentialScanHint; } + bool GetSequentialScanHint() const { return _fSequentialScanHint; } + + void SetRandomAccessHint(bool fRandomAccessHint) { _fRandomAccessHint = fRandomAccessHint; } + bool GetRandomAccessHint() const { return _fRandomAccessHint; } + + void SetUseLargePages(bool fUseLargePages) { _fUseLargePages = fUseLargePages; } + bool GetUseLargePages() const { return _fUseLargePages; } + + void SetRequestCount(DWORD dwRequestCount) { _dwRequestCount = dwRequestCount; } + DWORD GetRequestCount() const { return _dwRequestCount; } + + void SetDisableOSCache(bool fDisableOSCache) { _fDisableOSCache = fDisableOSCache; } + bool GetDisableOSCache() const { return _fDisableOSCache; } + + void SetDisableAllCache(bool fDisableAllCache) { _fDisableAllCache = fDisableAllCache; } + bool GetDisableAllCache() const { return _fDisableAllCache; } + + void SetZeroWriteBuffers(bool fZeroWriteBuffers) { _fZeroWriteBuffers = fZeroWriteBuffers; } + bool GetZeroWriteBuffers() const { return _fZeroWriteBuffers; } + + void SetRandomDataWriteBufferSize(UINT64 cbWriteBuffer) { _cbRandomDataWriteBuffer = cbWriteBuffer; } + UINT64 GetRandomDataWriteBufferSize(void) const { return _cbRandomDataWriteBuffer; } + + void SetRandomDataWriteBufferSourcePath(string sPath) { _sRandomDataWriteBufferSourcePath = sPath; } + string GetRandomDataWriteBufferSourcePath() const { return _sRandomDataWriteBufferSourcePath; } + + void SetUseBurstSize(bool fUseBurstSize) { _fUseBurstSize = fUseBurstSize; } + bool GetUseBurstSize() const { return _fUseBurstSize; } + + void SetBurstSize(DWORD dwBurstSize) { _dwBurstSize = dwBurstSize; } + DWORD GetBurstSize() const { return _dwBurstSize; } + + void SetThinkTime(DWORD dwThinkTime) { _dwThinkTime = dwThinkTime; } + DWORD GetThinkTime() const { return _dwThinkTime; } + + void SetEnableThinkTime(bool fEnable) { _fThinkTime = fEnable; } + bool GetEnableThinkTime() const { return _fThinkTime; } + + void SetThreadsPerFile(DWORD dwThreadsPerFile) { _dwThreadsPerFile = dwThreadsPerFile; } + DWORD GetThreadsPerFile() const { return _dwThreadsPerFile; } + + void SetCreateFile(bool fCreateFile) { _fCreateFile = fCreateFile; } + bool GetCreateFile() const { return _fCreateFile; } + + void SetFileSize(UINT64 ullFileSize) { _ullFileSize = ullFileSize; } + UINT64 GetFileSize() const { return _ullFileSize; } // TODO: InBytes + + void SetMaxFileSize(UINT64 ullMaxFileSize) { _ullMaxFileSize = ullMaxFileSize; } + UINT64 GetMaxFileSize() const { return _ullMaxFileSize; } + + void SetWriteRatio(UINT32 ulWriteRatio) { _ulWriteRatio = ulWriteRatio; } + UINT32 GetWriteRatio() const { return _ulWriteRatio; } + + void SetUseParallelAsyncIO(bool fParallelAsyncIO) { _fParallelAsyncIO = fParallelAsyncIO; } + bool GetUseParallelAsyncIO() const { return _fParallelAsyncIO; } + + void SetUseInterlockedSequential(bool fInterlockedSequential) { _fInterlockedSequential = fInterlockedSequential; } + bool GetUseInterlockedSequential() const { return _fInterlockedSequential; } + + void SetThreadStrideInBytes(UINT64 ullThreadStride) { _ullThreadStride = ullThreadStride; } + UINT64 GetThreadStrideInBytes() const { return _ullThreadStride; } + + void SetIOPriorityHint(PRIORITY_HINT _hint) + { + assert(_hint < MaximumIoPriorityHintType); + _ioPriorityHint = _hint; + } + PRIORITY_HINT GetIOPriorityHint() const { return _ioPriorityHint; } + + void SetPrecreated(bool fPrecreated) { _fPrecreated = fPrecreated; } + bool GetPrecreated() const { return _fPrecreated; } + + void SetThroughput(DWORD dwThroughputBytesPerMillisecond) { _dwThroughputBytesPerMillisecond = dwThroughputBytesPerMillisecond; } + DWORD GetThroughputInBytesPerMillisecond() const { return _dwThroughputBytesPerMillisecond; } + + string GetXml() const; + + bool AllocateAndFillRandomDataWriteBuffer(); + void FreeRandomDataWriteBuffer(); + BYTE* GetRandomDataWriteBuffer(); + +private: + string _sPath; + DWORD _dwBlockSize; + DWORD _dwRequestCount; // TODO: change the name to something more descriptive (OutstandingRequestCount?) + + UINT64 _ullBlockAlignment; + bool _fBlockAlignmentValid; + bool _fUseRandomAccessPattern; + + UINT64 _ullBaseFileOffset; + bool _fParallelAsyncIO; + bool _fInterlockedSequential; + bool _fDisableOSCache; + bool _fDisableAllCache; + bool _fZeroWriteBuffers; + DWORD _dwThreadsPerFile; + UINT64 _ullThreadStride; + + bool _fCreateFile; + bool _fPrecreated; // used to track which files have been created before the first timespan and which have to be created later + UINT64 _ullFileSize; + UINT64 _ullMaxFileSize; + UINT32 _ulWriteRatio; + bool _fUseBurstSize; // TODO: "use" or "enable"?; since burst size must be specified with the think time, one variable should be sufficient + DWORD _dwBurstSize; // number of IOs in a burst + DWORD _dwThinkTime; // time to pause before issuing the next burst of IOs + // TODO: could this be removed by using _dwThinkTime==0? + bool _fThinkTime; //variable to decide whether to think between IOs (default is false) + DWORD _dwThroughputBytesPerMillisecond; // set to 0 to disable throttling + + bool _fSequentialScanHint; // open file with the FILE_FLAG_SEQUENTIAL_SCAN hint + bool _fRandomAccessHint; // open file with the FILE_FLAG_RANDOM_ACCESS hint + bool _fUseLargePages; // Use large pages for IO buffers + + UINT64 _cbRandomDataWriteBuffer; // if > 0, then the write buffer should be filled with random data + string _sRandomDataWriteBufferSourcePath; // file that should be used for filling the write buffer (if the path is not available, use a crypto provider) + BYTE *_pRandomDataWriteBuffer; // a buffer used for write data when _cbWriteBuffer > 0; it's shared by all the threads working on this target + + PRIORITY_HINT _ioPriorityHint; + + bool _FillRandomDataWriteBuffer(); + + friend class UnitTests::ProfileUnitTests; + friend class UnitTests::TargetUnitTests; +}; + +class TimeSpan +{ +public: + TimeSpan() : + _ulDuration(10), + _ulWarmUp(5), + _ulCoolDown(0), + _ulRandSeed(0), + _dwThreadCount(0), + _fGroupAffinity(false), + _fDisableAffinity(false), + _fCompletionRoutines(false), + _fMeasureLatency(false), + _fCalculateIopsStdDev(false), + _ulIoBucketDurationInMilliseconds(1000) + { + } + + void AddAffinityAssignment(UINT32 ulAffinity) + { + _vAffinity.push_back(ulAffinity); + } + vector GetAffinityAssignments() const { return _vAffinity; } + + void AddTarget(const Target& target) + { + _vTargets.push_back(Target(target)); + } + vector GetTargets() const { return _vTargets; } + + void SetDuration(UINT32 ulDuration) { _ulDuration = ulDuration; } + UINT32 GetDuration() const { return _ulDuration; } + + void SetWarmup(UINT32 ulWarmup) { _ulWarmUp = ulWarmup; } + UINT32 GetWarmup() const { return _ulWarmUp; } + + void SetCooldown(UINT32 ulCooldown) { _ulCoolDown = ulCooldown; } + UINT32 GetCooldown() const { return _ulCoolDown; } + + void SetRandSeed(UINT32 ulRandSeed) { _ulRandSeed = ulRandSeed; } + UINT32 GetRandSeed() const { return _ulRandSeed; } + + void SetThreadCount(DWORD dwThreadCount) { _dwThreadCount = dwThreadCount; } + DWORD GetThreadCount() const { return _dwThreadCount; } + + void SetGroupAffinity(bool fGroupAffinity) { _fGroupAffinity = fGroupAffinity; } + bool GetGroupAffinity() const { return _fGroupAffinity; } + + void SetDisableAffinity(bool fDisableAffinity) { _fDisableAffinity = fDisableAffinity; } + bool GetDisableAffinity() const { return _fDisableAffinity; } + + void SetCompletionRoutines(bool fCompletionRoutines) { _fCompletionRoutines = fCompletionRoutines; } + bool GetCompletionRoutines() const { return _fCompletionRoutines; } + + void SetMeasureLatency(bool fMeasureLatency) { _fMeasureLatency = fMeasureLatency; } + bool GetMeasureLatency() const { return _fMeasureLatency; } + + void SetCalculateIopsStdDev(bool fCalculateStdDev) { _fCalculateIopsStdDev = fCalculateStdDev; } + bool GetCalculateIopsStdDev() const { return _fCalculateIopsStdDev; } + + void SetIoBucketDurationInMilliseconds(UINT32 ulIoBucketDurationInMilliseconds) { _ulIoBucketDurationInMilliseconds = ulIoBucketDurationInMilliseconds; } + UINT32 GetIoBucketDurationInMilliseconds() const { return _ulIoBucketDurationInMilliseconds; } + + string GetXml() const; + void MarkFilesAsPrecreated(const vector vFiles); + +private: + vector _vTargets; + UINT32 _ulDuration; + UINT32 _ulWarmUp; + UINT32 _ulCoolDown; + UINT32 _ulRandSeed; + DWORD _dwThreadCount; + bool _fGroupAffinity; + bool _fDisableAffinity; + vector _vAffinity; + bool _fCompletionRoutines; + bool _fMeasureLatency; + bool _fCalculateIopsStdDev; + UINT32 _ulIoBucketDurationInMilliseconds; + + friend class UnitTests::ProfileUnitTests; +}; + +enum class ResultsFormat +{ + Text, + Xml +}; + +enum class PrecreateFiles +{ + None, + UseMaxSize, + OnlyFilesWithConstantSizes, + OnlyFilesWithConstantOrZeroSizes +}; + +class Profile +{ +public: + Profile() : + _fVerbose(false), + _dwProgress(0), + _fEtwEnabled(false), + _fEtwProcess(false), + _fEtwThread(false), + _fEtwImageLoad(false), + _fEtwDiskIO(false), + _fEtwMemoryPageFaults(false), + _fEtwMemoryHardFaults(false), + _fEtwNetwork(false), + _fEtwRegistry(false), + _fEtwUsePagedMemory(false), + _fEtwUsePerfTimer(false), + _fEtwUseSystemTimer(false), + _fEtwUseCyclesCounter(false), + _resultsFormat(ResultsFormat::Text), + _precreateFiles(PrecreateFiles::None) + { + } + + void AddTimeSpan(const TimeSpan& timeSpan) + { + _vTimeSpans.push_back(TimeSpan(timeSpan)); + } + + const vector& GetTimeSpans() const { return _vTimeSpans; } + + void SetVerbose(bool fVerbose) { _fVerbose = fVerbose; } + bool GetVerbose() const { return _fVerbose; } + + void SetProgress(DWORD dwProgress) { _dwProgress = dwProgress; } + DWORD GetProgress() const { return _dwProgress; } + + void SetCmdLine(string sCmdLine) { _sCmdLine = sCmdLine; } + string GetCmdLine() const { return _sCmdLine; }; + + void SetResultsFormat(ResultsFormat format) { _resultsFormat = format; } + ResultsFormat GetResultsFormat() const { return _resultsFormat; } + + void SetPrecreateFiles(PrecreateFiles c) { _precreateFiles = c; } + PrecreateFiles GetPrecreateFiles() const { return _precreateFiles; } + + //ETW + void SetEtwEnabled(bool fEtwEnabled) { _fEtwEnabled = fEtwEnabled; } + void SetEtwProcess(bool fEtwProcess) { _fEtwProcess = fEtwProcess; } + void SetEtwThread(bool fEtwThread) { _fEtwThread = fEtwThread; } + void SetEtwImageLoad(bool fEtwImageLoad) { _fEtwImageLoad = fEtwImageLoad; } + void SetEtwDiskIO(bool fEtwDiskIO) { _fEtwDiskIO = fEtwDiskIO; } + void SetEtwMemoryPageFaults(bool fEtwMemoryPageFaults) { _fEtwMemoryPageFaults = fEtwMemoryPageFaults; } + void SetEtwMemoryHardFaults(bool fEtwMemoryHardFaults) { _fEtwMemoryHardFaults = fEtwMemoryHardFaults; } + void SetEtwNetwork(bool fEtwNetwork) { _fEtwNetwork = fEtwNetwork; } + void SetEtwRegistry(bool fEtwRegistry) { _fEtwRegistry = fEtwRegistry; } + void SetEtwUsePagedMemory(bool fEtwUsePagedMemory) { _fEtwUsePagedMemory = fEtwUsePagedMemory; } + void SetEtwUsePerfTimer(bool fEtwUsePerfTimer) { _fEtwUsePerfTimer = fEtwUsePerfTimer; } + void SetEtwUseSystemTimer(bool fEtwUseSystemTimer) { _fEtwUseSystemTimer = fEtwUseSystemTimer; } + void SetEtwUseCyclesCounter(bool fEtwUseCyclesCounter) { _fEtwUseCyclesCounter = fEtwUseCyclesCounter; } + + bool GetEtwEnabled() const { return _fEtwEnabled; } + bool GetEtwProcess() const { return _fEtwProcess; } + bool GetEtwThread() const { return _fEtwThread; } + bool GetEtwImageLoad() const { return _fEtwImageLoad; } + bool GetEtwDiskIO() const { return _fEtwDiskIO; } + bool GetEtwMemoryPageFaults() const { return _fEtwMemoryPageFaults; } + bool GetEtwMemoryHardFaults() const { return _fEtwMemoryHardFaults; } + bool GetEtwNetwork() const { return _fEtwNetwork; } + bool GetEtwRegistry() const { return _fEtwRegistry; } + bool GetEtwUsePagedMemory() const { return _fEtwUsePagedMemory; } + bool GetEtwUsePerfTimer() const { return _fEtwUsePerfTimer; } + bool GetEtwUseSystemTimer() const { return _fEtwUseSystemTimer; } + bool GetEtwUseCyclesCounter() const { return _fEtwUseCyclesCounter; } + + string GetXml() const; + bool Validate(bool fSingleSpec) const; + void MarkFilesAsPrecreated(const vector vFiles); + +private: + Profile(const Profile& T); + + vector_vTimeSpans; + bool _fVerbose; + DWORD _dwProgress; + string _sCmdLine; + ResultsFormat _resultsFormat; + PrecreateFiles _precreateFiles; + + //ETW + bool _fEtwEnabled; + bool _fEtwProcess; + bool _fEtwThread; + bool _fEtwImageLoad; + bool _fEtwDiskIO; + bool _fEtwMemoryPageFaults; + bool _fEtwMemoryHardFaults; + bool _fEtwNetwork; + bool _fEtwRegistry; + bool _fEtwUsePagedMemory; + bool _fEtwUsePerfTimer; + bool _fEtwUseSystemTimer; + bool _fEtwUseCyclesCounter; + + friend class UnitTests::ProfileUnitTests; +}; + +class ThreadParameters +{ +public: + ThreadParameters() : + pProfile(nullptr), + pTimeSpan(nullptr), + pullSharedSequentialOffsets(nullptr), + ulRandSeed(0), + ulThreadNo(0), + ulRelativeThreadNo(0) + { + } + + const Profile *pProfile; + const TimeSpan *pTimeSpan; + + vector vTargets; + vector vhTargets; + vector vullFileSizes; + vector vpDataBuffers; + vector vOverlapped; // each target has RequestCount OVERLAPPED structures + vector vOverlappedIdToTargetId; + vector vFirstOverlappedIdForTargetId; //id of the first overlapped structure in the vOverlapped vector by target + vector vdwIoType; //as many as vOverlapped; used by the completion routines + vector vIoStartTimes; + + // For vanilla sequential access (-s): + // Private per-thread offsets, incremented directly, indexed to number of targets + vector vullPrivateSequentialOffsets; + + // For interlocked sequential access (-si): + // Pointers to offsets shared between threads, incremented with an interlocked op + UINT64* pullSharedSequentialOffsets; + + UINT32 ulRandSeed; + UINT32 ulThreadNo; + UINT32 ulRelativeThreadNo; + + // accounting + volatile bool *pfAccountingOn; + PUINT64 pullStartTime; + ThreadResults *pResults; + + //group affinity + WORD wGroupNum; + DWORD dwProcNum; + GROUP_AFFINITY GroupAffinity; + + HANDLE hStartEvent; + + // TODO: check how it's used + HANDLE hEndEvent; //used only in case of completion routines (not for IO Completion Ports) + + bool AllocateAndFillBufferForTarget(const Target& target); + BYTE* GetReadBuffer(size_t iTarget, size_t iRequest); + BYTE* GetWriteBuffer(size_t iTarget, size_t iRequest); + DWORD GetTotalRequestCount() const; + +private: + ThreadParameters(const ThreadParameters& T); +}; + +class IResultParser +{ +public: + virtual string ParseResults(Profile& profile, const SystemInformation& system, vector vResults) = 0; + virtual int GetTotalScore() = 0; + virtual double GetAverageLatency() = 0; +}; diff --git a/CristalDiskMark/source/diskspd2_0_15a/Common/Histogram.h b/CristalDiskMark/source/diskspd2_0_15a/Common/Histogram.h new file mode 100644 index 0000000..ee0a312 --- /dev/null +++ b/CristalDiskMark/source/diskspd2_0_15a/Common/Histogram.h @@ -0,0 +1,273 @@ +/* + +DISKSPD + +Copyright(c) Microsoft Corporation +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#pragma once + +#include +#include +#include +#include +#include +#include + +#pragma push_macro("min") +#pragma push_macro("max") +#undef min +#undef max + +template +class Histogram +{ + private: + + unsigned _samples; + +#define USE_HASH_TABLE +#ifdef USE_HASH_TABLE + std::unordered_map _data; + + std::map _GetSortedData() const + { + return std::map(_data.begin(), _data.end()); + } +#else + std::map _data; + + std::map _GetSortedData() const + { + return _data; + } +#endif + public: + + Histogram() + : _samples(0) + {} + + void Clear() + { + _data.clear(); + _samples = 0; + } + + void Add(T v) + { + _data[ v ]++; + _samples++; + } + + void Merge(const Histogram &other) + { + for (auto i : other._data) + { + _data[ i.first ] += i.second; + } + + _samples += other._samples; + } + + T GetMin() const + { + T min(std::numeric_limits::max()); + + for (auto i : _data) + { + if (i.first < min) + { + min = i.first; + } + } + + return min; + } + + T GetMax() const + { + T max(std::numeric_limits::min()); + + for (auto i : _data) + { + if (i.first > max) + { + max = i.first; + } + } + + return max; + } + + unsigned GetSampleSize() const + { + return _samples; + } + + T GetPercentile(double p) const + { + // ISSUE-REVIEW + // What do the 0th and 100th percentile really mean? + if ((p < 0) || (p > 1)) + { + throw std::invalid_argument("Percentile must be >= 0 and <= 1"); + } + + const double target = GetSampleSize() * p; + + unsigned cur = 0; + for (auto i : _GetSortedData()) + { + cur += i.second; + if (cur >= target) + { + return i.first; + } + } + + throw std::runtime_error("Percentile is undefined"); + } + + T GetPercentile(int p) const + { + return GetPercentile(static_cast(p)/100); + } + + T GetMedian() const + { + return GetPercentile(0.5); + } + + double GetStdDev() const { return GetStandardDeviation(); } + double GetAvg() const { return GetMean(); } + + double GetMean() const + { + double sum(0); + unsigned samples = GetSampleSize(); + + for (auto i : _data) + { + double bucket_val = + static_cast(i.first) * i.second / samples; + + if (sum + bucket_val < 0) + { + throw std::overflow_error("while trying to accumulate sum"); + } + + sum += bucket_val; + } + + return sum; + } + + double GetStandardDeviation() const + { + double mean(GetMean()); + double ssd(0); + + for (auto i : _data) + { + double dev = static_cast(i.first) - mean; + double sqdev = dev*dev; + ssd += i.second * sqdev; + } + + return sqrt(ssd / GetSampleSize()); + } + + std::string GetHistogramCsv(const unsigned bins) const + { + return GetHistogramCsv(bins, GetMin(), GetMax()); + } + + std::string GetHistogramCsv(const unsigned bins, const T LOW, const T HIGH) const + { + // ISSUE-REVIEW + // Currently bins are defined as strictly less-than + // their upper limit, with the exception of the last + // bin. Otherwise where would I put the max value? + const double binSize = static_cast((HIGH - LOW) / bins); + double limit = static_cast(LOW); + + std::ostringstream os; + os.precision(std::numeric_limits::digits10); + + std::map sortedData = _GetSortedData(); + + auto pos = sortedData.begin(); + + unsigned cumulative = 0; + + for (unsigned bin = 1; bin <= bins; ++bin) + { + unsigned count = 0; + limit += binSize; + + while (pos != sortedData.end() && + (pos->first < limit || bin == bins)) + { + count += pos->second; + ++pos; + } + + cumulative += count; + + os << limit << "," << count << "," << cumulative << std::endl; + } + + return os.str(); + } + + std::string GetRawCsv() const + { + std::ostringstream os; + os.precision(std::numeric_limits::digits10); + + for (auto i : _GetSortedData()) + { + os << i.first << "," << i.second << std::endl; + } + + return os.str(); + } + + std::string GetRaw() const + { + std::ostringstream os; + + for (auto i : _GetSortedData()) + { + os << i.second << " " << i.first << std::endl; + } + + return os.str(); + } +}; + +#pragma pop_macro("min") +#pragma pop_macro("max") \ No newline at end of file diff --git a/CristalDiskMark/source/diskspd2_0_15a/Common/IoBucketizer.cpp b/CristalDiskMark/source/diskspd2_0_15a/Common/IoBucketizer.cpp new file mode 100644 index 0000000..8be6306 --- /dev/null +++ b/CristalDiskMark/source/diskspd2_0_15a/Common/IoBucketizer.cpp @@ -0,0 +1,143 @@ +/* + +DISKSPD + +Copyright(c) Microsoft Corporation +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#include "IoBucketizer.h" + +const unsigned __int64 INVALID_BUCKET_DURATION = 0; + +IoBucketizer::IoBucketizer() + : _bucketDuration(INVALID_BUCKET_DURATION), + _validBuckets(0) +{} + +void IoBucketizer::Initialize(unsigned __int64 bucketDuration, size_t validBuckets) +{ + if (_bucketDuration != INVALID_BUCKET_DURATION) + { + throw std::runtime_error("IoBucketizer has already been initialized"); + } + if (bucketDuration == INVALID_BUCKET_DURATION) + { + throw std::invalid_argument("Bucket duration must be a positive integer"); + } + + _bucketDuration = bucketDuration; + _validBuckets = validBuckets; + _vBuckets.reserve(_validBuckets); +} + +void IoBucketizer::Add(unsigned __int64 ioCompletionTime) +{ + if (_bucketDuration == INVALID_BUCKET_DURATION) + { + throw std::runtime_error("IoBucketizer has not been initialized"); + } + + size_t bucketNumber = static_cast(ioCompletionTime / _bucketDuration); + size_t currentSize = _vBuckets.size(); + if (currentSize < bucketNumber + 1) + { + _vBuckets.resize(bucketNumber + 1); + // Zero the new entries. Note that size is 1-based and bucketNumber is 0-based. + for (size_t i = currentSize; i <= bucketNumber; i++) + { + _vBuckets[i] = 0; + } + } + _vBuckets[bucketNumber]++; +} + +size_t IoBucketizer::GetNumberOfValidBuckets() const +{ + // Buckets beyond this may exist since Add is willing to extend the vector + // beyond the expected number of valid buckets, but they are not comparable + // buckets (straggling IOs over the timespan boundary). + return (_vBuckets.size() > _validBuckets ? _validBuckets : _vBuckets.size()); +} + +size_t IoBucketizer::GetNumberOfBuckets() const +{ + return _vBuckets.size(); +} + +unsigned int IoBucketizer::GetIoBucket(size_t bucketNumber) const +{ + return _vBuckets[bucketNumber]; +} + +double IoBucketizer::_GetMean() const +{ + size_t numBuckets = GetNumberOfValidBuckets(); + double sum = 0; + + for (size_t i = 0; i < numBuckets; i++) + { + sum += static_cast(_vBuckets[i]) / numBuckets; + } + + return sum; +} + +double IoBucketizer::GetStandardDeviation() const +{ + size_t numBuckets = GetNumberOfValidBuckets(); + + if(numBuckets == 0) + { + return 0.0; + } + + double mean = _GetMean(); + double ssd = 0; + + for (size_t i = 0; i < numBuckets; i++) + { + double dev = static_cast(_vBuckets[i]) - mean; + double sqdev = dev*dev; + ssd += sqdev; + } + + return sqrt(ssd / numBuckets); +} + +void IoBucketizer::Merge(const IoBucketizer& other) +{ + if(other._vBuckets.size() > _vBuckets.size()) + { + _vBuckets.resize(other._vBuckets.size()); + } + if (other._validBuckets > _validBuckets) + { + _validBuckets = other._validBuckets; + } + for(size_t i = 0; i < other._vBuckets.size(); i++) + { + _vBuckets[i] += other.GetIoBucket(i); + } +} \ No newline at end of file diff --git a/CristalDiskMark/source/diskspd2_0_15a/Common/IoBucketizer.h b/CristalDiskMark/source/diskspd2_0_15a/Common/IoBucketizer.h new file mode 100644 index 0000000..512c15d --- /dev/null +++ b/CristalDiskMark/source/diskspd2_0_15a/Common/IoBucketizer.h @@ -0,0 +1,52 @@ +/* + +DISKSPD + +Copyright(c) Microsoft Corporation +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#pragma once + +#include + +class IoBucketizer +{ +public: + IoBucketizer(); + void Initialize(unsigned __int64 bucketDuration, size_t validBuckets); + + size_t GetNumberOfValidBuckets() const; + size_t GetNumberOfBuckets() const; + unsigned int GetIoBucket(size_t bucketNumber) const; + void Add(unsigned __int64 ioCompletionTime); + double GetStandardDeviation() const; + void Merge(const IoBucketizer& other); +private: + double _GetMean() const; + + unsigned __int64 _bucketDuration; + size_t _validBuckets; + std::vector _vBuckets; +}; \ No newline at end of file diff --git a/CristalDiskMark/source/diskspd2_0_15a/DiskSpd_Documentation.docx b/CristalDiskMark/source/diskspd2_0_15a/DiskSpd_Documentation.docx new file mode 100644 index 0000000000000000000000000000000000000000..f0c963b2d2342983a64d4b7920d9e1c728c36858 GIT binary patch literal 220916 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

-V_E!ZkCQMN)V9A$U0nFF}nxSOGI$?AB! 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%0D4f%6qwsU_ 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�H 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 literal 0 HcmV?d00001 diff --git a/CristalDiskMark/source/diskspd2_0_15a/DiskSpd_Documentation.pdf b/CristalDiskMark/source/diskspd2_0_15a/DiskSpd_Documentation.pdf new file mode 100644 index 0000000000000000000000000000000000000000..a3105a6778541ac4ac167db5909435f7f62cce75 GIT binary patch literal 1277955 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�lt-qZLVhwEg`qN&5ryCh6VQy} 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 z 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%0DVNa>LO*~3`aWxX=#XG6QCo-}38uZ(tX% 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

L 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%0A7hW&B`(vbP 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¤-H6ss-K1=J{2G_i9hO)_*H@aKPvS2JQLFWM2nrl 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⪥UWatho-~7_2jk81L6Xl%%;x`o_U97yF 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 g{amlEoz2^NR)bgU5ej;N8zxHsJz0Z59>I5V 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�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

><0GaG39EeKdP|GLGQc~VOpd+VIWI=eiyKY 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 literal 0 HcmV?d00001 diff --git a/CristalDiskMark/source/diskspd2_0_15a/IORequestGenerator/IORequestGenerator.cpp b/CristalDiskMark/source/diskspd2_0_15a/IORequestGenerator/IORequestGenerator.cpp new file mode 100644 index 0000000..aa5d12c --- /dev/null +++ b/CristalDiskMark/source/diskspd2_0_15a/IORequestGenerator/IORequestGenerator.cpp @@ -0,0 +1,2771 @@ +/* + +DISKSPD + +Copyright(c) Microsoft Corporation +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +// IORequestGenerator.cpp : Defines the entry point for the DLL application. +// + +//FUTURE EXTENSION: make it compile with /W4 + +#ifndef _WIN32_WINNT + #define _WIN32_WINNT 0x0600 +#endif + +#ifndef _WIN32_IE + #define _WIN32_IE 0x0500 +#endif + +#include "common.h" +#include "IORequestGenerator.h" + +#include +#include +#include //DISK_GEOMETRY +#include +#include + +#include //WNODE_HEADER + +#include "etw.h" +#include +#include +#include "ThroughputMeter.h" +#include "OverlappedQueue.h" + +/*****************************************************************************/ +// gets partition size, return zero on failure +// +UINT64 GetPartitionSize(HANDLE hFile) +{ + assert(NULL != hFile && INVALID_HANDLE_VALUE != hFile); + + PARTITION_INFORMATION pinf; + OVERLAPPED ovlp = {}; + + ovlp.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); + if (ovlp.hEvent == nullptr) + { + PrintError("ERROR: Failed to create event (error code: %u)\n", GetLastError()); + return 0; + } + + DWORD rbcnt = 0; + DWORD status = ERROR_SUCCESS; + BOOL rslt; + + rslt = DeviceIoControl(hFile, + IOCTL_DISK_GET_PARTITION_INFO, + NULL, + 0, + &pinf, + sizeof(pinf), + &rbcnt, + &ovlp); + + if (!rslt) + { + status = GetLastError(); + if (status == ERROR_IO_PENDING) + { + if (WAIT_OBJECT_0 != WaitForSingleObject(ovlp.hEvent, INFINITE)) + { + PrintError("ERROR: Failed while waiting for event to be signaled (error code: %u)\n", GetLastError()); + } + else + { + rslt = TRUE; + } + } + else + { + PrintError("ERROR: Could not obtain partition info (error code: %u)\n", status); + } + } + + CloseHandle(ovlp.hEvent); + + if (!rslt) + { + return 0; + } + + return pinf.PartitionLength.QuadPart; +} + +/*****************************************************************************/ +// gets physical drive size, return zero on failure +// +UINT64 GetPhysicalDriveSize(HANDLE hFile) +{ + assert(NULL != hFile && INVALID_HANDLE_VALUE != hFile); + + DISK_GEOMETRY geom; + OVERLAPPED ovlp = {}; + + ovlp.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); + if (ovlp.hEvent == nullptr) + { + PrintError("ERROR: Failed to create event (error code: %u)\n", GetLastError()); + return 0; + } + + DWORD rbcnt = 0; + DWORD status = ERROR_SUCCESS; + BOOL rslt; + + rslt = DeviceIoControl(hFile, + IOCTL_DISK_GET_DRIVE_GEOMETRY, + NULL, + 0, + &geom, + sizeof(geom), + &rbcnt, + &ovlp); + + if (!rslt) + { + status = GetLastError(); + if (status == ERROR_IO_PENDING) + { + if (WAIT_OBJECT_0 != WaitForSingleObject(ovlp.hEvent, INFINITE)) + { + PrintError("ERROR: Failed while waiting for event to be signaled (error code: %u)\n", GetLastError()); + } + else + { + rslt = TRUE; + } + } + else + { + PrintError("ERROR: Could not obtain drive geometry (error code: %u)\n", status); + } + } + + CloseHandle(ovlp.hEvent); + + if (!rslt) + { + return 0; + } + + return (UINT64)geom.BytesPerSector * + (UINT64)geom.SectorsPerTrack * + (UINT64)geom.TracksPerCylinder * + (UINT64)geom.Cylinders.QuadPart; +} + +/*****************************************************************************/ +// activates specified privilege in process token +// +bool SetPrivilege(LPCSTR pszPrivilege) +{ + TOKEN_PRIVILEGES TokenPriv; + HANDLE hToken = INVALID_HANDLE_VALUE; + DWORD dwError; + bool fOk = true; + + if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken)) + { + PrintError("Error opening process token (error code: %u)\n", GetLastError()); + fOk = false; + goto cleanup; + } + + TokenPriv.PrivilegeCount = 1; + TokenPriv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; + if (!LookupPrivilegeValue(nullptr, pszPrivilege, &TokenPriv.Privileges[0].Luid)) + { + PrintError("Error looking up privilege value %s (error code: %u)\n", pszPrivilege, GetLastError()); + fOk = false; + goto cleanup; + } + + if (!AdjustTokenPrivileges(hToken, FALSE, &TokenPriv, 0, nullptr, nullptr)) + { + PrintError("Error adjusting token privileges for %s (error code: %u)\n", pszPrivilege, GetLastError()); + fOk = false; + goto cleanup; + } + + if (ERROR_SUCCESS != (dwError = GetLastError())) + { + PrintError("Error adjusting token privileges for %s (error code: %u)\n", pszPrivilege, dwError); + fOk = false; + goto cleanup; + } + +cleanup: + if (hToken != INVALID_HANDLE_VALUE) + { + CloseHandle(hToken); + } + + return fOk; +} + +/*****************************************************************************/ +// structures and global variables +// +struct ETWEventCounters g_EtwEventCounters; + +__declspec(align(4)) static LONG volatile g_lRunningThreadsCount = 0; //must be aligned on a 32-bit boundary, otherwise InterlockedIncrement + //and InterlockedDecrement will fail on 64-bit systems + +static ULONG volatile g_ulProcCount = 0; //number of CPUs present in the system +static BOOL volatile g_bRun; //used for letting threads know that they should stop working + +typedef NTSTATUS (__stdcall *NtQuerySysInfo)(SYSTEM_INFORMATION_CLASS, PVOID, ULONG, PULONG); +static NtQuerySysInfo g_pfnNtQuerySysInfo; + +static PRINTF g_pfnPrintOut = nullptr; +static PRINTF g_pfnPrintError = nullptr; +static PRINTF g_pfnPrintVerbose = nullptr; + +static BOOL volatile g_bThreadError = FALSE; //true means that an error has occured in one of the threads +BOOL volatile g_bTracing = TRUE; //true means that ETW is turned on + +// TODO: is this still needed? +__declspec(align(4)) static LONG volatile g_lGeneratorRunning = 0; //used to detect if GenerateRequests is already running + +static BOOL volatile g_bError = FALSE; //true means there was fatal error during intialization and threads shouldn't perform their work + +/*****************************************************************************/ +//structure and functions to get system groups and processors information +#define MAXIMUM_GROUPS_LARGE 32 + +typedef struct { + WORD wActiveGroupCount; //number of groups in the system + DWORD dwaActiveProcsCount[MAXIMUM_GROUPS_LARGE]; //number of processors per group +} ACTIVE_GROUPS_AND_PROCS, *PACTIVE_GROUPS_AND_PROCS; + +PACTIVE_GROUPS_AND_PROCS g_pActiveGroupsAndProcs; + +//Win7 kernel32.dll groups and processors exported functions +#define GET_ACTIVE_PROCESSOR_GROUP_COUNT ("GetActiveProcessorGroupCount") +#define GET_ACTIVE_PROCESSOR_COUNT ("GetActiveProcessorCount") +#define SET_THREAD_GROUP_AFFINITY ("SetThreadGroupAffinity") + +typedef WORD (WINAPI *PFN_GET_ACTIVE_PROCESSOR_GROUP_COUNT) (VOID); +typedef DWORD (WINAPI *PFN_GET_ACTIVE_PROCESSOR_COUNT) (WORD GroupNumber); +typedef DWORD (WINAPI *PFN_SET_THREAD_GROUP_AFFINITY) (HANDLE hThread, const GROUP_AFFINITY * pGroupAffinity, PGROUP_AFFINITY PreviousGroupAffinity); + +// for XP/2003 support +#define SET_FILE_INFORMATION_BY_HANDLE ("SetFileInformationByHandle") +typedef BOOL(WINAPI *NT6_SET_FILE_INFORMATION_BY_HANDLE) (HANDLE hFile, FILE_INFO_BY_HANDLE_CLASS FileInformationClass, LPVOID lpFileInformation, DWORD dwBufferSize); + +bool IORequestGenerator::_GetActiveGroupsAndProcs() const +{ + HMODULE kernel32; + PFN_GET_ACTIVE_PROCESSOR_GROUP_COUNT GetActiveProcessorGroupCount; + PFN_GET_ACTIVE_PROCESSOR_COUNT GetActiveProcessorCount; + WORD wActiveGroupCtr = 0; + SYSTEM_INFO SystemInfo; + + //load kernel32.dll + kernel32 = LoadLibraryExW(L"kernel32.dll", NULL, 0); + if (kernel32 == NULL) + { + PrintError("ERROR: kernel32.dll library failed to load!\r\n"); + return false; + } + + //get function address from kernel32.dll for groups + GetActiveProcessorGroupCount = (PFN_GET_ACTIVE_PROCESSOR_GROUP_COUNT)GetProcAddress(kernel32, GET_ACTIVE_PROCESSOR_GROUP_COUNT); + + if (GetActiveProcessorGroupCount != NULL) + { + g_pActiveGroupsAndProcs->wActiveGroupCount = GetActiveProcessorGroupCount(); + + //verify that group count number is not bigger than maximume groups supported by the OS + if (g_pActiveGroupsAndProcs->wActiveGroupCount > MAXIMUM_GROUPS_LARGE) + { + PrintError("ERROR: pActiveGroupsAndProcs->wActiveGroupCount = %d\r\n", g_pActiveGroupsAndProcs->wActiveGroupCount); + PrintError("ERROR: Incorrect value; there can be max %d groups in the system\r\n", MAXIMUM_GROUPS_LARGE); + return false; + } + + //get function address from kernel32.dll for processors per group + GetActiveProcessorCount = (PFN_GET_ACTIVE_PROCESSOR_COUNT)GetProcAddress(kernel32, GET_ACTIVE_PROCESSOR_COUNT); + + if (GetActiveProcessorCount != NULL) + { + g_ulProcCount = 0; + + //get number of processors per group + for (wActiveGroupCtr = 0; wActiveGroupCtr < g_pActiveGroupsAndProcs->wActiveGroupCount; wActiveGroupCtr++) + { + g_pActiveGroupsAndProcs->dwaActiveProcsCount[wActiveGroupCtr] = + GetActiveProcessorCount(wActiveGroupCtr); + g_ulProcCount += g_pActiveGroupsAndProcs->dwaActiveProcsCount[wActiveGroupCtr]; + } + } + else + { + PrintError("ERROR: GetActiveProcessorCount address not obtained with error: %d.!\r\n", GetLastError()); + return false; + } + } + else + { + g_pActiveGroupsAndProcs->wActiveGroupCount = 1; + g_pActiveGroupsAndProcs->dwaActiveProcsCount[0] = 0; + + GetSystemInfo(&SystemInfo); + g_pActiveGroupsAndProcs->dwaActiveProcsCount[0] = SystemInfo.dwNumberOfProcessors; + g_ulProcCount = g_pActiveGroupsAndProcs->dwaActiveProcsCount[0]; + + if (g_ulProcCount < 1) + { + PrintError("ERROR: Processor count = %d\n", g_pActiveGroupsAndProcs->dwaActiveProcsCount[0]); + PrintError("ERROR: Incorrect value; there has to be at least 1 processor in the system\n"); + return false; + } + } + if (g_pActiveGroupsAndProcs->wActiveGroupCount > 1 || g_ulProcCount > 64) + { + PrintError("WARNING: Complete CPU utilization cannot currently be gathered within DISKSPD for this system.\n" + " Use alternate mechanisms to gather this data such as perfmon/logman.\n" + " Active KGroups %u > 1 and/or processor count %u > 64.\n", + g_pActiveGroupsAndProcs->wActiveGroupCount, + g_ulProcCount); + } + return true; +} + +VOID SetProcGroupMask(WORD wGroupNum, DWORD dwProcNum, GROUP_AFFINITY *pGroupAffinity) +{ + //must zero this structure first, otherwise it fails to set affinity + memset(pGroupAffinity, 0, sizeof(GROUP_AFFINITY)); + + pGroupAffinity->Group = (USHORT)wGroupNum; + pGroupAffinity->Mask = (KAFFINITY)1<Mask)); + if (dwpPrevMask == 0) + { + PrintError("ERROR: SetThreadAffinityMask failed with error: %d.!\r\n", GetLastError()); + return FALSE; + } + + return TRUE; + } +} + +/*****************************************************************************/ +void IORequestGenerator::_CloseOpenFiles(vector& vhFiles) const +{ + for (size_t x = 0; x < vhFiles.size(); ++x) + { + if ((INVALID_HANDLE_VALUE != vhFiles[x]) && (nullptr != vhFiles[x])) + { + if (!CloseHandle(vhFiles[x])) + { + PrintError("Warning: unable to close file handle (error code: %u)\n", GetLastError()); + } + vhFiles[x] = nullptr; + } + } +} + +/*****************************************************************************/ +// wrapper for pfnPrintOut. printf cannot be used directly, because IORequestGenerator.dll +// may be consumed by gui app which doesn't have stdout +static void print(const char *format, ...) +{ + assert(NULL != format); + + if( NULL != g_pfnPrintOut ) + { + va_list listArg; + va_start(listArg, format); + g_pfnPrintOut(format, listArg); + va_end(listArg); + } +} + +/*****************************************************************************/ +// wrapper for pfnPrintError. fprintf(stderr) cannot be used directly, because IORequestGenerator.dll +// may be consumed by gui app which doesn't have stdout +void PrintError(const char *format, ...) +{ + assert(NULL != format); + + if( NULL != g_pfnPrintError ) + { + va_list listArg; + + va_start(listArg, format); + g_pfnPrintError(format, listArg); + va_end(listArg); + } +} + +/*****************************************************************************/ +// prints the string only if verbose mode is set to true +// +static void printfv(bool fVerbose, const char *format, ...) +{ + assert(NULL != format); + + if( NULL != g_pfnPrintVerbose && fVerbose ) + { + va_list argList; + va_start(argList, format); + g_pfnPrintVerbose(format, argList); + va_end(argList); + } +} + +/*****************************************************************************/ +// thread for gathering ETW data (etw functions are defined in etw.cpp) +// +DWORD WINAPI etwThreadFunc(LPVOID cookie) +{ + UNREFERENCED_PARAMETER(cookie); + + g_bTracing = TRUE; + BOOL result = TraceEvents(); + g_bTracing = FALSE; + + return result ? 0 : 1; +} + +/*****************************************************************************/ +// display file size in a user-friendly form using 'verbose' stream +// +void IORequestGenerator::_DisplayFileSizeVerbose(bool fVerbose, UINT64 fsize) const +{ + if( fsize > (UINT64)10*1024*1024*1024 ) // > 10GB + { + printfv(fVerbose, "%I64uGB", fsize >> 30); + } + else if( fsize > (UINT64)10*1024*1024 ) // > 10MB + { + printfv(fVerbose, "%I64uMB", fsize >> 20); + } + else if( fsize > 10*1024 ) // > 10KB + { + printfv(fVerbose, "%I64uKB", fsize >> 10); + } + else + { + printfv(fVerbose, "%I64uB", fsize); + } +} + +/*****************************************************************************/ +// generate 64-bit random number +static ULONG64 rand64() +{ + return + ((((ULONG64)rand()) & 0x7fff) | + ((((ULONG64)rand()) & 0x7fff) << 15) | + ((((ULONG64)rand()) & 0x7fff) << 30) | + (((((ULONG64)rand()) & 0x7fff) << 30) << 15) | + (((((ULONG64)rand()) & 0xF) << 30) << 30)); +} + +/*****************************************************************************/ +bool IORequestGenerator::_LoadDLLs() +{ + _hNTDLL = LoadLibraryExW(L"ntdll.dll", nullptr, 0); + if( nullptr == _hNTDLL ) + { + return false; + } + + g_pfnNtQuerySysInfo = (NtQuerySysInfo)GetProcAddress(_hNTDLL, "NtQuerySystemInformation"); + if( nullptr == g_pfnNtQuerySysInfo ) + { + return false; + } + + return true; +} + +/*****************************************************************************/ +// returns the number of CPUs present in the system +// +static ULONG getProcessorCount() +{ + SYSTEM_INFO SystemInfo; + + // get system information + GetSystemInfo(&SystemInfo); + + // and extract number or processors from there + return (ULONG)SystemInfo.dwNumberOfProcessors; +} + +/*****************************************************************************/ +// returns affinity mask +// +static DWORD_PTR getCPUMask(ULONG ulProcNum) +{ + assert(ulProcNum < 8 * sizeof(DWORD_PTR)); + + return ((DWORD_PTR)1) << ulProcNum; +} + +/*****************************************************************************/ +bool IORequestGenerator::_GetSystemPerfInfo(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION *pInfo, UINT32 uCpuCount) const +{ + NTSTATUS Status = NO_ERROR; + + assert(NULL != pInfo); + assert(uCpuCount > 0); + + Status = g_pfnNtQuerySysInfo(SystemProcessorPerformanceInformation, + pInfo, + sizeof(*pInfo) * uCpuCount, + NULL); + + return NT_SUCCESS(Status); +} + +/*****************************************************************************/ +// calculate the offset of the next I/O operation +// + +__inline UINT64 IORequestGenerator::GetNextFileOffset(ThreadParameters& tp, size_t targetNum, UINT64 prevOffset) +{ + Target &target = tp.vTargets[targetNum]; + + UINT64 blockAlignment = target.GetBlockAlignmentInBytes(); + UINT64 baseFileOffset = target.GetBaseFileOffsetInBytes(); + UINT64 blockSize = target.GetBlockSizeInBytes(); + UINT64 nextBlockOffset; + + // increment/produce - note, logically relative to base offset + if (target.GetUseRandomAccessPattern()) + { + nextBlockOffset = rand64(); + nextBlockOffset -= (nextBlockOffset % blockAlignment); + } + else if (target.GetUseParallelAsyncIO()) + { + nextBlockOffset = prevOffset - baseFileOffset + blockAlignment; + } + else if (target.GetUseInterlockedSequential()) + { + nextBlockOffset = InterlockedAdd64((PLONGLONG) &tp.pullSharedSequentialOffsets[targetNum], blockAlignment) - blockAlignment; + } + else // normal sequential access pattern + { + nextBlockOffset = (tp.vullPrivateSequentialOffsets[targetNum] += blockAlignment); + } + + // now apply bounds for IO offset + // aligned target size is the closed interval of byte offsets at which it is legal to issue IO + // ISSUE IMPROVEMENT: much of this should be precalculated. It belongs within Target, which will + // need discovery of target sizing moved from its current just-in-time at thread launch. + UINT64 alignedTargetSize = tp.vullFileSizes[targetNum] - baseFileOffset - blockSize; + if (target.GetUseRandomAccessPattern() || + target.GetUseInterlockedSequential()) + { + // these access patterns occur on blockaligned boundaries relative to base + // convert aligned target size to the open interval + alignedTargetSize = ((alignedTargetSize / blockAlignment) + 1) * blockAlignment; + nextBlockOffset %= alignedTargetSize; + } + else + { + // parasync and seq bases are potentially modified by threadstride and loop back to the + // file base offset + increment which will return them to their initial base offset. + if (nextBlockOffset > alignedTargetSize) + { + nextBlockOffset = (IORequestGenerator::GetThreadBaseFileOffset(tp, targetNum) - baseFileOffset) % blockAlignment; + tp.vullPrivateSequentialOffsets[targetNum] = nextBlockOffset; + } + } + + // Convert into the next full offset + nextBlockOffset += baseFileOffset; + +#ifndef NDEBUG + // Don't overrun the end of the file + UINT64 fileSize = tp.vullFileSizes[targetNum]; + assert(nextBlockOffset + blockSize <= fileSize); +#endif + + return nextBlockOffset; +} + +__inline UINT64 IORequestGenerator::GetThreadBaseFileOffset(ThreadParameters& tp, size_t targetNum) +{ + const Target &target = tp.vTargets[targetNum]; + + UINT64 baseFileOffset = target.GetBaseFileOffsetInBytes(); + UINT64 nextBlockOffset; + + if (target.GetUseRandomAccessPattern()) + { + nextBlockOffset = IORequestGenerator::GetNextFileOffset(tp, targetNum, 0); + } + else + { + // interlocked sequential - thread stride is always zero, enforced during profile validation + // parallel async - apply thread stride + // sequential - apply thread stride + nextBlockOffset = baseFileOffset + tp.ulRelativeThreadNo * target.GetThreadStrideInBytes(); + } + + return nextBlockOffset; +} + +__inline UINT64 IORequestGenerator::GetStartingFileOffset(ThreadParameters& tp, size_t targetNum) +{ + const Target &target = tp.vTargets[targetNum]; + + UINT64 baseFileOffset = target.GetBaseFileOffsetInBytes(); + UINT64 nextBlockOffset; + + if (target.GetUseRandomAccessPattern()) + { + nextBlockOffset = IORequestGenerator::GetNextFileOffset(tp, targetNum, 0); + } + else + { + // interlocked sequential - getnext starts the clock from zero, thread independent + // parallel async - getthreadbase, thread dependent + // sequential - "", and initialize private counter + if (target.GetUseInterlockedSequential()) + { + nextBlockOffset = IORequestGenerator::GetNextFileOffset(tp, targetNum, 0); + } + else + { + nextBlockOffset = IORequestGenerator::GetThreadBaseFileOffset(tp, targetNum); + + if (!target.GetUseParallelAsyncIO()) + { + tp.vullPrivateSequentialOffsets[targetNum] = nextBlockOffset - baseFileOffset; + } + } + } + + return nextBlockOffset; +} + +/*****************************************************************************/ +// Decide the kind of IO to issue during a mix test +// Future Work: Add more types of distribution in addition to random +__inline static IOOperation DecideIo(UINT32 ulWriteRatio) +{ + return (((UINT32)abs(rand() % 100 + 1)) > ulWriteRatio) ? IOOperation::ReadIO : IOOperation::WriteIO; + } + +/*****************************************************************************/ +// function called from worker thread +// performs asynch I/O using IO Completion Ports +// +__inline static bool doWorkUsingIOCompletionPorts(ThreadParameters *p, HANDLE hCompletionPort) +{ + assert(nullptr!= p); + assert(nullptr != hCompletionPort); + + bool fOk = true; + + LARGE_INTEGER li; + BOOL rslt = FALSE; + OVERLAPPED * pCompletedOvrp; + ULONG_PTR ulCompletionKey; + DWORD dwBytesTransferred; + DWORD dwIOCnt = 0; + OverlappedQueue overlappedQueue; + size_t cOverlapped = p->vOverlapped.size(); + + bool fMeasureLatency = p->pTimeSpan->GetMeasureLatency(); + + size_t cTargets = p->vTargets.size(); + vector vThroughputMeters(cTargets); + bool fUseThrougputMeter = false; + // TODO: move to a separate function + for (size_t i = 0; i < cTargets; i++) + { + Target *pTarget = &p->vTargets[i]; + DWORD dwBurstSize = pTarget->GetBurstSize(); + if (p->pTimeSpan->GetThreadCount() > 0) + { + dwBurstSize /= p->pTimeSpan->GetThreadCount(); + } + else + { + dwBurstSize /= pTarget->GetThreadsPerFile(); + } + + if (pTarget->GetThroughputInBytesPerMillisecond() > 0 || pTarget->GetThinkTime() > 0) + { + fUseThrougputMeter = true; + vThroughputMeters[i].Start(pTarget->GetThroughputInBytesPerMillisecond(), pTarget->GetBlockSizeInBytes(), pTarget->GetThinkTime(), dwBurstSize); + } + } + + //start IO operations + for (size_t i = 0; i < cOverlapped; i++) + { + overlappedQueue.Add(&p->vOverlapped[i]); + } + + // + // perform work + // + while(g_bRun && !g_bThreadError) + { + DWORD dwMinSleepTime = ~((DWORD)0); + for (size_t i = 0; i < overlappedQueue.GetCount(); i++) + { + OVERLAPPED *pReadyOverlapped = overlappedQueue.Remove(); + DWORD iOverlapped = (DWORD)(pReadyOverlapped - &p->vOverlapped[0]); + size_t iTarget = p->vOverlappedIdToTargetId[iOverlapped]; + size_t iRequest = iOverlapped - p->vFirstOverlappedIdForTargetId[iTarget]; + Target *pTarget = &p->vTargets[iTarget]; + ThroughputMeter *pThroughputMeter = &vThroughputMeters[iTarget]; + + DWORD dwSleepTime = pThroughputMeter->GetSleepTime(); + if (pThroughputMeter->IsRunning() && dwSleepTime > 0) + { + dwMinSleepTime = min(dwMinSleepTime, dwSleepTime); + overlappedQueue.Add(pReadyOverlapped); + continue; + } + + if (fMeasureLatency) + { + p->vIoStartTimes[iOverlapped] = PerfTimer::GetTime(); // record IO start time + } + + IOOperation readOrWrite; + readOrWrite = p->vdwIoType[iOverlapped] = DecideIo(pTarget->GetWriteRatio()); + if (readOrWrite == IOOperation::ReadIO) + { + rslt = ReadFile(p->vhTargets[iTarget], p->GetReadBuffer(iTarget, iRequest), pTarget->GetBlockSizeInBytes(), nullptr, pReadyOverlapped); + } + else + { + rslt = WriteFile(p->vhTargets[iTarget], p->GetWriteBuffer(iTarget, iRequest), pTarget->GetBlockSizeInBytes(), nullptr, pReadyOverlapped); + } + + if (!rslt && GetLastError() != ERROR_IO_PENDING) + { + PrintError("t[%u] error during %s error code: %u)\n", iOverlapped, (readOrWrite == IOOperation::ReadIO ? "read" : "write"), GetLastError()); + fOk = false; + goto cleanup; + } + + if (pThroughputMeter->IsRunning()) + { + pThroughputMeter->Adjust(pTarget->GetBlockSizeInBytes()); + } + } + + // if no IOs are in flight, wait for the next scheduling time + if (fUseThrougputMeter && (overlappedQueue.GetCount() == p->vOverlapped.size()) && dwMinSleepTime != ~((DWORD)0)) + { + Sleep(dwMinSleepTime); + } + + // wait till one of the IO operations finishes + if (GetQueuedCompletionStatus(hCompletionPort, &dwBytesTransferred, &ulCompletionKey, &pCompletedOvrp, 1) != 0) + { + //find which I/O operation it was (so we know to which buffer should we use) + DWORD iOverlapped = (DWORD)(pCompletedOvrp - &p->vOverlapped[0]); + size_t iTarget = p->vOverlappedIdToTargetId[iOverlapped]; + + //check if I/O transferred all of the requested bytes + Target *pTarget = &p->vTargets[iTarget]; + if (dwBytesTransferred != pTarget->GetBlockSizeInBytes()) + { + PrintError("Warning: thread %u transferred %u bytes instead of %u bytes\n", + p->ulThreadNo, + dwBytesTransferred, + pTarget->GetBlockSizeInBytes()); + } + + li.HighPart = pCompletedOvrp->OffsetHigh; + li.LowPart = pCompletedOvrp->Offset; + + if (*p->pfAccountingOn) + { + p->pResults->vTargetResults[iTarget].Add(dwBytesTransferred, + p->vdwIoType[iOverlapped], + &p->vIoStartTimes[iOverlapped], + p->pullStartTime, + fMeasureLatency, + p->pTimeSpan->GetCalculateIopsStdDev()); + } + + // TODO: move to a separate function + // check if we should print a progress dot + if (p->pProfile->GetProgress() != 0) + { + ++dwIOCnt; + if (dwIOCnt == p->pProfile->GetProgress()) + { + print("."); + dwIOCnt = 0; + } + } + + //restart the I/O operation that just completed + li.QuadPart = IORequestGenerator::GetNextFileOffset(*p, iTarget, li.QuadPart); + + pCompletedOvrp->Offset = li.LowPart; + pCompletedOvrp->OffsetHigh = li.HighPart; + + printfv(p->pProfile->GetVerbose(), "t[%u:%u] new I/O op at %I64u (starting in block: %I64u)\n", + p->ulThreadNo, + iTarget, + li.QuadPart, + li.QuadPart / pTarget->GetBlockSizeInBytes()); + + overlappedQueue.Add(pCompletedOvrp); + } + else + { + DWORD err = GetLastError(); + if (err != WAIT_TIMEOUT) + { + PrintError("error during overlapped IO operation (error code: %u)\n", err); + fOk = false; + goto cleanup; + } + } + } // end work loop + +cleanup: + return fOk; +} + +/*****************************************************************************/ +// I/O completion routine. used by ReadFileEx and WriteFileEx +// + +VOID CALLBACK fileIOCompletionRoutine(DWORD dwErrorCode, DWORD dwBytesTransferred, LPOVERLAPPED pOverlapped) +{ + assert(NULL != pOverlapped); + + BOOL rslt = FALSE; + LARGE_INTEGER li; + + ThreadParameters *p = (ThreadParameters *)pOverlapped->hEvent; + bool fMeasureLatency = p->pTimeSpan->GetMeasureLatency(); + + assert(NULL != p); + + //check error code + if (0 != dwErrorCode) + { + PrintError("Thread %u failed executing an I/O operation (error code: %u)\n", p->ulThreadNo, dwErrorCode); + goto cleanup; + } + + size_t iOverlapped = (pOverlapped - &p->vOverlapped[0]); + size_t iTarget = p->vOverlappedIdToTargetId[iOverlapped]; + Target *pTarget = &p->vTargets[iTarget]; + + //check if I/O operation transferred requested number of bytes + if (dwBytesTransferred != pTarget->GetBlockSizeInBytes()) + { + PrintError("Warning: thread %u transferred %u bytes instead of %u bytes\n", + p->ulThreadNo, + dwBytesTransferred, + pTarget->GetBlockSizeInBytes()); + } + + // check if we should print a progress dot + // BUGBUG: does not work ... io counter must be global + DWORD cdwIO = 0; + if (p->pProfile->GetProgress() != 0) + { + ++cdwIO; + if (cdwIO == p->pProfile->GetProgress()) + { + print("."); + cdwIO = 0; + } + } + + if (*p->pfAccountingOn) + { + p->pResults->vTargetResults[iTarget].Add(dwBytesTransferred, + p->vdwIoType[iOverlapped], + &p->vIoStartTimes[iOverlapped], + p->pullStartTime, + fMeasureLatency, + p->pTimeSpan->GetCalculateIopsStdDev()); + } + + //restart the I/O operation that just completed + li.HighPart = pOverlapped->OffsetHigh; + li.LowPart = pOverlapped->Offset; + + li.QuadPart = IORequestGenerator::GetNextFileOffset(*p, iTarget, li.QuadPart); + + pOverlapped->Offset = li.LowPart; + pOverlapped->OffsetHigh = li.HighPart; + + printfv(p->pProfile->GetVerbose(), "t[%u:%u] new I/O op at %I64u (starting in block: %I64u)\n", + p->ulThreadNo, + iTarget, + li.QuadPart, + li.QuadPart / pTarget->GetBlockSizeInBytes()); + + // start a new IO operation + if (g_bRun && !g_bThreadError) + { + size_t iRequest = iOverlapped - p->vFirstOverlappedIdForTargetId[iTarget]; + if (fMeasureLatency) + { + p->vIoStartTimes[iOverlapped] = PerfTimer::GetTime(); // record IO start time + } + + IOOperation readOrWrite; + readOrWrite = p->vdwIoType[iOverlapped] = DecideIo(pTarget->GetWriteRatio()); + if (readOrWrite == IOOperation::ReadIO) + { + rslt = ReadFileEx(p->vhTargets[iTarget], p->GetReadBuffer(iTarget, iRequest), pTarget->GetBlockSizeInBytes(), pOverlapped, fileIOCompletionRoutine); + } + else + { + rslt = WriteFileEx(p->vhTargets[iTarget], p->GetWriteBuffer(iTarget, iRequest), pTarget->GetBlockSizeInBytes(), pOverlapped, fileIOCompletionRoutine); + } + + if (!rslt) + { + PrintError("t[%u:%u] error during %s error code: %u)\n", p->ulThreadNo, iTarget, (readOrWrite == IOOperation::ReadIO ? "read" : "write"), GetLastError()); + goto cleanup; + } + } + +cleanup: + return; +} + +/*****************************************************************************/ +// function called from worker thread +// performs asynch I/O using IO Completion Routines (ReadFileEx, WriteFileEx) +// +__inline static bool doWorkUsingCompletionRoutines(ThreadParameters *p) +{ + assert(NULL != p); + bool fOk = true; + BOOL rslt = FALSE; + + //start IO operations + size_t iOverlapped = 0; + + bool fMeasureLatency = p->pTimeSpan->GetMeasureLatency(); + + for (size_t iTarget = 0; iTarget < p->vTargets.size(); iTarget++) + { + Target *pTarget = &p->vTargets[iTarget]; + for (size_t iRequest = 0; iRequest < pTarget->GetRequestCount(); ++iRequest) + { + if (fMeasureLatency) + { + p->vIoStartTimes[iOverlapped] = PerfTimer::GetTime(); // record IO start time + } + + IOOperation readOrWrite; + readOrWrite = p->vdwIoType[iOverlapped] = DecideIo(pTarget->GetWriteRatio()); + if (readOrWrite == IOOperation::ReadIO) + { + rslt = ReadFileEx(p->vhTargets[iTarget], p->GetReadBuffer(iTarget, iRequest), pTarget->GetBlockSizeInBytes(), &p->vOverlapped[iOverlapped], fileIOCompletionRoutine); + } + else + { + rslt = WriteFileEx(p->vhTargets[iTarget], p->GetWriteBuffer(iTarget, iRequest), pTarget->GetBlockSizeInBytes(), &p->vOverlapped[iOverlapped], fileIOCompletionRoutine); + } + + if (!rslt) + { + PrintError("t[%u:%u] error during %s error code: %u)\n", p->ulThreadNo, iTarget, (readOrWrite == IOOperation::ReadIO ? "read" : "write"), GetLastError()); + fOk = false; + goto cleanup; + } + iOverlapped++; + } + } + + DWORD dwWaitResult = 0; + while( g_bRun && !g_bThreadError ) + { + dwWaitResult = WaitForSingleObjectEx(p->hEndEvent, INFINITE, TRUE); + + assert(WAIT_IO_COMPLETION == dwWaitResult || (WAIT_OBJECT_0 == dwWaitResult && (!g_bRun || g_bThreadError))); + + //check WaitForSingleObjectEx status + if( WAIT_IO_COMPLETION != dwWaitResult && WAIT_OBJECT_0 != dwWaitResult ) + { + PrintError("Error in thread %u during WaitForSingleObjectEx (in completion routines)\n", p->ulThreadNo); + fOk = false; + goto cleanup; + } + } +cleanup: + return fOk; +} + +/*****************************************************************************/ +// worker thread function +// +DWORD WINAPI threadFunc(LPVOID cookie) +{ + /// for XP/20003 support + static bool once = true; + NT6_SET_FILE_INFORMATION_BY_HANDLE Nt6SetFileInformationByHandle = NULL; + + if (once) + { + //load kernel32.dll + HMODULE kernel32; + kernel32 = LoadLibraryExW(L"kernel32.dll", NULL, 0); + if (kernel32 == NULL) + { + PrintError("ERROR: kernel32.dll library failed to load!\r\n"); + return FALSE; + } + + //get function address from kernel32.dll + Nt6SetFileInformationByHandle = (NT6_SET_FILE_INFORMATION_BY_HANDLE) GetProcAddress( + kernel32, SET_FILE_INFORMATION_BY_HANDLE); + + once = false; + } + /// + + + bool fOk = true; + ThreadParameters *p = reinterpret_cast(cookie); + HANDLE hCompletionPort = nullptr; + + bool fMeasureLatency = p->pTimeSpan->GetMeasureLatency(); + bool fCalculateIopsStdDev = p->pTimeSpan->GetCalculateIopsStdDev(); + UINT64 ioBucketDuration = 0; + UINT32 expectedNumberOfBuckets = 0; + if(fCalculateIopsStdDev) + { + UINT32 ioBucketDurationInMilliseconds = p->pTimeSpan->GetIoBucketDurationInMilliseconds(); + ioBucketDuration = PerfTimer::MillisecondsToPerfTime(ioBucketDurationInMilliseconds); + expectedNumberOfBuckets = Util::QuotientCeiling(p->pTimeSpan->GetDuration() * 1000, ioBucketDurationInMilliseconds); + } + + //set random seed (each thread has a different one) + srand(p->ulRandSeed); + + //affinity + ULONG ulGroupProcs = 0; + if (!p->pTimeSpan->GetGroupAffinity()) + { + assert(g_ulProcCount > 0); + ulGroupProcs = getProcessorCount(); + } + + //simple affinity + if (!p->pTimeSpan->GetDisableAffinity() && (p->pTimeSpan->GetAffinityAssignments().size() == 0) && !p->pTimeSpan->GetGroupAffinity()) + { + HANDLE hThread = GetCurrentThread(); + ULONG ulProcNum = p->ulThreadNo % ulGroupProcs; + printfv(p->pProfile->GetVerbose(), "affinitizing thread %u to CPU%u\n", p->ulThreadNo, ulProcNum); + + // set thread affinity + if (0 == SetThreadAffinityMask(hThread, getCPUMask(ulProcNum))) + { + PrintError("Error setting affinity mask in thread %u\n", p->ulThreadNo); + fOk = false; + goto cleanup; + } + + // set thread ideal processor + if ((DWORD)-1 == SetThreadIdealProcessor(hThread, ulProcNum)) + { + PrintError("Error setting ideal processor in thread %u\n", p->ulThreadNo); + fOk = false; + goto cleanup; + } + } + + //advanced affinity + if (!p->pTimeSpan->GetDisableAffinity() && (p->pTimeSpan->GetAffinityAssignments().size() > 0) && !p->pTimeSpan->GetGroupAffinity()) + { + vector vAffinity(p->pTimeSpan->GetAffinityAssignments()); + + ULONG ulProcNum = p->ulThreadNo % vAffinity.size(); + UINT32 proc = vAffinity[ulProcNum]; + + assert(proc < g_ulProcCount); + if (ulProcNum >= g_ulProcCount) + { + PrintError("Invalid affinity mask (CPU id cannot be larger than the number of CPUs in the system)\n"); + fOk = false; + goto cleanup; + } + + printfv(p->pProfile->GetVerbose(), "affinitizing thread %u to CPU%u\n", p->ulThreadNo, proc); + + HANDLE hThread = GetCurrentThread(); + + // set thread affinity + if (0 == SetThreadAffinityMask(hThread, getCPUMask(proc))) + { + PrintError("Error setting affinity mask in thread %u\n", p->ulThreadNo); + fOk = false; + goto cleanup; + } + + // set thread ideal processor + if ((DWORD)-1 == SetThreadIdealProcessor(hThread, proc)) + { + PrintError("Error setting ideal processor in thread %u\n", p->ulThreadNo); + fOk = false; + goto cleanup; + } + } + + //group affinity + if (!p->pTimeSpan->GetDisableAffinity() && (p->pTimeSpan->GetAffinityAssignments().size() == 0) && p->pTimeSpan->GetGroupAffinity()) + { + SetProcGroupMask(p->wGroupNum, p->dwProcNum, &p->GroupAffinity); + + HANDLE hThread = GetCurrentThread(); + if (SetThreadGroupAndProcAffinity(hThread, &p->GroupAffinity, nullptr) == FALSE) + { + PrintError("Error setting affinity mask in thread %u\n", p->ulThreadNo); + fOk = false; + goto cleanup; + } + } + + // adjust thread token if large pages are needed + for (auto pTarget = p->vTargets.begin(); pTarget != p->vTargets.end(); pTarget++) + { + if (pTarget->GetUseLargePages()) + { + if (!SetPrivilege(SE_LOCK_MEMORY_NAME)) + { + fOk = false; + goto cleanup; + } + break; + } + } + + // TODO: open files + size_t iTarget = 0; + for (auto pTarget = p->vTargets.begin(); pTarget != p->vTargets.end(); pTarget++) + { + bool fPhysical = false; + bool fPartition = false; + + string sPath(pTarget->GetPath()); + const char *filename = sPath.c_str(); + + const char *fname = nullptr; //filename (can point to physFN) + char physFN[32]; //disk/partition name + + if (NULL == filename || NULL == *(filename)) + { + PrintError("FATAL ERROR: invalid filename\n"); + fOk = false; + goto cleanup; + } + + //check if it is a physical drive + if ('#' == *filename && NULL != *(filename + 1)) + { + UINT32 nDriveNo = (UINT32)atoi(filename + 1); + fPhysical = true; + sprintf_s(physFN, 32, "\\\\.\\PhysicalDrive%u", nDriveNo); + fname = physFN; + } + + //check if it is a partition + if (!fPhysical && NULL != *(filename + 1) && NULL == *(filename + 2) && isalpha((unsigned char)filename[0]) && ':' == filename[1]) + { + fPartition = true; + + sprintf_s(physFN, 32, "\\\\.\\%c:", filename[0]); + fname = physFN; + } + + //check if it is a regular file + if (!fPhysical && !fPartition) + { + fname = sPath.c_str(); + } + + //set file flags + DWORD dwFlags = FILE_ATTRIBUTE_NORMAL; + + if (pTarget->GetSequentialScanHint()) + { + dwFlags |= FILE_FLAG_SEQUENTIAL_SCAN; + } + + if (pTarget->GetRandomAccessHint()) + { + dwFlags |= FILE_FLAG_RANDOM_ACCESS; + } + + if ((pTarget->GetRequestCount() > 1) || (p->vTargets.size() > 1)) + { + dwFlags |= FILE_FLAG_OVERLAPPED; + } + + if (pTarget->GetDisableOSCache()) + { + dwFlags |= FILE_FLAG_NO_BUFFERING; + } + + if (pTarget->GetDisableAllCache()) + { + dwFlags |= (FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH); + } + + DWORD dwDesiredAccess = 0; + if (pTarget->GetWriteRatio() == 0) + { + dwDesiredAccess = GENERIC_READ; + } + else if (pTarget->GetWriteRatio() == 100) + { + dwDesiredAccess = GENERIC_WRITE; + } + else + { + dwDesiredAccess = GENERIC_READ | GENERIC_WRITE; + } + + HANDLE hFile = CreateFile(fname, + dwDesiredAccess, + FILE_SHARE_READ | FILE_SHARE_WRITE, + nullptr, //security + OPEN_EXISTING, + dwFlags, //flags (add overlapping) + nullptr); //template file + if (INVALID_HANDLE_VALUE == hFile) + { + // TODO: error out + PrintError("Error opening file: %s [%u]\n", sPath.c_str(), GetLastError()); + fOk = false; + goto cleanup; + } + + p->vhTargets.push_back(hFile); + + //set IO priority + if (Nt6SetFileInformationByHandle && pTarget->GetIOPriorityHint() != IoPriorityHintNormal) + { + FILE_IO_PRIORITY_HINT_INFO hintInfo; + hintInfo.PriorityHint = pTarget->GetIOPriorityHint(); + if (!Nt6SetFileInformationByHandle(hFile, FileIoPriorityHintInfo, &hintInfo, sizeof(hintInfo))) + { + PrintError("Error setting IO priority for file: %s [%u]\n", sPath.c_str(), GetLastError()); + fOk = false; + goto cleanup; + } + } + + // obtain file/disk/partition size + { + UINT64 fsize = 0; //file size + + //check if it is a disk + if (fPhysical) + { + fsize = GetPhysicalDriveSize(hFile); + } + // check if it is a partition + else if (fPartition) + { + fsize = GetPartitionSize(hFile); + } + // it has to be a regular file + else + { + ULARGE_INTEGER ulsize; + + ulsize.LowPart = GetFileSize(hFile, &ulsize.HighPart); + if (INVALID_FILE_SIZE == ulsize.LowPart && GetLastError() != NO_ERROR) + { + PrintError("Error getting file size\n"); + fOk = false; + goto cleanup; + } + else + { + fsize = ulsize.QuadPart; + } + } + + // check if file size is valid (if it's == 0, it won't be useful) + if (0 == fsize) + { + // TODO: error out + PrintError("The file is too small or there has been an error during getting file size\n"); + fOk = false; + goto cleanup; + } + + if (fsize < pTarget->GetMaxFileSize()) + { + PrintError("Warning - file size is less than MaxFileSize\n"); + } + + if (pTarget->GetMaxFileSize() > 0) + { + // user wants to use only a part of the target + // if smaller, of course use the entire content + p->vullFileSizes.push_back(pTarget->GetMaxFileSize() > fsize ? fsize : pTarget->GetMaxFileSize()); + } + else + { + // the whole file will be used + p->vullFileSizes.push_back(fsize); + } + + UINT64 startingFileOffset = IORequestGenerator::GetThreadBaseFileOffset(*p, iTarget); + + // test whether the file is large enough for this thread to do work + if (startingFileOffset + pTarget->GetBlockSizeInBytes() >= p->vullFileSizes[iTarget]) + { + PrintError("The file is too small. File: '%s' relative thread %u size: %I64u, base offset: %I64u block size: %u\n", + pTarget->GetPath().c_str(), + p->ulRelativeThreadNo, + fsize, + pTarget->GetBaseFileOffsetInBytes(), + pTarget->GetBlockSizeInBytes()); + fOk = false; + goto cleanup; + } + + if (pTarget->GetUseRandomAccessPattern()) + { + printfv(p->pProfile->GetVerbose(), "thread %u starting: file '%s' relative thread %u random pattern\n", + p->ulThreadNo, + pTarget->GetPath().c_str(), + p->ulRelativeThreadNo); + } + else + { + printfv(p->pProfile->GetVerbose(), "thread %u starting: file '%s' relative thread %u file offset: %I64u (starting in block: %I64u)\n", + p->ulThreadNo, + pTarget->GetPath().c_str(), + p->ulRelativeThreadNo, + startingFileOffset, + startingFileOffset / pTarget->GetBlockSizeInBytes()); + } + } + + // allocate memory for a data buffer + if (!p->AllocateAndFillBufferForTarget(*pTarget)) + { + PrintError("FATAL ERROR: Could not allocate a buffer bytes for target '%s'. Error code: 0x%x\n", pTarget->GetPath().c_str(), GetLastError()); + fOk = false; + goto cleanup; + } + iTarget++; + } + + // TODO: copy parameters for better memory locality? + // TODO: tell the main thread we're ready + // TODO: wait for a signal to start + + printfv(p->pProfile->GetVerbose(), "thread %u started (random seed: %u)\n", p->ulThreadNo, p->ulRandSeed); + + // TODO: check if it's still used + LARGE_INTEGER li; //used for setting file positions, etc. + DWORD dwIOCnt = 0; //number of completed I/O operations since last progress dot + + p->vullPrivateSequentialOffsets.clear(); + p->vullPrivateSequentialOffsets.resize(p->vTargets.size()); + p->pResults->vTargetResults.clear(); + p->pResults->vTargetResults.resize(p->vTargets.size()); + for (size_t i = 0; i < p->vullFileSizes.size(); i++) + { + p->pResults->vTargetResults[i].sPath = p->vTargets[i].GetPath(); + p->pResults->vTargetResults[i].ullFileSize = p->vullFileSizes[i]; + if(fCalculateIopsStdDev) + { + p->pResults->vTargetResults[i].readBucketizer.Initialize(ioBucketDuration, expectedNumberOfBuckets); + p->pResults->vTargetResults[i].writeBucketizer.Initialize(ioBucketDuration, expectedNumberOfBuckets); + } + } + + // + // synchronous access + // + //FUTURE EXTENSION: enable asynchronous I/O even if only 1 outstanding I/O per file (requires another parameter) + + if (p->vTargets.size() == 1 && p->vTargets[0].GetRequestCount() == 1) + { + Target *pTarget = &p->vTargets[0]; + DWORD dwBytesTransferred = 0; + + //advance file pointer to base file offset + li.QuadPart = IORequestGenerator::GetStartingFileOffset(*p, 0); + printfv(p->pProfile->GetVerbose(), "t[%u] initial I/O op at %I64u (starting in block: %I64u)\n", + p->ulThreadNo, + li.QuadPart, + li.QuadPart / pTarget->GetBlockSizeInBytes()); + //FUTURE EXTENSION: file pointer should be set through OVERLAPPED stucture for consistency with other scenarios (unless this is suspected to be the common way in real scenarios) + if (!SetFilePointerEx(p->vhTargets[0], li, NULL, FILE_BEGIN)) + { + PrintError("Error setting file pointer. Error code: %d.\n", GetLastError()); + fOk = false; + goto cleanup; + } + + BOOL rslt = FALSE; + + assert(nullptr != p->hStartEvent); + + //wait for a signal to start + printfv(p->pProfile->GetVerbose(), "thread %u: waiting for a signal to start\n", p->ulThreadNo); + if (WAIT_FAILED == WaitForSingleObject(p->hStartEvent, INFINITE)) + { + PrintError("Waiting for a signal to start failed (error code: %u)\n", GetLastError()); + fOk = false; + goto cleanup; + } + printfv(p->pProfile->GetVerbose(), "thread %u: received signal to start\n", p->ulThreadNo); + + // TODO: check if this is needed + //check if everything is ok + if (g_bError) + { + fOk = false; + goto cleanup; + } + + // + // perform work + // + + assert(nullptr != p->vhTargets[0] ); + assert(pTarget->GetBlockSizeInBytes() > 0); + + ThroughputMeter throughputMeter; + DWORD dwSleepTime; + + DWORD dwBurstSize = pTarget->GetBurstSize(); + if (p->pTimeSpan->GetThreadCount() > 0) + { + dwBurstSize /= p->pTimeSpan->GetThreadCount(); + } + else + { + dwBurstSize /= pTarget->GetThreadsPerFile(); + } + throughputMeter.Start(pTarget->GetThroughputInBytesPerMillisecond(), pTarget->GetBlockSizeInBytes(), pTarget->GetThinkTime(), dwBurstSize); + + while(g_bRun && !g_bThreadError) + { + if (throughputMeter.IsRunning()) + { + dwSleepTime = throughputMeter.GetSleepTime(); + if (0 != dwSleepTime) + { + Sleep(dwSleepTime); + continue; + } + } + + //start read or write operation (depends of the type of test) + //first access is always performed on base offset (even in case of random access) + + UINT64 ullStartTime = 0; + + if (fMeasureLatency) + { + ullStartTime = PerfTimer::GetTime(); // record IO start time + } + + IOOperation readOrWrite; + readOrWrite = DecideIo(pTarget->GetWriteRatio()); + if (readOrWrite == IOOperation::ReadIO) + { + rslt = ReadFile(p->vhTargets[0], p->GetReadBuffer(0, 0), pTarget->GetBlockSizeInBytes(), &dwBytesTransferred, nullptr); + } + else + { + rslt = WriteFile(p->vhTargets[0], p->GetWriteBuffer(0, 0), pTarget->GetBlockSizeInBytes(), &dwBytesTransferred, nullptr); + } + + if (!rslt) + { + PrintError("t[%u:%u] error during %s error code: %u)\n", p->ulThreadNo, 0, (readOrWrite == IOOperation::ReadIO ? "read" : "write"), GetLastError()); + fOk = false; + goto cleanup; + } + + //check if I/O operation transferred requested number of bytes + if (dwBytesTransferred != pTarget->GetBlockSizeInBytes()) + { + PrintError("Warning: thread %u transfered %u bytes instead of %u bytes\n", p->ulThreadNo, dwBytesTransferred, pTarget->GetBlockSizeInBytes()); + } + + if (throughputMeter.IsRunning()) + { + throughputMeter.Adjust(pTarget->GetBlockSizeInBytes()); + } + + if (*p->pfAccountingOn) + { + p->pResults->vTargetResults[0].Add(dwBytesTransferred, + readOrWrite, + &ullStartTime, + p->pullStartTime, + fMeasureLatency, + fCalculateIopsStdDev); + } + + // check if we should print a progress dot + if (0 != p->pProfile->GetProgress() > 0) + { + ++dwIOCnt; + if (dwIOCnt == p->pProfile->GetProgress()) + { + print("."); + dwIOCnt = 0; + } + } + + li.QuadPart = IORequestGenerator::GetNextFileOffset(*p, 0, li.QuadPart); + + printfv(p->pProfile->GetVerbose(), "t[%u] new I/O op at %I64u (starting in block: %I64u)\n", + p->ulThreadNo, + li.QuadPart, + li.QuadPart / pTarget->GetBlockSizeInBytes()); + + if (!SetFilePointerEx(p->vhTargets[0], li, NULL, FILE_BEGIN)) + { + PrintError("thread %u: Error setting file pointer\n", p->ulThreadNo); + fOk = false; + goto cleanup; + } + + assert(!g_bError); // at this point we shouldn't be seeing initialization error + } + }//end of synchronous access + // + // overlapped IO operations + // + else + { + // + // create IO completion port + // + for (unsigned int i = 0; i < p->vTargets.size(); i++) + { + if (!p->pTimeSpan->GetCompletionRoutines()) + { + hCompletionPort = CreateIoCompletionPort(p->vhTargets[i], hCompletionPort, 0, 1); + if (nullptr == hCompletionPort) + { + PrintError("unable to create IO completion port (error code: %u)\n", GetLastError()); + fOk = false; + goto cleanup; + } + } + } + + // + // fill the OVERLAPPED structures + // + + UINT32 cOverlapped = p->GetTotalRequestCount(); + + p->vOverlapped.clear(); + p->vOverlapped.resize(cOverlapped); + + p->vdwIoType.clear(); + p->vdwIoType.resize(cOverlapped); + + p->vIoStartTimes.clear(); + p->vIoStartTimes.resize(cOverlapped); + + p->vFirstOverlappedIdForTargetId.clear(); + + UINT32 iOverlapped = 0; + for (unsigned int iFile = 0; iFile < p->vTargets.size(); iFile++) + { + Target *pTarget = &p->vTargets[iFile]; + + li.QuadPart = IORequestGenerator::GetStartingFileOffset(*p, iFile); + p->vFirstOverlappedIdForTargetId.push_back(iOverlapped); + + for (DWORD iRequest = 0; iRequest < pTarget->GetRequestCount(); ++iRequest) + { + // on increment, get next except in the case of parallel async, which all start at the initial offset. + // note that we must only do this when needed, since it will advance global state. + if (iRequest != 0 && !pTarget->GetUseParallelAsyncIO()) + { + li.QuadPart = IORequestGenerator::GetNextFileOffset(*p, iFile, li.QuadPart); + } + + p->vOverlappedIdToTargetId.push_back(iFile); + if (!p->pTimeSpan->GetCompletionRoutines()) + { + p->vOverlapped[iOverlapped].hEvent = nullptr; //we don't need event, because we use IO completion port + } + else + { + //in case of completion routines hEvent field is not used, + //so we can use it to pass a pointer to the thread parameters + p->vOverlapped[iOverlapped].hEvent = (HANDLE)p; + } + + printfv(p->pProfile->GetVerbose(), "t[%u:%u] initial I/O op at %I64u (starting in block: %I64u)\n", + p->ulThreadNo, + iFile, + li.QuadPart, + li.QuadPart / pTarget->GetBlockSizeInBytes()); + + p->vOverlapped[iOverlapped].Offset = li.LowPart; + p->vOverlapped[iOverlapped].OffsetHigh = li.HighPart; + + ++iOverlapped; + } + } + + // + // wait for a signal to start + // + printfv(p->pProfile->GetVerbose(), "thread %u: waiting for a signal to start\n", p->ulThreadNo); + if( WAIT_FAILED == WaitForSingleObject(p->hStartEvent, INFINITE) ) + { + PrintError("Waiting for a signal to start failed (error code: %u)\n", GetLastError()); + fOk = false; + goto cleanup; + } + printfv(p->pProfile->GetVerbose(), "thread %u: received signal to start\n", p->ulThreadNo); + + //check if everything is ok + if (g_bError) + { + fOk = false; + goto cleanup; + } + + //error handling and memory freeing is done in doWorkUsingIOCompletionPorts and doWorkUsingCompletionRoutines + if (!p->pTimeSpan->GetCompletionRoutines()) + { + // use IO Completion Ports (it will also close the I/O completion port) + if (!doWorkUsingIOCompletionPorts(p, hCompletionPort)) + { + fOk = false; + goto cleanup; + } + } + else + { + //use completion routines + if (!doWorkUsingCompletionRoutines(p)) + { + fOk = false; + goto cleanup; + } + } + + assert(!g_bError); // at this point we shouldn't be seeing initialization error + } // end of overlapped IO operations + + // save results + +cleanup: + if (!fOk) + { + g_bThreadError = TRUE; + } + + // free memory allocated with VirtualAlloc + for (auto i = p->vpDataBuffers.begin(); i != p->vpDataBuffers.end(); i++) + { + if (nullptr != *i) + { +#pragma prefast(suppress:6001, "Prefast does not understand this vector will only contain validly allocated buffer pointers") + VirtualFree(*i, 0, MEM_RELEASE); + } + } + + // close files + for (auto i = p->vhTargets.begin(); i != p->vhTargets.end(); i++) + { + CloseHandle(*i); + } + + // close completion ports + if (hCompletionPort != nullptr) + { + CloseHandle(hCompletionPort); + } + + delete p; + + // notify master thread that we've finished + InterlockedDecrement(&g_lRunningThreadsCount); + + return fOk ? 1 : 0; +} + +/*****************************************************************************/ +struct ETWSessionInfo IORequestGenerator::_GetResultETWSession(const EVENT_TRACE_PROPERTIES *pTraceProperties) const +{ + struct ETWSessionInfo session = {}; + if (nullptr != pTraceProperties) + { + session.lAgeLimit = pTraceProperties->AgeLimit; + session.ulBufferSize = pTraceProperties->BufferSize; + session.ulBuffersWritten = pTraceProperties->BuffersWritten; + session.ulEventsLost = pTraceProperties->EventsLost; + session.ulFlushTimer = pTraceProperties->FlushTimer; + session.ulFreeBuffers = pTraceProperties->FreeBuffers; + session.ulLogBuffersLost = pTraceProperties->LogBuffersLost; + session.ulMaximumBuffers = pTraceProperties->MaximumBuffers; + session.ulMinimumBuffers = pTraceProperties->MinimumBuffers; + session.ulNumberOfBuffers = pTraceProperties->NumberOfBuffers; + session.ulRealTimeBuffersLost = pTraceProperties->RealTimeBuffersLost; + } + return session; +} + +DWORD IORequestGenerator::_CreateDirectoryPath(const char *pszPath) const +{ + char *c = nullptr; //variable used to browse the path + char dirPath[MAX_PATH]; //copy of the path (it will be altered) + + //only support absolute paths that specify the drive letter + if (pszPath[0] == '\0' || pszPath[1] != ':') + { + return ERROR_NOT_SUPPORTED; + } + + if (strcpy_s(dirPath, _countof(dirPath), pszPath) != 0) + { + return ERROR_BUFFER_OVERFLOW; + } + + c = dirPath; + while('\0' != *c) + { + if ('\\' == *c) + { + //skip the first one as it will be the drive name + if (c-dirPath >= 3) + { + *c = '\0'; + //create directory if it doesn't exist + if (GetFileAttributes(dirPath) == INVALID_FILE_ATTRIBUTES) + { + if (CreateDirectory(dirPath, NULL) == FALSE) + { + return GetLastError(); + } + } + *c = L'\\'; + } + } + + c++; + } + + return ERROR_SUCCESS; +} + +/*****************************************************************************/ +// create a file of the given size +// +bool IORequestGenerator::_CreateFile(UINT64 ullFileSize, const char *pszFilename, bool fZeroBuffers, bool fVerbose) const +{ + bool fSlowWrites = false; + printfv(fVerbose, "Creating file '%s' of size %I64u.\n", pszFilename, ullFileSize); + + //enable SE_MANAGE_VOLUME_NAME privilege, required to set valid size of a file + if (!SetPrivilege(SE_MANAGE_VOLUME_NAME)) + { + PrintError("WARNING: Could not set privileges for setting valid file size; will use a slower method of preparing the file\n", GetLastError()); + fSlowWrites = true; + } + + // there are various forms of paths we do not support creating subdir hierarchies + // for - relative and unc paths specifically. this is fine, and not neccesary to + // warn about. we can add support in the future. + DWORD dwError = _CreateDirectoryPath(pszFilename); + if (dwError != ERROR_SUCCESS && dwError != ERROR_NOT_SUPPORTED) + { + PrintError("WARNING: Could not create intermediate directory (error code: %u)\n", dwError); + } + + //create handle to the file + HANDLE hFile = CreateFile(pszFilename, + GENERIC_WRITE, + FILE_SHARE_WRITE, + NULL, //security + CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, //flags + NULL); //template file + if (INVALID_HANDLE_VALUE == hFile) + { + PrintError("Could not create the file (error code: %u)\n", GetLastError()); + return false; + } + + if (ullFileSize > 0) + { + LARGE_INTEGER li; + li.QuadPart = ullFileSize; + + LARGE_INTEGER liNewFilePointer; + + if (!SetFilePointerEx(hFile, li, &liNewFilePointer, FILE_BEGIN)) + { + PrintError("Could not set file pointer during file creation when extending file (error code: %u)\n", GetLastError()); + CloseHandle(hFile); + return false; + } + if (liNewFilePointer.QuadPart != li.QuadPart) + { + PrintError("File pointer improperly moved during file creation when extending file\n"); + CloseHandle(hFile); + return false; + } + + //extends file (warning! this is a kind of "reservation" of space; valid size of the file is still 0!) + if (!SetEndOfFile(hFile)) + { + PrintError("Error setting end of file (error code: %u)\n", GetLastError()); + CloseHandle(hFile); + return false; + } + //try setting valid size of the file (privileges for that are enabled before CreateFile) + if (!fSlowWrites && !SetFileValidData(hFile, ullFileSize)) + { + PrintError("WARNING: Could not set valid file size (error code: %u); trying a slower method of filling the file" + " (this does not affect performance, just makes the test preparation longer)\n", + GetLastError()); + fSlowWrites = true; + } + + //if setting valid size couldn't be performed, fill in the file by simply writing to it (slower) + if (fSlowWrites) + { + li.QuadPart = 0; + if (!SetFilePointerEx(hFile, li, &liNewFilePointer, FILE_BEGIN)) + { + PrintError("Could not set file pointer during file creation (error code: %u)\n", GetLastError()); + CloseHandle(hFile); + return false; + } + if (liNewFilePointer.QuadPart != li.QuadPart) + { + PrintError("File pointer improperly moved during file creation\n"); + CloseHandle(hFile); + return false; + } + + UINT32 ulBufSize; + UINT64 ullRemainSize; + + ulBufSize = 1024*1024; + if (ullFileSize < (UINT64)ulBufSize) + { + ulBufSize = (UINT32)ullFileSize; + } + + vector vBuf(ulBufSize); + for (UINT32 i=0; i 0) + { + DWORD dwBytesWritten; + if ((UINT64)ulBufSize > ullRemainSize) + { + ulBufSize = (UINT32)ullRemainSize; + } + if (!WriteFile(hFile, &vBuf[0], ulBufSize, &dwBytesWritten, NULL)) + { + PrintError("Error while writng during file creation (error code: %u)\n", GetLastError()); + CloseHandle(hFile); + return false; + } + if (dwBytesWritten != ulBufSize) + { + PrintError("Improperly written data during file creation\n"); + CloseHandle(hFile); + return false; + } + ullRemainSize -= ulBufSize; + } + } + } + + //if compiled with debug support, check file size +#ifndef NDEBUG + LARGE_INTEGER li; + if( GetFileSizeEx(hFile, &li) ) + { + assert(li.QuadPart == (LONGLONG)ullFileSize); + } +#endif + + CloseHandle(hFile); + + return TRUE; +} + +/*****************************************************************************/ +void IORequestGenerator::_TerminateWorkerThreads(vector& vhThreads) const +{ + for (UINT32 x = 0; x < vhThreads.size(); ++x) + { + assert(NULL != vhThreads[x]); +#pragma warning( push ) +#pragma warning( disable : 6258 ) + if (!TerminateThread(vhThreads[x], 0)) + { + PrintError("Warning: unable to terminate worker thread %u\n", x); + } +#pragma warning( pop ) + } +} +/*****************************************************************************/ +void IORequestGenerator::_AbortWorkerThreads(HANDLE hStartEvent, vector& vhThreads) const +{ + assert(NULL != hStartEvent); + + if (NULL == hStartEvent) + { + return; + } + + g_bError = TRUE; + if (!SetEvent(hStartEvent)) + { + PrintError("Error signaling start event\n"); + _TerminateWorkerThreads(vhThreads); + } + else + { + //FUTURE EXTENSION: maximal timeout may be added here (and below) + while (g_lRunningThreadsCount > 0) + { + Sleep(100); + } + } +} + +/*****************************************************************************/ +bool IORequestGenerator::_StopETW(bool fUseETW, TRACEHANDLE hTraceSession) const +{ + bool fOk = true; + if (fUseETW) + { + PEVENT_TRACE_PROPERTIES pETWSession = StopETWSession(hTraceSession); + if (nullptr == pETWSession) + { + PrintError("Error stopping ETW session\n"); + fOk = false; + } + else + { + free(pETWSession); + } + } + return fOk; +} + +/*****************************************************************************/ +// initializes all global parameters +// +void IORequestGenerator::_InitializeGlobalParameters() +{ +// g_vThreadResults.clear(); // TODO: remove + g_lRunningThreadsCount = 0; //number of currently running worker threads + g_ulProcCount = 0; //number of CPUs present in the system + g_bRun = TRUE; //used for letting threads know that they should stop working + + g_bThreadError = FALSE; //true means that an error has occured in one of the threads + g_bTracing = FALSE; //true means that ETW is turned on + + _hNTDLL = nullptr; //handle to ntdll.dll + g_bError = FALSE; //true means there was fatal error during intialization and threads shouldn't perform their work + + g_pActiveGroupsAndProcs = NULL; // structure with KGroup info +} + +bool IORequestGenerator::_PrecreateFiles(Profile& profile) const +{ + bool fOk = true; + if (profile.GetPrecreateFiles() != PrecreateFiles::None) + { + vector vFilesToCreate = _GetFilesToPrecreate(profile); + vector vCreatedFiles; + for (auto file : vFilesToCreate) + { + fOk = _CreateFile(file.ullFileSize, file.sPath.c_str(), file.fZeroWriteBuffers, profile.GetVerbose()); + if (!fOk) + { + break; + } + vCreatedFiles.push_back(file.sPath); + } + + if (fOk) + { + profile.MarkFilesAsPrecreated(vCreatedFiles); + } + } + return fOk; +} + +bool IORequestGenerator::GenerateRequests(Profile& profile, IResultParser& resultParser, PRINTF pPrintOut, PRINTF pPrintError, PRINTF pPrintVerbose, struct Synchronization *pSynch, int *totalScore, double *averageLatency) +{ + g_pfnPrintOut = pPrintOut; + g_pfnPrintError = pPrintError; + g_pfnPrintVerbose = pPrintVerbose; + + bool fOk = _PrecreateFiles(profile); + if (fOk) + { + const vector& vTimeSpans = profile.GetTimeSpans(); + vector vResults(vTimeSpans.size()); + for (size_t i = 0; fOk && (i < vTimeSpans.size()); i++) + { + printfv(profile.GetVerbose(), "Generating requests for timespan %u.\n", i + 1); + fOk = _GenerateRequestsForTimeSpan(profile, vTimeSpans[i], vResults[i], pSynch); + } + + // TODO: show results only for timespans that succeeded + SystemInformation system; + string sResults = resultParser.ParseResults(profile, system, vResults); + print("%s", sResults.c_str()); + *totalScore = resultParser.GetTotalScore() * 10; + *averageLatency = resultParser.GetAverageLatency(); + } + + return fOk; +} + +bool IORequestGenerator::_GenerateRequestsForTimeSpan(const Profile& profile, const TimeSpan& timeSpan, Results& results, struct Synchronization *pSynch) +{ + //FUTURE EXTENSION: add new I/O capabilities presented in Longhorn + //FUTURE EXTENSION: add a check if the folder is compressed (cache is always enabled in case of compressed folders) + + //check if I/O request generator is already running + LONG lGenState = InterlockedExchange(&g_lGeneratorRunning, 1); + if (1 == lGenState) + { + PrintError("FATAL ERROR: I/O Request Generator already running\n"); + return false; + } + + //initialize all global parameters (in case of second run, after the first one is finished) + _InitializeGlobalParameters(); + + HANDLE hStartEvent = nullptr; // start event (used to inform the worker threads that they should start the work) + HANDLE hEndEvent = nullptr; // end event (used only in case of completin routines (not for IO Completion Ports)) + + memset(&g_EtwEventCounters, 0, sizeof(struct ETWEventCounters)); // reset all etw event counters + + //ulProcCount = getProcessorCount(); + g_pActiveGroupsAndProcs = (PACTIVE_GROUPS_AND_PROCS)malloc(sizeof(ACTIVE_GROUPS_AND_PROCS)); + if (g_pActiveGroupsAndProcs == NULL) + { + PrintError("ERROR: Memory allocation for groups and procs structure failed!\r\n"); + return false; + } + if (_GetActiveGroupsAndProcs() == false) + { + PrintError("ERROR: Failed to get groups and processors information!\r\n"); + return false; + } + + bool fUseETW = false; //true if user wants ETW + + // + // load dlls + // + assert(nullptr == _hNTDLL); + if (!_LoadDLLs()) + { + PrintError("Error loading NtQuerySystemInformation\n"); + return false; + } + + //FUTURE EXTENSION: check for conflicts in alignment (when cache is turned off only sector aligned I/O are permitted) + //FUTURE EXTENSION: check if file sizes are enough to have at least first requests not wrapping around + + vector vTargets = timeSpan.GetTargets(); + // allocate memory for random data write buffers + for (auto i = vTargets.begin(); i != vTargets.end(); i++) + { + if ((i->GetRandomDataWriteBufferSize() > 0) && !i->AllocateAndFillRandomDataWriteBuffer()) + { + return false; + } + } + + // check if user wanted to create a file + for (auto i = vTargets.begin(); i != vTargets.end(); i++) + { + if ((i->GetFileSize() > 0) && (i->GetPrecreated() == false)) + { + string str = i->GetPath(); + const char *filename = str.c_str(); + if (NULL == filename || NULL == *(filename)) + { + PrintError("You have to provide a filename\n"); + return false; + } + + //skip physical drives and partitions + if ('#' == filename[0] || (':' == filename[1] && 0 == filename[2])) + { + continue; + } + + //create only regular files + if (!_CreateFile(i->GetFileSize(), filename, i->GetZeroWriteBuffers(), profile.GetVerbose())) + { + return false; + } + } + } + + // get thread count + UINT32 cThreads = timeSpan.GetThreadCount(); + if (cThreads < 1) + { + for (auto i = vTargets.begin(); i != vTargets.end(); i++) + { + cThreads += i->GetThreadsPerFile(); + } + } + + // allocate memory for thread handles + vector vhThreads(cThreads); + + // + // allocate memory for performance counters + // + vector vPerfInit(g_ulProcCount); + vector vPerfDone(g_ulProcCount); + vector vPerfDiff(g_ulProcCount); + + // + //create start event + // + + hStartEvent = CreateEvent(NULL, TRUE, FALSE, ""); + if (NULL == hStartEvent) + { + PrintError("Error creating the start event\n"); + return false; + } + + // + // create end event + // + if (timeSpan.GetCompletionRoutines()) + { + hEndEvent = CreateEvent(NULL, TRUE, FALSE, ""); + if (NULL == hEndEvent) + { + PrintError("Error creating the end event\n"); + return false; + } + } + + // + // create the threads + // + + g_bRun = TRUE; + WORD wGroupCtr = 0; + DWORD dwProcCtr = 0; + + volatile bool fAccountingOn = false; + UINT64 ullStartTime; //start time + UINT64 ullTimeDiff; //elapsed test time (in units returned by QueryPerformanceCounter) + vector vullSharedSequentialOffsets(vTargets.size(), 0); + + results.vThreadResults.clear(); + results.vThreadResults.resize(cThreads); + for (UINT32 iThread = 0; iThread < cThreads; ++iThread) + { + printfv(profile.GetVerbose(), "creating thread %u\n", iThread); + ThreadParameters *cookie = new ThreadParameters(); // threadFunc is going to free the memory + if (nullptr == cookie) + { + PrintError("FATAL ERROR: could not allocate memory\n"); + _AbortWorkerThreads(hStartEvent, vhThreads); + return false; + } + + UINT32 ulRelativeThreadNo = 0; + + if (timeSpan.GetThreadCount() > 0) + { + // fixed thread mode: all threads operate on all files + // and receive the entire seq index array. + // relative thread number is the same as thread number. + cookie->vTargets = vTargets; + cookie->pullSharedSequentialOffsets = &vullSharedSequentialOffsets[0]; + ulRelativeThreadNo = iThread; + } + else + { + size_t cAssignedThreads = 0; + size_t cBaseThread = 0; + auto psi = vullSharedSequentialOffsets.begin(); + for (auto i = vTargets.begin(); + i != vTargets.end(); + i++, psi++) + { + // per-file thread mode: groups of threads operate on individual files + // and receive the specific seq index for their file (note: singular). + // loop up through the targets to assign thread n to the appropriate file. + // relative thread number is file-relative, so keep track of the base + // thread number for the file and calculate relative to that. + // + // ex: two files, two threads per file + // t0: rt0 for f0 (cAssigned = 2, cBase = 0) + // t1: rt1 for f0 (cAssigned = 2, cBase = 0) + // t2: rt0 for f1 (cAssigned = 4, cBase = 2) + // t3: rt1 for f1 (cAssigned = 4, cBase = 2) + + cAssignedThreads += i->GetThreadsPerFile(); + if (iThread < cAssignedThreads) + { + cookie->vTargets.push_back(*i); + cookie->pullSharedSequentialOffsets = &(*psi); + ulRelativeThreadNo = (iThread - cBaseThread) % i->GetThreadsPerFile(); + + printfv(profile.GetVerbose(), "thread %u is relative thread %u for %s\n", iThread, ulRelativeThreadNo, i->GetPath().c_str()); + break; + } + cBaseThread += i->GetThreadsPerFile(); + } + } + + cookie->pProfile = &profile; + cookie->pTimeSpan = &timeSpan; + cookie->hStartEvent = hStartEvent; + cookie->hEndEvent = hEndEvent; + cookie->ulThreadNo = iThread; + cookie->ulRelativeThreadNo = ulRelativeThreadNo; + cookie->pfAccountingOn = &fAccountingOn; + cookie->pullStartTime = &ullStartTime; + cookie->ulRandSeed = timeSpan.GetRandSeed() + iThread; // each thread has a different random seed + + //Set thread group and proc affinity + if (timeSpan.GetGroupAffinity()) + { + cookie->wGroupNum = wGroupCtr; + cookie->dwProcNum = dwProcCtr; + + if (dwProcCtr == g_pActiveGroupsAndProcs->dwaActiveProcsCount[wGroupCtr] - 1) + { + dwProcCtr = 0; + if (wGroupCtr == g_pActiveGroupsAndProcs->wActiveGroupCount - 1) + { + wGroupCtr = 0; + } + else + { + wGroupCtr++; + } + } + else + { + dwProcCtr++; + } + } + + //create thread + cookie->pResults = &results.vThreadResults[iThread]; + + InterlockedIncrement(&g_lRunningThreadsCount); + DWORD dwThreadId; + HANDLE hThread = CreateThread(NULL, 64 * 1024, threadFunc, cookie, 0, &dwThreadId); + if (NULL == hThread) + { + //in case of error terminate running worker threads + PrintError("ERROR: unable to create thread (error code: %u)\n", GetLastError()); + InterlockedDecrement(&g_lRunningThreadsCount); + _AbortWorkerThreads(hStartEvent, vhThreads); + delete cookie; + return false; + } + + //store handle to the thread + vhThreads[iThread] = hThread; + } + // + // affinitize thread to first cpu + // (otherwise, because of bios bugs, RDTSC readings may be not accurate) + // + SetThreadAffinityMask(GetCurrentThread(), 1); //FUTURE EXTENSION: check if it is set correctly, on the end/error set the affinity (and priority) to original + + //FUTURE EXTENSION: SetPriorityClass HIGH/ABOVE_NORMAL + //FUTURE EXTENSION: lower priority so the worker threads will initialize (-2) + //FUTURE EXTENSION: raise priority so this thread will run after the time end + + if (STRUCT_SYNCHRONIZATION_SUPPORTS(pSynch, hStartEvent) && (NULL != pSynch->hStartEvent)) + { + if (WAIT_OBJECT_0 != WaitForSingleObject(pSynch->hStartEvent, INFINITE)) + { + PrintError("Error during WaitForSingleObject\n"); + _AbortWorkerThreads(hStartEvent, vhThreads); + return false; + } + } + + // + // get cycle count (it will be used to calculate actual work time) + // + DWORD dwWaitStatus = 0; + + //bAccountingOn = FALSE; // clear the accouning flag so that threads didn't count what they do while in the warmup phase + + BOOL bSynchStop = STRUCT_SYNCHRONIZATION_SUPPORTS(pSynch, hStopEvent) && (NULL != pSynch->hStopEvent); + BOOL bBreak = FALSE; + PEVENT_TRACE_PROPERTIES pETWSession = NULL; + + printfv(profile.GetVerbose(), "starting warm up...\n"); + // + // send start signal + // + if (!SetEvent(hStartEvent)) + { + PrintError("Error signaling start event\n"); + // stopETW(bUseETW, hTraceSession); + _TerminateWorkerThreads(vhThreads); //FUTURE EXTENSION: timeout for worker threads + return false; + } + + // + // wait specified amount of time in each phase (warm up, test, cool down) + // + if (timeSpan.GetWarmup() > 0) + { + if (bSynchStop) + { + assert(NULL != pSynch->hStopEvent); + dwWaitStatus = WaitForSingleObject(pSynch->hStopEvent, 1000 * timeSpan.GetWarmup()); + if (WAIT_OBJECT_0 != dwWaitStatus && WAIT_TIMEOUT != dwWaitStatus) + { + PrintError("Error during WaitForSingleObject\n"); + _TerminateWorkerThreads(vhThreads); + return false; + } + bBreak = (WAIT_TIMEOUT != dwWaitStatus); + } + else + { + Sleep(1000 * timeSpan.GetWarmup()); + } + } + + if (!bBreak) // proceed only if user didn't break the test + { + //FUTURE EXTENSION: starting ETW session shouldn't be done brutally here, should be done before warmup and here just a fast signal to start logging (see also stopping ETW session) + //FUTURE EXTENSION: put an ETW mark here, for easier parsing by external tools + + // + // start etw session + // + TRACEHANDLE hTraceSession = NULL; + if (fUseETW) + { + printfv(profile.GetVerbose(), "starting trace session\n"); + hTraceSession = StartETWSession(profile); + if (NULL == hTraceSession) + { + PrintError("Could not start ETW session\n"); + _TerminateWorkerThreads(vhThreads); + return false; + } + + if (NULL == CreateThread(NULL, 64 * 1024, etwThreadFunc, NULL, 0, NULL)) + { + PrintError("Warning: unable to create thread for ETW session\n"); + _TerminateWorkerThreads(vhThreads); + return false; + } + printfv(profile.GetVerbose(), "tracing events\n"); + } + + // + // read performance counters + // + if (_GetSystemPerfInfo(&vPerfInit[0], g_ulProcCount) == FALSE) + { + PrintError("Error reading performance counters\n"); + _StopETW(fUseETW, hTraceSession); + _TerminateWorkerThreads(vhThreads); + return false; + } + + printfv(profile.GetVerbose(), "starting measurements...\n"); + //get cycle count (it will be used to calculate actual work time) + + // + // notify the front-end that the test is about to start; + // do it before starting timing in order not to perturb measurements + // + if (STRUCT_SYNCHRONIZATION_SUPPORTS(pSynch, pfnCallbackTestStarted) && (NULL != pSynch->pfnCallbackTestStarted)) + { + pSynch->pfnCallbackTestStarted(); + } + + ullStartTime = PerfTimer::GetTime(); + +#pragma warning( push ) +#pragma warning( disable : 28931 ) + fAccountingOn = true; +#pragma warning( pop ) + + assert(timeSpan.GetDuration() > 0); + if (bSynchStop) + { + assert(NULL != pSynch->hStopEvent); + dwWaitStatus = WaitForSingleObject(pSynch->hStopEvent, 1000 * timeSpan.GetDuration()); + if (WAIT_OBJECT_0 != dwWaitStatus && WAIT_TIMEOUT != dwWaitStatus) + { + PrintError("Error during WaitForSingleObject\n"); + _StopETW(fUseETW, hTraceSession); + _TerminateWorkerThreads(vhThreads); //FUTURE EXTENSION: worker threads should have a chance to free allocated memory (see also other places calling terminateWorkerThreads()) + return FALSE; + } + bBreak = (WAIT_TIMEOUT != dwWaitStatus); + } + else + { + Sleep(1000 * timeSpan.GetDuration()); + } + + fAccountingOn = false; + + //get cycle count and perf counters + ullTimeDiff = PerfTimer::GetTime() - ullStartTime; + + // + // notify the front-end that the test has just finished; + // do it after stopping timing in order not to perturb measurements + // + if (STRUCT_SYNCHRONIZATION_SUPPORTS(pSynch, pfnCallbackTestFinished) && (NULL != pSynch->pfnCallbackTestFinished)) + { + pSynch->pfnCallbackTestFinished(); + } + + if (_GetSystemPerfInfo(&vPerfDone[0], g_ulProcCount) == FALSE) + { + PrintError("Error getting performance counters\n"); + _StopETW(fUseETW, hTraceSession); + _TerminateWorkerThreads(vhThreads); + return false; + } + + // + // stop etw session + // + if (fUseETW) + { + printfv(profile.GetVerbose(), "stopping ETW session\n"); + pETWSession = StopETWSession(hTraceSession); + if (NULL == pETWSession) + { + PrintError("Error stopping ETW session\n"); + return false; + } + else + { + free(pETWSession); + } + } + } + else + { + ullTimeDiff = 0; // mark that no test was run + } + + printfv(profile.GetVerbose(), "starting cool down...\n"); + if ((timeSpan.GetCooldown() > 0) && !bBreak) + { + if (bSynchStop) + { + assert(NULL != pSynch->hStopEvent); + dwWaitStatus = WaitForSingleObject(pSynch->hStopEvent, 1000 * timeSpan.GetCooldown()); + if (WAIT_OBJECT_0 != dwWaitStatus && WAIT_TIMEOUT != dwWaitStatus) + { + PrintError("Error during WaitForSingleObject\n"); + // stopETW(bUseETW, hTraceSession); + _TerminateWorkerThreads(vhThreads); + return false; + } + } + else + { + Sleep(1000 * timeSpan.GetCooldown()); + } + } + printfv(profile.GetVerbose(), "finished test...\n"); + + // + // signal the threads to finish + // + g_bRun = FALSE; + if (timeSpan.GetCompletionRoutines()) + { + if (!SetEvent(hEndEvent)) + { + PrintError("Error signaling end event\n"); + // stopETW(bUseETW, hTraceSession); + return false; + } + } + + // + // wait till all of the threads finish + // +#pragma warning( push ) +#pragma warning( disable : 28112 ) + while (g_lRunningThreadsCount > 0) + { + Sleep(10); //FUTURE EXTENSION: a timeout should be implemented + } +#pragma warning( pop ) + + + //check if there has been an error during threads execution + if (g_bThreadError) + { + PrintError("There has been an error during threads execution\n"); + return false; + } + + // + // close events' handles + // + CloseHandle(hStartEvent); + hStartEvent = NULL; + + if (NULL != hEndEvent) + { + CloseHandle(hEndEvent); + hEndEvent = NULL; + } + //FUTURE EXTENSION: hStartEvent and hEndEvent should be closed in case of error too + + // + // compute time spent by each cpu + // + for (unsigned int p = 0; p= vPerfInit[p].IdleTime.QuadPart); + assert(vPerfDone[p].KernelTime.QuadPart >= vPerfInit[p].KernelTime.QuadPart); + assert(vPerfDone[p].UserTime.QuadPart >= vPerfInit[p].UserTime.QuadPart); + assert(vPerfDone[p].Reserved1[0].QuadPart >= vPerfInit[p].Reserved1[0].QuadPart); + assert(vPerfDone[p].Reserved1[1].QuadPart >= vPerfInit[p].Reserved1[1].QuadPart); + assert(vPerfDone[p].Reserved2 >= vPerfInit[p].Reserved2); + + vPerfDiff[p].IdleTime.QuadPart = vPerfDone[p].IdleTime.QuadPart - vPerfInit[p].IdleTime.QuadPart; + vPerfDiff[p].KernelTime.QuadPart = vPerfDone[p].KernelTime.QuadPart - vPerfInit[p].KernelTime.QuadPart; + vPerfDiff[p].UserTime.QuadPart = vPerfDone[p].UserTime.QuadPart - vPerfInit[p].UserTime.QuadPart; + vPerfDiff[p].Reserved1[0].QuadPart = vPerfDone[p].Reserved1[0].QuadPart - vPerfInit[p].Reserved1[0].QuadPart; + vPerfDiff[p].Reserved1[1].QuadPart = vPerfDone[p].Reserved1[1].QuadPart - vPerfInit[p].Reserved1[1].QuadPart; + vPerfDiff[p].Reserved2 = vPerfDone[p].Reserved2 - vPerfInit[p].Reserved2; + } + + // + // process results and pass them to the result parser + // + + // get processors perf. info + results.vSystemProcessorPerfInfo = vPerfDiff; + results.ullTimeCount = ullTimeDiff; + + // + // create structure containing etw results and properties + // + results.fUseETW = fUseETW; + if (fUseETW) + { + results.EtwEventCounters = g_EtwEventCounters; + results.EtwSessionInfo = _GetResultETWSession(pETWSession); + + // TODO: refactor to a separate function + results.EtwMask.bProcess = profile.GetEtwProcess(); + results.EtwMask.bThread = profile.GetEtwThread(); + results.EtwMask.bImageLoad = profile.GetEtwImageLoad(); + results.EtwMask.bDiskIO = profile.GetEtwDiskIO(); + results.EtwMask.bMemoryPageFaults = profile.GetEtwMemoryPageFaults(); + results.EtwMask.bMemoryHardFaults = profile.GetEtwMemoryHardFaults(); + results.EtwMask.bNetwork = profile.GetEtwNetwork(); + results.EtwMask.bRegistry = profile.GetEtwRegistry(); + results.EtwMask.bUsePagedMemory = profile.GetEtwUsePagedMemory(); + results.EtwMask.bUsePerfTimer = profile.GetEtwUsePerfTimer(); + results.EtwMask.bUseSystemTimer = profile.GetEtwUseSystemTimer(); + results.EtwMask.bUseCyclesCounter = profile.GetEtwUseCyclesCounter(); + } + + if (g_pActiveGroupsAndProcs != nullptr) + { + free(g_pActiveGroupsAndProcs); + } + + // free memory used by random data write buffers + for (auto i = vTargets.begin(); i != vTargets.end(); i++) + { + i->FreeRandomDataWriteBuffer(); + } + + // TODO: this won't catch error cases, which exit early + InterlockedExchange(&g_lGeneratorRunning, 0); + return true; +} + +vector IORequestGenerator::_GetFilesToPrecreate(const Profile& profile) const +{ + vector vFilesToCreate; + const vector& vTimeSpans = profile.GetTimeSpans(); + map> filesMap; + for (const auto& timeSpan : vTimeSpans) + { + vector vTargets(timeSpan.GetTargets()); + for (const auto& target : vTargets) + { + struct CreateFileParameters createFileParameters; + createFileParameters.sPath = target.GetPath(); + createFileParameters.ullFileSize = target.GetFileSize(); + createFileParameters.fZeroWriteBuffers = target.GetZeroWriteBuffers(); + + filesMap[createFileParameters.sPath].push_back(createFileParameters); + } + } + + PrecreateFiles filter = profile.GetPrecreateFiles(); + for (auto fileMapEntry : filesMap) + { + if (fileMapEntry.second.size() > 0) + { + UINT64 ullLastNonZeroSize = fileMapEntry.second[0].ullFileSize; + UINT64 ullMaxSize = fileMapEntry.second[0].ullFileSize; + bool fLastZeroWriteBuffers = fileMapEntry.second[0].fZeroWriteBuffers; + bool fHasZeroSizes = false; + bool fConstantSize = true; + bool fConstantZeroWriteBuffers = true; + for (auto file : fileMapEntry.second) + { + ullMaxSize = max(ullMaxSize, file.ullFileSize); + if (ullLastNonZeroSize == 0) + { + ullLastNonZeroSize = file.ullFileSize; + } + if (file.ullFileSize == 0) + { + fHasZeroSizes = true; + } + if ((file.ullFileSize != 0) && (file.ullFileSize != ullLastNonZeroSize)) + { + fConstantSize = false; + } + if (file.fZeroWriteBuffers != fLastZeroWriteBuffers) + { + fConstantZeroWriteBuffers = false; + } + if (file.ullFileSize != 0) + { + ullLastNonZeroSize = file.ullFileSize; + } + fLastZeroWriteBuffers = file.fZeroWriteBuffers; + } + + if (fConstantZeroWriteBuffers && ullMaxSize > 0) + { + struct CreateFileParameters file = fileMapEntry.second[0]; + file.ullFileSize = ullMaxSize; + if (filter == PrecreateFiles::UseMaxSize) + { + vFilesToCreate.push_back(file); + } + else if ((filter == PrecreateFiles::OnlyFilesWithConstantSizes) && fConstantSize && !fHasZeroSizes) + { + vFilesToCreate.push_back(file); + } + else if ((filter == PrecreateFiles::OnlyFilesWithConstantOrZeroSizes) && fConstantSize) + { + vFilesToCreate.push_back(file); + } + } + } + } + + return vFilesToCreate; +} diff --git a/CristalDiskMark/source/diskspd2_0_15a/IORequestGenerator/IORequestGenerator.h b/CristalDiskMark/source/diskspd2_0_15a/IORequestGenerator/IORequestGenerator.h new file mode 100644 index 0000000..f9dd5b5 --- /dev/null +++ b/CristalDiskMark/source/diskspd2_0_15a/IORequestGenerator/IORequestGenerator.h @@ -0,0 +1,87 @@ +/* + +DISKSPD + +Copyright(c) Microsoft Corporation +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#pragma once +#define INITGUID //Include this #define to use SystemTraceControlGuid in Evntrace.h. +#include //ETW +#include //ntdll.dll + + +void PrintError(const char *format, ...); +void *ManagedMalloc(size_t size); +namespace UnitTests +{ + class IORequestGeneratorUnitTests; +} + +class IORequestGenerator +{ +public: + IORequestGenerator() : + _hNTDLL(nullptr) + { + + } + + bool GenerateRequests(Profile& profile, IResultParser& resultParser, PRINTF pPrintOut, PRINTF pPrintError, PRINTF pPrintVerbose, struct Synchronization *pSynch, int *totalScore, double *averageLatency); + static UINT64 GetNextFileOffset(ThreadParameters& tp, size_t targetNum, UINT64 prevOffset); + static UINT64 GetStartingFileOffset(ThreadParameters& tp, size_t targetNum); + static UINT64 GetThreadBaseFileOffset(ThreadParameters& tp, size_t targetNum); + +private: + + struct CreateFileParameters + { + string sPath; + UINT64 ullFileSize; + bool fZeroWriteBuffers; + }; + + bool _GenerateRequestsForTimeSpan(const Profile& profile, const TimeSpan& timeSpan, Results& results, struct Synchronization *pSynch); + void _AbortWorkerThreads(HANDLE hStartEvent, vector& vhThreads) const; + void _CloseOpenFiles(vector& vhFiles) const; + DWORD _CreateDirectoryPath(const char *path) const; + bool _CreateFile(UINT64 ullFileSize, const char *pszFilename, bool fZeroBuffers, bool fVerbose) const; + void _DisplayFileSizeVerbose(bool fVerbose, UINT64 fsize) const; + bool _GetActiveGroupsAndProcs() const; + struct ETWSessionInfo _GetResultETWSession(const EVENT_TRACE_PROPERTIES *pTraceProperties) const; + bool _GetSystemPerfInfo(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION *pInfo, UINT32 uCpuCount) const; + void _InitializeGlobalParameters(); + bool _LoadDLLs(); + bool _StopETW(bool fUseETW, TRACEHANDLE hTraceSession) const; + void _TerminateWorkerThreads(vector& vhThreads) const; + bool _ValidateProfile(const Profile& profile) const; + vector _GetFilesToPrecreate(const Profile& profile) const; + void _MarkFilesAsCreated(Profile& profile, const vector& vFiles) const; + bool _PrecreateFiles(Profile& profile) const; + + HINSTANCE volatile _hNTDLL; //handle to ntdll.dll + + friend class UnitTests::IORequestGeneratorUnitTests; +}; diff --git a/CristalDiskMark/source/diskspd2_0_15a/IORequestGenerator/OverlappedQueue.cpp b/CristalDiskMark/source/diskspd2_0_15a/IORequestGenerator/OverlappedQueue.cpp new file mode 100644 index 0000000..23fbd36 --- /dev/null +++ b/CristalDiskMark/source/diskspd2_0_15a/IORequestGenerator/OverlappedQueue.cpp @@ -0,0 +1,79 @@ +/* + +DISKSPD + +Copyright(c) Microsoft Corporation +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#include "OverlappedQueue.h" +#include + +OverlappedQueue::OverlappedQueue(void) : + _pHead(nullptr), + _pTail(nullptr), + _cItems(0) +{ +} + +void OverlappedQueue::Add(OVERLAPPED *pOverlapped) +{ + pOverlapped->Internal = NULL; + if (_pHead == nullptr) + { + assert(_pTail == nullptr); + _pHead = pOverlapped; + } + else + { + assert(_pTail != nullptr); + _pTail->Internal = (ULONG_PTR)pOverlapped; + } + _pTail = pOverlapped; + _cItems++; +} + +bool OverlappedQueue::IsEmpty(void) const +{ + return (_pHead == nullptr); +} + +OVERLAPPED *OverlappedQueue::Remove(void) +{ + assert(!IsEmpty()); + + OVERLAPPED *pOverlapped = _pHead; + _pHead = (OVERLAPPED *)pOverlapped->Internal; + if (_pHead == nullptr) + { + _pTail = nullptr; + } + _cItems--; + return pOverlapped; +} + +size_t OverlappedQueue::GetCount() const +{ + return _cItems; +} \ No newline at end of file diff --git a/CristalDiskMark/source/diskspd2_0_15a/IORequestGenerator/OverlappedQueue.h b/CristalDiskMark/source/diskspd2_0_15a/IORequestGenerator/OverlappedQueue.h new file mode 100644 index 0000000..622ac67 --- /dev/null +++ b/CristalDiskMark/source/diskspd2_0_15a/IORequestGenerator/OverlappedQueue.h @@ -0,0 +1,50 @@ +/* + +DISKSPD + +Copyright(c) Microsoft Corporation +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#pragma once +#include + +// +// OverlappedQueue is a simple class that implements a queue for OVERLAPPED elements +// +class OverlappedQueue +{ +public: + OverlappedQueue(void); + + void Add(OVERLAPPED *pOverlapped); + bool IsEmpty(void) const; + OVERLAPPED * Remove(void); + size_t GetCount() const; + +private: + OVERLAPPED *_pHead; + OVERLAPPED *_pTail; + size_t _cItems; +}; \ No newline at end of file diff --git a/CristalDiskMark/source/diskspd2_0_15a/IORequestGenerator/ThroughputMeter.cpp b/CristalDiskMark/source/diskspd2_0_15a/IORequestGenerator/ThroughputMeter.cpp new file mode 100644 index 0000000..83ed6f9 --- /dev/null +++ b/CristalDiskMark/source/diskspd2_0_15a/IORequestGenerator/ThroughputMeter.cpp @@ -0,0 +1,123 @@ +/* + +DISKSPD + +Copyright(c) Microsoft Corporation +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#include "ThroughputMeter.h" + +ThroughputMeter::ThroughputMeter(void) : + _fRunning(false) +{ +} + +bool ThroughputMeter::IsRunning(void) const +{ + return _fRunning; +} + +void ThroughputMeter::Start(DWORD cBytesPerMillisecond, DWORD dwBlockSize, DWORD dwThinkTime, DWORD dwBurstSize) +{ + // Initialization + _cbCompleted = 0; + _cIO = 0; // number of completed IOs in the current burst + _cbBlockSize = dwBlockSize; + + _fThrottle = false; + _cBytesPerMillisecond = 0; + _fThink = false; + _ullDelayUntil = 0; + _thinkTime = 0; + _burstSize = 0; + _fRunning = false; + + /// GetTickCount64 -> GetTickCount + _ullStartTimestamp = GetTickCount(); + + if (0 != cBytesPerMillisecond) + { + _fThrottle = true; + _cBytesPerMillisecond = cBytesPerMillisecond; + _fRunning = true; + } + else if (0 != dwThinkTime) + { + _fThink = true; + _thinkTime = dwThinkTime; + _burstSize = dwBurstSize; + _fRunning = true; + } +} + +DWORD ThroughputMeter::GetSleepTime(void) const +{ + if (_fThink) + { + /// GetTickCount64 -> GetTickCount + ULONGLONG ullTimestamp = GetTickCount(); + if (ullTimestamp < _ullDelayUntil) + { + return (DWORD)(_ullDelayUntil - ullTimestamp); + } + else + { + return (_fThrottle) ? _GetThrottleTime() : 0; + } + } + else + { + if (_fThrottle) // think time has not been specified only check for throttling + { + return _GetThrottleTime(); + } + else + { + return 0; + } + } +} + +DWORD ThroughputMeter::_GetThrottleTime(void) const +{ + /// GetTickCount64 -> GetTickCount + ULONGLONG cbExpected = (GetTickCount() - _ullStartTimestamp) * _cBytesPerMillisecond; + return cbExpected >= (_cbCompleted + _cbBlockSize) ? 0 : 1; +} + +void ThroughputMeter::Adjust(size_t cb) +{ + _cbCompleted += cb; + _cIO++; + if (_fThink) + { + if (_cIO >= _burstSize) + { + _cIO = 0; + /// GetTickCount64 -> GetTickCount + _ullDelayUntil = GetTickCount() + _thinkTime; + } + } +} \ No newline at end of file diff --git a/CristalDiskMark/source/diskspd2_0_15a/IORequestGenerator/ThroughputMeter.h b/CristalDiskMark/source/diskspd2_0_15a/IORequestGenerator/ThroughputMeter.h new file mode 100644 index 0000000..0375f05 --- /dev/null +++ b/CristalDiskMark/source/diskspd2_0_15a/IORequestGenerator/ThroughputMeter.h @@ -0,0 +1,61 @@ +/* + +DISKSPD + +Copyright(c) Microsoft Corporation +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#pragma once +#include + +// ThroughputMeter class assists in metering out throughput over +// time. The meter is started by calling Start() with the throughput +// to be simulated. GetSleepTime() returns 0 when the next IO can be issued. +// Adjust() is called to notify the ThroughputMeter about how many bytes were read/written. +class ThroughputMeter +{ +public: + ThroughputMeter(void); + + bool IsRunning(void) const; + void Start(DWORD cBytesPerMillisecond, DWORD dwBlockSize, DWORD dwThinkTime, DWORD dwBurstSize); + DWORD GetSleepTime(void) const; + void Adjust(size_t cb); + +private: + DWORD _GetThrottleTime(void) const; + + bool _fRunning; // true = throughput monitoring is on + bool _fThrottle; // true = throttling is on + bool _fThink; // true = think time is enabled + ULONGLONG _cbCompleted; // completed IO + DWORD _cbBlockSize; + DWORD _cBytesPerMillisecond; // rate of throttling + ULONGLONG _ullStartTimestamp; + ULONGLONG _ullDelayUntil; // timestamp at which the next IO can be executed + DWORD _thinkTime; // time to sleep between burst of IOs + DWORD _burstSize; // number of IOs in a burst. meaningless if think time is zero + DWORD _cIO; // count of IOs in the current burst +}; \ No newline at end of file diff --git a/CristalDiskMark/source/diskspd2_0_15a/IORequestGenerator/etw.cpp b/CristalDiskMark/source/diskspd2_0_15a/IORequestGenerator/etw.cpp new file mode 100644 index 0000000..445c3f4 --- /dev/null +++ b/CristalDiskMark/source/diskspd2_0_15a/IORequestGenerator/etw.cpp @@ -0,0 +1,502 @@ +/* + +DISKSPD + +Copyright(c) Microsoft Corporation +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#include "etw.h" +#include "common.h" +#include +#include + +#include //WNODE_HEADER + +#define INITGUID //Include this #define to use SystemTraceControlGuid in Evntrace.h. +#include //ETW + +#include "IORequestGenerator.h" + +// variables declared in IORequestGenerator.cpp +extern struct ETWEventCounters g_EtwEventCounters; +extern BOOL volatile g_bTracing; + + +DEFINE_GUID ( /* 3d6fa8d4-fe05-11d0-9dda-00c04fd7ba7c */ + DiskIoGuid, + 0x3d6fa8d4, + 0xfe05, + 0x11d0, + 0x9d, 0xda, 0x00, 0xc0, 0x4f, 0xd7, 0xba, 0x7c + ); + +DEFINE_GUID ( /* 90cbdc39-4a3e-11d1-84f4-0000f80464e3 */ + FileIoGuid, + 0x90cbdc39, + 0x4a3e, + 0x11d1, + 0x84, 0xf4, 0x00, 0x00, 0xf8, 0x04, 0x64, 0xe3 + ); + +DEFINE_GUID ( /* 2cb15d1d-5fc1-11d2-abe1-00a0c911f518 */ + ImageLoadGuid, + 0x2cb15d1d, + 0x5fc1, + 0x11d2, + 0xab, 0xe1, 0x00, 0xa0, 0xc9, 0x11, 0xf5, 0x18 + ); + +DEFINE_GUID ( /* 3d6fa8d3-fe05-11d0-9dda-00c04fd7ba7c */ + PageFaultGuid, + 0x3d6fa8d3, + 0xfe05, + 0x11d0, + 0x9d, 0xda, 0x00, 0xc0, 0x4f, 0xd7, 0xba, 0x7c + ); + +DEFINE_GUID ( /* 9a280ac0-c8e0-11d1-84e2-00c04fb998a2 */ + TcpIpGuid, + 0x9a280ac0, + 0xc8e0, + 0x11d1, + 0x84, 0xe2, 0x00, 0xc0, 0x4f, 0xb9, 0x98, 0xa2 + ); + +DEFINE_GUID ( /* bf3a50c5-a9c9-4988-a005-2df0b7c80f80 */ + UdpIpGuid, + 0xbf3a50c5, + 0xa9c9, + 0x4988, + 0xa0, 0x05, 0x2d, 0xf0, 0xb7, 0xc8, 0x0f, 0x80 + ); + +DEFINE_GUID ( /* 3d6fa8d0-fe05-11d0-9dda-00c04fd7ba7c */ + ProcessGuid, + 0x3d6fa8d0, + 0xfe05, + 0x11d0, + 0x9d, 0xda, 0x00, 0xc0, 0x4f, 0xd7, 0xba, 0x7c + ); + +DEFINE_GUID ( /* AE53722E-C863-11d2-8659-00C04FA321A1 */ + RegistryGuid, + 0xae53722e, + 0xc863, + 0x11d2, + 0x86, 0x59, 0x0, 0xc0, 0x4f, 0xa3, 0x21, 0xa1 +); + +DEFINE_GUID ( /* 3d6fa8d1-fe05-11d0-9dda-00c04fd7ba7c */ + ThreadGuid, + 0x3d6fa8d1, + 0xfe05, + 0x11d0, + 0x9d, 0xda, 0x00, 0xc0, 0x4f, 0xd7, 0xba, 0x7c + ); + +/*****************************************************************************/ +// consumes events' data +// +BOOL TraceEvents() +{ + TRACEHANDLE handles[1]; + EVENT_TRACE_LOGFILE logfile; + + memset(&logfile, 0, sizeof(EVENT_TRACE_LOGFILE)); + + logfile.LoggerName = KERNEL_LOGGER_NAME; + logfile.LogFileName = NULL; + logfile.LogFileMode = EVENT_TRACE_REAL_TIME_MODE; + + logfile.IsKernelTrace = true; + + handles[0] = OpenTrace(&logfile); + if( (TRACEHANDLE)INVALID_HANDLE_VALUE == handles[0] ) + { + PrintError("ETW ERROR: OpenTrace failed (error code: %d)\n", GetLastError()); + return false; + } + else + { + ProcessTrace(handles, 1, 0, 0); + CloseTrace(handles[0]); + } + + return true; +} + +/*****************************************************************************/ +// allocates memory for ETW properties structure +// +PEVENT_TRACE_PROPERTIES allocateEventTraceProperties() +{ + PEVENT_TRACE_PROPERTIES pProperties = NULL; + size_t size = 0; + + + size = sizeof(EVENT_TRACE_PROPERTIES)+sizeof(KERNEL_LOGGER_NAME); + pProperties = (PEVENT_TRACE_PROPERTIES)malloc(size); + if( NULL == pProperties ) + { + PrintError("FATAL ERROR: unable to allocate memory (error code: %d)\n", GetLastError()); + return NULL; + } + + memset(pProperties, 0, size); + + pProperties->LoggerNameOffset = sizeof(EVENT_TRACE_PROPERTIES); + pProperties->Wnode.BufferSize = (ULONG)size; + pProperties->Wnode.Flags = WNODE_FLAG_TRACED_GUID; + + strcpy_s((char *)pProperties+pProperties->LoggerNameOffset, + size-pProperties->LoggerNameOffset, KERNEL_LOGGER_NAME); + + return pProperties; +} + +/*****************************************************************************/ +// callback function for disk I/O events +void WINAPI eventDiskIo(PEVENT_TRACE pEvent) +{ + if( EVENT_TRACE_TYPE_IO_READ == pEvent->Header.Class.Type ) + { + ++g_EtwEventCounters.ullIORead; + } + else if( EVENT_TRACE_TYPE_IO_WRITE == pEvent->Header.Class.Type ) + { + ++g_EtwEventCounters.ullIOWrite; + } +} + +/*****************************************************************************/ +// callback function for LoadImage events +// +void WINAPI eventLoadImage(PEVENT_TRACE pEvent) +{ + if( EVENT_TRACE_TYPE_LOAD == pEvent->Header.Class.Type ) + { + ++g_EtwEventCounters.ullImageLoad; + } +} + +/*****************************************************************************/ +// callback function for memory events +// +void WINAPI eventPageFault(PEVENT_TRACE pEvent) +{ + if( EVENT_TRACE_TYPE_MM_COW == pEvent->Header.Class.Type ) + { + ++g_EtwEventCounters.ullMMCopyOnWrite; + } + else if( EVENT_TRACE_TYPE_MM_DZF == pEvent->Header.Class.Type ) + { + ++g_EtwEventCounters.ullMMDemandZeroFault; + } + else if( EVENT_TRACE_TYPE_MM_GPF == pEvent->Header.Class.Type ) + { + ++g_EtwEventCounters.ullMMGuardPageFault; + } + else if( EVENT_TRACE_TYPE_MM_HPF == pEvent->Header.Class.Type ) + { + ++g_EtwEventCounters.ullMMHardPageFault; + } + else if( EVENT_TRACE_TYPE_MM_TF == pEvent->Header.Class.Type ) + { + ++g_EtwEventCounters.ullMMTransitionFault; + } +} + +/*****************************************************************************/ +// callback function for network and TCP/IP events +// +void WINAPI eventTcpIp(PEVENT_TRACE pEvent) +{ + if( EVENT_TRACE_TYPE_ACCEPT == pEvent->Header.Class.Type ) + { + ++g_EtwEventCounters.ullNetAccept; + } + else if( EVENT_TRACE_TYPE_CONNECT == pEvent->Header.Class.Type ) + { + ++g_EtwEventCounters.ullNetConnect; + } + else if( EVENT_TRACE_TYPE_DISCONNECT == pEvent->Header.Class.Type ) + { + ++g_EtwEventCounters.ullNetDisconnect; + } + else if( EVENT_TRACE_TYPE_RECEIVE == pEvent->Header.Class.Type ) + { + ++g_EtwEventCounters.ullNetTcpReceive; + } + else if( EVENT_TRACE_TYPE_RECONNECT == pEvent->Header.Class.Type ) + { + ++g_EtwEventCounters.ullNetReconnect; + } + else if( EVENT_TRACE_TYPE_RETRANSMIT == pEvent->Header.Class.Type ) + { + ++g_EtwEventCounters.ullNetRetransmit; + } + else if( EVENT_TRACE_TYPE_SEND == pEvent->Header.Class.Type ) + { + ++g_EtwEventCounters.ullNetTcpSend; + } +} + +/*****************************************************************************/ +// callback function for UDP/IP events +// +void WINAPI eventUdpIp(PEVENT_TRACE pEvent) +{ + if( EVENT_TRACE_TYPE_SEND == pEvent->Header.Class.Type ) + { + ++g_EtwEventCounters.ullNetUdpSend; + } + else if( EVENT_TRACE_TYPE_RECEIVE == pEvent->Header.Class.Type ) + { + ++g_EtwEventCounters.ullNetUdpReceive; + } +} + +/*****************************************************************************/ +// callback function for thread events +// +void WINAPI eventThread(PEVENT_TRACE pEvent) +{ + if( EVENT_TRACE_TYPE_START == pEvent->Header.Class.Type ) + { + ++g_EtwEventCounters.ullThreadStart; + } + else if( EVENT_TRACE_TYPE_END == pEvent->Header.Class.Type ) + { + ++g_EtwEventCounters.ullThreadEnd; + } +} + +/*****************************************************************************/ +// callback function for process events +// +void WINAPI eventProcess(PEVENT_TRACE pEvent) +{ + if( EVENT_TRACE_TYPE_START == pEvent->Header.Class.Type ) + { + ++g_EtwEventCounters.ullProcessStart; + } + else if( EVENT_TRACE_TYPE_END == pEvent->Header.Class.Type ) + { + ++g_EtwEventCounters.ullProcessEnd; + } +} + +/*****************************************************************************/ +// callback function for registry events +// +void WINAPI eventRegistry(PEVENT_TRACE pEvent) +{ + if( EVENT_TRACE_TYPE_REGCREATE == pEvent->Header.Class.Type ) + { + ++g_EtwEventCounters.ullRegCreate; + } + else if( EVENT_TRACE_TYPE_REGDELETE == pEvent->Header.Class.Type ) + { + ++g_EtwEventCounters.ullRegDelete; + } + else if( EVENT_TRACE_TYPE_REGDELETEVALUE == pEvent->Header.Class.Type ) + { + ++g_EtwEventCounters.ullRegDeleteValue; + } + else if( EVENT_TRACE_TYPE_REGENUMERATEKEY == pEvent->Header.Class.Type ) + { + ++g_EtwEventCounters.ullRegEnumerateKey; + } + else if( EVENT_TRACE_TYPE_REGENUMERATEVALUEKEY == pEvent->Header.Class.Type ) + { + ++g_EtwEventCounters.ullRegEnumerateValueKey; + } + else if( EVENT_TRACE_TYPE_REGFLUSH == pEvent->Header.Class.Type ) + { + ++g_EtwEventCounters.ullRegFlush; + } +// else if( EVENT_TRACE_TYPE_REGKCBDMP == pEvent->Header.Class.Type ) +// { +// ++ETWEventCounters.ullRegKcbDmp; +// } + else if( EVENT_TRACE_TYPE_REGOPEN == pEvent->Header.Class.Type ) + { + ++g_EtwEventCounters.ullRegOpen; + } + else if( EVENT_TRACE_TYPE_REGQUERY == pEvent->Header.Class.Type ) + { + ++g_EtwEventCounters.ullRegQuery; + } + else if( EVENT_TRACE_TYPE_REGQUERYMULTIPLEVALUE == pEvent->Header.Class.Type ) + { + ++g_EtwEventCounters.ullRegQueryMultipleValue; + } + else if( EVENT_TRACE_TYPE_REGQUERYVALUE == pEvent->Header.Class.Type ) + { + ++g_EtwEventCounters.ullRegQueryValue; + } + else if( EVENT_TRACE_TYPE_REGSETINFORMATION == pEvent->Header.Class.Type ) + { + ++g_EtwEventCounters.ullRegSetInformation; + } + else if( EVENT_TRACE_TYPE_REGSETVALUE == pEvent->Header.Class.Type ) + { + ++g_EtwEventCounters.ullRegSetValue; + } +} + +/*****************************************************************************/ +// starts ETW session and sets callback functions for various groups of events +// +TRACEHANDLE StartETWSession(const Profile& profile) +{ + PEVENT_TRACE_PROPERTIES pProperties; + + pProperties = allocateEventTraceProperties(); + if (nullptr == pProperties) + { + return 0; + } + + pProperties->LogFileMode = EVENT_TRACE_REAL_TIME_MODE; + + //use paged memory + if (profile.GetEtwUsePagedMemory()) + { + pProperties->LogFileMode |= EVENT_TRACE_USE_PAGED_MEMORY; + } + + // + // event classes + // + if (profile.GetEtwProcess()) + { + pProperties->EnableFlags |= EVENT_TRACE_FLAG_PROCESS; + SetTraceCallback(&ProcessGuid, eventThread); + } + + if (profile.GetEtwThread()) + { + pProperties->EnableFlags |= EVENT_TRACE_FLAG_THREAD; + SetTraceCallback(&ThreadGuid, eventThread); + } + + if (profile.GetEtwImageLoad()) + { + pProperties->EnableFlags |= EVENT_TRACE_FLAG_IMAGE_LOAD; + SetTraceCallback(&ImageLoadGuid, eventLoadImage); + } + + if (profile.GetEtwDiskIO()) + { + pProperties->EnableFlags |= EVENT_TRACE_FLAG_DISK_IO; + SetTraceCallback(&DiskIoGuid, eventDiskIo); + } + + if (profile.GetEtwMemoryPageFaults()) + { + pProperties->EnableFlags |= EVENT_TRACE_FLAG_MEMORY_PAGE_FAULTS; + SetTraceCallback(&PageFaultGuid, eventPageFault); + } + + if (profile.GetEtwMemoryHardFaults()) + { + pProperties->EnableFlags |= EVENT_TRACE_FLAG_MEMORY_HARD_FAULTS; + SetTraceCallback(&PageFaultGuid, eventPageFault); + } + + if (profile.GetEtwNetwork()) + { + pProperties->EnableFlags |= EVENT_TRACE_FLAG_NETWORK_TCPIP; + SetTraceCallback(&TcpIpGuid, eventTcpIp); + SetTraceCallback(&UdpIpGuid, eventUdpIp); + } + + if (profile.GetEtwRegistry()) + { + pProperties->EnableFlags |= EVENT_TRACE_FLAG_REGISTRY; + SetTraceCallback(&RegistryGuid, eventRegistry); + } + + // + // timer + // + if (profile.GetEtwUsePerfTimer()) + { + pProperties->Wnode.ClientContext = 1; + } + if (profile.GetEtwUseSystemTimer()) + { + pProperties->Wnode.ClientContext = 2; + } + if (profile.GetEtwUseCyclesCounter()) + { + pProperties->Wnode.ClientContext = 3; + } + + pProperties->Wnode.Guid = SystemTraceControlGuid; + + TRACEHANDLE hTraceSession; + ULONG ret = StartTrace(&hTraceSession, KERNEL_LOGGER_NAME, pProperties); + free(pProperties); + if (ERROR_SUCCESS != ret) + { + PrintError("Error starting trace session\n"); + return 0; + } + + return hTraceSession; +} + +/*****************************************************************************/ +// stops ETW session +// +PEVENT_TRACE_PROPERTIES StopETWSession(TRACEHANDLE hTraceSession) +{ + PEVENT_TRACE_PROPERTIES pProperties; + + pProperties = allocateEventTraceProperties(); + if( NULL == pProperties ) + { + return NULL; + } + + ULONG ret; + + ret = ControlTrace(hTraceSession, NULL, pProperties, EVENT_TRACE_CONTROL_STOP); + if( ERROR_SUCCESS != ret ) + { + PrintError("Error stopping trace session\n"); + return NULL; + } + + //wait + while(g_bTracing) + { + Sleep(10); // TODO: remove active waiting + } + + return pProperties; +} \ No newline at end of file diff --git a/CristalDiskMark/source/diskspd2_0_15a/IORequestGenerator/etw.h b/CristalDiskMark/source/diskspd2_0_15a/IORequestGenerator/etw.h new file mode 100644 index 0000000..4043e35 --- /dev/null +++ b/CristalDiskMark/source/diskspd2_0_15a/IORequestGenerator/etw.h @@ -0,0 +1,41 @@ +/* + +DISKSPD + +Copyright(c) Microsoft Corporation +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#pragma once + + +#include +#include ///WNODE_HEADER +#define INITGUID //Include this #define to use SystemTraceControlGuid in Evntrace.h. +#include //ETW +#include "..\Common\Common.h" + +BOOL TraceEvents(); +TRACEHANDLE StartETWSession(const Profile& profile); +PEVENT_TRACE_PROPERTIES StopETWSession(TRACEHANDLE hTraceSession); \ No newline at end of file diff --git a/CristalDiskMark/source/diskspd2_0_15a/LICENSE b/CristalDiskMark/source/diskspd2_0_15a/LICENSE new file mode 100644 index 0000000..cd7af07 --- /dev/null +++ b/CristalDiskMark/source/diskspd2_0_15a/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2014 Microsoft + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/CristalDiskMark/source/diskspd2_0_15a/LICENSE.txt b/CristalDiskMark/source/diskspd2_0_15a/LICENSE.txt new file mode 100644 index 0000000..b4731ac --- /dev/null +++ b/CristalDiskMark/source/diskspd2_0_15a/LICENSE.txt @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2014 Microsoft + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/CristalDiskMark/source/diskspd2_0_15a/README.md b/CristalDiskMark/source/diskspd2_0_15a/README.md new file mode 100644 index 0000000..d3b8582 --- /dev/null +++ b/CristalDiskMark/source/diskspd2_0_15a/README.md @@ -0,0 +1,14 @@ +DISKSPD +======= + +DISKSPD is a storage load generator / performance test tool from the Windows/Windows Server and Cloud Server Infrastructure Engineering teams. Please see the included documentation (docx and pdf formats). + +Compilation is supported with Visual Studio and Visual Studio Express. Use the Visual Studio solution file inside the diskspd_vs2013 directory. + +Source code is hosted at the following repo, if you did not clone it directly: + +[https://github.com/microsoft/diskspd](https://github.com/microsoft/diskspd "https://github.com/microsoft/diskspd") + +A binary release is hosted by Microsoft at the following location: + +[http://aka.ms/diskspd](http://aka.ms/diskspd "http://aka.ms/diskspd") diff --git a/CristalDiskMark/source/diskspd2_0_15a/ResultParser/ResultParser.cpp b/CristalDiskMark/source/diskspd2_0_15a/ResultParser/ResultParser.cpp new file mode 100644 index 0000000..1719bc9 --- /dev/null +++ b/CristalDiskMark/source/diskspd2_0_15a/ResultParser/ResultParser.cpp @@ -0,0 +1,848 @@ +/* + +DISKSPD + +Copyright(c) Microsoft Corporation +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +// ResultParser.cpp : Defines the entry point for the DLL application. +// +#include "ResultParser.h" + +#include "common.h" + +#include +#include +#include //ntdll.dll + +#include //WNODE_HEADER +#include + +#include + +// TODO: refactor to a single function shared with the XmlResultParser +void ResultParser::_Print(const char *format, ...) +{ + assert(nullptr != format); + va_list listArg; + va_start(listArg, format); + char buffer[4096] = {}; + vsprintf_s(buffer, _countof(buffer), format, listArg); + va_end(listArg); + _sResult += buffer; +} + +/*****************************************************************************/ +// display file size in a user-friendly form +// + +void ResultParser::_DisplayFileSize(UINT64 fsize) +{ + if( fsize > (UINT64)10*1024*1024*1024 ) // > 10GB + { + _Print("%uGB", fsize >> 30); + } + else if( fsize > (UINT64)10*1024*1024 ) // > 10MB + { + _Print("%uMB", fsize >> 20); + } + else if( fsize > 10*1024 ) // > 10KB + { + _Print("%uKB", fsize >> 10); + } + else + { + _Print("%I64uB", fsize); + } +} + +/*****************************************************************************/ +void ResultParser::_DisplayETWSessionInfo(struct ETWSessionInfo sessionInfo) +{ + _Print("\n\n"); + _Print(" ETW Buffer Settings & Statistics\n"); + _Print("--------------------------------------------------------\n"); + _Print("(KB) Buffers (Secs) (Mins)\n"); + _Print("Size | Min | Max | Free | Written | Flush Age\n"); + + _Print("%-5lu %5lu %-5lu %-2lu %8lu %8lu %8d\n\n", + sessionInfo.ulBufferSize, + sessionInfo.ulMinimumBuffers, + sessionInfo.ulMaximumBuffers, + sessionInfo.ulFreeBuffers, + sessionInfo.ulBuffersWritten, + sessionInfo.ulFlushTimer, + sessionInfo.lAgeLimit); + + _Print("Allocated Buffers: %lu\n", + sessionInfo.ulNumberOfBuffers); + + _Print("LOST EVENTS:%15lu\n", + sessionInfo.ulEventsLost); + + _Print("LOST LOG BUFFERS:%10lu\n", + sessionInfo.ulLogBuffersLost); + + _Print("LOST REAL TIME BUFFERS:%4lu\n", + sessionInfo.ulRealTimeBuffersLost); +} + + +/*****************************************************************************/ +void ResultParser::_DisplayETW(struct ETWMask ETWMask, struct ETWEventCounters EtwEventCounters) +{ + _Print("\n\n\nETW:\n"); + _Print("----\n\n"); + + if (ETWMask.bDiskIO) + { + _Print("\tDisk I/O\n"); + + _Print("\t\tRead: %I64u\n", EtwEventCounters.ullIORead); + _Print("\t\tWrite: %I64u\n", EtwEventCounters.ullIOWrite); + } + if (ETWMask.bImageLoad) + { + _Print("\tLoad Image\n"); + + _Print("\t\tLoad Image: %I64u\n", EtwEventCounters.ullImageLoad); + } + if (ETWMask.bMemoryPageFaults) + { + _Print("\tMemory Page Faults\n"); + + _Print("\t\tCopy on Write: %I64u\n", EtwEventCounters.ullMMCopyOnWrite); + _Print("\t\tDemand Zero fault: %I64u\n", EtwEventCounters.ullMMDemandZeroFault); + _Print("\t\tGuard Page fault: %I64u\n", EtwEventCounters.ullMMGuardPageFault); + _Print("\t\tHard page fault: %I64u\n", EtwEventCounters.ullMMHardPageFault); + _Print("\t\tTransition fault: %I64u\n", EtwEventCounters.ullMMTransitionFault); + } + if (ETWMask.bMemoryHardFaults && !ETWMask.bMemoryPageFaults ) + { + _Print("\tMemory Hard Faults\n"); + _Print("\t\tHard page fault: %I64u\n", EtwEventCounters.ullMMHardPageFault); + } + if (ETWMask.bNetwork) + { + _Print("\tNetwork\n"); + + _Print("\t\tAccept: %I64u\n", EtwEventCounters.ullNetAccept); + _Print("\t\tConnect: %I64u\n", EtwEventCounters.ullNetConnect); + _Print("\t\tDisconnect: %I64u\n", EtwEventCounters.ullNetDisconnect); + _Print("\t\tReconnect: %I64u\n", EtwEventCounters.ullNetReconnect); + _Print("\t\tRetransmit: %I64u\n", EtwEventCounters.ullNetRetransmit); + _Print("\t\tTCP/IP Send: %I64u\n", EtwEventCounters.ullNetTcpSend); + _Print("\t\tTCP/IP Receive: %I64u\n", EtwEventCounters.ullNetTcpReceive); + _Print("\t\tUDP/IP Send: %I64u\n", EtwEventCounters.ullNetUdpSend); + _Print("\t\tUDP/IP Receive: %I64u\n", EtwEventCounters.ullNetUdpReceive); + } + if (ETWMask.bProcess) + { + _Print("\tProcess\n"); + + _Print("\t\tStart: %I64u\n", EtwEventCounters.ullProcessStart); + _Print("\t\tEnd: %I64u\n", EtwEventCounters.ullProcessEnd); + } + if (ETWMask.bRegistry) + { + _Print("\tRegistry\n"); + + _Print("\t\tNtCreateKey: %I64u\n", + EtwEventCounters.ullRegCreate); + + _Print("\t\tNtDeleteKey: %I64u\n", + EtwEventCounters.ullRegDelete); + + _Print("\t\tNtDeleteValueKey: %I64u\n", + EtwEventCounters.ullRegDeleteValue); + + _Print("\t\tNtEnumerateKey: %I64u\n", + EtwEventCounters.ullRegEnumerateKey); + + _Print("\t\tNtEnumerateValueKey: %I64u\n", + EtwEventCounters.ullRegEnumerateValueKey); + + _Print("\t\tNtFlushKey: %I64u\n", + EtwEventCounters.ullRegFlush); + + _Print("\t\tKcbDump/create: %I64u\n", + EtwEventCounters.ullRegKcbDmp); + + _Print("\t\tNtOpenKey: %I64u\n", + EtwEventCounters.ullRegOpen); + + _Print("\t\tNtQueryKey: %I64u\n", + EtwEventCounters.ullRegQuery); + + _Print("\t\tNtQueryMultipleValueKey: %I64u\n", + EtwEventCounters.ullRegQueryMultipleValue); + + _Print("\t\tNtQueryValueKey: %I64u\n", + EtwEventCounters.ullRegQueryValue); + + _Print("\t\tNtSetInformationKey: %I64u\n", + EtwEventCounters.ullRegSetInformation); + + _Print("\t\tNtSetValueKey: %I64u\n", + EtwEventCounters.ullRegSetValue); + } + if (ETWMask.bThread) + { + _Print("\tThread\n"); + + _Print("\t\tStart: %I64u\n", EtwEventCounters.ullThreadStart); + _Print("\t\tEnd: %I64u\n", EtwEventCounters.ullThreadEnd); + } +} + +void ResultParser::_PrintTarget(const Target &target, bool fUseThreadsPerFile, bool fCompletionRoutines) +{ + _Print("\tpath: '%s'\n", target.GetPath().c_str()); + _Print("\t\tthink time: %ums\n", target.GetThinkTime()); + _Print("\t\tburst size: %u\n", target.GetBurstSize()); + // TODO: completion routines/ports + + if (target.GetDisableAllCache()) + { + _Print("\t\tsoftware and hardware write cache disabled\n"); + } + else if (target.GetDisableOSCache()) + { + _Print("\t\tsoftware cache disabled\n"); + } + + if (!target.GetDisableAllCache() && !target.GetDisableOSCache()) + { + _Print("\t\tusing software and hardware write cache\n"); + } + + if (target.GetZeroWriteBuffers()) + { + _Print("\t\tzeroing write buffers\n"); + } + + if (target.GetRandomDataWriteBufferSize() > 0) + { + _Print("\t\twrite buffer size: %I64u\n", target.GetRandomDataWriteBufferSize()); + string sWriteBufferSourcePath = target.GetRandomDataWriteBufferSourcePath(); + if (sWriteBufferSourcePath != "") + { + _Print("\t\twrite buffer source: '%s'\n", sWriteBufferSourcePath.c_str()); + } + } + + if (target.GetUseParallelAsyncIO()) + { + _Print("\t\tusing parallel async I/O\n"); + } + + if (target.GetWriteRatio() == 0) + { + _Print("\t\tperforming read test\n"); + } + else if (target.GetWriteRatio() == 100) + { + _Print("\t\tperforming write test\n"); + } + else + { + _Print("\t\tperforming mix test (write/read ratio: %d/100)\n", target.GetWriteRatio()); + } + _Print("\t\tblock size: %d\n", target.GetBlockSizeInBytes()); + if (target.GetUseRandomAccessPattern()) + { + _Print("\t\tusing random I/O (alignment: "); + } + else + { + if (target.GetUseInterlockedSequential()) + { + _Print("\t\tusing interlocked sequential I/O (stride: "); + } + else + { + _Print("\t\tusing sequential I/O (stride: "); + } + } + _Print("%I64u)\n", target.GetBlockAlignmentInBytes()); + + _Print("\t\tnumber of outstanding I/O operations: %d\n", target.GetRequestCount()); + if (0 != target.GetBaseFileOffsetInBytes()) + { + _Print("\t\tbase file offset: %I64u\n", target.GetBaseFileOffsetInBytes()); + } + + if (0 != target.GetMaxFileSize()) + { + _Print("\t\tmax file size: %I64u\n", target.GetMaxFileSize()); + } + + _Print("\t\tthread stride size: %I64u\n", target.GetThreadStrideInBytes()); + + if (target.GetSequentialScanHint()) + { + _Print("\t\tusing FILE_FLAG_SEQUENTIAL_SCAN hint\n"); + } + + if (target.GetRandomAccessHint()) + { + _Print("\t\tusing FILE_FLAG_RANDOM_ACCESS hint\n"); + } + + if (fUseThreadsPerFile) + { + _Print("\t\tthreads per file: %d\n", target.GetThreadsPerFile()); + } + if (target.GetRequestCount() > 1 && fUseThreadsPerFile) + { + if (fCompletionRoutines) + { + _Print("\t\tusing completion routines (ReadFileEx/WriteFileEx)\n"); + } + else + { + _Print("\t\tusing I/O Completion Ports\n"); + } + } + + if (target.GetIOPriorityHint() == IoPriorityHintVeryLow) + { + _Print("\t\tIO priority: very low\n"); + } + else if (target.GetIOPriorityHint() == IoPriorityHintLow) + { + _Print("\t\tIO priority: low\n"); + } + else if (target.GetIOPriorityHint() == IoPriorityHintNormal) + { + _Print("\t\tIO priority: normal\n"); + } + else + { + _Print("\t\tIO priority: unknown\n"); + } +} + +void ResultParser::_PrintTimeSpan(const TimeSpan& timeSpan) +{ + _Print("\tduration: %us\n", timeSpan.GetDuration()); + _Print("\twarm up time: %us\n", timeSpan.GetWarmup()); + _Print("\tcool down time: %us\n", timeSpan.GetCooldown()); + if (timeSpan.GetDisableAffinity()) + { + _Print("\taffinity disabled\n"); + } + if (timeSpan.GetMeasureLatency()) + { + _Print("\tmeasuring latency\n"); + } + if (timeSpan.GetCalculateIopsStdDev()) + { + _Print("\tcalculating IOPS stddev with bucket duration = %u milliseconds\n", timeSpan.GetIoBucketDurationInMilliseconds()); + } + _Print("\trandom seed: %u\n", timeSpan.GetRandSeed()); + + vector vAffinity = timeSpan.GetAffinityAssignments(); + if ( vAffinity.size() > 0) + { + _Print("\tadvanced affinity: "); + for (unsigned int x = 0; x < vAffinity.size(); ++x) + { + _Print("%d", vAffinity[x]); + if (x < vAffinity.size() - 1) + { + _Print(", "); + } + } + _Print("\n"); + } + + vector vTargets(timeSpan.GetTargets()); + for (auto i = vTargets.begin(); i != vTargets.end(); i++) + { + _PrintTarget(*i, (timeSpan.GetThreadCount() == 0), timeSpan.GetCompletionRoutines()); + } +} + +void ResultParser::_PrintProfile(const Profile& profile) +{ + _Print("\nCommand Line: %s\n", profile.GetCmdLine().c_str()); + _Print("\n"); + _Print("Input parameters:\n\n"); + if (profile.GetVerbose()) + { + _Print("\tusing verbose mode\n"); + } + + const vector& vTimeSpans = profile.GetTimeSpans(); + int c = 1; + for (auto i = vTimeSpans.begin(); i != vTimeSpans.end(); i++) + { + _Print("\ttimespan: %3d\n", c++); + _Print("\t-------------\n"); + _PrintTimeSpan(*i); + _Print("\n"); + } +} + +void ResultParser::_PrintCpuUtilization(const Results& results) +{ + size_t ulProcCount = results.vSystemProcessorPerfInfo.size(); + double fTime = PerfTimer::PerfTimeToSeconds(results.ullTimeCount); + + char szFloatBuffer[1024]; + + _Print("\nCPU | Usage | User | Kernel | Idle\n"); + _Print("-------------------------------------------\n"); + + double busyTime = 0; + double totalIdleTime = 0; + double totalUserTime = 0; + double totalKrnlTime = 0; + + for (unsigned int x = 0; x totalLatencyHistogram; + IoBucketizer totalIoBucketizer; + + _PrintSectionFieldNames(timeSpan); + + _PrintSectionBorderLine(timeSpan); + + for (unsigned int iThread = 0; iThread < results.vThreadResults.size(); ++iThread) + { + const ThreadResults& threadResults = results.vThreadResults[iThread]; + for (unsigned int iFile = 0; iFile < threadResults.vTargetResults.size(); iFile++) + { + const TargetResults& targetResults = threadResults.vTargetResults[iFile]; + + UINT64 ullBytesCount = 0; + UINT64 ullIOCount = 0; + + Histogram latencyHistogram; + IoBucketizer ioBucketizer; + + if ((section == _SectionEnum::WRITE) || (section == _SectionEnum::TOTAL)) + { + ullBytesCount += targetResults.ullWriteBytesCount; + ullIOCount += targetResults.ullWriteIOCount; + + if (timeSpan.GetMeasureLatency()) + { + latencyHistogram.Merge(targetResults.writeLatencyHistogram); + totalLatencyHistogram.Merge(targetResults.writeLatencyHistogram); + } + + if (timeSpan.GetCalculateIopsStdDev()) + { + ioBucketizer.Merge(targetResults.writeBucketizer); + totalIoBucketizer.Merge(targetResults.writeBucketizer); + } + } + + if ((section == _SectionEnum::READ) || (section == _SectionEnum::TOTAL)) + { + ullBytesCount += targetResults.ullReadBytesCount; + ullIOCount += targetResults.ullReadIOCount; + + if (timeSpan.GetMeasureLatency()) + { + latencyHistogram.Merge(targetResults.readLatencyHistogram); + totalLatencyHistogram.Merge(targetResults.readLatencyHistogram); + } + + if (timeSpan.GetCalculateIopsStdDev()) + { + ioBucketizer.Merge(targetResults.readBucketizer); + totalIoBucketizer.Merge(targetResults.readBucketizer); + } + } + + _Print("%6u | %15llu | %12llu | %10.2f | %10.2f", + iThread, + ullBytesCount, + ullIOCount, + (double) ullBytesCount / 1024 / 1024 / fTime, + (double) ullIOCount / fTime); + + if (timeSpan.GetMeasureLatency()) + { + double avgLat = latencyHistogram.GetAvg() / 1000; + _Print(" | %8.3f", avgLat); + } + + if (timeSpan.GetCalculateIopsStdDev()) + { + double iopsStdDev = ioBucketizer.GetStandardDeviation() / fBucketTime; + _Print(" | %10.2f", iopsStdDev); + } + + if (timeSpan.GetMeasureLatency()) + { + if (latencyHistogram.GetSampleSize() > 0) + { + double latStdDev = latencyHistogram.GetStandardDeviation() / 1000; + _Print(" | %8.3f", latStdDev); + } + else + { + _Print(" | N/A"); + } + } + + _Print(" | %s (", targetResults.sPath.c_str()); + + _DisplayFileSize(targetResults.ullFileSize); + _Print(")\n"); + + ullTotalBytesCount += ullBytesCount; + ullTotalIOCount += ullIOCount; + } + } + + _PrintSectionBorderLine(timeSpan); + + double totalAvgLat = 0; + + if (timeSpan.GetMeasureLatency()) + { + totalAvgLat = totalLatencyHistogram.GetAvg() / 1000; + } + + _Print("total: %15llu | %12llu | %10.2f | %10.2f", + ullTotalBytesCount, + ullTotalIOCount, + (double) ullTotalBytesCount / 1024 / 1024 / fTime, + (double) ullTotalIOCount / fTime); + + + if (section == _SectionEnum::TOTAL) + { + _totalScore = (int)(ullTotalBytesCount / 1000 / fTime); + } + + if (timeSpan.GetMeasureLatency()) + { + _Print(" | %8.3f", totalAvgLat); + if (section == _SectionEnum::TOTAL) + { + _averageLatency = totalAvgLat; + } + } + + if (timeSpan.GetCalculateIopsStdDev()) + { + double iopsStdDev = totalIoBucketizer.GetStandardDeviation() / fBucketTime; + _Print(" | %10.2f", iopsStdDev); + } + + if (timeSpan.GetMeasureLatency()) + { + if (totalLatencyHistogram.GetSampleSize() > 0) + { + double latStdDev = totalLatencyHistogram.GetStandardDeviation() / 1000; + _Print(" | %8.3f", latStdDev); + } + else + { + _Print(" | N/A"); + } + } + + _Print("\n"); +} + +void ResultParser::_PrintLatencyPercentiles(const Results& results) +{ + Histogram readLatencyHistogram; + Histogram writeLatencyHistogram; + Histogram totalLatencyHistogram; + + for (const auto& thread : results.vThreadResults) + { + for (const auto& target : thread.vTargetResults) + { + readLatencyHistogram.Merge(target.readLatencyHistogram); + + writeLatencyHistogram.Merge(target.writeLatencyHistogram); + + totalLatencyHistogram.Merge(target.writeLatencyHistogram); + totalLatencyHistogram.Merge(target.readLatencyHistogram); + } + } + + bool fHasReads = readLatencyHistogram.GetSampleSize() > 0; + bool fHasWrites = writeLatencyHistogram.GetSampleSize() > 0; + + _Print(" %%-ile | Read (ms) | Write (ms) | Total (ms)\n"); + _Print("----------------------------------------------\n"); + + string readMin = + fHasReads ? + Util::DoubleToStringHelper(readLatencyHistogram.GetMin()/1000) : + "N/A"; + + string writeMin = + fHasWrites ? + Util::DoubleToStringHelper(writeLatencyHistogram.GetMin() / 1000) : + "N/A"; + + _Print(" min | %10s | %10s | %10.3lf\n", + readMin.c_str(), writeMin.c_str(), totalLatencyHistogram.GetMin()/1000); + + PercentileDescriptor percentiles[] = + { + { 0.25, "25th" }, + { 0.50, "50th" }, + { 0.75, "75th" }, + { 0.90, "90th" }, + { 0.95, "95th" }, + { 0.99, "99th" }, + { 0.999, "3-nines" }, + { 0.9999, "4-nines" }, + { 0.99999, "5-nines" }, + { 0.999999, "6-nines" }, + { 0.9999999, "7-nines" }, + { 0.99999999, "8-nines" }, + }; + + for (auto p : percentiles) + { + string readPercentile = + fHasReads ? + Util::DoubleToStringHelper(readLatencyHistogram.GetPercentile(p.Percentile) / 1000) : + "N/A"; + + string writePercentile = + fHasWrites ? + Util::DoubleToStringHelper(writeLatencyHistogram.GetPercentile(p.Percentile) / 1000) : + "N/A"; + + _Print("%7s | %10s | %10s | %10.3lf\n", + p.Name.c_str(), + readPercentile.c_str(), + writePercentile.c_str(), + totalLatencyHistogram.GetPercentile(p.Percentile)/1000); + } + + string readMax = Util::DoubleToStringHelper(readLatencyHistogram.GetMax() / 1000); + string writeMax = Util::DoubleToStringHelper(writeLatencyHistogram.GetMax() / 1000); + + _Print(" max | %10s | %10s | %10.3lf\n", + fHasReads ? readMax.c_str() : "N/A", + fHasWrites ? writeMax.c_str() : "N/A", + totalLatencyHistogram.GetMax()/1000); +} + +int ResultParser::GetTotalScore() +{ + return _totalScore; +} + +double ResultParser::GetAverageLatency() +{ + return _averageLatency; +} + +string ResultParser::ParseResults(Profile& profile, const SystemInformation& system, vector vResults) +{ + // TODO: print text representation of system information (see xml parser) + UNREFERENCED_PARAMETER(system); + + _sResult.clear(); + + _PrintProfile(profile); + + for (size_t iResult = 0; iResult < vResults.size(); iResult++) + { + _Print("\n\nResults for timespan %d:\n", iResult + 1); + _Print("*******************************************************************************\n"); + + const Results& results = vResults[iResult]; + const TimeSpan& timeSpan = profile.GetTimeSpans()[iResult]; + + size_t ulProcCount = results.vSystemProcessorPerfInfo.size(); + double fTime = PerfTimer::PerfTimeToSeconds(results.ullTimeCount); //test duration + + char szFloatBuffer[1024]; + + // There either is a fixed number of threads for all files to share (GetThreadCount() > 0) or a number of threads per file. + // In the latter case vThreadResults.size() == number of threads per file * file count + size_t ulThreadCnt = (timeSpan.GetThreadCount() > 0) ? timeSpan.GetThreadCount() : results.vThreadResults.size(); + + if (fTime < 0.0000001) + { + _Print("The test was interrupted before the measurements began. No results are displayed.\n"); + } + else + { + // TODO: parameters.bCreateFile; + + _Print("\n"); + sprintf_s(szFloatBuffer, sizeof(szFloatBuffer), "actual test time:\t%.2lfs\n", fTime); + _Print("%s", szFloatBuffer); + _Print("thread count:\t\t%u\n", ulThreadCnt); + + _Print("proc count:\t\t%u\n", ulProcCount); + _PrintCpuUtilization(results); + + _Print("\nTotal IO\n"); + _PrintSection(_SectionEnum::TOTAL, timeSpan, results); + + _Print("\nRead IO\n"); + _PrintSection(_SectionEnum::READ, timeSpan, results); + + _Print("\nWrite IO\n"); + _PrintSection(_SectionEnum::WRITE, timeSpan, results); + + if (timeSpan.GetMeasureLatency()) + { + _Print("\n\n"); + _PrintLatencyPercentiles(results); + } + + //etw + if (results.fUseETW) + { + _DisplayETW(results.EtwMask, results.EtwEventCounters); + _DisplayETWSessionInfo(results.EtwSessionInfo); + } + } + } + + if (vResults.size() > 1) + { + _Print("\n\nTotals:\n"); + _Print("*******************************************************************************\n\n"); + _Print("type | bytes | I/Os | MB/s | I/O per s\n"); + _Print("-------------------------------------------------------------------------------\n"); + + + UINT64 cbTotalWritten = 0; + UINT64 cbTotalRead = 0; + UINT64 cTotalWriteIO = 0; + UINT64 cTotalReadIO = 0; + UINT64 cTotalTicks = 0; + for (auto pResults = vResults.begin(); pResults != vResults.end(); pResults++) + { + double time = PerfTimer::PerfTimeToSeconds(pResults->ullTimeCount); + if (time >= 0.0000001) // skip timespans that were interrupted + { + cTotalTicks += pResults->ullTimeCount; + auto vThreadResults = pResults->vThreadResults; + for (auto pThreadResults = vThreadResults.begin(); pThreadResults != vThreadResults.end(); pThreadResults++) + { + for (auto pTargetResults = pThreadResults->vTargetResults.begin(); pTargetResults != pThreadResults->vTargetResults.end(); pTargetResults++) + { + cbTotalRead += pTargetResults->ullReadBytesCount; + cbTotalWritten += pTargetResults->ullWriteBytesCount; + cTotalReadIO += pTargetResults->ullReadIOCount; + cTotalWriteIO += pTargetResults->ullWriteIOCount; + } + } + } + } + + double totalTime = PerfTimer::PerfTimeToSeconds(cTotalTicks); + + _Print("write | %15I64u | %12I64u | %10.2lf | %10.2lf\n", + cbTotalWritten, + cTotalWriteIO, + (double)cbTotalWritten / 1024 / 1024 / totalTime, + (double)cTotalWriteIO / totalTime); + + _Print("read | %15I64u | %12I64u | %10.2lf | %10.2lf\n", + cbTotalRead, + cTotalReadIO, + (double)cbTotalRead / 1024 / 1024 / totalTime, + (double)cTotalReadIO / totalTime); + _Print("-------------------------------------------------------------------------------\n"); + _Print("total | %15I64u | %12I64u | %10.2lf | %10.2lf\n\n", + cbTotalRead + cbTotalWritten, + cTotalReadIO + cTotalWriteIO, + (double)(cbTotalRead + cbTotalWritten) / 1024 / 1024 / totalTime, + (double)(cTotalReadIO + cTotalWriteIO) / totalTime); + + _Print("total test time:\t%.2lfs\n", totalTime); + } + + return _sResult; +} diff --git a/CristalDiskMark/source/diskspd2_0_15a/ResultParser/ResultParser.h b/CristalDiskMark/source/diskspd2_0_15a/ResultParser/ResultParser.h new file mode 100644 index 0000000..7a267d4 --- /dev/null +++ b/CristalDiskMark/source/diskspd2_0_15a/ResultParser/ResultParser.h @@ -0,0 +1,65 @@ +/* + +DISKSPD + +Copyright(c) Microsoft Corporation +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#pragma once +#include "Common.h" + +namespace UnitTests +{ + class ResultParserUnitTests; +} + +class ResultParser : public IResultParser +{ +public: + string ParseResults(Profile& profile, const SystemInformation& system, vector vResults); + int GetTotalScore(); + double GetAverageLatency(); + +private: + void _DisplayFileSize(UINT64 fsize); + void _DisplayETWSessionInfo(struct ETWSessionInfo sessionInfo); + void _DisplayETW(struct ETWMask ETWMask, struct ETWEventCounters EtwEventCounters); + void _Print(const char *format, ...); + void _PrintProfile(const Profile& profile); + void _PrintCpuUtilization(const Results&); + enum class _SectionEnum {TOTAL, READ, WRITE}; + void _PrintSectionFieldNames(const TimeSpan& timeSpan); + void _PrintSectionBorderLine(const TimeSpan& timeSpan); + void _PrintSection(_SectionEnum, const TimeSpan&, const Results&); + void _PrintLatencyPercentiles(const Results&); + void _PrintTimeSpan(const TimeSpan &timeSpan); + void _PrintTarget(const Target &target, bool fUseThreadsPerFile, bool fCompletionRoutines); + + string _sResult; + int _totalScore; + double _averageLatency; + + friend class UnitTests::ResultParserUnitTests; +}; \ No newline at end of file diff --git a/CristalDiskMark/source/diskspd2_0_15a/XmlProfileParser/XmlProfileParser.cpp b/CristalDiskMark/source/diskspd2_0_15a/XmlProfileParser/XmlProfileParser.cpp new file mode 100644 index 0000000..920d6fb --- /dev/null +++ b/CristalDiskMark/source/diskspd2_0_15a/XmlProfileParser/XmlProfileParser.cpp @@ -0,0 +1,885 @@ +/* + +DISKSPD + +Copyright(c) Microsoft Corporation +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#include "XmlProfileParser.h" +#include +#include +#include + +// the vc com headers define a partial set of smartptr typedefs, which unfortunately +// aren't 1) complete for our use case and 2) vary between revs of the headers. +// this define disables the automatic definitions, letting us do them ourselves. +#define _COM_NO_STANDARD_GUIDS_ +#include + +_COM_SMARTPTR_TYPEDEF(IXMLDOMDocument2, __uuidof(IXMLDOMDocument2)); +_COM_SMARTPTR_TYPEDEF(IXMLDOMNode, __uuidof(IXMLDOMNodeList)); +_COM_SMARTPTR_TYPEDEF(IXMLDOMNodeList, __uuidof(IXMLDOMNodeList)); + +bool XmlProfileParser::ParseFile(const char *pszPath, Profile *pProfile) +{ + assert(pszPath != nullptr); + assert(pProfile != nullptr); + + bool fComInitialized = false; + HRESULT hr = CoInitialize(nullptr); + if (SUCCEEDED(hr)) + { + fComInitialized = true; + IXMLDOMDocument2Ptr spXmlDoc; + hr = CoCreateInstance(__uuidof(DOMDocument60), nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&spXmlDoc)); + if (SUCCEEDED(hr)) + { + hr = spXmlDoc->put_async(VARIANT_FALSE); + if (SUCCEEDED(hr)) + { + VARIANT_BOOL fvIsOk; + _variant_t vPath(pszPath); + hr = spXmlDoc->load(vPath, &fvIsOk); + if (SUCCEEDED(hr)) + { + bool fVerbose; + hr = _GetVerbose(spXmlDoc, &fVerbose); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + pProfile->SetVerbose(fVerbose); + } + + if (SUCCEEDED(hr)) + { + DWORD dwProgress; + hr = _GetProgress(spXmlDoc, &dwProgress); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + pProfile->SetProgress(dwProgress); + } + } + + if (SUCCEEDED(hr)) + { + string sResultFormat; + hr = _GetString(spXmlDoc, "//Profile/ResultFormat", &sResultFormat); + if (SUCCEEDED(hr) && (hr != S_FALSE) && sResultFormat == "xml") + { + pProfile->SetResultsFormat(ResultsFormat::Xml); + } + } + + if (SUCCEEDED(hr)) + { + string sCreateFiles; + hr = _GetString(spXmlDoc, "//Profile/PrecreateFiles", &sCreateFiles); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + if (sCreateFiles == "UseMaxSize") + { + pProfile->SetPrecreateFiles(PrecreateFiles::UseMaxSize); + } + else if (sCreateFiles == "CreateOnlyFilesWithConstantSizes") + { + pProfile->SetPrecreateFiles(PrecreateFiles::OnlyFilesWithConstantSizes); + } + else if (sCreateFiles == "CreateOnlyFilesWithConstantOrZeroSizes") + { + pProfile->SetPrecreateFiles(PrecreateFiles::OnlyFilesWithConstantOrZeroSizes); + } + else + { + hr = E_INVALIDARG; + } + } + } + + if (SUCCEEDED(hr)) + { + hr = _ParseEtw(spXmlDoc, pProfile); + } + + if (SUCCEEDED(hr)) + { + hr = _ParseTimeSpans(spXmlDoc, pProfile); + } + } + } + } + } + if (fComInitialized) + { + CoUninitialize(); + } + return SUCCEEDED(hr); +} + +HRESULT XmlProfileParser::_ParseEtw(IXMLDOMDocument2 &XmlDoc, Profile *pProfile) +{ + bool fEtwProcess; + HRESULT hr = _GetBool(XmlDoc, "//Profile/ETW/Process", &fEtwProcess); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + pProfile->SetEtwEnabled(true); + pProfile->SetEtwProcess(fEtwProcess); + } + + if (SUCCEEDED(hr)) + { + bool fEtwThread; + hr = _GetBool(XmlDoc, "//Profile/ETW/Thread", &fEtwThread); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + pProfile->SetEtwEnabled(true); + pProfile->SetEtwThread(fEtwThread); + } + } + + if (SUCCEEDED(hr)) + { + bool fEtwImageLoad; + hr = _GetBool(XmlDoc, "//Profile/ETW/ImageLoad", &fEtwImageLoad); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + pProfile->SetEtwEnabled(true); + pProfile->SetEtwImageLoad(fEtwImageLoad); + } + } + + if (SUCCEEDED(hr)) + { + bool fEtwDiskIO; + hr = _GetBool(XmlDoc, "//Profile/ETW/DiskIO", &fEtwDiskIO); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + pProfile->SetEtwEnabled(true); + pProfile->SetEtwDiskIO(fEtwDiskIO); + } + } + + if (SUCCEEDED(hr)) + { + bool fEtwMemoryPageFaults; + hr = _GetBool(XmlDoc, "//Profile/ETW/MemoryPageFaults", &fEtwMemoryPageFaults); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + pProfile->SetEtwEnabled(true); + pProfile->SetEtwMemoryPageFaults(fEtwMemoryPageFaults); + } + } + + if (SUCCEEDED(hr)) + { + bool fEtwMemoryHardFaults; + hr = _GetBool(XmlDoc, "//Profile/ETW/MemoryHardFaults", &fEtwMemoryHardFaults); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + pProfile->SetEtwEnabled(true); + pProfile->SetEtwMemoryHardFaults(fEtwMemoryHardFaults); + } + } + + if (SUCCEEDED(hr)) + { + bool fEtwNetwork; + hr = _GetBool(XmlDoc, "//Profile/ETW/Network", &fEtwNetwork); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + pProfile->SetEtwEnabled(true); + pProfile->SetEtwNetwork(fEtwNetwork); + } + } + + if (SUCCEEDED(hr)) + { + bool fEtwRegistry; + hr = _GetBool(XmlDoc, "//Profile/ETW/Registry", &fEtwRegistry); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + pProfile->SetEtwEnabled(true); + pProfile->SetEtwRegistry(fEtwRegistry); + } + } + + if (SUCCEEDED(hr)) + { + bool fEtwUsePagedMemory; + hr = _GetBool(XmlDoc, "//Profile/ETW/UsePagedMemory", &fEtwUsePagedMemory); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + pProfile->SetEtwEnabled(true); + pProfile->SetEtwUsePagedMemory(fEtwUsePagedMemory); + } + } + + if (SUCCEEDED(hr)) + { + bool fEtwUsePerfTimer; + hr = _GetBool(XmlDoc, "//Profile/ETW/UsePerfTimer", &fEtwUsePerfTimer); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + pProfile->SetEtwEnabled(true); + pProfile->SetEtwUsePerfTimer(fEtwUsePerfTimer); + } + } + + if (SUCCEEDED(hr)) + { + bool fEtwUseSystemTimer; + hr = _GetBool(XmlDoc, "//Profile/ETW/UseSystemTimer", &fEtwUseSystemTimer); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + pProfile->SetEtwEnabled(true); + pProfile->SetEtwUseSystemTimer(fEtwUseSystemTimer); + } + } + + if (SUCCEEDED(hr)) + { + bool fEtwUseCyclesCounter; + hr = _GetBool(XmlDoc, "//Profile/ETW/UseCyclesCounter", &fEtwUseCyclesCounter); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + pProfile->SetEtwEnabled(true); + pProfile->SetEtwUseCyclesCounter(fEtwUseCyclesCounter); + } + } + + return hr; +} + +HRESULT XmlProfileParser::_ParseTimeSpans(IXMLDOMDocument2 &XmlDoc, Profile *pProfile) +{ + IXMLDOMNodeListPtr spNodeList; + _variant_t query("//Profile/TimeSpans/TimeSpan"); + HRESULT hr = XmlDoc.selectNodes(query.bstrVal, &spNodeList); + if (SUCCEEDED(hr)) + { + long cNodes; + hr = spNodeList->get_length(&cNodes); + if (SUCCEEDED(hr)) + { + for (int i = 0; i < cNodes; i++) + { + IXMLDOMNodePtr spNode; + hr = spNodeList->get_item(i, &spNode); + if (SUCCEEDED(hr)) + { + TimeSpan timeSpan; + hr = _ParseTimeSpan(spNode, &timeSpan); + if (SUCCEEDED(hr)) + { + pProfile->AddTimeSpan(timeSpan); + } + } + } + } + } + + return hr; +} + +HRESULT XmlProfileParser::_ParseTimeSpan(IXMLDOMNode &XmlNode, TimeSpan *pTimeSpan) +{ + UINT32 ulDuration; + HRESULT hr = _GetUINT32(XmlNode, "Duration", &ulDuration); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + pTimeSpan->SetDuration(ulDuration); + } + + if (SUCCEEDED(hr)) + { + UINT32 ulWarmup; + hr = _GetUINT32(XmlNode, "Warmup", &ulWarmup); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + pTimeSpan->SetWarmup(ulWarmup); + } + } + + if (SUCCEEDED(hr)) + { + UINT32 ulCooldown; + hr = _GetUINT32(XmlNode, "Cooldown", &ulCooldown); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + pTimeSpan->SetCooldown(ulCooldown); + } + } + + if (SUCCEEDED(hr)) + { + UINT32 ulRandSeed; + hr = _GetUINT32(XmlNode, "RandSeed", &ulRandSeed); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + pTimeSpan->SetRandSeed(ulRandSeed); + } + } + + if (SUCCEEDED(hr)) + { + UINT32 ulThreadCount; + hr = _GetUINT32(XmlNode, "ThreadCount", &ulThreadCount); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + pTimeSpan->SetThreadCount(ulThreadCount); + } + } + + if (SUCCEEDED(hr)) + { + bool fGroupAffinity; + hr = _GetBool(XmlNode, "GroupAffinity", &fGroupAffinity); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + pTimeSpan->SetGroupAffinity(fGroupAffinity); + } + } + + if (SUCCEEDED(hr)) + { + bool fDisableAffinity; + hr = _GetBool(XmlNode, "DisableAffinity", &fDisableAffinity); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + pTimeSpan->SetDisableAffinity(fDisableAffinity); + } + } + + if (SUCCEEDED(hr)) + { + bool fCompletionRoutines; + hr = _GetBool(XmlNode, "CompletionRoutines", &fCompletionRoutines); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + pTimeSpan->SetCompletionRoutines(fCompletionRoutines); + } + } + + if (SUCCEEDED(hr)) + { + bool fMeasureLatency; + hr = _GetBool(XmlNode, "MeasureLatency", &fMeasureLatency); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + pTimeSpan->SetMeasureLatency(fMeasureLatency); + } + } + + if (SUCCEEDED(hr)) + { + bool fCalculateIopsStdDev; + hr = _GetBool(XmlNode, "CalculateIopsStdDev", &fCalculateIopsStdDev); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + pTimeSpan->SetCalculateIopsStdDev(fCalculateIopsStdDev); + } + } + + if (SUCCEEDED(hr)) + { + UINT32 ulIoBucketDuration; + hr = _GetUINT32(XmlNode, "IoBucketDuration", &ulIoBucketDuration); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + pTimeSpan->SetIoBucketDurationInMilliseconds(ulIoBucketDuration); + } + } + + if (SUCCEEDED(hr)) + { + hr = _ParseAffinityAssignment(XmlNode, pTimeSpan); + } + + if (SUCCEEDED(hr)) + { + hr = _ParseTargets(XmlNode, pTimeSpan); + } + return hr; +} + +HRESULT XmlProfileParser::_ParseTargets(IXMLDOMNode &XmlNode, TimeSpan *pTimeSpan) +{ + _variant_t query("Targets/Target"); + IXMLDOMNodeListPtr spNodeList; + HRESULT hr = XmlNode.selectNodes(query.bstrVal, &spNodeList); + if (SUCCEEDED(hr)) + { + long cNodes; + hr = spNodeList->get_length(&cNodes); + if (SUCCEEDED(hr)) + { + for (int i = 0; i < cNodes; i++) + { + IXMLDOMNodePtr spNode; + hr = spNodeList->get_item(i, &spNode); + if (SUCCEEDED(hr)) + { + Target target; + _ParseTarget(spNode, &target); + pTimeSpan->AddTarget(target); + } + } + } + } + return hr; +} + +HRESULT XmlProfileParser::_ParseRandomDataSource(IXMLDOMNode &XmlNode, Target *pTarget) +{ + IXMLDOMNodeListPtr spNodeList; + _variant_t query("RandomDataSource"); + HRESULT hr = XmlNode.selectNodes(query.bstrVal, &spNodeList); + if (SUCCEEDED(hr)) + { + long cNodes; + hr = spNodeList->get_length(&cNodes); + if (SUCCEEDED(hr) && (cNodes == 1)) + { + IXMLDOMNodePtr spNode; + hr = spNodeList->get_item(0, &spNode); + if (SUCCEEDED(hr)) + { + UINT64 cb; + hr = _GetUINT64(spNode, "SizeInBytes", &cb); + if (SUCCEEDED(hr) && (S_FALSE != hr)) + { + pTarget->SetRandomDataWriteBufferSize(cb); + + string sPath; + hr = _GetString(spNode, "FilePath", &sPath); + if (SUCCEEDED(hr) && (S_FALSE != hr)) + { + pTarget->SetRandomDataWriteBufferSourcePath(sPath); + } + } + } + } + } + return hr; +} + +HRESULT XmlProfileParser::_ParseWriteBufferContent(IXMLDOMNode &XmlNode, Target *pTarget) +{ + IXMLDOMNodeListPtr spNodeList; + _variant_t query("WriteBufferContent"); + HRESULT hr = XmlNode.selectNodes(query.bstrVal, &spNodeList); + if (SUCCEEDED(hr)) + { + long cNodes; + hr = spNodeList->get_length(&cNodes); + if (SUCCEEDED(hr) && (cNodes == 1)) + { + IXMLDOMNodePtr spNode; + hr = spNodeList->get_item(0, &spNode); + if (SUCCEEDED(hr)) + { + string sPattern; + hr = _GetString(spNode, "Pattern", &sPattern); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + if (sPattern == "sequential") + { + // that's the default option - do nothing + } + else if (sPattern == "zero") + { + pTarget->SetZeroWriteBuffers(true); + } + else if (sPattern == "random") + { + hr = _ParseRandomDataSource(spNode, pTarget); + } + else + { + hr = E_INVALIDARG; + } + } + } + } + } + return hr; +} + +HRESULT XmlProfileParser::_ParseTarget(IXMLDOMNode &XmlNode, Target *pTarget) +{ + string sPath; + HRESULT hr = _GetString(XmlNode, "Path", &sPath); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + pTarget->SetPath(sPath); + } + + if (SUCCEEDED(hr)) + { + DWORD dwBlockSize; + hr = _GetDWORD(XmlNode, "BlockSize", &dwBlockSize); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + pTarget->SetBlockSizeInBytes(dwBlockSize); + } + } + + if (SUCCEEDED(hr)) + { + UINT64 ullStrideSize; + hr = _GetUINT64(XmlNode, "StrideSize", &ullStrideSize); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + pTarget->SetBlockAlignmentInBytes(ullStrideSize); + } + } + + if (SUCCEEDED(hr)) + { + bool fInterlockedSequential; + hr = _GetBool(XmlNode, "InterlockedSequential", &fInterlockedSequential); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + pTarget->SetUseInterlockedSequential(fInterlockedSequential); + } + } + + if (SUCCEEDED(hr)) + { + UINT64 ullBaseFileOffset; + hr = _GetUINT64(XmlNode, "BaseFileOffset", &ullBaseFileOffset); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + pTarget->SetBaseFileOffsetInBytes(ullBaseFileOffset); + } + } + + if (SUCCEEDED(hr)) + { + bool fSequentialScan; + hr = _GetBool(XmlNode, "SequentialScan", &fSequentialScan); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + pTarget->SetSequentialScanHint(fSequentialScan); + } + } + + if (SUCCEEDED(hr)) + { + bool fRandomAccess; + hr = _GetBool(XmlNode, "RandomAccess", &fRandomAccess); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + pTarget->SetRandomAccessHint(fRandomAccess); + } + } + + if (SUCCEEDED(hr)) + { + bool fUseLargePages; + hr = _GetBool(XmlNode, "UseLargePages", &fUseLargePages); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + pTarget->SetUseLargePages(fUseLargePages); + } + } + + if (SUCCEEDED(hr)) + { + DWORD dwRequestCount; + hr = _GetDWORD(XmlNode, "RequestCount", &dwRequestCount); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + pTarget->SetRequestCount(dwRequestCount); + } + } + + if (SUCCEEDED(hr)) + { + UINT64 ullRandom; + hr = _GetUINT64(XmlNode, "Random", &ullRandom); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + pTarget->SetUseRandomAccessPattern(true); + pTarget->SetBlockAlignmentInBytes(ullRandom); + } + } + + if (SUCCEEDED(hr)) + { + bool fDisableOSCache; + hr = _GetBool(XmlNode, "DisableOSCache", &fDisableOSCache); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + pTarget->SetDisableOSCache(fDisableOSCache); + } + } + + if (SUCCEEDED(hr)) + { + bool fDisableAllCache; + hr = _GetBool(XmlNode, "DisableAllCache", &fDisableAllCache); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + pTarget->SetDisableAllCache(fDisableAllCache); + } + } + + if (SUCCEEDED(hr)) + { + hr = _ParseWriteBufferContent(XmlNode, pTarget); + } + + if (SUCCEEDED(hr)) + { + DWORD dwBurstSize; + hr = _GetDWORD(XmlNode, "BurstSize", &dwBurstSize); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + pTarget->SetBurstSize(dwBurstSize); + pTarget->SetUseBurstSize(true); + } + } + + if (SUCCEEDED(hr)) + { + DWORD dwThinkTime; + hr = _GetDWORD(XmlNode, "ThinkTime", &dwThinkTime); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + pTarget->SetThinkTime(dwThinkTime); + pTarget->SetEnableThinkTime(true); + } + } + + if (SUCCEEDED(hr)) + { + DWORD dwThroughput; + hr = _GetDWORD(XmlNode, "Throughput", &dwThroughput); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + pTarget->SetThroughput(dwThroughput); + } + } + + if (SUCCEEDED(hr)) + { + DWORD dwThreadsPerFile; + hr = _GetDWORD(XmlNode, "ThreadsPerFile", &dwThreadsPerFile); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + pTarget->SetThreadsPerFile(dwThreadsPerFile); + } + } + + if (SUCCEEDED(hr)) + { + UINT64 ullFileSize; + hr = _GetUINT64(XmlNode, "FileSize", &ullFileSize); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + pTarget->SetFileSize(ullFileSize); + pTarget->SetCreateFile(true); + } + } + + if (SUCCEEDED(hr)) + { + UINT64 ullMaxFileSize; + hr = _GetUINT64(XmlNode, "MaxFileSize", &ullMaxFileSize); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + pTarget->SetMaxFileSize(ullMaxFileSize); + } + } + + if (SUCCEEDED(hr)) + { + UINT32 ulWriteRatio; + hr = _GetUINT32(XmlNode, "WriteRatio", &ulWriteRatio); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + pTarget->SetWriteRatio(ulWriteRatio); + } + } + + if (SUCCEEDED(hr)) + { + bool fParallelAsyncIO; + hr = _GetBool(XmlNode, "ParallelAsyncIO", &fParallelAsyncIO); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + pTarget->SetUseParallelAsyncIO(fParallelAsyncIO); + } + } + + if (SUCCEEDED(hr)) + { + UINT64 ullThreadStride; + hr = _GetUINT64(XmlNode, "ThreadStride", &ullThreadStride); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + pTarget->SetThreadStrideInBytes(ullThreadStride); + } + } + + if (SUCCEEDED(hr)) + { + UINT32 ulIOPriority; + hr = _GetUINT32(XmlNode, "IOPriority", &ulIOPriority); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + PRIORITY_HINT hint[] = { IoPriorityHintVeryLow, IoPriorityHintLow, IoPriorityHintNormal }; + pTarget->SetIOPriorityHint(hint[ulIOPriority - 1]); + } + } + return hr; +} + +HRESULT XmlProfileParser::_ParseAffinityAssignment(IXMLDOMNode &XmlNode, TimeSpan *pTimeSpan) +{ + IXMLDOMNodeListPtr spNodeList; + _variant_t query("Affinity/AffinityAssignment"); + HRESULT hr = XmlNode.selectNodes(query.bstrVal, &spNodeList); + if (SUCCEEDED(hr)) + { + long cNodes; + hr = spNodeList->get_length(&cNodes); + if (SUCCEEDED(hr)) + { + for (int i = 0; i < cNodes; i++) + { + IXMLDOMNodePtr spNode; + hr = spNodeList->get_item(i, &spNode); + if (SUCCEEDED(hr)) + { + BSTR bstrText; + hr = spNode->get_text(&bstrText); + if (SUCCEEDED(hr)) + { + pTimeSpan->AddAffinityAssignment(_wtoi((wchar_t *)bstrText)); // TODO: change to unsigned + SysFreeString(bstrText); + } + } + } + } + } + return hr; +} + +HRESULT XmlProfileParser::_GetUINT32(IXMLDOMNode &XmlNode, const char *pszQuery, UINT32 *pulValue) const +{ + IXMLDOMNodePtr spNode; + _variant_t query(pszQuery); + HRESULT hr = XmlNode.selectSingleNode(query.bstrVal, &spNode); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + BSTR bstrText; + hr = spNode->get_text(&bstrText); + if (SUCCEEDED(hr)) + { + *pulValue = _wtoi((wchar_t *)bstrText); // TODO: make sure it works on large unsigned ints + SysFreeString(bstrText); + } + } + return hr; +} + +HRESULT XmlProfileParser::_GetString(IXMLDOMNode &XmlNode, const char *pszQuery, string *psValue) const +{ + IXMLDOMNodePtr spNode; + _variant_t query(pszQuery); + HRESULT hr = XmlNode.selectSingleNode(query.bstrVal, &spNode); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + BSTR bstrText; + hr = spNode->get_text(&bstrText); + if (SUCCEEDED(hr)) + { + // TODO: use wstring? + char path[MAX_PATH] = {}; + WideCharToMultiByte(CP_UTF8, 0 /*dwFlags*/, (wchar_t *)bstrText, static_cast(wcslen((wchar_t *)bstrText)), path, sizeof(path)-1, 0 /*lpDefaultChar*/, 0 /*lpUsedDefaultChar*/); + *psValue = string(path); + } + SysFreeString(bstrText); + } + return hr; +} + +HRESULT XmlProfileParser::_GetUINT64(IXMLDOMNode &XmlNode, const char *pszQuery, UINT64 *pullValue) const +{ + IXMLDOMNodePtr spNode; + _variant_t query(pszQuery); + HRESULT hr = XmlNode.selectSingleNode(query.bstrVal, &spNode); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + BSTR bstrText; + hr = spNode->get_text(&bstrText); + if (SUCCEEDED(hr)) + { + *pullValue = _wtoi64((wchar_t *)bstrText); // TODO: make sure it works on large unsigned ints + } + SysFreeString(bstrText); + } + return hr; +} + +HRESULT XmlProfileParser::_GetDWORD(IXMLDOMNode &XmlNode, const char *pszQuery, DWORD *pdwValue) const +{ + UINT32 value = 0; + HRESULT hr = _GetUINT32(XmlNode, pszQuery, &value); + if (SUCCEEDED(hr)) + { + *pdwValue = value; + } + return hr; +} + +HRESULT XmlProfileParser::_GetBool(IXMLDOMNode &XmlNode, const char *pszQuery, bool *pfValue) const +{ + HRESULT hr = S_OK; + IXMLDOMNodePtr spNode; + _variant_t query(pszQuery); + hr = XmlNode.selectSingleNode(query.bstrVal, &spNode); + if (SUCCEEDED(hr) && (hr != S_FALSE)) + { + BSTR bstrText; + hr = spNode->get_text(&bstrText); + if (SUCCEEDED(hr)) + { + *pfValue = (_wcsicmp(L"true", (wchar_t *)bstrText) == 0); + SysFreeString(bstrText); + } + } + return hr; +} + +HRESULT XmlProfileParser::_GetVerbose(IXMLDOMDocument2 &pXmlDoc, bool *pfVerbose) +{ + return _GetBool(pXmlDoc, "//Profile/Verbose", pfVerbose); +} + +HRESULT XmlProfileParser::_GetProgress(IXMLDOMDocument2 &pXmlDoc, DWORD *pdwProgress) +{ + return _GetDWORD(pXmlDoc, "//Profile/Progress", pdwProgress); +} \ No newline at end of file diff --git a/CristalDiskMark/source/diskspd2_0_15a/XmlProfileParser/XmlProfileParser.h b/CristalDiskMark/source/diskspd2_0_15a/XmlProfileParser/XmlProfileParser.h new file mode 100644 index 0000000..a378b73 --- /dev/null +++ b/CristalDiskMark/source/diskspd2_0_15a/XmlProfileParser/XmlProfileParser.h @@ -0,0 +1,57 @@ +/* + +DISKSPD + +Copyright(c) Microsoft Corporation +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#pragma once +#include +#include "Common.h" + +class XmlProfileParser +{ +public: + bool ParseFile(const char *pszPath, Profile *pProfile); + +private: + HRESULT _ParseEtw(IXMLDOMDocument2 &XmlDoc, Profile *pProfile); + HRESULT _ParseTimeSpans(IXMLDOMDocument2 &XmlDoc, Profile *pProfile); + HRESULT _ParseTimeSpan(IXMLDOMNode &XmlNode, TimeSpan *pTimeSpan); + HRESULT _ParseTargets(IXMLDOMNode &XmlNode, TimeSpan *pTimeSpan); + HRESULT _ParseRandomDataSource(IXMLDOMNode &XmlNode, Target *pTarget); + HRESULT _ParseWriteBufferContent(IXMLDOMNode &XmlNode, Target *pTarget); + HRESULT _ParseTarget(IXMLDOMNode &XmlNode, Target *pTarget); + HRESULT _ParseAffinityAssignment(IXMLDOMNode &XmlNode, TimeSpan *pTimeSpan); + + HRESULT _GetString(IXMLDOMNode &XmlNode, const char *pszQuery, string *psValue) const; + HRESULT _GetUINT32(IXMLDOMNode &XmlNode, const char *pszQuery, UINT32 *pulValue) const; + HRESULT _GetUINT64(IXMLDOMNode &XmlNode, const char *pszQuery, UINT64 *pullValue) const; + HRESULT _GetDWORD(IXMLDOMNode &XmlNode, const char *pszQuery, DWORD *pdwValue) const; + HRESULT _GetBool(IXMLDOMNode &XmlNode, const char *pszQuery, bool *pfValue) const; + + HRESULT _GetVerbose(IXMLDOMDocument2 &XmlDoc, bool *pfVerbose); + HRESULT _GetProgress(IXMLDOMDocument2 &XmlDoc, DWORD *pdwProgress); +}; \ No newline at end of file diff --git a/CristalDiskMark/source/diskspd2_0_15a/XmlProfileParser/diskspd.h b/CristalDiskMark/source/diskspd2_0_15a/XmlProfileParser/diskspd.h new file mode 100644 index 0000000..befd642 --- /dev/null +++ b/CristalDiskMark/source/diskspd2_0_15a/XmlProfileParser/diskspd.h @@ -0,0 +1,273 @@ +#pragma once + +#using +#using +#using +#using + +using namespace System::Security::Permissions; +[assembly:SecurityPermissionAttribute(SecurityAction::RequestMinimum, SkipVerification=false)]; +// +// このソース コードは xsd によって自動生成されました。Version=4.0.30319.33440 です。 +// +using namespace System; +ref class NewDataSet; + + +///

+///Represents a strongly typed in-memory cache of data. +/// +[System::Serializable, +System::ComponentModel::DesignerCategoryAttribute(L"code"), +System::ComponentModel::ToolboxItem(true), +System::Xml::Serialization::XmlSchemaProviderAttribute(L"GetTypedDataSetSchema"), +System::Xml::Serialization::XmlRootAttribute(L"NewDataSet"), +System::ComponentModel::Design::HelpKeywordAttribute(L"vs.data.DataSet")] +public ref class NewDataSet : public ::System::Data::DataSet { + + private: ::System::Data::SchemaSerializationMode _schemaSerializationMode; + + public: [System::Diagnostics::DebuggerNonUserCodeAttribute] + [System::CodeDom::Compiler::GeneratedCodeAttribute(L"System.Data.Design.TypedDataSetGenerator", L"4.0.0.0")] + NewDataSet(); + protected: [System::Diagnostics::DebuggerNonUserCodeAttribute] + [System::CodeDom::Compiler::GeneratedCodeAttribute(L"System.Data.Design.TypedDataSetGenerator", L"4.0.0.0")] + NewDataSet(::System::Runtime::Serialization::SerializationInfo^ info, ::System::Runtime::Serialization::StreamingContext context); + public: [System::Diagnostics::DebuggerNonUserCodeAttribute, + System::CodeDom::Compiler::GeneratedCodeAttribute(L"System.Data.Design.TypedDataSetGenerator", L"4.0.0.0"), + System::ComponentModel::BrowsableAttribute(true), + System::ComponentModel::DesignerSerializationVisibilityAttribute(::System::ComponentModel::DesignerSerializationVisibility::Visible)] + virtual property ::System::Data::SchemaSerializationMode SchemaSerializationMode { + ::System::Data::SchemaSerializationMode get() override; + System::Void set(::System::Data::SchemaSerializationMode value) override; + } + + public: [System::Diagnostics::DebuggerNonUserCodeAttribute, + System::CodeDom::Compiler::GeneratedCodeAttribute(L"System.Data.Design.TypedDataSetGenerator", L"4.0.0.0"), + System::ComponentModel::DesignerSerializationVisibilityAttribute(::System::ComponentModel::DesignerSerializationVisibility::Hidden)] + property ::System::Data::DataTableCollection^ Tables { + ::System::Data::DataTableCollection^ get() new; + } + + public: [System::Diagnostics::DebuggerNonUserCodeAttribute, + System::CodeDom::Compiler::GeneratedCodeAttribute(L"System.Data.Design.TypedDataSetGenerator", L"4.0.0.0"), + System::ComponentModel::DesignerSerializationVisibilityAttribute(::System::ComponentModel::DesignerSerializationVisibility::Hidden)] + property ::System::Data::DataRelationCollection^ Relations { + ::System::Data::DataRelationCollection^ get() new; + } + + protected: [System::Diagnostics::DebuggerNonUserCodeAttribute] + [System::CodeDom::Compiler::GeneratedCodeAttribute(L"System.Data.Design.TypedDataSetGenerator", L"4.0.0.0")] + virtual ::System::Void InitializeDerivedDataSet() override; + + public: [System::Diagnostics::DebuggerNonUserCodeAttribute] + [System::CodeDom::Compiler::GeneratedCodeAttribute(L"System.Data.Design.TypedDataSetGenerator", L"4.0.0.0")] + virtual ::System::Data::DataSet^ Clone() override; + + protected: [System::Diagnostics::DebuggerNonUserCodeAttribute] + [System::CodeDom::Compiler::GeneratedCodeAttribute(L"System.Data.Design.TypedDataSetGenerator", L"4.0.0.0")] + virtual ::System::Boolean ShouldSerializeTables() override; + + protected: [System::Diagnostics::DebuggerNonUserCodeAttribute] + [System::CodeDom::Compiler::GeneratedCodeAttribute(L"System.Data.Design.TypedDataSetGenerator", L"4.0.0.0")] + virtual ::System::Boolean ShouldSerializeRelations() override; + + protected: [System::Diagnostics::DebuggerNonUserCodeAttribute] + [System::CodeDom::Compiler::GeneratedCodeAttribute(L"System.Data.Design.TypedDataSetGenerator", L"4.0.0.0")] + virtual ::System::Void ReadXmlSerializable(::System::Xml::XmlReader^ reader) override; + + protected: [System::Diagnostics::DebuggerNonUserCodeAttribute] + [System::CodeDom::Compiler::GeneratedCodeAttribute(L"System.Data.Design.TypedDataSetGenerator", L"4.0.0.0")] + virtual ::System::Xml::Schema::XmlSchema^ GetSchemaSerializable() override; + + internal: [System::Diagnostics::DebuggerNonUserCodeAttribute] + [System::CodeDom::Compiler::GeneratedCodeAttribute(L"System.Data.Design.TypedDataSetGenerator", L"4.0.0.0")] + ::System::Void InitVars(); + + internal: [System::Diagnostics::DebuggerNonUserCodeAttribute] + [System::CodeDom::Compiler::GeneratedCodeAttribute(L"System.Data.Design.TypedDataSetGenerator", L"4.0.0.0")] + ::System::Void InitVars(::System::Boolean initTable); + + private: [System::Diagnostics::DebuggerNonUserCodeAttribute] + [System::CodeDom::Compiler::GeneratedCodeAttribute(L"System.Data.Design.TypedDataSetGenerator", L"4.0.0.0")] + ::System::Void InitClass(); + + private: [System::Diagnostics::DebuggerNonUserCodeAttribute] + [System::CodeDom::Compiler::GeneratedCodeAttribute(L"System.Data.Design.TypedDataSetGenerator", L"4.0.0.0")] + ::System::Void SchemaChanged(::System::Object^ sender, ::System::ComponentModel::CollectionChangeEventArgs^ e); + + public: [System::Diagnostics::DebuggerNonUserCodeAttribute] + [System::CodeDom::Compiler::GeneratedCodeAttribute(L"System.Data.Design.TypedDataSetGenerator", L"4.0.0.0")] + static ::System::Xml::Schema::XmlSchemaComplexType^ GetTypedDataSetSchema(::System::Xml::Schema::XmlSchemaSet^ xs); +}; + + +inline NewDataSet::NewDataSet() { + this->BeginInit(); + this->InitClass(); + ::System::ComponentModel::CollectionChangeEventHandler^ schemaChangedHandler = gcnew ::System::ComponentModel::CollectionChangeEventHandler(this, &NewDataSet::SchemaChanged); + __super::Tables->CollectionChanged += schemaChangedHandler; + __super::Relations->CollectionChanged += schemaChangedHandler; + this->EndInit(); +} + +inline NewDataSet::NewDataSet(::System::Runtime::Serialization::SerializationInfo^ info, ::System::Runtime::Serialization::StreamingContext context) : + ::System::Data::DataSet(info, context, false) { + if (this->IsBinarySerialized(info, context) == true) { + this->InitVars(false); + ::System::ComponentModel::CollectionChangeEventHandler^ schemaChangedHandler1 = gcnew ::System::ComponentModel::CollectionChangeEventHandler(this, &NewDataSet::SchemaChanged); + this->Tables->CollectionChanged += schemaChangedHandler1; + this->Relations->CollectionChanged += schemaChangedHandler1; + return; + } + ::System::String^ strSchema = (cli::safe_cast<::System::String^ >(info->GetValue(L"XmlSchema", ::System::String::typeid))); + if (this->DetermineSchemaSerializationMode(info, context) == ::System::Data::SchemaSerializationMode::IncludeSchema) { + ::System::Data::DataSet^ ds = (gcnew ::System::Data::DataSet()); + ds->ReadXmlSchema((gcnew ::System::Xml::XmlTextReader((gcnew ::System::IO::StringReader(strSchema))))); + this->DataSetName = ds->DataSetName; + this->Prefix = ds->Prefix; + this->Namespace = ds->Namespace; + this->Locale = ds->Locale; + this->CaseSensitive = ds->CaseSensitive; + this->EnforceConstraints = ds->EnforceConstraints; + this->Merge(ds, false, ::System::Data::MissingSchemaAction::Add); + this->InitVars(); + } + else { + this->ReadXmlSchema((gcnew ::System::Xml::XmlTextReader((gcnew ::System::IO::StringReader(strSchema))))); + } + this->GetSerializationData(info, context); + ::System::ComponentModel::CollectionChangeEventHandler^ schemaChangedHandler = gcnew ::System::ComponentModel::CollectionChangeEventHandler(this, &NewDataSet::SchemaChanged); + __super::Tables->CollectionChanged += schemaChangedHandler; + this->Relations->CollectionChanged += schemaChangedHandler; +} + +inline ::System::Data::SchemaSerializationMode NewDataSet::SchemaSerializationMode::get() { + return this->_schemaSerializationMode; +} +inline System::Void NewDataSet::SchemaSerializationMode::set(::System::Data::SchemaSerializationMode value) { + this->_schemaSerializationMode = __identifier(value); +} + +inline ::System::Data::DataTableCollection^ NewDataSet::Tables::get() { + return __super::Tables; +} + +inline ::System::Data::DataRelationCollection^ NewDataSet::Relations::get() { + return __super::Relations; +} + +inline ::System::Void NewDataSet::InitializeDerivedDataSet() { + this->BeginInit(); + this->InitClass(); + this->EndInit(); +} + +inline ::System::Data::DataSet^ NewDataSet::Clone() { + NewDataSet^ cln = (cli::safe_cast(__super::Clone())); + cln->InitVars(); + cln->SchemaSerializationMode = this->SchemaSerializationMode; + return cln; +} + +inline ::System::Boolean NewDataSet::ShouldSerializeTables() { + return false; +} + +inline ::System::Boolean NewDataSet::ShouldSerializeRelations() { + return false; +} + +inline ::System::Void NewDataSet::ReadXmlSerializable(::System::Xml::XmlReader^ reader) { + if (this->DetermineSchemaSerializationMode(reader) == ::System::Data::SchemaSerializationMode::IncludeSchema) { + this->Reset(); + ::System::Data::DataSet^ ds = (gcnew ::System::Data::DataSet()); + ds->ReadXml(reader); + this->DataSetName = ds->DataSetName; + this->Prefix = ds->Prefix; + this->Namespace = ds->Namespace; + this->Locale = ds->Locale; + this->CaseSensitive = ds->CaseSensitive; + this->EnforceConstraints = ds->EnforceConstraints; + this->Merge(ds, false, ::System::Data::MissingSchemaAction::Add); + this->InitVars(); + } + else { + this->ReadXml(reader); + this->InitVars(); + } +} + +inline ::System::Xml::Schema::XmlSchema^ NewDataSet::GetSchemaSerializable() { + ::System::IO::MemoryStream^ stream = (gcnew ::System::IO::MemoryStream()); + this->WriteXmlSchema((gcnew ::System::Xml::XmlTextWriter(stream, nullptr))); + stream->Position = 0; + return ::System::Xml::Schema::XmlSchema::Read((gcnew ::System::Xml::XmlTextReader(stream)), nullptr); +} + +inline ::System::Void NewDataSet::InitVars() { + this->InitVars(true); +} + +inline ::System::Void NewDataSet::InitVars(::System::Boolean initTable) { +} + +inline ::System::Void NewDataSet::InitClass() { + this->DataSetName = L"NewDataSet"; + this->Prefix = L""; + this->Namespace = L"http://microsoft.com/diskspd/DiskSpdConfig.xsd"; + this->Locale = (gcnew ::System::Globalization::CultureInfo(L"")); + this->EnforceConstraints = true; + this->SchemaSerializationMode = ::System::Data::SchemaSerializationMode::IncludeSchema; +} + +inline ::System::Void NewDataSet::SchemaChanged(::System::Object^ sender, ::System::ComponentModel::CollectionChangeEventArgs^ e) { + if (e->Action == ::System::ComponentModel::CollectionChangeAction::Remove) { + this->InitVars(); + } +} + +inline ::System::Xml::Schema::XmlSchemaComplexType^ NewDataSet::GetTypedDataSetSchema(::System::Xml::Schema::XmlSchemaSet^ xs) { + NewDataSet^ ds = (gcnew NewDataSet()); + ::System::Xml::Schema::XmlSchemaComplexType^ type = (gcnew ::System::Xml::Schema::XmlSchemaComplexType()); + ::System::Xml::Schema::XmlSchemaSequence^ sequence = (gcnew ::System::Xml::Schema::XmlSchemaSequence()); + ::System::Xml::Schema::XmlSchemaAny^ any = (gcnew ::System::Xml::Schema::XmlSchemaAny()); + any->Namespace = ds->Namespace; + sequence->Items->Add(any); + type->Particle = sequence; + ::System::Xml::Schema::XmlSchema^ dsSchema = ds->GetSchemaSerializable(); + if (xs->Contains(dsSchema->TargetNamespace)) { + ::System::IO::MemoryStream^ s1 = (gcnew ::System::IO::MemoryStream()); + ::System::IO::MemoryStream^ s2 = (gcnew ::System::IO::MemoryStream()); + try { + ::System::Xml::Schema::XmlSchema^ schema = nullptr; + dsSchema->Write(s1); + for ( ::System::Collections::IEnumerator^ schemas = xs->Schemas(dsSchema->TargetNamespace)->GetEnumerator(); schemas->MoveNext(); ) { + schema = (cli::safe_cast<::System::Xml::Schema::XmlSchema^ >(schemas->Current)); + s2->SetLength(0); + schema->Write(s2); + if (s1->Length == s2->Length) { + s1->Position = 0; + s2->Position = 0; + for ( ; ((s1->Position != s1->Length) + && (s1->ReadByte() == s2->ReadByte())); ) { + ; + } + if (s1->Position == s1->Length) { + return type; + } + } + } + } + finally { + if (s1 != nullptr) { + s1->Close(); + } + if (s2 != nullptr) { + s2->Close(); + } + } + } + xs->Add(dsSchema); + return type; +} diff --git a/CristalDiskMark/source/diskspd2_0_15a/XmlProfileParser/diskspd.xsd b/CristalDiskMark/source/diskspd2_0_15a/XmlProfileParser/diskspd.xsd new file mode 100644 index 0000000..945d578 --- /dev/null +++ b/CristalDiskMark/source/diskspd2_0_15a/XmlProfileParser/diskspd.xsd @@ -0,0 +1,236 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/CristalDiskMark/source/diskspd2_0_15a/XmlResultParser/exe/DiskSpd32.exe b/CristalDiskMark/source/diskspd2_0_15a/XmlResultParser/exe/DiskSpd32.exe new file mode 100644 index 0000000000000000000000000000000000000000..e52a2ad2adf7f8eb12ff7bc27e52b3a50d9c7a73 GIT binary patch literal 365112 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

%xWNz$94o^G2!2Eyl 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

Li_51Cnj&&YL5uc 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 obMIrGTK6lD%s\n", results.sPath.c_str()); + _Print("%I64u\n", results.ullBytesCount); + _Print("%I64u\n", results.ullFileSize); + _Print("%I64u\n", results.ullIOCount); + _Print("%I64u\n", results.ullReadBytesCount); + _Print("%I64u\n", results.ullReadIOCount); + _Print("%I64u\n", results.ullWriteBytesCount); + _Print("%I64u\n", results.ullWriteIOCount); +} + +void XmlResultParser::_PrintTargetLatency(const TargetResults& results) +{ + if (results.readLatencyHistogram.GetSampleSize() > 0) + { + _Print("%.3f\n", results.readLatencyHistogram.GetAvg() / 1000); + _Print("%.3f\n", results.readLatencyHistogram.GetStandardDeviation() / 1000); + } + if (results.writeLatencyHistogram.GetSampleSize() > 0) + { + _Print("%.3f\n", results.writeLatencyHistogram.GetAvg() / 1000); + _Print("%.3f\n", results.writeLatencyHistogram.GetStandardDeviation() / 1000); + } + Histogram totalLatencyHistogram; + totalLatencyHistogram.Merge(results.readLatencyHistogram); + totalLatencyHistogram.Merge(results.writeLatencyHistogram); + if (totalLatencyHistogram.GetSampleSize() > 0) + { + _Print("%.3f\n", totalLatencyHistogram.GetAvg() / 1000); + _Print("%.3f\n", totalLatencyHistogram.GetStandardDeviation() / 1000); + } +} + +void XmlResultParser::_PrintTargetIops(const IoBucketizer& readBucketizer, const IoBucketizer& writeBucketizer, UINT32 bucketTimeInMs) +{ + _Print("\n"); + + IoBucketizer totalIoBucketizer; + totalIoBucketizer.Merge(readBucketizer); + totalIoBucketizer.Merge(writeBucketizer); + + if (readBucketizer.GetNumberOfValidBuckets() > 0) + { + _Print("%.3f\n", readBucketizer.GetStandardDeviation() / (bucketTimeInMs / 1000.0)); + } + if (writeBucketizer.GetNumberOfValidBuckets() > 0) + { + _Print("%.3f\n", writeBucketizer.GetStandardDeviation() / (bucketTimeInMs / 1000.0)); + } + if (totalIoBucketizer.GetNumberOfValidBuckets() > 0) + { + _Print("%.3f\n", totalIoBucketizer.GetStandardDeviation() / (bucketTimeInMs / 1000.0)); + } + _PrintIops(readBucketizer, writeBucketizer, bucketTimeInMs); + _Print("\n"); +} + +void XmlResultParser::_PrintETWSessionInfo(struct ETWSessionInfo sessionInfo) +{ + _Print("\n"); + _Print("%lu\n", sessionInfo.ulBufferSize); + _Print("%lu\n", sessionInfo.ulMinimumBuffers); + _Print("%lu\n", sessionInfo.ulMaximumBuffers); + _Print("%lu", sessionInfo.ulFreeBuffers); + _Print("%lu\n", sessionInfo.ulBuffersWritten); + _Print("%lu\n", sessionInfo.ulFlushTimer); + _Print("%d\n", sessionInfo.lAgeLimit); + + _Print("%lu\n", sessionInfo.ulNumberOfBuffers); + _Print("%15lu\n", sessionInfo.ulEventsLost); + _Print("%10lu\n", sessionInfo.ulLogBuffersLost); + _Print("%4lu\n", sessionInfo.ulRealTimeBuffersLost); + _Print("\n"); +} + +void XmlResultParser::_PrintETW(struct ETWMask ETWMask, struct ETWEventCounters EtwEventCounters) +{ + _Print("\n"); + if (ETWMask.bDiskIO) + { + _Print("\n"); + _Print("%I64u\n", EtwEventCounters.ullIORead); + _Print("%I64u\n", EtwEventCounters.ullIOWrite); + _Print("\n"); + } + if (ETWMask.bImageLoad) + { + _Print("%I64u\n", EtwEventCounters.ullImageLoad); + } + if (ETWMask.bMemoryPageFaults) + { + _Print("\n"); + _Print("%I64u\n", EtwEventCounters.ullMMCopyOnWrite); + _Print("%I64u\n", EtwEventCounters.ullMMDemandZeroFault); + _Print("%I64u\n", EtwEventCounters.ullMMGuardPageFault); + _Print("%I64u\n", EtwEventCounters.ullMMHardPageFault); + _Print("%I64u\n", EtwEventCounters.ullMMTransitionFault); + _Print("\n"); + } + if (ETWMask.bMemoryHardFaults && !ETWMask.bMemoryPageFaults) + { + _Print("%I64u\n", EtwEventCounters.ullMMHardPageFault); + } + if (ETWMask.bNetwork) + { + _Print("\n"); + _Print("%I64u\n", EtwEventCounters.ullNetAccept); + _Print("%I64u\n", EtwEventCounters.ullNetConnect); + _Print("%I64u\n", EtwEventCounters.ullNetDisconnect); + _Print("%I64u\n", EtwEventCounters.ullNetReconnect); + _Print("%I64u\n", EtwEventCounters.ullNetRetransmit); + _Print("%I64u\n", EtwEventCounters.ullNetTcpSend); + _Print("%I64u\n", EtwEventCounters.ullNetTcpReceive); + _Print("%I64u\n", EtwEventCounters.ullNetUdpSend); + _Print("%I64u\n", EtwEventCounters.ullNetUdpReceive); + _Print("\n"); + } + if (ETWMask.bProcess) + { + _Print("\n"); + _Print("%I64u\n", EtwEventCounters.ullProcessStart); + _Print("%I64u\n", EtwEventCounters.ullProcessEnd); + _Print("\n"); + } + if (ETWMask.bRegistry) + { + _Print("\n"); + _Print("%I64u\n", EtwEventCounters.ullRegCreate); + _Print("%I64u\n", EtwEventCounters.ullRegDelete); + _Print("%I64u\n", EtwEventCounters.ullRegDeleteValue); + _Print("%I64u\n", EtwEventCounters.ullRegEnumerateKey); + _Print("%I64u\n", EtwEventCounters.ullRegEnumerateValueKey); + _Print("%I64u\n", EtwEventCounters.ullRegFlush); + _Print("%I64u\n", EtwEventCounters.ullRegKcbDmp); + _Print("%I64u\n", EtwEventCounters.ullRegOpen); + _Print("%I64u\n", EtwEventCounters.ullRegQuery); + _Print("%I64u\n", EtwEventCounters.ullRegQueryMultipleValue); + _Print("%I64u\n", EtwEventCounters.ullRegQueryValue); + _Print("%I64u\n", EtwEventCounters.ullRegSetInformation); + _Print("%I64u\n", EtwEventCounters.ullRegSetValue); + _Print("\n"); + } + if (ETWMask.bThread) + { + _Print("\n"); + _Print("%I64u\n", EtwEventCounters.ullThreadStart); + _Print("%I64u\n", EtwEventCounters.ullThreadEnd); + _Print("\n"); + } + _Print("\n"); +} + +void XmlResultParser::_PrintCpuUtilization(const Results& results) +{ + size_t ulProcCount = results.vSystemProcessorPerfInfo.size(); + double fTime = PerfTimer::PerfTimeToSeconds(results.ullTimeCount); + + _Print("\n"); + + double busyTime = 0; + double totalIdleTime = 0; + double totalUserTime = 0; + double totalKrnlTime = 0; + + for (unsigned int x = 0; x\n"); + _Print("%d\n", x); + _Print("%.2f\n", thisTime); + _Print("%.2f\n", userTime); + _Print("%.2f\n", krnlTime - idleTime); + _Print("%.2f\n", idleTime); + _Print("\n"); + + busyTime += thisTime; + totalIdleTime += idleTime; + totalUserTime += userTime; + totalKrnlTime += krnlTime; + } + _Print("\n"); + _Print("%.2f\n", busyTime / ulProcCount); + _Print("%.2f\n", totalUserTime / ulProcCount); + _Print("%.2f\n", (totalKrnlTime - totalIdleTime) / ulProcCount); + _Print("%.2f\n", totalIdleTime / ulProcCount); + _Print("\n"); + + _Print("\n"); +} + +// emit the iops time series (this obviates needing perfmon counters, in common cases, and provides file level data) +void XmlResultParser::_PrintIops(const IoBucketizer& readBucketizer, const IoBucketizer& writeBucketizer, UINT32 bucketTimeInMs) +{ + bool done = false; + for (size_t i = 0; !done; i++) + { + done = true; + + double r = 0.0; + double w = 0.0; + + if (readBucketizer.GetNumberOfValidBuckets() > i) + { + r = readBucketizer.GetIoBucket(i) / (bucketTimeInMs / 1000.0); + done = false; + } + if (writeBucketizer.GetNumberOfValidBuckets() > i) + { + w = writeBucketizer.GetIoBucket(i) / (bucketTimeInMs / 1000.0); + done = false; + } + if (!done) + { + _Print("\n", bucketTimeInMs*(i + 1), r, w, r + w); + } + } +} + +void XmlResultParser::_PrintOverallIops(const Results& results, UINT32 bucketTimeInMs) +{ + IoBucketizer readBucketizer; + IoBucketizer writeBucketizer; + + for (const auto& thread : results.vThreadResults) + { + for (const auto& target : thread.vTargetResults) + { + readBucketizer.Merge(target.readBucketizer); + writeBucketizer.Merge(target.writeBucketizer); + } + } + + _PrintTargetIops(readBucketizer, writeBucketizer, bucketTimeInMs); +} + +void XmlResultParser::_PrintLatencyPercentiles(const Results& results) +{ + Histogram readLatencyHistogram; + Histogram writeLatencyHistogram; + Histogram totalLatencyHistogram; + + for (const auto& thread : results.vThreadResults) + { + for (const auto& target : thread.vTargetResults) + { + readLatencyHistogram.Merge(target.readLatencyHistogram); + + writeLatencyHistogram.Merge(target.writeLatencyHistogram); + + totalLatencyHistogram.Merge(target.writeLatencyHistogram); + totalLatencyHistogram.Merge(target.readLatencyHistogram); + } + } + + _Print("\n"); + if (readLatencyHistogram.GetSampleSize() > 0) + { + _Print("%.3f\n", readLatencyHistogram.GetAvg() / 1000); + _Print("%.3f\n", readLatencyHistogram.GetStandardDeviation() / 1000); + } + if (writeLatencyHistogram.GetSampleSize() > 0) + { + _Print("%.3f\n", writeLatencyHistogram.GetAvg() / 1000); + _Print("%.3f\n", writeLatencyHistogram.GetStandardDeviation() / 1000); + } + if (totalLatencyHistogram.GetSampleSize() > 0) + { + _Print("%.3f\n", totalLatencyHistogram.GetAvg() / 1000); + _Print("%.3f\n", totalLatencyHistogram.GetStandardDeviation() / 1000); + } + + _Print("\n"); + _Print("0\n"); + if (readLatencyHistogram.GetSampleSize() > 0) + { + _Print("%.3f\n", readLatencyHistogram.GetMin() / 1000); + } + if (writeLatencyHistogram.GetSampleSize() > 0) + { + _Print("%.3f\n", writeLatencyHistogram.GetMin() / 1000); + } + if (totalLatencyHistogram.GetSampleSize() > 0) + { + _Print("%.3f\n", totalLatencyHistogram.GetMin() / 1000); + } + _Print("\n"); + + // Construct vector of percentiles and decimal precision to squelch trailing zeroes. This is more + // detailed than summary text output, and does not contain the decorated names (15th, etc.) + + vector> vPercentiles; + for (int p = 1; p <= 99; p++) + { + vPercentiles.push_back(make_pair(0, p)); + } + + vPercentiles.push_back(make_pair(1, 99.9)); + vPercentiles.push_back(make_pair(2, 99.99)); + vPercentiles.push_back(make_pair(3, 99.999)); + vPercentiles.push_back(make_pair(4, 99.9999)); + vPercentiles.push_back(make_pair(5, 99.99999)); + vPercentiles.push_back(make_pair(6, 99.999999)); + + for (auto p : vPercentiles) + { + _Print("\n"); + _Print("%.*f\n", p.first, p.second); + if (readLatencyHistogram.GetSampleSize() > 0) + { + _Print("%.3f\n", readLatencyHistogram.GetPercentile(p.second / 100) / 1000); + } + if (writeLatencyHistogram.GetSampleSize() > 0) + { + _Print("%.3f\n", writeLatencyHistogram.GetPercentile(p.second / 100) / 1000); + } + if (totalLatencyHistogram.GetSampleSize() > 0) + { + _Print("%.3f\n", totalLatencyHistogram.GetPercentile(p.second / 100) / 1000); + } + _Print("\n"); + } + + _Print("\n"); + _Print("100\n"); + if (readLatencyHistogram.GetSampleSize() > 0) + { + _Print("%.3f\n", readLatencyHistogram.GetMax() / 1000); + } + if (writeLatencyHistogram.GetSampleSize() > 0) + { + _Print("%.3f\n", writeLatencyHistogram.GetMax() / 1000); + } + if (totalLatencyHistogram.GetSampleSize() > 0) + { + _Print("%.3f\n", totalLatencyHistogram.GetMax() / 1000); + } + _Print("\n"); + _Print("\n"); +} + +int XmlResultParser::GetTotalScore() +{ + return 0; +} + +double XmlResultParser::GetAverageLatency() +{ + return 0.0; +} + +string XmlResultParser::ParseResults(Profile& profile, const SystemInformation& system, vector vResults) +{ + _sResult.clear(); + + _Print("\n"); + _sResult += system.GetXml(); + _sResult += profile.GetXml(); + for (size_t iResults = 0; iResults < vResults.size(); iResults++) + { + const Results& results = vResults[iResults]; + const TimeSpan& timeSpan = profile.GetTimeSpans()[iResults]; + + _Print("\n"); + double fTime = PerfTimer::PerfTimeToSeconds(results.ullTimeCount); //test duration + if (fTime >= 0.0000001) + { + // There either is a fixed number of threads for all files to share (GetThreadCount() > 0) or a number of threads per file. + // In the latter case vThreadResults.size() == number of threads per file * file count + size_t ulThreadCnt = (timeSpan.GetThreadCount() > 0) ? timeSpan.GetThreadCount() : results.vThreadResults.size(); + size_t ulProcCount = results.vSystemProcessorPerfInfo.size(); + + _Print("%.2f\n", fTime); + _Print("%u\n", ulThreadCnt); + _Print("%u\n", ulProcCount); + + _PrintCpuUtilization(results); + + if (timeSpan.GetMeasureLatency()) + { + _PrintLatencyPercentiles(results); + } + + if (timeSpan.GetCalculateIopsStdDev()) + { + _PrintOverallIops(results, timeSpan.GetIoBucketDurationInMilliseconds()); + } + + if (results.fUseETW) + { + _PrintETW(results.EtwMask, results.EtwEventCounters); + _PrintETWSessionInfo(results.EtwSessionInfo); + } + + for (size_t iThread = 0; iThread < results.vThreadResults.size(); iThread++) + { + const ThreadResults& threadResults = results.vThreadResults[iThread]; + _Print("\n"); + _Print("%u\n", iThread); + for (const auto& targetResults : threadResults.vTargetResults) + { + _Print("\n"); + _PrintTargetResults(targetResults); + if (timeSpan.GetMeasureLatency()) + { + _PrintTargetLatency(targetResults); + } + if (timeSpan.GetCalculateIopsStdDev()) + { + _PrintTargetIops(targetResults.readBucketizer, targetResults.writeBucketizer, timeSpan.GetIoBucketDurationInMilliseconds()); + } + _Print("\n"); + } + _Print("\n"); + } + } + else + { + _Print("The test was interrupted before the measurements began. No results are displayed.\n"); + } + _Print("\n"); + } + _Print(""); + return _sResult; +} \ No newline at end of file diff --git a/CristalDiskMark/source/diskspd2_0_15a/XmlResultParser/xmlresultparser.h b/CristalDiskMark/source/diskspd2_0_15a/XmlResultParser/xmlresultparser.h new file mode 100644 index 0000000..b55a47e --- /dev/null +++ b/CristalDiskMark/source/diskspd2_0_15a/XmlResultParser/xmlresultparser.h @@ -0,0 +1,53 @@ +/* + +DISKSPD + +Copyright(c) Microsoft Corporation +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#pragma once +#include "Common.h" + +class XmlResultParser: public IResultParser +{ +public: + string ParseResults(Profile& profile, const SystemInformation& system, vector vResults); + int GetTotalScore(); + double GetAverageLatency(); + +private: + void _PrintCpuUtilization(const Results& results); + void _PrintETW(struct ETWMask ETWMask, struct ETWEventCounters EtwEventCounters); + void _PrintETWSessionInfo(struct ETWSessionInfo sessionInfo); + void _PrintLatencyPercentiles(const Results& results); + void _PrintTargetResults(const TargetResults& results); + void _PrintTargetLatency(const TargetResults& results); + void _PrintTargetIops(const IoBucketizer& readBucketizer, const IoBucketizer& writeBucketizer, UINT32 bucketTimeInMs); + void _PrintOverallIops(const Results& results, UINT32 bucketTimeInMs); + void _PrintIops(const IoBucketizer& readBucketizer, const IoBucketizer& writeBucketizer, UINT32 bucketTimeInMs); + void _Print(const char *format, ...); + + string _sResult; +}; \ No newline at end of file diff --git a/CristalDiskMark/source/diskspd2_0_15a/diskspd_vs2015/CmdLineParser/CmdLineParser.vcxproj b/CristalDiskMark/source/diskspd2_0_15a/diskspd_vs2015/CmdLineParser/CmdLineParser.vcxproj new file mode 100644 index 0000000..5d05051 --- /dev/null +++ b/CristalDiskMark/source/diskspd2_0_15a/diskspd_vs2015/CmdLineParser/CmdLineParser.vcxproj @@ -0,0 +1,153 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {0EF5CE78-8E92-4A1B-A255-0F544AADA291} + CmdLineParser + 8.1 + + + + StaticLibrary + true + v140 + MultiByte + + + StaticLibrary + true + v140 + MultiByte + + + StaticLibrary + false + v140 + true + MultiByte + + + StaticLibrary + false + v140 + true + MultiByte + + + + + + + + + + + + + + + + + + + $(SolutionDir)\..\Common;$(IncludePath) + + + $(SolutionDir)\..\Common;$(IncludePath) + + + $(SolutionDir)\..\Common;$(IncludePath) + + + $(SolutionDir)\..\Common;$(IncludePath) + + + + Level3 + Disabled + true + false + true + + + true + + + false + + + + + Level3 + Disabled + true + false + true + + + true + + + true + + + + + Level3 + MaxSpeed + true + true + true + true + MultiThreaded + NoExtensions + + + true + true + true + + + + + Level3 + MaxSpeed + true + true + true + true + MultiThreaded + + + true + true + true + + + + + + + + + + + + \ No newline at end of file diff --git a/CristalDiskMark/source/diskspd2_0_15a/diskspd_vs2015/CmdLineParser/CmdLineParser.vcxproj.user b/CristalDiskMark/source/diskspd2_0_15a/diskspd_vs2015/CmdLineParser/CmdLineParser.vcxproj.user new file mode 100644 index 0000000..6fb136b --- /dev/null +++ b/CristalDiskMark/source/diskspd2_0_15a/diskspd_vs2015/CmdLineParser/CmdLineParser.vcxproj.user @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/CristalDiskMark/source/diskspd2_0_15a/diskspd_vs2015/CmdRequestCreator/CmdRequestCreator.vcxproj b/CristalDiskMark/source/diskspd2_0_15a/diskspd_vs2015/CmdRequestCreator/CmdRequestCreator.vcxproj new file mode 100644 index 0000000..b643762 --- /dev/null +++ b/CristalDiskMark/source/diskspd2_0_15a/diskspd_vs2015/CmdRequestCreator/CmdRequestCreator.vcxproj @@ -0,0 +1,166 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {D238F8AA-DE12-49E7-B4A7-9B69579A69C0} + CmdRequestCreator + 8.1 + + + + Application + true + v141 + MultiByte + + + Application + true + v141 + MultiByte + + + Application + false + v140 + true + MultiByte + + + Application + false + v140 + true + MultiByte + + + + + + + + + + + + + + + + + + + $(SolutionDir)\..\Common;$(IncludePath) + diskspd + + + $(SolutionDir)\..\Common;$(IncludePath) + diskspd + false + + + $(SolutionDir)\..\Common;$(IncludePath) + diskspd32 + + + $(SolutionDir)\..\Common;$(IncludePath) + diskspd64 + + + + Level3 + Disabled + true + false + true + + + true + $(SolutionDir)$(Configuration)\xmlprofileparser.lib;$(SolutionDir)$(Configuration)\iorequestgenerator.lib;$(SolutionDir)$(Configuration)\resultparser.lib;$(SolutionDir)$(Configuration)\xmlresultparser.lib;$(SolutionDir)$(Configuration)\common.lib;msxml6.lib;%(AdditionalDependencies) + Default + + + + + Level3 + Disabled + true + false + true + + + true + $(SolutionDir)$(Platform)\$(Configuration)\xmlprofileparser.lib;$(SolutionDir)$(Platform)\$(Configuration)\iorequestgenerator.lib;$(SolutionDir)$(Platform)\$(Configuration)\resultparser.lib;$(SolutionDir)$(Platform)\$(Configuration)\xmlresultparser.lib;$(SolutionDir)$(Platform)\$(Configuration)\common.lib;msxml6.lib;%(AdditionalDependencies) + Default + + + + + Level3 + MaxSpeed + true + true + true + true + MultiThreaded + NoExtensions + + + true + true + true + fileextd.lib;$(SolutionDir)$(Configuration)\xmlprofileparser.lib;$(SolutionDir)$(Configuration)\iorequestgenerator.lib;$(SolutionDir)$(Configuration)\resultparser.lib;$(SolutionDir)$(Configuration)\xmlresultparser.lib;$(SolutionDir)$(Configuration)\common.lib;msxml6.lib;%(AdditionalDependencies) + /SUBSYSTEM:CONSOLE,5.01 %(AdditionalOptions) + + + + + Level3 + MaxSpeed + true + true + true + true + MultiThreaded + + + true + true + true + fileextd.lib;$(SolutionDir)$(Platform)\$(Configuration)\xmlprofileparser.lib;$(SolutionDir)$(Platform)\$(Configuration)\iorequestgenerator.lib;$(SolutionDir)$(Platform)\$(Configuration)\resultparser.lib;$(SolutionDir)$(Platform)\$(Configuration)\xmlresultparser.lib;$(SolutionDir)$(Platform)\$(Configuration)\common.lib;msxml6.lib;%(AdditionalDependencies) + /SUBSYSTEM:CONSOLE,5.02 %(AdditionalOptions) + + + + + {0ef5ce78-8e92-4a1b-a255-0f544aada291} + + + + + + + + + + + + + \ No newline at end of file diff --git a/CristalDiskMark/source/diskspd2_0_15a/diskspd_vs2015/CmdRequestCreator/CmdRequestCreator.vcxproj.user b/CristalDiskMark/source/diskspd2_0_15a/diskspd_vs2015/CmdRequestCreator/CmdRequestCreator.vcxproj.user new file mode 100644 index 0000000..6e2aec7 --- /dev/null +++ b/CristalDiskMark/source/diskspd2_0_15a/diskspd_vs2015/CmdRequestCreator/CmdRequestCreator.vcxproj.user @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/CristalDiskMark/source/diskspd2_0_15a/diskspd_vs2015/Common/Common.vcxproj b/CristalDiskMark/source/diskspd2_0_15a/diskspd_vs2015/Common/Common.vcxproj new file mode 100644 index 0000000..b462f80 --- /dev/null +++ b/CristalDiskMark/source/diskspd2_0_15a/diskspd_vs2015/Common/Common.vcxproj @@ -0,0 +1,145 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {B253AB42-F482-417A-82CE-EDAFCD26F366} + Common + 8.1 + + + + StaticLibrary + true + v141 + MultiByte + + + StaticLibrary + true + v141 + MultiByte + + + StaticLibrary + false + v140 + true + MultiByte + + + StaticLibrary + false + v140 + true + MultiByte + + + + + + + + + + + + + + + + + + + + + Level3 + Disabled + true + false + true + + + true + + + false + + + + + Level3 + Disabled + true + false + true + + + true + + + true + + + + + Level3 + MaxSpeed + true + true + true + true + MultiThreaded + NoExtensions + + + true + true + true + + + + + Level3 + MaxSpeed + true + true + true + true + MultiThreaded + + + true + true + true + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/CristalDiskMark/source/diskspd2_0_15a/diskspd_vs2015/IORequestGenerator/IORequestGenerator.vcxproj b/CristalDiskMark/source/diskspd2_0_15a/diskspd_vs2015/IORequestGenerator/IORequestGenerator.vcxproj new file mode 100644 index 0000000..a6ce440 --- /dev/null +++ b/CristalDiskMark/source/diskspd2_0_15a/diskspd_vs2015/IORequestGenerator/IORequestGenerator.vcxproj @@ -0,0 +1,163 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {62DB1E99-FBA0-45FD-9355-423059BA03B8} + IORequestGenerator + 8.1 + + + + StaticLibrary + true + v141 + MultiByte + + + StaticLibrary + true + v141 + MultiByte + + + StaticLibrary + false + v140 + true + MultiByte + + + StaticLibrary + false + v140 + true + MultiByte + + + + + + + + + + + + + + + + + + + $(SolutionDir)\..\Common;$(IncludePath) + + + $(SolutionDir)\..\Common;$(IncludePath) + + + $(SolutionDir)\..\Common;$(IncludePath) + + + $(SolutionDir)\..\Common;$(IncludePath) + + + + Level3 + Disabled + true + false + true + + + true + E:\fbl_ph_dev01\sdktools\phtools\diskspd\IORequestGenerator\IORequestGenerator.def + + + false + + + + + Level3 + Disabled + true + false + true + + + true + E:\fbl_ph_dev01\sdktools\phtools\diskspd\IORequestGenerator\IORequestGenerator.def + + + true + + + + + Level3 + MaxSpeed + true + true + true + true + MultiThreaded + NoExtensions + + + true + true + true + E:\fbl_ph_dev01\sdktools\phtools\diskspd\IORequestGenerator\IORequestGenerator.def + + + + + Level3 + MaxSpeed + true + true + true + true + MultiThreaded + + + true + true + true + E:\fbl_ph_dev01\sdktools\phtools\diskspd\IORequestGenerator\IORequestGenerator.def + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/CristalDiskMark/source/diskspd2_0_15a/diskspd_vs2015/ResultParser/ResultParser.vcxproj b/CristalDiskMark/source/diskspd2_0_15a/diskspd_vs2015/ResultParser/ResultParser.vcxproj new file mode 100644 index 0000000..4a36b11 --- /dev/null +++ b/CristalDiskMark/source/diskspd2_0_15a/diskspd_vs2015/ResultParser/ResultParser.vcxproj @@ -0,0 +1,157 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {F6C211DC-B076-4716-BCDC-D7DE88973B66} + ResultParser + 8.1 + + + + StaticLibrary + true + v141 + MultiByte + + + StaticLibrary + true + v141 + MultiByte + + + StaticLibrary + false + v140 + true + MultiByte + + + StaticLibrary + false + v140 + true + MultiByte + + + + + + + + + + + + + + + + + + + $(SolutionDir)\..\Common;$(IncludePath) + + + $(SolutionDir)\..\Common;$(IncludePath) + + + $(SolutionDir)\..\Common;$(IncludePath) + + + $(SolutionDir)\..\Common;$(IncludePath) + + + + Level3 + Disabled + true + false + true + + + true + E:\fbl_ph_dev01\sdktools\phtools\diskspd\ResultParser\ResultParser.def + + + false + + + + + Level3 + Disabled + true + false + true + + + true + E:\fbl_ph_dev01\sdktools\phtools\diskspd\ResultParser\ResultParser.def + + + true + + + + + Level3 + MaxSpeed + true + true + true + true + MultiThreaded + NoExtensions + + + true + true + true + E:\fbl_ph_dev01\sdktools\phtools\diskspd\ResultParser\ResultParser.def + + + + + Level3 + MaxSpeed + true + true + true + true + MultiThreaded + + + true + true + true + E:\fbl_ph_dev01\sdktools\phtools\diskspd\ResultParser\ResultParser.def + + + + + + + + + + + + \ No newline at end of file diff --git a/CristalDiskMark/source/diskspd2_0_15a/diskspd_vs2015/XmlProfileParser/XmlProfileParser.vcxproj b/CristalDiskMark/source/diskspd2_0_15a/diskspd_vs2015/XmlProfileParser/XmlProfileParser.vcxproj new file mode 100644 index 0000000..f48ee8d --- /dev/null +++ b/CristalDiskMark/source/diskspd2_0_15a/diskspd_vs2015/XmlProfileParser/XmlProfileParser.vcxproj @@ -0,0 +1,159 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {EFF06674-B068-45F1-9661-DB9363B025B3} + XmlProfileParser + 8.1 + + + + StaticLibrary + true + v141 + MultiByte + + + StaticLibrary + true + v141 + MultiByte + + + StaticLibrary + false + v140 + true + MultiByte + + + StaticLibrary + false + v140 + true + MultiByte + + + + + + + + + + + + + + + + + + + $(SolutionDir)\..\Common;$(IncludePath) + + + $(SolutionDir)\..\Common;$(IncludePath) + + + $(SolutionDir)\..\Common;$(IncludePath) + + + $(SolutionDir)\..\Common;$(IncludePath) + + + + Level3 + Disabled + true + false + true + + + true + + + false + + + + + Level3 + Disabled + true + false + true + + + true + + + true + + + + + Level3 + MaxSpeed + true + true + true + true + MultiThreaded + NoExtensions + + + true + true + true + + + + + Level3 + MaxSpeed + true + true + true + true + MultiThreaded + + + true + true + true + + + + + + ..\..\XmlProfileParser\diskspd.xsd + + + + + + + + + + + + \ No newline at end of file diff --git a/CristalDiskMark/source/diskspd2_0_15a/diskspd_vs2015/XmlProfileParser/diskspd.h b/CristalDiskMark/source/diskspd2_0_15a/diskspd_vs2015/XmlProfileParser/diskspd.h new file mode 100644 index 0000000..860dfa1 --- /dev/null +++ b/CristalDiskMark/source/diskspd2_0_15a/diskspd_vs2015/XmlProfileParser/diskspd.h @@ -0,0 +1,277 @@ +#pragma once + +#using +#using +#using +#using + +using namespace System::Security::Permissions; +[assembly:SecurityPermissionAttribute(SecurityAction::RequestMinimum, SkipVerification=false)]; +// +// このソース コードは xsd によって自動生成されました。Version=4.6.1055.0 です。 +// +namespace XmlProfileParser { + using namespace System; + ref class NewDataSet; + + + ///

+///Represents a strongly typed in-memory cache of data. +/// + [System::Serializable, + System::ComponentModel::DesignerCategoryAttribute(L"code"), + System::ComponentModel::ToolboxItem(true), + System::Xml::Serialization::XmlSchemaProviderAttribute(L"GetTypedDataSetSchema"), + System::Xml::Serialization::XmlRootAttribute(L"NewDataSet"), + System::ComponentModel::Design::HelpKeywordAttribute(L"vs.data.DataSet")] + public ref class NewDataSet : public ::System::Data::DataSet { + + private: ::System::Data::SchemaSerializationMode _schemaSerializationMode; + + public: [System::Diagnostics::DebuggerNonUserCodeAttribute] + [System::CodeDom::Compiler::GeneratedCodeAttribute(L"System.Data.Design.TypedDataSetGenerator", L"4.0.0.0")] + NewDataSet(); + protected: [System::Diagnostics::DebuggerNonUserCodeAttribute] + [System::CodeDom::Compiler::GeneratedCodeAttribute(L"System.Data.Design.TypedDataSetGenerator", L"4.0.0.0")] + NewDataSet(::System::Runtime::Serialization::SerializationInfo^ info, ::System::Runtime::Serialization::StreamingContext context); + public: [System::Diagnostics::DebuggerNonUserCodeAttribute, + System::CodeDom::Compiler::GeneratedCodeAttribute(L"System.Data.Design.TypedDataSetGenerator", L"4.0.0.0"), + System::ComponentModel::BrowsableAttribute(true), + System::ComponentModel::DesignerSerializationVisibilityAttribute(::System::ComponentModel::DesignerSerializationVisibility::Visible)] + virtual property ::System::Data::SchemaSerializationMode SchemaSerializationMode { + ::System::Data::SchemaSerializationMode get() override; + System::Void set(::System::Data::SchemaSerializationMode value) override; + } + + public: [System::Diagnostics::DebuggerNonUserCodeAttribute, + System::CodeDom::Compiler::GeneratedCodeAttribute(L"System.Data.Design.TypedDataSetGenerator", L"4.0.0.0"), + System::ComponentModel::DesignerSerializationVisibilityAttribute(::System::ComponentModel::DesignerSerializationVisibility::Hidden)] + property ::System::Data::DataTableCollection^ Tables { + ::System::Data::DataTableCollection^ get() new; + } + + public: [System::Diagnostics::DebuggerNonUserCodeAttribute, + System::CodeDom::Compiler::GeneratedCodeAttribute(L"System.Data.Design.TypedDataSetGenerator", L"4.0.0.0"), + System::ComponentModel::DesignerSerializationVisibilityAttribute(::System::ComponentModel::DesignerSerializationVisibility::Hidden)] + property ::System::Data::DataRelationCollection^ Relations { + ::System::Data::DataRelationCollection^ get() new; + } + + protected: [System::Diagnostics::DebuggerNonUserCodeAttribute] + [System::CodeDom::Compiler::GeneratedCodeAttribute(L"System.Data.Design.TypedDataSetGenerator", L"4.0.0.0")] + virtual ::System::Void InitializeDerivedDataSet() override; + + public: [System::Diagnostics::DebuggerNonUserCodeAttribute] + [System::CodeDom::Compiler::GeneratedCodeAttribute(L"System.Data.Design.TypedDataSetGenerator", L"4.0.0.0")] + virtual ::System::Data::DataSet^ Clone() override; + + protected: [System::Diagnostics::DebuggerNonUserCodeAttribute] + [System::CodeDom::Compiler::GeneratedCodeAttribute(L"System.Data.Design.TypedDataSetGenerator", L"4.0.0.0")] + virtual ::System::Boolean ShouldSerializeTables() override; + + protected: [System::Diagnostics::DebuggerNonUserCodeAttribute] + [System::CodeDom::Compiler::GeneratedCodeAttribute(L"System.Data.Design.TypedDataSetGenerator", L"4.0.0.0")] + virtual ::System::Boolean ShouldSerializeRelations() override; + + protected: [System::Diagnostics::DebuggerNonUserCodeAttribute] + [System::CodeDom::Compiler::GeneratedCodeAttribute(L"System.Data.Design.TypedDataSetGenerator", L"4.0.0.0")] + virtual ::System::Void ReadXmlSerializable(::System::Xml::XmlReader^ reader) override; + + protected: [System::Diagnostics::DebuggerNonUserCodeAttribute] + [System::CodeDom::Compiler::GeneratedCodeAttribute(L"System.Data.Design.TypedDataSetGenerator", L"4.0.0.0")] + virtual ::System::Xml::Schema::XmlSchema^ GetSchemaSerializable() override; + + internal: [System::Diagnostics::DebuggerNonUserCodeAttribute] + [System::CodeDom::Compiler::GeneratedCodeAttribute(L"System.Data.Design.TypedDataSetGenerator", L"4.0.0.0")] + ::System::Void InitVars(); + + internal: [System::Diagnostics::DebuggerNonUserCodeAttribute] + [System::CodeDom::Compiler::GeneratedCodeAttribute(L"System.Data.Design.TypedDataSetGenerator", L"4.0.0.0")] + ::System::Void InitVars(::System::Boolean initTable); + + private: [System::Diagnostics::DebuggerNonUserCodeAttribute] + [System::CodeDom::Compiler::GeneratedCodeAttribute(L"System.Data.Design.TypedDataSetGenerator", L"4.0.0.0")] + ::System::Void InitClass(); + + private: [System::Diagnostics::DebuggerNonUserCodeAttribute] + [System::CodeDom::Compiler::GeneratedCodeAttribute(L"System.Data.Design.TypedDataSetGenerator", L"4.0.0.0")] + ::System::Void SchemaChanged(::System::Object^ sender, ::System::ComponentModel::CollectionChangeEventArgs^ e); + + public: [System::Diagnostics::DebuggerNonUserCodeAttribute] + [System::CodeDom::Compiler::GeneratedCodeAttribute(L"System.Data.Design.TypedDataSetGenerator", L"4.0.0.0")] + static ::System::Xml::Schema::XmlSchemaComplexType^ GetTypedDataSetSchema(::System::Xml::Schema::XmlSchemaSet^ xs); + }; +} +namespace XmlProfileParser { + + + inline NewDataSet::NewDataSet() { + this->BeginInit(); + this->InitClass(); + ::System::ComponentModel::CollectionChangeEventHandler^ schemaChangedHandler = gcnew ::System::ComponentModel::CollectionChangeEventHandler(this, &XmlProfileParser::NewDataSet::SchemaChanged); + __super::Tables->CollectionChanged += schemaChangedHandler; + __super::Relations->CollectionChanged += schemaChangedHandler; + this->EndInit(); + } + + inline NewDataSet::NewDataSet(::System::Runtime::Serialization::SerializationInfo^ info, ::System::Runtime::Serialization::StreamingContext context) : + ::System::Data::DataSet(info, context, false) { + if (this->IsBinarySerialized(info, context) == true) { + this->InitVars(false); + ::System::ComponentModel::CollectionChangeEventHandler^ schemaChangedHandler1 = gcnew ::System::ComponentModel::CollectionChangeEventHandler(this, &XmlProfileParser::NewDataSet::SchemaChanged); + this->Tables->CollectionChanged += schemaChangedHandler1; + this->Relations->CollectionChanged += schemaChangedHandler1; + return; + } + ::System::String^ strSchema = (cli::safe_cast<::System::String^ >(info->GetValue(L"XmlSchema", ::System::String::typeid))); + if (this->DetermineSchemaSerializationMode(info, context) == ::System::Data::SchemaSerializationMode::IncludeSchema) { + ::System::Data::DataSet^ ds = (gcnew ::System::Data::DataSet()); + ds->ReadXmlSchema((gcnew ::System::Xml::XmlTextReader((gcnew ::System::IO::StringReader(strSchema))))); + this->DataSetName = ds->DataSetName; + this->Prefix = ds->Prefix; + this->Namespace = ds->Namespace; + this->Locale = ds->Locale; + this->CaseSensitive = ds->CaseSensitive; + this->EnforceConstraints = ds->EnforceConstraints; + this->Merge(ds, false, ::System::Data::MissingSchemaAction::Add); + this->InitVars(); + } + else { + this->ReadXmlSchema((gcnew ::System::Xml::XmlTextReader((gcnew ::System::IO::StringReader(strSchema))))); + } + this->GetSerializationData(info, context); + ::System::ComponentModel::CollectionChangeEventHandler^ schemaChangedHandler = gcnew ::System::ComponentModel::CollectionChangeEventHandler(this, &XmlProfileParser::NewDataSet::SchemaChanged); + __super::Tables->CollectionChanged += schemaChangedHandler; + this->Relations->CollectionChanged += schemaChangedHandler; + } + + inline ::System::Data::SchemaSerializationMode NewDataSet::SchemaSerializationMode::get() { + return this->_schemaSerializationMode; + } + inline System::Void NewDataSet::SchemaSerializationMode::set(::System::Data::SchemaSerializationMode value) { + this->_schemaSerializationMode = __identifier(value); + } + + inline ::System::Data::DataTableCollection^ NewDataSet::Tables::get() { + return __super::Tables; + } + + inline ::System::Data::DataRelationCollection^ NewDataSet::Relations::get() { + return __super::Relations; + } + + inline ::System::Void NewDataSet::InitializeDerivedDataSet() { + this->BeginInit(); + this->InitClass(); + this->EndInit(); + } + + inline ::System::Data::DataSet^ NewDataSet::Clone() { + XmlProfileParser::NewDataSet^ cln = (cli::safe_cast(__super::Clone())); + cln->InitVars(); + cln->SchemaSerializationMode = this->SchemaSerializationMode; + return cln; + } + + inline ::System::Boolean NewDataSet::ShouldSerializeTables() { + return false; + } + + inline ::System::Boolean NewDataSet::ShouldSerializeRelations() { + return false; + } + + inline ::System::Void NewDataSet::ReadXmlSerializable(::System::Xml::XmlReader^ reader) { + if (this->DetermineSchemaSerializationMode(reader) == ::System::Data::SchemaSerializationMode::IncludeSchema) { + this->Reset(); + ::System::Data::DataSet^ ds = (gcnew ::System::Data::DataSet()); + ds->ReadXml(reader); + this->DataSetName = ds->DataSetName; + this->Prefix = ds->Prefix; + this->Namespace = ds->Namespace; + this->Locale = ds->Locale; + this->CaseSensitive = ds->CaseSensitive; + this->EnforceConstraints = ds->EnforceConstraints; + this->Merge(ds, false, ::System::Data::MissingSchemaAction::Add); + this->InitVars(); + } + else { + this->ReadXml(reader); + this->InitVars(); + } + } + + inline ::System::Xml::Schema::XmlSchema^ NewDataSet::GetSchemaSerializable() { + ::System::IO::MemoryStream^ stream = (gcnew ::System::IO::MemoryStream()); + this->WriteXmlSchema((gcnew ::System::Xml::XmlTextWriter(stream, nullptr))); + stream->Position = 0; + return ::System::Xml::Schema::XmlSchema::Read((gcnew ::System::Xml::XmlTextReader(stream)), nullptr); + } + + inline ::System::Void NewDataSet::InitVars() { + this->InitVars(true); + } + + inline ::System::Void NewDataSet::InitVars(::System::Boolean initTable) { + } + + inline ::System::Void NewDataSet::InitClass() { + this->DataSetName = L"NewDataSet"; + this->Prefix = L""; + this->Namespace = L"http://microsoft.com/diskspd/DiskSpdConfig.xsd"; + this->Locale = (gcnew ::System::Globalization::CultureInfo(L"")); + this->EnforceConstraints = true; + this->SchemaSerializationMode = ::System::Data::SchemaSerializationMode::IncludeSchema; + } + + inline ::System::Void NewDataSet::SchemaChanged(::System::Object^ sender, ::System::ComponentModel::CollectionChangeEventArgs^ e) { + if (e->Action == ::System::ComponentModel::CollectionChangeAction::Remove) { + this->InitVars(); + } + } + + inline ::System::Xml::Schema::XmlSchemaComplexType^ NewDataSet::GetTypedDataSetSchema(::System::Xml::Schema::XmlSchemaSet^ xs) { + XmlProfileParser::NewDataSet^ ds = (gcnew XmlProfileParser::NewDataSet()); + ::System::Xml::Schema::XmlSchemaComplexType^ type = (gcnew ::System::Xml::Schema::XmlSchemaComplexType()); + ::System::Xml::Schema::XmlSchemaSequence^ sequence = (gcnew ::System::Xml::Schema::XmlSchemaSequence()); + ::System::Xml::Schema::XmlSchemaAny^ any = (gcnew ::System::Xml::Schema::XmlSchemaAny()); + any->Namespace = ds->Namespace; + sequence->Items->Add(any); + type->Particle = sequence; + ::System::Xml::Schema::XmlSchema^ dsSchema = ds->GetSchemaSerializable(); + if (xs->Contains(dsSchema->TargetNamespace)) { + ::System::IO::MemoryStream^ s1 = (gcnew ::System::IO::MemoryStream()); + ::System::IO::MemoryStream^ s2 = (gcnew ::System::IO::MemoryStream()); + try { + ::System::Xml::Schema::XmlSchema^ schema = nullptr; + dsSchema->Write(s1); + for ( ::System::Collections::IEnumerator^ schemas = xs->Schemas(dsSchema->TargetNamespace)->GetEnumerator(); schemas->MoveNext(); ) { + schema = (cli::safe_cast<::System::Xml::Schema::XmlSchema^ >(schemas->Current)); + s2->SetLength(0); + schema->Write(s2); + if (s1->Length == s2->Length) { + s1->Position = 0; + s2->Position = 0; + for ( ; ((s1->Position != s1->Length) + && (s1->ReadByte() == s2->ReadByte())); ) { + ; + } + if (s1->Position == s1->Length) { + return type; + } + } + } + } + finally { + if (s1 != nullptr) { + s1->Close(); + } + if (s2 != nullptr) { + s2->Close(); + } + } + } + xs->Add(dsSchema); + return type; + } +} diff --git a/CristalDiskMark/source/diskspd2_0_15a/diskspd_vs2015/XmlResultParser/XmlResultParser.vcxproj b/CristalDiskMark/source/diskspd2_0_15a/diskspd_vs2015/XmlResultParser/XmlResultParser.vcxproj new file mode 100644 index 0000000..dbaa5a2 --- /dev/null +++ b/CristalDiskMark/source/diskspd2_0_15a/diskspd_vs2015/XmlResultParser/XmlResultParser.vcxproj @@ -0,0 +1,170 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {60A28E9C-C245-4D99-9C1C-EC911031743F} + Win32Proj + XmlResultParser + 8.1 + + + + StaticLibrary + true + v141 + Unicode + + + StaticLibrary + true + v141 + Unicode + + + StaticLibrary + false + v140 + true + Unicode + + + StaticLibrary + false + v140 + true + Unicode + + + + + + + + + + + + + + + + + + + $(SolutionDir)\..\Common;$(IncludePath) + + + $(SolutionDir)\..\Common;$(IncludePath) + + + $(SolutionDir)\..\Common;$(IncludePath) + + + $(SolutionDir)\..\Common;$(IncludePath) + + + + + + Level3 + Disabled + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + true + false + true + + + Windows + true + + + false + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + true + false + true + + + Windows + true + + + true + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + true + true + MultiThreaded + NoExtensions + + + Windows + true + true + true + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + true + true + MultiThreaded + + + Windows + true + true + true + + + + + + + + + + + + \ No newline at end of file diff --git a/CristalDiskMark/source/diskspd2_0_15a/diskspd_vs2015/diskspd_vs2013.v12.suo b/CristalDiskMark/source/diskspd2_0_15a/diskspd_vs2015/diskspd_vs2013.v12.suo new file mode 100644 index 0000000000000000000000000000000000000000..712b7a0cbedcdccdd3a64914f63e3336c8f2e454 GIT binary patch literal 61952 zcmeHQ36vy7na<*nOJTUi5fPf30jjB^tGatekUF~OV0veqi$PkLp6cqJX8NMK=YW}k zS#($M;1&c14@9}I5qvz4-4VrI->M8ebsyq$#a*8I++AcrpKn*0{l1KhuBfcMsxq^t z8!Gz!ol%*Q@&EBh#2^b!sM%AJo?4+=Nlq>To9T&&Gv=0HnjJjQQLxIB~FXawV`%XdAR8z%~I~tMI=F zp2+h~xLL)i+J2G4ag;nTs&zcvjH?p=amfEw-i#yX@_TVkIi+WL{!pA}TMq;rWt3^f zk-TKzv&ZFVhOpuoAEeuo`d?U=846z()X=0D1wJ0!Zg&IFes|IIaT} z0R4a>Ulhq20yY6Q1C9hZ)x&Fzod2;ezd1Gkcb^U7koLv= ze++m7oc|Gy!sIrh*VOq>or33DaIAO!AA)hr*1jk2>{Np%2VdROwnd;*}7Wzj4`p2NI zhi!!J(+^!_3}^ebysi;(g|bhl*P(xPp}Iv8QRfQa8pf(6HLskme^C$R`K4In;KC$U@DgaD9wznC5?14~URceCSRME|US&Q0Tw+6D3K@Oq~DCInUnqpPKVu>_6YB^M9!>d%6D|)nQOu0qIAH zSJe07ajnf!q)`61pal119F2~Jjf-E#@hKzkjz8sCCGbaxmwKpI{CA@4GoJCM-SF#p ziJQr>uyOHW9I00^xwpSv6twxz_H$26aqboWttiVrV7fG?&BMlYA(q=o(=yZx1%O70 z4O$NdLlP^`9TS^lPM6X@H(J zPE|C-=EvXS{FjVt7meKbzgLeBym;e5+phfh-PeEH<`&!2e%tRh{u25w%N9LsHMQH{ zxc}z36qM*%xwqLg0EB*&i7x(*2?)YhC zu}{R$y%f!PUh$ugvfnbQTmun1jD<(+Li-?giyn4;#?3g;{(TmXa{ylPuSHqfIha;L z;Ew}8ZSJ)AbMIHgQdYqKJYW-gHm0{ulsErB3;1c5mVIEpZuMK;|GDwsdG?9+p9Ul+ z8Z=npGoKs8iD!+IIdGpIhzVG&htS^5`hreR5V_#&`(PE|zwQq>9(k|)SKGe|Scb9O z(%w)6RPM*E_xuLw`r+g{)}LDNyZNK)nSUyNDjfZK+ee{!4}%-s;Ks0ih9lA~`E9@3 z_;c2NMgPmO@3sFwibnm+XqX#*H~o+EpLowieO~cjjk2^oGP&V*mcC;Coq~Gy2YAJ= z>VIzdiMrX6Ao$6nZD-AlECMtbuLzdhsi@Be7#5=F zbyj5ZoMZZ=PyW+KAF;qdecqg`&ix@rPh4e^ye)tYV_?S^MhzoOs9}&HePC9LZfDv! zb>o4^?Er}G5L$rTg12Bz9KtINBQk(Jc(vdD%VAK{-Fn*SuJ5x0RT;s26yB8_+C)V`@Yo55!yuk9oFPQ-SScbS4G=4K#v;J7e(3tF4A-T zIK#LyHML>?!Pub#0Bo0f%`V@I3$z(Anehuu)B?%Rq9)=qd+>|?DREZZDgLMHkiU$@ zBfU)0-oSl6<3I)0lHvsuSF`lh^sFeCEVKY zZ2hgz{xJ^RKlX^9drPMz?H{7`-rBzj749)Ab!tD|eNhHJEmJ4Ik2{weZ4)JHwa zEB>`8JBtP*Bq#hb7Tzfi4e?)*qfig67hdtJ^3OW{Yyhnu1XqLwLOc^dYOB*Zb@cz) zsAd<9c1TOH`d*HGEcd!*8Nb@a_rv>P|Bbv0$72Cr+rI{7uLUqQ{r?!`<@kk$`~TPZ zw_m9AtI-%zY3%QL?77?CeEPg~zs}se>z-H7W4Cjt=t-UL4D+BCLLXcSn(Q*nf>Hd@ zFVn5h1xkrZi3t5G@*Y&kIB{0U%H7gUC_s6^v>NrTL>JKKu@3*YUJxlH-%HU@~F zcn_@sKdp|xHjJ6}_^*Um;E0r*!c7*b9{Z2F{+RLifcFfh;&XWF+^n2+WkRt2L{7#} z`K(X*ihZshmsT2=oBm&C|1;-V~urP)0IFfN|>FE1w8x0Z?{u{GI}!N^}~4 z`)TU5)X}NeGQNX4(>VafI<^8BZyEz|e@Ob1I8s+m0cf#h)MN*M`?q<34B&$Ru6`{4 zAsjC-@>v{nMxNKYkzW8<2v`JI4B+`CIQ9Vk2Cx*c4DeyVa=;1z=hP~|YQRMR-g7aI zA2IU$O}G@lF9Q?+eSmcUd2JH;0l+9=JzxlMIe^zGiAIe4m~p%UNAA%mA7mX@A-@^G zk$a_aek+dK0NVi{2V4W#0ciUFe8#`hv}WbyYmooXZ2zt`jCalRoZa=OQ(-Zz+`-dF zw;FSk7G(OlI796dWyJtyUywn_)=IpPSKEB!s=vd9bll;a0)IAnA+y&)`UJ`I%8dsl z7gvQ(`);d@52SsayK;JgE8XmFCFC|ptWmf5Znu|6gxca2#A>?9H?Q3N2)*E5rLRJ) z=#Tlv?ca;yPJOv2BN$sZ`KH+&V=cZJp%?A)O_ehz!x(+k_pS|@ZdE>zt7W4_xmT%s z-WEC?42hr&FUK3X`SXP4+wYq)wbgb!pbq_c-QwG!TeJ%y z%V}Njg_hn59f1;a6m{}h;C}Q@uWpm>os#)|ut*G{Bv%&hO+MEU9yyN_xgHgvX-|S` zK^^s}ho%8_?$S-r%N<_W+;m%`%~1%g;OGQ6D)yvThtAEiG&0Xij<^ z$T3F59$R7xQw;ZZ0~hOQM~$qt3ltM)8|sXMf+&upCxu*0FWshJ%jj4WC>^(LR~ZxW zbmM-~e*qSwe$=Y!JB-U!U-_LA8o(sy4_dN z%w`0K!*m-$~Fy_~^G+|>=p;4iAz!)RIdbf-Q~87Ics*^YA@ zvuXTK;a4ZlF`vWOu#+^zL{m*=d^v5J+)bS7MF5{5Mgz41Y4U+Cbf~uF$A3KhmK)x` z_}*1VtX%x)y*IN$CMwns{kh}Cqkj3DMNi#-_s~Um4ejPN3Ow^Y*@su`y7tYhGS~k2 zzaIb5>2C~74*cP@^-sLsb$j2-w-%l_?Q7=pcb@R_x-b6UU%PHym5p8ejs2h5dBeSH zyPmzXXXo+%dGoCJhGu`Sn zGfnC>kW-Ol@PDN;-U>%x0m^`!7_8xBRkL{%XSmwnaFEvGHd`a^Mdqlzt6CZ&n(d`` ztD1d8tN7_@U`6U4f0Yzk3{bT|1?Q|89;sxnb)n#x4D{fu=Z z`ie%sN5{Z1&%X8S2}|y~r~k1#PI#@ew)^3g$j$3rI5xSgGxfR;UW)oiV)-M$+ zy>-E2rIe>FS?pT2VTnnjZLQELWc)`K*J<;a#5K}#u)fY%-#1_PD>jD0fhrmWr#O=5 zLk|j@Q)0iDgkI*%EqaR0+$!HYUkkra%h+16zclx($~Ah0gY7+auj^%O(F#+2&wTV~ zBPg@u4v>R_;Co7KsoG2CJ~Gcf>-)l(eb$)l$C2QakdDFaWV}g7#$s4YZuvezO0UyV zYAeQA#vsvxR;T(x2G@p_T>4uesSkdPx$Vh zr7sL#z$VE3zC5bU>cv~4#T!ukdpI}0^?^&5?0jfXVfQ01U9jJAKd{1G_Iik?tn1%p zOSxbkQT5l@TD4wyk(}K9nb#R{pOg!YpwLc&s;hFCba<7b-d5#CQR>V!u_^~iiz?N< zj4kI?Ic&=8xWjoJ#_UtM<8?f7_F3N-#_Y4kx+d`v| zIsTW|+~R-pxR1uJZomS-Lck)xV!(xfB>>hV5Z6QTmcjw5ro!;~Win^Ae?_z|J(ncr>WZh5NI>Ze~+UZduu*bP_5xXrw% zKx)uxR2%nS<@mec{CaM&YK@EZYsTM&8Gkpk;=k}rDvc;Icnh&HT-iAX>W$xO#($aO z)}%p)Mub}8zv_(NYQ}$7uF>W-z7TT!XEXk;{L0^mHqGPjerE_f&e5lQJ5HSko)=Z! zy^K{no`)#LP-5ovU^{cD-M){X^A~^DjQ`?OE6w;XJ_}>@bW62Q-m7QOo2NOr9fvce zcD_`KLg}dtk`~od>EF{FHf46)0duB2&0*2tbv)4nrE;}=U)cRu#^lY@9AsR8m*`kO z@n7{v>x2=35Qc}lI_9nZHdo6SIk)X*kdQAKjNNeQP{*iK6s0$*9OMW#_o+&$GuN8& zKjxmSj)@Plr>v!`dwhxYeNrknfeUDe?fOU69mAwU9V<@r-J5i5 z6s68w6S`xNw5apn%h+<3j$u<~#~oEVhDC$d@#HQY8$qEnr-XD2&WBu!bPN)!wUl$$ z?XB;V(yuB~S9UDcdGuMQ443d^$rDNEX*>Ojej$zT@bv(IC$3{@- z%qbxqgNx;DVYrow+8YW0152D;>k8%#J&% zbPS6Iuj9#GIyQnrXHH4GV^HtPt3^5n_l7=utDe(d(S2v#2ny}`N0p9Y(&2S9dy|fh zqSTpdLOKRXOR&;0Y|8Aoqe{oHXz)6o+@)h9D0Jo&pDN901w8FLgqQpk@usB#yw$e+ zrX_V$l-tes;i&1eZ}1l$#H>i=?-#qhKTCeU`7Z~gUOev$i!<^SCgSZFd=f}L7bM^C zQThI?NA__T-A^HNW~ye=D1KIa}+d!j^Hoz|G&g+@jfJ%JyAu|196k zmQN%*x;rwNXud0sH?wtiwMVmUnRdSZtuxi$nMrr%Vt6y#NdNNU6&s5aQ*XMfI^&&a z4|NsB$CbCzIkx1R)2Ss*|6kMpC*JwoYT?Us-T^yXxWn>nN!z>g>eBT8@jHs*Eq%_M zYWn}I-UKNv+(CLE?5s?7{iE(u!la|DT{+KpZ@ZL6QR>XKrvJ~pJFku%3$mxIwRPw5 zddvK z|Ia+`tEFR*Jr$00Yy^dN<4Bc`L0a0qOUEFwh9eytL7`p$sM0Y^I)assjiS_vNPU)8P`sphl{$ImuTm#4NYCLu7 zXT}`Y#P3Pky1Kh#>2!NrG#g8IMB7r`_$XOA9gpU-oyl}E8%w0J$?eDjmjoqK9qlXroZB@-ilwf%*G!|%F~H_Hs00Q8STzyV&s25+L;99ZHZ(o z)roV-Y{&L(ig! zj%IWCnQzZ`b#!#LC$szn-SXnZ#^Fh0B&k0o~+U|<=1*!w@mO8C)&F{IJ$9o_#ns4w}A|Mjtn(LYE$)AxT5_>3QRd&j){D?a7t zxM^iBf1S|$8Tj>DW^nU0H+^?udee;$v|s-Z{nvB6R0MtFN55u%|E(MTst-y#?(_~* zK0=*vn=#ejt+u%3p^*9S7XLnm2=`uXrM4c&F?{uT5V>(2C-GJ2BK|W1UPitj9q)MH z&Hs7)yy%i|K6iL5@k^^7@G^@jAo$*GrXH71eT!1%|6*a_*ST7@|Qr)5^bOulDym_S|i6K7HQ0UuSOKb;F+X4U`O{C+>y z?JdG(g3aWw*S?eb{idI!_P%mi>&Mo<*7Y*K(^W+}&zVvIzYj3ZS$;RZY~GW*4{n7Q zxK4O)&j|!okEvCL&h&}$>D`Ya&(Hqmr`00|wQjx+mN(3+y#oTcwaibE6B5XLmcJ>} zuu0I(dFQF>1R1|YLrQ2UVnkpp)ch+opoyi9)1 z%|%OkKtVxofiqPSAHO@e15iuby<@TGe+m5Z!~fuE*aW^6(32(f_K>zt9~Cz=oHKmt zZ5ZQjKp&TKe9GUNHeDzZbaLi=dLQ$M&s!A0GtTxRXz`ZhI^?Z%b*TtWtp(J(4EI}X z8!b+8{WBvMf^fxD3zEApMxHeae=eqIM z*oxL$-eAkrLGbGlg2`zWzO~^G{mZ?i*XR6aej&RImN&o$mkfW+i<4+V7hFAKg^F0p{v) z2#RX=ZOHx~Ypc3{t8UYN>hArhlt|RI`YXSAz cPsOlxi-G_GBrE?9@tadEJ`j0tz5bv72iEV0DgXcg literal 0 HcmV?d00001 diff --git a/CristalDiskMark/source/diskspd2_0_15a/diskspd_vs2015/diskspd_vs2015.sln b/CristalDiskMark/source/diskspd2_0_15a/diskspd_vs2015/diskspd_vs2015.sln new file mode 100644 index 0000000..69af998 --- /dev/null +++ b/CristalDiskMark/source/diskspd2_0_15a/diskspd_vs2015/diskspd_vs2015.sln @@ -0,0 +1,96 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0.30723.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CmdLineParser", "CmdLineParser\CmdLineParser.vcxproj", "{0EF5CE78-8E92-4A1B-A255-0F544AADA291}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CmdRequestCreator", "CmdRequestCreator\CmdRequestCreator.vcxproj", "{D238F8AA-DE12-49E7-B4A7-9B69579A69C0}" + ProjectSection(ProjectDependencies) = postProject + {B253AB42-F482-417A-82CE-EDAFCD26F366} = {B253AB42-F482-417A-82CE-EDAFCD26F366} + {EFF06674-B068-45F1-9661-DB9363B025B3} = {EFF06674-B068-45F1-9661-DB9363B025B3} + {0EF5CE78-8E92-4A1B-A255-0F544AADA291} = {0EF5CE78-8E92-4A1B-A255-0F544AADA291} + {62DB1E99-FBA0-45FD-9355-423059BA03B8} = {62DB1E99-FBA0-45FD-9355-423059BA03B8} + {60A28E9C-C245-4D99-9C1C-EC911031743F} = {60A28E9C-C245-4D99-9C1C-EC911031743F} + {F6C211DC-B076-4716-BCDC-D7DE88973B66} = {F6C211DC-B076-4716-BCDC-D7DE88973B66} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "IORequestGenerator", "IORequestGenerator\IORequestGenerator.vcxproj", "{62DB1E99-FBA0-45FD-9355-423059BA03B8}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ResultParser", "ResultParser\ResultParser.vcxproj", "{F6C211DC-B076-4716-BCDC-D7DE88973B66}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "XmlProfileParser", "XmlProfileParser\XmlProfileParser.vcxproj", "{EFF06674-B068-45F1-9661-DB9363B025B3}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Common", "Common\Common.vcxproj", "{B253AB42-F482-417A-82CE-EDAFCD26F366}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "XmlResultParser", "XmlResultParser\XmlResultParser.vcxproj", "{60A28E9C-C245-4D99-9C1C-EC911031743F}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {0EF5CE78-8E92-4A1B-A255-0F544AADA291}.Debug|Win32.ActiveCfg = Debug|Win32 + {0EF5CE78-8E92-4A1B-A255-0F544AADA291}.Debug|Win32.Build.0 = Debug|Win32 + {0EF5CE78-8E92-4A1B-A255-0F544AADA291}.Debug|x64.ActiveCfg = Debug|x64 + {0EF5CE78-8E92-4A1B-A255-0F544AADA291}.Debug|x64.Build.0 = Debug|x64 + {0EF5CE78-8E92-4A1B-A255-0F544AADA291}.Release|Win32.ActiveCfg = Release|Win32 + {0EF5CE78-8E92-4A1B-A255-0F544AADA291}.Release|Win32.Build.0 = Release|Win32 + {0EF5CE78-8E92-4A1B-A255-0F544AADA291}.Release|x64.ActiveCfg = Release|x64 + {0EF5CE78-8E92-4A1B-A255-0F544AADA291}.Release|x64.Build.0 = Release|x64 + {D238F8AA-DE12-49E7-B4A7-9B69579A69C0}.Debug|Win32.ActiveCfg = Debug|Win32 + {D238F8AA-DE12-49E7-B4A7-9B69579A69C0}.Debug|Win32.Build.0 = Debug|Win32 + {D238F8AA-DE12-49E7-B4A7-9B69579A69C0}.Debug|x64.ActiveCfg = Debug|x64 + {D238F8AA-DE12-49E7-B4A7-9B69579A69C0}.Debug|x64.Build.0 = Debug|x64 + {D238F8AA-DE12-49E7-B4A7-9B69579A69C0}.Release|Win32.ActiveCfg = Release|Win32 + {D238F8AA-DE12-49E7-B4A7-9B69579A69C0}.Release|Win32.Build.0 = Release|Win32 + {D238F8AA-DE12-49E7-B4A7-9B69579A69C0}.Release|x64.ActiveCfg = Release|x64 + {D238F8AA-DE12-49E7-B4A7-9B69579A69C0}.Release|x64.Build.0 = Release|x64 + {62DB1E99-FBA0-45FD-9355-423059BA03B8}.Debug|Win32.ActiveCfg = Debug|Win32 + {62DB1E99-FBA0-45FD-9355-423059BA03B8}.Debug|Win32.Build.0 = Debug|Win32 + {62DB1E99-FBA0-45FD-9355-423059BA03B8}.Debug|x64.ActiveCfg = Debug|x64 + {62DB1E99-FBA0-45FD-9355-423059BA03B8}.Debug|x64.Build.0 = Debug|x64 + {62DB1E99-FBA0-45FD-9355-423059BA03B8}.Release|Win32.ActiveCfg = Release|Win32 + {62DB1E99-FBA0-45FD-9355-423059BA03B8}.Release|Win32.Build.0 = Release|Win32 + {62DB1E99-FBA0-45FD-9355-423059BA03B8}.Release|x64.ActiveCfg = Release|x64 + {62DB1E99-FBA0-45FD-9355-423059BA03B8}.Release|x64.Build.0 = Release|x64 + {F6C211DC-B076-4716-BCDC-D7DE88973B66}.Debug|Win32.ActiveCfg = Debug|Win32 + {F6C211DC-B076-4716-BCDC-D7DE88973B66}.Debug|Win32.Build.0 = Debug|Win32 + {F6C211DC-B076-4716-BCDC-D7DE88973B66}.Debug|x64.ActiveCfg = Debug|x64 + {F6C211DC-B076-4716-BCDC-D7DE88973B66}.Debug|x64.Build.0 = Debug|x64 + {F6C211DC-B076-4716-BCDC-D7DE88973B66}.Release|Win32.ActiveCfg = Release|Win32 + {F6C211DC-B076-4716-BCDC-D7DE88973B66}.Release|Win32.Build.0 = Release|Win32 + {F6C211DC-B076-4716-BCDC-D7DE88973B66}.Release|x64.ActiveCfg = Release|x64 + {F6C211DC-B076-4716-BCDC-D7DE88973B66}.Release|x64.Build.0 = Release|x64 + {EFF06674-B068-45F1-9661-DB9363B025B3}.Debug|Win32.ActiveCfg = Debug|Win32 + {EFF06674-B068-45F1-9661-DB9363B025B3}.Debug|Win32.Build.0 = Debug|Win32 + {EFF06674-B068-45F1-9661-DB9363B025B3}.Debug|x64.ActiveCfg = Debug|x64 + {EFF06674-B068-45F1-9661-DB9363B025B3}.Debug|x64.Build.0 = Debug|x64 + {EFF06674-B068-45F1-9661-DB9363B025B3}.Release|Win32.ActiveCfg = Release|Win32 + {EFF06674-B068-45F1-9661-DB9363B025B3}.Release|Win32.Build.0 = Release|Win32 + {EFF06674-B068-45F1-9661-DB9363B025B3}.Release|x64.ActiveCfg = Release|x64 + {EFF06674-B068-45F1-9661-DB9363B025B3}.Release|x64.Build.0 = Release|x64 + {B253AB42-F482-417A-82CE-EDAFCD26F366}.Debug|Win32.ActiveCfg = Debug|Win32 + {B253AB42-F482-417A-82CE-EDAFCD26F366}.Debug|Win32.Build.0 = Debug|Win32 + {B253AB42-F482-417A-82CE-EDAFCD26F366}.Debug|x64.ActiveCfg = Debug|x64 + {B253AB42-F482-417A-82CE-EDAFCD26F366}.Debug|x64.Build.0 = Debug|x64 + {B253AB42-F482-417A-82CE-EDAFCD26F366}.Release|Win32.ActiveCfg = Release|Win32 + {B253AB42-F482-417A-82CE-EDAFCD26F366}.Release|Win32.Build.0 = Release|Win32 + {B253AB42-F482-417A-82CE-EDAFCD26F366}.Release|x64.ActiveCfg = Release|x64 + {B253AB42-F482-417A-82CE-EDAFCD26F366}.Release|x64.Build.0 = Release|x64 + {60A28E9C-C245-4D99-9C1C-EC911031743F}.Debug|Win32.ActiveCfg = Debug|Win32 + {60A28E9C-C245-4D99-9C1C-EC911031743F}.Debug|Win32.Build.0 = Debug|Win32 + {60A28E9C-C245-4D99-9C1C-EC911031743F}.Debug|x64.ActiveCfg = Debug|x64 + {60A28E9C-C245-4D99-9C1C-EC911031743F}.Debug|x64.Build.0 = Debug|x64 + {60A28E9C-C245-4D99-9C1C-EC911031743F}.Release|Win32.ActiveCfg = Release|Win32 + {60A28E9C-C245-4D99-9C1C-EC911031743F}.Release|Win32.Build.0 = Release|Win32 + {60A28E9C-C245-4D99-9C1C-EC911031743F}.Release|x64.ActiveCfg = Release|x64 + {60A28E9C-C245-4D99-9C1C-EC911031743F}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/CristalDiskMark/source/diskspd2_0_15a/exe/DiskSpd32L.exe b/CristalDiskMark/source/diskspd2_0_15a/exe/DiskSpd32L.exe new file mode 100644 index 0000000000000000000000000000000000000000..b5cd680dca23e3803d8c4ed3f34558fb4411dd15 GIT binary patch literal 294968 zcmeFakAGCf)jxhWdlME|va1A%5+q7gbg2y_Lc)S3hTTOWu;E97<(EE1T~e(Wb`w;B zfz3j0#@o_XTI~aU@R6tGv9_hHC@N?IG#do@B_9onl|H3*(xl3-l7OlEeV>_ocQ+8! zKj51e+_`)2%$YN1&YU^t%$d2R-&vYBi=|?Ug`ht z4cjf#-o0UVV9B!VrB#nTT=l@C+24KO``>>onEf9QW>*{@9TE>=K1}&au*- z7ZnfQyvsb@FRHlX2YzT#*xwfH-f#Q`imobAc*{>M%6;P5b|-Sh-|pW}@K1KfLK(4; zGZwPPLNfzL?5(HS-bHU4-_VX#fCN1V#*( zs1HRHWs&R!)DIe&)cyWj26gZFQue|wn_~97Op(7bg?o|DEavAnkvU@lWyX8-f4J7B zgk}e}KLuWyAl|C6JDN%+E3qM)z-p1E(1_TO&A9UidXNVY&+Rm7?)W#=42%NzUtNU! zTajx!2@&ACOI7lkWNKpd!gfH7GzD)17hejxV1)qvya{@p1f9gK`}e=F=gQ^lWcmBd z^8P-`6Fp*q+y8yHviJoetAADJ2_*3WcB;I>k1@9RMS96X_PnOb$$l-e0xYR{>NHQi z?rAvong8RB8F&(nqmeA!Wr(}%__Lh&-EwhfQTW8)5#8)jPlG7tc}6D0x=M@Z zStaUuPCnU6j2rd5EMIKE?JM$y&;X*I9r9O`O!iRH;%QZMfk@QTLl4lB27fsQqOKDH zd_<*1sc#C6W1g+V{R1#gLK}GhR7KHC8={^|tKb#Ik<@U<1W9y(tWEz7Sl%h#ejVZX)uBJLFJWA_a68jm$^l7ny?bOiSaL?x(vJPfv<2GKOnku>{j}0a@1tQ+W0hxH4TQ z=7`3B5rdRLmg}YaMZfSHCM(n%MS)CIh9ULB8wQb{yC{jI6DE8DFxPd$oPV2cLAt*K z{&tcP?XTg&BE)CxjtzonL90LZzU(RtGx}i;IdN|cAG(j-u>)gC_Z$io5CYkL{+OuP ziAVlQTcuK|;(shQ_^I5tXdx>-mG>^cO6xs&L1>hdu=S17Ym(&kTyRbw z@;Zf$V+SFs7cFeR285Clhvo-wrpYYTDjy~aXNqZIWhR6@4O*qj#=NQ!_AOpDF6;pU z@SdtHiZvrJMr1VhW%+NVF%3 z7Sky2<#Sg*mL^-1n7L%7v)Hk6mKQl6oL0e}Qr%s_basH>asdq2QsC|iond*~f0A?0 zkJ(h4>p)k#^>EVUR4({0O7cL7mPo`(o0r|>Y7Jjdt44+|jI0^STFdy&YX$eyq{Oc~1xY!CE>5}(q)Qqu zvOf&?V7a?$#x$Qu`3AuEu1Nsj`8l9%r^_Gd@>{z6FD{Zkz<*V(ozR7vQ+4f@5uqE| zlpc5MvTRp#xLd8dKHNRB=6crb=b?ntV|O0d8D43`UZIY*bzagmtIYX!ULKIo`lhbqeT-)~03(&F6T$%lh# z(KNyQcY^oDEK!xpyqz6Z-P;Lehpiz|M43s3{mb zYbakwnl92+E!5?JC4ai3jtI>@3l|ZOn0#X54EhNDGqaZpTK+E-5Gv?DJE-SO?Jrpq zl@L(AOemzu3goX)I=m-?bWOa+eE(mG`5qE@R(XXn-zQD=$Fv2fq9y2eVs0T5kcjp^ zmEqJDaN}K-%B&qJY&V)`OtN~3U-O*Om#fi|Oe(F{;4VwT$(BiuOh(CsL?G(Ol}Wx# z$fU%>i83jY$z+*Kk;yblwAxcqN|j3G*k{K^Xra!^-m-!}`BUUdi~8)8%g}nE2h%T_ zw%EaAywY}T1ph;$cwp5_f|{oj_-nPDgga%7LqByX^sKLho*IWf8_=U+q00bVG`vB8 zrMpe>JK|3Ii-xzz8{EAdzau81zi9Xsd4oHl`-o>d;?J6lJGMI--ecY;&n@$kxkmC^ zxHC&~z#eUKPA2m>XEiR!#H}6TwW9u`Q2&AjS&sSvG~MDo)S3pG0$1c@)_=t2=ipT{ zDq^#9GT1@3+cjX=-6|}A)59&wF}yuCIVX!0lv=wbG((@3lMw|BLaYowvdZ-7vndx( zSq~6+gWv9AH8dPGWe_%0W0}89RLp-PGudNB_L$e-Q3?o|04I8rz-0p5a)8U`e|%Pe z%fN3F9JMHez{bHXOa>RMtIbk^qnIbdRWNL>O8CyI2o2JIK)uG7xh+b^Rr(L88~8)` zA=;CHv1ak+hRgGnu(!YxE}y7$TrHjzh07=7*%UmRrdYh$Y+6oExI71sMp+hx%SS5< z=jH9^-(DqV_+6Q%&^=g$KjG)ZQq_hoo&WZ+r< zk@QlQhkR*G$d|Idgv$jQw$cDKhGHLltaSs@53Ww)U5w-9eM(~jONQ^ z-Ym_R#k|>?FPnLDG+&P6Rqv<<-zX%vHu!F3-dxR>%e?uTFCUKz8hiyv3LAWdNG3G+ zCLnP)_}oY)HuxqoZ;|FJV%{m5Zwm8H(|ptL!r$QYBPna}l`-#J%{P~M=WD+C%zMA) zyPtU%Yre(I8_;|KWO}5*_XzVY)qG2tH>ml7c(lC1x14!bXucJWSJ%`5^M0ywIYzr?7G7E57XoGl;b$YhjEM$05u zCiyZckckxL#YOVhWSLBn$uybxWinePb7eALCilx^u}lIoc|;~lWdf$AHY}IP3X!a; zqXd7^RrT@)cMb8oXN)^zA|`p*IWcbj_CNqaIZO?IiTSv)IItX+L7)v6z7C!~7_NCu ze*9^kJ({Og^X%6=hcwSo!|d}Mh0S)0=_n{ziBbz-;6WDVHRTIMR8hIeFN~w}j`}L720(;)PQYn4=j1}ZaYZkiL(n7t3iPN= zqDNhf6q7hT3`%I8HqCR~q{s2g=us+BN}|Vbqki49zZX3+bFf_ zS>?KiM?D;5j-gZ8=|5UxLo(4>m_%)&&qCLjeKzW8Amx@wbp&+Jsi>!uI?!JZt;5ru zg4@^-RTgp>g~|hSQL1AsaY`kO*G|wV7UHoXip*z|`8o#36ejRh{_?;&s_8HQqQ}O5 z#7cSiLM+&?Op*cZYuvps@7;O)M^9eXMA5!ciS_|Cu;_lkiw#+hDg}pLAK+BMQc;0A zw#i`iyA5!&D%hm?$Q#J4D*;PxjZo`F{+K-L!dC|D$cfwf}M)I$JEf0(!(;T^bfycVs{ z^H;^*)4ZzBBHkO7y9=xSul;#sF}vjuRk|4+0bWU}G-y=%0-^jm_0vO|Em{PIhLFbC zjSYD@yF?LhS!t&>MP;7O7YUE>B)VFbjTP^p)(0|Ip@zEwB2Ykg1)?r{Qe8HqE(67I zp{1t31XEO<^#XzO3t*1d;E`+~80UZmIv0Jp)v{<_-n$F=p5>QyCU~~IBHn@Q47(sZ z5ySLq*@eFmVAQ;(MGJQamai6UOI-&(8d<57SHun>uOX29fpy5hpA(0?Yf?Z^% zmwd7nl-5>2mk#EPvM#h~^KGxv6x8etm?Rmj zD4W?^UDMEr$!#j0S($;3Qxlf_Ba&X9;wL^>JI>N*T$-+#i|pPpKe0s-rT|E`E@G`l+bmO!mbqn ze+Hc7WcLKMiO00yF*T{xzz_CDcf#HXcLw6K(1HMNbrJCmzwky~#??_kZm5x*-j~B5+ ztat^4R%&5!usUOA?C~JrSYnT7veF%XUa%Rm*0ZBPI-ngt$XnP)0bpFplgUwiSWS$))`sQrMKrKDlF)|Vh4X+$4GtH$; zPbV^!oNkv@cwgh(1to$)JqHm z772B>&&DJ}Y}bpF`N#`^Xq$E?XyP^UjzZqL+GmyEa45&76J~0F&3T2v@=y;m7$1`l zL(kaGiUOKvGavgQCZX3C1OKiI`rVf2^LDv*u{kdndNymGb*yCmu)X2t6wRK(JeyhR zrb5rU>d~MAo3o>W)oy3gESZkqm2O}qqahz^GOczeE6FH}nf=m2$RMUc??}n z1ipj$GA&+PxZJM9yt#ENAvnFc!4Yon=&I|Y-dyUI*pL+fV)c&FyxCE24m|?Fs545R zE7nS%b02W5Zic*JwOi|IcPYVJFpdRtfKOqWj;H58d+av;dRJShglS}vASe$D}Fg%EgB0fo@FJ0 z7&*2ugP!uE17rDHnQ$t?ItsQ%8H!e%;Btb3n;L~-3ndq6jk@adGZ27mxBaD zAFw%F*}e+CkC5nwD#ko}*qKU2TTXY{Qakg!5?h){^ZVWuWu~85q3wmX0u#H@hI0Vw z=lcMah0uuXaP3LM^%}YO2!sy{IV8mvVt9%9VlpN?Qh|e` z{05~rQ@$HTRd$;Drsa%+@9^v+0{2~Zg&j!nw84uPn?E06y-0eWZr=&2DNMCs`p#a` zD)4hn|?x@17i zqVtmEEPiR~Y1BSin|xY@{t1_3fYcwp_h>@U5+-cw{J^HMMWj1snS!@a`m=L~9SQGB z(J~y!mub}P#;fX4BzmC+#;P-==tXZq_9ly6KSWT+4L~3V`suO^>lsi1Rb*Fi&y5y% z6voAdj1p2Rl#5Ju$!jtlm)LX zF9u$$J)wDc;qolUnjv_ltN)3`OsGc8!|Q6#h*^(fy~NVP^Z>%WH1!zbytK*3Fy(PE z<+bsGhB&5Y&7hEPYa+7lhK@r-#3te)eV=L9Q;x^>bz9YXw&F(Zbq!gL52 zY)+@+cL%NZbshcq&#wY~TLDpWNa#c?bO;{x&RBkf*?qyOXpk@LIi67hqPRhk)fchm z2Z_3b3l265gQdsR$F zf)kog2~L390U}2DCVv!=($N?{!3Avi6tvtJL80lD7I+_DeFfx;y~ny&#hP#z{5E8| zvoMvEyx{1IDV8zqq(mCPL;u_8IUBEes8O?l-w7&n1MmZ0 zYHt05bzLDaEw2e-2wc}d9H#nOu&Htz**XCQEi@5zq2pluW= z6=x&frl4>*Igo0G2JVmd(G;|d|F&I>Xgx9)5HRq_oy8)L;D>AxKs6TM00=HUauST@ z=WqWl7JC!aR@fBPWkWo}GAD@9u+fV$jYX&|*smo*Ka}&kEx}1lr()s1ehF7jE{k;H zhq=Oa(NpRF-WxJF7GH8-PP?BfE@KF@gp{*h>&}Ym^tr=CZdm6OV>7PC3CP{ z{_@6q>#R5!(V1s4GrYSZNRx?aBt>PwjB_Ts`sD} zZp%mZxNGayn5a3hj>z`pKSjSt7Eq#M01!>uwIMLc&60Cz93jrsEV_e=-gTv-(@``| z?$LUr4MgyB|4G!eFGUc$`9cb)c$MHiA`B#NZ+fQ?y{TOIum6_xK7k)5y|;Z#^rqLq z6!bnGzoT6AEKcuVp)tUP)JWJzuq3wVo=twf`>%i?!|cF=rJGr3lj{Hz%U8gy>onVC za83Ri_Z`G=Rl@`Iafaj6{7HWYe~Q5ZeaJ0*vQ;w!nGJY#Qzwo6O<-Mvu93ZtdV2;i z@oX{MaQZl5u!)e3dN#{si%1fEkV-}RmCOEWEV4I<>XLYZf6*cMKys8sxlf*0_vvLk zLEIMSi80AM@sI#&GjP{SH}Q;*fNTPm6F_Y6n7@2*Ansqq9AYNkijF- z2<4(@2Db!D*bg`1r~VrChvT)i8<1dtmaAI1?IF0{jRB>lNqU#T^ViA)&;`-cWNf{N z#vrl`#u1D;EpiIr-L1j#jXzoqK=nsL!!&&zo|$uEJWJ@~j;mi^N}Th(Pa#(UsqHHC zd<{WLM5)3bq(#mV%u|l~jaZsvG2OG(5K(@1pe5o4DHZ;!6U13PLbA=-L&n-MO`nKY z;fu~?R(-+N$VZO)2{uJ(v{F^MxSKdKbVnUli1ewJ;OH{`!g1(lfh|A?!Gy8`3q=@~ zf@k&8L*YFc5@5%JR477-Htc|EnXjnPJ0V^uyV2{8|JVfW7;|U8?SNL-aaEWvCI`(;^b4d` ziYk>^l~#BJ5qr6fP>c4=!>@YD;3aT*}G3seWm5>YjDS@2a$8UtdlGI@Dbd=WZ6kRRe zbpIvkO`h&~);}vYWU;`F@PzM#B==BhA)=y48{`=CtTUjMK1*xCrTfu#8;PmE;jMf6 z;+o-Asc!H6%dQEm(7>0oV3ac1HG5Q6x}Pmv%*yZA){_X(Hq!J0rizfQA35TPkat#J zlnsZ3yF^_!hgtQ~R(EsFG&q<`)aDCTP0VfX5?jboX+h)G-%GS2SZo#|w4@vZp!(AQ z#MD+TMG9IrxmDHfR@*TCAi;-d=={Sj7yWttX1J!E7Vt94x|%-P1l) z9czCAO{%KDTm8@xZoqA$_f~cQEMBTdCPQ%eIm57Ht%xMEhM&lAVmn3u*lW~V49lrP zD-g3x2A~Eq8%gt^TfQEe5(d4l6OfL_^vGxd>`nsK24HF!QFZ_}jP--VtU6Pw4FDxI zmj)5y%x7#T^Vd)*gi0gpo@LBE_lpWC8k*;b3UhRwDnbPozUwIJTA1bd-NMXDH9!%b zvryHLI#Q%sBYQP{3d%XwH#G<$NOJ9VXhq?b0i}9mqjw@`kd6Xn{K==qMA(s@*91R| ztwFUFxp!A}>mraG19vnJ6o77VDA1*pn9#iRQaE~hP)m&8LC8SJZ+iylNk4V6aE?5P zh$pGVvVKP6GFXWsXiM#jZ4<4$^CUFjCVfWGn7H9tv!MT_rBq>eRoJ@zk+72d{Pywa zs2@Iu?$UGu!0uDo828!WP`G)2T&F0jT1afT&xSr{@_ho@47-a&qAZ;Z^TQ&*^yRpG z+0ETnxjO(bgzNAE2nc)Qh~zeenBGHS(+HeLqpk1w`CT+;3v}2aZM{HfjPl2%11P|625?kjV8(~`uB!-j>5-rTc>o{-Zc2E$7%^hB zROiR4b7P_X#>659B!XZFy^kQ=S)>7l$z^H8^=>0z-1#1xHh`Qi; z>64Uuh?EgP1u2?GM^D5STj!7`5Xy)-n_7 z2W+;NOKH{;gM>wv64oZl#58;XVAt&=Yf@oriI3TgY_?6zkxr(b)+S$<$>6I(niZTb zbHug@lW-eZi`Z4RZ8XwV%~aO9k8dRBgaFicHgX;!TQz0#<#@s5t9H{6VM2bc63dQY zdrhDq*&Mpn>TAda@3Xsnwr>%HNpx|9AE9Zp#zu;UBeDoT@{SlAeAq!A#`G*iA8UjC zHcQ(`jgm7g|J5I)+?z;E=x0bf^8N)TLMZt8_!CrJ2I8b?!BH~7Eb`mj58;+rZtw?| zBYXS3XF%1r2_*%~e|w=cNJqsMyyX9jB^2sdQ|cVYL#oNok9;D!93GI@sH_Y*BE`UP zS^ERFX8^tPG~sB-tRg&-rJt3h!;{)z3c<5o*blS-%2@au8u&{bhX4xjnFv z|6ly&CVFWz5QIf`1Tlv#k!Oi(**#fMkJPTy9oDXD$cyTruG0&eN~%}zn;XavYOKSZ zhMM)}Vl;u)`M?_P#=F~o1o+yPDmehH>A90MjTW+R^^vH?wGkv+JE*KeZc7S-+iDW#ft z7`)vbX~NH{o1@}4(ZyJ*itNC1E%FMk(a3fxf(I^X=F+8qIPR&;`X}+la!k z*GLy+{W0B>27v_}UWCEV`pM;C-b<1;=P&Qfx_a=k~x$v;ghDfmp-4eUpK^*kS>Vv;9 zA8&cipNR`e+0}I_jqP6A`iZ!~)}Hdh^qQHjbhvG#R^;~DLPKB`9N@Q40vxFciOf_= zj5tVz5|+l)2KiRAbmSZJd*C_h!%yMAAuyz?AK-r{OU?vxc}-!j3cy*o zFD%A#K#=GyvgkFF^(>8vt%S{gO_45CK)6k6`*q79Kd+z3))NKFFpK;X8kKO8QcGn6 zfwQjDd$iQY(se;C_dX^>OwAqgx9eE*7byvZ$0ZP+4x1>5?PN@S4(5<3)G;!V)1Jub zC7T^hqPjF2HOXKubb4q&baJMXx~xOhR%ALQ`e3)ESYQyoNWSaW$wN;*jBO)eG=msS ze@Ki%A1PP90w^?+G6rp>lTt8;HZ2pbj{ zicvX;t*0@_(;#*r))&F3f&Y2%Wy8HAJ0W*=_m(?tN92TFGumB~8@!$k&%nTEY3Ql} z0i}+1`uJn-g=@26s(n&`I+n*4X6R%+NVz2n5rYmnp6!Va8zRYvKOh^|1 zRKLtR*Ub7Ok<~Br%$CVqnRT+vI?c@bkjOe&<^eK<@-&gPrT~#KW7&)%xnhkym5Cq> ze>vajrK|0?a*DNWjVu%zNY=5Np@g4w+K)+ z3BxWEG2|1`b)vslb=n}`;ww~$#kWBdaMW){k-FuU362PbA^N2<5KxiV&tHROhXDqz z9kTr~yp`*9f5Glo$w+lOg*t}#H+>u3AsTvk0r)sCR(I$8(CBc?y5bfI5SxLB;i0!8 zY)?Ld%JvBI0{DoQwE12iVsS#Pix%cJ8OwrC#;cJsKE7)AK>P*p**+F{VS~f8_(LO} z5bJZ#CD!MXSC=nYoWs7^kkb!xAY$G51NcrtnJu1!3ZHvaO!BYi;~8g%&=He117Apj zjMxYMfS(?pgDrydL8hrOo644LL;UKTP?^B z$=b99t>G_Xp&7wrhx|Rz3DIua3c$s7i6lg}QihLYhW1vJ!YcDXPbUQ5IlO8AEuLUgn*x8I z6RX>{8e5g>{&HCg>!QHLMZL=XZ|?rt)(L7-uCta6YASj(b;I z_zQJeDnE|<@E0SiQ~43f(Kd^}a}SLkl`UvRAJXoAP}3=>8O$jR9SR`=%3kO>3Z?ZG zm}OFFeeOpf-hb{F!w%VLQrK!~XFxHqm|les6XDg43{&qJMNc0UPqD=W?V}>V{JzUE zpOA$4?May57{@%*z}zV@@5l%=5O<`@N)3F*_Bp%kpCW}qh8fR+=>^N)=P|3g`r)h= z42%V{I{F#?!}{r2B0@4e(MqQ1t~dcsQhRT~f5;Sdi_eWF7ECxTqYT6{LxHb@= zTv?(96@!3}fhIt?!;@%^RaOqc&=awHi(~H_&z?Sux_cb~gZd$V+LGnZw7BTKRQ}lh zh|tw7Vb}wXdQegE=j|na)k@p6(&Jj`2|oRrq=7&|ogR+B;D!Y~EY!wokGs1Z^*=-- zXftNH@OED61>zeffXAn2YNf5LJWHFiztNlB;5mdyBKU2nzI&1JAP+W*@>u z{4>k=AK?*gY^%q@(*e|gSAMp#O4~3i zep?heUdGeQ>Cp)p8yRXt896JeiBkJes&RK;YS2ipIeSU$9jliBSvW7?LkqnP!|*%! zDf@3^EGfQY6WV`;F4XkJC?jRHCgK>FCrc9tl`v1X79nk#d2-6N$o;sBrqaF==ha1U z&e0B$B5_B1J?I&yI8sS*8wu{|FsfbY@kMYEd`O{(Sc6Sc1GswxbPr=)9CdBdb_P(D zCgLc_-kh$=u*GyUY|#iv?Ox_@^xAzD==?wfIG+suMehRLG|c1Fm8r2I z0Wsu)x7O8eRYD}ruLkq#WftJuXeq`#d%^V%PPHPIYv3P_!?e+9Cw|pEn~1CC4hMO5 z&ILYrUskT`OL2?!5I7y2$Yu@K*2CbThs$tM45jeR(%_EmqkJSl4#xbdw48Lc&e{Y^ z>mYeLY}g_uy6R(uE7r$dp#*}@+=;@T4N*_MY-Al;1J^CR6Q^K_(|sDai?W3_T}}%y ze_m`G@d2B&nfU)lvxu3uY=2?XCWJBw{-^UlYzbbztME#^Tu~xe6TvYv|fWKQLcwp#aSRfmcAy_ElK% zj;0FP2udXOz(qxD7AjQ&PF$svgoqVQZAJJJ{h6m61URae!k8XMQ)#c8xD#Fky5mni zXi)<7bob?-Xm)hINSPqv2Lw2waS=K%{}a?@@Xdh0=%3)x-|;An0PmrJB~Xv${2IUu z?iLX2!pBZth7@Cqku?UVWmq%cKo zbAL0&w5g<=U}sq^;*J}%ohm5h{=`wg14zqX;kTZlw$uy?ztuoDjx`#t;kUNX51@H9 z=oH9o!hVQ#xbSE92sMEHfHE7Kv!$6Yq6x5vVt9Z;7-f+*D)In|NQNf6SgyCx5pQC> zEz+ckP1}z3&6th*gZDyz2WPd`WAznhoG9A1bI@STWw8d5VhhT!D7ClG&-R`*1T5-gC17KsHolA_Wxfpx(Ku~IDkjAgOv`LXJ`yx%z) zgE0_rBz%Ygg%@o{8@6>OHEkU=?M^^r!fSyYFVf==u3k1qTTrjv6Q0z~Q?FJH&YK#-1%!nOfGPi1#J3+6=Uz8^pNt02$@ z{_glrU^}sS1x5qupF%jrr5K5E{tRf+5}AivrG51vaF-xNV^J>FTgSy~k+AcT3*&4= zpqqe_Jq!*PdhH1l#7@|qc!-tm1t;JG7SR)$J`Dw>H(t8pg%z6+3k{{8V`IZUZD$ek zb+zj{S&&8qg_zomFbcRB%dESiobq?_N;mr)U*u?=$q827IS=hFT$SgdbM{Y!iV5yXrLCMB?-3s;=jy=hGhzxty zSOHd$CAN*Od?Ji);e+8biy)WChGy8xU9N2-EcmX# zMF<1B(`uj5LI_nNN58u*IJaYfp?nK{pva<+#tXT&>s~MK2}{T7f1|KPP)gf&GBIp+ zQjA_WY9pWkE#aODy~4IlAwZJA!q?06Y&@ah51K8sKakYZL!WDnTX7?uui77km>v!)2hkyyQrz|DVdqDlcD&XiV{6;tBva50GA_aW zI7Pu&+$}XT5VYSa7#NH3B4#0>eaZDDu%5fv7J}2}cefIPM3g0huA)VWHrQM)LvZYzgJN9&!7Q7aWmYovP2)YWu~+(n?!Dvfb*lL;9+)|rsXx#vc&kT zOg1iQpBaX~9PQhP6(Cq9z^N_dPC0+L5R<+ben7$$$r)t!jwb9#KY_STYRsQet1MvV z{uJKp@SV0QgyX3YAtbp$9R=$L;vTmcg1LB_cRp|wK;`Q4IN5I5;J67rKs2+x7=qNC zU$IlnQU5alDcnY&9rY^-py(Z{5DtK4{eiC7h2KdyKacosXfW~eOPV;qVS!nd-9@28 zLHnu;a=#Y#I%CE)eyztEq@d9$3?wX!jzWcme?l;}-+=rkM6txo#90a9+8u<-op>uz z*+5a*=@Jzf#fl0y*oE>G0ce^7Fq@ z4ETZ*km@GkAH_1eq-#`zp#HPSDnM6z72u(rD{IL(1 zxM4ywr?ozD>>CWm@KbiojGtSunEzIsx{C=Vx5PWVlR85QKG3Ttn&WvzPdH@WB_;Mg zdf;kFbGY_s*t9zVu8)4`NRO8m)Yiqhu0RbP3hY;)lnYCkqNkXrZkT72CZw4pfoy*U zwVyT|iuO}rcbKfk%X;g69FajD>pptRBVQ%;*4Cun8W7k3(zKUCz|o|OP7?ecXo~mB zl((o?{J<8y!iqA8ryIdokS~$dNF{Fvm-M2h6+uKveBBHyDv7T%OfEF}8V#HLd=ylGU1A8U^2*Lh35=zg7-Na()@X9KjI*+fPyU#12%q-~?%i2|kYif|L{T#8f&g zRVtR^uvB@<2*&7a;z;~C)-;o(p0k<4pglX}n(D1W-`2mAt%(I({R!u-0*JoU<~pp2 zH9OP4=sV~3_B?&V3OET*xxL-Xh6a4`o+u(L$IGP+sg1D7V^p_SeL8zZKcD|nCZkV@6n|eYkIVtID ztkK%BQ!iI_r4PeOx_zuRd92DD*v|zI>M*Zeu6Ann3EJcdDgsO()|WHG(Oj1|JKTa$JX?5oE))G$Bt2bnONC?gavDnFz-HaE z*{`z(bSN*OEhb{5YvDTTVKLIRa6RtD*)lCw%=*Fpe!d>jGSbQb8^IPEr~h#a7(>Q4 zh?Ufg_)6*!T3wYV3rO=-Uo#hs1G zHZ#9$_#rP@Fg%`3dA7kW2JXew_ z@Bsc%xJl?OTduN9O}OsJqi_+=q+5kf@q%-Oyx;u7?}!F%4H8-{k;QbUd&u^-VqXO>ClCk`rswWx@Gdzu#+6xm%vb+!ELNcl7w1<1c~BT6U#-letx(F4eoZ=@}N8XbdFQ^Idwn9 zTr1(7%YgtqB7_HdL@14oW$VSf&hNVcfi`>uIv+OqSP88R&VTsSaZF_?=b0X8MByeU z?)??I7=hRyg@Nl~MIea0yMXQ52PQ2M z@4D%{5iFLg6H-u^Y}3@to}*C?;#H4`Ry$=^Lzh;I2@AiHoIUuzO#~ z<`yq#qa$I4xOc*~KvaP6k1t!Z1*%jKu|WoyMp?he%Ag;beEbZr{Uul={SBIPE-i2sC8E8VCyxQEG%0wFwRW3Nnn$1{pwN9R1It+-(hInlBvEJk~wW`1wV!OYcT) z`5#aYIEM}iPL2hq7@Yh*g>1d!M*h;H28-;E^RmexSmRiGBQf!QG!V%lnH;4Aj+r>| zUg1TkhZe=!vgr-+Zln~pFI&K8#qxAvi-0RRw}B&YW*+~e3({DKP@3NQI4xooWk8@# z(uyMFHO^Z-&C>j_T;0=y?|+~&gy%nutbh_fM=8nwFTaUi zj8A6>lnD20a1>ApowvTrJb-)Gh)_PeyT`q2*;v=1@I|#MH+*qqO)fh$6D~fBF`=V* zm!8MYm;MB2aDR_357FfTT+Eis6!fAK1h4{K(btjgyyt5A2td$D=fsTT*Ov;V&9YKm zgu`lS8JR+(=6aoCD{$WY{V*#x`h9Y@H7#hX7)k+BQ8S=00rm&(}7s= zkGLebcRYXpdh|gb9g@t6asI&i{JI3a!kx~(NTxk_3Y=Rj>+Fk@u=myFfJ^WIPLWB> zE;z3St72fV8_k6we1xXO(}`~GEQ^gpcMdC}?sOu`mbLUn189G|3$rn;QSpy_eeieu z`v@iGM{ayz5u%S+Npy(O-D@QgpSd}Qj`$`NlKiyw8`5Witg}!0OjTV25!4yt*2D5W zEp1*jMl?>3iOP>GST6?eT@}L;s8T&Z^0oVB3nCm}gmSK>flN!Hw9s5;O*1HJP*cNs z8naZQ=|KLoyS|>LyG@#|#cESRW_;~H$$Leebz4$fQ0p=5q;B~(_b0uE?^nbd`l0(MXw zfF=*7de8MfpAQ;w4Mugm605SDQR{#o{$i*%MKzz53%)`dCf+oVtuY>AmS= zCHhzeeI{e%B-vgm=&IT;R^u^M2f++EeF~Oj1?hDJ7v+LcT)Ksx@ zo9m0_Sc?0dP$}Cb>^oXiEOzaKGe340`i=;RM~>D13rX*~rdY(fXr;Ep+|_2?<^FKk z-mb$VTd^LGxbYNxp#ze5(J&BG1cX0I0pZ&hX%-6eUMMC3)QHONNvdp;EB%tns_y+} z6`jA%tO#5!D?!j@VyfAKj^jCRb;)TzLdJJ(m80?9od?AQ_?U7S% zjf&YUIdV%v1$`l(KTODHP$h)32Km z|71$!2o8I)X$ufXcLKW$>W5)sVY#dbtL|+$p)WHQI!SX1 zW|W(L4n5uq0oHyFOu^i&)pfvJ1e~fu8FU>q!gT1MPBM$7qecc-!RLXX+nNe@s0}*+ z7POVa?AV=4+kLkJ+NvmBvFVp1wAHNgApgVjs4^sN>}1JleymP@*~e<_cn}A6N(YfJ zY|Zyn<9C;oasqC}8JeB$)4^=|`p`j6;p=_Wjo>>}h+g4jo?v*C#g?i3CAe;=JK*lS zG>lHLGxR-deU*ed$a|gx)_Kw~FcpU`xs>bhElRWPd+JcGRlyUmKhrXoAkz(lnK z7{S%&^sJ)hzpBkVL1>RDK5xLkfhXTCYb*kK7!QaEmFq#3-g45%0 z6Zi|EZR!VOFx|@59F}^M@de2;{s!FgeKA!0yz#HL2cciinKLI<=$GGy-@&j4=aGW> z9_!cqsT#Kgb8jQY>BAE24?$*3F*LsjeUB)AslIpkVnW?>k-9fe&sxjQ!pBZuC3^v+ zGJ|G9J&Ux32`zB0sRjNMjU_FRpeJjAfP5yQ1ip4FazP2CTnSNzJd$Xn1I~jY+m{X~ z$MgNka5^E)a_yy~7e-XTT9ol&< ztc9e57jRxEywb_jw!vY`{=pXDFkPs>`~3VQ^|FlhlXcPb2nuwymx)o8X0#28^&$Sj zD71g7Dl)nTf&w%E%p9)nB~e1j0s-4ctq{t5C@Pco9~StHjx`d}9cIYy_4wl7>#6uL zd1Vla1sr`&nPgBxHik{3L@QDaCxv^48q6qXW6Jo*YlRPq9dOsEq0bh^YEMgF8_=lbQOFOs0IBhPe=Fxg|{V}>Ev(gWwC%hhW=~#Ka385^MekeSca42 zo#7@+aHt7^Fx|73S|x-fspPq?nW-w3g2B{ule2AT+)TaUl3EmUaVj%Z8(}0 zCZmwCrh|vt%m-ST7`Ay+JuehaIvu zyAR9$avubC2gw}1ABtixv-GOoxEc6eMh|NeJw{M%z35^6YI=MmDoxO1?Kx{dm2mj6cMS%~3^=D(+0#-4N_?$@*D{mAt-?D;ez+4%xo2sipO$2X}0myB<7 ztB*OpDT^52DQ}WN+1L1{EXMdw`9|aW-OI-J$2eL>qSgyPG7B!j&orz|{G^o!`IGu4 z8329ZM_CN~Qoj*?A76&wq|5O8#{Db40DFA}Z@@HbxK7C!S!9J96%twqXemY7urWgt zLC81p{aB%e=1W!HT&MYp@5g=$5MUW%PX6H&==J|cmqT>fN0$~{WdDC-`~?QUf0T*8 zjIJ}#mlKS{KQoSh{QJ81Bz<4^1GL)IWb=d;3X_>utm7&u7Wu9Q>H8Y9kT6LfO*Q46 z;+#t^(pl6H4O+KHEtcJViFP`)b*yZ4}t_Y!tF4kBp0y`@Hb zuY$zz<;OMJE*vG6XK1K~Ep95FX!Gq~+h()9q)(Gn=`G()P= zd>3zpd^a`nHz?{ zy4$Ke^5-?sO5ca72tV=e>M``}8cZ0lXAijAW|i~T!0+U)wLuBALtm9oUx+_NN8;-f zU)IzXuFP15&*C`QfeQX(SP1at+%L{cbD_ptq5YkqU)oA%RXR%(E4nQbE^7he&_t;Y z)`DUKD`xrm)APkQ3e7SOD647#-V45^jP#RMR^=SlK&zGu5Pco*O|w6!{jAhp!AhL& zX2K829=u5s=Jn5gDpOlWY{_wo7pbM2tqKjP#JV$hSa3Eal;%*+@30jT8T@tP67W`}28-!HcyckC2g@R=! zGB47B3RvhHnivDo)Aa3fQgIf+X6WscXNOrz-SR<7=x#Q}R`&#MvY16YaLDroTjkH- zd2ImOwHv-v@$zamz&*tl8i=hR@=5SB-0l+JhsKHHP^sA*@?yaWh325+-59IG+#iI7 z@|VbD8OS_6(98R4Hern075ACoNQytzOYJ-WMFyWe>?XUshjNGP?vN8MNtDrYrGrR* zT|m%_w&&ve=wcNQ-$$nMe9~EJ0BVfZIDsPQ&bMjJfC@GH1M~44?Li6=> z4D|Ct`3xJegeSKLLaC>WrC0E+H=(cKsT0fi@F6H+YEYaI09uHzVp2iugULoT z3cP~O(|ML{q;{FV-!;3a;-fBEw|L=maKpe1Av+OP(WKW%&h zZzthBFpf9yHTVsUuoJ(5A5y*nKaT?llb>%}3Ya(1C7Uk8=yDA%07>+~=!DD74}QSc z1HT6+0J{dA2^$Yhs^CAz0#9-;!V^rrXf?t}(1q8t={D?{qHa$1{L-nSlR#O~%sMPI zi>{&-XDkvWbyZUDB#&Q|98ojon=$`AX^F;8dJL^Api3TIZl}wwxX5a**#9HU{uhxs zlE6v*Z=1iq%x27Ld5{Uu90-6W{2gzOSek9q%< z_!{Gj)N@0gf0Oa`K0caZj<0tfL7)AJE=_cKlP<5~0@4V2I8AzB{_EyT;9;O;N2B+! z_<|KkKc9I69zP{J5PpG!bVL9;F>Z7i6mfS6=l#jE2;?+&yk61d86id=WaYU<3t{N# z>MHU%kkpa)sy5INm+?*nz6L!=cdx3IA=lGxJLR{tF+hIzmUvEzg$2o3 z+`I>8_2t#4PbP;>@ZX}KaO|g;VHASCh^Gx9(4IAu4n`vKu9||lRF@NO_2@EwLb6!g zi74~?d8>TRTB$hyL;-a_#6|QW;EVHk*lD5qK8wzSvl;eV29)0luG`26ScJ%7sC_n^ z0A*K#72%k3+00q^V3_+0xZXaY=+7IVPI~MxQ3lRJ``7w~ehWZF*!pJY2ON?qabo_Z_ z`IuIWw02BooqkCT{dH_RFi-@2!M{xj{_Tr-*)e?J42w)%bx%Wqz6qZm!&Z+YAUzwW z&v5c7N3j!uuLn>J81`k|%0Wu-BOIzCu6q*DQrT0sj_X+ozSfFgD!bTm6_jSU+udg!5si2v)I+#I427&3WOG{K zTs4%6g|Uu-h1Z2tZ9<1td(y_n6<#08ri_5`PDchTah#ioCJn#`r-W4iGawxTh2<75 zv^gRTfGl$NWAA9wZ5>ZR?J-JRZSL1QcwxKD%eYt_=+%WNSS@Ez9)tjZ-; z+61%!N&{V&;+tGOOp$0VRXfsIiCUNmOml(hQe;t~R5X^@8>ibFy!M8v_PVF=J% zBk};PmZ!OwtB(4axUGBIZqeqP(&n7g@DZ)ZUG#Q<`+_6#dm_uduzBoCsHCMBrSG-1 z+zso^qTOvXY#^(KV`Q**9V^pmZa-0M3ZZhh>UIJZ8&JUpnX9yWRRL&_;)sx(pu%>1 z=T5ZTZgJHAjvf*j@FOyaFtD@~p~5k!7Q@ws<7vEtNa!4V=ewBNCYtY_qB9B*$CeO!qyue$LjyZ@kVqs?geIP z_{brfi52^E0+HX7Dqh>!;68A#jV|$5FNMGH3h*Pn;BO%KKQrOOUqfDJ;SDayu*O^^cDcrQ)hcuabd@_R^r?3K z2ZRPd?BW)hDJ#KpmXkKDRK%9yG`Ma*zZ7Q z;rw%-sY#i8Y{v2SrMRD&3R5@$_Rw9gt;`TAi6pDzI;g9bo3MN{-CkmIGj$k)$F0SJ0u(f_py2HgCnPbA|=P2jTkZ+yb4_9`8J^$!eI=~#jln*e_CH{bg7~if;hZzeuGKV_Bn#(I( zRxBJqJRz(xg5yT$%vrV!u@TU0UAyS{oNjm25hkyuYcRG>BQzgAk!A{zaIB`!G`RAt zADBTBt=1Oz0U3p$m3F(|S%yVj04U?$Ghk*Y&>y(+VA&x%+M59*Q@3yBFOi&^V~4vE z&I&y5L^$yp+A%c?;pgKqAYp9a4Lp7LDy!YkE9o7A#OU+P!Y63$79PTqxQB50BdE;- zuge;k>$>_D!UD9s_Csg_1^=Upb7)u@Y`X8`%sxGTCv_NovK}SU{d@qypNdmpx={zA z;wJ<#I|J_Z6rY^;Ej(eHs_sp?Fu(pn>n^K$mRzhBn04p_i8EnOx1ll zbiQLI3uWl4tnDIM*xfVPI7Ayij~!4H;N`Kqy5U9ibR)o%FSf%GMpVgyhN!DU@wM`+ z37$4Kyo*#p>p}P7&>7}A#RftY==N1OI~eEni_gSXo>O2nv9 zqfRSr(i%zBV4^03nWRc^!b?JLL1|0dV=iqGW&#z^#37KwVJx?WTiQa!TWx7eTUv=C zf+mn=!iy4-Y9a}wn%09!6<;m{dUBSi_Ca$}mQUy`@MG~)3`Ne_9MU`22No`(-1aaTnoW)4qvhof7W5EBye*VEm zCpo{ZIHUhzeoh+pY2Fv0VjzZ&7hu**%lbx2Zk1QLCt&2@CG*99k3{a_!Iu)q#Dw0{ z31i0S8Kzl=g2Wgo=OqVSXg-7IH>L>XpLf7Np*-|Jin@;)&WV(-^s9Q!$L_~$Hylqm zpyJ4775V%m!`ll|Z!a{~Vlo8)Z4oWeGM;L@p105cZ_sQ02db@DZQOwr--H8gb&x6& z_faV)ND=Qm!WdMw$yK!Vsx36R*Zk^H>Qq#%fGRQab_f1|wmqK_~h4l^Nr#H-CJN3m+0OSqj-|;odgeG zo!5s?S)I4cD4wBvXTY?H?wx5A&(^)Ojp8}FcaBl4>0S*)bL+fwjpBK_cb-w~*S&tA z7S(wd!S;dfU6TB?-1F2euSVkGsKKXhIe+1JL>&B8mS*+kJkl^$tirFpoWG$J%rva} zNLl#I%)g*4R%{Y~{u(Pb3(Q|0O!0^=)|mmIJTXwxwwR?H0!!p_s%#5Az=hofPzy1} zXL`|;Frh#zgq(22F+liAm)ZO-xI=`2n{4d-T8!47M2xnwWOGE9Y!~wY3-nk~_s^fa zNpM=?y|X@SAKv~>=UTAO;$UZ2&v0X6&~C8cKGR<4 zXdnLiv7=p#bA)jLW{e(2TJr+=!EQkVEHFEx$8@yq~Kp{+!{>(u=bUZ;oD!e&x-rD@MQaj;||5zw+KzSB!q;&8sU$ zzk;5U;(WtfpcfYy-V(jI#PCkii_x#VzPe)cD{om{F^Y1AUOa=EO^Rn4-r0KbY{NT8 zFP>w-uvRhpm3MAk@m!b$(~IXBUcX+9e&tsZF42q8ucSxSN$-L~`jzx9IHX@m z?=qxE=_{mPNsrQ{cZHTS(>`#RlN0RQe^X@WLkp=yIsp?Uo~byEK|hshlMAeV|k)w~%s9QLLn$(Y8| z)F+)EBYf7hwabYc@m}-EW3t4T>Font)~j5o^cTdZ-yQ3%+*gN_1PawLC(iB|Z zL!QFQNpO+fhL>*obZC+9hKAa}rDbK2ETg3|VXC>5cW=9oEx^=fk2JmleGmOgk%lQvCxwDMs78xxNyJlx|n;y0K}IxST-R2-I$`g%E|KciY0D^ZP2%x z3AG7Rz|Ch~hwDPpccT|vV3~sp;{fOeRkU-Lo4biDb-+Z5x3 zjAfGTe8?1>l`H4~iR+N6J+J*&@>5{t2UkEZnKPZyrLmR18c`3>^IBXIbK{cuV@Lv= zFNrFB_5VuxzG9{CbDyfbN5Ym?u$d~0ROzPn?1)SHRdGo_f=mDNB|Waa{P|x=|A6vc zkB4&Vsc5Wxx1cW#C|}2Y{Y_x}CnQpp@A3Hb_3z%#9?#k#sfaCobWHYiwU6M61jAYU zqGUw-tZuA4y3bma{MA^X7A1d+E<`}~RuqmdO7!X7hV#|DyK!HGc^pd-|EqT6mb~}; z*C4i8W;-;NRoUAc+P%>Q$l_9LczZfwa>J!BH6bE;9G0{0v165vlY49q?D}}FBjCWb z2JirIhlW`0b{h7VVVpWJRnLE!XQE45?LFTGo6fch5b~|P2n*q|B67FG{K1-S;H=rFib&kdt&FmI#4<>TPTnB0fs zhsmdT-^QyLYwJE>-wt_;V1qL>87D)5XRM8qYVV&(jN2doqvQAO)_5Ytl8@A=y>YBR zwjg;uuSLh>jCa`?)h>B+!Y7UxNME_JEBge*-7><~8P99#84$|FKRTliC6Z(~N9Yc3 zu)&`9K2JpA>aV<_GRHV&PG>7T&i%#-Tm@gIj|qvI3Te@y$vhbrkOH~=b3;jXI-)kif)YH&l7*6y*&{#zHxWj;UY*!d~bMLQtC%Vw)R=4+dZctyL6ah zRB_n0z-i@oq@DYS!hpBtlnt$YK~m#i5_>MJIfW_tngzoW_f$~J;tg-1?Jl;DzZ0Tr z599IF0`w8%mhzC-!PS+|EXL9WYnivug3;9mWI&}awjz`BM{bC*hl1cvd$A*a1C@jg z6fo!7L4DHp3B$+rt>c%xY!9T5&wn{^2`{znFLO`lwJQr)R>&9iJYu?F_CH?744u=d0!}xE8v|aM0%Cj@8xn8j4jVC*j~o2 z>_z6c#4eY`m-2ka7zX+Ik&p%ck|6!>TH?dQL_ApaUz8WM-`u`?a<4r(c!X=wS*h5I z;K)$a4kW{P=_nnh(nsj2_&>wZbBze5IN?kN`-}CPVkxvA`#v*}5XeXRUAP^`5Jd?E z)XI?QPiFd&U1Wy0>K8+B;XFB*@4!fhtMyS9!+|+SLJm+MNc+Vokeg5-Nd6d#Yq0uR zxXZE4h90F?SWZm)fCL|dNvqJLriTM$2f zrpJ2Q+3N-Df7*=cvj15c-TxSPq^3{r(x<~VN4GK0z9pf~(;>U{yNrmn+0n6Bx0G>W z^Nvg;W506%hbXA3!n}Z+pRm}4-2x4ODfE-&<4{| ztO0o1g9vV{zyW_Zv~q?#P!`hRGq;lsUJjCX&sc6lHevfB>+#LF#ic;eNvJ=qFee_C zlGd|9i5=HaiwPG<;x-?s0zSlebO%z5Aw0`i-UKKrsQlhk>~WXVkALCi4gBCQEL4Py zN7=ztNFI1aLp~!R>BqmYZ08k3D*lBgFEX!%Qu)y2Y3Akl4!E>zWAL*dYmYF7^WDO3 z+*s#SA=;f&8H8_cpbv2_V-YK z`zssj^uTx-B1718haPl1I}r?4CWaO`>V}1aevCdJJQ>=aitn@7s@OtL5hSXFDC`D- zBKX0RzR*gNo5wIuSqokxaNH2>$oleXc!eJ28MGlflJ(`(lpG2Y<1;ViN^bCe5+iy4 zL6TJlDnC!fac$vcj#nz zbM<08w9nW3PnRa@#S`Ptm<+EEm&e{|(0qk6X4txOm~F@m*F2$n{5(j4@1i*0?ab=( zbtpJ}1%Hj@>jmbov3#Sz{0*;&H843T0t&cj12dM>R~MRdohOBbM#2rzL=AcJps(O| z$XLErxbfFmzD;2MhF8S8$BG8H`4?W%qySLTR~H&%d4s_GRozS%IwSlET`Yb}z^*%} z#!=t6&uy363OT4B>WL$^9@Je3eGZh{e_xS6eaAq(4vFtWS>+j#Cb^^B{2`A`EZq%| z|F-nK3{>Cn@Nu-zbErpI==MCAp*OdXD^==95nxg+$f4 z)l=0`$S|s05M~f?Pj-HVja7fLM&Qpwsv&OliH;{H`tv*VcmmZ_$8nMzS|AH~9J^rM zlQ`gF$-Km5nz_9k#ibG?DY5UwEzvy?4&_J#tsE}(k^4g^a@UKn6vT=Ockd~BQOY?q zgrq_ehc`AwY0*Il8`A{+0><>En9`79yMK(V@3MSm&moyujAqdrQVEex^UsITItEWM zXSdF1d8FH8`=cR;BR&rpreA`OJ|#X0qgNY<|KHD!e>&qI)HP(?uG*WYKfd$G6P@Ec zEqY(6_G2hw?E9?ESTOA5eWf}XdjMBI(Vf_JAEH~IJwD6(H>_`F$EWA~`l={{KA<63 zH;h>F#`Lod|AY=e36y9D=sd^{Fde%m0kU{u%3bgL)Aim7gg!&`^5Bdy?1=z4gC;H5?q~P9odYP0q+K; z@@C*l3=Pp4b+Qk-a6{iiw@o#m4i|T%MRG@4R6QIxOaDiqe}yah(lMBO{lD3S}&qDj1C_f85ev>Qdf;O=R-$j}q;EH+UefhB6x z(xRot%-jz-EPeQpL%~$z0GjnM^B9U4IRKmp`QBioUoSP0XrsuFID)$u;RuWoM5E{( z&^pb3|D*_#%(_?v!?EBAJt}j1sc8fSNHBsj!DBxb+z3jDID~?nynT>FFy}ra7OF;s z9+i1G$X^_y1-A+%g2-gdATrl-kpUT-TM%l9hJeXa)qi?YY&<&8_<&VXFK=4n^cnLI zZ>X{I5{^^555$j?(ME8OlU2h#`czlOR0vB_n7I)0ISwC0k#HI}C32I`OyPhAA({iw z`)%HU%ncabEXhfp$Nwg}`2YR8?0Lu!&T$~JiG_Tg$LXJrH|6$VgTrTxmrK!^WYzjC zZ$zn)yCrxkVSa9?Bmn}~P-To^7t-udM}+f4SQy}O2qZUi-$q)HOo$XYz%%e$?D6E( zK$AOC0|tU)9SZT6TMO>5VmyR_7D}ApatfPm?jCVMild(B>s%|nP9)YE*1}O)m@FjJ zhL_&o3`1WpF4a=#4tvwp$E`kN)hCl5Yy%>fE=ey!AQ*4Ofn6H0IL*4~o8jRJxb;mz z#4tSWp)ny$=VKu()$APxkId%bRE{A=GLZgYcOTMIQT@;`n?KXIoh)Iks3p50&+A@z z$^4|e$>|G5;ubao%IHuIyK}t>{-VfhJUziMut&!W1Ii-PU_kGz7XQ^{%eGa&<$7GY;faKx50*>68 zJ$(t79o*L;*QycW^y=HaY%Qm;gEX46U%c1McoFXCT+I40-h-WKuia+_q#+NsnFhPh zya{0?VDvl=GVTzNP1?5RCq*_+s46@{tH3_qt{oKvIRW~jCg=eLv(`{6sxDMY1R&|h4x@IvA}LI$$$7 z&S0|e@`diPn`3gN3Eao(&)g@~ZxuY-Q#W4^pdrE5!u%T+I%*)#Y^$!iDtYs+s~gR$ zeN(iQpB6#(`C6QrQY=xrIvPPS384x5PQX_KM(0~N2Gr?6Qh$IUB}NTa7dDy~!qY9R zULE9_(rBi@Gfg}>7{x-W_N8UQr`&uDK3bN5YY5I1P$#%fz=sGP5^w>)NFY5DNQ+RB zYf2;lVMlKKHRpQrnhO75)1*kit>p`1f&>_=O%qp+xH2_OT%Q$JmR2pUR0*1e#+NDb zGu?euS*C3i&yW8HN!Tplae&B3aA}IopQUXTTnBKGKz<~Ut2GE>pCDkFp+IXD#C8ca zHn`Mf^M6L`65KCHR6h}8L!`a{zuIv@e_u#3x}{ z!YeG7Nx*6boGa)Xg=ImcewFxeouVxhpG(CDRqL?%^RLFTb(`F0$i-Jy*wDa6bTO{bq z1l=S|8pvdgpl!k)#dS!0TIsV%eEx<-Nu=H`eDJ0d%|Xxy1dV9`i7`ptE$D56hJY~8 z4pQ4TGEstu2D z7%MYDK|*Zx65XHr;@5*Yv0?rA0QnoS4*{c7KJ0)0Ix)7&rz{@@X?)s5N!aVSd&1fe z1%lk*ay#CP)R{YgUFg@Q3FQ{vQZ1aPY2x}XxKz6AJCkdqbC_&yuB5^03MpqTSn2~3$!b3M+Y|E$pA z{Z1Pepys+h$pK0awikO{P-t!JTaXxniLU9`Ux?9Y^NFV=DHxZoBn`Z0wN2GBgja#=Gu_WNfMs%b5T;PVGMFlAnkl(S8$v$npAZ7`|2?IA;s~{#RMD@d;v!PJCf$O=X`r+|(*#8TTBrOM@ za?`CiRX;q|hO4l9D97591hY=r4ZbpMhL9wHB(g9~n=P&nP9l@{WKqDqI0uDl=PDDl ztHk%u@Z}tL4`oy1d^d^jGs-uza8hJpiPj*vpDSGT3)L(Wltq`IR|(ot{X&g}cKn>l z4Jh==SWOQ{i$D`ZBTzYh0T>d zs}&E%G}{wJIHhKSgmFYvTQa<*t~LUjOCp(3QvnRk4_D6K<~+kr$tZ{7#< z4;r&twJyOvp|Hw29`x0ld|d(qaOU9x*#IXPunl}1V)A*7e#n0oWf=#8i_>hrHfE<7u~) z%u3~jmcfFwh7vK$*Jl0>NwW&@>mbwmB*YAW=zP@=VY(QlIiFynzex8j zdGqZ4JB-Lw%`N_J2G1c_WTpyjig5tGFLTd>i(<>sWBOCZ4_6@>89(IhPUI=x^qhP<@)YlYuL4qrIVRciS7FE@|J3-_#>L_|9~@zo%@A>eEGHEVtaKiOH}{4dwA@8s-~CAxN|K@PU*@lyvK!2 zre062_sY6rWD6TrWDA>=dFz)Ei#G@Dwo}Zs9`@!?#>UF+hBSogtmSWZL&wd>(PVT_ zo$gtsdsge7HM(b=E=D+&HD?|K_S*^%i%CBu5I7nzRM0dFQuaf`o@zmRmhsam(Y3$R zzF`Td%*+Ewv8USV`(Y289u@{%ui(Sxq^=4>q;5AW9agw$IDkeV+!ey2X!c=@;A;F9 zV;>wmd7Qc3_KPCh%5UDZtUHjj-M~IW_0_Fog3BU0G-@o zXArU(M%ECTZ<3cqk`%`*aLjIKe@FLhPCTP~w&xqI%cM~0MybeI z8_h=>nHt@Le@(ilMfdDi9Cc5t?m2`*D$tL>QpC?CYc17x;Bk;)HS^g>gi$z0|^2Jas)3?&gMZwjfh5qtT>3Z|$*F$7H6j}ry^GARc7c>aUte-*Bj1>*|&5+w# z%=ef(uT>}*8jWFnX2u%Cf#gZfjTPGvCePDS1w~&iiX10_aXhX!rtde@4Y0i~!M?I^ zP&9ch^Sg}iGiE%1%=kX{g&DhHJqjtvYpJ?2nu6{aPoMd#A0h>_x}$M-G48IR;?4+t z3ArLmgK--}#SLj#DNep7I+cKO-jiIbv7Ds^B;w_k0EQIuXguLkr7cCBSe$E>xfJ;5 z;`~7+51C7p{O7LgFZrtg4=8!=RMq<_WuQAl-PljxpRpH3fP%zV(?eLDS%}O zfO-1pZyEmRZ%KU?Ws(n*M8}>Zdobyzxg+)LZ;^U-zp2IsH$GEvB7%?R_+=5EfP`_O zfbNL-5IyobwuwJoi^YaaHMqLq)R`rOKLa6FZqh4B*kDeY55oF1@UjT=g)k5$WFOBB zE?sY{a+B}vR}JD@BII60-ZM&@Chl9rEf2XM3ns6)eA*oGx>CHH#y)KIXeaeKxV5?B zWdmp##%*#Ws(w+55o;1sr)=AfmfoSuq-e;5m?-tD3#^Q%kCrM{#!VaP;cO+;a* zA$8+b(~B;S^G!#v7yU@>DRN=WViq$t%mJ{S6Qk_BtVytX@i^PFoEf8YYlBRSadWGh z6rVL&$tmscR4={>%KenTb3Nqj#j9*)n&J8isC9w#Kd+Jh+WK{2BIsU5tiX>5=s5 z^&}cPEgkjDkvU=*conCyy!|(*&K}q8DnvdS-3}?az#0nfOJ{Ae3$~eizB5D@tT5mI zoAgy-dWSM`ZmYV%s>k}vqxEP-#C}*|KCi-9{jkFPowyy=4r?P^kha7!RrQPBXutSY z2Kt4p0L|WYq&a&tddnX%gyZI-|E5tL@~QRoR7c!;+J~Y(&w4rsTRtps@ykIHtCQM3 zzZLV-)IU6M^l&r zSjEVD4?^aTu(;O6f_qq4D{rz_5ThW3q}f9uGE+$-WNv>(4lI(Gt^y$R+KKX8BEOU5 z*C)SO_zl(aCMKFL!qIf)0#?!GTaX#qMQ?h9g|+e~dj&BHLR>Y5LS&}WMaaAk=~7}2 z4kO6LxA9XhomF)Dh7uHOUYp;KcLGK>-n!2S-RsBtDOA+q3x!z6u!n<9d?>`yG^Z<= zIWWHjSdoeIHaL~UO3iML)p%I2-4OPMw29zuXEe6J4~(5`Zo!?5z^1K7CrSR%?%+#@vV}s^;0)K!Ve;|U+16Z3jLl4X9Ng*&KgTv3uH6d8at2(x z1rUjwYc~=SB}bB)1y@1?K5Z#o>kElrxzD@^C5p{61k;D>f>XjMAk>8sgP5@B%!`Bx2~=h?nMKJgy=~PyS+zF*LSt0>iJkFov;2lrtYyFW(Q5+mG3 z=p402Kh)km5Ri)19&vHCM@CY67N^=e7`SWB5wKwX- zZabNnD5Bt-9}i-}f-~@_Y!8a|NnZLeiW^ifsKSWDv&!;a2aVfv0@Ws@`m zqeCdnUl#m2 zH>{G7oA9g3Mn75I`+=tH-kbN#O9 zC&uV=2vv^IW`HkdDY(qP{Z#UNDF#qDJCjy3<`LR#iJ8km3`F=kTYr-n+mb|!67)Qg0AbJ)|OsGAh^Rw$QO)R%`!4|OJOQPkB!y&so;in?1-AF`R| zPbBwOgm%tlrHu#`i#R3b-5F@w;o7 zed*_!B+fA$PD3^^92PXj4Tr?V4Tp2!l;Kb#{_MvvvB?Y@UJQrn9Lbp8;G0JWjbu!v zS(|>|458SrKC#CB$t+g;(r3f z7W$>4Sn(J1jE~JmoEyV3t*VGJ;Z_mJtZ6=jO+cugaLvAIc!X=a0V~?B7;P(|bJPI+ zPy^4u5LW}l#nk{ANez(q`D!2?DOh&+dv~gZK+T&Eqst8{J|@*nxaPdMLLFRtVs`=S zU>i&5%@+nSVY!(*t|k)_sO)Y9g!nP^(%Tl?$<$(sU}iW)@EhF8MuZiT%ssLqqZeCT za3?#L%cy5hQY%7ui7VQPxTv+N>tScK78N2=PmT~-!f&}&hYlX8&jD<{+J>@|O2Pej zY+1#$m>*w7FKN~1skH$su@(eD>0DvRNDyPkB%7Pz7YwI|JiU2+$+Zn1gSlD-Cr!k# z)2`OtoRxE|``Mx9<2HFjob(`;!OT!>8a}8d*HCC4umhG+mljIHMXIigF5Uh&f0(BNgS^rv7&E{Hv^dCY#b@(Mo3O%{Q;47n2$m0@b|N!L6D%iEObT z%!#=LL9~r$3T&0m%JfhzCl9P=;KQ)KaBX!gFv&SLj51%qlxE2KHO6ZjdCigNxxPBz z>Nc9zFX2`?Bj?jR#}Z#|{K#P$R!&})gPkHS!Rq&efxfc^zda*X8v=OCwf$&S zQ}y~Lpv`X`LPIc#FlPdUo=QU!m3UIGmmwinuGox6<C%FXYgXtg%MP6pPHTp@D!RaDx{pZo>h-QsYOEb#lxU$B-e@64L!5_lpQAIpmOTTHgqIBIHH^Xo`)0F5MA z%Nolyq~Zs*7@kviqH|>|O_64G@?B_ljkPBTHzhCsPc&`qv}7?GdC(lcX61|}I9tH0 z2yPPa5`ftUaf-E;3CP}~uVu`^rgVMn4kAwIYuWhFLf3BN_b}e2=S@#FT5$jYw;p24 zOJ4SErhIxz%`UbveeGr-BlGQ%apr%G$7E_X71Yj&CfEWPO=1Zi3Uz}rahPIe$jmkx zZ#4wq(Hgz=T2p>|@f(_ervQ&Oqu|zx*IG6XeQgJR^VX6~X+toE@li%?7d=B8>DlP_ zD@g8_6X#_alHt*dauR(7D)WY9eY9_4;*4BX42I-+v@c&}-jE_m^p&WxF{ETh`z9sH zWret))L=p zI)%9HJ$Y4nA41QCz(`bfDBd|ba~#v z49Cw@Xq$b!v|2h zI{a>z`SgcaB|yyUUWiD|R0$mLo+a2jP2J!yeLkq*@i^LEKH61IJ*G*?#vF_m?WVP= zPd27=R82UXFd!mH62!A6`La)-s-5OI=5U&O5=?qDf@?|MuHx)Fm z3!culDP;(jqr%LIhPfI9*$v@|?i9Y#LQJXnp9aEIAASnpQP7Hp>1#$B63mOA=Dx!T ztcx$QK;hB~uAKrIPY&r#n}c?Dj)8jBppt+T9|@GGNYbUbS;3qgVwE6?rX-Q6<+mc^POfsSQ(LWvUsp(g{sL~Ia| z{fc2rNWhCac}~^2Ru!nVB1ihTBrhGLCKQj&s>j;`mt-HDLd*4IxV%@d*Nm4dLJuaa z95w;MVy7}*yHEU2tcdx?avr;{1pjlskE?+cRgmxFScd0#A9ud+h0*Yn&K;hQos8jl zhZ=%84>JSZ0)`ylTEmF#XFXVqju%<|{V~(H7=}9`;n#qkJ{FH%(JEw>k>WmVch??_ zb)7VKr`?VI;_eyNz6a)JjRL1`cOy^=>H5bHp=$%W?Y$$r+V`{_l(qHZ90sKxJg}eW z9vgVB^L1QbO>$?V8{B~8q8sd{v$GwDF&09azQby=PHD2P&UUm{w(&HR?UgMUt>2yC z>ufV!Peq%pqfRwjhn6MH_C^$CR9ZWrD+T zehPZ1TK@(Q=;mh_%JTC2v=>Lj0L#m?^agQRTpm#cG%PPeA3kpU$`W_MCUwtWlv;a) zq8;l`Ws`c(e_$IR7MEWDG@u8fyr4)MTC&;4D~v)Hrh!MEN8*iHE*OnygMI2Y$u9D` zJ9+u<;1kNfqV{m|GRmq-R-dr4dYxqT${#bU4rFyc_ruijJs`_(51D1C8H;5Z@T;i2 zOYw*^v2iMt^uR2*&-|e4Jo#qus2Mw``3}dRoq*y>K#gzb9DfqFsO~VF zo#7ng50<qU9|Un8SFiuguQ1zJQ~8@^Q->*+1@!N8oL5sW4@^03S4ce zC%f3XQbWCnzA_k|3pk+)^Dd=}ZZtKljiQ<+XH*m2-*s5qz`)Nj|34Y$bZ6dlSKwzb zqz0QrE_qTPeXsIK_WWpreumxnpn5Up^Q&mj?|}IT*9*5yHDCNbiv&8pMP1mNP~-wT zej{MV4}c?F3@XqKlvu&Q6fJU&pUR#e%E@UQ!CZG56PBniE5JM_ONlXf`Jrr+eLf0d z1#vZ=?Th#5ym`z#h8Abk`u5+IYa~^>DQkexKq1Va-RxA)NXrypEz&l?4q(5Hy}_mc z#mL{)f$L+|052QL8XyW6&;FG)z#5A=3_pl9K!3kAz>)Df1;q>?)c5_LH3N7*7lFzQ z;J*Qko^SqNXAThhb^kGQfX||sX%4V~#SO)Lf&UZc0HIOv zfGZ_v48eOd2X>XCsKOY^NOr{(KY$+Z$-3g#SN*$#v-Lw_0_egP8FF6HGw27Q9G`0O zI|8Gj7JrDV})kH4Tzpi=TLQfig=OedyP$MiVi%7xuFV+=zX2R1>}bV(4A( zf;J(ufUI6+&$CqT-$=xth(IpEVn8Y|kJ~tH7%v41qZ7wf7-!MYF=>4m%QIB<<75@t)$zMue;S;hw4)^ih-Rho@;(vka4~AXF2TGl6CKR$833;i3)G1|CsZJIOU%!Mq z42*@z&BajoI+L1YD}DhCl($Qlhh6d5*b}%BV?{^EV@^d+^O?yEY12nY$m?k7A`3ak z*e)INp(i2QdyPWqw}R$uVq#Dta{E~E zK46#TmVoBv^ckV$D%VK5uFwjU>wk{J^;vDEa=lBJLtCa?f1&F_ZMAZ}0@omwVH}2H z7qR{AXPXl_Fu#5ybHT(9&Rv6s2|Z^6~Jcolx!@mf`vu|WURux8v`$r5vg)Vs?xPBg1eQYaaCHR z3R)5b@mWD+MykeYy@I$@5IK>mEY0y-vZ1V8u&E$Yl^?0f)y4|$IMyVQs)>=R01g%0)q6mV`{@@)paC*t~4(4S09XVZNaeB%8Z*vf*NkVW2 z9W2-cV|;u-*@0(wI73u#_3?BO)?n20NxWTb340Dn!-sAQwqDN~tmQn1V%?-ed3LE! zH$MN$<&-UlH}Uug&*}D?uLB4!-EXU!NY@hFzs5_ZXiFra z(^W!A@%h17*&!6!QHoY`9ahJKcBpbS@J6*72;%#Is=v1Q`Wt)B`qO9ar)AiHQ|ppA zU%)yby8-8y{m*ry<%g`|1@CEd{q1}#h*u{+1ORQO8O2WH9tU4THZFvUQdh=3PCN?4 z3D9`d_l^0W@wg6C#arxDaaL=mr!^*ma^w`RT1<()0MVoNaDbBGbwYD{lOBC`OzLVd3117mIiiiS=UNnIY@(iicG_@@)+24`*AN zCTwm*G}M^2L|oU3%c*S?*JyFMv=(tCi7Q1rF0PXwFj#3Sze)L@8J5ADO>D3PO}}6$s*SAdq28 zDVHX=5OCTW0UrS<`njNX3;MYbJC&Zrh5xFAhn6HN<$41nindt-ehK&iO1ZWPdYqtf zEROre)ue6}^p%2MFK908wO&En1&t$b-a`}Ze2SU)d!I^kyi%@A@p%P4mQt=sg4iVp zQOY$}5Pu+|9*YgItR~CVg8qrHEEu4aYm4|)!$&(LU_gja641|8taSD#^Nyr_Nz->%mmY`2T4-PKo1>HjQ zG(o>1Xb$C(`Yxgu33{KPKNR$FqMs1-R-jqg^{2(Bk3Rdw=O+>%MY2JW8qHSE^aceT zr>ZMm&~pXdBupB}Bwx_eg*^(9vrweIl|D1YCr<*{g}sgJmk8P|=w6{VNxefORGo%~cC{X)>0 zf*wn>s-y3d*-QzzOqgY9nz*XOQ>%6zq%DAwq;&C1`*FA|IYQI z0>w;5H0|%8v*T_k3wg9rsR{n);=d1<#xrPgnhoYGMJqW<(TcW=?3AvRMYtwjG+5UP z_*sfpl=lEdD~Mqp0?mulurdv8LQ${<_==W45@OuhyusQp;%amrgS$Wnz| zgvo-)20`W$xy)US3<2LU2YG^DxA>*006r^#^BGp^2q3jA0Z)G@v4CMJ^{wCvE(>>T zIR&_d%R;KCe5D{xDGL>}u%xK0g$i0`0G^>r3));_dTDZKjhm-nqMIdGV)_AM(wDgN zapRs}8;MQt>m}V*@>w4pOTayr;h8FZOg}tk^k=$Ad6dv&u6uTeKR(x=9T2L3p;XQ< zf`>Ly(nI|}noq!!AF%VL<1Fp0ErQHPXn#3V%b}p>gnFC@dqFN-Yv#y3XQ|_nF0z{2zmmZk1f@mQHn{^=I2Ll;;kNgWoWeDl`PNOsYXW(_ z{!j8c^8S(cdK}9R2eLZb@q`drNNwAN_?ZT_oeE7u-qGHsnSI!Psf-1i+&!=w+u5GD z)a7k|XBn=+u0W%_ue0sm&Nl0YC4RP!-j}*AjN5;goMZi{mu`k?mpyvCc92r)1(7R~ zsJ@rz0#ZHggl1?8W?D}>q26TH*1WdlWg~&J(S@=B>vqO{9! zko{@JKHXS!TIqkW_&b1zvhN}L(pL58REgYqb|8bbH=-_#Sz8Uy7Ct(aqNx2Cy$rii zqjWR1Z-t=F&>V}FZIpInwJNL0My@8y%=iD!)#QGKjj1T;5bW9Sub=j-H6~2-4)|01 zg=hNfyQY_Gi*r?ZXdY6hwpZuXK%}$)DMbqd^$VG=FXvY4AJ-@}Y%yf6q8f#u9%m@! zIP$)G*2ZYOPar2apxDHZ`8A36oN90EacXaV^q@Rw;1g+4bQ8B7Y6y9ntk=-9nxgS= zm4SG;QVmT34d#6SgaC>;rUD-H%z3vVES0_mdFHHQz@6&`)~mJ^ zBgj^a4I-)8A?y^({{IPS;PPRd)4WY(ULP^uC_CZ8yhyP7QBzi!wEnaVaV=%MR z!t4%<87M{%=A?G`X;DrMvcYaJuN=%NcN;VDAx;pmFrbQ(J#B;1q&C#=j3=P^^T8(pB+GdZgdOM!<(F1cS9 z7Hk)HcZwDibL0g!n^zGB&wTx%1D#3RApNfbkW2+4S1Z8l4z3p)h9JVdNR+5vh+2jq zg7S(e(P|-T9fHW-PxS9X)HVcBQa=&ij37;2Ll6z`C%P6yqJ=UKPdJy2;*^T_%@D=A zLl>=Rkj7JuU1@1CfPgyuw5Rap~*)x`@q1Sp8qNOTipA!0o@$$ z)94TN(qqtATf-{m$1Gpsph3Z}x+jpj^# zm1>$YfI}Ul{uH5N`-JRPD($g8F1N~>luHDety?k!fCBjnja3x+9w!(|ArSD@UQ2hrw- znA8BE!#71Ap9Qv{S~nX zOs$EjGT(-)TVsdV8}HkK=I^of7}pEvZF-bDRDp5C4j(edDUzGjotnyHC>=0#RkZQGgENH zQL9RhtS18-<@jf+S<9FMUFsR%QWKs*Pp`9>*16>+Ufd%*mA5?Dyy#7SE?5z;-IG^mqznirKMtn)ZbXiy(9UN`*4SX z-lnY=c7K7$4Yq(%4D1*KA8=Ig1;?3xV~l*k0da}_@_b|QLZUw5`Nn5wfoRC*8+Uw5 z4KCL6jr}6KjiIj$HgGdq8$Ytwe1sxMURc!l20$70F5h%bV7v@?3vQLMZvM>}<`&+} z5zYp7N-7z*#+G1mn5zQ_0Pi;6IDm1ZlRs_zd4)eO;U{j#hw+QTvpDgfy}Gx56jonO1Lh>VQ8X02>k#IbND0RGSX0#>l z%6t9FJttqjz6Il5UdsYptWd`Ozu1Vx3bjA@*73wUdMXeHV)#;A47X>D8Wh9)nV*jP z#2EK65adjt;bj=8Dt5p+6)o)*I)h%j%Mzy2{6B`q6#qBSZv?6Y6fF{-2lYBpBv6|N zqkpF>pk&RS9qE}+!+m&i@(MhDfFLc*E8Z@Zb4{q^`n;Cp<=k49nMY6^sEE*_>w|A~ z>BXmeM*7UX3TO1uVj&Cy;lik|%otf=LX;U+z%c$9U$JMjp$!z^z8I1RaWmk;>HU)* zo59_x8GK1KgJL#=Vm5pCL`aFj|!>;GXPQA=;fXbZBpFNNd zG@JPI0)Mviryf6Y-h*00i^zN5e*?w~Bx?-J4vR5ENX@{8GUWazJM|JLS5plx7$EP6 zw?B^Z<1AN-`ORT8@`-9x5nieD=(ll^=nQ+LdBP#@x@I}>80c}EXQIux$d2ECC|t+Q zeW!|SM@|it&+W#0D2J5_JXjczib-z!(M&fE@9bf_8x>%KOVS~a7UI+KkA;k;M4hvB zoWen$-1tj-8koPnfhj6Iee~OXxJtF&!<55Sk$oatDe;`u*XhAO>wW$aXa;wERAl4Z zDHu_I@Vbs;*4!DmJn=-$YsgNudEp-uY>CaIUsJ}fFo>S|Lp&nd(5m&5(3gazl(vNdT0uw@lplf6 z9CZczq0)u}X0+D#l>^9ctqI?l0s|ra`RixYf~|Hx{GcNVzscYP-6((nKt%`%`*kQV zDdt=RgPK#kG>1!TLK-Y1REZswP;pi7q({sM6&-_&P!Yw7_`!?ln+tOkr^v!At*f8e z(}yi_mru*g17?;fjO~u+s8V!$7Cy$_(3fKtu=bTr!8CBCP}VSm+h-`sB~eO@H_`T@ zh~L>ywvPz$Mn&8bBmODT1L>b9{lj^-?Z*{y+KwU9@FR;Xa6|ROx7oIrfC>qoH#Bi2 zh$}DE*3tJRbEX8%xA~owsoECcj@^y=SEgEwmqxBwg){}6l~-%~>30+SAl%do*u0K> zMr)3p!Y2i;2!*b3^uR)nJW~f)OM|afq2o}~B69R;>!5KT+8Fg^*j%Br zYyVWM{!av}OwnelvgzB4k{YA=mFsP|Xl`cvD!5Ti+lXenlJoUJ^)Iw@q22&?daORu z4SK6ckG7rFM^Zx}mhVvGmDCG+iY8na+5C6G7Ldi&_I!-1el}O=Gqbox)3>)w1th;z z;pemYOCt+sTGhXBhKP1q3B5&F!lK-#t@}UiVIje0&ew*vh?9ooMpKUQ6#6_+;&H7j z883(=zh%B->!jufr$6f5vt;NPat6mRe_#yu>^(i_FO~$!!+6{FX<&tlUWLyP1IX(w z9JeM#%dJFf0-aTEXJE)KE?0~bnu@Kg3}`R$^-(7r=R`Tq*35p6o6qJ5t#1~`xbZ5U zU#{>=Q~WgN3$f(gC(H(n(VwRMnPKKwv-oB8^Gp8c_^lIuODulAets|f`Jd_^CBm=3 z;y16K-*^8xetpdtTvlvGGpub0Tu^zXwhk(YQjo!EZ)VHR|KEigap|FmuYX{ zqop>WR!i_>u7FGh?(mK0IDq3VYO2rJ*F4cZI>EGsFxbM{SjZ;^$BavimgqQqDa1S} zAMe10d?ptLBcaFCj|Z)*4xWi%%W)?q6~<%sFu$|QX8R1*1J&OfQF4(D4WYm=n36jC zC~w}$`A1hybSHC(kEgqMHhXl2T2L_^d`P!+l}Z8)o>ADbG74M9&yJ8gc z8bMKDQ9MfTjLE5qkJbUmYp=RY;|fFZ+D6JTiW2Ml-Mq4oTRbBtYW@6T-1>Pe*U#U0 z@;vKjeJ2;6{cmvMR?!={7#(Q1-Z~};F2-495qQfwBM~*byKYqzuC;BiQ)FACWJV-9KP!F@31PZzdzT_~G!4nG0%VbekPzoQpk;x`ntvW@ zJ!=5{r1=M()FJF#7Q0FP>~1`p-6zf$;J2-j$xE^L&FSZN^uSrk`!xJC;TN6Hc#3Le z_xt}Gzf|F8?L4&V{`B4X&+%(%V1A=}qRsvM-i18-pgqy2$?qcYGm6J%6uTi=fl=vU zH0%~|MeCeJuZ3>o;juVRor?KCa*I{Whx(&kbau4oS^1#CMu2Ou8Ar5%EtO8q{wIm* z{TC3G^h``=DGGOlxLeg}?j#xiLb842s&dzHOnh=9u+Q3*nn%G`E(L14&`@LhPi{EP z>-V3*$?X=7F((7hB8TZJip7WmiQtJV^80N@IOIWQV2X^WL(HGpzq_2V{d=&tAa=Si zXycBPg{XwRG0TY)NEjE)`#5>oGe{J3LK*Y3O;4Kldypp2AzphZvv9MGwvcBl%is(< zO#h54)-X%k#17XL=K3N8E^Wcgi)$Fpco$*D3v4x0_F=;F?8n??Z}yfYSS7Q- z9(WQq|J22b*u=C9+5L4d$ODIh;Z!8J_MQlsN)9mZi3Pt`${_B3{Hu)1r4GUIG$Lxj zZIs&ogNN3h2CZ}*q)HaExj+Q-f_z7IXJbIkwLBm0F~rZf+Z z?8hd=Mt0TqBMV*qha*}p2(9tqyC~FuqW|^nK%o?8qAo6|yiS`2eq8Qx@prAZh^`Tp zU(nV|dd&Tx#hY;3_Wf{Ux-g06tYY1d3>@EoCY-YrvrNt23}#oTmE;61mo8_pFEKEx zvP7$f3msst@XvvuaW`h+>W6PeOz>e$BshEi%98-M*tXllLY9V)O3;Aw3N_!165?BJ z+jA80v?%ewWWR+&aoGa<71^pN+2Hx>c_G9W>Ip^I8YLXa??*z0laJGiY;22_#=-o) zBZN3lnFb2vd0v!oAirWE%f}X7k!^~S4d!>X5Z-Rv-lPb7ql5$bo!rj+-eKFGvPYuL z#Yf6;Fu#|C@J`$InTl{(lyD%wUkX`)ZTn_L))plj%t zuyvG12V1qi+tlCx&-=a)Dwr19{a4{eBZTAl{n!s=F!5&jN1SkS;Td?7%1-w9Z^XkD zXxu0>^LTZ2{y}RK27m#B7H`X~kt(`>iq}UrwLJUaQwi8&IE|YsjPKd&X1YgFp7TMR zF;zcwEo|IiyOP2(eTbtlw<3EhLQKYG zOvXegD}vTDT<$FM55vyx%LO8DO69Hz3oi`jC15Xwv1dO4C#X-HWXV z4nHRmfNGSjdhy3L|JButKf=YTwows27bX0oA`C9hw^dzV{ZN+8f0cGz(flY%^JpA1 zqbR2qBjos^tc4dM`s;&>v!Lrl%ikv%oD&W5mAD|)i;vm-vxAGBwuQrkiyby3cab8$ zIZB>6fcz8_u}+a(5+%7{07)N)#t%`t+BT3KI|!(HaUXIST-=d>Cr526@Sh*FievwF zDURSnsW!Z3bnlnMJ`?r*o${?-jEE}-q;s003`HrIDN3tY5#d#uUy)QsNxm9SvIKP% zxJO%~XuMIH+dz0SPHO;FPa9xxb-XA^Oo@gVi4cf&jE$T3yC)e% zC6>A9FBnr{iFe^==iBpkEl8(nN}mea{yi)2t*4hlbLA$10HrkwNs0^AFED*`|p#m{yXN3TmLzr@WNUGLVo$fIX@>m<0D=y^;!>* zKkYpYmLJy5O!b|BoN*liH&(}3qL#Fo8rH=GJ#6C zbZ;brjrwT5zSZw_MPD{I+f!}eD(o&%?4aK$I+5%x<3r|qx2iE8kMQ8Cu16^jK3p2K zA?JA5%M#!PJ1>;2Yd#gz2^hvX8JZl^%JClP_L_Z9MItyvG7D~mX#SvGzVJ(pt*B2M z2_p;bfxC?9(8G*cbB=8GFVQc?>vsJCyI$r9HahP`eP$%^jpMEbmxy%1oyjZKpbDm# zkKMt69B-7(UwTyoa8lQx#}s{Qo?fWzgQ9j;TG;d94zy+;?ynQf&A2Z|>jRzW81$Hy zioqAZDJlks4sOPRe>)aj6bmA_(ku8Vf~yPpc2Dd=esF$SlBbNzpuX%L`^ZNB3exZu*0TqhjWxx0pb0Z?=Wac<`F{Hc{Erus?lRi{2G$VhpGbN+Ul~LwI72pX$UMrr& z7P>MDov01#*arCn3KKN2Mj4;DB8PdqKqvtb3OB*;1V6GTKk^fHn?k2P{q$ka>3+3* zq4}p9-x(H~;qZ3KZE+~Sp4l^s`VJTM^}kM0o^9_LMW>JKI$U&m2%kiFBo2WuvNMEz zuupKeiwgdN?<53%(Ak#v(E`4W8Js#RP0no@uMJY^DTxg>+J(p434yN8HYKVs;6RJ@ z&+}M_WQbZ2d0@Oyo&q(`|2bv>a(XJR!c2qQ1i{PaF)y-Z(}5CfK7P;|t63 z4eoL&-{7%?z$1A_7JQM7@70V~Le6!AiY6KYg(E2mqIf!>%@mps@#F}0|KelD%P5z5 zGxmQ&l%AXiTEZ+9xCZ1?>Zwk=rsjhdjtEtk02R7hP_)weKWP{dypFsg2i~+4K}o#} zk6J)3=OEW$d^L)kA?Ip{4jcB>6QFfd-e!|k>-=sc;4B3U;X=`hYcyIa<(m_1;X*9S z_({XE3ZHc4lDX=e;X=$+;leD|P`EHheRBC}F3bm}0J|`JFkkUAi64aV(J@2eW~$F@ z^+6w{pTLUFm0)>~=P%dxpJm+RMzhw@Ct;kf7+obrFHSMMsd{lLEIPm( zXY$kD^t$47e6Fo4zBc4_W54oQ2yHy=&8jQT!sn*C;+yapS62+xOF4RRjuHMe>6P&< z1?v^;lTP5-Vd_fPQwbH&Q;&{4F0$-k^0KSYh?Yf?YfqwFLK9l^FGzlV*TShmGwa8d zHtdAbP9Chh5H~MrCtIiZ%-epFV9R?ydBt83&v(Ge%8CX+NXkpePc#l|>>8HXH~PKg zC(a}!MiQ5}Q%3utQ5Z2DTMsIqIiW=stN9cBnfZ77$L5#%-TB4-^yKFo#vS%)$1(X~ z_cY?W){6Gb@3^9M_Iy42ME(SSODo&Vy;!v!Tg$@4O&3JH z5BSWAt5IG!mgFs*gz}kogo5gcm2EtOypU&*`_0u)qk%)|@qx-n0Tx|bedg5&X!PNz z`4%)s_J#{^O?Zp>Ef5Z2;mFb?gM}*A$>#i<5QC>B*44I}SqQdr$n%9w`G`k0@#sJ0 zTGtb}W}5I@qy~LND>wjG4qVzIK-x0?tRgO*IH4UwXd`h>LR$$9Bh*5uZ!@4?Lhlfg z5Z#1at-!rb$W5q~&}+j6KW-NAEA^(fTk1j5xSeuMnZ*zTz>|1E1^Y%zCg$%bUmShR{>oP zh)G;chm&a6Yk-CknoX$hH-NSfdWVp$4Ny0s5<;(wFQHaKu697pgbE1lAhe0l9|`pl z+9bZO1Ns@E)r8g%vKjZQwp)G{IK*)6j(Dj5gLYEWTPbis?<0zmc@g?-}uYqeN^d6ytEsoSAhe0lCPF_Wl>R25HH7L2tt8Y!sG87mLREycZa{Mh zZ6WkELax68nn7q0p~-|=2~8wa@HarW5t25W1&B%9LiF`SHxRmOU;@%U8UF$7E6HP#!gk}(Wh0r!adkDFX0eT^Zt0y#%xZlKZj}vMo?ng0P2oRH) z^ES}cL`x#72+bvKE}?2dUlU(KGYF0C0W_IV9ifSYwh_9GP&c70LXKWQpCyz-D2>o; zLYEL)MaV&@iO`u%fHHpy=tDxi#JvrON$jJe6OM8%=kEXyl0s73LTCnY&lB22Xe%Mx zJAi%-s9YOM@G&7Iw3g5|LI$CfcLCK1VJ5*UB8B%{K*6T`czuiANvs8y53BM8DO_&sgg8K9x{+Uk-?pmrca7Z{_g(c>!nLeYeZ}#Jyzx z1A&X0i|2{;Et@c)Osw*il;x)#4@l1Vbaz>FFsYSgH)qCpJ=G$BC~AR(yW zgp`D+30fhJ@e5%F&`Uz%Nopp?QF|+`?bTbY+KadLmfre-UziY@1Vu!pipAEbw4OM$ z4MHJEWZvJ}=gee+pw@fe=l?wK`%j)ZUwiGZwbx#I?X}lldrDmNeidExA>TayMRD;5 zzD4|tQ!3B7Xi*{PhLIH|{!@kZQ{n9q)5Q1o1VspE@ zSwy#j>{Vk6@>U-ga=n5?7`np<6|C&LR{|yk>hzNFA)H~?vomkmRDEt{X#OCQUAF#t z*1?WQLVn4Fz(_nM&doH8(`4Q-9_?n9UXrOh)(7oc$#`~I=z)FV8F7HG2w=&0wA%^6 z+#wK=M!mj8)TAz(F(UnA?K?? zZd+EQS7e5&2lL-vaj||V>vOA+qs>CjAaByqE5^6H~%P;X7i;n>NnU?sM#-JHodqNM8}Him&x_>$O3xH0EIZ} z!M-tIRp)yIn5I_E)~#ZhnB7Nw5X-IrfwRrX|C9Tk={!A8W7+ceG(^wKbhOD@RGX*q z^Yi^ljh|l_@HDQpe-Debl?gU?i%bg5w2Sh$u6nC3H&pzTwC^+Jrs{URs3mfC23xj} zG_%p_r|3?>>UF{5r@M<^5@kg&>fWUm0}9I>Mqmdo@3$8Ji7C8+J_1Z6wYGdj5_!*T z;_7bhWxJ!UNK#MJM?ZjlURTSmJoeIz znYO+;U<(A|%5O0XsuZ~;pD!FlCgt&E?qxyjtQ1)gv$Muy_x~jndXSJZUG-`<@2Rr6 zn`cWT=(pS5d@N1@RD@#(E&omud9rlc3x zB}=Tol=Rj-090tMSARyphwonx-tG(q1sA~|Tm!L&iq>^Cd3msdn~(c$CORee8XrEX z(89if)>8?E2>QIyu;0bP?zOA1^?j4gu&&}i5%-Cq@N~Z8g|jb}d*qoON>gs!$vV1} z`ggqb9YQ?@5ri(c7c32ow~+D|K1Tg(bTu|nSbG#9{e7DWELawppwHi>Z_Iz!-Mn6) zWBw?*8XJeh|Ab)4u0n94PFMF@4Pq?8mxu)Q0TN5@MtKR{1GK)Tm21#@ZLoAvH2*z) zvk6xy+ORf?qI*AQ9S@f;edkBReomN<(UF5QR_=YD&{*;#0ST6_il(=(?;r#d3*F62 zS7Cmvx_kTnz!#O>m6GH(N%AfCy+KLRZ1Lv>VD8OPdR;png!tBNQSmZA8LzR z_-sLZPas$i>?+KSWwp2OifFY*#BIN9E%w=!d zQ-tZq1!dL}@n?n99o606*(xpsc$-8~A6e&8z@xg{%~kTXdRP7j?&j@q;?U(8$k*tC zopyV)3ro)p74-&xgSHh;7x=L6KY^Tq5a@1Re2Br~yL*t!JHP3q;CNk$8{LKC>Ce_z zLt4)-_-9gZH=jqGa^JN?LT~uSRSHX9qwA+KBnq2kc(FL;LGpmJ-MC)zf|vtodKa3n z(OrdkLl|E##FN+w65Y*jpkNGz8c8I^QUB{x6M<96RoLHCfaq(Q0SV0=uRkNO!P^I- z*t$YtYezi8`xl8|(!>&ZjC2)F9m>5=j@ng(^ycFPMmzKIkQMjq@G{&?;u@B3y!M2N${TyIMUkDu*PUDBo<97Y^OjNd6j(z6~1jmG*T(Ft|S+PhAt)h*uyENkYkTF&X~y9RYVCEZ|X}T1+UTe^B7*c z@Z2c@yUlK33zgdgnHCNFnQxZ;Syy2}96fF!fYarvFIC{_rRY=fS|v3W)Be&-4~R&X zj40mSQV57CQ5IOhT`d#jNlEErj8r# zw%WbHXSNG`iyuXD$qvM;diV+H3L$1M+0Zx(Sp^nEv3W~ti-LixaW`%F&iKvL4 z0*(IqB&wsHsgN_jpFN#2*w zusK6bmM|{+V2zR?Eh-?vB)xd8q^8!s9x#4JQjISwIoRFuJDhgvArY5NL3y^;?g*-P zb1ny8XnAEHhLJCeU=9DPrz*ZugiPbdDj!GRW=1q$k15DrA1%aH1V(wS)8e%u0qh4b z{Cl5AdeBziWVvwz75^;70_L4U)v zO`5YS-Y$tD(XHWHz~);(QNhlu-?jRA#{(1$*Wa=o)$hvc$7-VjZ;lVM0cxk5m@0&% z&tF%DCCo)2N)K(}gPFx^M2gP@3H*l-0aCq-s5w^DcO~W^$?2hOUlp^8n3LN3_ESc4 z4iU*V{_z)?_x9b%m|5;~i6DO!kG}PwtnVGXiHdi~z4;&bPrQ^wsNi5C>bo(}~6 zDl>vmXdj}KajUo(QIdf4nGwbY*oYO>DYc)o4J8Op9Ct+R7tfbk1fJrAor!S>*lJ9X zYRq}sto_y_YhPik`8S2NVO6((ebsA-wvMASzifd1qcgz48Pk~6xsf~vdH!W;Qw@Ik<9`8z5HI~ z_c6cU5ckjg9K^qZUkdTF`Q`Duo!_(k{zQ6rk=6*(O5+#e_alDKknU2-W6QKBBswya zGBcAiGgC4%Go6_uMvltNbY*6a=8eBGZqISYpO8BC#BrHvnJ1lmN@n`0r)8d=amJZv zT~8W&NGqTFiTs}C`M#F<8PVWRjd?JjPY0^w8dDO3k$ zp`K#>;sm-xpodOEk3b!m%CW>F72h@PCy0+Q`}P=C)zGJSb|7 zgBJ!)L9MYMFqTO^!k~XNoTCF&b>Ut!e0(IZU7xe5qO#lw?Up3B+uL@qM2wx-c9?tB z+i3Q7h)bp@C*EO-?RJ2(p75}{q~k$+mvX@!x2r_rE7K}fetn@+--~5k)}8}@OMGX@xD+P7tUAkW z*0FB`HFYGui5DDfLd+wpl{cWJGqO%MLBd7&{7rm&C|vKrGf+RKn0un0fkaEJJOjO9 zjE8(Jm8!$C0DSjU%Z85fsqL8hGR&U*bG5_vrL$%0Ay%9D>^VHd$2?3YD%=}v-b&-& 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 literal 0 HcmV?d00001 diff --git a/CristalDiskMark/source/diskspd2_0_15a/exe/DiskSpd64L.exe b/CristalDiskMark/source/diskspd2_0_15a/exe/DiskSpd64L.exe new file mode 100644 index 0000000000000000000000000000000000000000..2b714e9542929217d9f2894298321e25d51fee03 GIT binary patch literal 350264 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 W#gw%IWm1aHH}VxE3?Vg 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

URpGGBrkGor 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

A(w}T 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 T41&gL$J9kfc#<;(=asNH#;qSA2+itz5 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�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

ICvXGuL!tQ zPT+L)9Ai%lBC9E&i=a+%yi$TP211~S=wnnZOTH@{@jFt$uf+^;6k08XcRZ8y2R}z$9l*nY8*z?^9(^l zD6$Ac(xNFqHj)2t$6AYLn~80uSTS%_s`*+;dDuCm#8F5qM3Gg$)e_Lk#yMsbd%IxAhQ_4}zrT`ag-6rNduKqKV)>d-0Fdwy4 zgLIa0DDf(3GwyTzit7Iz`1Jm;K-A(?{p;{1{Y4q46Hb}z6;B$K$cjiv#4OkeMMI#Dtg>|Yn)vn|xu&QpkZeQN6;n899XJE6C- zQ%cHJJa2AFnWcQYA{*;N6Y@DN6_Kzthn^aCH04Ng)K^O=gk@EzGbj<3l6y=wB)zUO z*kjh&2^-t{Ts}w=0ilOn`EwM@Z!u^Y<%_K-C1n*p(4H`8Paf9llwJ8S;^d1Xsi>cn zN!u_egXU^};4l;#piI5tF+<=-%mUvCmx00QAD>x5))o0ixbzRBe>|kbgl)(D4KL)s z^B@;t%O%fJ{k7A;VeKAXW4}ebQp4JHyvB(!Ov$<3_Y(VWV!d!@75a+=>sr`Yj0r{W zIN@bX5*EuN9t=gi7?R%k$-7fp{DQ@PI~JKOi@@LsDg@Xyjphuje|-Tw-q!{ei}{i4 zDf(Xv33;QStV)#UCj4Hp0CLSeHa$(4dlGm^nN;(uq|u^0ZYpl^4Vs!IP2TIpwCgv zy&Z_lmu@&G@tYM~6vQL~Lf_(gr}>-LgL^;J>C*e5a#I6B7O{@tI$?4q=a~#HzT=o< zP4ZilP2!m$IV=h}ghy69KdWGz{AcplWb2(#P?@CFZ4ZZCnxObGY;?w-t zPBOCMGnG9<*sNUB`bZ_pq{OO0iXNlp(Ky3^1sh*@0e_Rbn;+XSdq&w9E34!mGUF%$ zvhlWNlu@&1Vvk19Bg!95bEydr{HIisE|Ysx{K2gsuEFqAY;h5KX&ZzIS-BGeaWjkm z_(>3?!y3io#Oi7CT#(M@BW4D`r&(-uDqO zG8`UOB#sXykgr2T>_+2tXEY%FGq^=aS$qQAj0zvt?q2g0UnB(i6B1b9GBWs1kJl8i z+(Cdhok3w{lMsY3Of|u%5Yi_GYWzfMCw?`)7?-6)HY207g;dBwMByI{Vghw|X0QVB zY;=M*(%1VEz3GQZCm8MUJ3$cF^1A%0I-J1?I;!9H2PjJ09N8jlRz>PG%0E>a_1Kau zA4XTiMk6Dm(w%p`uMJ}_(v8R&88xwTEI(qt8NO}@67;VS&z<+?Kbw2mu0W=#3_{F@ z7tq}yG9N1}IjO)yj4~HQnU2hb)0_E--D;<&XhY>c6TQrj7l(VvN2Ki~3?$02`|Zwv z`64_iWk#deGn3;08wKrh$3nU@Ak+#jGUbGl74N`s$;fENV^ENn%k2xXF_DoG$I&>* zJ3_57EO~um;|N1BBSY>Zx&8TCIc3RseMxN^ai57|dEqPCwU-nEE7of}#+S&6qtl8^ z!IR1yqBtuT;f=*wDBjkNK~B7^^o}HbrC^@2jHy!QnC>iETbYLvz&m#TR0)k7Q%L0@ z_vFDf(Q{^FSEII-LOb+@6yc8Z29k&&+JNH8UASNfyNfuo!gAoTa0qkTB+hC-M$7-4yK(wnze=k)hV_%$DK;u>dDbhra~R zmAQiF2Yh4q;2N&UO60;)r<)vvfuV2nrr3qhKGW_rRS6g`|W)Df$*- z-zbZ~xMB~G0yIQ-Yy_eZ=u4R1MNmSUC@G~xP>)G9OWL?jt*Wk^Kef7a+WdyflV(-c zG**>X&u=I%tuZmYQQf*scD(x1nu^+)^GnOiD;pYAtOR(ajg9qHWwRP9=Qmc)tgEdr ztv^{u%mCeBLq#bQ5_sz}%0A-QH`06gW_CRiu>V(f<agb| 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 literal 0 HcmV?d00001 diff --git a/CristalDiskMark/source/diskspd2_0_15a/XmlResultParser/exe/DiskSpd64.exe b/CristalDiskMark/source/diskspd2_0_15a/XmlResultParser/exe/DiskSpd64.exe new file mode 100644 index 0000000000000000000000000000000000000000..cd2239c2d22b093984a3861f92f5f95d811fdbd6 GIT binary patch literal 414776 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 literal 0 HcmV?d00001 diff --git a/CristalDiskMark/source/diskspd2_0_15a/XmlResultParser/exe/DiskSpdA32.exe b/CristalDiskMark/source/diskspd2_0_15a/XmlResultParser/exe/DiskSpdA32.exe new file mode 100644 index 0000000000000000000000000000000000000000..88905a341dae7bce54f9790355cc93ade4ea1cf1 GIT binary patch literal 314424 zcmeFadwf*Y)i=J+IWx)RLNd8XZUam*0RurgNzg`uI+-LVL4t&fJ}6oz3E;^E376Vv zXdN!CL1`NZY6xhf*cL%;#?Tgw3SKbU>hsJHFaf-bwJl5r?a4qgCz)J+-+j(ZND%wH zzvuUPKfm{nmk(#oKKruv-fOSD_S$Q$y|d`P2Eq|SRCq>52|0>4{b!PY|NW1IvvP*KAn#(1y~r`ts6;A6~afU$$Dm;l~f_D<0P8FJ7i!yKdF$ zIg=)Zrusp@d1d*i^z^(}0?$+4J6`=6zMt~m{%RlIHJ;mF^~&#C{oi-I`l+0r^Xg^1 zrKfXVS%vq2lqG);NGD$zkmFyK-vd(itMq$mMY%xh2=u6=fROi@AX2&d=MMzpoFs(_ zVRH?5dFcwz?+-^2Jt_yRt6mRR)4k_nfAyYA z^+>RD@fGWaz!$+}NwiF8_Dj&ly>K`gQ;mKp8o(tx84-oyL{*tBiJG_?YpG-9OsLE8kZ4#p|_UKe6 zJZ2U9w0gHg;`FHkc_s*A+1FGgAXmKC*(^h{KRJxIbkW_95sc6Xteo6^T(~NUrIVT9_>Eyr4;KA zlM@Nzs-clDK+QBCp6F>DpLjk>9A$EQnB*9d3!maZC^vlGPF{Wfz(rQ8okxEM&S^4P z`CBtDdJ1zsPf{h3bJ0`O_JkUC7JL5Qnh%fft*I%D5t&HVzH}-lF-b8Z8`*8&J=Gww zNvAJd9k5*z5w){8{;^YEUS!2kO;|+CfBXXl)|kgw`io>F3!RJ05)x?`G>>Ic))Q-;4Y-?M@-&F`9OtC1Jx@ z%npCdmOza19lB%3V~Jb#j^*1SDDiv8U@6~E3L$mPmV}KHOFt>>*wJj+dksv7q&e~A zjvaOH;oZDtFUnYZm~frQMOHd;J+a{@Jo(`mLGdbn9_)ExgF9vt+l1!q0p6#Nz>;N9`sX!<`Q{AbV*L#sI z_!`f^DNQD*XW`>l?)XDZp=n+$%IQT~He6UF{7U#Q!69j_4k@<5A;q6?NIIuJLk}tt zmt8uQof*_gb7?X(^C&E73|0bQDSf!fWyJi@gnhSV$pe#E4v+U#AQYb&?1!hbJYdme zY36xlh{mGFuZXV&AYR1{4do>^nvY-k>^1EyN=Y>nsOZMoS@R0+x_4D*Eh|$I3ksoB z#9Ft=RK#K=DHX96#!p48Wef6z36zF7%U0_aKLxRtT;vTCDE)92vxNaw$X`3;FaIbn z6e!J{0Da|I*ezSeQ4WnWTebiOrNV^*r5PpPRtw{&92&c0M<8|!U_Q0u$+~S@wr->~ z?GR{96heSvOyU-6t|$IFG&3GU+v0b`Q(B3V^g|QqXpu}ui^k|^kxWO6C>`njbQC3- zhJrhzB+HO~UWQ9tX29b;6$mMGwBE%Ql;fdvv?EcWq}%+IM9V9smq_|W*QX{5Q=ufy zyd{zbxhOPBNdah+$7pGMzXIWj{ZnX7o+sbaKmEKI%n;hL5T$3g>T~q-k_RF|i;-;K zDLuXeUz8q|HfiSNp=}RXC_U14QHuPFOpz^ahHGvEujDcuTHr3mt_9cAfa_td<`6uo zh~XlG?d+_C&fQZnV{`O)6712_)aRq8Es<0?COiY+pON5?>ho9g44m7oQ;&l*;HW8N z(`S88J>pnB{}@-#KkU1wMVv>if89M*sjaw&D@KifUEC8>+;1~VhZonlzRIXtP{aU2;o|53hC^>$t5kG)T<9`yeI}Y6uxy)`t|kW zLWIa8H@Q4=-b8-X`}t_-!N?DHUlb#)g(`fX9o6$>?_!Z%<91Kdt^V&aF^OyM9VsQ9B0QvTz-vXM}gjs51 z`PMkA>K=(7Rb<`Nl%#u@E~Jde<

Qx>^te|8o#@@H;cx7@2#eF0=a># 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%0DLA_#~D^}D`aUj)cudB86S4FS0r6JX;x%5}V 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