├── .clang-format ├── .github ├── FUNDING.yml └── workflows │ ├── ci.yml │ └── mingw.cmake ├── .gitignore ├── CMakeLists.txt ├── LICENSE ├── README.md ├── examples ├── cpu.cpp ├── gpu.cpp ├── pci.cpp └── system.cpp ├── include └── infoware │ ├── cpu.hpp │ ├── detail │ ├── cpuid.hpp │ ├── memory.hpp │ ├── scope.hpp │ ├── sysctl.hpp │ └── winstring.hpp │ ├── gpu.hpp │ ├── infoware.hpp │ ├── linkage.hpp │ ├── pci.hpp │ ├── platform.hpp │ ├── system.hpp │ └── version.hpp ├── src ├── cpu │ ├── architecture │ │ ├── architecture_non_windows.cpp │ │ └── architecture_windows.cpp │ ├── endianness │ │ └── all.cpp │ ├── frequency │ │ ├── frequency_darwin.cpp │ │ ├── frequency_non_windows_non_darwin.cpp │ │ └── frequency_windows.cpp │ ├── instruction_set │ │ ├── instruction_set_darwin.cpp │ │ ├── instruction_set_darwin_arm.cpp │ │ ├── instruction_set_non_windows_non_darwin.cpp │ │ ├── instruction_set_windows.cpp │ │ └── instruction_set_x86.cpp │ ├── quantities_cache │ │ ├── quantities_cache_darwin.cpp │ │ ├── quantities_cache_non_windows_non_darwin.cpp │ │ └── quantities_cache_windows.cpp │ └── vendor_model_name │ │ ├── vendor_id_darwin_arm.cpp │ │ ├── vendor_id_x86.cpp │ │ ├── vendor_model_name_darwin.cpp │ │ ├── vendor_model_name_non_windows_non_darwin.cpp │ │ └── vendor_model_name_windows.cpp ├── detail │ ├── cpuid_non_windows_x86.cpp │ ├── cpuid_windows.cpp │ ├── sysctl_darwin.cpp │ ├── winstring_non_windows.cpp │ └── winstring_windows.cpp ├── gpu │ ├── Metal.mm │ ├── OpenCL.cpp │ ├── OpenGL_non_windows_non_darwin.cpp │ ├── OpenGL_windows.cpp │ ├── blank_all.cpp │ ├── d3d.cpp │ └── vulkan.cpp ├── pci.cpp ├── system │ ├── OS_info │ │ ├── os_info_darwin.cpp │ │ ├── os_info_non_windows_non_darwin.cpp │ │ └── os_info_windows.cpp │ ├── amounts │ │ ├── amounts_non_windows.cpp │ │ └── amounts_windows.cpp │ ├── displays │ │ ├── displays_darwin.cpp │ │ ├── displays_default_blank.cpp │ │ ├── displays_windows.cpp │ │ └── displays_x11.cpp │ ├── kernel_info │ │ ├── kernel_info_non_windows.cpp │ │ └── kernel_info_windows.cpp │ ├── memory │ │ ├── memory_darwin.cpp │ │ ├── memory_non_windows_non_darwin.cpp │ │ └── memory_windows.cpp │ └── process │ │ ├── process_stats_non_windows.cpp │ │ └── process_stats_windows.cpp └── version.cpp └── tools └── pci_generator.cpp /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | Language : Cpp 3 | BasedOnStyle : LLVM 4 | AlignAfterOpenBracket : true 5 | AlignEscapedNewlinesLeft : true 6 | AlignConsecutiveAssignments : true 7 | AllowShortFunctionsOnASingleLine : Inline 8 | AlwaysBreakTemplateDeclarations : true 9 | ColumnLimit : 160 10 | ConstructorInitializerIndentWidth: 6 11 | IndentCaseLabels : true 12 | MaxEmptyLinesToKeep : 2 13 | KeepEmptyLinesAtTheStartOfBlocks : false 14 | NamespaceIndentation : All 15 | PointerAlignment : Left 16 | SpacesBeforeTrailingComments : 2 17 | IndentWidth : 2 18 | TabWidth : 2 19 | UseTab : ForIndentation 20 | SpaceBeforeParens : Never 21 | ... 22 | 23 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: CC0-1.0 2 | # infoware - C++ System information Library 3 | 4 | # wait for the day nab gets a GitHub sponsorship 5 | #github: [ThePhD, nabijaczleweli] 6 | patreon: nabijaczleweli 7 | custom: https://www.paypal.me/nabijaczleweli 8 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: infoware CI 2 | on: 3 | push: 4 | pull_request: 5 | 6 | jobs: 7 | linux: 8 | name: ${{matrix.os}} amd64 (${{matrix.cpp-version}}) 9 | runs-on: ${{matrix.os}} 10 | strategy: 11 | fail-fast: false 12 | matrix: 13 | cpp-version: [g++, clang++] 14 | os: ["ubuntu-20.04", "ubuntu-22.04"] 15 | 16 | steps: 17 | - name: Checkout infoware 18 | uses: actions/checkout@v2 19 | with: 20 | path: infoware 21 | 22 | - name: Install apt packages 23 | run: sudo apt update && sudo apt install -y cmake ninja-build ocl-icd-opencl-dev 24 | 25 | - name: Generate CMake 26 | run: mkdir infoware/build && cd infoware/build && cmake -DCMAKE_BUILD_TYPE=Release -DINFOWARE_USE_OPENCL=ON -DINFOWARE_EXAMPLES=ON -DINFOWARE_TESTS=ON -G Ninja .. 27 | env: 28 | CXX: ${{matrix.cpp-version}} 29 | 30 | - name: Build Project 31 | run: cmake --build infoware/build 32 | 33 | - name: Run Tests 34 | run: ctest --test-dir infoware/build 35 | 36 | mingw: 37 | name: Linux MinGW (${{matrix.arch.pkg}}) 38 | runs-on: ubuntu-22.04 39 | strategy: 40 | fail-fast: false 41 | matrix: 42 | arch: 43 | - { pkg: i686, paths: i686 } 44 | - { pkg: x86-64, paths: x86_64 } 45 | 46 | steps: 47 | - name: Checkout infoware 48 | uses: actions/checkout@v2 49 | with: 50 | path: infoware 51 | 52 | - name: Install apt packages 53 | run: sudo apt update && sudo apt install -y cmake ninja-build g++-mingw-w64-${{matrix.arch.pkg}} 54 | 55 | - name: Generate CMake 56 | run: mkdir infoware/build && cd infoware/build && cmake -DCMAKE_BUILD_TYPE=Release -DMINGW_ARCH=${{matrix.arch.paths}} -DCMAKE_TOOLCHAIN_FILE=../.github/workflows/mingw.cmake -G Ninja .. 57 | 58 | - name: Build Project 59 | run: cmake --build infoware/build 60 | 61 | macos: 62 | name: macOS ${{matrix.os}} ${{matrix.arch}} 63 | runs-on: ${{matrix.os}} 64 | strategy: 65 | fail-fast: false 66 | matrix: 67 | os: ["macos-12", "macos-11", "macos-10.15"] 68 | arch: ["X64", "ARM64"] 69 | 70 | steps: 71 | - name: Checkout infoware 72 | uses: actions/checkout@v2 73 | with: 74 | path: infoware 75 | 76 | - name: Install homebrew packages 77 | run: brew install cmake ninja openssl 78 | 79 | - name: Generate CMake 80 | run: mkdir infoware/build && cd infoware/build && cmake -DCMAKE_BUILD_TYPE=Release -DINFOWARE_USE_OPENCL=ON -DINFOWARE_EXAMPLES=ON -DINFOWARE_TESTS=ON -G Ninja .. 81 | 82 | - name: Build Project 83 | run: cmake --build infoware/build 84 | 85 | - name: Run Tests 86 | run: ctest --test-dir infoware/build 87 | 88 | windows: # Windows amd64 and i386 build matrix 89 | strategy: 90 | fail-fast: false # Don't cancel other matrix jobs if one fails 91 | matrix: 92 | cfg: 93 | - { name: i386, arch: x86, chocoargs: "--x86"} 94 | - { name: amd64, arch: x64, chocoargs: ""} 95 | 96 | name: "Windows MSVC ${{matrix.cfg.name}}" 97 | runs-on: windows-2019 98 | steps: 99 | - name: Checkout infoware 100 | uses: actions/checkout@v2 101 | with: 102 | path: infoware 103 | 104 | - name: Configure MSBuild 105 | uses: ilammy/msvc-dev-cmd@v1 106 | with: 107 | arch: ${{ matrix.cfg.arch }} 108 | 109 | - name: Install chocolatey packages (${{ matrix.cfg.name }}) 110 | run: choco install ninja -y ${{ matrix.cfg.chocargs }} 111 | 112 | - name: Generate CMake 113 | run: mkdir infoware/build && cd infoware/build && cmake -G Ninja -DCMAKE_BUILD_TYPE=Release -DINFOWARE_EXAMPLES=ON -DINFOWARE_TESTS=ON .. 114 | 115 | - name: Build Project 116 | run: cmake --build infoware/build 117 | 118 | - name: Run Tests 119 | run: ctest --test-dir infoware/build 120 | -------------------------------------------------------------------------------- /.github/workflows/mingw.cmake: -------------------------------------------------------------------------------- 1 | set(CMAKE_SYSTEM_NAME Windows) 2 | set(CMAKE_SYSTEM_PROCESSOR ${MINGW_ARCH}) 3 | set(MINGW_TOOLCHAIN ${MINGW_ARCH}-w64-mingw32) 4 | 5 | set(CMAKE_FIND_ROOT_PATH /usr/${MINGW_TOOLCHAIN}) 6 | set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) 7 | set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) 8 | set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) 9 | 10 | set(CMAKE_C_COMPILER ${MINGW_TOOLCHAIN}-gcc) 11 | set(CMAKE_CXX_COMPILER ${MINGW_TOOLCHAIN}-g++) 12 | set(CMAKE_RC_COMPILER ${MINGW_TOOLCHAIN}-windres) 13 | set(CMAKE_MC_COMPILER ${MINGW_TOOLCHAIN}-windmc) 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !src 3 | !src/** 4 | !examples 5 | !examples/** 6 | !include 7 | !include/** 8 | !tools 9 | !tools/** 10 | !.gitignore 11 | !.github/** 12 | !.clang-format 13 | !CMakeLists.txt 14 | !LICENSE 15 | !README.md 16 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: CC0-1.0 2 | # infoware - C++ System information Library 3 | 4 | 5 | cmake_minimum_required(VERSION 3.6.0) 6 | 7 | 8 | set(infoware_version "0.6.0") 9 | 10 | project(infoware VERSION "${infoware_version}" LANGUAGES CXX) 11 | 12 | 13 | option(INFOWARE_USE_VULKAN "Add public, transitive define to infoware to use Vulkan for GPU detection." OFF) 14 | option(INFOWARE_USE_D3D "Add public, transitive define to infoware to use Direct 3D for GPU detection." OFF) 15 | option(INFOWARE_USE_OPENGL "Add public, transitive define to infoware to use Open Graphics Language (OpenGL) for GPU detection." OFF) 16 | option(INFOWARE_USE_OPENCL "Add public, transitive define to infoware to use Open Compute Language (OpenCL) for GPU detection." OFF) 17 | 18 | option(INFOWARE_USE_X11 "Add public, transitive define to infoware to use X11 for display detection." OFF) 19 | 20 | option(INFOWARE_USE_PCIIDS "Want PCI IDs. If disabled, the PCI ID database will not be compiled, and the pci.hpp API will be unimplemented." ON) 21 | 22 | option(INFOWARE_EXAMPLES "Add infoware examples to the build." OFF) 23 | option(INFOWARE_TESTS "Input tests for infoware." OFF) 24 | 25 | set(INFOWARE_PCI_IDS_PATH "" CACHE FILEPATH "pci.ids file to use. Overrides cloning from INFOWARE_PCI_IDS_REPOSITORY.") 26 | set(INFOWARE_PCI_IDS_REPOSITORY "https://github.com/pciutils/pciids" CACHE STRING "Path/URL to clone a pciids git repository from if override path not supplied. Defaults to https://github.com/pciutils/pciids.") 27 | 28 | if(INFOWARE_USE_VULKAN) 29 | if(INFOWARE_USE_D3D) 30 | message(WARNING "INFOWARE_USE_D3D specified, but the higher-priority INFOWARE_USE_VULKAN was specified, too, and will be used instead.") 31 | elseif(INFOWARE_USE_OPENCL) 32 | message(WARNING "INFOWARE_USE_OPENCL specified, but the higher-priority INFOWARE_USE_VULKAN was specified, too, and will be used instead.") 33 | elseif(INFOWARE_USE_OPENGL) 34 | message(WARNING "INFOWARE_USE_OPENGL specified, but the higher-priority INFOWARE_USE_VULKAN was specified, too, and will be used instead.") 35 | endif() 36 | endif() 37 | 38 | if(INFOWARE_USE_D3D) 39 | if(NOT WIN32) 40 | message(FATAL_ERROR "INFOWARE_USE_D3D only available on Win32.") 41 | endif() 42 | if(INFOWARE_USE_OPENCL) 43 | message(WARNING "INFOWARE_USE_OPENCL specified, but the higher-priority INFOWARE_USE_D3D was specified, too, and will be used instead.") 44 | elseif(INFOWARE_USE_OPENGL) 45 | message(WARNING "INFOWARE_USE_OPENGL specified, but the higher-priority INFOWARE_USE_D3D was specified, too, and will be used instead.") 46 | endif() 47 | endif() 48 | 49 | if(INFOWARE_USE_OPENCL) 50 | if(INFOWARE_USE_OPENGL) 51 | message(WARNING "INFOWARE_USE_OPENGL specified, but the higher-priority INFOWARE_USE_OPENCL was specified, too, and will be used instead.") 52 | endif() 53 | endif() 54 | 55 | if(INFOWARE_USE_X11 AND WIN32) 56 | message(WARNING "INFOWARE_USE_X11 specified, but compiling for Win32, WinAPI will be used instead.") 57 | endif() 58 | 59 | if(INFOWARE_USE_OPENGL AND APPLE) 60 | message(WARNING "INFOWARE_USE_OPENGL specified, but compiling for Darwin, Metal will be used instead.") 61 | endif() 62 | 63 | file(GLOB_RECURSE infoware_source_files LIST_DIRECTORIES false CONFIGURE_DEPENDS src/*.cpp) 64 | if(APPLE) 65 | file(GLOB_RECURSE infoware_objc_source_files LIST_DIRECTORIES FALSE CONFIGURE_DEPENDS src/*.mm) 66 | list(APPEND infoware_source_files ${infoware_objc_source_files}) 67 | endif() 68 | file(GLOB_RECURSE infoware_private_headers LIST_DIRECTORIES false CONFIGURE_DEPENDS include/infoware/detail/*.hpp) 69 | file(GLOB infoware_public_headers LIST_DIRECTORIES false CONFIGURE_DEPENDS include/infoware/*.hpp) 70 | 71 | add_library(infoware ${infoware_source_files} ${infoware_public_headers} ${infoware_private_headers}) 72 | add_library(iware::infoware ALIAS infoware) 73 | 74 | 75 | target_include_directories(infoware PRIVATE "${CMAKE_CURRENT_BINARY_DIR}") 76 | 77 | set_target_properties(infoware PROPERTIES CXX_STANDARD 14 78 | CXX_STANDARD_REQUIRED ON 79 | CXX_EXTENSIONS OFF 80 | 81 | PUBLIC_HEADER "${infoware_public_headers}" 82 | RUNTIME_OUTPUT_DIRECTORY "bin" 83 | LIBRARY_OUTPUT_DIRECTORY "bin" 84 | ARCHIVE_OUTPUT_DIRECTORY "lib" 85 | 86 | DEBUG_POSTFIX "d" 87 | MINSIZEREL_POSTFIX "msr" 88 | RELWITHDEBINFO_POSTFIX "rwdi") 89 | 90 | target_compile_definitions(infoware PRIVATE INFOWARE_VERSION="${infoware_version}" 91 | INFOWARE_BUILDING=1) 92 | if(BUILD_SHARED_LIBS) # Controls add_library() w/o explicit mode 93 | target_compile_definitions(infoware PUBLIC INFOWARE_DLL=1) 94 | endif() 95 | 96 | if(INFOWARE_USE_PCIIDS) 97 | target_compile_definitions(infoware PRIVATE INFOWARE_USE_PCIIDS) 98 | 99 | if(NOT Git_FOUND) # Could be pre-injected 100 | find_package(Git) 101 | endif() 102 | 103 | set(INFOWARE_PCI_DATA_DIR infoware_generated CACHE PATH "Output directory for the PCI ids generator") 104 | set(INFOWARE_PCI_DATA_HPP pci_data.hpp) 105 | set(INFOWARE_PCI_DATA_GEN "${INFOWARE_PCI_DATA_DIR}/${INFOWARE_PCI_DATA_HPP}") 106 | set(infoware_pci_ids_error "\ 107 | The pci.ids file, downloadable from https://github.com/pciutils/pciids or http://pci-ids.ucw.cz, is required for building infoware, \ 108 | and cloned automatically from that GitHub repository by default.\n\ 109 | To use a local copy, set INFOWARE_PCI_IDS_PATH to its location.") 110 | if(NOT CMAKE_CROSSCOMPILING) 111 | if(INFOWARE_PCI_IDS_PATH) 112 | if(NOT EXISTS "${INFOWARE_PCI_IDS_PATH}") 113 | message(WARNING "The specified pci.ids file INFOWARE_PCI_IDS_PATH=${INFOWARE_PCI_IDS_PATH} doesn't seem to exist.") 114 | endif() 115 | set(infoware_pci_ids_file "${INFOWARE_PCI_IDS_PATH}") 116 | elseif(NOT Git_FOUND) 117 | message(SEND_ERROR "Couldn't find a usable git executable in the environment, and the CMake variable INFOWARE_PCI_IDS_PATH is empty.\n${infoware_pci_ids_error}") 118 | else() 119 | # Thanks, @griwes 120 | set(infoware_pci_ids_file "${CMAKE_CURRENT_BINARY_DIR}/pciids/pci.ids") 121 | if(EXISTS "${infoware_pci_ids_file}") 122 | execute_process(COMMAND "${GIT_EXECUTABLE}" remote set-url origin "${INFOWARE_PCI_IDS_REPOSITORY}" 123 | WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/pciids") 124 | execute_process(COMMAND "${GIT_EXECUTABLE}" pull 125 | WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/pciids" 126 | RESULT_VARIABLE infoware_git_pciids_clone_err) 127 | else() 128 | execute_process(COMMAND "${GIT_EXECUTABLE}" clone "${INFOWARE_PCI_IDS_REPOSITORY}" -- pciids 129 | WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" 130 | RESULT_VARIABLE infoware_git_pciids_clone_err) 131 | endif() 132 | if(infoware_git_pciids_clone_err) 133 | message(SEND_ERROR "Cloning/pulling pciids repository from ${INFOWARE_PCI_IDS_REPOSITORY} failed with ${infoware_git_pciids_clone_err}.\n${infoware_pci_ids_error}") 134 | endif() 135 | endif() 136 | 137 | add_executable(infoware_pci_generator tools/pci_generator.cpp) 138 | set_target_properties(infoware_pci_generator PROPERTIES CXX_STANDARD 14 139 | CXX_STANDARD_REQUIRED ON 140 | CXX_EXTENSIONS OFF) 141 | 142 | add_custom_command(OUTPUT ${INFOWARE_PCI_DATA_GEN} 143 | COMMAND ${CMAKE_COMMAND} -E make_directory "${INFOWARE_PCI_DATA_DIR}" 144 | COMMAND $ "${infoware_pci_ids_file}" > "${INFOWARE_PCI_DATA_GEN}" 145 | DEPENDS "${infoware_pci_ids_file}" 146 | COMMENT "Generating ${INFOWARE_PCI_DATA_HPP}") 147 | add_custom_target(infoware_generate_pcis DEPENDS "${INFOWARE_PCI_DATA_GEN}") 148 | else() 149 | include(ExternalProject) 150 | ExternalProject_Add(infoware_generate_pcis 151 | SOURCE_DIR ${CMAKE_SOURCE_DIR} 152 | PREFIX ${CMAKE_BINARY_DIR}/pci_generator 153 | BINARY_DIR ${CMAKE_BINARY_DIR}/pci_generator 154 | BUILD_COMMAND ${CMAKE_COMMAND} --build --target infoware_generate_pcis 155 | INSTALL_COMMAND "" 156 | BUILD_ALWAYS ON 157 | CMAKE_ARGS -DINFOWARE_PCI_DATA_DIR:PATH=${CMAKE_BINARY_DIR}/${INFOWARE_PCI_DATA_DIR}) 158 | endif() 159 | add_dependencies(infoware infoware_generate_pcis) 160 | endif(INFOWARE_USE_PCIIDS) 161 | 162 | 163 | if(MSVC) 164 | # Only CMake 3.15.0 makes this stuff not necessary, but we have a shitty 165 | # minimum required version :/ 166 | string(REGEX REPLACE "/W[0-4]" "" CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS}) 167 | target_compile_options(infoware PRIVATE /EHsc /W4) 168 | target_compile_definitions(infoware PRIVATE UNICODE _UNICODE) 169 | else() 170 | target_compile_options(infoware PRIVATE -pedantic -Wall -Wextra -pipe) 171 | endif() 172 | 173 | if(WIN32 AND NOT MSVC) 174 | target_compile_options(infoware PRIVATE -march=native) 175 | endif() 176 | 177 | if(WIN32) 178 | target_link_libraries(infoware PRIVATE gdi32 version ole32 oleaut32 wbemuuid ntdll) 179 | endif() 180 | 181 | 182 | if(APPLE) 183 | target_link_libraries(infoware PRIVATE "-framework CoreFoundation" "-framework CoreGraphics" "-framework Metal") 184 | endif() 185 | 186 | 187 | if(INFOWARE_USE_VULKAN) 188 | target_compile_definitions(infoware PUBLIC INFOWARE_USE_VULKAN) 189 | find_package(Vulkan REQUIRED) 190 | target_link_libraries(infoware PUBLIC Vulkan::Vulkan) 191 | elseif(INFOWARE_USE_D3D) 192 | target_compile_definitions(infoware PUBLIC INFOWARE_USE_D3D) 193 | if (WIN32) 194 | target_link_libraries(infoware PUBLIC dxgi) 195 | endif() 196 | elseif(INFOWARE_USE_OPENCL) 197 | target_compile_definitions(infoware PUBLIC INFOWARE_USE_OPENCL) 198 | if(NOT APPLE) 199 | find_package(OpenCL REQUIRED) 200 | target_link_libraries(infoware PUBLIC OpenCL::OpenCL) 201 | else() 202 | target_link_libraries(infoware PUBLIC "-framework OpenCL") 203 | endif() 204 | elseif(INFOWARE_USE_OPENGL) 205 | target_compile_definitions(infoware PUBLIC INFOWARE_USE_OPENGL) 206 | 207 | if(WIN32) 208 | target_link_libraries(infoware PUBLIC opengl32) 209 | elseif(NOT APPLE) 210 | find_package(OpenGL REQUIRED) 211 | target_link_libraries(infoware PUBLIC OpenGL::EGL) # libgl1-mesa-dev 212 | else() 213 | target_link_libraries(infoware PUBLIC "-framework OpenGL") 214 | endif() 215 | endif() 216 | 217 | 218 | if(NOT APPLE AND INFOWARE_USE_X11) 219 | include(FindX11) 220 | target_compile_definitions(infoware PUBLIC INFOWARE_USE_X11) 221 | target_include_directories(infoware PUBLIC ${X11_INCLUDE_DIR}) 222 | target_link_libraries(infoware PUBLIC ${X11_LIBRARIES}) 223 | if(X11_Xrandr_FOUND) 224 | target_link_libraries(infoware PUBLIC ${X11_Xrandr_LIB}) 225 | else() 226 | message(FATAL_ERROR "Xrandr is required for infoware") 227 | endif() 228 | endif() 229 | 230 | 231 | if(INFOWARE_EXAMPLES) 232 | file(GLOB infoware_example_sources LIST_DIRECTORIES false examples/*.cpp) 233 | 234 | foreach(infoware_example_source IN LISTS infoware_example_sources) 235 | string(REGEX REPLACE "([^/\\]+[/\\])*([^/\\]+)\\.cpp" "\\2" infoware_example_name "${infoware_example_source}") 236 | string(REPLACE "/" "" infoware_example_name "${infoware_example_name}") 237 | 238 | add_executable(infoware_${infoware_example_name}_example "${infoware_example_source}") 239 | add_executable(iware::${infoware_example_name}_example ALIAS infoware_${infoware_example_name}_example) 240 | 241 | target_link_libraries(infoware_${infoware_example_name}_example PUBLIC infoware) 242 | 243 | set_target_properties(infoware_${infoware_example_name}_example PROPERTIES CXX_STANDARD 14 244 | CXX_STANDARD_REQUIRED ON 245 | CXX_EXTENSIONS OFF 246 | RUNTIME_OUTPUT_DIRECTORY "bin" 247 | LIBRARY_OUTPUT_DIRECTORY "bin" 248 | ARCHIVE_OUTPUT_DIRECTORY "lib") 249 | 250 | if(INFOWARE_TESTS) 251 | add_test(NAME example_${infoware_example_name} COMMAND infoware_${infoware_example_name}_example) 252 | endif() 253 | endforeach() 254 | endif() 255 | 256 | 257 | if(INFOWARE_TESTS) 258 | enable_testing() 259 | endif() 260 | 261 | 262 | # Use GNU install directories if CMAKE_INSTALL_PREFIX not specified 263 | include(GNUInstallDirs) 264 | 265 | # Specify where library and headers will be installed 266 | install(TARGETS infoware 267 | EXPORT infowareTargets 268 | ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}" 269 | RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" 270 | LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}" 271 | PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/infoware) 272 | target_include_directories(infoware PUBLIC $ 273 | $) 274 | 275 | # Create infowareConfigVersion package used to specify installed package version 276 | include(CMakePackageConfigHelpers) 277 | write_basic_package_version_file("${CMAKE_CURRENT_BINARY_DIR}/cmake/infowareConfigVersion.cmake" 278 | VERSION ${VERSION} 279 | COMPATIBILITY AnyNewerVersion) 280 | install(FILES ${CMAKE_CURRENT_BINARY_DIR}/cmake/infowareConfigVersion.cmake 281 | DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/infoware 282 | COMPONENT devel) 283 | 284 | # Specifying config file that will be used to find a library using find_package(). 285 | export(TARGETS ${PROJECT_NAME} 286 | FILE infowareConfig.cmake) 287 | install(EXPORT infowareTargets 288 | FILE infowareConfig.cmake 289 | DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/infoware) 290 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | CC0 1.0 Universal 2 | 3 | Statement of Purpose 4 | 5 | The laws of most jurisdictions throughout the world automatically confer 6 | exclusive Copyright and Related Rights (defined below) upon the creator and 7 | subsequent owner(s) (each and all, an "owner") of an original work of 8 | authorship and/or a database (each, a "Work"). 9 | 10 | Certain owners wish to permanently relinquish those rights to a Work for the 11 | purpose of contributing to a commons of creative, cultural and scientific 12 | works ("Commons") that the public can reliably and without fear of later 13 | claims of infringement build upon, modify, incorporate in other works, reuse 14 | and redistribute as freely as possible in any form whatsoever and for any 15 | purposes, including without limitation commercial purposes. These owners may 16 | contribute to the Commons to promote the ideal of a free culture and the 17 | further production of creative, cultural and scientific works, or to gain 18 | reputation or greater distribution for their Work in part through the use and 19 | efforts of others. 20 | 21 | For these and/or other purposes and motivations, and without any expectation 22 | of additional consideration or compensation, the person associating CC0 with a 23 | Work (the "Affirmer"), to the extent that he or she is an owner of Copyright 24 | and Related Rights in the Work, voluntarily elects to apply CC0 to the Work 25 | and publicly distribute the Work under its terms, with knowledge of his or her 26 | Copyright and Related Rights in the Work and the meaning and intended legal 27 | effect of CC0 on those rights. 28 | 29 | 1. Copyright and Related Rights. A Work made available under CC0 may be 30 | protected by copyright and related or neighboring rights ("Copyright and 31 | Related Rights"). Copyright and Related Rights include, but are not limited 32 | to, the following: 33 | 34 | i. the right to reproduce, adapt, distribute, perform, display, communicate, 35 | and translate a Work; 36 | 37 | ii. moral rights retained by the original author(s) and/or performer(s); 38 | 39 | iii. publicity and privacy rights pertaining to a person's image or likeness 40 | depicted in a Work; 41 | 42 | iv. rights protecting against unfair competition in regards to a Work, 43 | subject to the limitations in paragraph 4(a), below; 44 | 45 | v. rights protecting the extraction, dissemination, use and reuse of data in 46 | a Work; 47 | 48 | vi. database rights (such as those arising under Directive 96/9/EC of the 49 | European Parliament and of the Council of 11 March 1996 on the legal 50 | protection of databases, and under any national implementation thereof, 51 | including any amended or successor version of such directive); and 52 | 53 | vii. other similar, equivalent or corresponding rights throughout the world 54 | based on applicable law or treaty, and any national implementations thereof. 55 | 56 | 2. Waiver. To the greatest extent permitted by, but not in contravention of, 57 | applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and 58 | unconditionally waives, abandons, and surrenders all of Affirmer's Copyright 59 | and Related Rights and associated claims and causes of action, whether now 60 | known or unknown (including existing as well as future claims and causes of 61 | action), in the Work (i) in all territories worldwide, (ii) for the maximum 62 | duration provided by applicable law or treaty (including future time 63 | extensions), (iii) in any current or future medium and for any number of 64 | copies, and (iv) for any purpose whatsoever, including without limitation 65 | commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes 66 | the Waiver for the benefit of each member of the public at large and to the 67 | detriment of Affirmer's heirs and successors, fully intending that such Waiver 68 | shall not be subject to revocation, rescission, cancellation, termination, or 69 | any other legal or equitable action to disrupt the quiet enjoyment of the Work 70 | by the public as contemplated by Affirmer's express Statement of Purpose. 71 | 72 | 3. Public License Fallback. Should any part of the Waiver for any reason be 73 | judged legally invalid or ineffective under applicable law, then the Waiver 74 | shall be preserved to the maximum extent permitted taking into account 75 | Affirmer's express Statement of Purpose. In addition, to the extent the Waiver 76 | is so judged Affirmer hereby grants to each affected person a royalty-free, 77 | non transferable, non sublicensable, non exclusive, irrevocable and 78 | unconditional license to exercise Affirmer's Copyright and Related Rights in 79 | the Work (i) in all territories worldwide, (ii) for the maximum duration 80 | provided by applicable law or treaty (including future time extensions), (iii) 81 | in any current or future medium and for any number of copies, and (iv) for any 82 | purpose whatsoever, including without limitation commercial, advertising or 83 | promotional purposes (the "License"). The License shall be deemed effective as 84 | of the date CC0 was applied by Affirmer to the Work. Should any part of the 85 | License for any reason be judged legally invalid or ineffective under 86 | applicable law, such partial invalidity or ineffectiveness shall not 87 | invalidate the remainder of the License, and in such case Affirmer hereby 88 | affirms that he or she will not (i) exercise any of his or her remaining 89 | Copyright and Related Rights in the Work or (ii) assert any associated claims 90 | and causes of action with respect to the Work, in either case contrary to 91 | Affirmer's express Statement of Purpose. 92 | 93 | 4. Limitations and Disclaimers. 94 | 95 | a. No trademark or patent rights held by Affirmer are waived, abandoned, 96 | surrendered, licensed or otherwise affected by this document. 97 | 98 | b. Affirmer offers the Work as-is and makes no representations or warranties 99 | of any kind concerning the Work, express, implied, statutory or otherwise, 100 | including without limitation warranties of title, merchantability, fitness 101 | for a particular purpose, non infringement, or the absence of latent or 102 | other defects, accuracy, or the present or absence of errors, whether or not 103 | discoverable, all to the greatest extent permissible under applicable law. 104 | 105 | c. Affirmer disclaims responsibility for clearing rights of other persons 106 | that may apply to the Work or any use thereof, including without limitation 107 | any person's Copyright and Related Rights in the Work. Further, Affirmer 108 | disclaims responsibility for obtaining any necessary consents, permissions 109 | or other rights required for any use of the Work. 110 | 111 | d. Affirmer understands and acknowledges that Creative Commons is not a 112 | party to this document and has no duty or obligation with respect to this 113 | CC0 or use of the Work. 114 | 115 | For more information, please see 116 | 117 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # infoware [![License](https://img.shields.io/badge/license-CC0-green.svg?style=flat)](LICENSE) [![CI status](https://github.com/ThePhD/infoware/actions/workflows/ci.yml/badge.svg)](https://github.com/ThePhD/infoware/actions/workflows/ci.yml) 2 | 3 | C++ Library for pulling system and hardware information, without hitting the command line. 4 | 5 | 6 | ## Requirements 7 | No non-built-in ones by default.
8 | Some libraries are required for extended functionality. See the [Configurability](#configurability) section below for details. 9 | 10 | On Windows one needs to link to `gdi32`, `version`, `Ole32`, `OleAut32`, `wbemuuid` and `ntdll`. 11 | 12 | A usable `git` binary is required by default, to clone https://github.com/pciutils/pciids. 13 | `INFOWARE_PCI_IDS_REPOSITORY` can be set to override that clone URI. 14 | `INFOWARE_PCI_IDS_PATH` can be set to use the specified file instead of using git at all. 15 | 16 | ## Configurability 17 | |CMake definition and C++ preprocessor macro| Meaning |Linker library| Priority | 18 | |-------------------------------------------|-----------------------------------|--------------|---------------| 19 | | `INFOWARE_USE_X11` | Use X11 for display detection | `X11` | D3D | 21 | | `INFOWARE_USE_D3D` | Use D3D for GPU detection | `dxgi` | >OpenCL | 22 | | `INFOWARE_USE_OPENCL` | Use OpenCL for GPU detection | `OpenCL` | Darwin | 23 | | `INFOWARE_USE_OPENGL` | Use OpenGL for GPU detection |OS-dependent\*| 8 | #include 9 | 10 | 11 | static const char* cache_type_name(iware::cpu::cache_type_t cache_type) noexcept; 12 | static const char* architecture_name(iware::cpu::architecture_t architecture) noexcept; 13 | static const char* endianness_name(iware::cpu::endianness_t endianness) noexcept; 14 | 15 | 16 | int main() { 17 | std::cout << "Infoware version " << iware::version << '\n'; 18 | 19 | { 20 | const auto quantities = iware::cpu::quantities(); 21 | std::cout << "\n" 22 | " Quantities:\n" 23 | << " Logical CPUs : " << quantities.logical << '\n' 24 | << " Physical CPUs: " << quantities.physical << '\n' 25 | << " CPU packages : " << quantities.packages << '\n'; 26 | } 27 | 28 | { 29 | std::cout << "\n" 30 | " Caches:\n"; 31 | for(auto i = 1u; i <= 3; ++i) { 32 | const auto cache = iware::cpu::cache(i); 33 | std::cout << " L" << i << ":\n" 34 | << " Size : " << cache.size << "B\n" 35 | << " Line size : " << cache.line_size << "B\n" 36 | << " Associativity: " << static_cast(cache.associativity) << '\n' 37 | << " Type : " << cache_type_name(cache.type) << '\n'; 38 | } 39 | } 40 | 41 | { 42 | std::cout << "\n" 43 | << " Architecture: " << architecture_name(iware::cpu::architecture()) << '\n' 44 | << " Frequency: " << iware::cpu::frequency() << " Hz\n" 45 | << " Endianness: " << endianness_name(iware::cpu::endianness()) << '\n' 46 | << " Model name: " << iware::cpu::model_name() << '\n' 47 | << " Vendor ID: " << iware::cpu::vendor_id() << '\n'; 48 | } 49 | 50 | { 51 | std::cout << std::boolalpha 52 | << "\n" 53 | " Instruction set support:\n"; 54 | for(auto&& set : {std::make_pair("3D-now!", iware::cpu::instruction_set_t::s3d_now), // 55 | std::make_pair("MMX ", iware::cpu::instruction_set_t::mmx), // 56 | std::make_pair("SSE ", iware::cpu::instruction_set_t::sse), // 57 | std::make_pair("SSE2 ", iware::cpu::instruction_set_t::sse2), // 58 | std::make_pair("SSE3 ", iware::cpu::instruction_set_t::sse3), // 59 | std::make_pair("AVX ", iware::cpu::instruction_set_t::avx), // 60 | std::make_pair("Neon ", iware::cpu::instruction_set_t::neon)}) 61 | std::cout << " " << set.first << ": " << iware::cpu::instruction_set_supported(set.second) << '\n'; 62 | } 63 | 64 | std::cout << '\n'; 65 | } 66 | 67 | 68 | static const char* cache_type_name(iware::cpu::cache_type_t cache_type) noexcept { 69 | switch(cache_type) { 70 | case iware::cpu::cache_type_t::unified: 71 | return "Unified"; 72 | case iware::cpu::cache_type_t::instruction: 73 | return "Instruction"; 74 | case iware::cpu::cache_type_t::data: 75 | return "Data"; 76 | case iware::cpu::cache_type_t::trace: 77 | return "Trace"; 78 | default: 79 | return "Unknown"; 80 | } 81 | } 82 | 83 | static const char* architecture_name(iware::cpu::architecture_t architecture) noexcept { 84 | switch(architecture) { 85 | case iware::cpu::architecture_t::x64: 86 | return "x64"; 87 | case iware::cpu::architecture_t::arm: 88 | return "ARM"; 89 | case iware::cpu::architecture_t::itanium: 90 | return "Itanium"; 91 | case iware::cpu::architecture_t::x86: 92 | return "x86"; 93 | default: 94 | return "Unknown"; 95 | } 96 | } 97 | 98 | static const char* endianness_name(iware::cpu::endianness_t endianness) noexcept { 99 | switch(endianness) { 100 | case iware::cpu::endianness_t::little: 101 | return "Little-Endian"; 102 | case iware::cpu::endianness_t::big: 103 | return "Big-Endian"; 104 | default: 105 | return "Unknown"; 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /examples/gpu.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: CC0-1.0 2 | // infoware - C++ System information Library 3 | 4 | 5 | #include "infoware/gpu.hpp" 6 | #include "infoware/version.hpp" 7 | #include 8 | 9 | 10 | static const char* vendor_name(iware::gpu::vendor_t vendor) noexcept; 11 | 12 | 13 | int main() { 14 | std::cout << "Infoware version " << iware::version << '\n'; 15 | 16 | { 17 | const auto device_properties = iware::gpu::device_properties(); 18 | std::cout << "\n" 19 | " Properties:\n"; 20 | if(device_properties.empty()) 21 | std::cout << " No detection methods enabled\n"; 22 | else 23 | for(auto i = 0u; i < device_properties.size(); ++i) { 24 | const auto& properties_of_device = device_properties[i]; 25 | std::cout << " Device #" << (i + 1) << ":\n" 26 | << " Vendor : " << vendor_name(properties_of_device.vendor) << '\n' 27 | << " Name : " << properties_of_device.name << '\n' 28 | << " RAM size : " << properties_of_device.memory_size << "B\n" 29 | << " Cache size : " << properties_of_device.cache_size << "B\n" 30 | << " Max frequency: " << properties_of_device.max_frequency << "Hz\n"; 31 | } 32 | } 33 | 34 | std::cout << '\n'; 35 | } 36 | 37 | 38 | static const char* vendor_name(iware::gpu::vendor_t vendor) noexcept { 39 | switch(vendor) { 40 | case iware::gpu::vendor_t::intel: 41 | return "Intel"; 42 | case iware::gpu::vendor_t::amd: 43 | return "AMD"; 44 | case iware::gpu::vendor_t::nvidia: 45 | return "NVidia"; 46 | case iware::gpu::vendor_t::microsoft: 47 | return "Microsoft"; 48 | case iware::gpu::vendor_t::qualcomm: 49 | return "Qualcomm"; 50 | case iware::gpu::vendor_t::apple: 51 | return "Apple"; 52 | default: 53 | return "Unknown"; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /examples/pci.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: CC0-1.0 2 | // infoware - C++ System information Library 3 | 4 | 5 | #include "infoware/pci.hpp" 6 | #include "infoware/version.hpp" 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | 13 | namespace { 14 | struct format_pci_id { 15 | std::uint64_t pci_id; 16 | }; 17 | 18 | std::ostream& operator<<(std::ostream& out, const format_pci_id& id) { 19 | out << "0x" << std::setw(sizeof(std::uint64_t) * 2) << std::setfill('0') << std::internal << std::hex << std::uppercase << id.pci_id; 20 | return out; 21 | } 22 | } // anonymous namespace 23 | 24 | static void print_named_id(const char* subsystem, std::uint64_t pci_id); 25 | static bool print_vendor(std::uint64_t vendor_id, const char* vendor_name); 26 | 27 | 28 | int main(int, const char** argv) { 29 | std::cout << "Infoware version " << iware::version << '\n'; 30 | 31 | #ifdef INFOWARE_USE_PCIIDS 32 | if(argv[1] == nullptr) 33 | std::cout << "Usage: " << argv[0] << " [device_id]" << '\n'; 34 | else { 35 | const auto vendor_id = std::strtoull(argv[1], nullptr, 0); 36 | 37 | if(argv[2] == nullptr) { 38 | if(!print_vendor(vendor_id, iware::pci::identify_vendor(vendor_id))) 39 | return 1; 40 | } else { 41 | const auto device_id = std::strtoull(argv[2], nullptr, 0); 42 | 43 | const auto device = iware::pci::identify_device(vendor_id, device_id); 44 | const auto vendor_ok = print_vendor(vendor_id, device.vendor_name); 45 | 46 | if(device.device_name) { 47 | std::cout << "Device " << format_pci_id{device_id} << ' ' << device.device_name << '\n'; 48 | } else 49 | print_named_id("device", device_id); 50 | 51 | if(!vendor_ok || !device.device_name) 52 | return (vendor_ok ? 0 : 1) | (device.device_name ? 0 : 2); 53 | } 54 | } 55 | #else 56 | std::cout << "Compiled without PCI ID support\n"; 57 | #endif 58 | } 59 | 60 | 61 | static void print_named_id(const char* subsystem, std::uint64_t pci_id) { 62 | std::cout << "Unrecognised " << subsystem << " with ID " << format_pci_id{pci_id} << '\n'; 63 | } 64 | 65 | static bool print_vendor(std::uint64_t vendor_id, const char* vendor_name) { 66 | if(vendor_name) 67 | std::cout << "Vendor " << format_pci_id{vendor_id} << ' ' << vendor_name << '\n'; 68 | else 69 | print_named_id("vendor", vendor_id); 70 | 71 | return vendor_name; 72 | } 73 | -------------------------------------------------------------------------------- /examples/system.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: CC0-1.0 2 | // infoware - C++ System information Library 3 | 4 | 5 | #include "infoware/system.hpp" 6 | #include "infoware/version.hpp" 7 | #include 8 | #include 9 | 10 | 11 | static const char* kernel_variant_name(iware::system::kernel_t variant) noexcept; 12 | 13 | 14 | int main() { 15 | std::cout << "Infoware version " << iware::version << '\n'; 16 | 17 | { 18 | std::cout << "\n" 19 | " Connected HIDs:\n" 20 | << " Mice : " << iware::system::mouse_amount() << '\n' 21 | << " Keyboards: " << iware::system::keyboard_amount() << '\n' 22 | << " Other : " << iware::system::other_HID_amount() << '\n'; 23 | } 24 | 25 | { 26 | const auto memory = iware::system::memory(); 27 | std::cout << "\n" 28 | " Memory:\n" 29 | " Physical:\n" 30 | << " Available: " << memory.physical_available << "B\n" 31 | << " Total : " << memory.physical_total << "B\n" 32 | << " Virtual:\n" 33 | << " Available: " << memory.virtual_available << "B\n" 34 | << " Total : " << memory.virtual_total << "B\n"; 35 | } 36 | 37 | { 38 | const auto kernel_info = iware::system::kernel_info(); 39 | std::cout << "\n" 40 | " Kernel:\n" 41 | << " Variant: " << kernel_variant_name(kernel_info.variant) << '\n' 42 | << " Version: " << kernel_info.major << '.' << kernel_info.minor << '.' << kernel_info.patch << " build " << kernel_info.build_number << '\n'; 43 | } 44 | 45 | { 46 | const auto OS_info = iware::system::OS_info(); 47 | std::cout << "\n" 48 | " OS:\n" 49 | << " Name : " << OS_info.name << '\n' 50 | << " Full name: " << OS_info.full_name << '\n' 51 | << " Version : " << OS_info.major << '.' << OS_info.minor << '.' << OS_info.patch << " build " << OS_info.build_number << '\n'; 52 | } 53 | 54 | { 55 | const auto displays = iware::system::displays(); 56 | std::cout << "\n" 57 | " Displays:\n"; 58 | if(displays.empty()) 59 | std::cout << " None connected or no detection method enabled\n"; 60 | else 61 | for(auto i = 0u; i < displays.size(); ++i) { 62 | const auto& display = displays[i]; 63 | std::cout << " #" << (i + 1) << ":\n" 64 | << " Resolution : " << display.width << 'x' << display.height << '\n' 65 | << " DPI : " << display.dpi << '\n' 66 | << " Colour depth: " << display.bpp << "b\n" 67 | << " Refresh rate: " << display.refresh_rate << "Hz\n"; 68 | } 69 | } 70 | 71 | { 72 | const auto configs = iware::system::available_display_configurations(); 73 | std::cout << "\n" 74 | " Display configurations:\n"; 75 | if(configs.empty()) 76 | std::cout << " No displays connected, no detection method enabled, or not supported\n"; 77 | else 78 | for(auto i = 0u; i < configs.size(); ++i) { 79 | const auto& display_configs = configs[i]; 80 | std::cout << " Display #" << (i + 1) << ":\n"; 81 | 82 | for(auto j = 0u; j < display_configs.size(); ++j) { 83 | const auto& config = display_configs[j]; 84 | std::cout << " #" << (j + 1) << ":\n" 85 | << " Resolution : " << config.width << 'x' << config.height << '\n' 86 | << " Refresh rates: "; 87 | 88 | bool first = true; 89 | for(auto rate : config.refresh_rates) { 90 | if(first) 91 | first = false; 92 | else 93 | std::cout << ", "; 94 | 95 | std::cout << rate << "Hz"; 96 | } 97 | 98 | std::cout << '\n'; 99 | } 100 | } 101 | } 102 | 103 | { 104 | const auto process_stats = iware::system::process_stats(); 105 | std::cout << "\n" 106 | " Process:\n" 107 | " user " 108 | << process_stats.user_time.tv_sec << '.' << std::setfill('0') << std::setw(9) << process_stats.user_time.tv_nsec << "s\n" 109 | << " sys " << process_stats.kernel_time.tv_sec << '.' << std::setfill('0') << std::setw(9) << process_stats.kernel_time.tv_nsec << "s\n" 110 | << '\n' 111 | << " Faults : " << process_stats.page_faults << "\n" 112 | << " Peak memory: " << process_stats.peak_memory_usage << "B\n" 113 | << '\n' 114 | << " Reads : " << process_stats.read_operations << '\n' 115 | << " Writes : " << process_stats.write_operations << '\n'; 116 | } 117 | 118 | std::cout << '\n'; 119 | } 120 | 121 | 122 | static const char* kernel_variant_name(iware::system::kernel_t variant) noexcept { 123 | switch(variant) { 124 | case iware::system::kernel_t::windows_nt: 125 | return "Windows NT"; 126 | case iware::system::kernel_t::linux: 127 | return "Linux"; 128 | case iware::system::kernel_t::darwin: 129 | return "Darwin"; 130 | default: 131 | return "Unknown"; 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /include/infoware/cpu.hpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: CC0-1.0 2 | // infoware - C++ System information Library 3 | 4 | 5 | #pragma once 6 | 7 | #include 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | 14 | namespace iware { 15 | namespace cpu { 16 | enum class architecture_t { 17 | x64, 18 | arm, 19 | itanium, 20 | x86, 21 | unknown, 22 | }; 23 | 24 | enum class endianness_t { 25 | little, 26 | big, 27 | }; 28 | 29 | enum class instruction_set_t { 30 | // x86 31 | s3d_now, 32 | s3d_now_extended, 33 | mmx, 34 | mmx_extended, 35 | sse, 36 | sse2, 37 | sse3, 38 | ssse3, 39 | sse4a, 40 | sse41, 41 | sse42, 42 | aes, 43 | 44 | avx, 45 | avx2, 46 | 47 | avx_512, 48 | avx_512_f, 49 | avx_512_cd, 50 | avx_512_pf, 51 | avx_512_er, 52 | avx_512_vl, 53 | avx_512_bw, 54 | avx_512_bq, 55 | avx_512_dq, 56 | avx_512_ifma, 57 | avx_512_vbmi, 58 | 59 | hle, 60 | 61 | bmi1, 62 | bmi2, 63 | adx, 64 | mpx, 65 | sha, 66 | prefetch_wt1, 67 | 68 | fma3, 69 | fma4, 70 | 71 | xop, 72 | 73 | rd_rand, 74 | 75 | x64, 76 | x87_fpu, 77 | 78 | 79 | // ARM 80 | fhm, 81 | dotprod, 82 | rdm, 83 | lse, 84 | pmull, 85 | specres, 86 | sb, 87 | frintts, 88 | lrcpc, 89 | lrcpc2, 90 | fcma, 91 | jscvt, 92 | pauth, 93 | pauth2, 94 | fpac, 95 | dpb, 96 | dpb2, 97 | bf16, 98 | i8mm, 99 | ecv, 100 | les2, 101 | csv2, 102 | csv3, 103 | dit, 104 | fp16, 105 | ssbs, 106 | bti, 107 | fp_sync_exception, 108 | neon, 109 | armv8_1_atomics, 110 | armv8_2_fhm, 111 | armv8_2_compnum, 112 | watchpoint, 113 | breakpoint, 114 | armv8_crc32, 115 | armv8_gpi, 116 | adv_simd, 117 | adv_simd_hpfp_cvt, 118 | ucnormal_mem, 119 | }; 120 | 121 | enum class cache_type_t { 122 | unified, 123 | instruction, 124 | data, 125 | trace, 126 | }; 127 | 128 | struct quantities_t { 129 | /// Hyperthreads. 130 | std::uint32_t logical; 131 | /// Physical "cores". 132 | std::uint32_t physical; 133 | /// Physical CPU units/packages/sockets. 134 | std::uint32_t packages; 135 | }; 136 | 137 | struct cache_t { 138 | std::size_t size; 139 | std::size_t line_size; 140 | std::uint8_t associativity; 141 | cache_type_t type; 142 | }; 143 | 144 | 145 | /// Returns the quantity of CPU at various gradation. 146 | INFOWARE_API_LINKAGE quantities_t quantities(); 147 | 148 | /// Get CPU's cache properties. 149 | /// 150 | /// `level` is the cache level (3 -> L3 cache). 151 | INFOWARE_API_LINKAGE cache_t cache(unsigned int level); 152 | 153 | /// Returns the architecture of the current CPU. 154 | INFOWARE_API_LINKAGE architecture_t architecture() noexcept; 155 | 156 | /// Returns the current frequency of the current CPU in Hz. 157 | INFOWARE_API_LINKAGE std::uint64_t frequency() noexcept; 158 | 159 | /// Returns the current endianness of the current CPU. 160 | INFOWARE_API_LINKAGE endianness_t endianness() noexcept; 161 | 162 | /// Returns the CPU's vendor. 163 | INFOWARE_API_LINKAGE std::string vendor(); 164 | 165 | /// Returns the CPU's vendor according to the CPUID instruction 166 | INFOWARE_API_LINKAGE std::string vendor_id(); 167 | 168 | /// Returns the CPU's model name. 169 | INFOWARE_API_LINKAGE std::string model_name(); 170 | 171 | /// Returns whether an instruction set is supported by the current CPU. 172 | /// 173 | /// `noexcept` on Windows 174 | INFOWARE_API_LINKAGE bool instruction_set_supported(instruction_set_t set); 175 | 176 | /// Retrieve all of the instruction sets this hardware supports 177 | INFOWARE_API_LINKAGE std::vector supported_instruction_sets(); 178 | } // namespace cpu 179 | } // namespace iware 180 | -------------------------------------------------------------------------------- /include/infoware/detail/cpuid.hpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: CC0-1.0 2 | // infoware - C++ System information Library 3 | 4 | 5 | #pragma once 6 | 7 | 8 | #include 9 | 10 | #include 11 | 12 | 13 | namespace iware { 14 | namespace detail { 15 | INFOWARE_API_LINKAGE_INTERNAL void cpuid(std::int32_t (&out)[4], std::int32_t x); 16 | 17 | INFOWARE_API_LINKAGE_INTERNAL std::uint64_t xgetbv(std::uint32_t x); 18 | } // namespace detail 19 | } // namespace iware 20 | -------------------------------------------------------------------------------- /include/infoware/detail/memory.hpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: CC0-1.0 2 | // infoware - C++ System information Library 3 | 4 | 5 | #pragma once 6 | 7 | 8 | namespace iware { 9 | namespace detail { 10 | struct release_deleter { 11 | template 12 | void operator()(T* p) const { 13 | p->Release(); 14 | } 15 | }; 16 | } // namespace detail 17 | } // namespace iware 18 | -------------------------------------------------------------------------------- /include/infoware/detail/scope.hpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: CC0-1.0 2 | // infoware - C++ System information Library 3 | 4 | 5 | #pragma once 6 | 7 | 8 | #include 9 | 10 | 11 | namespace iware { 12 | namespace detail { 13 | namespace { 14 | struct quickscope_wrapper { 15 | std::function func; 16 | 17 | quickscope_wrapper(const quickscope_wrapper&) = delete; 18 | ~quickscope_wrapper() { 19 | if(func) 20 | func(); 21 | } 22 | }; 23 | } // namespace 24 | } // namespace detail 25 | } // namespace iware 26 | -------------------------------------------------------------------------------- /include/infoware/detail/sysctl.hpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: CC0-1.0 2 | // infoware - C++ System information Library 3 | 4 | 5 | #pragma once 6 | 7 | 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | 15 | namespace iware { 16 | namespace detail { 17 | /// https://github.com/ThePhD/infoware/issues/13 18 | INFOWARE_API_LINKAGE_INTERNAL std::string sysctl(const char* name); 19 | INFOWARE_API_LINKAGE_INTERNAL std::string sysctl(int mib_0, int mib_1); 20 | 21 | INFOWARE_API_LINKAGE_INTERNAL std::pair deconstruct_sysctl_int(const std::string& data); 22 | } // namespace detail 23 | } // namespace iware 24 | -------------------------------------------------------------------------------- /include/infoware/detail/winstring.hpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: CC0-1.0 2 | // infoware - C++ System information Library 3 | 4 | 5 | #pragma once 6 | 7 | 8 | #include 9 | 10 | #include 11 | 12 | 13 | namespace iware { 14 | namespace detail { 15 | INFOWARE_API_LINKAGE_INTERNAL std::string narrowen_bstring(const wchar_t* wstr); 16 | INFOWARE_API_LINKAGE_INTERNAL std::string narrowen_winstring(const wchar_t* wstr); 17 | } // namespace detail 18 | } // namespace iware 19 | -------------------------------------------------------------------------------- /include/infoware/gpu.hpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: CC0-1.0 2 | // infoware - C++ System information Library 3 | 4 | 5 | #pragma once 6 | 7 | 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | 15 | namespace iware { 16 | namespace gpu { 17 | enum class vendor_t { 18 | intel, 19 | amd, 20 | nvidia, 21 | microsoft, 22 | qualcomm, 23 | apple, 24 | unknown, 25 | }; 26 | 27 | struct device_properties_t { 28 | vendor_t vendor; 29 | std::string name; 30 | std::size_t memory_size; 31 | std::size_t cache_size; 32 | std::uint64_t max_frequency; 33 | }; 34 | 35 | 36 | /// Returns all GPU's properties. 37 | INFOWARE_API_LINKAGE std::vector device_properties(); 38 | } // namespace gpu 39 | } // namespace iware 40 | -------------------------------------------------------------------------------- /include/infoware/infoware.hpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: CC0-1.0 2 | // infoware - C++ System information Library 3 | 4 | 5 | #pragma once 6 | 7 | 8 | #include "cpu.hpp" 9 | #include "gpu.hpp" 10 | #include "system.hpp" 11 | #include "version.hpp" 12 | -------------------------------------------------------------------------------- /include/infoware/linkage.hpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: CC0-1.0 2 | // infoware - C++ System information Library 3 | 4 | 5 | #pragma once 6 | 7 | #if defined _MSC_VER 8 | #if defined INFOWARE_DLL 9 | #if defined INFOWARE_BUILDING 10 | #define INFOWARE_API_LINKAGE __declspec(dllexport) 11 | #define INFOWARE_API_LINKAGE_INTERNAL 12 | #else 13 | #define INFOWARE_API_LINKAGE __declspec(dllimport) 14 | #define INFOWARE_API_LINKAGE_INTERNAL 15 | #endif // FICAPI_BUILD - Building the Library vs. Using the Library 16 | #else 17 | #define INFOWARE_API_LINKAGE 18 | #define INFOWARE_API_LINKAGE_INTERNAL 19 | #endif // Building a DLL vs. Static Library 20 | #else // g++ / clang++ 21 | #define INFOWARE_API_LINKAGE __attribute__((visibility("default"))) 22 | #define INFOWARE_API_LINKAGE_INTERNAL __attribute__((visibility("hidden"))) 23 | #endif // MSVC vs. other shared object / dll attributes 24 | -------------------------------------------------------------------------------- /include/infoware/pci.hpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: CC0-1.0 2 | // infoware - C++ System information Library 3 | 4 | 5 | #pragma once 6 | 7 | 8 | #include 9 | 10 | #include 11 | #include 12 | 13 | 14 | namespace iware { 15 | namespace pci { 16 | struct device { 17 | const char* vendor_name; 18 | const char* device_name; 19 | }; 20 | 21 | 22 | /// Get the names for the device with the specified PCI ID from the vendor with the specified PCI ID. 23 | /// 24 | /// If the vendor was not found, both names are nullptr. 25 | /// If the vendor was found, but the device wasn't, the device name is nullptr; 26 | INFOWARE_API_LINKAGE device identify_device(std::uint64_t vendor_id, std::uint64_t device_id) noexcept; 27 | 28 | /// Get the name the vendor with the specified PCI ID, or nullptr if not found. 29 | INFOWARE_API_LINKAGE const char* identify_vendor(std::uint64_t vendor_id) noexcept; 30 | } // namespace pci 31 | } // namespace iware 32 | -------------------------------------------------------------------------------- /include/infoware/platform.hpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: CC0-1.0 2 | // infoware - C++ System information Library 3 | 4 | 5 | #pragma once 6 | 7 | 8 | #if defined(__i386__) || defined(__x86_64__) || defined(_M_X64) || defined(_M_IX86) 9 | #define INFOWARE_X86 1 10 | #endif /* x86 */ 11 | 12 | #if defined(__arm64__) || defined(_M_ARM64) 13 | #define INFOWARE_ARM 1 14 | #endif /* ARM */ 15 | -------------------------------------------------------------------------------- /include/infoware/system.hpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: CC0-1.0 2 | // infoware - C++ System information Library 3 | 4 | 5 | #pragma once 6 | 7 | 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | // Some garbage compilers define this, doesn't seem deterministic; see https://github.com/ThePhD/infoware/issues/42 16 | #ifdef linux 17 | #undef linux 18 | #endif 19 | 20 | 21 | namespace iware { 22 | namespace system { 23 | struct memory_t { 24 | std::uint64_t physical_available; 25 | std::uint64_t physical_total; 26 | std::uint64_t virtual_available; 27 | std::uint64_t virtual_total; 28 | }; 29 | 30 | enum class kernel_t { 31 | windows_nt, 32 | linux, 33 | darwin, 34 | unknown, 35 | }; 36 | 37 | struct kernel_info_t { 38 | kernel_t variant; 39 | std::uint32_t major; 40 | std::uint32_t minor; 41 | std::uint32_t patch; 42 | std::uint32_t build_number; 43 | }; 44 | 45 | struct OS_info_t { 46 | std::string name; 47 | std::string full_name; 48 | unsigned int major; 49 | unsigned int minor; 50 | unsigned int patch; 51 | unsigned int build_number; 52 | }; 53 | 54 | struct display_t { 55 | std::uint32_t width; 56 | std::uint32_t height; 57 | std::uint32_t dpi; 58 | /// Bits Per Pixel a.k.a. depth 59 | std::uint32_t bpp; 60 | double refresh_rate; 61 | }; 62 | 63 | struct display_config_t { 64 | std::uint32_t width; 65 | std::uint32_t height; 66 | std::vector refresh_rates; 67 | }; 68 | 69 | struct process_stats_t { 70 | ::timespec user_time; 71 | ::timespec kernel_time; 72 | 73 | std::size_t page_faults; 74 | /// PeakWorkingSetSize/ru_maxrss in bytes 75 | std::size_t peak_memory_usage; 76 | 77 | std::uint64_t read_operations; 78 | std::uint64_t write_operations; 79 | }; 80 | 81 | /// Get amount of connected mice. 82 | INFOWARE_API_LINKAGE std::size_t mouse_amount() noexcept; 83 | 84 | /// Get amount of connected keyboards. 85 | /// 86 | /// Always returns 0 on Linuxish kernels, as it can not be detected there. 87 | INFOWARE_API_LINKAGE std::size_t keyboard_amount() noexcept; 88 | 89 | /// Get amount of other connected HIDs. 90 | /// 91 | /// Always returns 0 on Linuxish kernels, as it can not be detected there. 92 | INFOWARE_API_LINKAGE std::size_t other_HID_amount() noexcept; 93 | 94 | /// Get RAM statistics. 95 | INFOWARE_API_LINKAGE memory_t memory() noexcept; 96 | 97 | /// Get kernel information. 98 | INFOWARE_API_LINKAGE kernel_info_t kernel_info(); 99 | 100 | /// Get system information. 101 | INFOWARE_API_LINKAGE OS_info_t OS_info(); 102 | 103 | /// Get information about displays. 104 | INFOWARE_API_LINKAGE std::vector displays(); 105 | 106 | /// Get information about available configurations for each display. 107 | INFOWARE_API_LINKAGE std::vector> available_display_configurations(); 108 | 109 | /// Get information about the calling process. 110 | INFOWARE_API_LINKAGE process_stats_t process_stats(); 111 | } // namespace system 112 | } // namespace iware 113 | -------------------------------------------------------------------------------- /include/infoware/version.hpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: CC0-1.0 2 | // infoware - C++ System information Library 3 | 4 | 5 | #pragma once 6 | 7 | 8 | #include 9 | 10 | namespace iware { 11 | INFOWARE_API_LINKAGE extern const char* const version; 12 | } 13 | -------------------------------------------------------------------------------- /src/cpu/architecture/architecture_non_windows.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: CC0-1.0 2 | // infoware - C++ System information Library 3 | 4 | 5 | #ifndef _WIN32 6 | 7 | 8 | #include "infoware/cpu.hpp" 9 | #include 10 | #include 11 | 12 | 13 | // https://github.com/karelzak/util-linux/blob/master/sys-utils/lscpu.c 14 | iware::cpu::architecture_t iware::cpu::architecture() noexcept { 15 | utsname buf; 16 | 17 | if(uname(&buf) == -1) 18 | return iware::cpu::architecture_t::unknown; 19 | 20 | if(!strcmp(buf.machine, "x86_64")) 21 | return iware::cpu::architecture_t::x64; 22 | else if(strstr(buf.machine, "arm") == buf.machine) 23 | return iware::cpu::architecture_t::arm; 24 | else if(!strcmp(buf.machine, "ia64") || !strcmp(buf.machine, "IA64")) 25 | return iware::cpu::architecture_t::itanium; 26 | else if(!strcmp(buf.machine, "i686")) 27 | return iware::cpu::architecture_t::x86; 28 | else 29 | return iware::cpu::architecture_t::unknown; 30 | } 31 | 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /src/cpu/architecture/architecture_windows.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: CC0-1.0 2 | // infoware - C++ System information Library 3 | 4 | 5 | #ifdef _WIN32 6 | 7 | 8 | #include "infoware/cpu.hpp" 9 | #define WIN32_LEAN_AND_MEAN 10 | #include 11 | 12 | 13 | // https://msdn.microsoft.com/en-us/library/windows/desktop/ms724958(v=vs.85).aspx 14 | iware::cpu::architecture_t iware::cpu::architecture() noexcept { 15 | SYSTEM_INFO sysinfo; 16 | GetNativeSystemInfo(&sysinfo); 17 | 18 | switch(sysinfo.wProcessorArchitecture) { 19 | case PROCESSOR_ARCHITECTURE_AMD64: 20 | return iware::cpu::architecture_t::x64; 21 | case PROCESSOR_ARCHITECTURE_ARM: 22 | return iware::cpu::architecture_t::arm; 23 | case PROCESSOR_ARCHITECTURE_IA64: 24 | return iware::cpu::architecture_t::itanium; 25 | case PROCESSOR_ARCHITECTURE_INTEL: 26 | return iware::cpu::architecture_t::x86; 27 | default: 28 | return iware::cpu::architecture_t::unknown; 29 | } 30 | } 31 | 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /src/cpu/endianness/all.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: CC0-1.0 2 | // infoware - C++ System information Library 3 | 4 | 5 | #include "infoware/cpu.hpp" 6 | #include 7 | 8 | 9 | iware::cpu::endianness_t iware::cpu::endianness() noexcept { 10 | const std::uint16_t test = 0xFF00; 11 | const auto result = *static_cast(static_cast(&test)); 12 | 13 | if(result == 0xFF) 14 | return iware::cpu::endianness_t::big; 15 | else 16 | return iware::cpu::endianness_t::little; 17 | } 18 | -------------------------------------------------------------------------------- /src/cpu/frequency/frequency_darwin.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: CC0-1.0 2 | // infoware - C++ System information Library 3 | 4 | 5 | #ifdef __APPLE__ 6 | 7 | 8 | #include "infoware/cpu.hpp" 9 | #include "infoware/detail/sysctl.hpp" 10 | 11 | 12 | std::uint64_t iware::cpu::frequency() noexcept { 13 | const auto ctl_data = iware::detail::sysctl("hw.cpufrequency"); 14 | if(ctl_data.empty()) 15 | return 0; 16 | 17 | const auto data = iware::detail::deconstruct_sysctl_int(ctl_data); 18 | if(!data.first) 19 | return 0; 20 | 21 | return data.second; 22 | } 23 | 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /src/cpu/frequency/frequency_non_windows_non_darwin.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: CC0-1.0 2 | // infoware - C++ System information Library 3 | 4 | 5 | #ifndef _WIN32 6 | #ifndef __APPLE__ 7 | 8 | 9 | #include "infoware/cpu.hpp" 10 | #include 11 | #include 12 | 13 | 14 | std::uint64_t iware::cpu::frequency() noexcept { 15 | std::ifstream cpuinfo("/proc/cpuinfo"); 16 | 17 | if(!cpuinfo.is_open() || !cpuinfo) 18 | return 0; 19 | 20 | for(std::string line; std::getline(cpuinfo, line);) 21 | if(line.find("cpu MHz") == 0) { 22 | const auto colon_id = line.find_first_of(':'); 23 | return static_cast(std::strtod(line.c_str() + colon_id + 1, nullptr) * 1'000'000); 24 | } 25 | 26 | return 0; 27 | } 28 | 29 | 30 | #endif 31 | #endif 32 | -------------------------------------------------------------------------------- /src/cpu/frequency/frequency_windows.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: CC0-1.0 2 | // infoware - C++ System information Library 3 | 4 | 5 | #ifdef _WIN32 6 | 7 | 8 | #include "infoware/cpu.hpp" 9 | #include "infoware/detail/scope.hpp" 10 | #define WIN32_LEAN_AND_MEAN 11 | #include 12 | 13 | 14 | std::uint64_t iware::cpu::frequency() noexcept { 15 | HKEY hkey; 16 | if(RegOpenKeyExA(HKEY_LOCAL_MACHINE, R"(HARDWARE\DESCRIPTION\System\CentralProcessor\0)", 0, KEY_READ, &hkey)) { 17 | // Fallback 18 | LARGE_INTEGER freq; 19 | QueryPerformanceFrequency(&freq); 20 | return freq.QuadPart * 1'000; 21 | } 22 | iware::detail::quickscope_wrapper hkey_closer{[&] { RegCloseKey(hkey); }}; 23 | 24 | DWORD freq_mhz; 25 | DWORD freq_mhz_len = sizeof(freq_mhz); 26 | if(RegQueryValueExA(hkey, "~MHz", nullptr, nullptr, static_cast(static_cast(&freq_mhz)), &freq_mhz_len)) 27 | return {}; 28 | 29 | return freq_mhz * 1'000'000; 30 | } 31 | 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /src/cpu/instruction_set/instruction_set_darwin.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: CC0-1.0 2 | // infoware - C++ System information Library 3 | 4 | 5 | #ifdef __APPLE__ 6 | 7 | 8 | #include "infoware/cpu.hpp" 9 | #include "infoware/detail/sysctl.hpp" 10 | #include 11 | #include 12 | #include 13 | 14 | 15 | static std::pair instruction_set_to_names(iware::cpu::instruction_set_t set) { 16 | static const char* const mmx[] = {"MMX"}; 17 | static const char* const threednow[] = {"3DNOW", "3DNOWEXT"}; 18 | static const char* const sse[] = {"SSE"}; 19 | static const char* const sse2[] = {"SSE2"}; 20 | static const char* const sse3[] = {"SSSE3", "SSE3"}; 21 | static const char* const avx[] = {"AVX"}; 22 | static const char* const fhm[] = {"FHM"}; 23 | static const char* const dotprod[] = {"DOTPROD"}; 24 | static const char* const rdm[] = {"RDM"}; 25 | static const char* const lse[] = {"LSE"}; 26 | static const char* const pmull[] = {"PMULL"}; 27 | static const char* const specres[] = {"SPECRES"}; 28 | static const char* const sb[] = {"SB"}; 29 | static const char* const frintts[] = {"FRINTTS"}; 30 | static const char* const lrcpc[] = {"LRCPC"}; 31 | static const char* const lrcpc2[] = {"LRCPC2"}; 32 | static const char* const fcma[] = {"FCMA"}; 33 | static const char* const jscvt[] = {"JSCVT"}; 34 | static const char* const pauth[] = {"PAUTH"}; 35 | static const char* const pauth2[] = {"PAUTH2"}; 36 | static const char* const fpac[] = {"FPAC"}; 37 | static const char* const dpb[] = {"DPB"}; 38 | static const char* const dpb2[] = {"DPB2"}; 39 | static const char* const bf16[] = {"BF16"}; 40 | static const char* const i8mm[] = {"I8MM"}; 41 | static const char* const ecv[] = {"ECV"}; 42 | static const char* const les2[] = {"LES2"}; 43 | static const char* const csv2[] = {"CSV2"}; 44 | static const char* const csv3[] = {"CSV3"}; 45 | static const char* const dit[] = {"DIT"}; 46 | static const char* const fp16[] = {"FP16"}; 47 | static const char* const ssbs[] = {"SSBS"}; 48 | static const char* const bti[] = {"BTI"}; 49 | static const char* const fp_sync_exception[] = {"FP_SYNC_EXCEPTION"}; 50 | static const char* const neon[] = {"NEON"}; 51 | static const char* const armv8_1_atomics[] = {"ARMV8_1_ATOMICS"}; 52 | static const char* const armv8_2_fhm[] = {"ARMV8_2_FHM"}; 53 | static const char* const armv8_2_compnum[] = {"ARMV8_2_COMPNUM"}; 54 | static const char* const watchpoint[] = {"WATCHPOINT"}; 55 | static const char* const breakpoint[] = {"BREAKPOINT"}; 56 | static const char* const armv8_crc32[] = {"ARMV8_CRC32"}; 57 | static const char* const armv8_gpi[] = {"ARMV8_GPI"}; 58 | static const char* const adv_simd[] = {"ADV_SIMD"}; 59 | static const char* const adv_simd_hpfp_cvt[] = {"ADV_SIMD_HPFP_CVT"}; 60 | static const char* const ucnormal_mem[] = {"UCNORMAL_MEM"}; 61 | 62 | 63 | #define HANDLED_CASE(iset, variable) \ 64 | case iware::cpu::instruction_set_t::iset: \ 65 | return {variable, variable + (sizeof(variable) / sizeof(*variable))}; 66 | 67 | switch(set) { 68 | HANDLED_CASE(s3d_now, threednow) 69 | HANDLED_CASE(mmx, mmx) 70 | HANDLED_CASE(sse, sse) 71 | HANDLED_CASE(sse2, sse2) 72 | HANDLED_CASE(sse3, sse3) 73 | HANDLED_CASE(avx, avx) 74 | HANDLED_CASE(fhm, fhm) 75 | HANDLED_CASE(dotprod, dotprod) 76 | HANDLED_CASE(rdm, rdm) 77 | HANDLED_CASE(lse, lse) 78 | HANDLED_CASE(pmull, pmull) 79 | HANDLED_CASE(specres, specres) 80 | HANDLED_CASE(sb, sb) 81 | HANDLED_CASE(frintts, frintts) 82 | HANDLED_CASE(lrcpc, lrcpc) 83 | HANDLED_CASE(lrcpc2, lrcpc2) 84 | HANDLED_CASE(fcma, fcma) 85 | HANDLED_CASE(jscvt, jscvt) 86 | HANDLED_CASE(pauth, pauth) 87 | HANDLED_CASE(pauth2, pauth2) 88 | HANDLED_CASE(fpac, fpac) 89 | HANDLED_CASE(dpb, dpb) 90 | HANDLED_CASE(dpb2, dpb2) 91 | HANDLED_CASE(bf16, bf16) 92 | HANDLED_CASE(i8mm, i8mm) 93 | HANDLED_CASE(ecv, ecv) 94 | HANDLED_CASE(les2, les2) 95 | HANDLED_CASE(csv2, csv2) 96 | HANDLED_CASE(csv3, csv3) 97 | HANDLED_CASE(dit, dit) 98 | HANDLED_CASE(fp16, fp16) 99 | HANDLED_CASE(ssbs, ssbs) 100 | HANDLED_CASE(bti, bti) 101 | HANDLED_CASE(fp_sync_exception, fp_sync_exception) 102 | HANDLED_CASE(neon, neon) 103 | HANDLED_CASE(armv8_1_atomics, armv8_1_atomics) 104 | HANDLED_CASE(armv8_2_fhm, armv8_2_fhm) 105 | HANDLED_CASE(armv8_2_compnum, armv8_2_compnum) 106 | HANDLED_CASE(watchpoint, watchpoint) 107 | HANDLED_CASE(breakpoint, breakpoint) 108 | HANDLED_CASE(armv8_crc32, armv8_crc32) 109 | HANDLED_CASE(armv8_gpi, armv8_gpi) 110 | HANDLED_CASE(adv_simd, adv_simd) 111 | HANDLED_CASE(adv_simd_hpfp_cvt, adv_simd_hpfp_cvt) 112 | HANDLED_CASE(ucnormal_mem, ucnormal_mem) 113 | 114 | default: 115 | return {nullptr, nullptr}; 116 | } 117 | 118 | #undef HANDLED_CASE 119 | } 120 | 121 | 122 | bool iware::cpu::instruction_set_supported(iware::cpu::instruction_set_t set) { 123 | const auto ises = supported_instruction_sets(); 124 | if(std::find(ises.begin(), ises.end(), set) != ises.cend()) 125 | return true; 126 | 127 | const auto set_names = instruction_set_to_names(set); 128 | if(!set_names.first) 129 | return false; 130 | 131 | auto ctl_data = iware::detail::sysctl("machdep.cpu.features"); 132 | if(ctl_data.empty()) 133 | return 0; 134 | 135 | for(auto cur_name = std::strtok(&ctl_data[0], " \t\n"); cur_name; cur_name = std::strtok(nullptr, " \t\n")) 136 | if(std::any_of(set_names.first, set_names.second, [&](auto name) { return name == cur_name; })) 137 | return true; 138 | 139 | return false; 140 | } 141 | 142 | 143 | #endif 144 | -------------------------------------------------------------------------------- /src/cpu/instruction_set/instruction_set_darwin_arm.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: CC0-1.0 2 | // infoware - C++ System information Library 3 | 4 | 5 | #include "infoware/platform.hpp" 6 | #if __APPLE__ && INFOWARE_ARM 7 | 8 | 9 | #include "infoware/cpu.hpp" 10 | #include 11 | #include 12 | 13 | 14 | static bool has_feature(const char* feature) { 15 | int value = 0; 16 | std::size_t size = sizeof(value); 17 | return !sysctlbyname(feature, &value, &size, nullptr, 0) && value; 18 | } 19 | 20 | static bool feature_is_supported(const char* name) { 21 | return has_feature(name); 22 | } 23 | 24 | template 25 | static bool feature_is_supported(const char* name, Names... names) { 26 | return has_feature(name) || feature_is_supported(names...); 27 | } 28 | 29 | template 30 | static void push_if_supported(std::vector& instructions, iware::cpu::instruction_set_t instruction, Names... names) { 31 | if(feature_is_supported(names...)) { 32 | instructions.push_back(instruction); 33 | } 34 | } 35 | 36 | 37 | std::vector iware::cpu::supported_instruction_sets() { 38 | std::vector instructions; 39 | 40 | push_if_supported(instructions, iware::cpu::instruction_set_t::sha, "hw.optional.arm.FEAT_SHA3", "hw.optional.arm.FEAT_SHA256", "hw.optional.arm.FEAT_SHA512", 41 | "hw.optional.arm.FEAT_SHA1", "hw.optional.armv8_2_sha512", "hw.optional.armv8_2_sha3"); 42 | push_if_supported(instructions, iware::cpu::instruction_set_t::aes, "hw.optional.arm.FEAT_AES"); 43 | 44 | push_if_supported(instructions, iware::cpu::instruction_set_t::fhm /****************/, "hw.optional.arm.FEAT_FHM"); 45 | push_if_supported(instructions, iware::cpu::instruction_set_t::dotprod /************/, "hw.optional.arm.FEAT_DotProd"); 46 | push_if_supported(instructions, iware::cpu::instruction_set_t::rdm /****************/, "hw.optional.arm.FEAT_RDM"); 47 | push_if_supported(instructions, iware::cpu::instruction_set_t::lse /****************/, "hw.optional.arm.FEAT_LSE"); 48 | push_if_supported(instructions, iware::cpu::instruction_set_t::pmull /**************/, "hw.optional.arm.FEAT_PMULL"); 49 | push_if_supported(instructions, iware::cpu::instruction_set_t::specres /************/, "hw.optional.arm.FEAT_SPECRES"); 50 | push_if_supported(instructions, iware::cpu::instruction_set_t::sb /*****************/, "hw.optional.arm.FEAT_SB"); 51 | push_if_supported(instructions, iware::cpu::instruction_set_t::frintts /************/, "hw.optional.arm.FEAT_FRINTTS"); 52 | push_if_supported(instructions, iware::cpu::instruction_set_t::lrcpc /**************/, "hw.optional.arm.FEAT_LRCPC"); 53 | push_if_supported(instructions, iware::cpu::instruction_set_t::lrcpc2 /*************/, "hw.optional.arm.FEAT_LRCPC2"); 54 | push_if_supported(instructions, iware::cpu::instruction_set_t::fcma /***************/, "hw.optional.arm.FEAT_FCMA"); 55 | push_if_supported(instructions, iware::cpu::instruction_set_t::jscvt /**************/, "hw.optional.arm.FEAT_JSCVT"); 56 | push_if_supported(instructions, iware::cpu::instruction_set_t::pauth /**************/, "hw.optional.arm.FEAT_PAuth"); 57 | push_if_supported(instructions, iware::cpu::instruction_set_t::pauth2 /*************/, "hw.optional.arm.FEAT_PAuth2"); 58 | push_if_supported(instructions, iware::cpu::instruction_set_t::fpac /***************/, "hw.optional.arm.FEAT_FPAC"); 59 | push_if_supported(instructions, iware::cpu::instruction_set_t::dpb /****************/, "hw.optional.arm.FEAT_DPB"); 60 | push_if_supported(instructions, iware::cpu::instruction_set_t::dpb2 /***************/, "hw.optional.arm.FEAT_DPB2"); 61 | push_if_supported(instructions, iware::cpu::instruction_set_t::bf16 /***************/, "hw.optional.arm.FEAT_BF16"); 62 | push_if_supported(instructions, iware::cpu::instruction_set_t::i8mm /***************/, "hw.optional.arm.FEAT_BF16"); 63 | push_if_supported(instructions, iware::cpu::instruction_set_t::ecv /****************/, "hw.optional.arm.FEAT_ECV"); 64 | push_if_supported(instructions, iware::cpu::instruction_set_t::les2 /***************/, "hw.optional.arm.FEAT_LES2"); 65 | push_if_supported(instructions, iware::cpu::instruction_set_t::csv2 /***************/, "hw.optional.arm.FEAT_CSV2"); 66 | push_if_supported(instructions, iware::cpu::instruction_set_t::csv3 /***************/, "hw.optional.arm.FEAT_CSV3"); 67 | push_if_supported(instructions, iware::cpu::instruction_set_t::dit /****************/, "hw.optional.arm.FEAT_DIT"); 68 | push_if_supported(instructions, iware::cpu::instruction_set_t::fp16 /***************/, "hw.optional.arm.FEAT_FP16", "hw.optional.neon_fp16"); 69 | push_if_supported(instructions, iware::cpu::instruction_set_t::ssbs /***************/, "hw.optional.arm.FEAT_SSBS"); 70 | push_if_supported(instructions, iware::cpu::instruction_set_t::bti /****************/, "hw.optional.arm.FEAT_BTI"); 71 | push_if_supported(instructions, iware::cpu::instruction_set_t::fp_sync_exception /**/, "hw.optional.arm.FP_SyncExceptions"); 72 | push_if_supported(instructions, iware::cpu::instruction_set_t::neon /***************/, "hw.optional.neon"); 73 | push_if_supported(instructions, iware::cpu::instruction_set_t::armv8_1_atomics /****/, "hw.optional.armv8_1_atomics"); 74 | push_if_supported(instructions, iware::cpu::instruction_set_t::armv8_2_fhm /********/, "hw.optional.armv8_2_fhm"); 75 | push_if_supported(instructions, iware::cpu::instruction_set_t::armv8_2_compnum /****/, "hw.optional.armv8_2_compnum"); 76 | push_if_supported(instructions, iware::cpu::instruction_set_t::watchpoint /*********/, "hw.optional.watchpoint"); 77 | push_if_supported(instructions, iware::cpu::instruction_set_t::breakpoint /*********/, "hw.optional.breakpoint"); 78 | push_if_supported(instructions, iware::cpu::instruction_set_t::armv8_crc32 /********/, "hw.optional.armv8_crc32"); 79 | push_if_supported(instructions, iware::cpu::instruction_set_t::armv8_gpi /**********/, "hw.optional.armv8_gpi"); 80 | push_if_supported(instructions, iware::cpu::instruction_set_t::adv_simd /***********/, "hw.optional.AdvSIMD"); 81 | push_if_supported(instructions, iware::cpu::instruction_set_t::adv_simd_hpfp_cvt /**/, "hw.optional.AdvSIMD_HPFPCvt"); 82 | push_if_supported(instructions, iware::cpu::instruction_set_t::ucnormal_mem /*******/, "hw.optional.ucnormal_mem"); 83 | return instructions; 84 | } 85 | 86 | 87 | #endif /* __APPLE__ && INFOWARE_ARM */ 88 | -------------------------------------------------------------------------------- /src/cpu/instruction_set/instruction_set_non_windows_non_darwin.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: CC0-1.0 2 | // infoware - C++ System information Library 3 | 4 | 5 | #ifndef _WIN32 6 | #ifndef __APPLE__ 7 | 8 | 9 | #include "infoware/cpu.hpp" 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | 17 | static std::pair instruction_set_to_names(iware::cpu::instruction_set_t set) { 18 | static const char* mmx[] = {"mmx"}; 19 | static const char* threednow[] = {"3dnow", "3dnowext"}; 20 | static const char* sse[] = {"sse"}; 21 | static const char* sse2[] = {"sse2"}; 22 | static const char* sse3[] = {"ssse3", "sse3"}; 23 | static const char* avx[] = {"avx"}; 24 | 25 | 26 | #define HANDLED_CASE(iset, variable) \ 27 | case iware::cpu::instruction_set_t::iset: \ 28 | return {variable, variable + (sizeof(variable) / sizeof(*variable))}; 29 | 30 | switch(set) { 31 | HANDLED_CASE(s3d_now, threednow) 32 | HANDLED_CASE(mmx, mmx) 33 | HANDLED_CASE(sse, sse) 34 | HANDLED_CASE(sse2, sse2) 35 | HANDLED_CASE(sse3, sse3) 36 | HANDLED_CASE(avx, avx) 37 | 38 | default: 39 | return {nullptr, nullptr}; 40 | } 41 | 42 | #undef HANDLED_CASE 43 | } 44 | 45 | 46 | bool iware::cpu::instruction_set_supported(iware::cpu::instruction_set_t set) { 47 | const auto ises = supported_instruction_sets(); 48 | if(std::find(ises.begin(), ises.end(), set) != ises.cend()) 49 | return true; 50 | 51 | const auto set_names = instruction_set_to_names(set); 52 | if(!set_names.first) 53 | return false; 54 | 55 | std::ifstream cpuinfo("/proc/cpuinfo"); 56 | 57 | if(!cpuinfo.is_open() || !cpuinfo) 58 | return false; 59 | 60 | for(std::string tmp; std::getline(cpuinfo, tmp);) 61 | if(tmp.find("flags") == 0) { 62 | const auto colon_id = tmp.find_first_of(':'); 63 | std::istringstream is(tmp.c_str() + colon_id + 1); 64 | while(is >> tmp) 65 | if(std::any_of(set_names.first, set_names.second, [&](auto name) { return tmp == name; })) 66 | return true; 67 | } 68 | 69 | return false; 70 | } 71 | 72 | 73 | #endif 74 | #endif 75 | -------------------------------------------------------------------------------- /src/cpu/instruction_set/instruction_set_windows.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: CC0-1.0 2 | // infoware - C++ System information Library 3 | 4 | 5 | #ifdef _WIN32 6 | 7 | 8 | #include "infoware/cpu.hpp" 9 | #include 10 | #define WIN32_LEAN_AND_MEAN 11 | #include 12 | 13 | 14 | bool iware::cpu::instruction_set_supported(iware::cpu::instruction_set_t set) { 15 | std::vector ises = supported_instruction_sets(); 16 | if(std::find(ises.cbegin(), ises.cend(), set) != ises.cend()) 17 | return true; 18 | 19 | // TODO: is this necessary if we detect things with xgetbv and cpuid? 20 | // That is, AVX usually needs to have both OS support alongside 21 | DWORD feature; 22 | switch(set) { 23 | case iware::cpu::instruction_set_t::s3d_now: 24 | feature = PF_3DNOW_INSTRUCTIONS_AVAILABLE; 25 | break; 26 | case iware::cpu::instruction_set_t::mmx: 27 | feature = PF_MMX_INSTRUCTIONS_AVAILABLE; 28 | break; 29 | case iware::cpu::instruction_set_t::sse: 30 | feature = PF_XMMI_INSTRUCTIONS_AVAILABLE; 31 | break; 32 | case iware::cpu::instruction_set_t::sse2: 33 | feature = PF_XMMI64_INSTRUCTIONS_AVAILABLE; 34 | break; 35 | case iware::cpu::instruction_set_t::sse3: 36 | feature = PF_SSE3_INSTRUCTIONS_AVAILABLE; 37 | break; 38 | case iware::cpu::instruction_set_t::avx: 39 | feature = PF_XMMI64_INSTRUCTIONS_AVAILABLE; 40 | break; 41 | default: 42 | return false; 43 | } 44 | 45 | return IsProcessorFeaturePresent(feature) != 0; 46 | } 47 | 48 | 49 | #endif 50 | -------------------------------------------------------------------------------- /src/cpu/instruction_set/instruction_set_x86.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: CC0-1.0 2 | // infoware - C++ System information Library 3 | 4 | 5 | #include "infoware/platform.hpp" 6 | #if INFOWARE_X86 7 | 8 | #include "infoware/cpu.hpp" 9 | #include "infoware/detail/cpuid.hpp" 10 | 11 | 12 | #if defined(_WIN32) && defined(_MSC_VER) 13 | #include 14 | #define INFOWARE_XCR_XFEATURE_ENABLED_MASK _XCR_XFEATURE_ENABLED_MASK 15 | #else 16 | #define INFOWARE_XCR_XFEATURE_ENABLED_MASK 0 17 | #endif // Is MSVC 18 | 19 | static bool has_os_avx() { 20 | bool avxsupport = false; 21 | 22 | std::int32_t cpuinfo[4]; 23 | iware::detail::cpuid(cpuinfo, 1); 24 | 25 | bool osusesxsave_restore = (cpuinfo[2] & (1 << 27)) != 0; 26 | bool cpusupportsavx = (cpuinfo[2] & (1 << 28)) != 0; 27 | 28 | if(osusesxsave_restore && cpusupportsavx) { 29 | const auto xcrFeatureMask = iware::detail::xgetbv(INFOWARE_XCR_XFEATURE_ENABLED_MASK); 30 | avxsupport = (xcrFeatureMask & 0x06) == 0x06; 31 | } 32 | 33 | return avxsupport; 34 | } 35 | 36 | static bool has_os_avx_512() { 37 | if(!has_os_avx()) 38 | return false; 39 | 40 | const auto xcrFeatureMask = iware::detail::xgetbv(INFOWARE_XCR_XFEATURE_ENABLED_MASK); 41 | return (xcrFeatureMask & 0xE6) == 0xE6; 42 | } 43 | 44 | 45 | std::vector iware::cpu::supported_instruction_sets() { 46 | std::int32_t info[4]; 47 | iware::detail::cpuid(info, 0); 48 | const auto idinfo = info[0]; 49 | 50 | iware::detail::cpuid(info, 0x80000000); 51 | const std::uint32_t extendedidinfo = info[0]; 52 | 53 | std::vector supported; 54 | supported.reserve(64); 55 | 56 | 57 | #define ADD_SET_IF(infoindex, bitindex, name) \ 58 | if((info[(infoindex)] & (1 << (bitindex))) != 0) \ 59 | supported.push_back(iware::cpu::instruction_set_t::name); 60 | 61 | 62 | if(idinfo >= 0x00000001) { 63 | iware::detail::cpuid(info, 0x00000001); 64 | 65 | ADD_SET_IF(3, 22, mmx_extended); 66 | ADD_SET_IF(3, 23, mmx); 67 | ADD_SET_IF(3, 25, sse); 68 | ADD_SET_IF(3, 26, sse2); 69 | 70 | ADD_SET_IF(2, 0, sse3); 71 | ADD_SET_IF(2, 9, ssse3); 72 | ADD_SET_IF(2, 19, sse41); 73 | ADD_SET_IF(2, 20, sse42); 74 | ADD_SET_IF(2, 25, aes); 75 | ADD_SET_IF(2, 28, fma3); 76 | ADD_SET_IF(2, 12, rd_rand); 77 | } 78 | 79 | if(idinfo >= 0x00000007) { 80 | iware::detail::cpuid(info, 0x00000007); 81 | 82 | if(has_os_avx()) { 83 | // Both must be present to have AVX 84 | ADD_SET_IF(1, 5, avx2); 85 | } 86 | ADD_SET_IF(1, 4, hle); 87 | 88 | ADD_SET_IF(1, 3, bmi1); 89 | ADD_SET_IF(1, 8, bmi2); 90 | ADD_SET_IF(1, 19, adx); 91 | ADD_SET_IF(1, 14, mpx); 92 | ADD_SET_IF(1, 29, sha); 93 | 94 | if(has_os_avx_512()) { 95 | supported.push_back(iware::cpu::instruction_set_t::avx_512); 96 | 97 | ADD_SET_IF(1, 16, avx_512_f); 98 | ADD_SET_IF(1, 28, avx_512_cd); 99 | ADD_SET_IF(1, 26, avx_512_pf); 100 | ADD_SET_IF(1, 27, avx_512_er); 101 | ADD_SET_IF(1, 31, avx_512_vl); 102 | ADD_SET_IF(1, 30, avx_512_bw); 103 | ADD_SET_IF(1, 17, avx_512_dq); 104 | ADD_SET_IF(1, 21, avx_512_ifma); 105 | ADD_SET_IF(2, 1, avx_512_vbmi); 106 | } 107 | 108 | ADD_SET_IF(2, 0, prefetch_wt1); 109 | } 110 | 111 | if(extendedidinfo >= 0x80000001) { 112 | iware::detail::cpuid(info, 0x80000001); 113 | 114 | ADD_SET_IF(3, 29, x64); 115 | ADD_SET_IF(3, 0, x87_fpu); 116 | ADD_SET_IF(3, 30, s3d_now); 117 | ADD_SET_IF(3, 31, s3d_now_extended); 118 | ADD_SET_IF(3, 29, x64); 119 | ADD_SET_IF(2, 5, bmi1); 120 | ADD_SET_IF(2, 6, bmi2); 121 | ADD_SET_IF(2, 16, adx); 122 | ADD_SET_IF(2, 11, mpx); 123 | } 124 | 125 | 126 | #undef ADD_SET_IF 127 | 128 | 129 | return supported; 130 | } 131 | 132 | 133 | #endif /* INFOWARE_X86 */ 134 | -------------------------------------------------------------------------------- /src/cpu/quantities_cache/quantities_cache_darwin.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: CC0-1.0 2 | // infoware - C++ System information Library 3 | 4 | 5 | #ifdef __APPLE__ 6 | 7 | 8 | #include "infoware/cpu.hpp" 9 | #include "infoware/detail/sysctl.hpp" 10 | 11 | 12 | // https://github.com/ThePhD/infoware/issues/12#issuecomment-495291650 13 | iware::cpu::quantities_t iware::cpu::quantities() { 14 | iware::cpu::quantities_t ret{}; 15 | 16 | const auto ctl_thread_data = iware::detail::sysctl("machdep.cpu.thread_count"); 17 | if(!ctl_thread_data.empty()) { 18 | const auto thread_data = iware::detail::deconstruct_sysctl_int(ctl_thread_data); 19 | if(thread_data.first) 20 | ret.logical = thread_data.second; 21 | } 22 | 23 | const auto ctl_core_data = iware::detail::sysctl("machdep.cpu.core_count"); 24 | if(!ctl_core_data.empty()) { 25 | const auto core_data = iware::detail::deconstruct_sysctl_int(ctl_core_data); 26 | if(core_data.first) 27 | ret.physical = core_data.second; 28 | } 29 | 30 | const auto ctl_packages_data = iware::detail::sysctl("hw.packages"); 31 | if(!ctl_packages_data.empty()) { 32 | const auto packages_data = iware::detail::deconstruct_sysctl_int(ctl_packages_data); 33 | if(packages_data.first) 34 | ret.packages = packages_data.second; 35 | } 36 | 37 | return ret; 38 | } 39 | 40 | // This is hell 41 | // 42 | // https://github.com/ThePhD/infoware/issues/12#issuecomment-495782115 43 | // 44 | // TODO: couldn't find a good way to get the associativity (default 0) or the type (default unified) 45 | iware::cpu::cache_t iware::cpu::cache(unsigned int level) { 46 | // Unspecified keys default to nullptr 47 | static const char* size_keys[][3]{{}, {"hw.l1icachesize", "hw.l1dcachesize", "hw.l1cachesize"}, {"hw.l2cachesize"}, {"hw.l3cachesize"}}; 48 | 49 | 50 | iware::cpu::cache_t ret{}; 51 | 52 | const auto ctl_cachelinesize_data = iware::detail::sysctl("hw.cachelinesize"); 53 | if(!ctl_cachelinesize_data.empty()) { 54 | const auto cachelinesize_data = iware::detail::deconstruct_sysctl_int(ctl_cachelinesize_data); 55 | if(cachelinesize_data.first) 56 | ret.line_size = cachelinesize_data.second; 57 | } 58 | 59 | if(level < sizeof(size_keys) / sizeof(*size_keys)) 60 | for(auto key : size_keys[level]) { 61 | if(!key) 62 | break; 63 | 64 | const auto ctl_cachesize_data = iware::detail::sysctl(key); 65 | if(!ctl_cachesize_data.empty()) { 66 | const auto cachesize_data = iware::detail::deconstruct_sysctl_int(ctl_cachesize_data); 67 | if(cachesize_data.first) 68 | ret.size += cachesize_data.second; 69 | } 70 | } 71 | 72 | return ret; 73 | } 74 | 75 | 76 | #endif 77 | -------------------------------------------------------------------------------- /src/cpu/quantities_cache/quantities_cache_non_windows_non_darwin.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: CC0-1.0 2 | // infoware - C++ System information Library 3 | 4 | 5 | #ifndef _WIN32 6 | #ifndef __APPLE__ 7 | 8 | 9 | #include "infoware/cpu.hpp" 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | 18 | // http://stackoverflow.com/a/150971/2851815 19 | // https://github.com/karelzak/util-linux/blob/25b7045e5db032df5354c0749cb454a20b89c522/sys-utils/lscpu.c#L1119 20 | iware::cpu::quantities_t iware::cpu::quantities() { 21 | iware::cpu::quantities_t ret{}; 22 | ret.logical = sysconf(_SC_NPROCESSORS_ONLN); 23 | 24 | std::ifstream cpuinfo("/proc/cpuinfo"); 25 | 26 | if(!cpuinfo.is_open() || !cpuinfo) 27 | return ret; 28 | 29 | std::vector package_ids; 30 | for(std::string line; std::getline(cpuinfo, line);) 31 | if(line.find("physical id") == 0) { 32 | const auto physical_id = std::strtoul(line.c_str() + line.find_first_of("1234567890"), nullptr, 10); 33 | if(std::find(package_ids.begin(), package_ids.end(), physical_id) == package_ids.end()) 34 | package_ids.emplace_back(physical_id); 35 | } 36 | 37 | ret.packages = package_ids.size(); 38 | ret.physical = ret.logical / ret.packages; 39 | 40 | return ret; 41 | } 42 | 43 | // http://superuser.com/a/203481 44 | iware::cpu::cache_t iware::cpu::cache(unsigned int level) { 45 | std::string prefix("/sys/devices/system/cpu/cpu0/cache/index" + std::to_string(level) + '/'); 46 | iware::cpu::cache_t ret{}; 47 | 48 | { 49 | std::ifstream size(prefix + "size"); 50 | if(size.is_open() && size) { 51 | char suffix; 52 | size >> ret.size >> suffix; 53 | switch(suffix) { 54 | case 'G': 55 | ret.size *= 1024; 56 | [[fallthrough]]; 57 | case 'M': 58 | ret.size *= 1024; 59 | [[fallthrough]]; 60 | case 'K': 61 | ret.size *= 1024; 62 | } 63 | } 64 | } 65 | 66 | { 67 | std::ifstream line_size(prefix + "coherency_line_size"); 68 | if(line_size.is_open() && line_size) 69 | line_size >> ret.line_size; 70 | } 71 | 72 | { 73 | std::ifstream associativity(prefix + "associativity"); 74 | if(associativity.is_open() && associativity) { 75 | unsigned int tmp; 76 | associativity >> tmp; 77 | ret.associativity = tmp; 78 | } 79 | } 80 | 81 | { 82 | std::ifstream type(prefix + "type"); 83 | if(type.is_open() && type) { 84 | std::string tmp; 85 | type >> tmp; 86 | if(tmp.find("nified") == 1) 87 | ret.type = iware::cpu::cache_type_t::unified; 88 | else if(tmp.find("nstruction") == 1) 89 | ret.type = iware::cpu::cache_type_t::instruction; 90 | else if(tmp.find("ata") == 1) 91 | ret.type = iware::cpu::cache_type_t::data; 92 | else if(tmp.find("race") == 1) 93 | ret.type = iware::cpu::cache_type_t::trace; 94 | } 95 | } 96 | 97 | return ret; 98 | } 99 | 100 | 101 | #endif 102 | #endif 103 | -------------------------------------------------------------------------------- /src/cpu/quantities_cache/quantities_cache_windows.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: CC0-1.0 2 | // infoware - C++ System information Library 3 | 4 | 5 | #ifdef _WIN32 6 | 7 | 8 | #include "infoware/cpu.hpp" 9 | #include 10 | #include 11 | #define WIN32_LEAN_AND_MEAN 12 | #include 13 | 14 | 15 | static std::vector cpuinfo_buffer() { 16 | std::vector buffer; 17 | 18 | DWORD byte_count = 0; 19 | GetLogicalProcessorInformation(nullptr, &byte_count); 20 | buffer.resize(byte_count / sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION)); 21 | GetLogicalProcessorInformation(buffer.data(), &byte_count); 22 | 23 | return buffer; 24 | } 25 | 26 | 27 | // C++ified http://stackoverflow.com/a/28894219/2851815 28 | iware::cpu::quantities_t iware::cpu::quantities() { 29 | iware::cpu::quantities_t ret{}; 30 | for(auto&& info : cpuinfo_buffer()) 31 | switch(info.Relationship) { 32 | case RelationProcessorCore: 33 | ++ret.physical; 34 | // A hyperthreaded core supplies more than one logical processor. 35 | ret.logical += static_cast(std::bitset(static_cast(info.ProcessorMask)).count()); 36 | break; 37 | 38 | case RelationProcessorPackage: 39 | // Logical processors share a physical package. 40 | ++ret.packages; 41 | break; 42 | 43 | default: 44 | break; 45 | } 46 | 47 | return ret; 48 | } 49 | 50 | iware::cpu::cache_t iware::cpu::cache(unsigned int level) { 51 | for(auto&& info : cpuinfo_buffer()) 52 | if(info.Relationship == RelationCache) 53 | // Cache data is in ptr->Cache, one CACHE_DESCRIPTOR structure for each cache. 54 | if(info.Cache.Level == level) { 55 | iware::cpu::cache_type_t type{}; 56 | switch(info.Cache.Type) { 57 | case CacheUnified: 58 | type = iware::cpu::cache_type_t::unified; 59 | break; 60 | case CacheInstruction: 61 | type = iware::cpu::cache_type_t::instruction; 62 | break; 63 | case CacheData: 64 | type = iware::cpu::cache_type_t::data; 65 | break; 66 | case CacheTrace: 67 | type = iware::cpu::cache_type_t::trace; 68 | break; 69 | } 70 | return {info.Cache.Size, info.Cache.LineSize, info.Cache.Associativity, type}; 71 | } 72 | 73 | return {}; 74 | } 75 | 76 | 77 | #endif 78 | -------------------------------------------------------------------------------- /src/cpu/vendor_model_name/vendor_id_darwin_arm.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: CC0-1.0 2 | // infoware - C++ System information Library 3 | 4 | 5 | #include "infoware/cpu.hpp" 6 | #include "infoware/detail/sysctl.hpp" 7 | #include "infoware/platform.hpp" 8 | #include 9 | #include 10 | 11 | 12 | #if __APPLE__ && INFOWARE_ARM 13 | #include 14 | 15 | std::string iware::cpu::vendor_id() { 16 | return iware::detail::sysctl(CTL_KERN, HW_MACHINE); 17 | } 18 | #endif /* INFOWARE_ARM */ 19 | -------------------------------------------------------------------------------- /src/cpu/vendor_model_name/vendor_id_x86.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: CC0-1.0 2 | // infoware - C++ System information Library 3 | 4 | 5 | #include "infoware/platform.hpp" 6 | #if INFOWARE_X86 7 | 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | 14 | std::string iware::cpu::vendor_id() { 15 | std::int32_t info[4]; 16 | char name[13]; 17 | 18 | iware::detail::cpuid(info, 0); 19 | std::memcpy(name + 0, &info[1], 4); 20 | std::memcpy(name + 4, &info[3], 4); 21 | std::memcpy(name + 8, &info[2], 4); 22 | name[12] = '\0'; 23 | 24 | return name; 25 | } 26 | 27 | 28 | #endif /* INFOWARE_X86 */ 29 | -------------------------------------------------------------------------------- /src/cpu/vendor_model_name/vendor_model_name_darwin.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: CC0-1.0 2 | // infoware - C++ System information Library 3 | 4 | 5 | #ifdef __APPLE__ 6 | 7 | 8 | #include "infoware/cpu.hpp" 9 | #include "infoware/detail/sysctl.hpp" 10 | 11 | 12 | std::string iware::cpu::vendor() { 13 | return iware::detail::sysctl("machdep.cpu.vendor"); 14 | } 15 | 16 | std::string iware::cpu::model_name() { 17 | return iware::detail::sysctl("machdep.cpu.brand_string"); 18 | } 19 | 20 | 21 | #endif 22 | -------------------------------------------------------------------------------- /src/cpu/vendor_model_name/vendor_model_name_non_windows_non_darwin.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: CC0-1.0 2 | // infoware - C++ System information Library 3 | 4 | 5 | #ifndef _WIN32 6 | #ifndef __APPLE__ 7 | 8 | 9 | #include "infoware/cpu.hpp" 10 | #include 11 | #include 12 | 13 | 14 | static std::string cpuinfo_value(const char* key) { 15 | std::ifstream cpuinfo("/proc/cpuinfo"); 16 | 17 | if(!cpuinfo.is_open() || !cpuinfo) 18 | return {}; 19 | 20 | for(std::string line; std::getline(cpuinfo, line);) 21 | if(line.find(key) == 0) { 22 | const auto colon_id = line.find_first_of(':'); 23 | const auto nonspace_id = line.find_first_not_of(" \t", colon_id + 1); 24 | return line.c_str() + nonspace_id; 25 | } 26 | 27 | return {}; 28 | } 29 | 30 | 31 | std::string iware::cpu::vendor() { 32 | return cpuinfo_value("vendor"); 33 | } 34 | 35 | std::string iware::cpu::model_name() { 36 | return cpuinfo_value("model name"); 37 | } 38 | 39 | 40 | #endif 41 | #endif 42 | -------------------------------------------------------------------------------- /src/cpu/vendor_model_name/vendor_model_name_windows.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: CC0-1.0 2 | // infoware - C++ System information Library 3 | 4 | 5 | #ifdef _WIN32 6 | 7 | 8 | #include "infoware/cpu.hpp" 9 | #include "infoware/detail/scope.hpp" 10 | #define WIN32_LEAN_AND_MEAN 11 | #include 12 | 13 | 14 | template 15 | static std::string central_processor_subkey(const char* key) { 16 | HKEY hkey; 17 | if(RegOpenKeyExA(HKEY_LOCAL_MACHINE, R"(HARDWARE\DESCRIPTION\System\CentralProcessor\0)", 0, KEY_READ, &hkey)) 18 | return {}; 19 | iware::detail::quickscope_wrapper hkey_closer{[&] { RegCloseKey(hkey); }}; 20 | 21 | char identifier[IdentLen]; 22 | DWORD identifier_len = sizeof(identifier); 23 | LPBYTE lpdata = static_cast(static_cast(&identifier[0])); 24 | if(RegQueryValueExA(hkey, key, nullptr, nullptr, lpdata, &identifier_len)) 25 | return {}; 26 | 27 | return identifier; 28 | } 29 | 30 | std::string iware::cpu::vendor() { 31 | return central_processor_subkey<12 + 1>("VendorIdentifier"); 32 | } 33 | 34 | std::string iware::cpu::model_name() { 35 | return central_processor_subkey<64 + 1>("ProcessorNameString"); 36 | } 37 | 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /src/detail/cpuid_non_windows_x86.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: CC0-1.0 2 | // infoware - C++ System information Library 3 | 4 | 5 | #ifndef _WIN32 6 | 7 | #include "infoware/platform.hpp" 8 | #if INFOWARE_X86 9 | 10 | #include "infoware/detail/cpuid.hpp" 11 | #include 12 | #include 13 | 14 | 15 | void iware::detail::cpuid(std::int32_t (&out)[4], std::int32_t x) { 16 | __cpuid_count(x, 0, out[0], out[1], out[2], out[3]); 17 | } 18 | 19 | std::uint64_t iware::detail::xgetbv(std::uint32_t index) { 20 | std::uint32_t eax, edx; 21 | __asm__ __volatile__("xgetbv" : "=a"(eax), "=d"(edx) : "c"(index)); 22 | return ((uint64_t)edx << 32) | eax; 23 | } 24 | 25 | 26 | #endif /* INFOWARE_X86 */ 27 | #endif /* _WIN32 */ 28 | -------------------------------------------------------------------------------- /src/detail/cpuid_windows.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: CC0-1.0 2 | // infoware - C++ System information Library 3 | 4 | 5 | #ifdef _WIN32 6 | 7 | 8 | #include "infoware/detail/cpuid.hpp" 9 | #include 10 | #include 11 | 12 | 13 | void iware::detail::cpuid(std::int32_t (&out)[4], std::int32_t x) { 14 | __cpuidex(out, x, 0); 15 | } 16 | 17 | std::uint64_t iware::detail::xgetbv(std::uint32_t x) { 18 | return _xgetbv(x); 19 | } 20 | 21 | 22 | #endif 23 | -------------------------------------------------------------------------------- /src/detail/sysctl_darwin.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: CC0-1.0 2 | // infoware - C++ System information Library 3 | 4 | 5 | #ifdef __APPLE__ 6 | 7 | 8 | #include "infoware/detail/sysctl.hpp" 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | 16 | // Requires data.size() >= sizeof(T) 17 | template 18 | static std::pair deconstruct_specific_int(const std::string& data) { 19 | std::pair out{true, {}}; 20 | std::memcpy(&out.second, data.data(), sizeof(out.second)); 21 | return out; 22 | } 23 | 24 | 25 | #define SYSCTL_IMPL(fname, ...) \ 26 | std::size_t len{}; \ 27 | if(fname(__VA_ARGS__, nullptr, &len, nullptr, 0)) \ 28 | return {}; \ 29 | \ 30 | std::string ret(len, '\0'); \ 31 | if(fname(__VA_ARGS__, &ret[0], &len, nullptr, 0)) \ 32 | return {}; \ 33 | \ 34 | return ret 35 | 36 | std::string iware::detail::sysctl(const char* name) { 37 | SYSCTL_IMPL(::sysctlbyname, name); 38 | } 39 | 40 | std::string iware::detail::sysctl(int mib_0, int mib_1) { 41 | int name[2]{mib_0, mib_1}; 42 | 43 | SYSCTL_IMPL(::sysctl, name, sizeof(name) / sizeof(*name)); 44 | } 45 | 46 | 47 | std::pair iware::detail::deconstruct_sysctl_int(const std::string& data) { 48 | switch(data.size()) { 49 | case sizeof(std::uint16_t): 50 | return deconstruct_specific_int(data); 51 | 52 | case sizeof(std::uint32_t): 53 | return deconstruct_specific_int(data); 54 | 55 | case sizeof(std::uint64_t): 56 | return deconstruct_specific_int(data); 57 | 58 | default: 59 | return {}; 60 | } 61 | } 62 | 63 | #endif 64 | -------------------------------------------------------------------------------- /src/detail/winstring_non_windows.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: CC0-1.0 2 | // infoware - C++ System information Library 3 | 4 | 5 | #ifndef _WIN32 6 | 7 | 8 | #include "infoware/detail/winstring.hpp" 9 | 10 | 11 | std::string iware::detail::narrowen_winstring(const wchar_t*) { 12 | return {}; 13 | } 14 | 15 | std::string iware::detail::narrowen_bstring(const wchar_t*) { 16 | return {}; 17 | } 18 | 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /src/detail/winstring_windows.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: CC0-1.0 2 | // infoware - C++ System information Library 3 | 4 | 5 | #ifdef _WIN32 6 | 7 | 8 | #include "infoware/detail/winstring.hpp" 9 | #include 10 | #include 11 | #define WIN32_LEAN_AND_MEAN 12 | #include 13 | #include 14 | 15 | 16 | static std::string transcode_from_wide(const wchar_t* wstr, std::size_t wstr_size) { 17 | std::string ret; 18 | // convert even embedded NUL 19 | if(const auto len = WideCharToMultiByte(CP_UTF8, 0, wstr, static_cast(wstr_size), nullptr, 0, 0, 0)) { 20 | ret.resize(len, '\0'); 21 | if(!WideCharToMultiByte(CP_UTF8, 0, wstr, static_cast(wstr_size), &ret[0], len, 0, 0)) 22 | ret.clear(); 23 | } 24 | return ret; 25 | } 26 | 27 | std::string iware::detail::narrowen_winstring(const wchar_t* wstr) { 28 | if(!wstr) 29 | return {}; 30 | 31 | return transcode_from_wide(wstr, std::wcslen(wstr)); 32 | } 33 | 34 | std::string iware::detail::narrowen_bstring(const wchar_t* bstr) { 35 | if(!bstr) 36 | return {}; 37 | 38 | return transcode_from_wide(bstr, SysStringLen(const_cast(bstr))); 39 | } 40 | 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /src/gpu/Metal.mm: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: CC0-1.0 2 | // infoware - C++ System information Library 3 | 4 | 5 | #if __APPLE__ && !defined(INFOWARE_USE_OPENCL) && !defined(INFOWARE_USE_VULKAN) 6 | 7 | 8 | #include "infoware/gpu.hpp" 9 | #import 10 | 11 | 12 | std::vector iware::gpu::device_properties() { 13 | NSArray>* devices = MTLCopyAllDevices(); 14 | std::vector results; 15 | 16 | for(id device in devices) { 17 | const char* name = [device.name UTF8String]; 18 | 19 | // there is not cache_size and max_frequency in MTLDevice 20 | results.push_back(device_properties_t{ 21 | vendor_t::apple, std::string(name, device.name.length), device.recommendedMaxWorkingSetSize, 22 | 0, // OpenCL returns 0 on M2 23 | 1000 // OpenCL returns 1000 on M2 24 | }); 25 | } 26 | return results; 27 | } 28 | 29 | 30 | #endif /* __APPLE__ && !defined (INFOWARE_USE_OPENCL) && !defined(INFOWARE_USE_VULKAN) */ 31 | -------------------------------------------------------------------------------- /src/gpu/OpenCL.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: CC0-1.0 2 | // infoware - C++ System information Library 3 | 4 | 5 | #ifndef INFOWARE_USE_VULKAN 6 | #ifndef INFOWARE_USE_D3D 7 | #ifdef INFOWARE_USE_OPENCL 8 | 9 | #include "infoware/gpu.hpp" 10 | #include 11 | #include 12 | #ifdef __APPLE__ 13 | #include 14 | #else 15 | #include 16 | #endif 17 | 18 | 19 | static iware::gpu::vendor_t parse_vendor(const char* name) { 20 | if(!std::strcmp(name, "Intel(R) Corporation") || !std::strcmp(name, "Intel")) 21 | return iware::gpu::vendor_t::intel; 22 | else if(!std::strcmp(name, "Advanced Micro Devices, Inc.") || !std::strcmp(name, "AMD")) 23 | return iware::gpu::vendor_t::amd; 24 | else if(!std::strcmp(name, "NVIDIA Corporation")) 25 | return iware::gpu::vendor_t::nvidia; 26 | else if(!std::strcmp(name, "Apple")) 27 | return iware::gpu::vendor_t::apple; 28 | else 29 | return iware::gpu::vendor_t::unknown; 30 | } 31 | 32 | 33 | /// See https://github.com/Oblomov/clinfo/blob/bfc628e74d4cdbf5c5adca169e8bae540fca92ef/src/clinfo.c#L2104 for other available props 34 | std::vector iware::gpu::device_properties() { 35 | cl_platform_id platforms[64]; 36 | cl_uint platforms_used; 37 | clGetPlatformIDs(sizeof(platforms) / sizeof(*platforms), platforms, &platforms_used); 38 | 39 | std::vector ret; 40 | for(auto i = 0u; i < platforms_used; ++i) { 41 | cl_device_id devices[64]; 42 | cl_uint devices_used; 43 | clGetDeviceIDs(platforms[i], CL_DEVICE_TYPE_GPU, sizeof(devices) / sizeof(*devices), devices, &devices_used); 44 | 45 | for(auto j = 0u; j < devices_used; ++j) { 46 | char name[256]; 47 | char vendorname[256]; 48 | cl_ulong cache; 49 | cl_ulong memory; 50 | cl_uint max_frequency; 51 | 52 | clGetDeviceInfo(devices[j], CL_DEVICE_GLOBAL_MEM_CACHE_SIZE, sizeof(cache), &cache, nullptr); 53 | clGetDeviceInfo(devices[j], CL_DEVICE_MAX_CLOCK_FREQUENCY, sizeof(max_frequency), &max_frequency, nullptr); 54 | clGetDeviceInfo(devices[j], CL_DEVICE_GLOBAL_MEM_SIZE, sizeof(memory), &memory, nullptr); 55 | clGetDeviceInfo(devices[j], CL_DEVICE_VENDOR, sizeof(vendorname) / sizeof(*vendorname), &vendorname, nullptr); 56 | clGetDeviceInfo(devices[j], CL_DEVICE_NAME, sizeof(name) / sizeof(*name), &name, nullptr); 57 | 58 | ret.push_back({parse_vendor(vendorname), name, memory, cache, max_frequency * 1'000'000}); 59 | } 60 | } 61 | 62 | return ret; 63 | } 64 | 65 | 66 | #endif 67 | #endif 68 | #endif 69 | -------------------------------------------------------------------------------- /src/gpu/OpenGL_non_windows_non_darwin.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: CC0-1.0 2 | // infoware - C++ System information Library 3 | 4 | 5 | #ifndef INFOWARE_USE_VULKAN 6 | #ifndef INFOWARE_USE_D3D 7 | #ifndef INFOWARE_USE_OPENCL 8 | #ifndef _WIN32 9 | #ifndef __APPLE__ 10 | #ifdef INFOWARE_USE_OPENGL 11 | 12 | #include "infoware/detail/scope.hpp" 13 | #include "infoware/gpu.hpp" 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | 21 | static iware::gpu::vendor_t vendor_from_name(std::string name) { 22 | std::transform(name.begin(), name.end(), name.begin(), ::toupper); 23 | 24 | if(name.find("NVIDIA") != std::string::npos) 25 | return iware::gpu::vendor_t::nvidia; 26 | else if(name.find("AMD") != std::string::npos || name.find("ATI") != std::string::npos || name.find("ADVANCED MICRO DEVICES") != std::string::npos) 27 | return iware::gpu::vendor_t::amd; 28 | else if(name.find("INTEL") != std::string::npos) 29 | return iware::gpu::vendor_t::intel; 30 | else if(name.find("MICROSOFT") != std::string::npos) 31 | return iware::gpu::vendor_t::microsoft; 32 | else if(name.find("QUALCOMM") != std::string::npos) 33 | return iware::gpu::vendor_t::qualcomm; 34 | else 35 | return iware::gpu::vendor_t::unknown; 36 | } 37 | 38 | std::vector iware::gpu::device_properties() { 39 | EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY); 40 | eglInitialize(display, nullptr, nullptr); 41 | iware::detail::quickscope_wrapper display_deleter{[&]() { eglTerminate(display); }}; 42 | 43 | // Choose an EGL Config 44 | static const EGLint config_attributes[] = {EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT, EGL_NONE}; 45 | EGLConfig config; 46 | EGLint numConfigs{}; 47 | if(!eglChooseConfig(display, config_attributes, &config, 1, &numConfigs) || !numConfigs) 48 | return {}; 49 | 50 | // Create an EGL Surface 51 | static const EGLint pbuffer_attributes[] = {EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE}; 52 | EGLSurface surface = eglCreatePbufferSurface(display, config, pbuffer_attributes); 53 | if(surface == EGL_NO_SURFACE) 54 | return {}; 55 | iware::detail::quickscope_wrapper surface_deleter{[&]() { eglDestroySurface(display, surface); }}; 56 | 57 | static const EGLint context_attributes[] = {EGL_CONTEXT_MAJOR_VERSION, 2, EGL_CONTEXT_MINOR_VERSION, 0, EGL_NONE}; 58 | EGLContext context = eglCreateContext(display, config, EGL_NO_CONTEXT, context_attributes); 59 | if(context == EGL_NO_CONTEXT) 60 | return {}; 61 | iware::detail::quickscope_wrapper context_deleter{[&]() { eglDestroyContext(display, context); }}; 62 | 63 | eglMakeCurrent(display, surface, surface, context); 64 | iware::detail::quickscope_wrapper context_restorer{[&]() { eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); }}; 65 | 66 | 67 | auto vendor = reinterpret_cast(glGetString(GL_VENDOR)); 68 | std::string renderer = reinterpret_cast(glGetString(GL_RENDERER)); 69 | 70 | iware::gpu::vendor_t vendor_type = vendor_from_name(vendor); 71 | if(vendor_type == iware::gpu::vendor_t::unknown) 72 | vendor_type = vendor_from_name(renderer); 73 | 74 | // Check if context has extension for meminfo, we can access the dedicated vram using GL_NVX_gpu_memory_info 75 | // which is supported using mesa on AMD and NVIDIA devices, but not on Intel (that is fine, they do not have dedicated VRAM) 76 | // Funnily enough this won't work on NVIDIA devices at all because NVIDIA does not support EGL higher than OpenGL ES 2.0, this extension 77 | // is available in OpenGL 2.0 but not in ES 78 | // In the future there should be a fallback for GLX context especially for NVIDIA devices 79 | bool has_NVX_mem_info = false; 80 | if(auto extensions = reinterpret_cast(glGetString(GL_EXTENSIONS))) 81 | has_NVX_mem_info = std::strstr(extensions, "GL_NVX_gpu_memory_info"); 82 | 83 | GLint total_memory = 0; 84 | if(has_NVX_mem_info) 85 | glGetIntegerv(GL_GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX, &total_memory); 86 | 87 | 88 | // We can't get the cache size or the max frequency, so we just set them to 0 89 | return {device_properties_t{ 90 | std::move(vendor_type), 91 | std::move(renderer), 92 | static_cast(total_memory), 93 | 0, 94 | 0, 95 | }}; 96 | } 97 | 98 | 99 | #endif 100 | #endif 101 | #endif 102 | #endif 103 | #endif 104 | #endif 105 | -------------------------------------------------------------------------------- /src/gpu/OpenGL_windows.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: CC0-1.0 2 | // infoware - C++ System information Library 3 | 4 | 5 | #ifndef INFOWARE_USE_VULKAN 6 | #ifndef INFOWARE_USE_D3D 7 | #ifndef INFOWARE_USE_OPENCL 8 | #ifdef _WIN32 9 | #ifdef INFOWARE_USE_OPENGL 10 | 11 | #include "infoware/gpu.hpp" 12 | 13 | 14 | std::vector iware::gpu::device_properties() { 15 | #warning No OpenGL Win32 implementation 16 | return {}; 17 | } 18 | 19 | 20 | #endif 21 | #endif 22 | #endif 23 | #endif 24 | #endif 25 | -------------------------------------------------------------------------------- /src/gpu/blank_all.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: CC0-1.0 2 | // infoware - C++ System information Library 3 | 4 | 5 | #ifndef INFOWARE_USE_OPENGL 6 | #ifndef INFOWARE_USE_OPENCL 7 | #ifndef INFOWARE_USE_D3D 8 | #ifndef INFOWARE_USE_VULKAN 9 | #ifndef __APPLE__ 10 | 11 | 12 | #include "infoware/gpu.hpp" 13 | 14 | 15 | std::vector iware::gpu::device_properties() { 16 | return {}; 17 | } 18 | 19 | 20 | #endif 21 | #endif 22 | #endif 23 | #endif 24 | #endif 25 | -------------------------------------------------------------------------------- /src/gpu/d3d.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: CC0-1.0 2 | // infoware - C++ System information Library 3 | 4 | 5 | #ifndef INFOWARE_USE_VULKAN 6 | #ifdef INFOWARE_USE_D3D 7 | 8 | 9 | #include "infoware/detail/memory.hpp" 10 | #include "infoware/detail/winstring.hpp" 11 | #include "infoware/gpu.hpp" 12 | #include "infoware/pci.hpp" 13 | #include 14 | #include 15 | 16 | 17 | static iware::gpu::vendor_t vendor_from_name(const std::string& v) { 18 | if(v.find("NVidia") != std::string::npos || v.find("NVIDIA") != std::string::npos) 19 | return iware::gpu::vendor_t::nvidia; 20 | else if(v.find("AMD") != std::string::npos || v.find("ATi") != std::string::npos || v.find("Advanced Micro Devices") != std::string::npos) 21 | return iware::gpu::vendor_t::amd; 22 | else if(v.find("Intel") != std::string::npos) 23 | return iware::gpu::vendor_t::intel; 24 | else if(v.find("Microsoft") != std::string::npos) 25 | return iware::gpu::vendor_t::microsoft; 26 | else if(v.find("Qualcomm") != std::string::npos) 27 | return iware::gpu::vendor_t::qualcomm; 28 | else 29 | return iware::gpu::vendor_t::unknown; 30 | } 31 | 32 | 33 | std::vector iware::gpu::device_properties() { 34 | IDXGIFactory* factory_raw; 35 | if(CreateDXGIFactory(__uuidof(IDXGIFactory), reinterpret_cast(&factory_raw)) != S_OK) 36 | return {}; 37 | std::unique_ptr factory(factory_raw); 38 | 39 | std::vector devices{}; 40 | for(auto aid = 0u;; ++aid) { 41 | IDXGIAdapter* adapter_raw; 42 | const auto adapter_result = factory->EnumAdapters(aid, &adapter_raw); 43 | if(adapter_result != S_OK || adapter_result == DXGI_ERROR_NOT_FOUND) 44 | break; 45 | std::unique_ptr adapter(adapter_raw); 46 | 47 | DXGI_ADAPTER_DESC adapterdesc; 48 | adapter->GetDesc(&adapterdesc); 49 | 50 | const auto device = iware::pci::identify_device(adapterdesc.VendorId, adapterdesc.DeviceId); 51 | std::string device_name = device.device_name ? device.device_name : iware::detail::narrowen_winstring(adapterdesc.Description); 52 | 53 | devices.push_back({vendor_from_name(device.vendor_name), device_name, adapterdesc.DedicatedVideoMemory, adapterdesc.SharedSystemMemory, 54 | // TODO: there's purportedly (https://en.wikipedia.org/wiki/Windows_Display_Driver_Model#WDDM_2.3) 55 | // a Windows API for getting the max clock, but I haven't been able to find it or use it 56 | 0}); 57 | } 58 | return devices; 59 | } 60 | 61 | 62 | #endif 63 | #endif 64 | -------------------------------------------------------------------------------- /src/gpu/vulkan.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: CC0-1.0 2 | // infoware - C++ System information Library 3 | 4 | 5 | #ifdef INFOWARE_USE_VULKAN 6 | 7 | 8 | #include "infoware/detail/scope.hpp" 9 | #include "infoware/gpu.hpp" 10 | #include 11 | #include 12 | #include 13 | 14 | 15 | std::vector iware::gpu::device_properties() { 16 | VkInstanceCreateInfo createInfo{}; 17 | createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; 18 | 19 | VkInstance instance; 20 | VkResult result = vkCreateInstance(&createInfo, nullptr, &instance); 21 | if(result != VK_SUCCESS) 22 | throw nullptr; 23 | iware::detail::quickscope_wrapper instance_deleter{[&]() { vkDestroyInstance(instance, nullptr); }}; 24 | 25 | 26 | uint32_t devices_len = 2; 27 | std::vector devices(devices_len); 28 | while((result = vkEnumeratePhysicalDevices(instance, &devices_len, devices.data())) == VK_INCOMPLETE) { 29 | devices.emplace_back(); 30 | devices_len = devices.size(); 31 | } 32 | if(result != VK_SUCCESS) 33 | return {}; 34 | devices.resize(devices_len); 35 | 36 | std::vector ret; 37 | ret.reserve(devices.size()); 38 | for(auto&& device : devices) { 39 | VkPhysicalDeviceProperties props{}; 40 | vkGetPhysicalDeviceProperties(device, &props); 41 | 42 | // https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceProperties.html 43 | // > If the vendor has a PCI vendor ID, the low 16 bits of vendorID must contain that PCI vendor ID, and the remaining bits must be set to zero. 44 | // > Otherwise, the value returned must be a valid Khronos vendor ID, 45 | // None of the s match anything in our enum. 46 | auto vendor = vendor_t::unknown; 47 | switch(props.vendorID) { 48 | case 0x8086: // Intel Corporation 49 | vendor = vendor_t::intel; 50 | break; 51 | case 0x1002: // Advanced Micro Devices, Inc. [AMD/ATI] 52 | case 0x1022: // Advanced Micro Devices, Inc. [AMD] 53 | vendor = vendor_t::amd; 54 | break; 55 | case 0x10de: // NVIDIA Corporation 56 | case 0x12d2: // NVidia / SGS Thomson (Joint Venture) 57 | vendor = vendor_t::nvidia; 58 | break; 59 | case 0x1414: // Microsoft Corporation 60 | vendor = vendor_t::microsoft; 61 | break; 62 | case 0x168c: // Qualcomm Atheros 63 | case 0x17cb: // Qualcomm 64 | case 0x1969: // Qualcomm Atheros 65 | case 0x5143: // Qualcomm Inc 66 | vendor = vendor_t::qualcomm; 67 | break; 68 | case 0x106b: // Apple Inc. 69 | vendor = vendor_t::apple; 70 | break; 71 | } 72 | 73 | VkPhysicalDeviceMemoryProperties mem{}; 74 | vkGetPhysicalDeviceMemoryProperties(device, &mem); 75 | 76 | ret.emplace_back(device_properties_t{ 77 | vendor, 78 | props.deviceName, 79 | std::accumulate(mem.memoryHeaps, mem.memoryHeaps + mem.memoryHeapCount, static_cast(0), [](auto i, auto&& heap) { return i + heap.size; }), 80 | 0, 81 | 0, 82 | }); 83 | } 84 | return ret; 85 | } 86 | 87 | 88 | #endif 89 | -------------------------------------------------------------------------------- /src/pci.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: CC0-1.0 2 | // infoware - C++ System information Library 3 | 4 | 5 | #ifdef INFOWARE_USE_PCIIDS 6 | 7 | 8 | #include "infoware/pci.hpp" 9 | #include "infoware_generated/pci_data.hpp" 10 | #include 11 | #include 12 | 13 | 14 | namespace { 15 | struct id_pair_t { 16 | std::uint64_t id; 17 | std::size_t index; 18 | }; 19 | 20 | struct pci_vendor_info_t { 21 | std::uint64_t pci_id; 22 | const char* name; 23 | std::initializer_list device_indices; 24 | }; 25 | 26 | struct pci_device_info_t { 27 | std::uint64_t pci_id; 28 | const char* name; 29 | }; 30 | } // anonymous namespace 31 | 32 | 33 | static const id_pair_t indices[]{INFOWARE_GENERATED_PCI_INDICES}; 34 | static const pci_vendor_info_t vendors[]{INFOWARE_GENERATED_PCI_VENDORS}; 35 | static const pci_device_info_t devices[]{INFOWARE_GENERATED_PCI_DEVICES}; 36 | 37 | 38 | static const pci_vendor_info_t* find_vendor(std::uint64_t vendor_id) noexcept { 39 | const auto idx_itr = std::lower_bound(std::begin(indices), std::end(indices), vendor_id, [](auto&& left, auto right) { return left.id < right; }); 40 | if(idx_itr != std::end(indices) && idx_itr->id == vendor_id) 41 | return &vendors[idx_itr->index]; 42 | else 43 | return nullptr; 44 | } 45 | 46 | 47 | iware::pci::device iware::pci::identify_device(std::uint64_t vendor_id, std::uint64_t device_id) noexcept { 48 | const auto vendor = find_vendor(vendor_id); 49 | if(!vendor) 50 | return {nullptr, nullptr}; 51 | 52 | const auto device_itr = std::lower_bound(std::begin(vendor->device_indices), std::end(vendor->device_indices), device_id, 53 | [](auto left, auto right) { return devices[left].pci_id < right; }); 54 | if(device_itr == std::end(vendor->device_indices) || devices[*device_itr].pci_id != device_id) 55 | return {vendor->name, nullptr}; 56 | 57 | const auto& device = devices[*device_itr]; 58 | return {vendor->name, device.name}; 59 | } 60 | 61 | 62 | const char* iware::pci::identify_vendor(std::uint64_t pci_id) noexcept { 63 | if(const auto vendor = find_vendor(pci_id)) 64 | return vendor->name; 65 | else 66 | return nullptr; 67 | } 68 | 69 | 70 | #endif 71 | -------------------------------------------------------------------------------- /src/system/OS_info/os_info_darwin.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: CC0-1.0 2 | // infoware - C++ System information Library 3 | 4 | 5 | #ifdef __APPLE__ 6 | 7 | 8 | #include "infoware/detail/sysctl.hpp" 9 | #include "infoware/system.hpp" 10 | #include 11 | 12 | 13 | iware::system::OS_info_t iware::system::OS_info() { 14 | auto ctl_osrelease_data = iware::detail::sysctl("kern.osrelease"); 15 | char* osrelease_marker = &ctl_osrelease_data[0]; 16 | 17 | const auto ctl_osrevision_data = iware::detail::sysctl("kern.osrevision"); 18 | unsigned int build_number{}; 19 | if(!ctl_osrevision_data.empty()) { 20 | const auto osrevision_data = iware::detail::deconstruct_sysctl_int(ctl_osrevision_data); 21 | if(osrevision_data.first) 22 | build_number = osrevision_data.second; 23 | } 24 | 25 | return {iware::detail::sysctl("kern.ostype"), // 26 | iware::detail::sysctl("kern.version"), // 27 | static_cast(std::strtoul(osrelease_marker, &osrelease_marker, 10)), // 28 | static_cast(std::strtoul(osrelease_marker + 1, &osrelease_marker, 10)), // 29 | static_cast(std::strtoul(osrelease_marker + 1, nullptr, 10)), // 30 | build_number}; 31 | } 32 | 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /src/system/OS_info/os_info_non_windows_non_darwin.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: CC0-1.0 2 | // infoware - C++ System information Library 3 | 4 | 5 | #ifndef _WIN32 6 | #ifndef __APPLE__ 7 | 8 | 9 | #include "infoware/system.hpp" 10 | #include 11 | #include 12 | 13 | 14 | static iware::system::OS_info_t lsb_release(std::ifstream& release) { 15 | iware::system::OS_info_t ret{}; 16 | 17 | for(std::string line; std::getline(release, line);) 18 | if(line.find("DISTRIB_ID") == 0) 19 | ret.name = line.substr(line.find('=') + 1); 20 | else if(line.find("DISTRIB_RELEASE") == 0) { 21 | char* marker = &line[line.find('=') + 1]; 22 | ret.major = std::strtoul(marker, &marker, 10); 23 | ret.minor = std::strtoul(marker + 1, &marker, 10); 24 | ret.patch = std::strtoul(marker + 1, &marker, 10); 25 | ret.build_number = std::strtoul(marker + 1, nullptr, 10); 26 | } else if(line.find("DISTRIB_DESCRIPTION") == 0) { 27 | const auto start_idx = line.find('"') + 1; 28 | const auto end_idx = line.size() - 1; 29 | ret.full_name = line.substr(start_idx, end_idx - start_idx); 30 | } 31 | 32 | return ret; 33 | } 34 | 35 | static void trim_quotes(std::string& in) { 36 | if(in.empty()) 37 | return; 38 | 39 | if(in.back() == '"') 40 | in.pop_back(); 41 | 42 | if(in.front() == '"') 43 | in.erase(in.begin()); 44 | } 45 | 46 | 47 | // https://www.linux.org/docs/man5/os-release.html 48 | iware::system::OS_info_t iware::system::OS_info() { 49 | std::ifstream release("/etc/os-release"); 50 | 51 | if(!release.is_open() || !release) { 52 | release.open("/usr/lib/os-release", std::ios::in); 53 | if(!release.is_open() || !release) { 54 | release.open("/etc/lsb-release", std::ios::in); 55 | if(!release.is_open() || !release) 56 | return {}; 57 | else 58 | return lsb_release(release); 59 | } 60 | } 61 | 62 | iware::system::OS_info_t ret{}; 63 | 64 | for(std::string line; std::getline(release, line);) 65 | if(line.find("NAME") == 0) 66 | ret.name = line.substr(line.find('=') + 1); 67 | else if(line.find("PRETTY_NAME") == 0) 68 | ret.full_name = line.substr(line.find('=') + 1); 69 | else if(line.find("VERSION_ID") == 0) { 70 | char* marker = &line[line.find('=') + 1]; 71 | if(marker[0] == '"') 72 | ++marker; 73 | ret.major = std::strtoul(marker, &marker, 10); 74 | if(marker[0] && marker[0] != '"') 75 | ret.minor = std::strtoul(marker + 1, &marker, 10); 76 | if(marker[0] && marker[0] != '"') 77 | ret.patch = std::strtoul(marker + 1, &marker, 10); 78 | if(marker[0] && marker[0] != '"') 79 | ret.build_number = std::strtoul(marker + 1, nullptr, 10); 80 | } 81 | 82 | trim_quotes(ret.name); 83 | trim_quotes(ret.full_name); 84 | 85 | return ret; 86 | } 87 | 88 | 89 | #endif 90 | #endif 91 | -------------------------------------------------------------------------------- /src/system/OS_info/os_info_windows.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: CC0-1.0 2 | // infoware - C++ System information Library 3 | 4 | 5 | #ifdef _WIN32 6 | 7 | 8 | #include "infoware/detail/memory.hpp" 9 | #include "infoware/detail/scope.hpp" 10 | #include "infoware/detail/winstring.hpp" 11 | #include "infoware/system.hpp" 12 | #include 13 | #include 14 | #define WIN32_LEAN_AND_MEAN 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #ifdef _MSC_VER 21 | #define strtok_r(...) strtok_s(__VA_ARGS__) 22 | #endif 23 | 24 | 25 | // Use WIM to acquire Win32_OperatingSystem.Caption (same as .Name, but ends before the '|') 26 | // https://msdn.microsoft.com/en-us/library/aa390423(v=vs.85).aspx 27 | static std::string version_name() { 28 | auto err = CoInitializeEx(nullptr, COINIT_MULTITHREADED); 29 | if(err == RPC_E_CHANGED_MODE) // COM already initialised as COINIT_APARTMENTTHREADED: must pass that to bump the reference count 30 | err = CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); 31 | if(FAILED(err)) 32 | return {}; 33 | iware::detail::quickscope_wrapper com_uninitialiser{CoUninitialize}; 34 | 35 | const auto init_result = 36 | CoInitializeSecurity(nullptr, -1, nullptr, nullptr, RPC_C_AUTHN_LEVEL_DEFAULT, RPC_C_IMP_LEVEL_IMPERSONATE, nullptr, EOAC_NONE, nullptr); 37 | if(FAILED(init_result) && init_result != RPC_E_TOO_LATE) 38 | return {}; 39 | 40 | IWbemLocator* wbem_loc_raw; 41 | if(FAILED(CoCreateInstance(CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER, IID_IWbemLocator, reinterpret_cast(&wbem_loc_raw)))) 42 | return {}; 43 | std::unique_ptr wbem_loc(wbem_loc_raw); 44 | 45 | IWbemServices* wbem_services_raw; 46 | wchar_t network_resource[] = LR"(ROOT\CIMV2)"; 47 | if(FAILED(wbem_loc->ConnectServer(network_resource, nullptr, nullptr, 0, 0, 0, 0, &wbem_services_raw))) 48 | return {}; 49 | std::unique_ptr wbem_services(wbem_services_raw); 50 | 51 | if(FAILED(CoSetProxyBlanket(wbem_services.get(), RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, nullptr, RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, nullptr, 52 | EOAC_NONE))) 53 | return {}; 54 | 55 | IEnumWbemClassObject* query_iterator_raw; 56 | wchar_t query_lang[] = L"WQL"; 57 | wchar_t query[] = L"SELECT Caption FROM Win32_OperatingSystem"; 58 | if(FAILED(wbem_services->ExecQuery(query_lang, query, WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, nullptr, &query_iterator_raw))) 59 | return {}; 60 | std::unique_ptr query_iterator(query_iterator_raw); 61 | 62 | std::string ret; 63 | while(query_iterator) { 64 | IWbemClassObject* value_raw; 65 | unsigned long iter_result; 66 | 67 | query_iterator->Next(static_cast(WBEM_INFINITE), 1, &value_raw, &iter_result); 68 | if(!iter_result) 69 | break; 70 | std::unique_ptr value(value_raw); 71 | 72 | VARIANT val; 73 | VariantInit(&val); 74 | value->Get(L"Caption", 0, &val, 0, 0); 75 | iware::detail::quickscope_wrapper val_destructor{[&] { VariantClear(&val); }}; 76 | 77 | ret = iware::detail::narrowen_bstring(val.bstrVal); 78 | } 79 | 80 | return ret; 81 | } 82 | 83 | static unsigned int build_number() { 84 | HKEY hkey{}; 85 | if(RegOpenKeyExA(HKEY_LOCAL_MACHINE, R"(Software\Microsoft\Windows NT\CurrentVersion)", 0, KEY_READ, &hkey)) 86 | return {}; 87 | iware::detail::quickscope_wrapper hkey_closer{[&] { RegCloseKey(hkey); }}; 88 | 89 | DWORD ubr{}; 90 | DWORD ubr_size = sizeof(ubr); 91 | if(!RegQueryValueExA(hkey, "UBR", nullptr, nullptr, reinterpret_cast(&ubr), &ubr_size)) 92 | return ubr; 93 | 94 | // Fall back to BuildLabEx in the early version of Windows 8.1 and less. 95 | DWORD buildlabex_size{}; 96 | if(RegQueryValueExA(hkey, "BuildLabEx", nullptr, nullptr, nullptr, &buildlabex_size)) 97 | return {}; 98 | 99 | std::string buildlabex(buildlabex_size, {}); // REG_SZ may not be NUL-terminated 100 | if(RegQueryValueExA(hkey, "BuildLabEx", nullptr, nullptr, reinterpret_cast(&buildlabex[0]), &buildlabex_size)) 101 | return {}; 102 | 103 | char* ctx{}; 104 | auto token = strtok_r(&buildlabex[0], ".", &ctx); 105 | token = strtok_r(nullptr, ".", &ctx); 106 | return token ? std::strtoul(token, nullptr, 10) : 0; 107 | } 108 | 109 | // RtlGetVersion() started being phased out in Windows 8; need to load it dynamically for Windows 11(?) 110 | // https://docs.microsoft.com/en-us/windows/win32/devnotes/rtlgetversion 111 | iware::system::OS_info_t iware::system::OS_info() { 112 | static NTSTATUS(NTAPI * pRtlGetVersion)(_Out_ PRTL_OSVERSIONINFOW lpVersionInformation) = [] { 113 | decltype(pRtlGetVersion) ret{}; 114 | if(HMODULE ntdllh = GetModuleHandleA("ntdll.dll")) 115 | ret = reinterpret_cast(GetProcAddress(ntdllh, "RtlGetVersion")); 116 | return ret; 117 | }(); 118 | RTL_OSVERSIONINFOW os_version_info{}; 119 | os_version_info.dwOSVersionInfoSize = sizeof(os_version_info); 120 | if(pRtlGetVersion) 121 | pRtlGetVersion(&os_version_info); 122 | 123 | return {"Windows NT", version_name(), os_version_info.dwMajorVersion, os_version_info.dwMinorVersion, os_version_info.dwBuildNumber, build_number()}; 124 | } 125 | 126 | 127 | #endif 128 | -------------------------------------------------------------------------------- /src/system/amounts/amounts_non_windows.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: CC0-1.0 2 | // infoware - C++ System information Library 3 | 4 | 5 | #ifndef _WIN32 6 | 7 | 8 | #include "infoware/detail/scope.hpp" 9 | #include "infoware/system.hpp" 10 | #include 11 | #include 12 | 13 | 14 | // http://man7.org/linux/man-pages/man3/wordexp.3.html 15 | static std::size_t count_expansions(const char* of) noexcept { 16 | wordexp_t exp{}; 17 | iware::detail::quickscope_wrapper exp_deleter{[&]() { wordfree(&exp); }}; 18 | 19 | if(wordexp(of, &exp, 0)) 20 | return 0; 21 | 22 | // If nothing is expanded wordexp() returns the original string 23 | if(exp.we_wordc == 1 && std::strcmp(exp.we_wordv[0], of) == 0) 24 | return 0; 25 | else 26 | return exp.we_wordc; 27 | } 28 | 29 | 30 | // http://unix.stackexchange.com/questions/25601/how-do-mouse-events-work-in-linux 31 | // https://www.kernel.org/doc/Documentation/input/input.txt section 3.2.2 32 | std::size_t iware::system::mouse_amount() noexcept { 33 | return count_expansions("/dev/input/mouse*"); 34 | } 35 | 36 | // https://www.kernel.org/doc/Documentation/input/input.txt section 3.2.1 37 | // Doesn't specify that and there doesn't seem to be a way to get it 38 | std::size_t iware::system::keyboard_amount() noexcept { 39 | return 0; 40 | } 41 | 42 | std::size_t iware::system::other_HID_amount() noexcept { 43 | return 0; 44 | } 45 | 46 | 47 | #endif 48 | -------------------------------------------------------------------------------- /src/system/amounts/amounts_windows.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: CC0-1.0 2 | // infoware - C++ System information Library 3 | 4 | 5 | #ifdef _WIN32 6 | 7 | 8 | #include "infoware/system.hpp" 9 | #define WIN32_LEAN_AND_MEAN 10 | #include 11 | #include 12 | 13 | 14 | // https://msdn.microsoft.com/en-us/library/windows/desktop/ms645598(v=vs.85).aspx 15 | // https://msdn.microsoft.com/en-us/library/windows/desktop/ms645568(v=vs.85).aspx 16 | static std::size_t device_amount(unsigned int device_type) noexcept { 17 | // Assuming 64 is enough for anyone 18 | RAWINPUTDEVICELIST input_devices[64]; 19 | unsigned int input_devices_n = sizeof(input_devices) / sizeof(RAWINPUTDEVICELIST); 20 | const auto amt = GetRawInputDeviceList(input_devices, &input_devices_n, sizeof(RAWINPUTDEVICELIST)); 21 | 22 | return std::count_if(input_devices, input_devices + amt, [&](auto&& device) { return device.dwType == device_type; }); 23 | } 24 | 25 | 26 | std::size_t iware::system::mouse_amount() noexcept { 27 | return device_amount(RIM_TYPEMOUSE); 28 | } 29 | 30 | std::size_t iware::system::keyboard_amount() noexcept { 31 | return device_amount(RIM_TYPEKEYBOARD); 32 | } 33 | 34 | std::size_t iware::system::other_HID_amount() noexcept { 35 | return device_amount(RIM_TYPEHID); 36 | } 37 | 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /src/system/displays/displays_darwin.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: CC0-1.0 2 | // infoware - C++ System information Library 3 | // 4 | // 5 | // Darwin support via Carbon API originally by Arthur Biancarelli – https://github.com/ThePhD/infoware/issues/17#issuecomment-538789869 6 | 7 | 8 | #ifdef __APPLE__ 9 | 10 | 11 | #include "infoware/detail/scope.hpp" 12 | #include "infoware/system.hpp" 13 | #include 14 | #include 15 | #include 16 | 17 | 18 | template 19 | static std::vector enumerate_displays(F&& cbk) { 20 | std::uint32_t num_displays; 21 | if(CGGetActiveDisplayList(0, nullptr, &num_displays) != kCGErrorSuccess) 22 | return {}; 23 | 24 | std::vector display_ids(num_displays); 25 | if(CGGetActiveDisplayList(num_displays, display_ids.data(), &num_displays) != kCGErrorSuccess) 26 | return {}; 27 | 28 | 29 | std::vector ret; 30 | ret.reserve(num_displays); 31 | 32 | for(std::size_t i = 0; i < num_displays; ++i) 33 | ret.emplace_back(std::move(cbk(display_ids[i]))); 34 | 35 | return ret; 36 | } 37 | 38 | 39 | std::vector iware::system::displays() { 40 | return enumerate_displays([](auto display_id) { 41 | const std::uint32_t width = CGDisplayPixelsWide(display_id); 42 | // 25.4 millimeters per inch 43 | const std::uint32_t dpi = width / (CGDisplayScreenSize(display_id).width / 25.4); 44 | 45 | auto display_mode = CGDisplayCopyDisplayMode(display_id); 46 | iware::detail::quickscope_wrapper display_mode_deleter{[&]() { CGDisplayModeRelease(display_mode); }}; 47 | 48 | #pragma GCC diagnostic push 49 | #pragma GCC diagnostic ignored "-Wdeprecated-declarations" 50 | // A string in the form --------RRRRRRRRGGGGGGGGBBBBBBBB 51 | auto pixel_encoding_raw = CGDisplayModeCopyPixelEncoding(display_mode); 52 | iware::detail::quickscope_wrapper pixel_encoding_raw_deleter{[&]() { CFRelease(pixel_encoding_raw); }}; 53 | #pragma GCC diagnostic pop 54 | 55 | // Count the number of occurences of R/G/B pixels 56 | std::uint32_t bpp{}; 57 | if(const auto pixel_encoding = CFStringGetCStringPtr(pixel_encoding_raw, kCFStringEncodingUTF8)) 58 | bpp = std::count_if(pixel_encoding, pixel_encoding + std::strlen(pixel_encoding), [](auto c) { return c == 'R' || c == 'G' || c == 'B'; }); 59 | 60 | 61 | return iware::system::display_t{width, static_cast(CGDisplayPixelsHigh(display_id)), dpi, bpp, 62 | // The refresh rate, in hertz, of the specified display mode for a CRT display. 63 | // Some displays may not use conventional video vertical and horizontal sweep in painting the screen; 64 | // for these displays, the return value is 0. 65 | // 66 | // Tested to return 0 for Retina displays 67 | CGDisplayModeGetRefreshRate(display_mode)}; 68 | }); 69 | } 70 | 71 | std::vector> iware::system::available_display_configurations() { 72 | return enumerate_displays>([](auto display_id) { 73 | auto modes = CGDisplayCopyAllDisplayModes(display_id, nullptr); 74 | if(!modes) 75 | return std::vector{}; 76 | iware::detail::quickscope_wrapper modes_deleter{[&]() { CFRelease(modes); }}; 77 | 78 | const auto modes_len = CFArrayGetCount(modes); 79 | std::vector ret; 80 | ret.reserve(modes_len); 81 | 82 | for(auto i = 0l; i < modes_len; ++i) { 83 | auto mode = static_cast(const_cast(CFArrayGetValueAtIndex(modes, i))); 84 | 85 | ret.emplace_back(iware::system::display_config_t{static_cast(CGDisplayModeGetWidth(mode)), 86 | static_cast(CGDisplayModeGetHeight(mode)), 87 | {CGDisplayModeGetRefreshRate(mode)}}); 88 | } 89 | 90 | return ret; 91 | }); 92 | } 93 | 94 | 95 | #endif 96 | -------------------------------------------------------------------------------- /src/system/displays/displays_default_blank.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: CC0-1.0 2 | // infoware - C++ System information Library 3 | 4 | 5 | #ifndef _WIN32 6 | #ifndef __APPLE__ 7 | #ifndef INFOWARE_USE_X11 8 | 9 | 10 | #include "infoware/system.hpp" 11 | 12 | 13 | std::vector iware::system::displays() { 14 | return {}; 15 | } 16 | 17 | std::vector> iware::system::available_display_configurations() { 18 | return {}; 19 | } 20 | 21 | 22 | #endif 23 | #endif 24 | #endif 25 | -------------------------------------------------------------------------------- /src/system/displays/displays_windows.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: CC0-1.0 2 | // infoware - C++ System information Library 3 | 4 | 5 | #ifdef _WIN32 6 | 7 | 8 | #include "infoware/detail/scope.hpp" 9 | #include "infoware/system.hpp" 10 | #include 11 | #include 12 | #include 13 | #define WIN32_LEAN_AND_MEAN 14 | #include 15 | 16 | 17 | struct bundle { 18 | HDC desktop_dc; 19 | std::vector ret; 20 | }; 21 | 22 | static BOOL CALLBACK consume_one_display(HMONITOR, HDC hdc, LPRECT rect, LPARAM userdata) { 23 | auto& bundle = *reinterpret_cast(userdata); 24 | 25 | const unsigned int desktop_dpi = GetDeviceCaps(bundle.desktop_dc, LOGPIXELSX); 26 | // https://blogs.msdn.microsoft.com/oldnewthing/20101013-00/?p=12543 27 | const unsigned int desktop_bpp = GetDeviceCaps(bundle.desktop_dc, BITSPIXEL) * GetDeviceCaps(bundle.desktop_dc, PLANES); 28 | const double desktop_refresh_rate = GetDeviceCaps(bundle.desktop_dc, VREFRESH); 29 | 30 | 31 | // Sometimes returns 0 – fall back to the desktop's globals if so. 32 | const unsigned int monitor_dpi = GetDeviceCaps(hdc, LOGPIXELSX); 33 | const unsigned int monitor_bpp = GetDeviceCaps(hdc, BITSPIXEL) * GetDeviceCaps(hdc, PLANES); 34 | const double monitor_refresh_rate = GetDeviceCaps(hdc, VREFRESH); 35 | 36 | const unsigned int width = std::abs(rect->right - rect->left); 37 | const unsigned int height = std::abs(rect->bottom - rect->top); 38 | 39 | // See http://stackoverflow.com/a/12654433/2851815 and up for DPI. In short: can't be done too too well, go with best solution. 40 | bundle.ret.push_back({width, height, monitor_dpi ? monitor_dpi : desktop_dpi, monitor_bpp ? monitor_bpp : desktop_bpp, 41 | monitor_refresh_rate ? monitor_refresh_rate : desktop_refresh_rate}); 42 | 43 | return TRUE; 44 | } 45 | 46 | std::vector iware::system::displays() { 47 | struct bundle bundle = {GetDC(nullptr), {}}; 48 | iware::detail::quickscope_wrapper desktop_dc_deleter{[&]() { ReleaseDC(nullptr, bundle.desktop_dc); }}; 49 | 50 | EnumDisplayMonitors(bundle.desktop_dc, nullptr, &consume_one_display, reinterpret_cast(&bundle)); 51 | 52 | return std::move(bundle.ret); 53 | } 54 | 55 | std::vector> iware::system::available_display_configurations() { 56 | std::vector> ret; 57 | 58 | DISPLAY_DEVICE dev; 59 | dev.cb = sizeof(dev); 60 | 61 | for(DWORD dev_i = 0; EnumDisplayDevices(nullptr, dev_i, &dev, EDD_GET_DEVICE_INTERFACE_NAME); ++dev_i) { 62 | std::vector configs; 63 | const auto add_config = [&](auto&& mode) { 64 | configs.emplace_back(iware::system::display_config_t{mode.dmPelsWidth, mode.dmPelsHeight, {static_cast(mode.dmDisplayFrequency)}}); 65 | }; 66 | 67 | DEVMODE mode{}; 68 | for(DWORD mode_i = 0; EnumDisplaySettings(dev.DeviceName, mode_i, &mode); ++mode_i) 69 | if(configs.empty()) 70 | add_config(mode); 71 | else { 72 | auto&& last = configs.back(); 73 | if(last.width == mode.dmPelsWidth && last.height == mode.dmPelsHeight) { 74 | if(std::find(last.refresh_rates.begin(), last.refresh_rates.end(), mode.dmDisplayFrequency) == last.refresh_rates.end()) 75 | last.refresh_rates.emplace_back(mode.dmDisplayFrequency); 76 | } else 77 | add_config(mode); 78 | } 79 | 80 | if(!configs.empty()) 81 | ret.emplace_back(std::move(configs)); 82 | } 83 | 84 | return ret; 85 | } 86 | 87 | 88 | #endif 89 | -------------------------------------------------------------------------------- /src/system/displays/displays_x11.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: CC0-1.0 2 | // infoware - C++ System information Library 3 | 4 | 5 | #ifndef _WIN32 6 | #ifndef __APPLE__ 7 | #ifdef INFOWARE_USE_X11 8 | 9 | 10 | #include "infoware/detail/scope.hpp" 11 | #include "infoware/system.hpp" 12 | #include 13 | #include 14 | #include 15 | 16 | 17 | template 18 | static std::vector enumerate_screens(F&& cbk) { 19 | const auto display_name = std::getenv("DISPLAY"); 20 | if(!display_name) 21 | return {}; 22 | 23 | auto display = XOpenDisplay(display_name); 24 | if(!display) 25 | return {}; 26 | iware::detail::quickscope_wrapper display_deleter{[&]() { XCloseDisplay(display); }}; 27 | 28 | const auto screen_count = ScreenCount(display); 29 | std::vector ret; 30 | ret.reserve(screen_count); 31 | 32 | for(auto i = 0; i < screen_count; ++i) { 33 | const auto root = RootWindow(display, i); 34 | auto config = XRRGetScreenInfo(display, root); 35 | if(!config) 36 | continue; 37 | iware::detail::quickscope_wrapper config_deleter{[&]() { XRRFreeScreenConfigInfo(config); }}; 38 | 39 | ret.emplace_back(std::move(cbk(display, i, config))); 40 | } 41 | 42 | return ret; 43 | } 44 | 45 | 46 | std::vector iware::system::displays() { 47 | return enumerate_screens([](auto display, auto screen_number, auto screen_config) { 48 | const std::uint32_t width = DisplayWidth(display, screen_number); 49 | return iware::system::display_t{ 50 | width, 51 | static_cast(DisplayHeight(display, screen_number)), 52 | // 25.4 millimeters per inch 53 | static_cast(width / (DisplayWidthMM(display, screen_number) / 25.4)), 54 | static_cast(DefaultDepth(display, screen_number)), 55 | static_cast(XRRConfigCurrentRate(screen_config)), 56 | }; 57 | }); 58 | } 59 | 60 | std::vector> iware::system::available_display_configurations() { 61 | return enumerate_screens>([](auto, auto, auto screen_config) { 62 | int size_count; 63 | const auto sizes = XRRConfigSizes(screen_config, &size_count); 64 | 65 | std::vector configs; 66 | configs.reserve(size_count); 67 | 68 | for(auto i = 0; i < size_count; i++) { 69 | int rate_count; 70 | const auto rates = XRRConfigRates(screen_config, i, &rate_count); 71 | 72 | configs.emplace_back(iware::system::display_config_t{ 73 | static_cast(sizes[i].width), static_cast(sizes[i].height), {rates, rates + rate_count}}); 74 | } 75 | 76 | return configs; 77 | }); 78 | } 79 | 80 | 81 | #endif 82 | #endif 83 | #endif 84 | -------------------------------------------------------------------------------- /src/system/kernel_info/kernel_info_non_windows.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: CC0-1.0 2 | // infoware - C++ System information Library 3 | 4 | 5 | #ifndef _WIN32 6 | 7 | 8 | #include "infoware/system.hpp" 9 | #include 10 | #include 11 | #include 12 | 13 | 14 | iware::system::kernel_info_t iware::system::kernel_info() { 15 | utsname uts; 16 | uname(&uts); 17 | 18 | char* marker = uts.release; 19 | const std::uint32_t major = std::strtoul(marker, &marker, 10); 20 | const std::uint32_t minor = std::strtoul(marker + 1, &marker, 10); 21 | const std::uint32_t patch = std::strtoul(marker + 1, &marker, 10); 22 | const std::uint32_t build_number = std::strtoul(marker + 1, nullptr, 10); 23 | 24 | auto kernel = iware::system::kernel_t::unknown; 25 | if(!std::strcmp(uts.sysname, "Linux")) 26 | kernel = iware::system::kernel_t::linux; 27 | else if(!std::strcmp(uts.sysname, "Darwin")) 28 | kernel = iware::system::kernel_t::darwin; 29 | 30 | return {kernel, major, minor, patch, build_number}; 31 | } 32 | 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /src/system/kernel_info/kernel_info_windows.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: CC0-1.0 2 | // infoware - C++ System information Library 3 | 4 | 5 | #ifdef _WIN32 6 | 7 | 8 | #include "infoware/detail/scope.hpp" 9 | #include "infoware/system.hpp" 10 | #include 11 | #include 12 | #define WIN32_LEAN_AND_MEAN 13 | #include 14 | 15 | 16 | // Get OS (platform) version from kernel32.dll because GetVersion is deprecated in Win8+ 17 | // https://msdn.microsoft.com/en-us/library/windows/desktop/ms724439(v=vs.85).aspx 18 | iware::system::kernel_info_t iware::system::kernel_info() { 19 | std::string path; 20 | path.resize(GetSystemDirectoryA(nullptr, 0) - 1); 21 | GetSystemDirectoryA(&path[0], static_cast(path.size() + 1)); 22 | path += "\\kernel32.dll"; 23 | 24 | const auto ver_info_len = GetFileVersionInfoSizeA(path.c_str(), nullptr); 25 | auto ver_info = std::make_unique(ver_info_len); 26 | GetFileVersionInfoA(path.c_str(), 0, ver_info_len, ver_info.get()); 27 | 28 | VS_FIXEDFILEINFO* file_version; 29 | unsigned int file_version_len; 30 | VerQueryValueA(ver_info.get(), "", reinterpret_cast(&file_version), &file_version_len); 31 | 32 | return {iware::system::kernel_t::windows_nt, HIWORD(file_version->dwProductVersionMS), LOWORD(file_version->dwProductVersionMS), 33 | HIWORD(file_version->dwProductVersionLS), LOWORD(file_version->dwProductVersionLS)}; 34 | } 35 | 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /src/system/memory/memory_darwin.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: CC0-1.0 2 | // infoware - C++ System information Library 3 | 4 | 5 | #ifdef __APPLE__ 6 | 7 | 8 | #include "infoware/detail/sysctl.hpp" 9 | #include "infoware/system.hpp" 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | 18 | /// Adapted from https://stackoverflow.com/q/14789672/2851815 19 | iware::system::memory_t iware::system::memory() noexcept { 20 | iware::system::memory_t ret{}; 21 | 22 | const auto host = mach_host_self(); 23 | 24 | const auto ctl_ram = iware::detail::sysctl(CTL_HW, HW_MEMSIZE); 25 | if(!ctl_ram.empty()) { 26 | const auto ram = iware::detail::deconstruct_sysctl_int(ctl_ram); 27 | if(ram.first) 28 | ret.virtual_total = ram.second; 29 | } 30 | 31 | vm_statistics64 stats; 32 | natural_t count = HOST_VM_INFO64_COUNT; 33 | if(host_statistics64(host, HOST_VM_INFO64, reinterpret_cast(&stats), &count) == KERN_SUCCESS) 34 | ret.virtual_available = stats.free_count * getpagesize(); 35 | 36 | ret.physical_total = ret.virtual_total; 37 | ret.physical_available = ret.virtual_available; 38 | 39 | return ret; 40 | } 41 | 42 | 43 | #endif 44 | -------------------------------------------------------------------------------- /src/system/memory/memory_non_windows_non_darwin.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: CC0-1.0 2 | // infoware - C++ System information Library 3 | 4 | 5 | #ifndef _WIN32 6 | #ifndef __APPLE__ 7 | 8 | 9 | #include "infoware/system.hpp" 10 | #include 11 | #include 12 | 13 | 14 | iware::system::memory_t iware::system::memory() noexcept { 15 | std::ifstream meminfo("/proc/meminfo"); 16 | 17 | if(!meminfo.is_open() || !meminfo) 18 | return {}; 19 | 20 | iware::system::memory_t ret; 21 | for(std::string line; std::getline(meminfo, line);) { 22 | const auto colon_id = line.find_first_of(':'); 23 | const auto value = std::strtoul(line.c_str() + colon_id + 1, nullptr, 10) * 1024; 24 | 25 | if(line.find("MemTotal") == 0) 26 | ret.physical_total = value; 27 | else if(line.find("MemAvailable") == 0) 28 | ret.physical_available = value; 29 | else if(line.find("VmallocTotal") == 0) 30 | ret.virtual_total = value; 31 | else if(line.find("VmallocUsed") == 0) 32 | ret.virtual_available = ret.virtual_total - value; 33 | } 34 | 35 | return ret; 36 | } 37 | 38 | 39 | #endif 40 | #endif 41 | -------------------------------------------------------------------------------- /src/system/memory/memory_windows.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: CC0-1.0 2 | // infoware - C++ System information Library 3 | 4 | 5 | #ifdef _WIN32 6 | 7 | 8 | #include "infoware/system.hpp" 9 | #define WIN32_LEAN_AND_MEAN 10 | #include 11 | 12 | 13 | iware::system::memory_t iware::system::memory() noexcept { 14 | MEMORYSTATUSEX mem; 15 | mem.dwLength = sizeof(mem); 16 | if(!GlobalMemoryStatusEx(&mem)) 17 | return {}; 18 | 19 | return {mem.ullAvailPhys, mem.ullTotalPhys, mem.ullAvailVirtual, mem.ullTotalVirtual}; 20 | } 21 | 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /src/system/process/process_stats_non_windows.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: CC0-1.0 2 | // infoware - C++ System information Library 3 | 4 | 5 | #ifndef _WIN32 6 | 7 | 8 | #include "infoware/system.hpp" 9 | #include 10 | 11 | 12 | iware::system::process_stats_t iware::system::process_stats() { 13 | struct rusage usage; 14 | getrusage(RUSAGE_SELF, &usage); 15 | return { 16 | {usage.ru_utime.tv_sec, usage.ru_utime.tv_usec * 1000}, // 17 | {usage.ru_stime.tv_sec, usage.ru_stime.tv_usec * 1000}, // 18 | 19 | static_cast(usage.ru_minflt + usage.ru_majflt), // 20 | static_cast(usage.ru_maxrss * 1024), // 21 | 22 | static_cast(usage.ru_inblock), // 23 | static_cast(usage.ru_oublock), // 24 | }; 25 | } 26 | 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /src/system/process/process_stats_windows.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: CC0-1.0 2 | // infoware - C++ System information Library 3 | 4 | 5 | #ifdef _WIN32 6 | 7 | 8 | #include "infoware/system.hpp" 9 | #define WIN32_LEAN_AND_MEAN 10 | #include 11 | 12 | #include 13 | 14 | 15 | static timespec FILETIME_to_timespec(const FILETIME& ft) { 16 | auto ns = 100 * (static_cast(ft.dwHighDateTime) << 32) | static_cast(ft.dwLowDateTime); 17 | return {static_cast(ns / 1000'000'000), static_cast(ns % 1000'000'000)}; 18 | } 19 | iware::system::process_stats_t iware::system::process_stats() { 20 | auto process = GetCurrentProcess(); 21 | 22 | FILETIME user_time{}, kernel_time{}, _{}; 23 | GetProcessTimes(process, &_, &_, &kernel_time, &user_time); 24 | 25 | PROCESS_MEMORY_COUNTERS_EX counters{}; 26 | counters.cb = sizeof(counters); 27 | GetProcessMemoryInfo(process, reinterpret_cast(&counters), sizeof(counters)); 28 | 29 | IO_COUNTERS io{}; 30 | GetProcessIoCounters(process, &io); 31 | 32 | return { 33 | FILETIME_to_timespec(user_time), // 34 | FILETIME_to_timespec(kernel_time), // 35 | 36 | counters.PageFaultCount, // 37 | counters.PeakWorkingSetSize, // 38 | 39 | io.ReadOperationCount, // 40 | io.WriteOperationCount, // 41 | }; 42 | } 43 | 44 | #endif 45 | -------------------------------------------------------------------------------- /src/version.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: CC0-1.0 2 | // infoware - C++ System information Library 3 | 4 | 5 | #include "infoware/version.hpp" 6 | 7 | 8 | const char* const iware::version = INFOWARE_VERSION; 9 | -------------------------------------------------------------------------------- /tools/pci_generator.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: CC0-1.0 2 | // infoware - C++ System information Library 3 | 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | 15 | struct vendor_t { 16 | std::uint64_t pci_id; 17 | std::size_t name_index; 18 | std::vector devices; 19 | }; 20 | 21 | struct device_t { 22 | std::uint64_t pci_id; 23 | std::size_t name_index; 24 | }; 25 | 26 | 27 | int main(int argc, const char** argv) { 28 | if(argc < 2) { 29 | std::cerr << "In file missing\n"; 30 | return 1; 31 | } 32 | 33 | std::ifstream in(argv[1]); 34 | if(!in) { 35 | std::cerr << "Couldn't open input file\n"; 36 | return 2; 37 | } 38 | 39 | 40 | std::vector vendor_id_indices; 41 | std::vector device_id_indices; 42 | std::vector vendor_device_names; 43 | 44 | 45 | for(std::string line; std::getline(in, line);) { 46 | if(line.empty()) 47 | continue; 48 | if(line[0] == 'C') // Got to device classes. which we don't want 49 | break; 50 | 51 | const auto tabcount = line.find_first_not_of('\t'); 52 | if(!std::isxdigit(line[tabcount]) || tabcount >= 3) 53 | continue; 54 | 55 | if(*line.rbegin() == '\r') // Remove carriage return if present for CRLF encoded files. 56 | line.erase(line.length() - 1); 57 | 58 | char* current_name{}; 59 | auto current_number = std::strtoull(line.c_str() + tabcount, ¤t_name, 16); 60 | while(std::isspace(*current_name)) 61 | ++current_name; 62 | 63 | if(tabcount == 0) // Vendor 64 | vendor_id_indices.push_back({current_number, vendor_device_names.size(), {}}); 65 | else if(tabcount == 1) { // Device 66 | vendor_id_indices.back().devices.push_back(device_id_indices.size()); 67 | device_id_indices.push_back({current_number, vendor_device_names.size()}); 68 | } 69 | 70 | vendor_device_names.emplace_back(current_name); 71 | } 72 | 73 | 74 | std::sort(std::end(vendor_id_indices), std::end(vendor_id_indices), [](auto&& a, auto&& b) { return a.pci_id < b.pci_id; }); 75 | 76 | 77 | auto& out = std::cout; 78 | out << std::hex << std::showbase; 79 | 80 | out << "#define INFOWARE_GENERATED_PCI_INDICES"; 81 | std::size_t idx = 0; 82 | for(auto&& index : vendor_id_indices) { 83 | out << " \\\n\t{" << index.pci_id << ", " << idx << "},"; 84 | ++idx; 85 | } 86 | 87 | out << "\n\n\n" 88 | "#define INFOWARE_GENERATED_PCI_VENDORS"; 89 | for(auto&& vendor : vendor_id_indices) { 90 | out << " \\\n\t{" << vendor.pci_id << ", R\"(" << vendor_device_names[vendor.name_index] << ")\", {"; 91 | for(auto i : vendor.devices) 92 | out << i << ", "; 93 | out << "}},"; 94 | } 95 | 96 | out << "\n\n\n" 97 | "#define INFOWARE_GENERATED_PCI_DEVICES"; 98 | for(auto&& device : device_id_indices) 99 | out << " \\\n\t{" << device.pci_id << ", R\"(" << vendor_device_names[device.name_index] << ")\"},"; 100 | 101 | out << "\n\n\n" 102 | "namespace {}\n"; // Suppress bogus "warning: backslash-newline at end of file" on GCC 103 | } 104 | --------------------------------------------------------------------------------