├── .gitignore ├── .gitmodules ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── DebugStream.cpp ├── DebugStream.h ├── HybridDetect └── HybridDetect.h ├── LICENSE.txt ├── LibXPUInfo.cpp ├── LibXPUInfo.h ├── LibXPUInfo.sln ├── LibXPUInfo.vcxproj ├── LibXPUInfo.vcxproj.filters ├── LibXPUInfo_DXCore.cpp ├── LibXPUInfo_EXT_IGCL.cpp ├── LibXPUInfo_EXT_IGCL.h ├── LibXPUInfo_IGCL.cpp ├── LibXPUInfo_IPC.cpp ├── LibXPUInfo_IPC.h ├── LibXPUInfo_IntelDeviceInfoDX11.cpp ├── LibXPUInfo_JSON.cpp ├── LibXPUInfo_JSON.h ├── LibXPUInfo_L0.cpp ├── LibXPUInfo_Metal.h ├── LibXPUInfo_Metal.mm ├── LibXPUInfo_NVML.cpp ├── LibXPUInfo_OpenCL.cpp ├── LibXPUInfo_SetupAPI.cpp ├── LibXPUInfo_TelemetryTracker.cpp ├── LibXPUInfo_Util.cpp ├── LibXPUInfo_Util.h ├── LibXPUInfo_WMI.cpp ├── README.md ├── SECURITY.md ├── TestLibXPUInfo ├── TestLibXPUInfo.cpp ├── TestLibXPUInfo.vcxproj └── TestLibXPUInfo.vcxproj.filters ├── TestXPUInfoIPC ├── TestXPUInfoIPC.cpp ├── TestXPUInfoIPC.vcxproj ├── TestXPUInfoIPC.vcxproj.filters ├── TestXPUInfoIPC_Shared.h └── TestXPUInfoIPC_Shared │ ├── TestXPUInfoIPC_Shared.vcxproj │ └── TestXPUInfoIPC_Shared.vcxproj.filters ├── external ├── .gitignore ├── NVML │ └── README.txt ├── buildExternalDeps_L0.bat ├── buildExternalDeps_OCL.bat ├── getNVMLDep.bat ├── l0_CMakeLists.patch ├── l0_removeSpectre.bat └── setup_submodules.bat └── utility ├── LibXPUInfo_D3D12Utility.cpp └── LibXPUInfo_D3D12Utility.h /.gitignore: -------------------------------------------------------------------------------- 1 | .vs 2 | x64 3 | ARM64 4 | *.bak 5 | BuildExternalDeps/NVML 6 | BuildExternalDeps/NVML.zip 7 | *.vcxproj.user 8 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "external/rapidjson"] 2 | path = external/rapidjson 3 | url = https://github.com/Tencent/rapidjson.git 4 | [submodule "external/OpenCL-CLHPP"] 5 | path = external/OpenCL-CLHPP 6 | url = https://github.com/KhronosGroup/OpenCL-CLHPP.git 7 | [submodule "external/IGCL"] 8 | path = external/IGCL 9 | url = https://github.com/intel/drivers.gpu.control-library 10 | [submodule "external/level-zero"] 11 | path = external/level-zero 12 | url = https://github.com/oneapi-src/level-zero 13 | [submodule "external/OpenCL-Headers"] 14 | path = external/OpenCL-Headers 15 | url = https://github.com/KhronosGroup/OpenCL-Headers.git 16 | [submodule "external/OpenCL-ICD-Loader"] 17 | path = external/OpenCL-ICD-Loader 18 | url = https://github.com/KhronosGroup/OpenCL-ICD-Loader.git 19 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | We as members, contributors, and leaders pledge to make participation in our 6 | community a harassment-free experience for everyone, regardless of age, body 7 | size, visible or invisible disability, ethnicity, sex characteristics, gender 8 | identity and expression, level of experience, education, socio-economic status, 9 | nationality, personal appearance, race, caste, color, religion, or sexual 10 | identity and orientation. 11 | 12 | We pledge to act and interact in ways that contribute to an open, welcoming, 13 | diverse, inclusive, and healthy community. 14 | 15 | ## Our Standards 16 | 17 | Examples of behavior that contributes to a positive environment for our 18 | community include: 19 | 20 | * Demonstrating empathy and kindness toward other people 21 | * Being respectful of differing opinions, viewpoints, and experiences 22 | * Giving and gracefully accepting constructive feedback 23 | * Accepting responsibility and apologizing to those affected by our mistakes, 24 | and learning from the experience 25 | * Focusing on what is best not just for us as individuals, but for the overall 26 | community 27 | 28 | Examples of unacceptable behavior include: 29 | 30 | * The use of sexualized language or imagery, and sexual attention or advances of 31 | any kind 32 | * Trolling, insulting or derogatory comments, and personal or political attacks 33 | * Public or private harassment 34 | * Publishing others' private information, such as a physical or email address, 35 | without their explicit permission 36 | * Other conduct which could reasonably be considered inappropriate in a 37 | professional setting 38 | 39 | ## Enforcement Responsibilities 40 | 41 | Community leaders are responsible for clarifying and enforcing our standards of 42 | acceptable behavior and will take appropriate and fair corrective action in 43 | response to any behavior that they deem inappropriate, threatening, offensive, 44 | or harmful. 45 | 46 | Community leaders have the right and responsibility to remove, edit, or reject 47 | comments, commits, code, wiki edits, issues, and other contributions that are 48 | not aligned to this Code of Conduct, and will communicate reasons for moderation 49 | decisions when appropriate. 50 | 51 | ## Scope 52 | 53 | This Code of Conduct applies within all community spaces, and also applies when 54 | an individual is officially representing the community in public spaces. 55 | Examples of representing our community include using an official e-mail address, 56 | posting via an official social media account, or acting as an appointed 57 | representative at an online or offline event. 58 | 59 | ## Enforcement 60 | 61 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 62 | reported to the community leaders responsible for enforcement at 63 | CommunityCodeOfConduct AT intel DOT com. 64 | All complaints will be reviewed and investigated promptly and fairly. 65 | 66 | All community leaders are obligated to respect the privacy and security of the 67 | reporter of any incident. 68 | 69 | ## Enforcement Guidelines 70 | 71 | Community leaders will follow these Community Impact Guidelines in determining 72 | the consequences for any action they deem in violation of this Code of Conduct: 73 | 74 | ### 1. Correction 75 | 76 | **Community Impact**: Use of inappropriate language or other behavior deemed 77 | unprofessional or unwelcome in the community. 78 | 79 | **Consequence**: A private, written warning from community leaders, providing 80 | clarity around the nature of the violation and an explanation of why the 81 | behavior was inappropriate. A public apology may be requested. 82 | 83 | ### 2. Warning 84 | 85 | **Community Impact**: A violation through a single incident or series of 86 | actions. 87 | 88 | **Consequence**: A warning with consequences for continued behavior. No 89 | interaction with the people involved, including unsolicited interaction with 90 | those enforcing the Code of Conduct, for a specified period of time. This 91 | includes avoiding interactions in community spaces as well as external channels 92 | like social media. Violating these terms may lead to a temporary or permanent 93 | ban. 94 | 95 | ### 3. Temporary Ban 96 | 97 | **Community Impact**: A serious violation of community standards, including 98 | sustained inappropriate behavior. 99 | 100 | **Consequence**: A temporary ban from any sort of interaction or public 101 | communication with the community for a specified period of time. No public or 102 | private interaction with the people involved, including unsolicited interaction 103 | with those enforcing the Code of Conduct, is allowed during this period. 104 | Violating these terms may lead to a permanent ban. 105 | 106 | ### 4. Permanent Ban 107 | 108 | **Community Impact**: Demonstrating a pattern of violation of community 109 | standards, including sustained inappropriate behavior, harassment of an 110 | individual, or aggression toward or disparagement of classes of individuals. 111 | 112 | **Consequence**: A permanent ban from any sort of public interaction within the 113 | community. 114 | 115 | ## Attribution 116 | 117 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], 118 | version 2.1, available at 119 | [https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1]. 120 | 121 | Community Impact Guidelines were inspired by 122 | [Mozilla's code of conduct enforcement ladder][Mozilla CoC]. 123 | 124 | For answers to common questions about this code of conduct, see the FAQ at 125 | [https://www.contributor-covenant.org/faq][FAQ]. Translations are available at 126 | [https://www.contributor-covenant.org/translations][translations]. 127 | 128 | [homepage]: https://www.contributor-covenant.org 129 | [v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html 130 | [Mozilla CoC]: https://github.com/mozilla/diversity 131 | [FAQ]: https://www.contributor-covenant.org/faq 132 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | ### License 4 | 5 | is licensed under the terms in [LICENSE]. By contributing to the project, you agree to the license and copyright terms therein and release your contribution under these terms. 6 | 7 | ### Sign your work 8 | 9 | Please use the sign-off line at the end of the patch. Your signature certifies that you wrote the patch or otherwise have the right to pass it on as an open-source patch. The rules are pretty simple: if you can certify 10 | the below (from [developercertificate.org](http://developercertificate.org/)): 11 | 12 | ``` 13 | Developer Certificate of Origin 14 | Version 1.1 15 | 16 | Copyright (C) 2004, 2006 The Linux Foundation and its contributors. 17 | 660 York Street, Suite 102, 18 | San Francisco, CA 94110 USA 19 | 20 | Everyone is permitted to copy and distribute verbatim copies of this 21 | license document, but changing it is not allowed. 22 | 23 | Developer's Certificate of Origin 1.1 24 | 25 | By making a contribution to this project, I certify that: 26 | 27 | (a) The contribution was created in whole or in part by me and I 28 | have the right to submit it under the open source license 29 | indicated in the file; or 30 | 31 | (b) The contribution is based upon previous work that, to the best 32 | of my knowledge, is covered under an appropriate open source 33 | license and I have the right under that license to submit that 34 | work with modifications, whether created in whole or in part 35 | by me, under the same open source license (unless I am 36 | permitted to submit under a different license), as indicated 37 | in the file; or 38 | 39 | (c) The contribution was provided directly to me by some other 40 | person who certified (a), (b) or (c) and I have not modified 41 | it. 42 | 43 | (d) I understand and agree that this project and the contribution 44 | are public and that a record of the contribution (including all 45 | personal information I submit with it, including my sign-off) is 46 | maintained indefinitely and may be redistributed consistent with 47 | this project or the open source license(s) involved. 48 | ``` 49 | 50 | Then you just add a line to every git commit message: 51 | 52 | Signed-off-by: Joe Smith 53 | 54 | Use your real name (sorry, no pseudonyms or anonymous contributions.) 55 | 56 | If you set your `user.name` and `user.email` git configs, you can sign your 57 | commit automatically with `git commit -s`. 58 | -------------------------------------------------------------------------------- /DebugStream.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2024 Intel Corporation 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | // A simple mechanism to send debug messages to the debugger or the console 5 | 6 | #include "DebugStream.h" 7 | 8 | #ifdef _WIN32 9 | #ifndef _WIN32_WINNT 10 | #define _WIN32_WINNT 0x501 // WinXP or greater 11 | #endif 12 | #include 13 | 14 | #if (_WIN32_WINNT < 0x501) 15 | #error("Must set _WIN32_WINNT >= 0x501") 16 | #endif 17 | #endif // _WIN32 18 | 19 | namespace XI 20 | { 21 | void DebugStream::OutputToDebugger() noexcept 22 | { 23 | #if !DISABLE_DEBUGSTREAM 24 | try 25 | { 26 | #ifdef _WIN32 27 | if (IsDebuggerPresent()) 28 | { 29 | OutputDebugStringA(str().c_str()); 30 | } 31 | else 32 | #elif defined(__APPLE__) 33 | if (1) 34 | { 35 | std::cerr << str().c_str(); 36 | } 37 | else 38 | #endif 39 | 40 | if (bPrintAlways_) 41 | { 42 | std::cout << str().c_str(); 43 | } 44 | #ifndef __APPLE__ 45 | clear(); 46 | #endif 47 | } 48 | catch (...) 49 | { 50 | } 51 | #endif // DISABLE_DEBUGSTREAM 52 | } 53 | 54 | DebugStream::DebugStream(bool bPrintAlways) 55 | : bPrintAlways_(bPrintAlways) 56 | { 57 | } 58 | 59 | DebugStream::~DebugStream() 60 | { 61 | OutputToDebugger(); 62 | } 63 | 64 | 65 | void DebugStreamW::OutputToDebugger() noexcept 66 | { 67 | #if !DISABLE_DEBUGSTREAM 68 | try 69 | { 70 | #ifdef _WIN32 71 | if (IsDebuggerPresent()) 72 | { 73 | OutputDebugStringW(str().c_str()); 74 | } 75 | else 76 | #elif defined(__APPLE__) 77 | if (1) 78 | { 79 | std::cerr << str().c_str(); 80 | } 81 | else 82 | #endif 83 | 84 | if (bPrintAlways_) 85 | { 86 | std::wcout << str().c_str(); 87 | } 88 | #ifndef __APPLE__ 89 | clear(); 90 | #endif 91 | } 92 | catch (...) 93 | { 94 | } 95 | #endif // DISABLE_DEBUGSTREAM 96 | } 97 | 98 | DebugStreamW::DebugStreamW(bool bPrintAlways) 99 | : bPrintAlways_(bPrintAlways) 100 | { 101 | } 102 | 103 | DebugStreamW::~DebugStreamW() 104 | { 105 | OutputToDebugger(); 106 | } 107 | 108 | } // XI 109 | -------------------------------------------------------------------------------- /DebugStream.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2024 Intel Corporation 2 | // SPDX-License-Identifier: Apache-2.0 3 | // These contents may have been developed with support from one or more Intel-operated generative artificial intelligence solutions 4 | 5 | // A simple mechanism to send debug messages to the debugger or the console 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | #ifndef DEBUGSTREAM_DEFAULT_PRINT 14 | #define DEBUGSTREAM_DEFAULT_PRINT false 15 | #endif 16 | 17 | namespace XI 18 | { 19 | #ifndef DISABLE_DEBUGSTREAM 20 | #define DISABLE_DEBUGSTREAM 0 21 | #endif 22 | 23 | #if DISABLE_DEBUGSTREAM 24 | // Copilot: create class based on std::ostream that does nothing 25 | class NullBuffer : public std::streambuf { 26 | protected: 27 | // Override the overflow function to discard output 28 | int overflow(int c) override { 29 | return c; 30 | } 31 | }; 32 | class NullBufferW : public std::wstreambuf { 33 | protected: 34 | // Override the overflow function to discard output 35 | std::wstreambuf::int_type overflow(std::wstreambuf::int_type c) override { 36 | return c; 37 | } 38 | }; 39 | 40 | class NullOStream : public std::ostream { 41 | public: 42 | NullOStream() : std::ostream(&nullBuffer) {} 43 | 44 | private: 45 | NullBuffer nullBuffer; 46 | }; 47 | 48 | class NullOStreamW : public std::wostream { 49 | public: 50 | NullOStreamW() : std::wostream(&nullBuffer) {} 51 | 52 | private: 53 | NullBufferW nullBuffer; 54 | }; 55 | #endif 56 | 57 | class DebugStream 58 | #if !DISABLE_DEBUGSTREAM 59 | :public std::ostringstream 60 | #else 61 | :public NullOStream 62 | #endif 63 | { 64 | public: 65 | // false or default constructor prints only to debugger when present, true prints to stdout if no debugger 66 | DebugStream(bool bPrintAlways=DEBUGSTREAM_DEFAULT_PRINT); 67 | ~DebugStream(); 68 | DebugStream(const DebugStream&) = delete; 69 | DebugStream& operator=(const DebugStream&) = delete; 70 | 71 | void OutputToDebugger() noexcept; 72 | 73 | private: 74 | bool bPrintAlways_; 75 | }; 76 | 77 | class DebugStreamW 78 | #if !DISABLE_DEBUGSTREAM 79 | :public std::wostringstream 80 | #else 81 | : public NullOStreamW 82 | #endif 83 | { 84 | public: 85 | DebugStreamW(bool bPrintAlways = DEBUGSTREAM_DEFAULT_PRINT); 86 | ~DebugStreamW(); 87 | DebugStreamW(const DebugStreamW&) = delete; 88 | DebugStreamW& operator=(const DebugStreamW&) = delete; 89 | 90 | void OutputToDebugger() noexcept; 91 | 92 | private: 93 | bool bPrintAlways_; 94 | }; 95 | 96 | #ifdef UNICODE 97 | using DebugStreamT = DebugStreamW; 98 | #else 99 | using DebugStreamT = DebugStream; 100 | #endif 101 | 102 | } // XI 103 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /LibXPUInfo.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.2.32526.322 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LibXPUInfo", "LibXPUInfo.vcxproj", "{A6C0F0AD-8176-44EA-AEEC-632385D0FA2A}" 7 | EndProject 8 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TestLibXPUInfo", "TestLibXPUInfo\TestLibXPUInfo.vcxproj", "{A1FE53C4-2ABE-48B4-8222-BB55E6CF98F1}" 9 | ProjectSection(ProjectDependencies) = postProject 10 | {A6C0F0AD-8176-44EA-AEEC-632385D0FA2A} = {A6C0F0AD-8176-44EA-AEEC-632385D0FA2A} 11 | EndProjectSection 12 | EndProject 13 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "XPUInfoIPC", "TestXPUInfoIPC\TestXPUInfoIPC.vcxproj", "{7C4FE0E5-0FE3-42C7-9147-2976B55D022C}" 14 | ProjectSection(ProjectDependencies) = postProject 15 | {4E2CB0FC-040A-4DBD-A20F-915C5590DCFF} = {4E2CB0FC-040A-4DBD-A20F-915C5590DCFF} 16 | {A6C0F0AD-8176-44EA-AEEC-632385D0FA2A} = {A6C0F0AD-8176-44EA-AEEC-632385D0FA2A} 17 | EndProjectSection 18 | EndProject 19 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TestXPUInfoIPC_Shared", "TestXPUInfoIPC\TestXPUInfoIPC_Shared\TestXPUInfoIPC_Shared.vcxproj", "{4E2CB0FC-040A-4DBD-A20F-915C5590DCFF}" 20 | ProjectSection(ProjectDependencies) = postProject 21 | {A6C0F0AD-8176-44EA-AEEC-632385D0FA2A} = {A6C0F0AD-8176-44EA-AEEC-632385D0FA2A} 22 | EndProjectSection 23 | EndProject 24 | Global 25 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 26 | Debug|x64 = Debug|x64 27 | DebugDynamic|x64 = DebugDynamic|x64 28 | Release|x64 = Release|x64 29 | ReleaseDynamic|x64 = ReleaseDynamic|x64 30 | EndGlobalSection 31 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 32 | {A6C0F0AD-8176-44EA-AEEC-632385D0FA2A}.Debug|x64.ActiveCfg = Debug|x64 33 | {A6C0F0AD-8176-44EA-AEEC-632385D0FA2A}.Debug|x64.Build.0 = Debug|x64 34 | {A6C0F0AD-8176-44EA-AEEC-632385D0FA2A}.DebugDynamic|x64.ActiveCfg = DebugDynamic|x64 35 | {A6C0F0AD-8176-44EA-AEEC-632385D0FA2A}.DebugDynamic|x64.Build.0 = DebugDynamic|x64 36 | {A6C0F0AD-8176-44EA-AEEC-632385D0FA2A}.Release|x64.ActiveCfg = Release|x64 37 | {A6C0F0AD-8176-44EA-AEEC-632385D0FA2A}.Release|x64.Build.0 = Release|x64 38 | {A6C0F0AD-8176-44EA-AEEC-632385D0FA2A}.ReleaseDynamic|x64.ActiveCfg = ReleaseDynamic|x64 39 | {A6C0F0AD-8176-44EA-AEEC-632385D0FA2A}.ReleaseDynamic|x64.Build.0 = ReleaseDynamic|x64 40 | {A1FE53C4-2ABE-48B4-8222-BB55E6CF98F1}.Debug|x64.ActiveCfg = Debug|x64 41 | {A1FE53C4-2ABE-48B4-8222-BB55E6CF98F1}.Debug|x64.Build.0 = Debug|x64 42 | {A1FE53C4-2ABE-48B4-8222-BB55E6CF98F1}.DebugDynamic|x64.ActiveCfg = DebugDynamic|x64 43 | {A1FE53C4-2ABE-48B4-8222-BB55E6CF98F1}.DebugDynamic|x64.Build.0 = DebugDynamic|x64 44 | {A1FE53C4-2ABE-48B4-8222-BB55E6CF98F1}.Release|x64.ActiveCfg = Release|x64 45 | {A1FE53C4-2ABE-48B4-8222-BB55E6CF98F1}.Release|x64.Build.0 = Release|x64 46 | {A1FE53C4-2ABE-48B4-8222-BB55E6CF98F1}.ReleaseDynamic|x64.ActiveCfg = ReleaseDynamic|x64 47 | {A1FE53C4-2ABE-48B4-8222-BB55E6CF98F1}.ReleaseDynamic|x64.Build.0 = ReleaseDynamic|x64 48 | {7C4FE0E5-0FE3-42C7-9147-2976B55D022C}.Debug|x64.ActiveCfg = Debug|x64 49 | {7C4FE0E5-0FE3-42C7-9147-2976B55D022C}.Debug|x64.Build.0 = Debug|x64 50 | {7C4FE0E5-0FE3-42C7-9147-2976B55D022C}.DebugDynamic|x64.ActiveCfg = DebugDynamic|x64 51 | {7C4FE0E5-0FE3-42C7-9147-2976B55D022C}.DebugDynamic|x64.Build.0 = DebugDynamic|x64 52 | {7C4FE0E5-0FE3-42C7-9147-2976B55D022C}.Release|x64.ActiveCfg = Release|x64 53 | {7C4FE0E5-0FE3-42C7-9147-2976B55D022C}.Release|x64.Build.0 = Release|x64 54 | {7C4FE0E5-0FE3-42C7-9147-2976B55D022C}.ReleaseDynamic|x64.ActiveCfg = ReleaseDynamic|x64 55 | {7C4FE0E5-0FE3-42C7-9147-2976B55D022C}.ReleaseDynamic|x64.Build.0 = ReleaseDynamic|x64 56 | {4E2CB0FC-040A-4DBD-A20F-915C5590DCFF}.Debug|x64.ActiveCfg = Debug|x64 57 | {4E2CB0FC-040A-4DBD-A20F-915C5590DCFF}.Debug|x64.Build.0 = Debug|x64 58 | {4E2CB0FC-040A-4DBD-A20F-915C5590DCFF}.DebugDynamic|x64.ActiveCfg = DebugDynamic|x64 59 | {4E2CB0FC-040A-4DBD-A20F-915C5590DCFF}.DebugDynamic|x64.Build.0 = DebugDynamic|x64 60 | {4E2CB0FC-040A-4DBD-A20F-915C5590DCFF}.Release|x64.ActiveCfg = Release|x64 61 | {4E2CB0FC-040A-4DBD-A20F-915C5590DCFF}.Release|x64.Build.0 = Release|x64 62 | {4E2CB0FC-040A-4DBD-A20F-915C5590DCFF}.ReleaseDynamic|x64.ActiveCfg = ReleaseDynamic|x64 63 | {4E2CB0FC-040A-4DBD-A20F-915C5590DCFF}.ReleaseDynamic|x64.Build.0 = ReleaseDynamic|x64 64 | EndGlobalSection 65 | GlobalSection(SolutionProperties) = preSolution 66 | HideSolutionNode = FALSE 67 | EndGlobalSection 68 | GlobalSection(ExtensibilityGlobals) = postSolution 69 | SolutionGuid = {F2E1AFAC-F41A-4D13-A17C-FC26C0048486} 70 | EndGlobalSection 71 | EndGlobal 72 | -------------------------------------------------------------------------------- /LibXPUInfo.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | {06105fd3-9824-4222-960a-553cb0dbbe91} 18 | 19 | 20 | {b16fb5e7-45db-40ed-ab60-417d71c8dc8b} 21 | 22 | 23 | 24 | 25 | Header Files 26 | 27 | 28 | Header Files 29 | 30 | 31 | Header Files 32 | 33 | 34 | Header Files 35 | 36 | 37 | Header Files 38 | 39 | 40 | NVML 41 | 42 | 43 | Header Files 44 | 45 | 46 | Header Files 47 | 48 | 49 | IGCL 50 | 51 | 52 | 53 | 54 | Source Files 55 | 56 | 57 | Source Files 58 | 59 | 60 | IGCL 61 | 62 | 63 | Source Files 64 | 65 | 66 | Source Files 67 | 68 | 69 | Source Files 70 | 71 | 72 | Source Files 73 | 74 | 75 | Source Files 76 | 77 | 78 | Source Files 79 | 80 | 81 | Source Files 82 | 83 | 84 | Source Files 85 | 86 | 87 | Source Files 88 | 89 | 90 | Source Files 91 | 92 | 93 | Source Files 94 | 95 | 96 | Source Files 97 | 98 | 99 | IGCL 100 | 101 | 102 | -------------------------------------------------------------------------------- /LibXPUInfo_EXT_IGCL.cpp: -------------------------------------------------------------------------------- 1 | #ifdef XPUINFO_USE_IGCL 2 | 3 | #include "LibXPUInfo_EXT_IGCL.h" 4 | 5 | namespace XI 6 | { 7 | // IGCL 8 | IGCLAdapterProperties::IGCLAdapterProperties() : 9 | ctl_device_adapter_properties_t{ 0 } 10 | { 11 | Size = sizeof(ctl_device_adapter_properties_t); 12 | pDeviceID = malloc(sizeof(LUID)); 13 | device_id_size = sizeof(LUID); 14 | }; 15 | IGCLAdapterProperties::~IGCLAdapterProperties() 16 | { 17 | if (pDeviceID) 18 | free(pDeviceID); 19 | } 20 | IGCLPciProperties::IGCLPciProperties() : 21 | ctl_pci_properties_t{ 0 }, InitialPCIState{ 0 } 22 | { 23 | Size = sizeof(ctl_pci_properties_t); 24 | maxSpeed.Size = sizeof(ctl_pci_speed_t); 25 | InitialPCIState.Size = sizeof(ctl_pci_state_t); 26 | InitialPCIState.speed.Size = sizeof(ctl_pci_speed_t); 27 | } 28 | } 29 | 30 | #endif // XPUINFO_USE_IGCL 31 | -------------------------------------------------------------------------------- /LibXPUInfo_EXT_IGCL.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2024 Intel Corporation 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | #pragma once 5 | 6 | #include "LibXPUInfo.h" 7 | #include "igcl_api.h" 8 | 9 | namespace XI 10 | { 11 | // IGCL 12 | struct IGCLAdapterProperties : ctl_device_adapter_properties_t, NoCopyAssign 13 | { 14 | IGCLAdapterProperties(); 15 | ~IGCLAdapterProperties(); 16 | }; 17 | struct IGCLPciProperties : ctl_pci_properties_t 18 | { 19 | ctl_pci_state_t InitialPCIState; 20 | IGCLPciProperties(); 21 | }; 22 | } 23 | -------------------------------------------------------------------------------- /LibXPUInfo_IPC.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2024 Intel Corporation 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | // Utility code for using XPUInfo out-of-process 5 | #ifdef XPUINFO_USE_IPC 6 | #include "LibXPUInfo_IPC.h" 7 | #define OPEN_FILE_MAPPING_ERROR ((DWORD)0xC00007D0L) 8 | #define UNABLE_MAP_VIEW_OF_FILE ((DWORD)0xC00007D1L) 9 | 10 | namespace XI 11 | { 12 | #ifdef _WIN32 13 | namespace Win 14 | { 15 | 16 | ProcessInformation::~ProcessInformation() 17 | { 18 | if (hProcess) 19 | { 20 | CloseHandle(hProcess); 21 | } 22 | if (hThread) 23 | { 24 | CloseHandle(hThread); 25 | } 26 | } 27 | 28 | NamedEvent::NamedEvent(const char* sharedName) 29 | { 30 | m_hEvent = CreateEventA(nullptr, FALSE, FALSE, sharedName); 31 | XPUINFO_REQUIRE(m_hEvent); 32 | } 33 | 34 | NamedMutex::NamedMutex(const char* sharedName) 35 | { 36 | m_hMutex = CreateMutexA(nullptr, FALSE, sharedName); 37 | m_CreateError = GetLastError(); 38 | XPUINFO_REQUIRE(m_hMutex); 39 | } 40 | 41 | NamedMutex::ScopedLock::ScopedLock(NamedMutex& m, UI32 timeout, UI32* pResult) 42 | : 43 | m_Mutex(m), m_pOutResult(pResult) 44 | { 45 | m_Result = WaitForSingleObject(m.m_hMutex, timeout); 46 | if (m_pOutResult) 47 | { 48 | *m_pOutResult = m_Result; 49 | } 50 | } 51 | 52 | NamedSemaphore::NamedSemaphore(const char* name, const I32 initialCount) 53 | { 54 | m_hSem = CreateSemaphoreA(nullptr, initialCount, initialCount, name); 55 | m_CreateError = GetLastError(); 56 | } 57 | 58 | NamedSemaphore::ScopedAcquire::ScopedAcquire(NamedSemaphore& sem, UI32 timeout) : 59 | m_sem(sem) 60 | { 61 | m_Result = WaitForSingleObject(sem.m_hSem, timeout); 62 | } 63 | 64 | NamedSemaphore::ScopedAcquire::~ScopedAcquire() 65 | { 66 | if (m_Result == WAIT_OBJECT_0) 67 | { 68 | UI32 res = ReleaseSemaphore(m_sem.m_hSem, 1, nullptr); 69 | XPUINFO_REQUIRE(res); 70 | } 71 | } 72 | 73 | NamedSharedMemory::NamedSharedMemory(size_t size, const char* sharedName, bool bReadOnlyAccess) : 74 | m_Size(size), 75 | m_hMutex((std::string(sharedName) + "_MUTEX").c_str()) 76 | { 77 | static_assert(sizeof(size_t) == 8, "Assuming 64-bit"); 78 | m_hSharedMemory = CreateFileMappingA( 79 | (HANDLE)INVALID_HANDLE_VALUE, 80 | nullptr, // no security 81 | PAGE_READWRITE, // to allow read & write access 82 | (DWORD)(size >> 32), 83 | (DWORD)size, // file size 84 | sharedName); // object name 85 | 86 | DWORD MemStatus = GetLastError(); // to see if this is the first opening 87 | if (m_hSharedMemory == nullptr) 88 | { 89 | m_Status = OPEN_FILE_MAPPING_ERROR; 90 | // this is fatal, if we can't get data then there's no 91 | // point in continuing. 92 | } 93 | else 94 | { 95 | NamedMutex::ScopedLock lock(m_hMutex); 96 | if (MemStatus != ERROR_ALREADY_EXISTS) 97 | { 98 | // this is the first access to the file so initialize the 99 | // instance count 100 | m_pMappedMemory = MapViewOfFile( 101 | m_hSharedMemory, // shared mem handle 102 | FILE_MAP_WRITE, // access desired 103 | 0, // starting offset 104 | 0, 105 | 0); // map the entire object 106 | if (m_pMappedMemory != nullptr) 107 | { 108 | // if here, then pdwInstanceCount should be valid 109 | // so initialize the shared memory structure 110 | // clear memory block 111 | memset(m_pMappedMemory, 0, size); 112 | 113 | m_Status = ERROR_SUCCESS; 114 | } 115 | else 116 | { 117 | m_Status = UNABLE_MAP_VIEW_OF_FILE; 118 | } 119 | } 120 | else 121 | { 122 | // the status is ERROR_ALREADY_EXISTS which is successful 123 | m_Status = ERROR_SUCCESS; 124 | } 125 | // see if Read Only access is required 126 | if (m_Status == ERROR_SUCCESS) 127 | { 128 | // by now the shared memory has already been initialized so 129 | // we if we don't need write access any more or if it has 130 | // already been opened, then open with the desired access 131 | m_pMappedMemory = MapViewOfFile( 132 | m_hSharedMemory, // shared mem handle 133 | (bReadOnlyAccess ? FILE_MAP_READ : 134 | FILE_MAP_WRITE), // access desired 135 | 0, // starting offset 136 | 0, 137 | 0); // map the entire object 138 | if (m_pMappedMemory == nullptr) 139 | { 140 | m_Status = UNABLE_MAP_VIEW_OF_FILE; 141 | // this is fatal, if we can't get data then there's no 142 | // point in continuing. 143 | } 144 | else 145 | { 146 | m_Status = ERROR_SUCCESS; 147 | } 148 | } 149 | } 150 | } 151 | 152 | NamedSharedMemory::~NamedSharedMemory() 153 | { 154 | if (ERROR_SUCCESS == m_Status) 155 | { 156 | if (m_pMappedMemory) 157 | { 158 | XPUINFO_REQUIRE(UnmapViewOfFile(m_pMappedMemory)); 159 | } 160 | if (m_hSharedMemory) 161 | { 162 | XPUINFO_REQUIRE(CloseHandle(m_hSharedMemory)); 163 | } 164 | } 165 | } 166 | 167 | NamedPipe::NamedPipe(const String& pipeName, // Must have format "\\\\.\\pipe\\Name" 168 | const String& mutexName, // Must NOT begin with "\\\\.\\pipe" 169 | size_t bufferSize, 170 | bool isServer) : m_bServer(isServer), 171 | m_bufferSize(bufferSize), 172 | m_Mutex(mutexName.c_str()) 173 | { 174 | XPUINFO_REQUIRE(m_bufferSize && (m_bufferSize < 0x100000000ULL)); // Check for 32-bit-safe size 175 | if (!m_bServer) 176 | { 177 | // Client-scope lock used to prevent server exit before client completes 178 | m_pLock.reset(new NamedMutex::ScopedLock(m_Mutex)); 179 | m_hPipe = CreateFileA(pipeName.c_str(), 180 | GENERIC_READ | GENERIC_WRITE, 181 | 0, 182 | nullptr, 183 | OPEN_EXISTING, 184 | 0, 185 | nullptr); 186 | } 187 | else 188 | { 189 | // Create pipe 190 | m_hPipe = CreateNamedPipeA(pipeName.c_str(), 191 | PIPE_ACCESS_DUPLEX, 192 | PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, 193 | 1, // Single instance 194 | (DWORD)bufferSize, 195 | (DWORD)bufferSize, 196 | PIPE_WAIT, 197 | nullptr); 198 | } 199 | } 200 | 201 | bool NamedPipe::Connect() 202 | { 203 | if (!Valid()) 204 | { 205 | return false; 206 | } 207 | if (!m_bConnected) 208 | { 209 | bool bRet = ConnectNamedPipe(m_hPipe, nullptr) ? 210 | TRUE : (GetLastError() == ERROR_PIPE_CONNECTED); 211 | m_bConnected = bRet; 212 | return bRet; 213 | } 214 | else 215 | { 216 | return true; 217 | } 218 | } 219 | 220 | bool NamedPipe::Disconnect() 221 | { 222 | if (m_bConnected && m_bServer) 223 | { 224 | NamedMutex::ScopedLock lock(m_Mutex); // Client must be done first 225 | bool bRet = !!DisconnectNamedPipe(m_hPipe); 226 | m_bConnected = false; // Play it safe if disconnect failed 227 | return bRet; 228 | } 229 | else 230 | { 231 | return true; 232 | } 233 | } 234 | 235 | } // Win 236 | #endif 237 | } // XI 238 | #endif //XPUINFO_USE_IPC 239 | -------------------------------------------------------------------------------- /LibXPUInfo_IPC.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2024 Intel Corporation 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | // Utility code for using XPUInfo out-of-process via Inter-Process Communication (IPC) 5 | // 6 | // NOTE: These IPC classes are intended to provide some improved readability, structure, 7 | // and exception-safety over plain C calling the OS-provided IPC APIs directly. It is the 8 | // APPLICATION'S responsibility to implement IPC in a way that is free of race conditions, 9 | // deadlocks, etc. 10 | 11 | #pragma once 12 | #ifdef XPUINFO_USE_IPC 13 | #include "LibXPUInfo.h" 14 | #ifdef _WIN32 15 | #include 16 | #endif 17 | 18 | #pragma warning(push) 19 | #pragma warning(disable : 4251) 20 | 21 | namespace XI 22 | { 23 | #ifdef _WIN32 24 | namespace Win 25 | { 26 | // Wrapper for use with CreateProcess 27 | class XPUINFO_EXPORT ProcessInformation : public PROCESS_INFORMATION, NoCopyAssign 28 | { 29 | public: 30 | ProcessInformation() : PROCESS_INFORMATION{} {} // zero-initialize 31 | ~ProcessInformation(); // Close non-zero handles 32 | }; 33 | 34 | class XPUINFO_EXPORT NamedEvent: public NoCopyAssign 35 | { 36 | public: 37 | NamedEvent(const char* sharedName); 38 | 39 | void Set() 40 | { 41 | SetEvent(m_hEvent); 42 | } 43 | UI32 Wait(UI32 timeout = INFINITE) 44 | { 45 | return WaitForSingleObject(m_hEvent, timeout); 46 | } 47 | ~NamedEvent() 48 | { 49 | if (m_hEvent) 50 | { 51 | CloseHandle(m_hEvent); 52 | } 53 | } 54 | protected: 55 | HANDLE m_hEvent; 56 | }; 57 | 58 | class XPUINFO_EXPORT NamedMutex : public NoCopyAssign 59 | { 60 | public: 61 | NamedMutex(const char* sharedName); 62 | ~NamedMutex() 63 | { 64 | if (m_hMutex) 65 | { 66 | CloseHandle(m_hMutex); 67 | } 68 | } 69 | 70 | class ScopedLock : public NoCopyAssign 71 | { 72 | public: 73 | ScopedLock(NamedMutex& m, UI32 timeout = INFINITE, UI32* pResult = nullptr); 74 | ~ScopedLock() 75 | { 76 | if (m_Result != WAIT_FAILED) 77 | { 78 | ReleaseMutex(m_Mutex.m_hMutex); 79 | } 80 | } 81 | 82 | protected: 83 | NamedMutex& m_Mutex; 84 | UI32 m_Result; 85 | UI32* m_pOutResult; 86 | }; 87 | friend class ScopedLock; 88 | protected: 89 | HANDLE m_hMutex; 90 | UI32 m_CreateError; 91 | }; 92 | 93 | class XPUINFO_EXPORT NamedSemaphore : public NoCopyAssign 94 | { 95 | public: 96 | NamedSemaphore(const char* name, const I32 initialCount); 97 | ~NamedSemaphore() 98 | { 99 | if (m_hSem) 100 | { 101 | CloseHandle(m_hSem); 102 | } 103 | } 104 | 105 | friend class ScopedAcquire; 106 | class ScopedAcquire 107 | { 108 | public: 109 | ScopedAcquire(NamedSemaphore& sem, UI32 timeout = INFINITE); 110 | ~ScopedAcquire(); 111 | protected: 112 | NamedSemaphore& m_sem; 113 | UI32 m_Result; 114 | }; 115 | protected: 116 | HANDLE m_hSem; 117 | UI32 m_CreateError; 118 | }; 119 | 120 | class XPUINFO_EXPORT NamedSharedMemory : public NoCopyAssign 121 | { 122 | public: 123 | NamedSharedMemory(size_t size, const char* sharedName, bool bReadOnlyAccess = false); 124 | ~NamedSharedMemory(); 125 | 126 | UI32 getStatus() const { return m_Status; } 127 | NamedMutex& getMutex() { return m_hMutex; } 128 | void* getSharedMemPtr() { 129 | XPUINFO_REQUIRE(m_pMappedMemory); 130 | return m_pMappedMemory; 131 | } 132 | size_t size() const { return m_Size; } 133 | 134 | protected: 135 | const size_t m_Size; 136 | HANDLE m_hSharedMemory; 137 | NamedMutex m_hMutex; 138 | void* m_pMappedMemory = nullptr; 139 | UI32 m_Status = UI32(-1); 140 | }; 141 | 142 | class XPUINFO_EXPORT NamedPipe : public NoCopyAssign 143 | { 144 | public: 145 | NamedPipe(const String& pipeName, // Must have format "\\\\.\\pipe\\Name" 146 | const String& mutexName, // Must NOT begin with "\\\\.\\pipe" 147 | size_t bufferSize, 148 | bool isServer = false); 149 | ~NamedPipe() 150 | { 151 | if (Valid()) 152 | { 153 | XPUINFO_REQUIRE(Disconnect()); 154 | XPUINFO_REQUIRE(CloseHandle(m_hPipe)); 155 | } 156 | } 157 | 158 | bool Valid() const { return (m_hPipe != INVALID_HANDLE_VALUE) && (m_hPipe != 0); } 159 | bool Connected() const { return Valid() && (!m_bServer || m_bConnected); } 160 | 161 | bool Connect(); 162 | bool Disconnect(); 163 | 164 | template 165 | bool Read(T& value) 166 | { 167 | XPUINFO_REQUIRE(Connected()); 168 | DWORD bytesRead = 0; 169 | return ((ReadFile(m_hPipe, &value, sizeof(value), &bytesRead, nullptr) != FALSE) && 170 | (bytesRead == sizeof(value))); 171 | } 172 | template <> 173 | bool Read(String& outString) 174 | { 175 | XPUINFO_REQUIRE(Connected()); 176 | outString.resize(m_bufferSize); 177 | DWORD bytesRead = 0; 178 | BOOL bRet = ReadFile(m_hPipe, outString.data(), (DWORD)outString.size(), &bytesRead, nullptr); 179 | outString[std::min(bytesRead, DWORD(m_bufferSize - 1))] = 0; // Just in case 180 | outString.resize(bytesRead); 181 | return !!bRet; 182 | } 183 | template 184 | bool Write(const T& value) 185 | { 186 | XPUINFO_REQUIRE(Connected()); 187 | DWORD bytesWritten = 0; 188 | return ((WriteFile(m_hPipe, &value, sizeof(value), &bytesWritten, nullptr) != FALSE) && 189 | (bytesWritten == sizeof(value))); 190 | } 191 | template <> 192 | bool Write(const String& inString) 193 | { 194 | XPUINFO_REQUIRE(Connected()); 195 | DWORD bytesWritten = 0; 196 | BOOL bRet = WriteFile(m_hPipe, inString.data(), 197 | (DWORD)std::min(inString.length(), m_bufferSize), 198 | &bytesWritten, nullptr); 199 | return bRet && (bytesWritten == inString.length()); // Error if string longer than buffer 200 | } 201 | protected: 202 | HANDLE m_hPipe; 203 | bool m_bConnected = false; 204 | const bool m_bServer; 205 | const size_t m_bufferSize; 206 | NamedMutex m_Mutex; 207 | std::unique_ptr m_pLock; 208 | }; 209 | } // Win 210 | #endif // _WIN32 211 | } // XI 212 | 213 | #pragma warning(pop) 214 | 215 | #endif // XPUINFO_USE_IPC 216 | -------------------------------------------------------------------------------- /LibXPUInfo_IntelDeviceInfoDX11.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2024 Intel Corporation 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | #include "LibXPUInfo.h" 5 | #include "LibXPUInfo_Util.h" 6 | #include 7 | #include 8 | #include "DebugStream.h" 9 | 10 | namespace WRL = Microsoft::WRL; 11 | 12 | // Adapted from Intel GPUDetect code sample 13 | 14 | #define GGF_SUCCESS 0 15 | #define GGF_ERROR -1 16 | #define GGF_E_UNSUPPORTED_HARDWARE -2 17 | #define GGF_E_UNSUPPORTED_DRIVER -3 18 | #define GGF_E_D3D_ERROR -4 19 | 20 | // The new device dependent counter 21 | #define INTEL_VENDOR_ID 0x8086 22 | 23 | // The new device dependent counter 24 | #define INTEL_DEVICE_INFO_COUNTERS "Intel Device Information" 25 | 26 | // From DXUT.h 27 | #ifndef SAFE_DELETE 28 | #define SAFE_DELETE(p) { if (p) { delete (p); (p)=nullptr; } } 29 | #endif 30 | #ifndef SAFE_DELETE_ARRAY 31 | #define SAFE_DELETE_ARRAY(p) { if (p) { delete[] (p); (p)=nullptr; } } 32 | #endif 33 | #ifndef SAFE_RELEASE 34 | #define SAFE_RELEASE(p) { if (p) { (p)->Release(); (p)=nullptr; } } 35 | #endif 36 | #define DXTRACE_ERR(msg, hr) { XI::DebugStreamT dStr(false); dStr << (msg) << ": " << (hr) << std::endl; } 37 | 38 | namespace 39 | { 40 | // New device dependent structure 41 | struct IntelDeviceInfoV1 42 | { 43 | DWORD GPUMaxFreq; 44 | DWORD GPUMinFreq; 45 | }; 46 | 47 | struct IntelDeviceInfoV2 48 | { 49 | DWORD GPUMaxFreq; 50 | DWORD GPUMinFreq; 51 | DWORD GTGeneration; 52 | DWORD EUCount; 53 | DWORD PackageTDP; 54 | DWORD MaxFillRate; 55 | }; 56 | 57 | struct IntelDeviceInfoHeader 58 | { 59 | DWORD Size; 60 | DWORD Version; 61 | }; 62 | 63 | /***************************************************************************************** 64 | * checkForIntelCounter 65 | * 66 | * Description: 67 | * Checks a device counter for match to INTEL_DEVICE_INFO_COUNTERS 68 | * Supported device info: 69 | * GPU Max Frequency, GPU Min Frequency, GT Generation, EU Count, Package TDP, Max Fill Rate 70 | * 71 | * Parameters: 72 | * ID3D11Device *pDevice - Input: pointer to graphics device object 73 | * 74 | * int index - Input: index to counter to check 75 | * 76 | * D3D11_COUNTER_DESC &intelCounterDesc - Input: allocated counter descriptor struct 77 | * Output: the counter found, if matches 78 | * 79 | * IntelDeviceInfoHeader *pIntelDeviceInfoHeader - Input: allocated Intel Device Info Header 80 | * Output: Info header filled with Version and Size 81 | * 82 | * Return: 83 | * true: found the Intel device info counter 84 | * false: not found 85 | * 86 | *****************************************************************************************/ 87 | 88 | bool checkForIntelCounter(ID3D11Device* pDevice, int index, D3D11_COUNTER_DESC& intelCounterDesc, IntelDeviceInfoHeader* pIntelDeviceInfoHeader) 89 | { 90 | bool bRetVal = false; // default to failed 91 | HRESULT hr = NULL; 92 | 93 | D3D11_COUNTER_TYPE counterType; 94 | D3D11_COUNTER_DESC counterDescription; 95 | UINT uiSlotsRequired, uiNameLength, uiUnitsLength, uiDescLength; 96 | 97 | counterType = static_cast(0); 98 | counterDescription.Counter = static_cast(index + D3D11_COUNTER_DEVICE_DEPENDENT_0); 99 | counterDescription.MiscFlags = 0; 100 | uiSlotsRequired = uiNameLength = uiUnitsLength = uiDescLength = 0; 101 | 102 | // Obtain string sizes CheckCounter needs to return 103 | hr = pDevice->CheckCounter(&counterDescription, &counterType, &uiSlotsRequired, nullptr, &uiNameLength, nullptr, &uiUnitsLength, nullptr, &uiDescLength); 104 | 105 | if (SUCCEEDED(hr)) 106 | { 107 | // CREATE SPACE FOR COUNTER STRINGS 108 | LPSTR sName = new char[uiNameLength]; 109 | LPSTR sUnits = new char[uiUnitsLength]; 110 | LPSTR sDesc = new char[uiDescLength]; 111 | 112 | // obtain the strings from counter - will use sDesc and sUnits 113 | hr = pDevice->CheckCounter(&counterDescription, &counterType, &uiSlotsRequired, sName, &uiNameLength, sUnits, &uiUnitsLength, sDesc, &uiDescLength); 114 | 115 | if (SUCCEEDED(hr)) 116 | { 117 | int match = strcmp(sName, INTEL_DEVICE_INFO_COUNTERS); 118 | 119 | if (match == 0) 120 | { 121 | int IntelCounterMajorVersion; 122 | int IntelCounterSize; 123 | int argsFilled; 124 | 125 | // Save counter to return 126 | intelCounterDesc.Counter = counterDescription.Counter; 127 | 128 | argsFilled = sscanf_s(sDesc, "Version %d", &IntelCounterMajorVersion); 129 | 130 | // If sscanf extracted one field (Version), must not be Version 1 of Intel counter description string 131 | if (argsFilled == 1) 132 | { 133 | argsFilled = sscanf_s(sUnits, "Size %d", &IntelCounterSize); 134 | if (!argsFilled) 135 | { 136 | if (IntelCounterMajorVersion == 2) 137 | { 138 | IntelCounterSize = sizeof(IntelDeviceInfoV2); 139 | } 140 | } 141 | } 142 | else 143 | { 144 | // Fall back to version 1.0 - assume at least that is supported 145 | IntelCounterMajorVersion = 1; 146 | IntelCounterSize = sizeof(IntelDeviceInfoV1); 147 | } 148 | 149 | // save version/size for return 150 | pIntelDeviceInfoHeader->Version = IntelCounterMajorVersion; 151 | pIntelDeviceInfoHeader->Size = IntelCounterSize; 152 | 153 | bRetVal = true; // Success 154 | 155 | } 156 | } 157 | 158 | // DELETE STRING SPACE - SIZE MAY DIFFER FOR NEXT COUNTER 159 | SAFE_DELETE_ARRAY(sName); 160 | SAFE_DELETE_ARRAY(sUnits); 161 | SAFE_DELETE_ARRAY(sDesc); 162 | 163 | } 164 | 165 | return bRetVal; 166 | 167 | } 168 | 169 | /***************************************************************************************** 170 | * getIntelDeviceInfo 171 | * 172 | * Description: 173 | * Gets device info if available 174 | * Supported device info: 175 | * GPU Max Frequency, GPU Min Frequency, GT Generation, EU Count, Package TDP, Max Fill Rate 176 | * 177 | * Parameters: 178 | * IntelDeviceInfoHeader *pIntelDeviceInfoHeader - Input: allocated IntelDeviceInfoHeader * 179 | * Output: Intel device info header, if found 180 | * 181 | * void *pIntelDeviceInfoBuffer - Input: allocated void * with sufficient space 182 | * for largest counter data 183 | * Output: IntelDeviceInfoV[#] counter data 184 | * based on IntelDeviceInfoHeader 185 | * Return: 186 | * GGF_SUCCESS: Able to find Data is valid 187 | * GGF_ERROR: General error. 188 | * GGF_E_UNSUPPORTED_DRIVER: Unsupported driver on Intel, data is invalid 189 | * GGF_E_D3D_ERROR: General error return - unkonwn D3D failure. 190 | * 191 | *****************************************************************************************/ 192 | 193 | long getIntelDeviceInfo(IntelDeviceInfoHeader* pIntelDeviceInfoHeader, void* pIntelDeviceInfoBuffer, IDXGIAdapter1* pIntelAdapter) 194 | { 195 | XPUINFO_REQUIRE(pIntelDeviceInfoBuffer != nullptr); 196 | XPUINFO_REQUIRE(pIntelDeviceInfoHeader); 197 | if (!pIntelDeviceInfoBuffer || !pIntelDeviceInfoHeader) 198 | { 199 | return GGF_ERROR; 200 | } 201 | 202 | // The device information is stored in a D3D counter. 203 | // We must create a D3D device, find the Intel counter 204 | // and query the counter info 205 | HRESULT hr = NULL; 206 | ID3D11Device* pDevice = nullptr; 207 | ID3D11DeviceContext* pImmediateContext = nullptr; 208 | 209 | D3D_FEATURE_LEVEL featureLevel; 210 | ZeroMemory(&featureLevel, sizeof(D3D_FEATURE_LEVEL)); 211 | 212 | // Create the D3D11 Device for primary graphics 213 | hr = D3D11CreateDevice(pIntelAdapter, D3D_DRIVER_TYPE_UNKNOWN, nullptr, 0, nullptr, 0, 214 | D3D11_SDK_VERSION, &pDevice, &featureLevel, &pImmediateContext); 215 | 216 | if (FAILED(hr)) 217 | { 218 | SAFE_RELEASE(pImmediateContext); 219 | SAFE_RELEASE(pDevice); 220 | 221 | XI::DebugStream dStr(true); 222 | dStr << __FILE__ << ": " << __FUNCTION__ << ": D3D11CreateDevice failed: " << hr << std::endl; 223 | 224 | return GGF_E_D3D_ERROR; 225 | } 226 | 227 | // The counter is in a device dependent counter 228 | D3D11_COUNTER_INFO counterInfo; 229 | ZeroMemory(&counterInfo, sizeof(D3D11_COUNTER_INFO)); 230 | 231 | // Query the device to find the number of device dependent counters. 232 | pDevice->CheckCounterInfo(&counterInfo); 233 | 234 | if (counterInfo.LastDeviceDependentCounter == 0) 235 | { 236 | SAFE_RELEASE(pImmediateContext); 237 | SAFE_RELEASE(pDevice); 238 | 239 | //DXTRACE_ERR(TEXT("No device dependent counters"), hr); 240 | 241 | // The driver does not support the Device Info Counter. 242 | return GGF_E_UNSUPPORTED_DRIVER; 243 | } 244 | 245 | // Get number of device dependent counters to search through 246 | int numDependentCounters = counterInfo.LastDeviceDependentCounter - D3D11_COUNTER_DEVICE_DEPENDENT_0 + 1; 247 | 248 | // The counter is in a device dependent counter 249 | // Search for the Intel device specific counter by name - INTEL_DEVICE_INFO_COUNTERS 250 | D3D11_COUNTER_DESC intelCounterDesc; 251 | ZeroMemory(&intelCounterDesc, sizeof(D3D11_COUNTER_DESC)); 252 | 253 | // Search device dependent counters for INTEL_DEVICE_INFO_COUNTERS 254 | for (int i = 0; i < numDependentCounters; ++i) 255 | { 256 | if (checkForIntelCounter(pDevice, i, intelCounterDesc, pIntelDeviceInfoHeader)) 257 | break; 258 | } 259 | 260 | // Make sure found Intel counter description 261 | if (intelCounterDesc.Counter == 0) 262 | { 263 | SAFE_RELEASE(pImmediateContext); 264 | SAFE_RELEASE(pDevice); 265 | 266 | DXTRACE_ERR(TEXT("Could not find counter"), hr); 267 | 268 | // The driver does not support the Intel Device Info Counter. 269 | return GGF_E_UNSUPPORTED_DRIVER; 270 | } 271 | 272 | 273 | 274 | // Create the Intel device counter 275 | ID3D11Counter* pIntelCounter = nullptr; 276 | 277 | hr = pDevice->CreateCounter(&intelCounterDesc, &pIntelCounter); 278 | if (FAILED(hr)) 279 | { 280 | SAFE_RELEASE(pIntelCounter); 281 | SAFE_RELEASE(pImmediateContext); 282 | SAFE_RELEASE(pDevice); 283 | 284 | DXTRACE_ERR(TEXT("CreateCounter failed"), hr); 285 | return GGF_E_D3D_ERROR; 286 | } 287 | 288 | 289 | // Begin and end counter capture to collect data 290 | pImmediateContext->Begin(pIntelCounter); 291 | pImmediateContext->End(pIntelCounter); 292 | 293 | 294 | 295 | // Create space for a pointer to counter data buffer 296 | DWORD pData[2] = { 0,0 }; // Can hold a 32 or 64 bit pointer 297 | 298 | // Retrieve a pointer to Intel counter data - NOTE: NOT the data itself! 299 | hr = pImmediateContext->GetData(pIntelCounter, pData, sizeof(pData), 0); 300 | 301 | if (FAILED(hr) || hr == S_FALSE) 302 | { 303 | SAFE_RELEASE(pIntelCounter); 304 | SAFE_RELEASE(pImmediateContext); 305 | SAFE_RELEASE(pDevice); 306 | 307 | DXTRACE_ERR(TEXT("GetData failed"), hr); 308 | return GGF_E_D3D_ERROR; 309 | } 310 | 311 | 312 | // Extract returned pointer to counter data buffer 313 | void* pDeviceInfoBuffer = *(void**)pData; 314 | 315 | // Copy Counter data to save in buffer space passed on pIntelDeviceInfoBuffer 316 | memcpy(pIntelDeviceInfoBuffer, pDeviceInfoBuffer, pIntelDeviceInfoHeader->Size); 317 | 318 | 319 | // Clean up 320 | SAFE_RELEASE(pIntelCounter); 321 | SAFE_RELEASE(pImmediateContext); 322 | SAFE_RELEASE(pDevice); 323 | 324 | return GGF_SUCCESS; 325 | } 326 | } // private 327 | 328 | namespace XI 329 | { 330 | void Device::initDXIntelPerfCounter(IDXGIAdapter1* pAdapter) 331 | { 332 | // Retrieve Intel device information 333 | IntelDeviceInfoHeader intelDeviceInfoHeader = { 0 }; 334 | byte intelDeviceInfoBuffer[1024]; // enough space to allow some future expansion 335 | 336 | DebugStream dStr(false); 337 | long getStatus = getIntelDeviceInfo(&intelDeviceInfoHeader, &intelDeviceInfoBuffer, pAdapter); 338 | if (getStatus == GGF_SUCCESS) 339 | { 340 | //_tprintf(TEXT("Intel Device Info Version %d (%d bytes)\n"), intelDeviceInfoHeader.Version, intelDeviceInfoHeader.Size); 341 | 342 | if (intelDeviceInfoHeader.Version >= 2) 343 | { 344 | IntelDeviceInfoV2* pIntelDeviceInfo = (IntelDeviceInfoV2*)intelDeviceInfoBuffer; 345 | updateIfDstNotSet(m_props.FreqMaxMHz, (I32)pIntelDeviceInfo->GPUMaxFreq); 346 | updateIfDstNotSet(m_props.FreqMinMHz, (I32)pIntelDeviceInfo->GPUMinFreq); 347 | updateIfDstNotSet(m_props.DeviceGenerationID, (I32)pIntelDeviceInfo->GTGeneration); 348 | updateIfDstVal(m_props.DeviceGenerationAPI, API_TYPE_UNKNOWN, API_TYPE_DX11_INTEL_PERF_COUNTER); 349 | updateIfDstNotSet(m_props.NumComputeUnits, (I32)pIntelDeviceInfo->EUCount); 350 | if (pIntelDeviceInfo->PackageTDP > 0) 351 | updateIfDstNotSet(m_props.PackageTDP, (I32)pIntelDeviceInfo->PackageTDP); 352 | // MaxFillRate needed? 353 | 354 | if (intelDeviceInfoHeader.Version > 2) 355 | { 356 | dStr << __FUNCTION__ << ": NOTE: DeviceInfoHeader.Version > 2, check for updated fields\n"; 357 | } 358 | validAPIs = validAPIs | API_TYPE_DX11_INTEL_PERF_COUNTER; 359 | } 360 | else if (intelDeviceInfoHeader.Version == 1) 361 | { 362 | IntelDeviceInfoV1* pIntelDeviceInfo = (IntelDeviceInfoV1*)intelDeviceInfoBuffer; 363 | updateIfDstNotSet(m_props.FreqMaxMHz, (I32)pIntelDeviceInfo->GPUMaxFreq); 364 | updateIfDstNotSet(m_props.FreqMinMHz, (I32)pIntelDeviceInfo->GPUMinFreq); 365 | validAPIs = validAPIs | API_TYPE_DX11_INTEL_PERF_COUNTER; 366 | } 367 | else 368 | { 369 | dStr << __FUNCTION__ << "ERROR: UNKNOWN Intel Device Version \n"; 370 | } 371 | } 372 | else if (getStatus == GGF_E_UNSUPPORTED_HARDWARE) 373 | { 374 | dStr << __FUNCTION__ << "ERROR: GGF_E_UNSUPPORTED_HARDWARE\n"; 375 | } 376 | else if (getStatus == GGF_E_UNSUPPORTED_DRIVER) 377 | { 378 | dStr << __FUNCTION__ << "ERROR: GGF_E_UNSUPPORTED_DRIVER\n"; 379 | } 380 | else 381 | { 382 | dStr << __FUNCTION__ << "ERROR: UNKOWN ERROR\n"; 383 | } 384 | } 385 | 386 | } // XI 387 | -------------------------------------------------------------------------------- /LibXPUInfo_JSON.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2024 Intel Corporation 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | #pragma once 5 | 6 | #ifdef XPUINFO_USE_RAPIDJSON 7 | #include "LibXPUInfo.h" 8 | #include "LibXPUInfo_Util.h" // for XI::convert 9 | #include "rapidjson/document.h" 10 | #include "rapidjson/prettywriter.h" 11 | #include 12 | #include 13 | // Support serialization 14 | #include 15 | 16 | #define XPUINFO_JSON_VERSION "0.0.1" 17 | 18 | namespace XI 19 | { 20 | namespace JSON 21 | { 22 | template 23 | const char* safeGetValString(const T& val, const char* valName) 24 | { 25 | if (val.HasMember(valName)) 26 | { 27 | if (val[valName].IsString()) 28 | { 29 | return val[valName].GetString(); 30 | } 31 | } 32 | return nullptr; 33 | } 34 | 35 | template 36 | std::string safeGetString(const T& val, const char* valName) 37 | { 38 | if (val.HasMember(valName)) 39 | { 40 | if (val[valName].IsString()) 41 | { 42 | return val[valName].GetString(); 43 | } 44 | } 45 | return std::string(); 46 | } 47 | 48 | template 49 | std::wstring safeGetWString(const T& val, const char* valName) 50 | { 51 | if (val.HasMember(valName)) 52 | { 53 | if (val[valName].IsString()) 54 | { 55 | return convert(val[valName].GetString()); 56 | } 57 | } 58 | return std::wstring(); 59 | } 60 | 61 | template 62 | std::optional safeGetUI64(const T& val, const char* valName) 63 | { 64 | if (val.HasMember(valName)) 65 | { 66 | if (val[valName].IsUint64()) 67 | { 68 | return val[valName].GetUint64(); 69 | } 70 | } 71 | return std::nullopt; 72 | } 73 | 74 | template 75 | std::optional safeGetI64(const T& val, const char* valName) 76 | { 77 | if (val.HasMember(valName)) 78 | { 79 | if (val[valName].IsInt64()) 80 | { 81 | return val[valName].GetInt64(); 82 | } 83 | } 84 | return std::nullopt; 85 | } 86 | 87 | template 88 | std::optional safeGetUI32(const T& val, const char* valName) 89 | { 90 | if (val.HasMember(valName)) 91 | { 92 | if (val[valName].IsUint()) 93 | { 94 | return val[valName].GetUint(); 95 | } 96 | } 97 | return std::nullopt; 98 | } 99 | 100 | template 101 | std::optional safeGetI32(const T& val, const char* valName) 102 | { 103 | if (val.HasMember(valName)) 104 | { 105 | if (val[valName].IsInt()) 106 | { 107 | return val[valName].GetInt(); 108 | } 109 | } 110 | return std::nullopt; 111 | } 112 | 113 | template 114 | std::optional safeGetDouble(const T& val, const char* valName) 115 | { 116 | if (val.HasMember(valName)) 117 | { 118 | if (val[valName].IsDouble()) 119 | { 120 | return val[valName].GetDouble(); 121 | } 122 | } 123 | return std::nullopt; 124 | } 125 | 126 | template 127 | std::optional safeGetBool(const T& val, const char* valName) 128 | { 129 | if (val.HasMember(valName)) 130 | { 131 | if (val[valName].IsBool()) 132 | { 133 | return val[valName].GetBool(); 134 | } 135 | } 136 | return std::nullopt; 137 | } 138 | 139 | // For validating original vs. deserialized objects 140 | bool XPUINFO_EXPORT compareXI(const XPUInfoPtr& pXI, const XPUInfoPtr& pXID); 141 | 142 | } // JSON 143 | 144 | } // XI 145 | #endif // XPUINFO_USE_RAPIDJSON 146 | -------------------------------------------------------------------------------- /LibXPUInfo_Metal.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/intel/LibXPUInfo/a0ff66db1e65e61d5cfb51bff59303ee320f8123/LibXPUInfo_Metal.h -------------------------------------------------------------------------------- /LibXPUInfo_Metal.mm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/intel/LibXPUInfo/a0ff66db1e65e61d5cfb51bff59303ee320f8123/LibXPUInfo_Metal.mm -------------------------------------------------------------------------------- /LibXPUInfo_NVML.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2024 Intel Corporation 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | /* To enable NVML, 5 | 1. Get package from https://developer.download.nvidia.com/compute/cuda/redist/cuda_nvml_dev/windows-x86_64/, currently cuda_nvml_dev-windows-x86_64-12.5.39-archive.zip 6 | 2. Extract contents to $(SolutionDir)external\NVML 7 | 3. Add XPUINFO_USE_NVML to preprocessor definitions for LibXPUInfo project 8 | */ 9 | #ifdef XPUINFO_USE_NVML 10 | #include "LibXPUInfo.h" 11 | #include "DebugStream.h" 12 | #include "LibXPUInfo_Util.h" 13 | #include "nvml.h" 14 | #pragma comment(lib, "nvml.lib") 15 | #ifdef _WIN32 16 | #include 17 | #endif 18 | 19 | #if 0 // For experimenting with NVML 20 | #define PRINT_IF_SUCCESS(var, funcName) if (NVML_SUCCESS==result) std::cout << #funcName << " -> " << #var << ": " << var << std::endl; 21 | #else 22 | #define PRINT_IF_SUCCESS(var, funcName) 23 | #endif 24 | 25 | namespace XI 26 | { 27 | void Device::initNVMLDevice(nvmlDevice_t device) 28 | { 29 | nvmlReturn_t result; 30 | char name[NVML_DEVICE_NAME_BUFFER_SIZE]; 31 | String nameStr; 32 | UI32 LinkGen = 0; 33 | UI32 LinkWidth = 0; 34 | 35 | result = nvmlDeviceGetName(device, name, NVML_DEVICE_NAME_BUFFER_SIZE); 36 | if (NVML_SUCCESS == result) 37 | { 38 | nameStr = name; 39 | } 40 | 41 | // Ampere has 64 or 128 CUDA cores per SM 42 | UI32 numGPUCores = 0; 43 | result = nvmlDeviceGetNumGpuCores(device, &numGPUCores); 44 | if (NVML_SUCCESS == result) 45 | { 46 | // Overwrite OpenCL result which is SM, use CUDA cores 47 | m_props.NumComputeUnits = (I32)numGPUCores; 48 | } 49 | 50 | nvmlEnableState_t mode = NVML_FEATURE_DISABLED; 51 | result = nvmlDeviceGetPowerManagementMode(device, &mode); 52 | if (NVML_SUCCESS == result) 53 | { 54 | } 55 | UI32 powerLimit = 0; 56 | UI32 minPowerLimit = 0; 57 | result = nvmlDeviceGetPowerUsage(device, &powerLimit); // Seems to be current power draw 58 | PRINT_IF_SUCCESS(powerLimit, nvmlDeviceGetPowerUsage); 59 | result = nvmlDeviceGetPowerManagementDefaultLimit(device, &powerLimit); // dnw 60 | PRINT_IF_SUCCESS(powerLimit, nvmlDeviceGetPowerManagementDefaultLimit); 61 | result = nvmlDeviceGetPowerManagementLimit(device, &powerLimit); // dnw 62 | PRINT_IF_SUCCESS(powerLimit, nvmlDeviceGetPowerManagementLimit); 63 | result = nvmlDeviceGetPowerManagementLimitConstraints(device, &minPowerLimit, &powerLimit); // dnw 64 | PRINT_IF_SUCCESS(minPowerLimit, nvmlDeviceGetPowerManagementLimitConstraints); 65 | PRINT_IF_SUCCESS(powerLimit, nvmlDeviceGetPowerManagementLimitConstraints); 66 | result = nvmlDeviceGetEnforcedPowerLimit(device, &powerLimit); // dnw - should the the one we want 67 | PRINT_IF_SUCCESS(powerLimit, nvmlDeviceGetEnforcedPowerLimit); 68 | 69 | if (NVML_SUCCESS == result) 70 | { 71 | updateIfDstNotSet(m_props.PackageTDP, (I32)(powerLimit / 1000)); 72 | } 73 | 74 | UI32 busWidth = 0; 75 | result = nvmlDeviceGetMemoryBusWidth(device, &busWidth); 76 | PRINT_IF_SUCCESS(busWidth, nvmlDeviceGetMemoryBusWidth); 77 | nvmlMemory_t memoryInfo; 78 | result = nvmlDeviceGetMemoryInfo(device, &memoryInfo); 79 | PRINT_IF_SUCCESS(memoryInfo.total, nvmlDeviceGetMemoryInfo); 80 | 81 | UI32 freqSM = 0, freqGfx = 0, freqMem=0; 82 | //result = nvmlDeviceGetClock(device, NVML_CLOCK_SM, NVML_CLOCK_ID_APP_CLOCK_DEFAULT, &freqSM); 83 | result = nvmlDeviceGetMaxClockInfo(device, NVML_CLOCK_SM, &freqSM); 84 | if (NVML_SUCCESS == result) 85 | { 86 | updateIfDstNotSet(m_props.FreqMaxMHz, (I32)freqSM); 87 | } 88 | PRINT_IF_SUCCESS(freqSM, nvmlDeviceGetMaxClockInfo); 89 | result = nvmlDeviceGetMaxClockInfo(device, NVML_CLOCK_GRAPHICS, &freqGfx); 90 | PRINT_IF_SUCCESS(freqGfx, nvmlDeviceGetMaxClockInfo); 91 | result = nvmlDeviceGetMaxClockInfo(device, NVML_CLOCK_MEM, &freqMem); 92 | PRINT_IF_SUCCESS(freqMem, nvmlDeviceGetMaxClockInfo); 93 | UI32 freqVideo = 0; 94 | result = nvmlDeviceGetMaxClockInfo(device, NVML_CLOCK_VIDEO, &freqVideo); 95 | PRINT_IF_SUCCESS(freqVideo, nvmlDeviceGetMaxClockInfo); 96 | 97 | unsigned int clockMHz = 0; 98 | result = nvmlDeviceGetClock(device, NVML_CLOCK_GRAPHICS, NVML_CLOCK_ID_CURRENT, &clockMHz); 99 | PRINT_IF_SUCCESS(clockMHz, nvmlDeviceGetClock); 100 | 101 | nvmlUtilization_t utilization = {}; 102 | result = nvmlDeviceGetUtilizationRates(device, &utilization); 103 | PRINT_IF_SUCCESS(utilization.gpu, nvmlDeviceGetClock); 104 | PRINT_IF_SUCCESS(utilization.memory, nvmlDeviceGetClock); 105 | 106 | result = nvmlDeviceGetCurrPcieLinkGeneration(device, &LinkGen); 107 | if (NVML_SUCCESS == result) 108 | { 109 | result = nvmlDeviceGetCurrPcieLinkWidth(device, &LinkWidth); 110 | if (NVML_SUCCESS == result) 111 | { 112 | updateIfDstNotSet(m_props.PCICurrentGen, (I32)LinkGen); 113 | updateIfDstNotSet(m_props.PCICurrentWidth, (I32)LinkWidth); 114 | } 115 | } 116 | 117 | nvmlDeviceArchitecture_t arch = 0; 118 | result = nvmlDeviceGetArchitecture(device, &arch); 119 | if (NVML_SUCCESS == result) 120 | { 121 | if (m_props.DeviceGenerationID < 0) 122 | { 123 | m_props.DeviceGenerationID = arch; 124 | m_props.DeviceGenerationAPI = API_TYPE_NVML; 125 | } 126 | } 127 | 128 | int cccMajor = 0, cccMinor = 0; 129 | result = nvmlDeviceGetCudaComputeCapability(device, &cccMajor, &cccMinor); 130 | if (NVML_SUCCESS == result) 131 | { 132 | m_props.VendorSpecific.nVidia.cudaComputeCapability_Major = cccMajor; 133 | m_props.VendorSpecific.nVidia.cudaComputeCapability_Minor = cccMinor; 134 | } 135 | 136 | // Currently only for multi-instance GPU (MIG) 137 | #if 0 138 | nvmlDeviceAttributes_t devAttrs{}; 139 | result = nvmlDeviceGetAttributes(device, &devAttrs); 140 | if (NVML_SUCCESS == result) 141 | { 142 | 143 | } 144 | #endif 145 | 146 | #if 0 // TODO: calculate MemoryBandWidthMax 147 | if (freqMem && busWidth) 148 | { 149 | I64 memBW_Bps = (busWidth / 8 * freqMem) * (1024*1024ULL); 150 | // TODO: Not correct - about half of actual 151 | //updateIfDstNotSet(m_props.MemoryBandWidthMax, memBW_Bps); 152 | } 153 | #endif 154 | 155 | validAPIs = validAPIs | API_TYPE_NVML; 156 | m_nvmlDevice = device; 157 | } 158 | 159 | #ifdef XPUINFO_USE_TELEMETRYTRACKER 160 | bool TelemetryTracker::RecordNVML(TimedRecord& rec) 161 | { 162 | nvmlDevice_t dev = m_Device->getHandle_NVML(); 163 | bool bRet = false; 164 | if (dev) 165 | { 166 | unsigned int clockMHz = 0; 167 | auto result = nvmlDeviceGetClock(dev, NVML_CLOCK_GRAPHICS, NVML_CLOCK_ID_CURRENT, &clockMHz); 168 | if (NVML_SUCCESS == result) 169 | { 170 | rec.freq = clockMHz; 171 | if (m_records.size() == 0) 172 | { 173 | m_ResultMask = (TelemetryItem)(m_ResultMask | TELEMETRYITEM_FREQUENCY); 174 | } 175 | bRet = true; 176 | } 177 | nvmlUtilization_t utilization = {}; 178 | result = nvmlDeviceGetUtilizationRates(dev, &utilization); 179 | if (NVML_SUCCESS == result) 180 | { 181 | rec.activity_compute = utilization.gpu; 182 | rec.activity_global = utilization.memory; 183 | if (m_records.size() == 0) 184 | { 185 | m_ResultMask = (TelemetryItem)(m_ResultMask | TELEMETRYITEM_RENDER_COMPUTE_ACTIVITY| TELEMETRYITEM_GLOBAL_ACTIVITY); 186 | } 187 | bRet = true; 188 | } 189 | 190 | } 191 | return bRet; 192 | } 193 | #endif 194 | 195 | #ifdef _WIN32 196 | static nvmlReturn_t safeInitNVML() 197 | { 198 | nvmlReturn_t result = NVML_ERROR_UNINITIALIZED; 199 | __try 200 | { 201 | result = nvmlInit(); 202 | } 203 | __except (GetExceptionCode() == VcppException(ERROR_SEVERITY_ERROR, ERROR_MOD_NOT_FOUND) 204 | ? EXCEPTION_EXECUTE_HANDLER 205 | : EXCEPTION_CONTINUE_SEARCH) 206 | { 207 | result = NVML_ERROR_UNINITIALIZED; 208 | } 209 | return result; 210 | } 211 | #endif 212 | 213 | void XPUInfo::initNVML() 214 | { 215 | #ifdef _WIN32 216 | nvmlReturn_t result = safeInitNVML(); 217 | #else 218 | nvmlReturn_t result = nvmlInit(); 219 | #endif 220 | 221 | if (NVML_SUCCESS == result) 222 | { 223 | UI32 device_count=0; 224 | result = nvmlDeviceGetCount(&device_count); 225 | if (NVML_SUCCESS == result) 226 | { 227 | m_UsedAPIs = m_UsedAPIs | API_TYPE_NVML; 228 | 229 | for (UI32 i = 0; i < device_count; ++i) 230 | { 231 | nvmlDevice_t device = nullptr; 232 | result = nvmlDeviceGetHandleByIndex(i, &device); 233 | if (NVML_SUCCESS == result) 234 | { 235 | nvmlPciInfo_t pci; 236 | result = nvmlDeviceGetPciInfo(device, &pci); 237 | if (NVML_SUCCESS == result) 238 | { 239 | PCIAddressType pciAddr; 240 | pciAddr.bus = pci.bus; 241 | pciAddr.device = pci.device; 242 | pciAddr.domain = pci.domain; 243 | pciAddr.function = 0; 244 | String dbdf = pci.busId; 245 | auto posLastDot = dbdf.rfind('.'); 246 | String funcStr = dbdf.substr(posLastDot + 1); 247 | if (funcStr[0] != '0') 248 | { 249 | pciAddr.function = atoi(funcStr.c_str()); 250 | } 251 | 252 | for (auto& [luid, dev] : m_Devices) 253 | { 254 | if (dev->getProperties().PCIAddress == pciAddr) 255 | { 256 | dev->initNVMLDevice(device); 257 | break; 258 | } 259 | } 260 | } 261 | } 262 | } 263 | } 264 | else 265 | { 266 | DebugStream dStr(true); 267 | dStr << "Failed to query device count: " << nvmlErrorString(result) << std::endl; 268 | } 269 | } 270 | 271 | } 272 | 273 | void XPUInfo::shutdownNVML() 274 | { 275 | if (m_UsedAPIs & API_TYPE_NVML) 276 | { 277 | #ifdef _DEBUG 278 | auto result = 279 | #endif 280 | nvmlShutdown(); 281 | XPUINFO_DEBUG_REQUIRE(NVML_SUCCESS == result); 282 | } 283 | } 284 | 285 | } // XI 286 | #endif // XPUINFO_USE_LEVELZERO 287 | -------------------------------------------------------------------------------- /LibXPUInfo_OpenCL.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2024 Intel Corporation 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | #ifdef XPUINFO_USE_OPENCL 5 | #include "LibXPUInfo.h" 6 | #include "CL/opencl.hpp" 7 | #include "DebugStream.h" 8 | 9 | #ifndef CL_DEVICE_IP_VERSION_INTEL 10 | /* For GPU devices, version 1.0.0: */ 11 | 12 | #define CL_DEVICE_IP_VERSION_INTEL 0x4250 13 | #define CL_DEVICE_ID_INTEL 0x4251 14 | #define CL_DEVICE_NUM_SLICES_INTEL 0x4252 15 | #define CL_DEVICE_NUM_SUB_SLICES_PER_SLICE_INTEL 0x4253 16 | #define CL_DEVICE_NUM_EUS_PER_SUB_SLICE_INTEL 0x4254 17 | #define CL_DEVICE_NUM_THREADS_PER_EU_INTEL 0x4255 18 | #define CL_DEVICE_FEATURE_CAPABILITIES_INTEL 0x4256 19 | 20 | typedef cl_bitfield cl_device_feature_capabilities_intel; 21 | 22 | /* For GPU devices, version 1.0.0: */ 23 | 24 | #define CL_DEVICE_FEATURE_FLAG_DP4A_INTEL (1 << 0) 25 | #define CL_DEVICE_FEATURE_FLAG_DPAS_INTEL (1 << 1) 26 | #endif 27 | 28 | namespace XI 29 | { 30 | 31 | void Device::initOpenCLDevice(cl_platform_id inPlatform, cl_device_id inDevice, const std::string& inExtensions) 32 | { 33 | m_CLPlatform = inPlatform; 34 | m_CLDevice = inDevice; 35 | 36 | cl::Device clDevice(inDevice); 37 | 38 | cl_int err; 39 | cl::string devName; 40 | devName = clDevice.getInfo(&err); 41 | HYBRIDDETECT_DEBUG_REQUIRE(CL_SUCCESS == err); 42 | m_OpenCLAdapterName = std::move(devName); 43 | 44 | if (m_props.NumComputeUnits == -1) 45 | { 46 | cl_uint maxCU = 0; 47 | err = clDevice.getInfo(CL_DEVICE_MAX_COMPUTE_UNITS, &maxCU); 48 | if (CL_SUCCESS == err) 49 | m_props.NumComputeUnits = (I32)maxCU; 50 | } 51 | 52 | if (m_props.FreqMaxMHz == -1) 53 | { 54 | cl_uint maxFreq = 0; 55 | err = clDevice.getInfo(CL_DEVICE_MAX_CLOCK_FREQUENCY, &maxFreq); 56 | if (CL_SUCCESS == err) 57 | m_props.FreqMaxMHz = (I32)maxFreq; 58 | } 59 | 60 | if (inExtensions.find("cl_intel_device_attribute_query") != std::string::npos) 61 | { 62 | cl_version ip_version = 0; 63 | err = clDevice.getInfo(CL_DEVICE_IP_VERSION_INTEL, &ip_version); 64 | if ((CL_SUCCESS==err) && ip_version) 65 | { 66 | if (m_props.DeviceGenerationAPI == API_TYPE_UNKNOWN) 67 | { 68 | m_props.DeviceGenerationAPI = API_TYPE_OPENCL; 69 | m_props.DeviceGenerationID = ip_version; 70 | } 71 | if (m_props.DeviceIPVersion == 0) 72 | { 73 | m_props.DeviceIPVersion = ip_version; 74 | } 75 | } 76 | 77 | cl_device_feature_capabilities_intel features = 0; 78 | err = clDevice.getInfo(CL_DEVICE_FEATURE_CAPABILITIES_INTEL, &features); 79 | if ((CL_SUCCESS == err) && features) 80 | { 81 | if (features & CL_DEVICE_FEATURE_FLAG_DP4A_INTEL) 82 | { 83 | m_props.VendorFlags.IntelFeatureFlags.FLAG_DP4A = 1; 84 | } 85 | if (features & CL_DEVICE_FEATURE_FLAG_DPAS_INTEL) 86 | { 87 | m_props.VendorFlags.IntelFeatureFlags.FLAG_DPAS = 1; 88 | } 89 | } 90 | } 91 | 92 | { // IGCL may be wrong with old drivers, so allow CL to fix it 93 | cl_bool isUMA = 0; 94 | err = clDevice.getInfo(CL_DEVICE_HOST_UNIFIED_MEMORY, &isUMA); 95 | if (CL_SUCCESS == err) 96 | { 97 | if ((m_props.UMA == UMA_UNKNOWN) || (isUMA && (m_props.UMA == NONUMA_DISCRETE)) || 98 | (!isUMA && (m_props.UMA == UMA_INTEGRATED))) 99 | { 100 | m_props.UMA = isUMA ? UMA_INTEGRATED : NONUMA_DISCRETE; 101 | } 102 | } 103 | } 104 | validAPIs = validAPIs | API_TYPE_OPENCL; 105 | } 106 | 107 | void XPUInfo::initOpenCL() 108 | { 109 | std::vector platforms; 110 | cl_int err = cl::Platform::get(&platforms); 111 | if (CL_SUCCESS == err) 112 | { 113 | int clDevsFound = 0; 114 | for (auto& platform : platforms) 115 | { 116 | cl::string pfVendor, pfName; 117 | pfVendor = platform.getInfo(&err); 118 | HYBRIDDETECT_DEBUG_REQUIRE(CL_SUCCESS == err); 119 | pfName = platform.getInfo(&err); 120 | HYBRIDDETECT_DEBUG_REQUIRE(CL_SUCCESS == err); 121 | 122 | DebugStream dStr(false); 123 | dStr << "Platform vendor = " << pfVendor << " \tname = " << pfName << std::endl; 124 | if (pfVendor == "Microsoft") 125 | { 126 | dStr << "Skipping platform!" << std::endl; 127 | continue; 128 | } 129 | 130 | std::vector clDevices; 131 | err = platform.getDevices(CL_DEVICE_TYPE_GPU, &clDevices); 132 | if (CL_SUCCESS == err) 133 | { 134 | for (auto& clDevice : clDevices) 135 | { 136 | cl::string devName; 137 | devName = clDevice.getInfo(&err); 138 | HYBRIDDETECT_DEBUG_REQUIRE(CL_SUCCESS == err); 139 | dStr << "\t" << devName; 140 | 141 | // if (HasExtension()) 142 | cl::string exts = clDevice.getInfo(&err); 143 | HYBRIDDETECT_DEBUG_REQUIRE(CL_SUCCESS == err); 144 | cl_bool luidFromCLValid = CL_FALSE; 145 | UI64 luidFromCL = 0; 146 | bool curDevFound = false; 147 | if (exts.find("cl_khr_device_uuid") != cl::string::npos) 148 | { 149 | err = clDevice.getInfo(CL_DEVICE_LUID_VALID_KHR, &luidFromCLValid); 150 | HYBRIDDETECT_DEBUG_REQUIRE(CL_SUCCESS == err); 151 | err = clDevice.getInfo(CL_DEVICE_LUID_KHR, &luidFromCL); 152 | HYBRIDDETECT_DEBUG_REQUIRE(CL_SUCCESS == err); 153 | if (luidFromCLValid) 154 | { 155 | dStr << ", LUID = " << std::hex << luidFromCL; 156 | 157 | auto xiDev = getDeviceInternal(luidFromCL); 158 | if (xiDev) 159 | { 160 | curDevFound = true; 161 | xiDev->initOpenCLDevice(platform(), clDevice(), exts); 162 | dStr << ", CL Platform = " << xiDev->m_CLPlatform << ", CL Device = " << xiDev->m_CLDevice; 163 | ++clDevsFound; 164 | } 165 | 166 | dStr << std::dec; 167 | } 168 | } 169 | if (!curDevFound) 170 | { 171 | auto xiDev = getDeviceInternal(devName.c_str()); 172 | if (xiDev) 173 | { 174 | curDevFound = true; 175 | xiDev->initOpenCLDevice(platform(), clDevice(), exts); 176 | ++clDevsFound; 177 | } 178 | } 179 | dStr << std::endl; 180 | } 181 | } 182 | } 183 | if (clDevsFound) 184 | { 185 | m_UsedAPIs = m_UsedAPIs | API_TYPE_OPENCL; 186 | } 187 | } 188 | } 189 | 190 | } // XI 191 | #endif // LIBXPUINFO_USE_OPENCL 192 | -------------------------------------------------------------------------------- /LibXPUInfo_SetupAPI.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2024 Intel Corporation 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | #ifdef XPUINFO_USE_SETUPAPI 5 | 6 | #ifndef WIN32_LEAN_AND_MEAN 7 | #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers 8 | #endif 9 | #include "LibXPUInfo.h" 10 | #include "LibXPUInfo_Util.h" 11 | #include // include before devguid.h, devpkey.h in one module 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include "DebugStream.h" 17 | 18 | #pragma comment (lib, "Setupapi.lib") 19 | 20 | namespace 21 | { 22 | // Found here, but not sure where they got it: https://wine-devel.winehq.narkive.com/vKO2Bkgj/patch-1-2-dxgi-tests-add-test-for-enumerating-display-adapters-using-setupapi 23 | // Valid on >=Win10 24 | DEFINE_DEVPROPKEY(DEVPROPKEY_DISPLAY_ADAPTER_LUID, 0x60b193cb, 0x5276, 0x4d0f, 0x96, 0xfc, 0xf1, 0x73, 0xab, 0xad, 0x3e, 0xc6, 2); // sizeof(LUID) 25 | 26 | /* 27 | Return code Description 28 | ERROR_INVALID_FLAGS 29 | The value of Flags is not zero. 30 | ERROR_INVALID_HANDLE 31 | The device information set that is specified by DevInfoSet is not valid. 32 | ERROR_INVALID_PARAMETER 33 | A supplied parameter is not valid. One possibility is that the device information element is not valid. 34 | ERROR_INVALID_REG_PROPERTY 35 | The property key that is supplied by PropertyKey is not valid. 36 | ERROR_INVALID_DATA 37 | An unspecified internal data value was not valid. 38 | ERROR_INVALID_USER_BUFFER 39 | A user buffer is not valid. One possibility is that PropertyBuffer is NULL and PropertBufferSize is not zero. 40 | ERROR_NO_SUCH_DEVINST 41 | The device instance that is specified by DevInfoData does not exist. 42 | ERROR_INSUFFICIENT_BUFFER 43 | The PropertyBuffer buffer is too small to hold the requested property value, or an internal data buffer that was passed to a system call was too small. 44 | ERROR_NOT_ENOUGH_MEMORY 45 | There was not enough system memory available to complete the operation. 46 | ERROR_NOT_FOUND 47 | The requested device property does not exist. 48 | ERROR_ACCESS_DENIED 49 | The caller does not have Administrator privileges. 50 | */ 51 | 52 | #define CASE_ERR_TO_STR(e) case e: str << #e; break; 53 | 54 | XI::WString GetErrorCodeStr(DWORD lr) 55 | { 56 | std::wostringstream str; 57 | switch (lr) 58 | { 59 | CASE_ERR_TO_STR(ERROR_INVALID_FLAGS) 60 | CASE_ERR_TO_STR(ERROR_INVALID_HANDLE) 61 | CASE_ERR_TO_STR(ERROR_INVALID_PARAMETER) 62 | CASE_ERR_TO_STR(ERROR_INVALID_REG_PROPERTY) 63 | CASE_ERR_TO_STR(ERROR_INVALID_DATA) 64 | CASE_ERR_TO_STR(ERROR_INVALID_USER_BUFFER) 65 | CASE_ERR_TO_STR(ERROR_NO_SUCH_DEVINST) 66 | CASE_ERR_TO_STR(ERROR_INSUFFICIENT_BUFFER) 67 | CASE_ERR_TO_STR(ERROR_NOT_ENOUGH_MEMORY) 68 | CASE_ERR_TO_STR(ERROR_NOT_FOUND) 69 | CASE_ERR_TO_STR(ERROR_ACCESS_DENIED) 70 | default: 71 | str << L"Unknown Error"; 72 | } 73 | 74 | return str.str(); 75 | } 76 | 77 | bool sdiGetProp(HDEVINFO info, std::vector& tempBuf, PSP_DEVINFO_DATA pDID, const DEVPROPKEY* pDPK, XI::WString& outStr) 78 | { 79 | DEVPROPTYPE PropType; 80 | bool bRet = SetupDiGetDevicePropertyW( 81 | info, 82 | pDID, 83 | pDPK, 84 | &PropType, 85 | (PBYTE)tempBuf.data(), 86 | (DWORD)tempBuf.size(), 87 | nullptr, 88 | 0); 89 | if (!bRet) 90 | { 91 | auto lastErr = GetLastError(); 92 | XI::DebugStreamW dStr(true); 93 | dStr << L"ERROR: " << __FUNCTIONW__ << L" returned " << GetErrorCodeStr(lastErr) << "(" << lastErr << ")\n"; 94 | } 95 | bRet = bRet && (PropType == DEVPROP_TYPE_STRING); 96 | if (bRet) 97 | { 98 | outStr = tempBuf.data(); 99 | } 100 | return bRet; 101 | } 102 | } 103 | 104 | namespace XI 105 | { 106 | namespace //private 107 | { 108 | bool getInfoForClass(const GUID* devClass, std::vector& outInfos) 109 | { 110 | HDEVINFO m_info = SetupDiGetClassDevsW(devClass, 111 | L"PCI", // Filter out remote desktop which is "SWD" 112 | nullptr, DIGCF_PRESENT); 113 | HYBRIDDETECT_DEBUG_REQUIRE(m_info != INVALID_HANDLE_VALUE); 114 | 115 | SP_DEVINFO_DATA devInfoData; 116 | ZeroMemory(&devInfoData, sizeof(devInfoData)); 117 | devInfoData.cbSize = sizeof(devInfoData); 118 | 119 | DWORD devIdx = 0; 120 | while (SetupDiEnumDeviceInfo(m_info, devIdx, &devInfoData)) 121 | { 122 | DebugStreamW dStr(false); 123 | DriverInfoPtr curInfo(new DriverInfo); 124 | 125 | dStr << L"\tDevice " << devIdx << ": "; 126 | ++devIdx; 127 | DWORD numKeys = 0; 128 | if (SetupDiGetDevicePropertyKeys(m_info, &devInfoData, nullptr, 0, &numKeys, 0)) 129 | { 130 | dStr << L" with " << numKeys << L" keys"; 131 | } 132 | 133 | DEVPROPTYPE PropType; 134 | DWORD nameSize = 0; 135 | std::vector tempStr; 136 | tempStr.resize(256); 137 | 138 | /* 139 | if (SetupDiGetDevicePropertyW( 140 | m_info, 141 | &devInfoData, 142 | &DEVPKEY_Device_EnumeratorName, 143 | &PropType, 144 | (PBYTE)tempStr.data(), 145 | (DWORD)tempStr.size(), 146 | &nameSize, 147 | 0)) 148 | { 149 | // Should be PCI unless filter above changed 150 | dStr << L" at \"" << tempStr.data() << L"\""; 151 | } 152 | */ 153 | 154 | if (sdiGetProp(m_info, tempStr, &devInfoData, &DEVPKEY_Device_DriverDesc, curInfo->DriverDesc)) 155 | { 156 | dStr << curInfo->DriverDesc; 157 | } 158 | 159 | if (sdiGetProp(m_info, tempStr, &devInfoData, &DEVPKEY_Device_DeviceDesc, curInfo->DeviceDesc)) 160 | { 161 | if (curInfo->DeviceDesc != curInfo->DriverDesc) 162 | { 163 | dStr << L", (" << curInfo->DeviceDesc << ")"; 164 | } 165 | } 166 | else 167 | { 168 | DWORD err = GetLastError(); 169 | dStr << L",(DEVPKEY_Device_DeviceDesc: " << GetErrorCodeStr(err) << ")"; 170 | } 171 | 172 | if (sdiGetProp(m_info, tempStr, &devInfoData, &DEVPKEY_Device_DriverVersion, curInfo->DriverVersion)) 173 | { 174 | dStr << L", " << curInfo->DriverVersion; 175 | } 176 | 177 | FILETIME fileTime{}; 178 | SYSTEMTIME sysTime{}; 179 | if (SetupDiGetDevicePropertyW( 180 | m_info, 181 | &devInfoData, 182 | &DEVPKEY_Device_DriverDate, 183 | &PropType, 184 | (PBYTE)&fileTime, 185 | sizeof(FILETIME), 186 | nullptr, 187 | 0)) 188 | { 189 | curInfo->DriverDate = fileTime; 190 | SYSTEMTIME curSysTime; 191 | GetSystemTime(&curSysTime); 192 | if (FileTimeToSystemTime(&fileTime, &sysTime)) 193 | { 194 | dStr << L", " << sysTime.wMonth << L"/" << sysTime.wDay << L"/" << sysTime.wYear; 195 | float yearsCur = curSysTime.wYear + curSysTime.wMonth / 12.0f + curSysTime.wDay / 365.25f; 196 | float yearsDriver = sysTime.wYear + sysTime.wMonth / 12.0f + sysTime.wDay / 365.25f; 197 | auto oldPrec = dStr.precision(2); 198 | dStr << L" (" << yearsCur - yearsDriver << " years old)"; 199 | dStr.precision(oldPrec); 200 | } 201 | } 202 | 203 | if (SetupDiGetDevicePropertyW( 204 | m_info, 205 | &devInfoData, 206 | &DEVPKEY_Device_InstallDate, 207 | &PropType, 208 | (PBYTE)&fileTime, 209 | sizeof(FILETIME), 210 | nullptr, 211 | 0)) 212 | { 213 | curInfo->InstallDate = fileTime; 214 | SYSTEMTIME curSysTime; 215 | GetSystemTime(&curSysTime); 216 | if (FileTimeToSystemTime(&fileTime, &sysTime)) 217 | { 218 | dStr << L",InstallDate, " << sysTime.wMonth << L"/" << sysTime.wDay << L"/" << sysTime.wYear; 219 | float yearsCur = curSysTime.wYear + curSysTime.wMonth / 12.0f + curSysTime.wDay / 365.25f; 220 | float yearsDriver = sysTime.wYear + sysTime.wMonth / 12.0f + sysTime.wDay / 365.25f; 221 | auto oldPrec = dStr.precision(2); 222 | dStr << L" (" << yearsCur - yearsDriver << " years old)"; 223 | dStr.precision(oldPrec); 224 | } 225 | } 226 | 227 | if (sdiGetProp(m_info, tempStr, &devInfoData, &DEVPKEY_Device_InstanceId, curInfo->DeviceInstanceId)) 228 | { 229 | dStr << L"(" << tempStr.data() << L") "; 230 | } 231 | 232 | /* 233 | if (SetupDiGetDevicePropertyW( 234 | m_info, 235 | &devInfoData, 236 | &DEVPKEY_Device_Service, 237 | &PropType, 238 | (PBYTE)tempStr.data(), 239 | (DWORD)tempStr.size(), 240 | &nameSize, 241 | 0)) 242 | { 243 | // With filter as PCI, should never be "SWD" or other indicator of software service 244 | dStr << L" service = \"" << tempStr.data() << L"\""; 245 | } 246 | */ 247 | 248 | if (SetupDiGetDevicePropertyW( 249 | m_info, 250 | &devInfoData, 251 | &DEVPKEY_Device_LocationInfo, 252 | &PropType, 253 | (PBYTE)tempStr.data(), 254 | (DWORD)tempStr.size(), 255 | &nameSize, 256 | 0)) 257 | { 258 | dStr << L" at \"" << tempStr.data() << L"\""; 259 | bool locValid = curInfo->LocationInfo.GetFromWStr(tempStr.data()); 260 | if (!locValid) 261 | { 262 | dStr << " ** Error parsing location!\n"; 263 | continue; 264 | } 265 | } 266 | 267 | // For Intel, this might be an unofficial way to find the "GT Generation" 268 | if (sdiGetProp(m_info, tempStr, &devInfoData, &DEVPKEY_Device_DriverInfSection, curInfo->DriverInfSection)) 269 | { 270 | dStr << ", Inf Section = " << curInfo->DriverInfSection; 271 | } 272 | 273 | LUID curLUID{}; 274 | HYBRIDDETECT_DEBUG_REQUIRE(*(UI64*)&curInfo->DeviceLUID == 0ULL); 275 | if (SetupDiGetDevicePropertyW( 276 | m_info, 277 | &devInfoData, 278 | &DEVPROPKEY_DISPLAY_ADAPTER_LUID, 279 | &PropType, 280 | (PBYTE)&curLUID, 281 | (DWORD)sizeof(LUID), 282 | &nameSize, 283 | 0) && (nameSize == sizeof(LUID))) 284 | { 285 | curInfo->DeviceLUID = curLUID; 286 | dStr << ", LUID = " << std::hex << *(UI64*)&curLUID << std::dec; 287 | } 288 | 289 | outInfos.emplace_back(std::move(curInfo)); 290 | dStr << std::endl; 291 | 292 | } // while 293 | 294 | if (m_info) 295 | { 296 | SetupDiDestroyDeviceInfoList(m_info); 297 | } 298 | return true; 299 | } 300 | } // private ns 301 | 302 | SetupDeviceInfo::SetupDeviceInfo() 303 | { 304 | getInfoForClass(&GUID_DEVCLASS_DISPLAY, m_DevInfoPtrs); 305 | getInfoForClass(&GUID_DEVCLASS_COMPUTEACCELERATOR, m_DevInfoPtrs); 306 | } 307 | 308 | const DriverInfoPtr SetupDeviceInfo::getByLUID(const UI64 inLUID) const 309 | { 310 | for (const auto& info : m_DevInfoPtrs) 311 | { 312 | UI64 curLUID = LuidToUI64(info->DeviceLUID); 313 | if (curLUID && (inLUID == curLUID)) 314 | { 315 | return info; 316 | } 317 | } 318 | return nullptr; 319 | } 320 | 321 | const DriverInfoPtr SetupDeviceInfo::getAtAddress(const PCIAddressType& inAddress) const 322 | { 323 | for (const auto& info : m_DevInfoPtrs) 324 | { 325 | if (inAddress == info->LocationInfo) 326 | { 327 | return info; 328 | } 329 | } 330 | return nullptr; 331 | } 332 | 333 | const DriverInfoPtr SetupDeviceInfo::getByName(const WString& inName) const 334 | { 335 | for (const auto& info : m_DevInfoPtrs) 336 | { 337 | if ((inName == info->DriverDesc) || (inName == info->DeviceDesc)) 338 | { 339 | return info; 340 | } 341 | } 342 | return nullptr; 343 | } 344 | 345 | SetupDeviceInfo::~SetupDeviceInfo() 346 | { 347 | } 348 | 349 | } // XI 350 | #else 351 | // Build stub so we don't have to change interface 352 | #include "LibXPUInfo.h" 353 | XI::SetupDeviceInfo::~SetupDeviceInfo() {} 354 | #endif // XPUINFO_USE_SETUPAPI 355 | -------------------------------------------------------------------------------- /LibXPUInfo_TelemetryTracker.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2024 Intel Corporation 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | #ifdef XPUINFO_USE_TELEMETRYTRACKER 5 | #include "LibXPUInfo.h" 6 | #include "LibXPUInfo_Util.h" 7 | #ifdef _WIN32 8 | #include 9 | #include 10 | #include 11 | #pragma comment(lib, "pdh") 12 | #endif // _WIN32 13 | 14 | #include 15 | 16 | namespace XI 17 | { 18 | 19 | void TelemetryTracker::printRecordHeader(std::ostream& ostr) const 20 | { 21 | ostr << "Time(s)"; 22 | #if defined(_WIN32) && !defined(_M_ARM64) 23 | ostr << ", %CPU, CPU Freq (MHz), GPU Local Mem Used (GB), GPU Shared Mem (GB), GPU Dedicated Mem (GB), GPU Total Mem (GB)"; 24 | #endif 25 | if (m_ResultMask & TELEMETRYITEM_FREQUENCY) 26 | ostr << ", Freq(MHz)"; 27 | bool haveBW = (m_ResultMask & (TELEMETRYITEM_READ_BW | TELEMETRYITEM_WRITE_BW)) == (TELEMETRYITEM_READ_BW | TELEMETRYITEM_WRITE_BW); 28 | if (haveBW) 29 | { 30 | ostr << ",Rd BW(MB/s),Wr BW(MB/s),BW(MB/s)"; 31 | } 32 | if (m_ResultMask & TELEMETRYITEM_GLOBAL_ACTIVITY) 33 | ostr << ",% Global"; 34 | if (m_ResultMask & TELEMETRYITEM_RENDER_COMPUTE_ACTIVITY) 35 | ostr << ",% Compute"; 36 | if (m_ResultMask & TELEMETRYITEM_MEDIA_ACTIVITY) 37 | ostr << ",% Media"; 38 | if (m_ResultMask & TELEMETRYITEM_MEMORY_USAGE) 39 | ostr << ",Device Memory Used (MB)"; 40 | if (m_ResultMask & TELEMETRYITEM_FREQUENCY_MEDIA) 41 | ostr << ",Media Freq (MHz)"; 42 | if (m_ResultMask & TELEMETRYITEM_FREQUENCY_MEMORY) 43 | ostr << ",Memory Freq (GT/s)"; 44 | if (m_ResultMask & TELEMETRYITEM_SYSTEMMEMORY) 45 | ostr << ",Physical System Memory Available (GB),Commit Total (GB),Commit Limit (GB),Commit Peak (GB)"; 46 | 47 | ostr << std::endl; 48 | } 49 | 50 | UI64 TelemetryTracker::getMaxMemUsage() const 51 | { 52 | UI64 maxMemUsage = 0; 53 | for (const auto& rec : m_records) 54 | { 55 | maxMemUsage = std::max(maxMemUsage, rec.deviceMemoryUsedBytes); 56 | } 57 | return maxMemUsage; 58 | } 59 | 60 | UI64 TelemetryTracker::getInitialMemUsage() const 61 | { 62 | UI64 memUsage = 0; 63 | if (m_records.size()) 64 | { 65 | memUsage = m_records.front().deviceMemoryUsedBytes; 66 | } 67 | return memUsage; 68 | } 69 | 70 | const DevicePtr& TelemetryTracker::getDevice() const 71 | { 72 | return m_Device; 73 | } 74 | 75 | void TelemetryTracker::printRecord(TimedRecords::const_iterator it, std::ostream& ostr) const 76 | { 77 | const auto& rec = *it; 78 | const auto default_precision{ ostr.precision() }; 79 | 80 | if (m_ResultMask & TELEMETRYITEM_TIMESTAMP_DOUBLE) 81 | { 82 | ostr << rec.timeStamp - m_startTime; 83 | } 84 | else 85 | { 86 | XPUINFO_REQUIRE(m_timestamp_freq != 0); 87 | auto elapsed_Secs = (rec.timeStampUI64 - m_startTimeUI64) / double(m_timestamp_freq); 88 | ostr << elapsed_Secs; 89 | } 90 | 91 | #if defined(_WIN32) && !defined(_M_ARM64) 92 | ostr << "," << rec.pctCPU << "," << rec.cpu_freq / (100.0); 93 | ostr << "," << rec.gpu_mem_Local / (1024.0 * 1024 * 1024); 94 | ostr << "," << rec.gpu_mem_Adapter_Shared / (1024.0 * 1024 * 1024); 95 | ostr << "," << rec.gpu_mem_Adapter_Dedicated / (1024.0 * 1024 * 1024); 96 | ostr << "," << rec.gpu_mem_Adapter_Total / (1024.0 * 1024 * 1024); 97 | #endif 98 | 99 | if (m_ResultMask & TELEMETRYITEM_FREQUENCY) 100 | { 101 | ostr << "," << rec.freq; 102 | } 103 | bool haveBW = (m_ResultMask & (TELEMETRYITEM_READ_BW | TELEMETRYITEM_WRITE_BW)) == (TELEMETRYITEM_READ_BW | TELEMETRYITEM_WRITE_BW); 104 | if ((it - m_records.begin()) > 0) 105 | { 106 | const auto& prev = *(it - 1); 107 | double tDelta = rec.timeStamp - prev.timeStamp; 108 | 109 | if (haveBW) 110 | { 111 | UI64 rdDelta = rec.bw_read - prev.bw_read; 112 | UI64 wrDelta = rec.bw_write - prev.bw_write; 113 | UI64 bwDelta = rdDelta + wrDelta; 114 | ostr << "," << rdDelta / (tDelta * (1024 * 1024)); 115 | ostr << "," << wrDelta / (tDelta * (1024 * 1024)); 116 | ostr << "," << bwDelta / (tDelta * (1024 * 1024)); 117 | } 118 | if ((m_ResultMask & (TELEMETRYITEM_GLOBAL_ACTIVITY | TELEMETRYITEM_TIMESTAMP_DOUBLE)) == (TELEMETRYITEM_GLOBAL_ACTIVITY | TELEMETRYITEM_TIMESTAMP_DOUBLE)) 119 | { 120 | ostr << "," << (rec.activity_global - prev.activity_global) * 100. / tDelta; 121 | } 122 | if ((m_ResultMask & (TELEMETRYITEM_RENDER_COMPUTE_ACTIVITY | TELEMETRYITEM_TIMESTAMP_DOUBLE)) == (TELEMETRYITEM_RENDER_COMPUTE_ACTIVITY | TELEMETRYITEM_TIMESTAMP_DOUBLE)) 123 | { 124 | ostr << "," << (rec.activity_compute - prev.activity_compute) * 100. / tDelta; 125 | } 126 | if ((m_ResultMask & (TELEMETRYITEM_MEDIA_ACTIVITY | TELEMETRYITEM_TIMESTAMP_DOUBLE)) == (TELEMETRYITEM_MEDIA_ACTIVITY | TELEMETRYITEM_TIMESTAMP_DOUBLE)) 127 | { 128 | ostr << "," << (rec.activity_media - prev.activity_media) * 100. / tDelta; 129 | } 130 | } 131 | else 132 | { 133 | if (haveBW) 134 | { 135 | ostr << ",,,"; 136 | } 137 | } 138 | if (m_ResultMask & TELEMETRYITEM_GLOBAL_ACTIVITY) 139 | { 140 | if (!(m_ResultMask & TELEMETRYITEM_TIMESTAMP_DOUBLE)) 141 | { 142 | ostr << "," << rec.activity_global; 143 | } 144 | else if ((it - m_records.begin()) == 0) 145 | { 146 | ostr << ","; 147 | } 148 | } 149 | if (m_ResultMask & TELEMETRYITEM_RENDER_COMPUTE_ACTIVITY) 150 | { 151 | if (!(m_ResultMask & TELEMETRYITEM_TIMESTAMP_DOUBLE)) 152 | { 153 | ostr << "," << rec.activity_compute; 154 | } 155 | else if ((it - m_records.begin()) == 0) 156 | { 157 | ostr << ","; 158 | } 159 | } 160 | if (m_ResultMask & TELEMETRYITEM_MEDIA_ACTIVITY) 161 | { 162 | if ((it - m_records.begin()) == 0) 163 | { 164 | ostr << ","; 165 | } 166 | } 167 | if (m_ResultMask & TELEMETRYITEM_MEMORY_USAGE) 168 | { 169 | //ostr << "," << 100.0 * rec.deviceMemoryUsedBytes / (rec.deviceMemoryBudgetBytes); 170 | ostr << "," << (rec.deviceMemoryUsedBytes) / (1024.0 * 1024); 171 | } 172 | 173 | if (m_ResultMask & TELEMETRYITEM_FREQUENCY_MEDIA) 174 | { 175 | ostr << "," << (rec.freq_media); 176 | } 177 | if (m_ResultMask & TELEMETRYITEM_FREQUENCY_MEMORY) 178 | { 179 | ostr << "," << std::setprecision(3) << (rec.freq_memory / 1000.0) << std::setprecision(default_precision); 180 | } 181 | if (m_ResultMask & TELEMETRYITEM_SYSTEMMEMORY) 182 | { 183 | SaveRestoreIOSFlags saveFlags(ostr); 184 | ostr << "," << std::setprecision(5) << (rec.systemMemoryPhysicalAvailable / (1024.0 * 1024 * 1024)) 185 | << "," << (rec.systemMemoryCommitTotal / (1024.0 * 1024 * 1024)) 186 | << "," << (rec.systemMemoryCommitLimit / (1024.0 * 1024 * 1024)) 187 | << "," << (rec.systemMemoryCommitPeak / (1024.0 * 1024 * 1024)) 188 | ; 189 | } 190 | 191 | ostr << std::endl; 192 | } 193 | 194 | String TelemetryTracker::getLog() const 195 | { 196 | std::ostringstream ostr; 197 | ostr << "Stats for " << convert(m_Device->name()) << " (" << m_msPeriod << "ms interval):" << std::endl; 198 | printRecordHeader(ostr); 199 | if (m_records.size()) 200 | { 201 | for (TimedRecords::const_iterator it = m_records.begin(); it != m_records.end(); ++it) 202 | { 203 | printRecord(it, ostr); 204 | } 205 | } 206 | else 207 | { 208 | ostr << "TelemetryTracker: No records!\n"; 209 | } 210 | 211 | return ostr.str(); 212 | } 213 | 214 | TelemetryTracker::TelemetryTracker(const DevicePtr& deviceToTrack, UI32 msPeriod, std::ostream* pRealTimeOutputStream): 215 | m_Device(deviceToTrack), m_msPeriod(msPeriod), 216 | m_ResultMask(TELEMETRYITEM_UNKNOWN), 217 | m_pRealtime_ostr(pRealTimeOutputStream) 218 | { 219 | #if defined(_WIN32) && !defined(_M_ARM64) 220 | InitPDH(); 221 | 222 | if (m_Device->getCurrentAPIs() & (API_TYPE_IGCL|API_TYPE_LEVELZERO|API_TYPE_DXCORE)) 223 | { 224 | m_records.reserve(1024); 225 | 226 | InitializeThreadpoolEnvironment(&m_CallBackEnviron); 227 | 228 | // Create a cleanup group for this thread pool. 229 | m_cleanupgroup = CreateThreadpoolCleanupGroup(); 230 | 231 | // Create a timer with the same callback environment. 232 | m_timer = CreateThreadpoolTimer(MyTimerCallback, 233 | this, 234 | &m_CallBackEnviron); 235 | 236 | if (nullptr == m_timer) { 237 | printf("CreateThreadpoolTimer failed. LastError: %lu\n", 238 | GetLastError()); 239 | } 240 | } 241 | 242 | if ((m_Device->getCurrentAPIs() & API_TYPE_IGCL) == 0) 243 | { 244 | BOOL bRet = QueryPerformanceFrequency((LARGE_INTEGER*)&m_timestamp_freq); 245 | XPUINFO_REQUIRE(bRet); 246 | } 247 | 248 | #ifdef XPUINFO_USE_IGCL 249 | if ((m_Device->getCurrentAPIs() & (API_TYPE_IGCL|API_TYPE_IGCL_L0)) == (API_TYPE_IGCL|API_TYPE_IGCL_L0)) 250 | { 251 | InitIGCL(); 252 | } 253 | #endif 254 | 255 | #endif // Win32 256 | 257 | #ifdef XPUINFO_USE_LEVELZERO 258 | if (m_Device->getCurrentAPIs() & API_TYPE_LEVELZERO) 259 | { 260 | InitL0(); 261 | } 262 | #endif 263 | } 264 | 265 | TelemetryTracker::~TelemetryTracker() noexcept(false) 266 | { 267 | stop(); 268 | // 269 | // Wait for all callbacks to finish. 270 | // CloseThreadpoolCleanupGroupMembers also releases objects 271 | // that are members of the cleanup group, so it is not necessary 272 | // to call close functions on individual objects 273 | // after calling CloseThreadpoolCleanupGroupMembers. 274 | // 275 | #if defined(_WIN32) && !defined(_M_ARM64) 276 | if (m_pdhQuery) 277 | { 278 | PDH_STATUS pdhs = PdhCloseQuery(m_pdhQuery); 279 | XPUINFO_REQUIRE(ERROR_SUCCESS == pdhs); 280 | } 281 | 282 | if (m_timer) 283 | { 284 | CloseThreadpoolTimer(m_timer); 285 | } 286 | 287 | if (m_cleanupgroup) 288 | { 289 | CloseThreadpoolCleanupGroupMembers(m_cleanupgroup, 290 | FALSE, 291 | nullptr); 292 | // Clean up the cleanup group. 293 | CloseThreadpoolCleanupGroup(m_cleanupgroup); 294 | } 295 | #endif 296 | if (m_pRealtime_ostr) { 297 | (*m_pRealtime_ostr) << std::flush; 298 | } 299 | } 300 | 301 | void TelemetryTracker::start() 302 | { 303 | #if defined(_WIN32) && !defined(_M_ARM64) 304 | if (m_timer && m_msPeriod) 305 | { 306 | // Set the timer to fire now 307 | FILETIME FileDueTime = { 0 }; 308 | 309 | SetThreadpoolTimer(m_timer, 310 | &FileDueTime, 311 | m_msPeriod, 312 | 0); 313 | } 314 | #endif 315 | } 316 | 317 | void TelemetryTracker::stop() 318 | { 319 | #if defined(_WIN32) && !defined(_M_ARM64) 320 | if (m_timer) 321 | { 322 | SetThreadpoolTimer(m_timer, 323 | nullptr, 324 | 0, 325 | 0); 326 | 327 | WaitForThreadpoolTimerCallbacks(m_timer, TRUE); 328 | } 329 | #endif 330 | } 331 | 332 | bool TelemetryTracker::RecordCPUTimestamp(TimedRecord& rec) 333 | { 334 | // See std::chrono 335 | #if defined(_WIN32) && !defined(_M_ARM64) 336 | BOOL bRet = QueryPerformanceCounter((LARGE_INTEGER*)&rec.timeStampUI64); 337 | XPUINFO_REQUIRE(bRet); 338 | #else 339 | bool bRet = false; 340 | #endif 341 | 342 | if (m_records.size() == 0) 343 | { 344 | m_startTimeUI64 = rec.timeStampUI64; 345 | } 346 | 347 | return !!bRet; 348 | } 349 | 350 | bool TelemetryTracker::RecordMemoryUsage(TimedRecord& rec) 351 | { 352 | #ifdef _WIN32 353 | // Note: If we want process-specific info, see these APIs: 354 | // GetProcessMemoryInfo /PROCESS_MEMORY_COUNTERS_EX2 -- See https://learn.microsoft.com/en-us/windows/win32/psapi/enumerating-all-processes?redirectedfrom=MSDN 355 | // GlobalMemoryStatusEx 356 | 357 | PERFORMANCE_INFORMATION pi; 358 | if (GetPerformanceInfo(&pi, sizeof(pi))) 359 | { 360 | rec.systemMemoryPhysicalAvailable = pi.PhysicalAvailable * pi.PageSize; 361 | rec.systemMemoryCommitTotal = pi.CommitTotal * pi.PageSize; 362 | rec.systemMemoryCommitLimit = pi.CommitLimit * pi.PageSize; 363 | rec.systemMemoryCommitPeak = pi.CommitPeak * pi.PageSize; 364 | 365 | if (!(m_ResultMask & TELEMETRYITEM_SYSTEMMEMORY)) 366 | { 367 | m_ResultMask = (TelemetryItem)(m_ResultMask | TELEMETRYITEM_SYSTEMMEMORY); 368 | } 369 | } 370 | #endif 371 | 372 | auto memusage = m_Device->getMemUsage(); 373 | if (memusage.currentUsage) 374 | { 375 | rec.deviceMemoryUsedBytes = memusage.currentUsage; 376 | rec.deviceMemoryBudgetBytes = memusage.budget; 377 | if (!(m_ResultMask & TELEMETRYITEM_MEMORY_USAGE)) 378 | { 379 | m_ResultMask = (TelemetryItem)(m_ResultMask | TELEMETRYITEM_MEMORY_USAGE); 380 | } 381 | return true; 382 | } 383 | return false; 384 | } 385 | 386 | void TelemetryTracker::RecordNow() 387 | { 388 | TimedRecord rec{}; 389 | bool bUpdate = false; 390 | std::lock_guard lock(m_RecordMutex); // for now, only support one at a time 391 | 392 | // Frequency, throttleReason (L0, IGCL) 393 | // Memory (VRAM) read/write/timestamp (IGCL) 394 | // Engine Utilization (IGCL, PDH/perfmon) 395 | // PCIe bandwidth (IGCL, L0 zes_pci_state_t, zes_pci_stats_t) 396 | 397 | // IGCL: 398 | // * Freq 399 | // * VRAM Read BW 400 | // * VRAM Write BW 401 | 402 | if (m_Device->getCurrentAPIs() & API_TYPE_DXCORE) 403 | { 404 | bUpdate = RecordMemoryUsage(rec) || bUpdate; 405 | } 406 | 407 | #ifdef XPUINFO_USE_IGCL 408 | if (m_Device->getCurrentAPIs() & API_TYPE_IGCL) 409 | { 410 | bUpdate = RecordIGCL(rec) || bUpdate; 411 | } 412 | #endif // XPUINFO_USE_IGCL 413 | 414 | #if defined(_WIN32) && !defined(_M_ARM64) 415 | bUpdate = RecordCPU_PDH(rec) || bUpdate; 416 | #endif 417 | 418 | #ifdef XPUINFO_USE_LEVELZERO 419 | if (m_Device->getCurrentAPIs() & API_TYPE_LEVELZERO) 420 | { 421 | bool bL0 = RecordL0(rec); 422 | bUpdate = bL0 || bUpdate; 423 | } 424 | #endif 425 | 426 | #ifdef XPUINFO_USE_NVML 427 | if (m_Device->getCurrentAPIs() & API_TYPE_NVML) 428 | { 429 | bUpdate = RecordNVML(rec) || bUpdate; 430 | } 431 | #endif 432 | 433 | if (bUpdate) 434 | { 435 | if (!(m_Device->getCurrentAPIs() & API_TYPE_IGCL)) // Need CPU timestamp 436 | { 437 | RecordCPUTimestamp(rec); 438 | } 439 | 440 | m_records.push_back(rec); 441 | if (m_pRealtime_ostr) 442 | { 443 | if (m_records.size() == 1) 444 | { 445 | printRecordHeader(*m_pRealtime_ostr); 446 | } 447 | printRecord(m_records.end()-1, *m_pRealtime_ostr); 448 | } 449 | } 450 | } 451 | 452 | #if defined(_WIN32) && !defined(_M_ARM64) 453 | static std::string getLuidStringForPDH(const LUID& luid) 454 | { 455 | std::ostringstream luidStream; 456 | luidStream << std::hex << std::setw(8) << std::setfill('0') << std::uppercase << luid.HighPart << 457 | "_0x" << std::setw(8) << std::setfill('0') << luid.LowPart; 458 | return luidStream.str(); 459 | } 460 | 461 | void TelemetryTracker::InitPDH() 462 | { 463 | static const char counterCPU_T[] = "\\Processor(_Total)\\% Processor Time"; 464 | /* Processor Utility is the amount of work a processor is completing, 465 | as a percentage of the amount of work the processor could complete 466 | if it were running at its nominal performanceand never idle. 467 | On some processors, Processor Utility may exceed 100 % . 468 | */ 469 | static const char counterCPU_Utility[] = "\\Processor Information(_Total)\\% Processor Utility"; // Matches Win10 task manager CPU %Utilization 470 | static const char counterCPU_Freq[] = "\\Processor Information(_Total)\\Processor Frequency"; 471 | static const char counterCPU_PctPerf[] = "\\Processor Information(_Total)\\% Processor Performance"; 472 | //"\\GPU Adapter Memory(luid_0x00000000_0x00013E1A_phys_0)\Total Committed" 473 | static const char* counterGPU_Memory = "\\GPU Adapter Memory(luid_0x"; 474 | static const char* counterGPU_Memory_Shared = "*)\\Shared Usage"; 475 | static const char* counterGPU_Memory_Dedicated = "*)\\Dedicated Usage"; 476 | static const char* counterGPU_Memory_Total = "*)\\Total Committed"; 477 | static const char* counterGPULocal_Memory[] = { "\\GPU Local Adapter Memory(luid_0x", "*)\\Local Usage" }; 478 | 479 | std::string luidPdhStr(getLuidStringForPDH(getDevice()->getLUIDAsStruct())); 480 | std::string gpuMemoryLocalCounterPath = counterGPULocal_Memory[0] + luidPdhStr + counterGPULocal_Memory[1]; 481 | std::string gpuMemSharedCounterPath = counterGPU_Memory + luidPdhStr + counterGPU_Memory_Shared; 482 | std::string gpuMemDedicatedCounterPath = counterGPU_Memory + luidPdhStr + counterGPU_Memory_Dedicated; 483 | std::string gpuMemTotalCounterPath = counterGPU_Memory + luidPdhStr + counterGPU_Memory_Total; 484 | 485 | PDH_STATUS pdhs = PdhOpenQueryA(nullptr, 0, &m_pdhQuery); 486 | if (pdhs == ERROR_SUCCESS) 487 | { 488 | // static syntax: \\Computer\PerfObject(ParentInstance/ObjectInstance#InstanceIndex)\Counter 489 | pdhs = PdhAddCounterA(m_pdhQuery, counterCPU_Utility, 0, &m_pdhCtrCPU); 490 | XPUINFO_REQUIRE(ERROR_SUCCESS == pdhs); 491 | 492 | pdhs = PdhAddCounterA(m_pdhQuery, counterCPU_Freq, 0, &m_pdhCtrCPUFreq); 493 | XPUINFO_REQUIRE(ERROR_SUCCESS == pdhs); 494 | 495 | pdhs = PdhAddCounterA(m_pdhQuery, counterCPU_PctPerf, 0, &m_pdhCtrCPUPctPerf); 496 | XPUINFO_REQUIRE(ERROR_SUCCESS == pdhs); 497 | 498 | pdhs = PdhAddCounterA(m_pdhQuery, gpuMemoryLocalCounterPath.c_str(), 0, &m_pdhCtrGPUMemLocal); 499 | XPUINFO_REQUIRE(ERROR_SUCCESS == pdhs); 500 | 501 | pdhs = PdhAddCounterA(m_pdhQuery, gpuMemSharedCounterPath.c_str(), 0, &m_pdhCtrGPUAdapterMemShared); 502 | XPUINFO_REQUIRE(ERROR_SUCCESS == pdhs); 503 | 504 | pdhs = PdhAddCounterA(m_pdhQuery, gpuMemDedicatedCounterPath.c_str(), 0, &m_pdhCtrGPUAdapterMemDedicated); 505 | XPUINFO_REQUIRE(ERROR_SUCCESS == pdhs); 506 | 507 | pdhs = PdhAddCounterA(m_pdhQuery, gpuMemTotalCounterPath.c_str(), 0, &m_pdhCtrGPUAdapterMemTotal); 508 | XPUINFO_REQUIRE(ERROR_SUCCESS == pdhs); 509 | 510 | // The first query does not return valid data, so do it here. 511 | pdhs = PdhCollectQueryData(m_pdhQuery); 512 | XPUINFO_REQUIRE(ERROR_SUCCESS == pdhs); 513 | } 514 | } 515 | 516 | bool TelemetryTracker::RecordCPU_PDH(TimedRecord& rec) 517 | { 518 | PDH_STATUS pdhs = PdhCollectQueryData(m_pdhQuery); // Collects the current raw data value for all counters in the specified query and updates the status code of each counter. 519 | if (ERROR_SUCCESS == pdhs) 520 | { 521 | PDH_FMT_COUNTERVALUE DisplayValue; 522 | DWORD CounterType; 523 | 524 | pdhs = PdhGetFormattedCounterValue(m_pdhCtrCPU, 525 | PDH_FMT_DOUBLE, 526 | &CounterType, 527 | &DisplayValue); 528 | if (ERROR_SUCCESS != pdhs) 529 | { 530 | return false; 531 | } 532 | rec.pctCPU = DisplayValue.doubleValue; 533 | 534 | // This freq is constant, multiply by %Perf to match task manager 535 | pdhs = PdhGetFormattedCounterValue(m_pdhCtrCPUFreq, 536 | PDH_FMT_DOUBLE, 537 | &CounterType, 538 | &DisplayValue); 539 | if (ERROR_SUCCESS != pdhs) 540 | { 541 | return false; 542 | } 543 | rec.cpu_freq = DisplayValue.doubleValue; 544 | 545 | pdhs = PdhGetFormattedCounterValue(m_pdhCtrCPUPctPerf, 546 | PDH_FMT_DOUBLE, 547 | &CounterType, 548 | &DisplayValue); 549 | if (ERROR_SUCCESS != pdhs) 550 | { 551 | return false; 552 | } 553 | rec.cpu_freq *= DisplayValue.doubleValue; 554 | 555 | pdhs = PdhGetFormattedCounterValue(m_pdhCtrGPUMemLocal, 556 | PDH_FMT_DOUBLE, 557 | &CounterType, 558 | &DisplayValue); 559 | if (ERROR_SUCCESS != pdhs) 560 | { 561 | return false; 562 | } 563 | rec.gpu_mem_Local = DisplayValue.doubleValue; 564 | 565 | pdhs = PdhGetFormattedCounterValue(m_pdhCtrGPUAdapterMemTotal, 566 | PDH_FMT_DOUBLE, 567 | &CounterType, 568 | &DisplayValue); 569 | if (ERROR_SUCCESS != pdhs) 570 | { 571 | return false; 572 | } 573 | rec.gpu_mem_Adapter_Total = DisplayValue.doubleValue; 574 | 575 | pdhs = PdhGetFormattedCounterValue(m_pdhCtrGPUAdapterMemShared, 576 | PDH_FMT_DOUBLE, 577 | &CounterType, 578 | &DisplayValue); 579 | if (ERROR_SUCCESS != pdhs) 580 | { 581 | return false; 582 | } 583 | rec.gpu_mem_Adapter_Shared = DisplayValue.doubleValue; 584 | 585 | pdhs = PdhGetFormattedCounterValue(m_pdhCtrGPUAdapterMemDedicated, 586 | PDH_FMT_DOUBLE, 587 | &CounterType, 588 | &DisplayValue); 589 | if (ERROR_SUCCESS != pdhs) 590 | { 591 | return false; 592 | } 593 | rec.gpu_mem_Adapter_Dedicated = DisplayValue.doubleValue; 594 | 595 | return true; 596 | } 597 | return false; 598 | } 599 | #endif 600 | 601 | } // XI 602 | #endif // XPUINFO_USE_TELEMETRYTRACKER 603 | -------------------------------------------------------------------------------- /LibXPUInfo_Util.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2024 Intel Corporation 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | // These contents may have been developed with support from one or more Intel-operated generative artificial intelligence solutions 5 | 6 | #ifndef _SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING 7 | #define _SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING 8 | #endif 9 | #include "LibXPUInfo.h" 10 | #include 11 | #include 12 | #include 13 | 14 | namespace XI 15 | { 16 | XPUINFO_EXPORT std::string convert(const std::wstring& wstr) 17 | { 18 | std::wstring_convert> converter; 19 | return converter.to_bytes(wstr); 20 | } 21 | 22 | XPUINFO_EXPORT std::wstring convert(const std::string& str) 23 | { 24 | std::wstring_convert> converter; 25 | return converter.from_bytes(str); 26 | } 27 | 28 | std::string toLower(const std::string& s) 29 | { 30 | std::string data; 31 | data.resize(s.size()); 32 | for (size_t i = 0; i < s.size(); ++i) 33 | { 34 | data[i] = static_cast(std::tolower(s.data()[i])); 35 | } 36 | return data; 37 | } 38 | 39 | std::wstring toLower(const std::wstring& s) 40 | { 41 | std::wstring data; 42 | data.resize(s.size()); 43 | for (size_t i = 0; i < s.size(); ++i) 44 | { 45 | data[i] = std::towlower(s.data()[i]); 46 | } 47 | return data; 48 | } 49 | 50 | #ifdef _WIN32 51 | namespace Win 52 | { 53 | String GetLastErrorStr(DWORD dwErr) 54 | { 55 | String errStr; 56 | // Retrieve the system error message for the last-error code 57 | 58 | LPVOID lpMsgBuf; 59 | 60 | FormatMessageA( 61 | FORMAT_MESSAGE_ALLOCATE_BUFFER | 62 | FORMAT_MESSAGE_FROM_SYSTEM | 63 | FORMAT_MESSAGE_IGNORE_INSERTS, 64 | nullptr, 65 | dwErr, 66 | MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 67 | (LPSTR)&lpMsgBuf, 68 | 0, nullptr); 69 | 70 | errStr = (LPCSTR)lpMsgBuf; // Copy 71 | LocalFree(lpMsgBuf); 72 | 73 | return errStr; 74 | } 75 | 76 | #pragma comment(lib, "version.lib") 77 | 78 | // Copilot: write function to get dll version, modified for std::optional 79 | std::optional GetDllVersion(const std::string& filePath) { 80 | RuntimeVersion versionInfo; 81 | DWORD handle = 0; 82 | DWORD size = GetFileVersionInfoSizeA(filePath.c_str(), &handle); 83 | if (size == 0) { 84 | return std::nullopt; 85 | } 86 | 87 | std::vector buffer(size); 88 | if (!GetFileVersionInfoA(filePath.c_str(), handle, size, buffer.data())) { 89 | return std::nullopt; 90 | } 91 | 92 | void* verInfo = nullptr; 93 | UINT verInfoSize = 0; 94 | if (VerQueryValueA(buffer.data(), "\\", &verInfo, &verInfoSize) && verInfoSize >= sizeof(VS_FIXEDFILEINFO)) { 95 | VS_FIXEDFILEINFO* fileInfo = static_cast(verInfo); 96 | versionInfo.major = HIWORD(fileInfo->dwProductVersionMS); 97 | versionInfo.minor = LOWORD(fileInfo->dwProductVersionMS); 98 | versionInfo.build = HIWORD(fileInfo->dwProductVersionLS); 99 | } 100 | 101 | if ((verInfoSize >= sizeof(VS_FIXEDFILEINFO)) && 102 | VerQueryValueA(buffer.data(), "\\StringFileInfo\\040904E4\\ProductVersion", &verInfo, &verInfoSize)) { 103 | versionInfo.productVersion = std::string(static_cast(verInfo), verInfoSize - 1); 104 | } 105 | 106 | return versionInfo; 107 | } 108 | 109 | bool GetVersionFromFile(const String& filePath, RuntimeVersion& fileVer) 110 | { 111 | auto rval = GetDllVersion(filePath); 112 | if (rval.has_value()) 113 | { 114 | fileVer = std::move(rval.value()); 115 | return true; 116 | } 117 | return false; 118 | } 119 | 120 | XPUINFO_EXPORT std::string getDateString(const FILETIME& ft) 121 | { 122 | SYSTEMTIME stime; 123 | FileTimeToSystemTime(&ft, &stime); 124 | std::string dateStr; 125 | const char fmt[] = "yyyy-MM-dd"; 126 | int rval = GetDateFormatA(LOCALE_INVARIANT, 0, &stime, fmt, nullptr, 0); 127 | if (rval) 128 | { 129 | dateStr.resize(rval - 1); // Don't include null terminator 130 | rval = GetDateFormatA(LOCALE_INVARIANT, 0, &stime, fmt, dateStr.data(), rval); 131 | } 132 | return dateStr; 133 | } 134 | 135 | } // Win 136 | #endif // _WIN32 137 | 138 | } // XI 139 | -------------------------------------------------------------------------------- /LibXPUInfo_Util.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2024 Intel Corporation 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | #pragma once 5 | #include "LibXPUInfo.h" 6 | #ifndef XPUINFO_USE_STD_CHRONO 7 | #ifdef _WIN32 8 | #define XPUINFO_USE_STD_CHRONO 0 9 | #else 10 | #define XPUINFO_USE_STD_CHRONO 1 11 | #endif 12 | #endif 13 | 14 | #if XPUINFO_USE_STD_CHRONO 15 | #include 16 | #endif 17 | 18 | namespace XI 19 | { 20 | #if XPUINFO_USE_STD_CHRONO 21 | typedef std::chrono::high_resolution_clock ClockType; 22 | typedef std::chrono::time_point TimerTickValueType; 23 | typedef std::chrono::nanoseconds TimerDuration; 24 | #else 25 | typedef UI64 TimerTickValueType; 26 | typedef UI64 TimerDuration; 27 | #endif 28 | 29 | template 30 | XI::UI64 reinterpretAsUI64(const T& x) 31 | { 32 | return *reinterpret_cast(&x); 33 | } 34 | 35 | template 36 | void updateIfNotZero(T& dst, const T& src) 37 | { 38 | if (src != T(0)) 39 | { 40 | dst = src; 41 | } 42 | } 43 | 44 | template 45 | void updateIfDstNotSet(T& dst, const T& src) 46 | { 47 | if (dst == T(-1)) 48 | { 49 | dst = src; 50 | } 51 | } 52 | 53 | template 54 | void updateIfDstVal(T& dst, const T& isVal, const T& src) 55 | { 56 | if (dst == isVal) 57 | { 58 | dst = src; 59 | } 60 | } 61 | 62 | template 63 | bool isValidPCIAddr(const T& addr) 64 | { 65 | using namespace XI; 66 | I32 vcnt = 0; 67 | vcnt += (I32(addr.domain) > 0); 68 | vcnt += (I32(addr.bus) > 0); 69 | vcnt += (I32(addr.device) > 0); 70 | vcnt += (I32(addr.function) > 0); 71 | 72 | return (vcnt > 0) && 73 | (addr.domain != -1) && 74 | (addr.bus != -1) && 75 | (addr.device != -1) && 76 | (addr.function != -1); 77 | } 78 | 79 | XPUINFO_EXPORT std::string convert(const std::wstring& inWStr); 80 | XPUINFO_EXPORT std::wstring convert(const std::string& str); 81 | XPUINFO_EXPORT std::string toLower(const std::string& s); 82 | XPUINFO_EXPORT std::wstring toLower(const std::wstring& s); 83 | 84 | typedef TimerTickValueType TimerTick; 85 | 86 | class XPUINFO_EXPORT TimeInterval 87 | { 88 | public: 89 | TimeInterval() : tStart{}, tEnd{} {} 90 | TimeInterval(TimerTick t0, TimerTick t1) : tStart(t0), tEnd(t1) {} 91 | TimerTick tStart; 92 | TimerTick tEnd; 93 | TimerDuration operator()() const { return tEnd - tStart; } 94 | }; 95 | 96 | class XPUINFO_EXPORT Timer 97 | { 98 | public: 99 | static TimerTick GetNow() 100 | { 101 | #if !XPUINFO_USE_STD_CHRONO 102 | TimerTick tcur; 103 | QueryPerformanceCounter((LARGE_INTEGER*)&tcur); 104 | return tcur; 105 | #else 106 | return ClockType::now(); 107 | #endif 108 | } 109 | 110 | static TimerDuration GetScale() 111 | { 112 | #if !XPUINFO_USE_STD_CHRONO 113 | TimerTick tFreq; 114 | QueryPerformanceFrequency((LARGE_INTEGER*)&tFreq); // counts per sec 115 | return tFreq; 116 | #else 117 | using namespace std::literals; 118 | return std::chrono::nanoseconds(1s); 119 | #endif 120 | } 121 | 122 | Timer() : mStart{}, mTotal{} 123 | { 124 | mTimerFrequency = Timer::GetScale(); 125 | #if !XPUINFO_USE_STD_CHRONO 126 | mInvTimerFrequency = mTimerFrequency ? 1.0 / mTimerFrequency : 0.; 127 | #else 128 | mInvTimerFrequency = mTimerFrequency.count() ? 1.0 / mTimerFrequency.count() : 0.; 129 | #endif 130 | } 131 | 132 | void Start() 133 | { 134 | mStart = GetNow(); 135 | } 136 | 137 | void Stop() 138 | { 139 | TimerTick tcur = GetNow(); 140 | auto t = tcur - mStart; 141 | mTotal = mTotal + t; 142 | #if !XPUINFO_USE_STD_CHRONO 143 | mStart = 0; 144 | #endif 145 | } 146 | 147 | void Reset() 148 | { 149 | #if !XPUINFO_USE_STD_CHRONO 150 | mTotal = 0; 151 | mStart = 0; 152 | #else 153 | mTotal = mTotal.zero(); 154 | //TODO: Needed? 155 | //mStart = 0; 156 | #endif 157 | } 158 | 159 | void ResetAndStart() 160 | { 161 | Reset(); 162 | Start(); 163 | } 164 | 165 | TimeInterval GetInterval() { 166 | TimerTick tcur = GetNow(); 167 | return TimeInterval(mStart, tcur); 168 | } 169 | 170 | double GetElapsedSecs() 171 | { 172 | #if !XPUINFO_USE_STD_CHRONO 173 | return mTotal * mInvTimerFrequency; 174 | #else 175 | return mTotal.count() * mInvTimerFrequency; 176 | #endif 177 | } 178 | 179 | static double GetIntervalSecs(const TimeInterval& i) 180 | { 181 | return double(i() / Timer::GetScale()); 182 | } 183 | TimerTick GetStart() const { return mStart; } 184 | private: 185 | TimerTick mStart; 186 | TimerDuration mTotal; 187 | TimerDuration mTimerFrequency; 188 | double mInvTimerFrequency; 189 | }; 190 | 191 | #ifdef _WIN32 192 | namespace Win 193 | { 194 | XPUINFO_EXPORT String GetLastErrorStr(DWORD dwErr); 195 | XPUINFO_EXPORT bool GetVersionFromFile(const String& filePath, RuntimeVersion& fileVer); 196 | XPUINFO_EXPORT std::string getDateString(const FILETIME& ft); 197 | } 198 | #endif // _WIN32 199 | 200 | class L0_Extensions : public std::vector 201 | { 202 | public: 203 | L0_Extensions(size_t inSize); 204 | 205 | const ze_driver_extension_properties_t* find(const char* inExtName) const; 206 | }; 207 | 208 | template< 209 | class CharT, 210 | class Traits = std::char_traits 211 | > 212 | class SaveRestoreIOSFlags 213 | { 214 | public: 215 | typedef std::basic_ios Stream; 216 | SaveRestoreIOSFlags(Stream& s): m_stream(s), m_Flags(s.flags()) {} 217 | ~SaveRestoreIOSFlags() 218 | { 219 | m_stream.setf(m_Flags); 220 | } 221 | 222 | protected: 223 | Stream& m_stream; 224 | const std::ios::fmtflags m_Flags; 225 | }; 226 | 227 | } // XI 228 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # LibXPUInfo 2 | LibXPUInfo coalesces multiple APIs to provide multi-vendor, cross-platform device information in support of optimized device-selection by applications. 3 | 4 | [Click here for LibXPUInfo license](LICENSE.txt). 5 | 6 | ## Platforms (all 64-bit only) 7 | * Supported: 8 | * Windows 10+ (Primary target) 9 | * Not currently supported: 10 | * MacOS X 12+ x64/arm64. (CPU, System, and Metal GPUs only, no explicit NPU information) 11 | * Linux, tested on Ubuntu 20.04. (Limited system and CPU info) 12 | 13 | ## Build Instructions 14 | * Prerequisites: 15 | * LibXPUInfo targets C++14 or greater build environments. 16 | * Install CMake with it in your path. 17 | * Using the Visual Studio Installer, if not already present, add component "C++ x64/x86 Spectre-mitigated libs" for the version of the compiler you are using (i.e. "MSVC v143 - VS 2022") 18 | * Or, remove lines from external/level-zero/CmakeLists.txt that add /Qspectre. Try external\l0_removeSpectre.bat to perform this patch. 19 | 20 | * If you want to accept the licenses of all git submodule dependencies, clone this repository with _--recurse-submodules_ to get dependencies which will be placed in folder _external/_. Otherwise, modify .gitmodules to remove unwanted dependencies, and remove the corresponding LIBXPUINFO_USE_* preprocessor definitions. 21 | * Git submodules 22 | * Intel Graphics Control Library (IGCL) - [License](https://github.com/intel/drivers.gpu.control-library/blob/master/License.txt) 23 | * Level Zero Loader - [License](https://github.com/oneapi-src/level-zero/blob/master/LICENSE) 24 | * See above note regarding Spectre-mitigated libs 25 | * OpenCL-CLHPP - [License](https://github.com/KhronosGroup/OpenCL-CLHPP/blob/main/LICENSE.txt) 26 | * OpenCL-Headers - [License](https://github.com/KhronosGroup/OpenCL-Headers/blob/main/LICENSE) 27 | * OpenCL-ICD-Loader - [License](https://github.com/KhronosGroup/OpenCL-ICD-Loader/blob/main/LICENSE) 28 | * RapidJSON - [License](https://github.com/Tencent/rapidjson/blob/master/license.txt) 29 | * If not using RapidJSON, remove XPUINFO_USE_RAPIDJSON from LibXPUInfo project and all projects using LibXPUInfo. 30 | 31 | * Windows 32 | * If you want to use nVidia NVML and accept [NVML license](https://developer.download.nvidia.com/compute/cuda/redist/cuda_nvml_dev/LICENSE.txt), run external\getNVMLDep.bat 33 | * If you do not want to use NVML, remove XPUINFO_USE_NVML from preprocessor arguments for LibXPUInfo.vcxproj 34 | * If you want to use OpenCL and accept related Apache-2.0 licenses, run **external/buildExternalDeps_OCL.bat** 35 | * If you want to use Level Zero and accept related MIT license, run **external/buildExternalDeps_L0.bat** 36 | * See above note regarding Spectre-mitigated libs 37 | * Open LibXPUInfo.sln and build 38 | * Note: Modify XPUINFO_USE_* preprocessor flags as desired 39 | * **Note:** If you pull changes that update the Level Zero or OpenCL submodules, run the correspondig buildExternalDeps_*.bat again before building LibXPUInfo. 40 | * MacOS/Linux - Not currently supported. No build config files provided. Use at your own risk - information provided may be incorrect. 41 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | Intel is committed to rapidly addressing security vulnerabilities affecting our customers and providing clear guidance on the solution, impact, severity and mitigation. 3 | 4 | ## Reporting a Vulnerability 5 | Please report any security vulnerabilities in this project [utilizing the guidelines here](https://www.intel.com/content/www/us/en/security-center/vulnerability-handling-guidelines.html). 6 | -------------------------------------------------------------------------------- /TestLibXPUInfo/TestLibXPUInfo.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2024 Intel Corporation 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | #ifndef NOMINMAX 5 | #define NOMINMAX 6 | #endif 7 | #ifndef TESTLIBXPUINFO_STANDALONE 8 | #define TESTLIBXPUINFO_STANDALONE 1 9 | #endif 10 | #include "LibXPUInfo.h" 11 | #include "LibXPUInfo_Util.h" 12 | #include "LibXPUInfo_JSON.h" 13 | #include "utility/LibXPUInfo_D3D12Utility.h" 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | using namespace XI; 20 | 21 | #ifdef XPUINFO_USE_RAPIDJSON 22 | bool getXPUInfoJSON(std::ostream& ostr, const XI::XPUInfoPtr& pXI) 23 | { 24 | if (!ostr.fail()) 25 | { 26 | rapidjson::Document doc; 27 | doc.SetObject(); 28 | 29 | if (pXI->serialize(doc)) 30 | { 31 | rapidjson::OStreamWrapper out(ostr); 32 | rapidjson::PrettyWriter writer(out); 33 | doc.Accept(writer); // Accept() traverses the DOM and generates Handler events. 34 | ostr << std::endl; 35 | return true; 36 | } 37 | } 38 | return false; 39 | } 40 | 41 | bool testWriteJSON(const std::filesystem::path jsonPath) 42 | { 43 | std::filesystem::create_directories(std::filesystem::absolute(jsonPath).parent_path()); // Create if needed 44 | std::ofstream jf(jsonPath); 45 | APIType apis = APIType(XPUINFO_INIT_ALL_APIS | API_TYPE_WMI); 46 | std::cout << "Initializing XPUInfo with APIType = " << apis << "...\n"; 47 | XI::XPUInfoPtr pXI(new XPUInfo(apis)); 48 | 49 | bool result = getXPUInfoJSON(jf, pXI); 50 | if (!result) 51 | { 52 | std::cout << "Error writing " << std::filesystem::absolute(jsonPath) << std::endl; 53 | } 54 | else 55 | { 56 | std::cout << "Wrote " << std::filesystem::absolute(jsonPath) << std::endl; 57 | } 58 | return result; 59 | } 60 | 61 | bool testVerifyJSON() 62 | { 63 | std::ostringstream ostr; 64 | APIType apis = APIType(XPUINFO_INIT_ALL_APIS | API_TYPE_WMI); 65 | std::cout << "Initializing XPUInfo with APIType = " << apis << "...\n"; 66 | XI::XPUInfoPtr pXI(new XPUInfo(apis)); 67 | if (getXPUInfoJSON(ostr, pXI)) 68 | { 69 | std::istringstream istr(ostr.str()); 70 | if (!istr.bad()) 71 | { 72 | rapidjson::IStreamWrapper isw(istr); 73 | rapidjson::Document doc; 74 | doc.ParseStream(isw); 75 | if (doc.HasParseError()) 76 | { 77 | std::cout << "Error : " << doc.GetParseError() << ": " 78 | << "Offset : " << doc.GetErrorOffset() << '\n'; 79 | return false; 80 | } 81 | XI::XPUInfoPtr pXID(XI::XPUInfo::deserialize(doc)); 82 | #ifdef _WIN32 83 | pXID->initDXCore(true); 84 | for (const auto& [luid, pDev] :pXID->getDeviceMap()) 85 | { 86 | if (pDev->getCurrentAPIs() & API_TYPE_DXCORE) 87 | { 88 | XPUINFO_REQUIRE(pDev->getHandle_DXCore()); 89 | } 90 | } 91 | #endif 92 | bool xiEqual = JSON::compareXI(pXI, pXID); 93 | if (!xiEqual) 94 | { 95 | std::cout << "XPUInfo comparison failed!\n"; 96 | } 97 | else 98 | { 99 | std::cout << "XPUInfo comparison matched!\n"; 100 | } 101 | return xiEqual; 102 | } 103 | } 104 | else 105 | { 106 | std::cout << "Failed to get XPUInfo JSON!\n"; 107 | } 108 | return false; 109 | } 110 | 111 | bool testReadJSON(const std::filesystem::path jsonPath) 112 | { 113 | if (std::filesystem::directory_entry(jsonPath).is_regular_file()) 114 | { 115 | std::ifstream istr(jsonPath); 116 | if (!istr.bad()) 117 | { 118 | rapidjson::IStreamWrapper isw(istr); 119 | rapidjson::Document doc; 120 | doc.ParseStream(isw); 121 | if (doc.HasParseError()) 122 | { 123 | std::cout << "Error : " << doc.GetParseError() << ": " 124 | << "Offset : " << doc.GetErrorOffset() << '\n'; 125 | return false; 126 | } 127 | XI::XPUInfoPtr pXID(XI::XPUInfo::deserialize(doc)); 128 | std::cout << *pXID << std::endl; 129 | return true; 130 | } 131 | } 132 | else 133 | { 134 | std::cout << "File not found: " << std::filesystem::absolute(jsonPath).string() << std::endl; 135 | } 136 | return false; 137 | } 138 | #endif 139 | 140 | #ifdef _WIN32 141 | class ScopedD3D12MemoryAllocation 142 | { 143 | public: 144 | ScopedD3D12MemoryAllocation(IUnknown* adapter, double sizeInGB) 145 | { 146 | size_t sizeInBytes = static_cast(sizeInGB * 1024 * 1024 * 1024); 147 | if (!CreateD3D12DeviceAndAllocateResource(adapter, sizeInBytes, m_gpuMem)) 148 | { 149 | throw std::runtime_error("Failed to allocate D3D12 memory"); 150 | } 151 | 152 | } 153 | protected: 154 | std::list> m_gpuMem; 155 | }; 156 | 157 | static const XI::RuntimeNames runtimes = { 158 | "Microsoft.AI.MachineLearning.dll", "DirectML.dll", "onnxruntime.dll", "OpenVino.dll", 159 | "onnxruntime_providers_shared.dll", "onnxruntime_providers_openvino.dll", 160 | }; 161 | 162 | int testInflateGPUMem(double sizeInGB, const std::string& devName) 163 | { 164 | try 165 | { 166 | XPUInfo xi(XPUINFO_INIT_ALL_APIS, runtimes); 167 | auto xiDev = xi.getDevice(devName.c_str()); 168 | if (xiDev) 169 | { 170 | std::cout << xi << std::endl << std::endl; 171 | std::cout << "Allocating " << sizeInGB << " GB on " << XI::convert(xiDev->name()) << std::endl; 172 | auto devHandle = xiDev->getHandle_DXCore(); 173 | XPUINFO_REQUIRE(devHandle); 174 | try 175 | { 176 | ScopedD3D12MemoryAllocation mem(devHandle, sizeInGB); 177 | std::cout << "Press any key to continue...\n"; 178 | int c = getchar(); (void)c; 179 | } 180 | catch (const std::exception& e) 181 | { 182 | std::cout << "Exception near ScopedD3D12MemoryAllocation: " << e.what() << std::endl; 183 | return -1; 184 | } 185 | } 186 | else 187 | { 188 | std::cout << "Device not found: " << devName << std::endl; 189 | return -1; 190 | } 191 | } 192 | catch (const std::exception& e) 193 | { 194 | std::cout << "Exception attempting inflate_gpu_mem: " << e.what() << std::endl; 195 | return -1; 196 | } 197 | return 0; 198 | } 199 | #else 200 | static const XI::RuntimeNames runtimes; // empty for now 201 | #endif 202 | 203 | #ifdef XPUINFO_USE_TELEMETRYTRACKER 204 | int runTelemetry(XI::UI32 telemInterval_ms, XI::UI32 telem_gpu_idx) 205 | { 206 | // Find desired GPU, then start running 207 | APIType apis = APIType(XI::API_TYPE_DXGI | XI::API_TYPE_SETUPAPI \ 208 | | XI::API_TYPE_DX11_INTEL_PERF_COUNTER \ 209 | | XI::API_TYPE_LEVELZERO \ 210 | | XI::API_TYPE_IGCL_L0 | XI::API_TYPE_IGCL \ 211 | | XI::API_TYPE_DXCORE | XI::API_TYPE_NVML); 212 | 213 | XI::XPUInfo xi(apis, runtimes); 214 | 215 | auto telemDevice = xi.getDeviceByIndex(telem_gpu_idx); 216 | { 217 | XI::TelemetryTrackerWithScopedLog tt(telemDevice, telemInterval_ms, std::cout); 218 | std::cout << "Telemetry started on device " << XI::convert(telemDevice->name()) << " with " << telemInterval_ms << " ms interval.\n"; 219 | std::cout << "Press any key to stop...\n"; 220 | tt.start(); 221 | auto c = getchar(); 222 | (void)c; 223 | } 224 | std::cout << std::endl << xi << std::endl; 225 | return 0; 226 | } 227 | #endif 228 | 229 | #if TESTLIBXPUINFO_STANDALONE 230 | int main(int argc, char* argv[]) 231 | #else 232 | int printXPUInfo(int argc, char* argv[]) 233 | #endif 234 | { 235 | bool testIndividual = false; 236 | bool bRunTelemetry = false; 237 | XI::UI32 telemInterval_ms = 0; 238 | XI::UI32 telem_gpu_idx = 0; 239 | APIType additionalAPIs = APIType(0); 240 | APIType apiMask = APIType(0); 241 | 242 | for (int a = 1; a < argc; ++a) 243 | { 244 | String arg(argv[a]); 245 | #ifdef _WIN32 246 | if (arg == "-1") 247 | { 248 | testIndividual = true; 249 | } 250 | #endif 251 | if (arg == "-telemetry") // -telemetry [] 252 | { 253 | if ((a + 1 < argc)) 254 | { 255 | std::istringstream istr(argv[++a]); 256 | XI::UI32 msInterval = 0; 257 | istr >> msInterval; 258 | if (!istr.bad()) 259 | { 260 | telemInterval_ms = msInterval; 261 | bRunTelemetry = true; 262 | } 263 | } 264 | if ((a + 1 < argc) && (strlen(argv[a+1]) > 0) && (argv[a+1][0] != '-')) 265 | { 266 | std::istringstream istr(argv[++a]); 267 | XI::UI32 gpuIdx; 268 | istr >> gpuIdx; 269 | if (!istr.bad()) 270 | { 271 | telem_gpu_idx = gpuIdx; 272 | } 273 | } 274 | } 275 | if (arg == "-igcl_l0_enable") 276 | { 277 | additionalAPIs |= XI::API_TYPE_IGCL_L0; 278 | } 279 | // If specified, this takes precedence over additionalAPIs 280 | else if ((arg == "-apis") && (a+1 < argc)) 281 | { 282 | std::underlying_type_t inMask; 283 | std::istringstream istr(argv[++a]); 284 | istr >> std::hex >> inMask; 285 | if (!istr.bad()) 286 | { 287 | apiMask = static_cast(inMask); 288 | } 289 | } 290 | #ifdef _WIN32 291 | // -inflate_gpu_mem 10.5 Arc 292 | else if ((arg == "-inflate_gpu_mem") && (a + 2 < argc)) 293 | { 294 | double sizeInGB; 295 | std::istringstream istr(argv[++a]); 296 | std::string devName(argv[++a]); 297 | istr >> sizeInGB; 298 | if (!istr.fail()) 299 | { 300 | return testInflateGPUMem(sizeInGB, devName); 301 | } 302 | else 303 | { 304 | std::cout << "Argument error - Invalid size: " << istr.str() << std::endl; 305 | return -1; 306 | } 307 | return -1; 308 | } 309 | #endif 310 | #ifdef XPUINFO_USE_RAPIDJSON 311 | if ((arg == "-write_json") && (a + 1 < argc)) 312 | { 313 | testWriteJSON(argv[++a]); 314 | } 315 | else if (arg == "-verify_json") 316 | { 317 | testVerifyJSON(); 318 | } 319 | else if ((arg == "-from_json") && (a + 1 < argc)) 320 | { 321 | testReadJSON(argv[++a]); 322 | } 323 | #endif 324 | } 325 | 326 | try 327 | { 328 | if (bRunTelemetry) 329 | { 330 | return runTelemetry(telemInterval_ms, telem_gpu_idx); 331 | } 332 | else 333 | if (!testIndividual) 334 | { 335 | XI::Timer timer; 336 | #ifdef _WIN32 337 | APIType apis = APIType((XI::API_TYPE_DXGI | XI::API_TYPE_SETUPAPI \ 338 | | XI::API_TYPE_DX11_INTEL_PERF_COUNTER | XI::API_TYPE_IGCL | XI::API_TYPE_OPENCL \ 339 | | XI::API_TYPE_LEVELZERO \ 340 | | XI::API_TYPE_DXCORE | XI::API_TYPE_NVML) | API_TYPE_WMI); 341 | #else 342 | APIType apis = XI::API_TYPE_METAL; 343 | #endif 344 | apis |= additionalAPIs; 345 | if (apiMask != XI::API_TYPE_UNKNOWN) 346 | { 347 | apis = apiMask; 348 | } 349 | timer.Start(); 350 | std::cout << "Initializing XPUInfo with APIType = " << apis << "...\n"; 351 | XI::XPUInfo xi(apis, runtimes); 352 | std::cout << xi << std::endl; 353 | timer.Stop(); 354 | std::cout << "XPUInfo Time: " << timer.GetElapsedSecs() << " seconds\n"; 355 | } 356 | else 357 | { 358 | std::vector apiVec; 359 | apiVec.push_back(XPUINFO_INIT_ALL_APIS); // All but WMI 360 | apiVec.push_back(APIType(XPUINFO_INIT_ALL_APIS | API_TYPE_WMI)); 361 | 362 | // Either DXGI or DXCore is needed in all cases 363 | apiVec.push_back(APIType(XI::API_TYPE_DXGI | XI::API_TYPE_DX11_INTEL_PERF_COUNTER)); 364 | apiVec.push_back(XI::API_TYPE_DXCORE); 365 | apiVec.push_back(APIType(XI::API_TYPE_DXGI | XI::API_TYPE_SETUPAPI)); 366 | apiVec.push_back(APIType(XI::API_TYPE_DXGI | XI::API_TYPE_SETUPAPI | XI::API_TYPE_LEVELZERO)); 367 | apiVec.push_back(APIType(XI::API_TYPE_DXCORE | XI::API_TYPE_SETUPAPI)); 368 | apiVec.push_back(APIType(XI::API_TYPE_DXCORE | XI::API_TYPE_IGCL)); 369 | apiVec.push_back(APIType(XI::API_TYPE_DXCORE | XI::API_TYPE_OPENCL)); 370 | apiVec.push_back(APIType(XI::API_TYPE_DXCORE | XI::API_TYPE_LEVELZERO)); 371 | apiVec.push_back(APIType(XI::API_TYPE_DXCORE | XI::API_TYPE_NVML)); 372 | 373 | for (auto api : apiVec) 374 | { 375 | std::cout << "Initializing XPUInfo with APIType = " << api << "...\n"; 376 | XI::Timer timer; 377 | timer.Start(); 378 | XI::XPUInfo xi(api, runtimes); 379 | std::cout << xi << std::endl; 380 | timer.Stop(); 381 | std::cout << "XPUInfo Time: " << timer.GetElapsedSecs() << " seconds\n"; 382 | } 383 | } 384 | } 385 | catch (...) 386 | { 387 | std::cout << "Exception initializing XPUInfo!\n"; 388 | return -1; 389 | } 390 | return 0; 391 | } 392 | -------------------------------------------------------------------------------- /TestLibXPUInfo/TestLibXPUInfo.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | DebugDynamic 6 | Win32 7 | 8 | 9 | DebugDynamic 10 | x64 11 | 12 | 13 | Debug 14 | Win32 15 | 16 | 17 | ReleaseDynamic 18 | Win32 19 | 20 | 21 | ReleaseDynamic 22 | x64 23 | 24 | 25 | Release 26 | Win32 27 | 28 | 29 | Debug 30 | x64 31 | 32 | 33 | Release 34 | x64 35 | 36 | 37 | 38 | 16.0 39 | Win32Proj 40 | {a1fe53c4-2abe-48b4-8222-bb55e6cf98f1} 41 | TestLibXPUInfo 42 | 10.0 43 | 44 | 45 | 46 | Application 47 | true 48 | v143 49 | Unicode 50 | 51 | 52 | Application 53 | true 54 | v143 55 | Unicode 56 | 57 | 58 | Application 59 | false 60 | v143 61 | true 62 | Unicode 63 | 64 | 65 | Application 66 | false 67 | v143 68 | true 69 | Unicode 70 | 71 | 72 | Application 73 | true 74 | v143 75 | NotSet 76 | 77 | 78 | Application 79 | true 80 | v143 81 | NotSet 82 | 83 | 84 | Application 85 | false 86 | v143 87 | true 88 | Unicode 89 | 90 | 91 | Application 92 | false 93 | v143 94 | true 95 | Unicode 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | false 129 | 130 | 131 | 132 | Level3 133 | true 134 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 135 | true 136 | 137 | 138 | Console 139 | true 140 | 141 | 142 | 143 | 144 | Level3 145 | true 146 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 147 | true 148 | 149 | 150 | Console 151 | true 152 | 153 | 154 | 155 | 156 | Level3 157 | true 158 | true 159 | true 160 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 161 | true 162 | 163 | 164 | Console 165 | true 166 | true 167 | true 168 | 169 | 170 | 171 | 172 | Level3 173 | true 174 | true 175 | true 176 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 177 | true 178 | 179 | 180 | Console 181 | true 182 | true 183 | true 184 | 185 | 186 | 187 | 188 | Level4 189 | true 190 | RAPIDJSON_HAS_STDSTRING=1;XPUINFO_USE_SYSTEMEMORYINFO;XPUINFO_USE_RUNTIMEVERSIONINFO;XPUINFO_USE_RAPIDJSON;XPUINFO_USE_TELEMETRYTRACKER;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 191 | true 192 | $(SolutionDir);$(SolutionDir)external\OpenCL-Headers;$(SolutionDir)external\rapidjson\include 193 | stdcpp17 194 | 195 | 196 | Console 197 | true 198 | d3d12.lib;dxcore.lib;d3d11.lib;opencl.lib;ze_loader.lib;dxgi.lib;LibXPUInfo.lib;$(CoreLibraryDependencies);%(AdditionalDependencies) 199 | $(SolutionDir)external\OpenCL-ICD-Loader-install\lib;$(SolutionDir)external\NVML\lib\x64;$(SolutionDir)external\level-zero-build\install\lib;$(SolutionDir)..\external\level-zero\lib\$(Configuration);$(OutDir) 200 | ze_loader.dll;nvml.dll;dxcore.dll;opencl.dll 201 | 202 | 203 | 204 | 205 | Level4 206 | true 207 | XPUINFO_BUILD_SHARED;RAPIDJSON_HAS_STDSTRING=1;XPUINFO_USE_SYSTEMEMORYINFO;XPUINFO_USE_RUNTIMEVERSIONINFO;XPUINFO_USE_RAPIDJSON;_DEBUG;_CONSOLE;%(PreprocessorDefinitions);XPUINFO_USE_TELEMETRYTRACKER 208 | true 209 | $(SolutionDir);$(SolutionDir)external\OpenCL-Headers;$(SolutionDir)external\rapidjson\include 210 | stdcpp17 211 | 212 | 213 | Console 214 | true 215 | d3d12.lib;LibXPUInfo.lib;$(CoreLibraryDependencies);%(AdditionalDependencies) 216 | $(OutDir) 217 | 218 | 219 | 220 | 221 | 222 | 223 | Level4 224 | true 225 | true 226 | true 227 | RAPIDJSON_HAS_STDSTRING=1;XPUINFO_USE_SYSTEMEMORYINFO;XPUINFO_USE_RUNTIMEVERSIONINFO;XPUINFO_USE_RAPIDJSON;XPUINFO_USE_TELEMETRYTRACKER;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 228 | true 229 | $(SolutionDir);$(SolutionDir)external\OpenCL-Headers;$(SolutionDir)external\rapidjson\include 230 | stdcpp17 231 | true 232 | 233 | 234 | Console 235 | true 236 | true 237 | true 238 | d3d12.lib;dxcore.lib;d3d11.lib;opencl.lib;ze_loader.lib;dxgi.lib;LibXPUInfo.lib;$(CoreLibraryDependencies);%(AdditionalDependencies) 239 | $(SolutionDir)external\OpenCL-ICD-Loader-install\lib;$(SolutionDir)external\NVML\lib\x64;$(SolutionDir)external\level-zero-build\install\lib;$(SolutionDir)..\external\level-zero\lib\RelWithDebInfo;$(OutDir) 240 | ze_loader.dll;nvml.dll;dxcore.dll;opencl.dll 241 | 242 | 243 | 244 | 245 | Level4 246 | true 247 | true 248 | true 249 | XPUINFO_BUILD_SHARED;RAPIDJSON_HAS_STDSTRING=1;XPUINFO_USE_SYSTEMEMORYINFO;XPUINFO_USE_RUNTIMEVERSIONINFO;XPUINFO_USE_RAPIDJSON;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);XPUINFO_USE_TELEMETRYTRACKER 250 | true 251 | $(SolutionDir);$(SolutionDir)external\OpenCL-Headers;$(SolutionDir)external\rapidjson\include 252 | stdcpp17 253 | true 254 | 255 | 256 | Console 257 | true 258 | true 259 | true 260 | d3d12.lib;LibXPUInfo.lib;$(CoreLibraryDependencies);%(AdditionalDependencies) 261 | $(OutDir) 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | -------------------------------------------------------------------------------- /TestLibXPUInfo/TestLibXPUInfo.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | Source Files 23 | 24 | 25 | 26 | 27 | Header Files 28 | 29 | 30 | -------------------------------------------------------------------------------- /TestXPUInfoIPC/TestXPUInfoIPC.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2024 Intel Corporation 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | /* IPC Test - XPUInfo initialized on server, client checks success 5 | * 6 | * There are 2 paths here - pipe and shared-memory. The pipe path is simpler and preferred. 7 | * 8 | * Shared-memory path: 9 | * - Client process launches server process, Server waits for first signal 10 | * - Client initializes shared memory 11 | * - Client passes "initMask" through shared memory and signals completion 12 | * - Server receives initMask, initializes XPUInfo, writes response to shared memory, and exits 13 | * - Client waits for server process completion, checks exit result code, and displays result. 14 | */ 15 | #include "LibXPUInfo.h" 16 | #include "LibXPUInfo_IPC.h" 17 | #include "TestXPUInfoIPC_Shared.h" 18 | #include "LibXPUInfo_Util.h" 19 | #include "LibXPUInfo_JSON.h" 20 | #include 21 | #include 22 | #include 23 | 24 | #ifdef TESTXPUINFOIPC_SHARED 25 | #if TESTXPUINFOIPC_SUPPORT_PIPE 26 | int XPUInfoIPC_Client_Pipe(const char* serverCommandString, PROCESS_INFORMATION& pi) 27 | { 28 | // This event is used for our handshake/protocol 29 | static XI::Win::NamedEvent S_Event(EVENT_NAME); 30 | 31 | DWORD exitCode = 0; 32 | STARTUPINFOA si{}; 33 | si.cb = sizeof(si); 34 | 35 | BOOL bRet = CreateProcessA(NULL, 36 | const_cast(serverCommandString), 37 | NULL, NULL, 38 | TRUE, 39 | CREATE_SUSPENDED, 40 | NULL, NULL, 41 | &si, &pi); 42 | XPUINFO_REQUIRE(bRet); 43 | int res = ResumeThread(pi.hThread); 44 | XPUINFO_REQUIRE(res != -1); 45 | if (bRet) 46 | { 47 | // Start by waiting for server to signal ready 48 | std::cout << "[CLIENT] Waiting..." << std::endl; 49 | auto waitRes = S_Event.Wait(); 50 | XPUINFO_REQUIRE(waitRes == WAIT_OBJECT_0); 51 | 52 | std::cout << "[CLIENT] Opening Pipe..." << std::endl; 53 | { // Pipe scope 54 | // Open pipe 55 | XI::Win::NamedPipe Pipe(PIPE_NAME, MUTEX_NAME, BUFSIZE); 56 | if (Pipe.Valid()) 57 | { 58 | XI::APIType initMask = XPUINFO_INIT_ALL_APIS | XI::API_TYPE_WMI; 59 | std::cout << "[CLIENT] Pipe opened, writing initMask = " << initMask << std::endl; 60 | 61 | bRet = Pipe.Write(initMask); 62 | XPUINFO_REQUIRE(bRet); 63 | std::cout << "[CLIENT] Wrote " << sizeof(initMask) << " bytes to pipe\n"; 64 | 65 | // Read pipe 66 | std::cout << "[CLIENT] Reading from pipe...\n"; 67 | XI::String buffer; 68 | bRet = Pipe.Read(buffer); 69 | if (!bRet) 70 | { 71 | auto gle = GetLastError(); 72 | std::cout << "[CLIENT] Pipe Read Error " << gle << ": " << XI::Win::GetLastErrorStr(gle); 73 | XPUINFO_REQUIRE(bRet); 74 | } 75 | std::cout << "[CLIENT] Read " << buffer.size() << " from pipe:\n" << buffer; 76 | } 77 | } // end pipe scope 78 | 79 | // Validate server exit 80 | std::cout << "[CLIENT] Waiting for server to exit..." << std::endl; 81 | DWORD dwRes = WaitForSingleObject(pi.hProcess, INFINITE); 82 | if (dwRes == WAIT_OBJECT_0) 83 | { 84 | bRet = GetExitCodeProcess(pi.hProcess, &exitCode); 85 | XPUINFO_REQUIRE(bRet); 86 | std::cout << "[CLIENT] Subprocess returned " << exitCode << std::endl; 87 | } 88 | } 89 | return exitCode; 90 | } 91 | 92 | int XPUInfo_IPC_Server_Pipe() 93 | { 94 | // This semaphore limits server execution to 1 client at a time, 95 | // so if multiple clients are trying to run multiple server processes, 96 | // each server process will service just one client. 97 | static XI::Win::NamedSemaphore S_SingleExecSemaphore(SEMAPHORE_NAME, 1); 98 | // This event is used for our handshake/protocol 99 | static XI::Win::NamedEvent S_Event(EVENT_NAME); 100 | 101 | std::cout << "[SERVER] Initializing XPUInfo Server (Pipe)...\n"; 102 | try 103 | { 104 | XI::Win::NamedSemaphore::ScopedAcquire lock(S_SingleExecSemaphore); 105 | int exitCode = 0; 106 | 107 | XI::Win::NamedPipe Pipe(PIPE_NAME, MUTEX_NAME, BUFSIZE, true); 108 | // Signal ready, regardless of status so client is not stuck 109 | S_Event.Set(); 110 | if (Pipe.Valid()) 111 | { 112 | std::cout << "[SERVER] Pipe Created\n"; 113 | 114 | if (Pipe.Connect()) // wait for someone to connect to the pipe 115 | { 116 | // Read pipe to get initMask 117 | XI::APIType initMask = XI::APIType::API_TYPE_UNKNOWN; 118 | 119 | if (Pipe.Read(initMask)) 120 | { 121 | std::cout << "[SERVER] Read " << sizeof(initMask) << " bytes from pipe:\tinitMask = " << initMask << std::endl; 122 | 123 | XI::XPUInfo xi(initMask); 124 | 125 | std::ostringstream str; 126 | str << xi << std::endl; 127 | 128 | if (Pipe.Write(str.str())) 129 | { 130 | std::cout << "[SERVER] Wrote " << str.str().length() << " bytes to pipe\n"; 131 | } 132 | else 133 | { 134 | std::cout << "[SERVER] Pipe write failed!\n"; 135 | } 136 | XPUINFO_REQUIRE(Pipe.Disconnect()); 137 | } 138 | else 139 | { 140 | XPUINFO_REQUIRE_MSG(0, "Failed to read initMask"); 141 | } 142 | } 143 | else 144 | { 145 | auto lastErr = GetLastError(); 146 | std::cout << "[SERVER] ConnectNamedPipe failed with " << lastErr << ": " << XI::Win::GetLastErrorStr(lastErr); 147 | return lastErr; 148 | } 149 | } 150 | else 151 | { 152 | DWORD err = exitCode = GetLastError(); 153 | std::cout << "[SERVER] CreateNamedPipeA failed with result = " << err << ": " << XI::Win::GetLastErrorStr(err); 154 | } 155 | return exitCode; 156 | } 157 | catch (...) 158 | { 159 | std::cout << "Exception initializing XPUInfo!\n"; 160 | return -1; 161 | } 162 | } 163 | #endif // TESTXPUINFOIPC_SUPPORT_PIPE 164 | 165 | #if TESTXPUINFOIPC_SUPPORT_SHAREDMEM 166 | int XPUInfoIPC_Client(const char* serverCommandString, PROCESS_INFORMATION& pi) 167 | { 168 | // This event is used for our handshake/protocol 169 | static XI::Win::NamedEvent S_Event(EVENT_NAME); 170 | 171 | DWORD exitCode = 0; 172 | STARTUPINFOA si{}; 173 | si.cb = sizeof(si); 174 | 175 | BOOL bRet = CreateProcessA(NULL, 176 | const_cast(serverCommandString), 177 | NULL, NULL, 178 | TRUE, 179 | CREATE_SUSPENDED, 180 | NULL, NULL, 181 | &si, &pi); 182 | XPUINFO_REQUIRE(bRet); 183 | int res = ResumeThread(pi.hThread); 184 | XPUINFO_REQUIRE(res != -1); 185 | if (bRet) 186 | { 187 | XI::Win::NamedSharedMemory SharedMem(BUFSIZE, SHARED_MEM_NAME); 188 | XPUINFO_REQUIRE(!SharedMem.getStatus()); 189 | XI::APIType initMask = XPUINFO_INIT_ALL_APIS; 190 | std::cout << "Setting initMask = " << std::hex << initMask << std::dec << std::endl; 191 | { 192 | XI::Win::NamedMutex::ScopedLock lock(SharedMem.getMutex()); 193 | *(XI::APIType*)SharedMem.getSharedMemPtr() = initMask; 194 | } 195 | S_Event.Set(); 196 | 197 | std::cout << "Waiting..." << std::endl; 198 | DWORD dwRes = WaitForSingleObject(pi.hProcess, INFINITE); 199 | if (dwRes == WAIT_OBJECT_0) 200 | { 201 | bRet = GetExitCodeProcess(pi.hProcess, &exitCode); 202 | XPUINFO_REQUIRE(bRet); 203 | { 204 | XI::Win::NamedMutex::ScopedLock lock(SharedMem.getMutex()); 205 | const char* str = (const char*)SharedMem.getSharedMemPtr(); 206 | if (bRet) 207 | { 208 | std::cout << "Subprocess returned " << exitCode << ", output:\n" << str << std::endl; 209 | } 210 | } 211 | } 212 | } 213 | return exitCode; 214 | } 215 | 216 | int XPUInfo_IPC_Server() 217 | { 218 | // This semaphore limits server execution to 1 client at a time, 219 | // so if multiple clients are trying to run multiple server processes, 220 | // each server process will service just one client. 221 | static XI::Win::NamedSemaphore S_SingleExecSemaphore(SEMAPHORE_NAME, 1); 222 | // This event is used for our handshake/protocol 223 | static XI::Win::NamedEvent S_Event(EVENT_NAME); 224 | 225 | std::cout << "Initializing XPUInfo Server...\n"; 226 | try 227 | { 228 | XI::Win::NamedSemaphore::ScopedAcquire lock(S_SingleExecSemaphore); 229 | XI::Win::NamedSharedMemory SharedMem(BUFSIZE, SHARED_MEM_NAME); 230 | XPUINFO_REQUIRE(!SharedMem.getStatus()); 231 | 232 | // Wait for data received before exiting. 233 | auto dwRes = S_Event.Wait(); 234 | XI::APIType initMask = XI::APIType::API_TYPE_UNKNOWN; 235 | if (dwRes == WAIT_OBJECT_0) 236 | { 237 | { 238 | XI::Win::NamedMutex::ScopedLock lockSharedMem(SharedMem.getMutex()); 239 | initMask = *(XI::APIType*)SharedMem.getSharedMemPtr(); 240 | std::cout << "Received initMask = " << std::hex << initMask << std::dec << std::endl; 241 | } 242 | } 243 | 244 | std::ostringstream str; 245 | XI::XPUInfo xi(initMask); 246 | str << xi << std::endl; 247 | 248 | { 249 | XI::Win::NamedMutex::ScopedLock lockSharedMem(SharedMem.getMutex()); 250 | if (!SharedMem.getStatus()) 251 | { 252 | char* sharedString = (char*)SharedMem.getSharedMemPtr(); 253 | strncpy_s(sharedString, SharedMem.size(), str.str().c_str(), _TRUNCATE); 254 | } 255 | } 256 | return 0; 257 | } 258 | catch (...) 259 | { 260 | std::cout << "Exception initializing XPUInfo!\n"; 261 | return -1; 262 | } 263 | } 264 | #endif // TESTXPUINFOIPC_SUPPORT_SHAREDMEM 265 | #else // TESTXPUINFOIPC_SHARED 266 | 267 | #ifdef XPUINFO_USE_RAPIDJSON 268 | bool getXPUInfoJSON(std::ostream& ostr, const XI::XPUInfoPtr& pXI, double xiTime) 269 | { 270 | if (!ostr.fail()) 271 | { 272 | rapidjson::Document doc; 273 | doc.SetObject(); 274 | 275 | if (pXI->serialize(doc)) 276 | { 277 | auto& a = doc.GetAllocator(); 278 | doc.AddMember("XPUInfoInitSecs", xiTime, a); 279 | rapidjson::OStreamWrapper out(ostr); 280 | rapidjson::PrettyWriter writer(out); 281 | doc.Accept(writer); // Accept() traverses the DOM and generates Handler events. 282 | ostr << std::endl; 283 | return true; 284 | } 285 | } 286 | return false; 287 | } 288 | 289 | int writeXPUInfoJSON(const char* jsonPath, const XI::RuntimeNames& runtimes, 290 | const XI::APIType apis = XPUINFO_INIT_ALL_APIS | XI::API_TYPE_WMI) 291 | { 292 | XI::Timer timer; 293 | timer.Start(); 294 | XI::XPUInfoPtr pXI(new XI::XPUInfo(apis, runtimes)); 295 | timer.Stop(); 296 | double xiTime = timer.GetElapsedSecs(); 297 | std::ofstream outFile(jsonPath); 298 | return (!getXPUInfoJSON(outFile, pXI, xiTime)); 299 | } 300 | #endif // XPUINFO_USE_RAPIDJSON 301 | 302 | namespace // private 303 | { 304 | std::vector parseCommaSeparatedList(const std::string& input) { 305 | std::vector result; 306 | std::stringstream ss(input); 307 | std::string item; 308 | 309 | while (std::getline(ss, item, ',')) { 310 | result.push_back(item); 311 | } 312 | 313 | return result; 314 | } 315 | } // private 316 | 317 | int main(int argc, char* argv[]) 318 | { 319 | int procRetVal = -1; 320 | #ifdef _DEBUG 321 | std::cout << argv[0] << " "; 322 | for (int a = 1; a < argc; ++a) 323 | { 324 | std::cout << argv[a] << " "; 325 | } 326 | std::cout << std::endl; 327 | #endif 328 | 329 | #ifdef _WIN32 330 | try 331 | { 332 | bool isServer = false; 333 | bool usePipe = true; 334 | XI::RuntimeNames runtimes; 335 | XI::APIType apis = XPUINFO_INIT_ALL_APIS | XI::API_TYPE_WMI; 336 | for (int a = 1; a < argc; ++a) 337 | { 338 | std::string arg(argv[a]); 339 | #ifdef XPUINFO_USE_RAPIDJSON 340 | // Usage: -write_json outfileName apiMask 341 | if (arg == "-write_json") 342 | { 343 | XPUINFO_REQUIRE(a + 1 < argc); 344 | return writeXPUInfoJSON(argv[++a], runtimes, apis); 345 | } 346 | else 347 | #endif 348 | // Usage: -apis apiMaskHex 349 | // Put this arg before -write_json or others using it 350 | if (arg == "-apis") 351 | { 352 | XPUINFO_REQUIRE(a + 1 < argc); 353 | std::underlying_type_t inMask; 354 | std::istringstream istr(argv[++a]); 355 | istr >> std::hex >> inMask; 356 | if (!istr.fail()) 357 | { 358 | apis = static_cast(inMask); 359 | } 360 | } 361 | else if (arg == "-runtimes") 362 | { 363 | // Read runtime names as comma-separated list 364 | if ((a + 1) < argc) 365 | { 366 | runtimes = parseCommaSeparatedList(argv[a + 1]); 367 | } 368 | } 369 | else if (arg == "-server") 370 | { 371 | isServer = true; 372 | } 373 | else if (arg == "-sharedmem") 374 | { 375 | usePipe = false; 376 | } 377 | } // for each arg 378 | 379 | XPUINFO_REQUIRE_CONSTEXPR_MSG(TESTXPUINFOIPC_SUPPORT_PIPE || TESTXPUINFOIPC_SUPPORT_SHAREDMEM, 380 | "Must build with TESTXPUINFOIPC_SUPPORT_PIPE or TESTXPUINFOIPC_SUPPORT_SHAREDMEM"); 381 | #if TESTXPUINFOIPC_SUPPORT_PIPE || TESTXPUINFOIPC_SUPPORT_SHAREDMEM 382 | if (isServer) 383 | { 384 | if (usePipe) 385 | { 386 | XPUINFO_REQUIRE_CONSTEXPR_MSG(TESTXPUINFOIPC_SUPPORT_PIPE, 387 | "Must build with TESTXPUINFOIPC_SUPPORT_PIPE"); 388 | #if TESTXPUINFOIPC_SUPPORT_PIPE 389 | procRetVal = XPUInfo_IPC_Server_Pipe(); 390 | #endif 391 | } 392 | else 393 | { 394 | XPUINFO_REQUIRE_CONSTEXPR_MSG(TESTXPUINFOIPC_SUPPORT_SHAREDMEM, 395 | "Must build with TESTXPUINFOIPC_SUPPORT_SHAREDMEM"); 396 | #if TESTXPUINFOIPC_SUPPORT_SHAREDMEM 397 | procRetVal = XPUInfo_IPC_Server(); 398 | #endif 399 | } 400 | } 401 | else 402 | { 403 | char szFileName[MAX_PATH]; 404 | 405 | auto sizeRet = GetModuleFileNameA(NULL, szFileName, MAX_PATH); 406 | auto lastErr = GetLastError(); 407 | if ((lastErr != ERROR_INSUFFICIENT_BUFFER) && sizeRet) 408 | { 409 | std::cout << "Launching server process: " << szFileName << std::endl; 410 | 411 | std::string args; 412 | args.reserve(32767); // See CreateProcess docs - unclear if this is required 413 | args = szFileName; 414 | args += " -server"; 415 | XI::Win::ProcessInformation pi; 416 | if (!usePipe) 417 | { 418 | XPUINFO_REQUIRE_CONSTEXPR_MSG(TESTXPUINFOIPC_SUPPORT_SHAREDMEM, 419 | "Must build with TESTXPUINFOIPC_SUPPORT_SHAREDMEM"); 420 | args += " -sharedmem"; 421 | #if TESTXPUINFOIPC_SUPPORT_SHAREDMEM 422 | procRetVal = XPUInfoIPC_Client(args.c_str(), pi); 423 | #endif 424 | } 425 | else 426 | { 427 | XPUINFO_REQUIRE_CONSTEXPR_MSG(TESTXPUINFOIPC_SUPPORT_PIPE, 428 | "Must build with TESTXPUINFOIPC_SUPPORT_PIPE"); 429 | #if TESTXPUINFOIPC_SUPPORT_PIPE 430 | procRetVal = XPUInfoIPC_Client_Pipe(args.c_str(), pi); 431 | #endif 432 | } 433 | } 434 | else 435 | { 436 | std::cout << "Error from GetModuleFileNameA, size returned = " << sizeRet << std::endl; 437 | } 438 | } // End Client 439 | std::cout << (isServer ? "[SERVER] " : "[CLIENT] ") << "Exiting with code " << procRetVal << std::endl; 440 | #endif // TESTXPUINFOIPC_SUPPORT_PIPE || TESTXPUINFOIPC_SUPPORT_SHAREDMEM 441 | } 442 | catch (std::logic_error& e) 443 | { 444 | std::cout << "Caught exception: " << e.what() << std::endl; 445 | procRetVal = 0; 446 | } 447 | #endif // _WIN32 448 | return procRetVal; 449 | } 450 | 451 | #endif // TESTXPUINFOIPC_SHARED 452 | -------------------------------------------------------------------------------- /TestXPUInfoIPC/TestXPUInfoIPC.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | DebugDynamic 6 | Win32 7 | 8 | 9 | DebugDynamic 10 | x64 11 | 12 | 13 | Debug 14 | Win32 15 | 16 | 17 | ReleaseDynamic 18 | Win32 19 | 20 | 21 | ReleaseDynamic 22 | x64 23 | 24 | 25 | Release 26 | Win32 27 | 28 | 29 | Debug 30 | x64 31 | 32 | 33 | Release 34 | x64 35 | 36 | 37 | 38 | 16.0 39 | Win32Proj 40 | {7c4fe0e5-0fe3-42c7-9147-2976b55d022c} 41 | TestXPUInfoIPC 42 | 10.0 43 | XPUInfoIPC 44 | 45 | 46 | 47 | Application 48 | true 49 | v143 50 | Unicode 51 | 52 | 53 | Application 54 | true 55 | v143 56 | Unicode 57 | 58 | 59 | Application 60 | false 61 | v143 62 | true 63 | Unicode 64 | 65 | 66 | Application 67 | false 68 | v143 69 | true 70 | Unicode 71 | 72 | 73 | Application 74 | true 75 | v143 76 | Unicode 77 | 78 | 79 | Application 80 | true 81 | v143 82 | Unicode 83 | 84 | 85 | Application 86 | false 87 | v143 88 | true 89 | Unicode 90 | 91 | 92 | Application 93 | false 94 | v143 95 | true 96 | Unicode 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | false 130 | 131 | 132 | 133 | Level3 134 | true 135 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 136 | true 137 | 138 | 139 | Console 140 | true 141 | 142 | 143 | 144 | 145 | Level3 146 | true 147 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 148 | true 149 | 150 | 151 | Console 152 | true 153 | 154 | 155 | 156 | 157 | Level3 158 | true 159 | true 160 | true 161 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 162 | true 163 | 164 | 165 | Console 166 | true 167 | true 168 | true 169 | 170 | 171 | 172 | 173 | Level3 174 | true 175 | true 176 | true 177 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 178 | true 179 | 180 | 181 | Console 182 | true 183 | true 184 | true 185 | 186 | 187 | 188 | 189 | Level4 190 | true 191 | RAPIDJSON_HAS_STDSTRING=1;XPUINFO_USE_SYSTEMEMORYINFO;XPUINFO_USE_RUNTIMEVERSIONINFO;XPUINFO_USE_RAPIDJSON;XPUINFO_USE_IPC;NOMINMAX;_CRT_SECURE_NO_WARNINGS;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 192 | true 193 | $(SolutionDir)external\rapidjson\include;$(SolutionDir);%(AdditionalIncludeDirectories) 194 | stdcpp17 195 | 196 | 197 | Console 198 | true 199 | testxpuinfoipc_shared.lib;dxcore.lib;d3d11.lib;opencl.lib;ze_loader.lib;dxgi.lib;LibXPUInfo.lib;$(CoreLibraryDependencies);%(AdditionalDependencies) 200 | $(SolutionDir)external\OpenCL-ICD-Loader-install\lib;$(SolutionDir)external\NVML\lib\x64;$(SolutionDir)external\level-zero-build\install\lib;$(SolutionDir)..\external\level-zero\lib\$(Configuration);$(SolutionDir)x64\Debug 201 | ze_loader.dll;nvml.dll;dxcore.dll;opencl.dll 202 | 203 | 204 | 205 | 206 | Level4 207 | true 208 | XPUINFO_BUILD_SHARED;RAPIDJSON_HAS_STDSTRING=1;XPUINFO_USE_SYSTEMEMORYINFO;XPUINFO_USE_RUNTIMEVERSIONINFO;XPUINFO_USE_RAPIDJSON;XPUINFO_USE_IPC;NOMINMAX;_CRT_SECURE_NO_WARNINGS;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 209 | true 210 | $(SolutionDir)external\rapidjson\include;$(SolutionDir);%(AdditionalIncludeDirectories) 211 | stdcpp17 212 | 213 | 214 | Console 215 | true 216 | testxpuinfoipc_shared.lib;LibXPUInfo.lib;$(CoreLibraryDependencies);%(AdditionalDependencies) 217 | $(OutDir) 218 | 219 | 220 | 221 | 222 | 223 | 224 | Level4 225 | true 226 | true 227 | true 228 | RAPIDJSON_HAS_STDSTRING=1;XPUINFO_USE_SYSTEMEMORYINFO;XPUINFO_USE_RUNTIMEVERSIONINFO;XPUINFO_USE_RAPIDJSON;XPUINFO_USE_IPC;NOMINMAX;_CRT_SECURE_NO_WARNINGS;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 229 | true 230 | stdcpp17 231 | $(SolutionDir)external\rapidjson\include;$(SolutionDir);%(AdditionalIncludeDirectories) 232 | true 233 | 234 | 235 | Console 236 | true 237 | true 238 | true 239 | ze_loader.dll;nvml.dll;dxcore.dll;opencl.dll 240 | testxpuinfoipc_shared.lib;dxcore.lib;d3d11.lib;opencl.lib;ze_loader.lib;dxgi.lib;LibXPUInfo.lib;$(CoreLibraryDependencies);%(AdditionalDependencies) 241 | $(SolutionDir)external\OpenCL-ICD-Loader-install\lib;$(SolutionDir)external\NVML\lib\x64;$(SolutionDir)external\level-zero-build\install\lib;$(SolutionDir)..\external\level-zero\lib\RelWithDebInfo;$(SolutionDir)x64\Release 242 | 243 | 244 | 245 | 246 | Level4 247 | true 248 | true 249 | true 250 | XPUINFO_BUILD_SHARED;RAPIDJSON_HAS_STDSTRING=1;XPUINFO_USE_SYSTEMEMORYINFO;XPUINFO_USE_RUNTIMEVERSIONINFO;XPUINFO_USE_RAPIDJSON;XPUINFO_USE_IPC;NOMINMAX;_CRT_SECURE_NO_WARNINGS;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 251 | true 252 | stdcpp17 253 | $(SolutionDir)external\rapidjson\include;$(SolutionDir);%(AdditionalIncludeDirectories) 254 | true 255 | 256 | 257 | Console 258 | true 259 | true 260 | true 261 | 262 | 263 | testxpuinfoipc_shared.lib;LibXPUInfo.lib;$(CoreLibraryDependencies);%(AdditionalDependencies) 264 | $(OutDir) 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | -------------------------------------------------------------------------------- /TestXPUInfoIPC/TestXPUInfoIPC.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | -------------------------------------------------------------------------------- /TestXPUInfoIPC/TestXPUInfoIPC_Shared.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2024 Intel Corporation 2 | // SPDX-License-Identifier: Apache-2.0 3 | #pragma once 4 | 5 | #ifndef TESTXPUINFOIPC_SUPPORT_PIPE 6 | #define TESTXPUINFOIPC_SUPPORT_PIPE 0 7 | #endif 8 | #ifndef TESTXPUINFOIPC_SUPPORT_SHAREDMEM 9 | #define TESTXPUINFOIPC_SUPPORT_SHAREDMEM 0 10 | #endif 11 | 12 | #if TESTXPUINFOIPC_SUPPORT_PIPE || TESTXPUINFOIPC_SUPPORT_SHAREDMEM 13 | #define BUFSIZE 4096 14 | #define SHARED_MEM_NAME "XPUINFO_IPC_SHAREDMEM" 15 | #define EVENT_NAME "XPUINFO_IPC_EVENT" 16 | #define MUTEX_NAME "XPUINFO_IPC_MUTEX" 17 | #define SEMAPHORE_NAME "XPUINFO_IPC_SEMAPHORE" 18 | #endif 19 | 20 | #ifdef _WIN32 21 | #if TESTXPUINFOIPC_SUPPORT_PIPE 22 | #define PIPE_NAME "\\\\.\\pipe\\XPUINFO_IPC" 23 | int XPUInfoIPC_Client_Pipe(const char* serverCommandString, PROCESS_INFORMATION& pi); 24 | int XPUInfo_IPC_Server_Pipe(); 25 | #endif // TESTXPUINFOIPC_SUPPORT_PIPE 26 | #if TESTXPUINFOIPC_SUPPORT_SHAREDMEM 27 | int XPUInfoIPC_Client(const char* serverCommandString, PROCESS_INFORMATION& pi); 28 | int XPUInfo_IPC_Server(); 29 | #endif // TESTXPUINFOIPC_SUPPORT_SHAREDMEM 30 | #endif // _WIN32 31 | -------------------------------------------------------------------------------- /TestXPUInfoIPC/TestXPUInfoIPC_Shared/TestXPUInfoIPC_Shared.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | DebugDynamic 6 | Win32 7 | 8 | 9 | DebugDynamic 10 | x64 11 | 12 | 13 | Debug 14 | Win32 15 | 16 | 17 | ReleaseDynamic 18 | Win32 19 | 20 | 21 | ReleaseDynamic 22 | x64 23 | 24 | 25 | Release 26 | Win32 27 | 28 | 29 | Debug 30 | x64 31 | 32 | 33 | Release 34 | x64 35 | 36 | 37 | 38 | 16.0 39 | Win32Proj 40 | {4e2cb0fc-040a-4dbd-a20f-915c5590dcff} 41 | TestXPUInfoIPCShared 42 | 10.0 43 | 44 | 45 | 46 | Application 47 | true 48 | v143 49 | Unicode 50 | 51 | 52 | Application 53 | true 54 | v143 55 | Unicode 56 | 57 | 58 | Application 59 | false 60 | v143 61 | true 62 | Unicode 63 | 64 | 65 | Application 66 | false 67 | v143 68 | true 69 | Unicode 70 | 71 | 72 | StaticLibrary 73 | true 74 | v143 75 | Unicode 76 | 77 | 78 | StaticLibrary 79 | true 80 | v143 81 | Unicode 82 | 83 | 84 | StaticLibrary 85 | false 86 | v143 87 | true 88 | Unicode 89 | 90 | 91 | StaticLibrary 92 | false 93 | v143 94 | true 95 | Unicode 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | Level3 130 | true 131 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 132 | true 133 | 134 | 135 | Console 136 | true 137 | 138 | 139 | 140 | 141 | Level3 142 | true 143 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 144 | true 145 | 146 | 147 | Console 148 | true 149 | 150 | 151 | 152 | 153 | Level3 154 | true 155 | true 156 | true 157 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 158 | true 159 | 160 | 161 | Console 162 | true 163 | true 164 | true 165 | 166 | 167 | 168 | 169 | Level3 170 | true 171 | true 172 | true 173 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 174 | true 175 | 176 | 177 | Console 178 | true 179 | true 180 | true 181 | 182 | 183 | 184 | 185 | Level4 186 | true 187 | RAPIDJSON_HAS_STDSTRING=1;XPUINFO_USE_SYSTEMEMORYINFO;XPUINFO_USE_RUNTIMEVERSIONINFO;XPUINFO_USE_RAPIDJSON;XPUINFO_USE_IPC;TESTXPUINFOIPC_SHARED;_CRT_SECURE_NO_WARNINGS;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 188 | true 189 | $(SolutionDir)external\rapidjson\include;$(SolutionDir) 190 | stdcpp17 191 | 192 | 193 | Console 194 | true 195 | 196 | 197 | 198 | 199 | Level4 200 | true 201 | XPUINFO_BUILD_SHARED;RAPIDJSON_HAS_STDSTRING=1;XPUINFO_USE_SYSTEMEMORYINFO;XPUINFO_USE_RUNTIMEVERSIONINFO;XPUINFO_USE_RAPIDJSON;XPUINFO_USE_IPC;TESTXPUINFOIPC_SHARED;_CRT_SECURE_NO_WARNINGS;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 202 | true 203 | $(SolutionDir)external\rapidjson\include;$(SolutionDir) 204 | stdcpp17 205 | 206 | 207 | Console 208 | true 209 | 210 | 211 | 212 | 213 | Level4 214 | true 215 | true 216 | true 217 | RAPIDJSON_HAS_STDSTRING=1;XPUINFO_USE_SYSTEMEMORYINFO;XPUINFO_USE_RUNTIMEVERSIONINFO;XPUINFO_USE_RAPIDJSON;XPUINFO_USE_IPC;TESTXPUINFOIPC_SHARED;_CRT_SECURE_NO_WARNINGS;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 218 | true 219 | $(SolutionDir)external\rapidjson\include;$(SolutionDir) 220 | stdcpp17 221 | true 222 | 223 | 224 | Console 225 | true 226 | true 227 | true 228 | 229 | 230 | 231 | 232 | Level4 233 | true 234 | true 235 | true 236 | XPUINFO_BUILD_SHARED;RAPIDJSON_HAS_STDSTRING=1;XPUINFO_USE_SYSTEMEMORYINFO;XPUINFO_USE_RUNTIMEVERSIONINFO;XPUINFO_USE_RAPIDJSON;XPUINFO_USE_IPC;TESTXPUINFOIPC_SHARED;_CRT_SECURE_NO_WARNINGS;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 237 | true 238 | $(SolutionDir)external\rapidjson\include;$(SolutionDir) 239 | stdcpp17 240 | true 241 | 242 | 243 | Console 244 | true 245 | true 246 | true 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | -------------------------------------------------------------------------------- /TestXPUInfoIPC/TestXPUInfoIPC_Shared/TestXPUInfoIPC_Shared.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | 23 | 24 | Header Files 25 | 26 | 27 | -------------------------------------------------------------------------------- /external/.gitignore: -------------------------------------------------------------------------------- 1 | NVML/* 2 | !NVML/README.txt 3 | level-zero-build 4 | OpenCL-Headers-build 5 | OpenCL-Headers-install 6 | OpenCL-ICD-Loader-build 7 | OpenCL-ICD-Loader-install 8 | -------------------------------------------------------------------------------- /external/NVML/README.txt: -------------------------------------------------------------------------------- 1 | To support NVML: 2 | 1) Get package from https://developer.download.nvidia.com/compute/cuda/redist/cuda_nvml_dev/windows-x86_64/, currently cuda_nvml_dev-windows-x86_64-12.5.39-archive.zip 3 | 2) Extract zip to this folder 4 | 3) Run /external/buildExternalDeps.bat 5 | -------------------------------------------------------------------------------- /external/buildExternalDeps_L0.bat: -------------------------------------------------------------------------------- 1 | @setlocal 2 | 3 | @set _CMAKEGEN="Visual Studio 17 2022" 4 | set _EXTPATH=%~dp0 5 | 6 | @where cmake 7 | @if %ERRORLEVEL% neq 0 ( 8 | echo cmake not found! 9 | goto ERROR 10 | ) 11 | 12 | cmake -S %_EXTPATH%/level-zero -B %_EXTPATH%/level-zero-build -D CMAKE_INSTALL_PREFIX=%_EXTPATH%/level-zero-build/install -G %_CMAKEGEN% -A x64 13 | if %ERRORLEVEL% neq 0 goto ERROR 14 | cmake --build %_EXTPATH%/level-zero-build --target install --config RelWithDebInfo 15 | if %ERRORLEVEL% neq 0 goto ERROR 16 | 17 | goto END 18 | :ERROR 19 | @echo FAILED! 20 | @exit /b -1 21 | 22 | :END 23 | @endlocal 24 | -------------------------------------------------------------------------------- /external/buildExternalDeps_OCL.bat: -------------------------------------------------------------------------------- 1 | @setlocal 2 | 3 | @set _CMAKEGEN="Visual Studio 17 2022" 4 | set _EXTPATH=%~dp0 5 | 6 | @where cmake 7 | @if %ERRORLEVEL% neq 0 ( 8 | echo cmake not found! 9 | goto ERROR 10 | ) 11 | 12 | cmake -D BUILD_TESTING=OFF -D CMAKE_INSTALL_PREFIX=%_EXTPATH%/OpenCL-Headers-install -S %_EXTPATH%/OpenCL-Headers -B %_EXTPATH%/OpenCL-Headers-build -G %_CMAKEGEN% -A x64 13 | if %ERRORLEVEL% neq 0 goto ERROR 14 | 15 | cmake --build %_EXTPATH%/OpenCL-Headers-build --target install 16 | if %ERRORLEVEL% neq 0 goto ERROR 17 | 18 | cmake -D CMAKE_PREFIX_PATH=%~dp0/OpenCL-Headers-install -D CMAKE_INSTALL_PREFIX=%_EXTPATH%/OpenCL-ICD-Loader-install -S %_EXTPATH%/OpenCL-ICD-Loader -B %_EXTPATH%/OpenCL-ICD-Loader-build -G %_CMAKEGEN% -A x64 19 | if %ERRORLEVEL% neq 0 goto ERROR 20 | 21 | cmake --build %_EXTPATH%/OpenCL-ICD-Loader-build --target install --config RelWithDebInfo 22 | @REM -- /property:ContinueOnError=true 23 | if %ERRORLEVEL% neq 0 goto ERROR 24 | 25 | goto END 26 | :ERROR 27 | @echo FAILED! 28 | @exit /b -1 29 | 30 | :END 31 | @endlocal 32 | -------------------------------------------------------------------------------- /external/getNVMLDep.bat: -------------------------------------------------------------------------------- 1 | @setlocal 2 | set _EXTPATH=%~dp0 3 | 4 | @REM %_EXTPATH%\NVML is a pre-created folder 5 | @if EXIST %_EXTPATH%\NVML\lib\x64\nvml.lib if EXIST %_EXTPATH%\NVML\include\nvml.h goto NVML_DONE 6 | 7 | @echo Make sure env var https_proxy is set if needed! 8 | set NVML_BASE_NAME=cuda_nvml_dev-windows-x86_64-12.8.90-archive 9 | 10 | if NOT EXIST NVML.zip curl.exe -o NVML.zip https://developer.download.nvidia.com/compute/cuda/redist/cuda_nvml_dev/windows-x86_64/%NVML_BASE_NAME%.zip 11 | @if %ERRORLEVEL% neq 0 goto ERROR 12 | c:\Windows\System32\tar.exe xvf NVML.zip 13 | @if %ERRORLEVEL% neq 0 goto ERROR 14 | if NOT EXIST %_EXTPATH%\NVML\lib move %NVML_BASE_NAME%\lib %_EXTPATH%\NVML 15 | @if %ERRORLEVEL% neq 0 goto ERROR 16 | if NOT EXIST %_EXTPATH%\NVML\include move %NVML_BASE_NAME%\include %_EXTPATH%\NVML 17 | @if %ERRORLEVEL% neq 0 goto ERROR 18 | rmdir /s /q %NVML_BASE_NAME% 19 | del NVML.zip 20 | 21 | :ERROR 22 | exit /B %ERRORLEVEL% 23 | :NVML_DONE 24 | 25 | @endlocal 26 | -------------------------------------------------------------------------------- /external/l0_CMakeLists.patch: -------------------------------------------------------------------------------- 1 | diff --git a/CMakeLists.txt b/CMakeLists.txt 2 | index 67bcb9c..8e8ab67 100644 3 | --- a/CMakeLists.txt 4 | +++ b/CMakeLists.txt 5 | @@ -107,12 +107,12 @@ if(MSVC) 6 | set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /DYNAMICBASE") 7 | set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /guard:cf") 8 | # enable Spectre Mitigation, not supported by clang-cl 9 | - if((NOT CMAKE_CXX_COMPILER_ID STREQUAL Clang) AND (NOT CMAKE_CXX_COMPILER_ID STREQUAL IntelLLVM)) 10 | - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /Qspectre") 11 | - endif() 12 | - if((NOT CMAKE_C_COMPILER_ID STREQUAL Clang) AND NOT (CMAKE_C_COMPILER_ID STREQUAL IntelLLVM)) 13 | - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /Qspectre") 14 | - endif() 15 | +# if((NOT CMAKE_CXX_COMPILER_ID STREQUAL Clang) AND (NOT CMAKE_CXX_COMPILER_ID STREQUAL IntelLLVM)) 16 | +# set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /Qspectre") 17 | +# endif() 18 | +# if((NOT CMAKE_C_COMPILER_ID STREQUAL Clang) AND NOT (CMAKE_C_COMPILER_ID STREQUAL IntelLLVM)) 19 | +# set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /Qspectre") 20 | +# endif() 21 | endif() 22 | 23 | #CXX compiler support 24 | -------------------------------------------------------------------------------- /external/l0_removeSpectre.bat: -------------------------------------------------------------------------------- 1 | set _EXTPATH=%~dp0 2 | 3 | pushd %_EXTPATH%\level-zero 4 | git apply %_EXTPATH%\l0_CMakeLists.patch 5 | popd 6 | -------------------------------------------------------------------------------- /external/setup_submodules.bat: -------------------------------------------------------------------------------- 1 | @REM This is for setting up a local build or new git repo from a git archive 2 | @REM This info comes from: git submodule status 3 | 4 | @setlocal 5 | set _ROOT=%~dp0\.. 6 | pushd %_ROOT% 7 | 8 | rmdir external\rapidjson 9 | git submodule add https://github.com/Tencent/rapidjson.git ./external/rapidjson 10 | @if %ERRORLEVEL% neq 0 goto ERROR 11 | cd external\rapidjson 12 | git checkout 7c73dd7de7c4f14379b781418c6e947ad464c818 13 | cd ..\.. 14 | 15 | rmdir external\OpenCL-CLHPP 16 | git submodule add https://github.com/KhronosGroup/OpenCL-CLHPP.git ./external/OpenCL-CLHPP 17 | cd external\OpenCL-CLHPP 18 | git checkout 6db44b8db11952b53d271b6d1657ac5d04a45871 19 | cd ..\.. 20 | 21 | rmdir external\IGCL 22 | git submodule add https://github.com/intel/drivers.gpu.control-library ./external/IGCL 23 | cd external\IGCL 24 | git checkout 5d7c64e45ae47e95deef542f174d8bdc24ee23cf 25 | cd ..\.. 26 | 27 | rmdir external\level-zero 28 | git submodule add https://github.com/oneapi-src/level-zero ./external/level-zero 29 | cd external\level-zero 30 | git checkout v1.17.42 31 | cd ..\.. 32 | 33 | rmdir external\OpenCL-Headers 34 | git submodule add https://github.com/KhronosGroup/OpenCL-Headers.git ./external/OpenCL-Headers 35 | cd external\OpenCL-Headers 36 | git checkout 542d7a8f65ecfd88b38de35d8b10aa67b36b33b2 37 | cd ..\.. 38 | 39 | rmdir external\OpenCL-ICD-Loader 40 | git submodule add https://github.com/KhronosGroup/OpenCL-ICD-Loader.git ./external/OpenCL-ICD-Loader 41 | cd external\OpenCL-ICD-Loader 42 | git checkout v2024.05.08 43 | cd ..\.. 44 | 45 | git submodule update --init --recursive 46 | goto END 47 | :ERROR 48 | @echo "Error - do you need to set https_proxy?" 49 | 50 | :END 51 | git submodule status --recursive 52 | 53 | popd 54 | @endlocal 55 | -------------------------------------------------------------------------------- /utility/LibXPUInfo_D3D12Utility.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 Intel Corporation 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | #ifdef _WIN32 5 | 6 | #include "LibXPUInfo.h" 7 | #include "LibXPUInfo_D3D12Utility.h" 8 | #include 9 | #include 10 | #include 11 | 12 | using Microsoft::WRL::ComPtr; 13 | 14 | namespace XI { 15 | 16 | // NOTE: This can only be called once we know that DXCore is available 17 | bool CreateD3D12DeviceAndAllocateResource(IUnknown* pAdapter, size_t sizeInBytes, std::list>& outResources) 18 | { 19 | try 20 | { 21 | // Enable the D3D12 debug layer. 22 | #if 0 //defined(_DEBUG) 23 | ComPtr debugController; 24 | if (SUCCEEDED(D3D12GetDebugInterface(IID_PPV_ARGS(&debugController)))) 25 | { 26 | debugController->EnableDebugLayer(); 27 | } 28 | #endif 29 | ComPtr dxcoreAdapter; 30 | XPUINFO_REQUIRE_MSG(SUCCEEDED(pAdapter->QueryInterface(dxcoreAdapter.GetAddressOf())), "Error getting DXCore Adapter"); 31 | 32 | bool memRequestOk = false; 33 | // Requesting >16GB on Intel Meteor Lake with 32GB system RAM results in stack corruption exception in driver (unrecoverable). 34 | // Need to test on other devices, but for now set limit of min(16GB, memBudget). 35 | constexpr size_t maxIntelIntegratedAllocSize = 16ULL * 1024 * 1024 * 1024; 36 | if (dxcoreAdapter->IsQueryStateSupported(DXCoreAdapterState::AdapterMemoryBudget)) 37 | { 38 | DXCoreAdapterMemoryBudgetNodeSegmentGroup nsg{}; 39 | DXCoreAdapterMemoryBudget memBudget; 40 | /*THROW_IF_FAILED*/ 41 | HRESULT hr = dxcoreAdapter->QueryState(DXCoreAdapterState::AdapterMemoryBudget, &nsg, &memBudget); 42 | if (FAILED(hr)) 43 | { 44 | std::cout << __FUNCTION__ << ": Error getting adapter memory budget\n"; 45 | } 46 | else if (memBudget.budget < sizeInBytes) 47 | { 48 | std::cout << __FUNCTION__ << ": Memory requested, " << sizeInBytes / (1024.0 * 1024 * 1024) << 49 | " GB, exceeds available, " << memBudget.budget / (1024.0 * 1024 * 1024) << " GB\n"; 50 | } 51 | else 52 | { 53 | memRequestOk = true; 54 | } 55 | } 56 | 57 | if (memRequestOk) 58 | { 59 | // Create the D3D12 device. 60 | ComPtr device; 61 | if (FAILED(D3D12CreateDevice(pAdapter, D3D_FEATURE_LEVEL_12_1, IID_PPV_ARGS(&device)))) 62 | { 63 | throw std::runtime_error("Failed to create D3D12 device."); 64 | } 65 | 66 | auto lastResourceSize = sizeInBytes % maxIntelIntegratedAllocSize; 67 | auto resourceSize = sizeInBytes / maxIntelIntegratedAllocSize; 68 | auto numResourcesToAllocate = resourceSize + (lastResourceSize!=0); 69 | 70 | // Describe and create a committed resource. 71 | D3D12_HEAP_PROPERTIES heapProperties = {}; 72 | heapProperties.Type = D3D12_HEAP_TYPE_DEFAULT; 73 | heapProperties.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN; 74 | heapProperties.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN; 75 | heapProperties.CreationNodeMask = 1; 76 | heapProperties.VisibleNodeMask = 1; 77 | 78 | D3D12_RESOURCE_DESC resourceDesc = {}; 79 | resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; 80 | resourceDesc.Alignment = 0; 81 | resourceDesc.Width = sizeInBytes; 82 | resourceDesc.Height = 1; 83 | resourceDesc.DepthOrArraySize = 1; 84 | resourceDesc.MipLevels = 1; 85 | resourceDesc.Format = DXGI_FORMAT_UNKNOWN; 86 | resourceDesc.SampleDesc.Count = 1; 87 | resourceDesc.SampleDesc.Quality = 0; 88 | resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; 89 | resourceDesc.Flags = D3D12_RESOURCE_FLAG_NONE; 90 | 91 | for (size_t i = 0; i < numResourcesToAllocate; ++i) 92 | { 93 | ComPtr resource; 94 | resourceDesc.Width = (i==numResourcesToAllocate-1) ? lastResourceSize : maxIntelIntegratedAllocSize; 95 | 96 | if (FAILED(device->CreateCommittedResource( 97 | &heapProperties, 98 | D3D12_HEAP_FLAG_NONE, 99 | &resourceDesc, 100 | D3D12_RESOURCE_STATE_COMMON, 101 | nullptr, 102 | IID_PPV_ARGS(&resource)))) 103 | { 104 | throw std::runtime_error("Failed to create committed resource."); 105 | } 106 | outResources.emplace_back(std::move(resource)); 107 | } 108 | } 109 | } 110 | catch (const std::runtime_error& e) 111 | { 112 | std::cout << "CreateCommittedResource() failed: " << e.what() << std::endl; 113 | return false; 114 | } 115 | catch (...) 116 | { 117 | //throw std::runtime_error("Unhandled exception calling CreateCommittedResource()"); 118 | std::cout << "Unhandled exception calling CreateCommittedResource()\n"; 119 | return false; 120 | } 121 | return true; 122 | } 123 | 124 | } // XI 125 | 126 | #endif // _WIN32 127 | -------------------------------------------------------------------------------- /utility/LibXPUInfo_D3D12Utility.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 Intel Corporation 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | // This header/cpp is intended for use by an application for testing purposes and is not part of LibXPUInfo API. 5 | 6 | #pragma once 7 | #ifdef _WIN32 8 | #include 9 | #include 10 | #include 11 | 12 | namespace XI { 13 | 14 | // For testing purposes, allocate GPU memory in chunks of 16GB or less. 15 | bool CreateD3D12DeviceAndAllocateResource(IUnknown* pAdapter, size_t sizeInBytes, std::list>& outResources); 16 | 17 | } // XI 18 | 19 | #endif // _WIN32 20 | --------------------------------------------------------------------------------