├── .clang-format ├── .dockerignore ├── .github └── workflows │ └── compile.yml ├── .gitignore ├── AppImage ├── README.md └── make_appimage.sh ├── CMakeLists.txt ├── COPYING ├── Dockerfile ├── LICENSE ├── README.markdown ├── cmake ├── cmake_uninstall.cmake.in ├── compile-flags-helpers.cmake ├── modules │ ├── FindASan.cmake │ ├── FindCurses.cmake │ ├── FindLibdrm.cmake │ ├── FindMSan.cmake │ ├── FindSanitizers.cmake │ ├── FindSystemd.cmake │ ├── FindTSan.cmake │ ├── FindUBSan.cmake │ ├── FindUDev.cmake │ ├── asan-wrapper │ └── sanitize-helpers.cmake └── optimization_flags.cmake ├── desktop ├── nvtop.desktop ├── nvtop.metainfo.xml.in └── nvtop.svg ├── include ├── ascend │ └── dcmi_interface_api.h ├── ini.h ├── libdrm │ └── xe_drm.h ├── list.h ├── nvtop │ ├── common.h │ ├── device_discovery.h │ ├── extract_gpuinfo.h │ ├── extract_gpuinfo_common.h │ ├── extract_processinfo_fdinfo.h │ ├── get_process_info.h │ ├── info_messages.h │ ├── interface.h │ ├── interface_common.h │ ├── interface_internal_common.h │ ├── interface_layout_selection.h │ ├── interface_options.h │ ├── interface_ring_buffer.h │ ├── interface_setup_win.h │ ├── plot.h │ ├── time.h │ └── version.h.in └── uthash.h ├── manpage └── nvtop.in ├── screenshot ├── NVTOP_ex1.png └── Nvtop-config.png ├── snap └── snapcraft.yaml ├── src ├── CMakeLists.txt ├── amdgpu_ids.h ├── device_discovery_linux.c ├── extract_gpuinfo.c ├── extract_gpuinfo_amdgpu.c ├── extract_gpuinfo_amdgpu_utils.c ├── extract_gpuinfo_apple.m ├── extract_gpuinfo_ascend.c ├── extract_gpuinfo_intel.c ├── extract_gpuinfo_intel.h ├── extract_gpuinfo_intel_i915.c ├── extract_gpuinfo_intel_xe.c ├── extract_gpuinfo_mali_common.c ├── extract_gpuinfo_msm.c ├── extract_gpuinfo_msm_utils.c ├── extract_gpuinfo_nvidia.c ├── extract_gpuinfo_panfrost.c ├── extract_gpuinfo_panfrost_utils.c ├── extract_gpuinfo_panthor.c ├── extract_gpuinfo_panthor_utils.c ├── extract_gpuinfo_tpu.c ├── extract_gpuinfo_v3d.c ├── extract_gpuinfo_v3d_utils.c ├── extract_processinfo_fdinfo.c ├── extract_processinfo_mac.c ├── get_process_info_linux.c ├── get_process_info_mac.c ├── info_messages_linux.c ├── info_messages_mac.c ├── ini.c ├── interface.c ├── interface_layout_selection.c ├── interface_options.c ├── interface_ring_buffer.c ├── interface_setup_win.c ├── mali_common.h ├── nvtop.c ├── panfrost_drm.h ├── panfrost_utils.h ├── panthor_drm.h ├── panthor_utils.h ├── plot.c └── time.c └── tests ├── CMakeLists.txt └── interfaceTests.cpp /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | Language: Cpp 3 | # BasedOnStyle: LLVM 4 | AccessModifierOffset: -2 5 | AlignAfterOpenBracket: Align 6 | AlignArrayOfStructures: None 7 | AlignConsecutiveMacros: None 8 | AlignConsecutiveAssignments: None 9 | AlignConsecutiveBitFields: None 10 | AlignConsecutiveDeclarations: None 11 | AlignEscapedNewlines: Right 12 | AlignOperands: Align 13 | AlignTrailingComments: true 14 | AllowAllArgumentsOnNextLine: true 15 | AllowAllConstructorInitializersOnNextLine: true 16 | AllowAllParametersOfDeclarationOnNextLine: true 17 | AllowShortEnumsOnASingleLine: true 18 | AllowShortBlocksOnASingleLine: Never 19 | AllowShortCaseLabelsOnASingleLine: false 20 | AllowShortFunctionsOnASingleLine: All 21 | AllowShortLambdasOnASingleLine: All 22 | AllowShortIfStatementsOnASingleLine: Never 23 | AllowShortLoopsOnASingleLine: false 24 | AlwaysBreakAfterDefinitionReturnType: None 25 | AlwaysBreakAfterReturnType: None 26 | AlwaysBreakBeforeMultilineStrings: false 27 | AlwaysBreakTemplateDeclarations: MultiLine 28 | AttributeMacros: 29 | - __capability 30 | BinPackArguments: true 31 | BinPackParameters: true 32 | BraceWrapping: 33 | AfterCaseLabel: false 34 | AfterClass: false 35 | AfterControlStatement: Never 36 | AfterEnum: false 37 | AfterFunction: false 38 | AfterNamespace: false 39 | AfterObjCDeclaration: false 40 | AfterStruct: false 41 | AfterUnion: false 42 | AfterExternBlock: false 43 | BeforeCatch: false 44 | BeforeElse: false 45 | BeforeLambdaBody: false 46 | BeforeWhile: false 47 | IndentBraces: false 48 | SplitEmptyFunction: true 49 | SplitEmptyRecord: true 50 | SplitEmptyNamespace: true 51 | BreakBeforeBinaryOperators: None 52 | BreakBeforeConceptDeclarations: true 53 | BreakBeforeBraces: Attach 54 | BreakBeforeInheritanceComma: false 55 | BreakInheritanceList: BeforeColon 56 | BreakBeforeTernaryOperators: true 57 | BreakConstructorInitializersBeforeComma: false 58 | BreakConstructorInitializers: BeforeColon 59 | BreakAfterJavaFieldAnnotations: false 60 | BreakStringLiterals: true 61 | ColumnLimit: 120 62 | CommentPragmas: '^ IWYU pragma:' 63 | CompactNamespaces: false 64 | ConstructorInitializerAllOnOneLineOrOnePerLine: false 65 | ConstructorInitializerIndentWidth: 4 66 | ContinuationIndentWidth: 4 67 | Cpp11BracedListStyle: true 68 | DeriveLineEnding: true 69 | DerivePointerAlignment: false 70 | DisableFormat: false 71 | EmptyLineAfterAccessModifier: Never 72 | EmptyLineBeforeAccessModifier: LogicalBlock 73 | ExperimentalAutoDetectBinPacking: false 74 | FixNamespaceComments: true 75 | ForEachMacros: 76 | - foreach 77 | - Q_FOREACH 78 | - BOOST_FOREACH 79 | IfMacros: 80 | - KJ_IF_MAYBE 81 | IncludeBlocks: Preserve 82 | IncludeCategories: 83 | - Regex: '^"(llvm|llvm-c|clang|clang-c)/' 84 | Priority: 2 85 | SortPriority: 0 86 | CaseSensitive: false 87 | - Regex: '^(<|"(gtest|gmock|isl|json)/)' 88 | Priority: 3 89 | SortPriority: 0 90 | CaseSensitive: false 91 | - Regex: '.*' 92 | Priority: 1 93 | SortPriority: 0 94 | CaseSensitive: false 95 | IncludeIsMainRegex: '(Test)?$' 96 | IncludeIsMainSourceRegex: '' 97 | IndentAccessModifiers: false 98 | IndentCaseLabels: false 99 | IndentCaseBlocks: false 100 | IndentGotoLabels: true 101 | IndentPPDirectives: None 102 | IndentExternBlock: AfterExternBlock 103 | IndentRequires: false 104 | IndentWidth: 2 105 | IndentWrappedFunctionNames: false 106 | InsertTrailingCommas: None 107 | JavaScriptQuotes: Leave 108 | JavaScriptWrapImports: true 109 | KeepEmptyLinesAtTheStartOfBlocks: true 110 | LambdaBodyIndentation: Signature 111 | MacroBlockBegin: '' 112 | MacroBlockEnd: '' 113 | MaxEmptyLinesToKeep: 1 114 | NamespaceIndentation: None 115 | ObjCBinPackProtocolList: Auto 116 | ObjCBlockIndentWidth: 2 117 | ObjCBreakBeforeNestedBlockParam: true 118 | ObjCSpaceAfterProperty: false 119 | ObjCSpaceBeforeProtocolList: true 120 | PenaltyBreakAssignment: 2 121 | PenaltyBreakBeforeFirstCallParameter: 19 122 | PenaltyBreakComment: 300 123 | PenaltyBreakFirstLessLess: 120 124 | PenaltyBreakString: 1000 125 | PenaltyBreakTemplateDeclaration: 10 126 | PenaltyExcessCharacter: 1000000 127 | PenaltyReturnTypeOnItsOwnLine: 60 128 | PenaltyIndentedWhitespace: 0 129 | PointerAlignment: Right 130 | PPIndentWidth: -1 131 | ReferenceAlignment: Pointer 132 | ReflowComments: true 133 | ShortNamespaceLines: 1 134 | SortIncludes: CaseSensitive 135 | SortJavaStaticImport: Before 136 | SortUsingDeclarations: true 137 | SpaceAfterCStyleCast: false 138 | SpaceAfterLogicalNot: false 139 | SpaceAfterTemplateKeyword: true 140 | SpaceBeforeAssignmentOperators: true 141 | SpaceBeforeCaseColon: false 142 | SpaceBeforeCpp11BracedList: false 143 | SpaceBeforeCtorInitializerColon: true 144 | SpaceBeforeInheritanceColon: true 145 | SpaceBeforeParens: ControlStatements 146 | SpaceAroundPointerQualifiers: Default 147 | SpaceBeforeRangeBasedForLoopColon: true 148 | SpaceInEmptyBlock: false 149 | SpaceInEmptyParentheses: false 150 | SpacesBeforeTrailingComments: 1 151 | SpacesInAngles: Never 152 | SpacesInConditionalStatement: false 153 | SpacesInContainerLiterals: true 154 | SpacesInCStyleCastParentheses: false 155 | SpacesInLineCommentPrefix: 156 | Minimum: 1 157 | Maximum: -1 158 | SpacesInParentheses: false 159 | SpacesInSquareBrackets: false 160 | SpaceBeforeSquareBrackets: false 161 | BitFieldColonSpacing: Both 162 | Standard: Latest 163 | StatementAttributeLikeMacros: 164 | - Q_EMIT 165 | StatementMacros: 166 | - Q_UNUSED 167 | - QT_REQUIRE_VERSION 168 | TabWidth: 8 169 | UseCRLF: false 170 | UseTab: Never 171 | WhitespaceSensitiveMacros: 172 | - STRINGIZE 173 | - PP_STRINGIZE 174 | - BOOST_PP_STRINGIZE 175 | - NS_SWIFT_NAME 176 | - CF_SWIFT_NAME 177 | ... 178 | 179 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | .gitignore -------------------------------------------------------------------------------- /.github/workflows/compile.yml: -------------------------------------------------------------------------------- 1 | name: Compile Ubuntu 2 | 3 | on: 4 | - push 5 | - pull_request 6 | 7 | jobs: 8 | build: 9 | runs-on: ${{ matrix.os }} 10 | 11 | strategy: 12 | fail-fast: false 13 | 14 | matrix: 15 | os: [ubuntu-latest, ubuntu-24.04, ubuntu-22.04] 16 | 17 | env: 18 | BUILD_DIR: build 19 | DEBIAN_FRONTEND: noninteractive 20 | 21 | steps: 22 | - uses: actions/checkout@v4 23 | 24 | - name: Install dependencies 25 | run: sudo apt-get install -y libncurses5-dev libncursesw5-dev libdrm-dev libsystemd-dev 26 | 27 | - name: Configure CMake 28 | run: cmake -S . -B $BUILD_DIR 29 | 30 | - name: Build 31 | run: cmake --build $BUILD_DIR 32 | 33 | - name: Install 34 | run: DESTDIR="$PWD/build/install" cmake --build $BUILD_DIR --target install 35 | 36 | - name: Upload 37 | uses: actions/upload-artifact@v4 38 | with: 39 | name: nvtop ${{ matrix.os }} 40 | path: ${{ env.BUILD_DIR }}/install 41 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *ctags 3 | build/ 4 | cmake-build*/ 5 | .vscode 6 | .idea 7 | -------------------------------------------------------------------------------- /AppImage/README.md: -------------------------------------------------------------------------------- 1 | # Build the AppImage 2 | 3 | ```bash 4 | podman pull ubuntu:18.04 5 | podman run --interactive --tty --rm --volume $PWD:/nvtop ubuntu:24.04 6 | cd nvtop 7 | ./AppImage/make_appimage.sh 8 | ``` 9 | -------------------------------------------------------------------------------- /AppImage/make_appimage.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | export ARCH="$(uname -m)" 4 | export APPIMAGE_EXTRACT_AND_RUN=1 5 | APPIMAGETOOL="https://github.com/AppImage/appimagetool/releases/download/continuous/appimagetool-$ARCH.AppImage" 6 | 7 | install_deps() { 8 | apt-get update 9 | apt-get install -y gcc g++ cmake libncurses5-dev libncursesw5-dev libdrm-dev \ 10 | wget file libudev-dev ninja-build cmake file desktop-file-utils 11 | } 12 | 13 | configure_nvtop() { 14 | cmake -B build -S . -DCMAKE_BUILD_TYPE=Release \ 15 | -DUSE_LIBUDEV_OVER_LIBSYSTEMD=ON -DCMAKE_INSTALL_PREFIX=/usr 16 | } 17 | 18 | build_nvtop() { 19 | cmake --build build 20 | } 21 | 22 | install_nvtop_AppDir() { 23 | DESTDIR=$PWD/AppDir cmake --build build --target install 24 | } 25 | 26 | bundle_dependencies() { 27 | mkdir -p AppDir/usr/lib 28 | ldd AppDir/usr/bin/nvtop | awk -F"[> ]" '{print $4}' \ 29 | | xargs -I {} cp -vf {} AppDir/usr/lib 30 | cp -v /lib64/ld-linux-x86-64.so.2 AppDir 31 | } 32 | 33 | configure_appdir() { 34 | cat >> AppDir/AppRun <<- 'EOF' 35 | #!/bin/sh 36 | HERE="$(readlink -f "$(dirname "$0")")" 37 | exec "$HERE/ld-linux-x86-64.so.2" \ 38 | --library-path "$HERE/usr/lib" "$HERE"/usr/bin/nvtop "$@" 39 | EOF 40 | chmod u+x AppDir/AppRun 41 | ln -s usr/share/applications/nvtop.desktop AppDir 42 | ln -s usr/share/icons/nvtop.svg AppDir 43 | ln -s usr/share/icons/nvtop.svg AppDir/.DirIcon 44 | } 45 | 46 | get_appimagetool() { 47 | wget -q "$APPIMAGETOOL" -O ./appimagetool 48 | chmod u+x ./appimagetool 49 | } 50 | 51 | create_AppImage() { 52 | install_deps 53 | configure_nvtop 54 | build_nvtop 55 | install_nvtop_AppDir 56 | bundle_dependencies 57 | configure_appdir 58 | get_appimagetool 59 | export VERSION="$(./AppDir/AppRun --version | awk '{print $NF}')" 60 | ./appimagetool -n AppDir 61 | } 62 | 63 | create_AppImage 64 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.18) 2 | 3 | #///////////////////////////////////////////////////////////////////# 4 | # PROJECT # 5 | #///////////////////////////////////////////////////////////////////# 6 | 7 | project(nvtop VERSION 3.2.0 8 | LANGUAGES C CXX) 9 | 10 | set(default_build_type "Release") 11 | # Default build type 12 | if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) 13 | message(STATUS "Setting build type to '${default_build_type}' as none was specified.") 14 | set(CMAKE_BUILD_TYPE "${default_build_type}" CACHE 15 | STRING "Choose the type of build." FORCE) 16 | endif() 17 | set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS 18 | "Debug" "Release" "MinSizeRel" "RelWithDebInfo") 19 | set(CMAKE_EXPORT_COMPILE_COMMANDS ON) 20 | 21 | #///////////////////////////////////////////////////////////////////# 22 | # DEPENDENCIES # 23 | #///////////////////////////////////////////////////////////////////# 24 | 25 | list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules ${CMAKE_CURRENT_SOURCE_DIR}/cmake) 26 | 27 | set(CURSES_NEED_NCURSES TRUE) 28 | # Try to find ncurses with unicode support first 29 | set(CURSES_NEED_WIDE TRUE) 30 | find_package(Curses QUIET) 31 | if (NOT CURSE_FOUND) 32 | # Fallback to regular ncurses library, which may also support unicode! 33 | set(CURSES_NEED_WIDE FALSE) 34 | find_package(Curses REQUIRED) 35 | endif() 36 | 37 | add_library(ncurses INTERFACE IMPORTED) 38 | set_property(TARGET ncurses PROPERTY 39 | INTERFACE_INCLUDE_DIRECTORIES ${CURSES_INCLUDE_DIRS}) 40 | set_property(TARGET ncurses PROPERTY 41 | INTERFACE_LINK_LIBRARIES ${CURSES_LIBRARIES}) 42 | add_compile_definitions(NCURSES_ENABLE_STDBOOL_H=1) 43 | 44 | #///////////////////////////////////////////////////////////////////# 45 | # COMPILATION OPTIONS # 46 | #///////////////////////////////////////////////////////////////////# 47 | 48 | # Use full RPATH on build tree 49 | set(CMAKE_SKIP_BUILD_RPATH FALSE) 50 | # Do not build with install RPATH 51 | set(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE) 52 | # Set the RPATH when install 53 | set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) 54 | # Only set RPATH if the installation directory is not a system directory 55 | LIST(FIND 56 | CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES "${CMAKE_INSTALL_PREFIX}/lib" 57 | isSystemDir) 58 | if("${isSystemDir}" STREQUAL "-1") 59 | set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib") 60 | else() 61 | set(CMAKE_INSTALL_RPATH "") 62 | endif() 63 | 64 | if(APPLE) 65 | set(APPLE_SUPPORT_DEFAULT ON) 66 | set(NVIDIA_SUPPORT_DEFAULT OFF) 67 | set(AMDGPU_SUPPORT_DEFAULT OFF) 68 | set(INTEL_SUPPORT_DEFAULT OFF) 69 | set(MSM_SUPPORT_DEFAULT OFF) 70 | set(PANFROST_SUPPORT_DEFAULT OFF) 71 | set(PANTHOR_SUPPORT_DEFAULT OFF) 72 | set(ASCEND_SUPPORT_DEFAULT OFF) 73 | elseif(ASCEND_SUPPORT) 74 | set(APPLE_SUPPORT_DEFAULT OFF) 75 | set(NVIDIA_SUPPORT_DEFAULT OFF) 76 | set(AMDGPU_SUPPORT_DEFAULT OFF) 77 | set(INTEL_SUPPORT_DEFAULT OFF) 78 | set(MSM_SUPPORT_DEFAULT OFF) 79 | set(PANFROST_SUPPORT_DEFAULT OFF) 80 | set(PANTHOR_SUPPORT_DEFAULT OFF) 81 | set(ASCEND_SUPPORT_DEFAULT ON) 82 | else() 83 | set(APPLE_SUPPORT_DEFAULT OFF) 84 | set(NVIDIA_SUPPORT_DEFAULT ON) 85 | set(AMDGPU_SUPPORT_DEFAULT ON) 86 | set(INTEL_SUPPORT_DEFAULT ON) 87 | set(V3D_SUPPORT_DEFAULT ON) 88 | set(MSM_SUPPORT_DEFAULT ON) 89 | set(PANFROST_SUPPORT_DEFAULT ON) 90 | set(PANTHOR_SUPPORT_DEFAULT ON) 91 | set(ASCEND_SUPPORT_DEFAULT OFF) 92 | endif() 93 | 94 | # TPU support is only available on Linux 95 | if (CMAKE_SYSTEM_NAME STREQUAL "Linux") 96 | # Check for libtpuinfo.so to set the default for TPU support 97 | find_library(LIBTPUINFO 98 | NAMES libtpuinfo.so 99 | PATHS /usr/lib /usr/lib64 /usr/local/lib /usr/local/lib64 100 | HINTS ${CMAKE_INSTALL_PREFIX}/lib ${CMAKE_INSTALL_PREFIX}/lib64 lib lib64 101 | ) 102 | if (NOT LIBTPUINFO) 103 | set(TPU_SUPPORT_DEFAULT OFF) 104 | else() 105 | set(TPU_SUPPORT_DEFAULT ON) 106 | endif() 107 | else() 108 | set(TPU_SUPPORT_DEFAULT OFF) 109 | endif() 110 | 111 | option(NVIDIA_SUPPORT "Build support for NVIDIA GPUs through libnvml" ${NVIDIA_SUPPORT_DEFAULT}) 112 | option(AMDGPU_SUPPORT "Build support for AMD GPUs through amdgpu driver" ${AMDGPU_SUPPORT_DEFAULT}) 113 | option(INTEL_SUPPORT "Build support for Intel GPUs through i915 or xe driver" ${INTEL_SUPPORT_DEFAULT}) 114 | option(MSM_SUPPORT "Build support for Adreno GPUs through msm driver" ${MSM_SUPPORT_DEFAULT}) 115 | option(APPLE_SUPPORT "Build support for Apple GPUs through Metal" ${APPLE_SUPPORT_DEFAULT}) 116 | option(PANFROST_SUPPORT "Build support for Mali GPUs through panfrost driver" ${PANFROST_SUPPORT_DEFAULT}) 117 | option(PANTHOR_SUPPORT "Build support for Mali GPUs through panthor driver" ${PANTHOR_SUPPORT_DEFAULT}) 118 | option(ASCEND_SUPPORT "Build support for Ascend NPUs through Ascend DCMI" ${ASCEND_SUPPORT_DEFAULT}) 119 | option(V3D_SUPPORT "Build support for Raspberrypi through v3d" ${V3D_SUPPORT_DEFAULT}) 120 | option(TPU_SUPPORT "Build support for Google TPUs through GRPC" ${TPU_SUPPORT_DEFAULT}) 121 | 122 | add_subdirectory(src) 123 | 124 | #///////////////////////////////////////////////////////////////////# 125 | # INSTALL # 126 | #///////////////////////////////////////////////////////////////////# 127 | 128 | string(TIMESTAMP TODAY_MANPAGE "%B %Y") 129 | string(TIMESTAMP TODAY_ISO_8601 "%Y-%m-%d") 130 | configure_file( 131 | "${CMAKE_CURRENT_SOURCE_DIR}/manpage/nvtop.in" 132 | "${CMAKE_CURRENT_BINARY_DIR}/manpage/nvtop" 133 | IMMEDIATE @ONLY) 134 | configure_file( 135 | "${CMAKE_CURRENT_SOURCE_DIR}/desktop/nvtop.metainfo.xml.in" 136 | "${CMAKE_CURRENT_BINARY_DIR}/desktop/io.github.syllo.nvtop.metainfo.xml" 137 | IMMEDIATE @ONLY) 138 | install(FILES 139 | "${CMAKE_CURRENT_BINARY_DIR}/manpage/nvtop" 140 | DESTINATION share/man/man1/ 141 | PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ 142 | RENAME nvtop.1) 143 | install(FILES 144 | "${CMAKE_CURRENT_SOURCE_DIR}/desktop/nvtop.svg" 145 | DESTINATION share/icons/hicolor/scalable/apps 146 | PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ) 147 | install(FILES 148 | "${CMAKE_CURRENT_SOURCE_DIR}/desktop/nvtop.desktop" 149 | DESTINATION share/applications 150 | PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ) 151 | install(FILES 152 | "${CMAKE_CURRENT_BINARY_DIR}/desktop/io.github.syllo.nvtop.metainfo.xml" 153 | DESTINATION share/metainfo 154 | PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ) 155 | 156 | configure_file( 157 | "${CMAKE_CURRENT_SOURCE_DIR}/cmake/cmake_uninstall.cmake.in" 158 | "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" 159 | IMMEDIATE @ONLY) 160 | add_custom_target(uninstall 161 | COMMAND ${CMAKE_COMMAND} -P 162 | ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake) 163 | 164 | #///////////////////////////////////////////////////////////////////# 165 | # TESTING # 166 | #///////////////////////////////////////////////////////////////////# 167 | 168 | 169 | if (NOT CMAKE_BUILD_TYPE STREQUAL "Debug") 170 | option(BUILD_TESTING "Build tests" OFF) 171 | endif() 172 | include(CTest) 173 | add_subdirectory(tests) 174 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | 2 | # BUILD: docker build . -t nvtop 3 | # or use other image with: --build-arg IMAGE=nvcr.io/nvidia/cudagl:11.4.2-base-ubuntu20.04 4 | # or nvidia/driver:418.87.01-ubuntu18.04, nvcr.io/nvidia/cudagl:11.4.2-base-ubuntu20.04 5 | # USE: docker run --rm -it --gpus all --pid host nvtop 6 | 7 | ARG IMAGE=nvidia/opengl:1.2-glvnd-runtime-ubuntu20.04 8 | 9 | FROM ${IMAGE} as builder 10 | 11 | ENV DEBIAN_FRONTEND=noninteractive 12 | 13 | RUN apt-get update && \ 14 | apt-get install -yq build-essential wget libncurses5-dev libncursesw5-dev libssl-dev \ 15 | pkg-config libdrm-dev libgtest-dev libudev-dev python3-venv 16 | 17 | # Get a recent-enough CMake 18 | RUN python3 -m venv /.venv && \ 19 | . /.venv/bin/activate && \ 20 | pip install --upgrade pip && \ 21 | pip install cmake 22 | 23 | COPY . /nvtop 24 | WORKDIR /nvtop 25 | RUN mkdir -p /nvtop/build && \ 26 | cd /nvtop/build && \ 27 | . /.venv/bin/activate && \ 28 | cmake .. && \ 29 | make -j && \ 30 | make install 31 | 32 | # Stage 2 33 | FROM ${IMAGE} 34 | RUN DEBIAN_FRONTEND=noninteractive apt-get update -y && apt-get install -yq libncurses5 libncursesw5 libdrm-amdgpu1 \ 35 | && rm -rf /var/lib/apt/lists/* 36 | COPY --from=builder /usr/local/bin/nvtop /usr/local/bin/nvtop 37 | COPY --from=builder /usr/local/share/man/man1/nvtop.1 /usr/local/share/man/man1/nvtop.1 38 | 39 | ENV LANG=C.UTF-8 40 | 41 | ENTRYPOINT [ "/usr/local/bin/nvtop" ] 42 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | COPYING -------------------------------------------------------------------------------- /cmake/cmake_uninstall.cmake.in: -------------------------------------------------------------------------------- 1 | if(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") 2 | message(FATAL_ERROR 3 | "Cannot find install manifest: @CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") 4 | endif(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") 5 | 6 | file(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files) 7 | string(REGEX REPLACE "\n" ";" files "${files}") 8 | foreach(file ${files}) 9 | message(STATUS "Uninstalling $ENV{DESTDIR}${file}") 10 | if(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") 11 | exec_program( "@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\"" 12 | OUTPUT_VARIABLE rm_out RETURN_VALUE rm_retval) 13 | if(NOT "${rm_retval}" STREQUAL 0) 14 | message(FATAL_ERROR "Problem when removing $ENV{DESTDIR}${file}") 15 | endif(NOT "${rm_retval}" STREQUAL 0) 16 | else(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") 17 | message(STATUS 18 | "File 19 | $ENV{DESTDIR}${file} 20 | does not 21 | exist.") 22 | endif(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") 23 | endforeach(file) 24 | -------------------------------------------------------------------------------- /cmake/compile-flags-helpers.cmake: -------------------------------------------------------------------------------- 1 | include(CheckLinkerFlag) 2 | 3 | function(add_compiler_option_to_target_type TARGET BUILDTYPE VISIBILITY OPTIONS) 4 | include(CheckCCompilerFlag) 5 | list(APPEND OPTIONS ${ARGN}) 6 | foreach(COMPILE_OPTION IN LISTS OPTIONS) 7 | string(REPLACE "=" "-" COMPILE_OPTION_NAME "${COMPILE_OPTION}") 8 | check_c_compiler_flag(${COMPILE_OPTION} "compiler_has${COMPILE_OPTION_NAME}") 9 | if (${compiler_has${COMPILE_OPTION_NAME}}) 10 | target_compile_options(${TARGET} ${VISIBILITY} 11 | $<$:${COMPILE_OPTION}>) 12 | endif() 13 | endforeach() 14 | endfunction() 15 | 16 | function(add_compiler_option_to_all_but_target_type TARGET BUILDTYPE VISIBILITY OPTIONS) 17 | include(CheckCCompilerFlag) 18 | list(APPEND OPTIONS ${ARGN}) 19 | foreach(COMPILE_OPTION IN LISTS OPTIONS) 20 | string(REPLACE "=" "-" COMPILE_OPTION_NAME "${COMPILE_OPTION}") 21 | check_c_compiler_flag(${COMPILE_OPTION} "compiler_has${COMPILE_OPTION_NAME}") 22 | if (${compiler_has${COMPILE_OPTION_NAME}}) 23 | target_compile_options(${TARGET} ${VISIBILITY} 24 | $<$>:${COMPILE_OPTION}>) 25 | endif() 26 | endforeach() 27 | endfunction() 28 | 29 | function(add_linker_option_to_target_type TARGET BUILDTYPE VISIBILITY OPTIONS) 30 | include(CheckCCompilerFlag) 31 | list(APPEND OPTIONS ${ARGN}) 32 | foreach(LINK_OPTION IN LISTS OPTIONS) 33 | string(REPLACE "," "_" LINK_OPTION_NAME "${LINK_OPTION}") 34 | check_linker_flag(C "${LINK_OPTION}" "linker_has${LINK_OPTION_NAME}") 35 | if (${linker_has${LINK_OPTION_NAME}}) 36 | target_link_libraries(${TARGET} ${VISIBILITY} 37 | $<$:${LINK_OPTION}>) 38 | endif() 39 | endforeach() 40 | endfunction() 41 | 42 | function(add_linker_option_to_all_but_target_type TARGET BUILDTYPE VISIBILITY OPTIONS) 43 | include(CheckCCompilerFlag) 44 | list(APPEND OPTIONS ${ARGN}) 45 | foreach(LINK_OPTION IN LISTS OPTIONS) 46 | string(REPLACE "," "_" LINK_OPTION_NAME "${LINK_OPTION}") 47 | check_linker_flag(C "${LINK_OPTION}" "linker_has${LINK_OPTION_NAME}") 48 | if (${linker_has${LINK_OPTION_NAME}}) 49 | target_link_libraries(${TARGET} ${VISIBILITY} 50 | $<$>:${LINK_OPTION}>) 51 | endif() 52 | endforeach() 53 | endfunction() 54 | 55 | function(add_sanitizers_to_target TARGET BUILDTYPE VISIBILITY SANITIZERS) 56 | list(APPEND SANITIZERS ${ARGN}) 57 | foreach(SAN IN LISTS SANITIZERS) 58 | set(CMAKE_REQUIRED_FLAGS "-fsanitize=${SAN}") 59 | check_c_compiler_flag("-fsanitize=${SAN}" "sanitizer-${SAN}-available") 60 | unset(CMAKE_REQUIRED_FLAGS) 61 | if (${sanitizer-${SAN}-available}) 62 | list(APPEND AVAILABLE_SANITIZERS ${SAN}) 63 | endif() 64 | endforeach() 65 | foreach(SAN IN LISTS AVAILABLE_SANITIZERS) 66 | target_compile_options(${TARGET} ${VISIBILITY} $<$:-fsanitize=${SAN}>) 67 | target_link_libraries(${TARGET} ${VISIBILITY} $<$:-fsanitize=${SAN}>) 68 | endforeach() 69 | endfunction() 70 | -------------------------------------------------------------------------------- /cmake/modules/FindASan.cmake: -------------------------------------------------------------------------------- 1 | # The MIT License (MIT) 2 | # 3 | # Copyright (c) 4 | # 2013 Matthew Arsenault 5 | # 2015-2016 RWTH Aachen University, Federal Republic of Germany 6 | # 7 | # Permission is hereby granted, free of charge, to any person obtaining a copy 8 | # of this software and associated documentation files (the "Software"), to deal 9 | # in the Software without restriction, including without limitation the rights 10 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | # copies of the Software, and to permit persons to whom the Software is 12 | # furnished to do so, subject to the following conditions: 13 | # 14 | # The above copyright notice and this permission notice shall be included in all 15 | # copies or substantial portions of the Software. 16 | # 17 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | # SOFTWARE. 24 | 25 | option(SANITIZE_ADDRESS "Enable AddressSanitizer for sanitized targets." Off) 26 | 27 | set(FLAG_CANDIDATES 28 | # Clang 3.2+ use this version. The no-omit-frame-pointer option is optional. 29 | "-g -fsanitize=address -fno-omit-frame-pointer" 30 | "-g -fsanitize=address" 31 | 32 | # Older deprecated flag for ASan 33 | "-g -faddress-sanitizer" 34 | ) 35 | 36 | 37 | if (SANITIZE_ADDRESS AND (SANITIZE_THREAD OR SANITIZE_MEMORY)) 38 | message(FATAL_ERROR "AddressSanitizer is not compatible with " 39 | "ThreadSanitizer or MemorySanitizer.") 40 | endif () 41 | 42 | 43 | include(sanitize-helpers) 44 | 45 | if (SANITIZE_ADDRESS) 46 | sanitizer_check_compiler_flags("${FLAG_CANDIDATES}" "AddressSanitizer" 47 | "ASan") 48 | 49 | find_program(ASan_WRAPPER "asan-wrapper" PATHS ${CMAKE_MODULE_PATH}) 50 | mark_as_advanced(ASan_WRAPPER) 51 | endif () 52 | 53 | function (add_sanitize_address TARGET) 54 | if (NOT SANITIZE_ADDRESS) 55 | return() 56 | endif () 57 | 58 | sanitizer_add_flags(${TARGET} "AddressSanitizer" "ASan") 59 | endfunction () 60 | -------------------------------------------------------------------------------- /cmake/modules/FindCurses.cmake: -------------------------------------------------------------------------------- 1 | # Distributed under the OSI-approved BSD 3-Clause License. See accompanying 2 | # file Copyright.txt or https://cmake.org/licensing for details. 3 | 4 | #[=======================================================================[.rst: 5 | FindCurses 6 | ---------- 7 | 8 | Find the curses or ncurses include file and library. 9 | 10 | Result Variables 11 | ^^^^^^^^^^^^^^^^ 12 | 13 | This module defines the following variables: 14 | 15 | ``CURSES_FOUND`` 16 | True if Curses is found. 17 | ``CURSES_INCLUDE_DIRS`` 18 | The include directories needed to use Curses. 19 | ``CURSES_LIBRARIES`` 20 | The libraries needed to use Curses. 21 | ``CURSES_CFLAGS`` 22 | Parameters which ought be given to C/C++ compilers when using Curses. 23 | ``CURSES_HAVE_CURSES_H`` 24 | True if curses.h is available. 25 | ``CURSES_HAVE_NCURSES_H`` 26 | True if ncurses.h is available. 27 | ``CURSES_HAVE_NCURSES_NCURSES_H`` 28 | True if ``ncurses/ncurses.h`` is available. 29 | ``CURSES_HAVE_NCURSES_CURSES_H`` 30 | True if ``ncurses/curses.h`` is available. 31 | 32 | Set ``CURSES_NEED_NCURSES`` to ``TRUE`` before the 33 | ``find_package(Curses)`` call if NCurses functionality is required. 34 | Set ``CURSES_NEED_WIDE`` to ``TRUE`` before the 35 | ``find_package(Curses)`` call if unicode functionality is required. 36 | 37 | Backward Compatibility 38 | ^^^^^^^^^^^^^^^^^^^^^^ 39 | 40 | The following variable are provided for backward compatibility: 41 | 42 | ``CURSES_INCLUDE_DIR`` 43 | Path to Curses include. Use ``CURSES_INCLUDE_DIRS`` instead. 44 | ``CURSES_LIBRARY`` 45 | Path to Curses library. Use ``CURSES_LIBRARIES`` instead. 46 | #]=======================================================================] 47 | 48 | include(CheckLibraryExists) 49 | 50 | # we don't know anything about cursesw, so only ncurses 51 | # may be ncursesw 52 | if(NOT CURSES_NEED_WIDE) 53 | set(NCURSES_LIBRARY_NAME "ncurses") 54 | else() 55 | set(NCURSES_LIBRARY_NAME "ncursesw") 56 | # Also, if we are searchig fo wide curses - we are actually searching 57 | # for ncurses, we don't know about any other unicode version. 58 | set(CURSES_NEED_NCURSES TRUE) 59 | endif() 60 | 61 | find_library(CURSES_CURSES_LIBRARY NAMES curses) 62 | 63 | find_library(CURSES_NCURSES_LIBRARY NAMES "${NCURSES_LIBRARY_NAME}" ) 64 | set(CURSES_USE_NCURSES FALSE) 65 | 66 | if(CURSES_NCURSES_LIBRARY AND ((NOT CURSES_CURSES_LIBRARY) OR CURSES_NEED_NCURSES)) 67 | set(CURSES_USE_NCURSES TRUE) 68 | endif() 69 | # http://cygwin.com/ml/cygwin-announce/2010-01/msg00002.html 70 | # cygwin ncurses stopped providing curses.h symlinks see above 71 | # message. Cygwin is an ncurses package, so force ncurses on 72 | # cygwin if the curses.h is missing 73 | if(CYGWIN) 74 | if (CURSES_NEED_WIDE) 75 | if(NOT EXISTS /usr/include/ncursesw/curses.h) 76 | set(CURSES_USE_NCURSES TRUE) 77 | endif() 78 | else() 79 | if(NOT EXISTS /usr/include/curses.h) 80 | set(CURSES_USE_NCURSES TRUE) 81 | endif() 82 | endif() 83 | endif() 84 | 85 | 86 | # Not sure the logic is correct here. 87 | # If NCurses is required, use the function wsyncup() to check if the library 88 | # has NCurses functionality (at least this is where it breaks on NetBSD). 89 | # If wsyncup is in curses, use this one. 90 | # If not, try to find ncurses and check if this has the symbol. 91 | # Once the ncurses library is found, search the ncurses.h header first, but 92 | # some web pages also say that even with ncurses there is not always a ncurses.h: 93 | # http://osdir.com/ml/gnome.apps.mc.devel/2002-06/msg00029.html 94 | # So at first try ncurses.h, if not found, try to find curses.h under the same 95 | # prefix as the library was found, if still not found, try curses.h with the 96 | # default search paths. 97 | if(CURSES_CURSES_LIBRARY AND CURSES_NEED_NCURSES) 98 | include(CMakePushCheckState) 99 | cmake_push_check_state() 100 | set(CMAKE_REQUIRED_QUIET ${Curses_FIND_QUIETLY}) 101 | CHECK_LIBRARY_EXISTS("${CURSES_CURSES_LIBRARY}" 102 | wsyncup "" CURSES_CURSES_HAS_WSYNCUP) 103 | 104 | if(CURSES_NCURSES_LIBRARY AND NOT CURSES_CURSES_HAS_WSYNCUP) 105 | CHECK_LIBRARY_EXISTS("${CURSES_NCURSES_LIBRARY}" 106 | wsyncup "" CURSES_NCURSES_HAS_WSYNCUP) 107 | if( CURSES_NCURSES_HAS_WSYNCUP) 108 | set(CURSES_USE_NCURSES TRUE) 109 | endif() 110 | endif() 111 | cmake_pop_check_state() 112 | 113 | endif() 114 | 115 | if(CURSES_USE_NCURSES) 116 | get_filename_component(_cursesLibDir "${CURSES_NCURSES_LIBRARY}" PATH) 117 | get_filename_component(_cursesParentDir "${_cursesLibDir}" PATH) 118 | 119 | # Use CURSES_NCURSES_INCLUDE_PATH if set, for compatibility. 120 | if(CURSES_NCURSES_INCLUDE_PATH) 121 | if (CURSES_NEED_WIDE) 122 | find_path(CURSES_INCLUDE_PATH 123 | NAMES ncursesw/ncurses.h ncursesw/curses.h ncursesw.h cursesw.h 124 | PATHS ${CURSES_NCURSES_INCLUDE_PATH} 125 | NO_DEFAULT_PATH 126 | ) 127 | else() 128 | find_path(CURSES_INCLUDE_PATH 129 | NAMES ncurses/ncurses.h ncurses/curses.h ncurses.h curses.h 130 | PATHS ${CURSES_NCURSES_INCLUDE_PATH} 131 | NO_DEFAULT_PATH 132 | ) 133 | endif() 134 | endif() 135 | 136 | if (CURSES_NEED_WIDE) 137 | set(CURSES_TINFO_LIBRARY_NAME tinfow) 138 | find_path(CURSES_INCLUDE_PATH 139 | NAMES ncursesw/ncurses.h ncursesw/curses.h ncursesw.h cursesw.h 140 | HINTS "${_cursesParentDir}/include" 141 | ) 142 | else() 143 | set(CURSES_TINFO_LIBRARY_NAME tinfo) 144 | find_path(CURSES_INCLUDE_PATH 145 | NAMES ncurses/ncurses.h ncurses/curses.h ncurses.h curses.h 146 | HINTS "${_cursesParentDir}/include" 147 | ) 148 | endif() 149 | 150 | # Previous versions of FindCurses provided these values. 151 | if(NOT DEFINED CURSES_LIBRARY) 152 | set(CURSES_LIBRARY "${CURSES_NCURSES_LIBRARY}") 153 | endif() 154 | 155 | CHECK_LIBRARY_EXISTS("${CURSES_NCURSES_LIBRARY}" 156 | cbreak "" CURSES_NCURSES_HAS_CBREAK) 157 | if(NOT CURSES_NCURSES_HAS_CBREAK) 158 | find_library(CURSES_EXTRA_LIBRARY "${CURSES_TINFO_LIBRARY_NAME}" HINTS "${_cursesLibDir}") 159 | find_library(CURSES_EXTRA_LIBRARY "${CURSES_TINFO_LIBRARY_NAME}" ) 160 | endif() 161 | else() 162 | get_filename_component(_cursesLibDir "${CURSES_CURSES_LIBRARY}" PATH) 163 | get_filename_component(_cursesParentDir "${_cursesLibDir}" PATH) 164 | 165 | #We can't find anything with CURSES_NEED_WIDE because we know 166 | #only about ncursesw unicode curses version 167 | if(NOT CURSES_NEED_WIDE) 168 | find_path(CURSES_INCLUDE_PATH 169 | NAMES curses.h 170 | HINTS "${_cursesParentDir}/include" 171 | ) 172 | endif() 173 | 174 | # Previous versions of FindCurses provided these values. 175 | if(NOT DEFINED CURSES_CURSES_H_PATH) 176 | set(CURSES_CURSES_H_PATH "${CURSES_INCLUDE_PATH}") 177 | endif() 178 | if(NOT DEFINED CURSES_LIBRARY) 179 | set(CURSES_LIBRARY "${CURSES_CURSES_LIBRARY}") 180 | endif() 181 | endif() 182 | 183 | # Report whether each possible header name exists in the include directory. 184 | if(NOT DEFINED CURSES_HAVE_NCURSES_NCURSES_H) 185 | if(CURSES_NEED_WIDE) 186 | if(EXISTS "${CURSES_INCLUDE_PATH}/ncursesw/ncurses.h") 187 | set(CURSES_HAVE_NCURSES_NCURSES_H "${CURSES_INCLUDE_PATH}/ncursesw/ncurses.h") 188 | endif() 189 | elseif(EXISTS "${CURSES_INCLUDE_PATH}/ncurses/ncurses.h") 190 | set(CURSES_HAVE_NCURSES_NCURSES_H "${CURSES_INCLUDE_PATH}/ncurses/ncurses.h") 191 | endif() 192 | if(NOT DEFINED CURSES_HAVE_NCURSES_NCURSES_H) 193 | set(CURSES_HAVE_NCURSES_NCURSES_H "CURSES_HAVE_NCURSES_NCURSES_H-NOTFOUND") 194 | endif() 195 | endif() 196 | if(NOT DEFINED CURSES_HAVE_NCURSES_CURSES_H) 197 | if(CURSES_NEED_WIDE) 198 | if(EXISTS "${CURSES_INCLUDE_PATH}/ncursesw/curses.h") 199 | set(CURSES_HAVE_NCURSES_CURSES_H "${CURSES_INCLUDE_PATH}/ncursesw/curses.h") 200 | endif() 201 | elseif(EXISTS "${CURSES_INCLUDE_PATH}/ncurses/curses.h") 202 | set(CURSES_HAVE_NCURSES_CURSES_H "${CURSES_INCLUDE_PATH}/ncurses/curses.h") 203 | endif() 204 | if(NOT DEFINED CURSES_HAVE_NCURSES_CURSES_H) 205 | set(CURSES_HAVE_NCURSES_CURSES_H "CURSES_HAVE_NCURSES_CURSES_H-NOTFOUND") 206 | endif() 207 | endif() 208 | if(NOT CURSES_NEED_WIDE) 209 | #ncursesw can't be found for this paths 210 | if(NOT DEFINED CURSES_HAVE_NCURSES_H) 211 | if(EXISTS "${CURSES_INCLUDE_PATH}/ncurses.h") 212 | set(CURSES_HAVE_NCURSES_H "${CURSES_INCLUDE_PATH}/ncurses.h") 213 | else() 214 | set(CURSES_HAVE_NCURSES_H "CURSES_HAVE_NCURSES_H-NOTFOUND") 215 | endif() 216 | endif() 217 | if(NOT DEFINED CURSES_HAVE_CURSES_H) 218 | if(EXISTS "${CURSES_INCLUDE_PATH}/curses.h") 219 | set(CURSES_HAVE_CURSES_H "${CURSES_INCLUDE_PATH}/curses.h") 220 | else() 221 | set(CURSES_HAVE_CURSES_H "CURSES_HAVE_CURSES_H-NOTFOUND") 222 | endif() 223 | endif() 224 | endif() 225 | 226 | find_library(CURSES_FORM_LIBRARY form HINTS "${_cursesLibDir}") 227 | find_library(CURSES_FORM_LIBRARY form ) 228 | 229 | # Previous versions of FindCurses provided these values. 230 | if(NOT DEFINED FORM_LIBRARY) 231 | set(FORM_LIBRARY "${CURSES_FORM_LIBRARY}") 232 | endif() 233 | 234 | # Need to provide the *_LIBRARIES 235 | set(CURSES_LIBRARIES ${CURSES_LIBRARY}) 236 | 237 | if(CURSES_EXTRA_LIBRARY) 238 | set(CURSES_LIBRARIES ${CURSES_LIBRARIES} ${CURSES_EXTRA_LIBRARY}) 239 | endif() 240 | 241 | if(CURSES_FORM_LIBRARY) 242 | set(CURSES_LIBRARIES ${CURSES_LIBRARIES} ${CURSES_FORM_LIBRARY}) 243 | endif() 244 | 245 | # Provide the *_INCLUDE_DIRS and *_CFLAGS results. 246 | set(CURSES_INCLUDE_DIRS ${CURSES_INCLUDE_PATH}) 247 | set(CURSES_INCLUDE_DIR ${CURSES_INCLUDE_PATH}) # compatibility 248 | 249 | find_package(PkgConfig QUIET) 250 | if(PKG_CONFIG_FOUND) 251 | pkg_check_modules(NCURSES QUIET ${NCURSES_LIBRARY_NAME}) 252 | set(CURSES_CFLAGS ${NCURSES_CFLAGS_OTHER}) 253 | endif() 254 | 255 | include(FindPackageHandleStandardArgs) 256 | FIND_PACKAGE_HANDLE_STANDARD_ARGS(Curses DEFAULT_MSG 257 | CURSES_LIBRARY CURSES_INCLUDE_PATH) 258 | 259 | mark_as_advanced( 260 | CURSES_INCLUDE_PATH 261 | CURSES_CURSES_LIBRARY 262 | CURSES_NCURSES_LIBRARY 263 | CURSES_EXTRA_LIBRARY 264 | CURSES_FORM_LIBRARY 265 | ) 266 | -------------------------------------------------------------------------------- /cmake/modules/FindLibdrm.cmake: -------------------------------------------------------------------------------- 1 | #.rst: 2 | # FindLibdrm 3 | # ------- 4 | # 5 | # Try to find libdrm on a Unix system. 6 | # 7 | # This will define the following variables: 8 | # 9 | # ``Libdrm_FOUND`` 10 | # True if (the requested version of) libdrm is available 11 | # ``Libdrm_VERSION`` 12 | # The version of libdrm 13 | # ``Libdrm_LIBRARIES`` 14 | # This can be passed to target_link_libraries() instead of the ``Libdrm::Libdrm`` 15 | # target 16 | # ``Libdrm_INCLUDE_DIRS`` 17 | # This should be passed to target_include_directories() if the target is not 18 | # used for linking 19 | # ``Libdrm_DEFINITIONS`` 20 | # This should be passed to target_compile_options() if the target is not 21 | # used for linking 22 | # 23 | # If ``Libdrm_FOUND`` is TRUE, it will also define the following imported target: 24 | # 25 | # ``Libdrm::Libdrm`` 26 | # The libdrm library 27 | # 28 | # In general we recommend using the imported target, as it is easier to use. 29 | # Bear in mind, however, that if the target is in the link interface of an 30 | # exported library, it must be made available by the package config file. 31 | 32 | #============================================================================= 33 | # SPDX-FileCopyrightText: 2014 Alex Merry 34 | # SPDX-FileCopyrightText: 2014 Martin Gräßlin 35 | # 36 | # SPDX-License-Identifier: BSD-3-Clause 37 | #============================================================================= 38 | 39 | if(CMAKE_VERSION VERSION_LESS 2.8.12) 40 | message(FATAL_ERROR "CMake 2.8.12 is required by FindLibdrm.cmake") 41 | endif() 42 | if(CMAKE_MINIMUM_REQUIRED_VERSION VERSION_LESS 2.8.12) 43 | message(AUTHOR_WARNING "Your project should require at least CMake 2.8.12 to use FindLibdrm.cmake") 44 | endif() 45 | 46 | if(NOT WIN32) 47 | # Use pkg-config to get the directories and then use these values 48 | # in the FIND_PATH() and FIND_LIBRARY() calls 49 | find_package(PkgConfig) 50 | pkg_check_modules(PKG_Libdrm QUIET libdrm) 51 | 52 | set(Libdrm_DEFINITIONS ${PKG_Libdrm_CFLAGS_OTHER}) 53 | set(Libdrm_VERSION ${PKG_Libdrm_VERSION}) 54 | 55 | find_path(Libdrm_INCLUDE_DIR 56 | NAMES 57 | xf86drm.h 58 | HINTS 59 | ${PKG_Libdrm_INCLUDE_DIRS} 60 | ) 61 | find_library(Libdrm_LIBRARY 62 | NAMES 63 | drm 64 | HINTS 65 | ${PKG_Libdrm_LIBRARY_DIRS} 66 | ) 67 | 68 | include(FindPackageHandleStandardArgs) 69 | find_package_handle_standard_args(Libdrm 70 | FOUND_VAR 71 | Libdrm_FOUND 72 | REQUIRED_VARS 73 | Libdrm_LIBRARY 74 | Libdrm_INCLUDE_DIR 75 | VERSION_VAR 76 | Libdrm_VERSION 77 | ) 78 | 79 | if(Libdrm_FOUND AND NOT TARGET Libdrm::Libdrm) 80 | add_library(Libdrm::Libdrm UNKNOWN IMPORTED) 81 | set_target_properties(Libdrm::Libdrm PROPERTIES 82 | IMPORTED_LOCATION "${Libdrm_LIBRARY}" 83 | INTERFACE_COMPILE_OPTIONS "${Libdrm_DEFINITIONS}" 84 | INTERFACE_INCLUDE_DIRECTORIES "${Libdrm_INCLUDE_DIR}" 85 | INTERFACE_INCLUDE_DIRECTORIES "${Libdrm_INCLUDE_DIR}/libdrm" 86 | ) 87 | endif() 88 | 89 | mark_as_advanced(Libdrm_LIBRARY Libdrm_INCLUDE_DIR) 90 | 91 | # compatibility variables 92 | set(Libdrm_LIBRARIES ${Libdrm_LIBRARY}) 93 | set(Libdrm_INCLUDE_DIRS ${Libdrm_INCLUDE_DIR} "${Libdrm_INCLUDE_DIR}/libdrm") 94 | set(Libdrm_VERSION_STRING ${Libdrm_VERSION}) 95 | 96 | else() 97 | message(STATUS "FindLibdrm.cmake cannot find libdrm on Windows systems.") 98 | set(Libdrm_FOUND FALSE) 99 | endif() 100 | 101 | include(FeatureSummary) 102 | set_package_properties(Libdrm PROPERTIES 103 | URL "https://wiki.freedesktop.org/dri/" 104 | DESCRIPTION "Userspace interface to kernel DRM services" 105 | ) 106 | -------------------------------------------------------------------------------- /cmake/modules/FindMSan.cmake: -------------------------------------------------------------------------------- 1 | # The MIT License (MIT) 2 | # 3 | # Copyright (c) 4 | # 2013 Matthew Arsenault 5 | # 2015-2016 RWTH Aachen University, Federal Republic of Germany 6 | # 7 | # Permission is hereby granted, free of charge, to any person obtaining a copy 8 | # of this software and associated documentation files (the "Software"), to deal 9 | # in the Software without restriction, including without limitation the rights 10 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | # copies of the Software, and to permit persons to whom the Software is 12 | # furnished to do so, subject to the following conditions: 13 | # 14 | # The above copyright notice and this permission notice shall be included in all 15 | # copies or substantial portions of the Software. 16 | # 17 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | # SOFTWARE. 24 | 25 | option(SANITIZE_MEMORY "Enable MemorySanitizer for sanitized targets." Off) 26 | 27 | set(FLAG_CANDIDATES 28 | "-g -fsanitize=memory" 29 | ) 30 | 31 | 32 | include(sanitize-helpers) 33 | 34 | if (SANITIZE_MEMORY) 35 | if (NOT ${CMAKE_SYSTEM_NAME} STREQUAL "Linux") 36 | message(WARNING "MemorySanitizer disabled for target ${TARGET} because " 37 | "MemorySanitizer is supported for Linux systems only.") 38 | set(SANITIZE_MEMORY Off CACHE BOOL 39 | "Enable MemorySanitizer for sanitized targets." FORCE) 40 | elseif (NOT ${CMAKE_SIZEOF_VOID_P} EQUAL 8) 41 | message(WARNING "MemorySanitizer disabled for target ${TARGET} because " 42 | "MemorySanitizer is supported for 64bit systems only.") 43 | set(SANITIZE_MEMORY Off CACHE BOOL 44 | "Enable MemorySanitizer for sanitized targets." FORCE) 45 | else () 46 | sanitizer_check_compiler_flags("${FLAG_CANDIDATES}" "MemorySanitizer" 47 | "MSan") 48 | endif () 49 | endif () 50 | 51 | function (add_sanitize_memory TARGET) 52 | if (NOT SANITIZE_MEMORY) 53 | return() 54 | endif () 55 | 56 | sanitizer_add_flags(${TARGET} "MemorySanitizer" "MSan") 57 | endfunction () 58 | -------------------------------------------------------------------------------- /cmake/modules/FindSanitizers.cmake: -------------------------------------------------------------------------------- 1 | # The MIT License (MIT) 2 | # 3 | # Copyright (c) 4 | # 2013 Matthew Arsenault 5 | # 2015-2016 RWTH Aachen University, Federal Republic of Germany 6 | # 7 | # Permission is hereby granted, free of charge, to any person obtaining a copy 8 | # of this software and associated documentation files (the "Software"), to deal 9 | # in the Software without restriction, including without limitation the rights 10 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | # copies of the Software, and to permit persons to whom the Software is 12 | # furnished to do so, subject to the following conditions: 13 | # 14 | # The above copyright notice and this permission notice shall be included in all 15 | # copies or substantial portions of the Software. 16 | # 17 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | # SOFTWARE. 24 | 25 | # If any of the used compiler is a GNU compiler, add a second option to static 26 | # link against the sanitizers. 27 | option(SANITIZE_LINK_STATIC "Try to link static against sanitizers." Off) 28 | 29 | 30 | 31 | 32 | set(FIND_QUIETLY_FLAG "") 33 | if (DEFINED Sanitizers_FIND_QUIETLY) 34 | set(FIND_QUIETLY_FLAG "QUIET") 35 | endif () 36 | 37 | find_package(ASan ${FIND_QUIETLY_FLAG}) 38 | find_package(TSan ${FIND_QUIETLY_FLAG}) 39 | find_package(MSan ${FIND_QUIETLY_FLAG}) 40 | find_package(UBSan ${FIND_QUIETLY_FLAG}) 41 | 42 | 43 | 44 | 45 | function(sanitizer_add_blacklist_file FILE) 46 | if(NOT IS_ABSOLUTE ${FILE}) 47 | set(FILE "${CMAKE_CURRENT_SOURCE_DIR}/${FILE}") 48 | endif() 49 | get_filename_component(FILE "${FILE}" REALPATH) 50 | 51 | sanitizer_check_compiler_flags("-fsanitize-blacklist=${FILE}" 52 | "SanitizerBlacklist" "SanBlist") 53 | endfunction() 54 | 55 | function(add_sanitizers ...) 56 | # If no sanitizer is enabled, return immediately. 57 | if (NOT (SANITIZE_ADDRESS OR SANITIZE_MEMORY OR SANITIZE_THREAD OR 58 | SANITIZE_UNDEFINED)) 59 | return() 60 | endif () 61 | 62 | foreach (TARGET ${ARGV}) 63 | # Check if this target will be compiled by exactly one compiler. Other- 64 | # wise sanitizers can't be used and a warning should be printed once. 65 | get_target_property(TARGET_TYPE ${TARGET} TYPE) 66 | if (TARGET_TYPE STREQUAL "INTERFACE_LIBRARY") 67 | message(WARNING "Can't use any sanitizers for target ${TARGET}, " 68 | "because it is an interface library and cannot be " 69 | "compiled directly.") 70 | return() 71 | endif () 72 | sanitizer_target_compilers(${TARGET} TARGET_COMPILER) 73 | list(LENGTH TARGET_COMPILER NUM_COMPILERS) 74 | if (NUM_COMPILERS GREATER 1) 75 | message(WARNING "Can't use any sanitizers for target ${TARGET}, " 76 | "because it will be compiled by incompatible compilers. " 77 | "Target will be compiled without sanitizers.") 78 | return() 79 | 80 | # If the target is compiled by no or no known compiler, give a warning. 81 | elseif (NUM_COMPILERS EQUAL 0) 82 | message(WARNING "Sanitizers for target ${TARGET} may not be" 83 | " usable, because it uses no or an unknown compiler. " 84 | "This is a false warning for targets using only " 85 | "object lib(s) as input.") 86 | endif () 87 | 88 | # Add sanitizers for target. 89 | add_sanitize_address(${TARGET}) 90 | add_sanitize_thread(${TARGET}) 91 | add_sanitize_memory(${TARGET}) 92 | add_sanitize_undefined(${TARGET}) 93 | endforeach () 94 | endfunction(add_sanitizers) 95 | -------------------------------------------------------------------------------- /cmake/modules/FindSystemd.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # - Find systemd libraries 3 | # 4 | # SYSTEMD_INCLUDE_DIRS - where to find systemd/sd-journal.h, etc. 5 | # SYSTEMD_LIBRARIES - List of libraries when using libsystemd. 6 | # SYSTEMD_FOUND - True if libsystemd is found. 7 | # A "systemd" target is created when found 8 | 9 | pkg_search_module(PC_SYSTEMD QUIET libsystemd) 10 | 11 | find_path(SYSTEMD_INCLUDE_DIR 12 | NAMES 13 | systemd/sd-device.h 14 | HINTS 15 | ${PC_SYSTEMD_INCLUDE_DIRS} 16 | ) 17 | 18 | find_library(SYSTEMD_LIBRARY 19 | NAMES 20 | systemd 21 | HINTS 22 | ${PC_SYSTEMD_LIBRARY_DIRS} 23 | ) 24 | 25 | include(FindPackageHandleStandardArgs) 26 | find_package_handle_standard_args(Systemd 27 | REQUIRED_VARS SYSTEMD_LIBRARY SYSTEMD_INCLUDE_DIR 28 | VERSION_VAR PC_SYSTEMD_VERSION) 29 | 30 | if(SYSTEMD_FOUND) 31 | set(SYSTEMD_LIBRARIES ${SYSTEMD_LIBRARY}) 32 | set(SYSTEMD_INCLUDE_DIRS ${SYSTEMD_INCLUDE_DIR}) 33 | 34 | add_library(systemd INTERFACE IMPORTED GLOBAL) 35 | target_include_directories(systemd INTERFACE ${SYSTEMD_INCLUDE_DIRS}) 36 | set_target_properties(systemd PROPERTIES INTERFACE_INCLUDE_DIRECTORIES ${SYSTEMD_INCLUDE_DIRS}) 37 | target_link_libraries(systemd INTERFACE ${SYSTEMD_LIBRARIES}) 38 | else() 39 | set(SYSTEMD_LIBRARIES) 40 | set(SYSTEMD_INCLUDE_DIRS) 41 | endif() 42 | 43 | mark_as_advanced(SYSTEMD_LIBRARIES SYSTEMD_INCLUDE_DIRS) -------------------------------------------------------------------------------- /cmake/modules/FindTSan.cmake: -------------------------------------------------------------------------------- 1 | # The MIT License (MIT) 2 | # 3 | # Copyright (c) 4 | # 2013 Matthew Arsenault 5 | # 2015-2016 RWTH Aachen University, Federal Republic of Germany 6 | # 7 | # Permission is hereby granted, free of charge, to any person obtaining a copy 8 | # of this software and associated documentation files (the "Software"), to deal 9 | # in the Software without restriction, including without limitation the rights 10 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | # copies of the Software, and to permit persons to whom the Software is 12 | # furnished to do so, subject to the following conditions: 13 | # 14 | # The above copyright notice and this permission notice shall be included in all 15 | # copies or substantial portions of the Software. 16 | # 17 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | # SOFTWARE. 24 | 25 | option(SANITIZE_THREAD "Enable ThreadSanitizer for sanitized targets." Off) 26 | 27 | set(FLAG_CANDIDATES 28 | "-g -fsanitize=thread" 29 | ) 30 | 31 | 32 | # ThreadSanitizer is not compatible with MemorySanitizer. 33 | if (SANITIZE_THREAD AND SANITIZE_MEMORY) 34 | message(FATAL_ERROR "ThreadSanitizer is not compatible with " 35 | "MemorySanitizer.") 36 | endif () 37 | 38 | 39 | include(sanitize-helpers) 40 | 41 | if (SANITIZE_THREAD) 42 | if (NOT ${CMAKE_SYSTEM_NAME} STREQUAL "Linux" AND 43 | NOT ${CMAKE_SYSTEM_NAME} STREQUAL "Darwin") 44 | message(WARNING "ThreadSanitizer disabled for target ${TARGET} because " 45 | "ThreadSanitizer is supported for Linux systems and macOS only.") 46 | set(SANITIZE_THREAD Off CACHE BOOL 47 | "Enable ThreadSanitizer for sanitized targets." FORCE) 48 | elseif (NOT ${CMAKE_SIZEOF_VOID_P} EQUAL 8) 49 | message(WARNING "ThreadSanitizer disabled for target ${TARGET} because " 50 | "ThreadSanitizer is supported for 64bit systems only.") 51 | set(SANITIZE_THREAD Off CACHE BOOL 52 | "Enable ThreadSanitizer for sanitized targets." FORCE) 53 | else () 54 | sanitizer_check_compiler_flags("${FLAG_CANDIDATES}" "ThreadSanitizer" 55 | "TSan") 56 | endif () 57 | endif () 58 | 59 | function (add_sanitize_thread TARGET) 60 | if (NOT SANITIZE_THREAD) 61 | return() 62 | endif () 63 | 64 | sanitizer_add_flags(${TARGET} "ThreadSanitizer" "TSan") 65 | endfunction () 66 | -------------------------------------------------------------------------------- /cmake/modules/FindUBSan.cmake: -------------------------------------------------------------------------------- 1 | # The MIT License (MIT) 2 | # 3 | # Copyright (c) 4 | # 2013 Matthew Arsenault 5 | # 2015-2016 RWTH Aachen University, Federal Republic of Germany 6 | # 7 | # Permission is hereby granted, free of charge, to any person obtaining a copy 8 | # of this software and associated documentation files (the "Software"), to deal 9 | # in the Software without restriction, including without limitation the rights 10 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | # copies of the Software, and to permit persons to whom the Software is 12 | # furnished to do so, subject to the following conditions: 13 | # 14 | # The above copyright notice and this permission notice shall be included in all 15 | # copies or substantial portions of the Software. 16 | # 17 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | # SOFTWARE. 24 | 25 | option(SANITIZE_UNDEFINED 26 | "Enable UndefinedBehaviorSanitizer for sanitized targets." Off) 27 | 28 | set(FLAG_CANDIDATES 29 | "-g -fsanitize=undefined" 30 | ) 31 | 32 | 33 | include(sanitize-helpers) 34 | 35 | if (SANITIZE_UNDEFINED) 36 | sanitizer_check_compiler_flags("${FLAG_CANDIDATES}" 37 | "UndefinedBehaviorSanitizer" "UBSan") 38 | endif () 39 | 40 | function (add_sanitize_undefined TARGET) 41 | if (NOT SANITIZE_UNDEFINED) 42 | return() 43 | endif () 44 | 45 | sanitizer_add_flags(${TARGET} "UndefinedBehaviorSanitizer" "UBSan") 46 | endfunction () 47 | -------------------------------------------------------------------------------- /cmake/modules/FindUDev.cmake: -------------------------------------------------------------------------------- 1 | # Configure libudev environment 2 | # 3 | # UDEV_FOUND - system has a libudev 4 | # UDEV_INCLUDE_DIR - where to find header files 5 | # UDEV_LIBRARIES - the libraries to link against udev 6 | # UDEV_STABLE - it's true when is the version greater or equals to 143 - version when the libudev was stabilized in its API 7 | # An "udev" target is created when found 8 | # 9 | # Adapted from a version of Petr Vanek 10 | # copyright (c) 2011 Petr Vanek 11 | # copyright (c) 2022 Maxime Schmitt 12 | # 13 | # Redistribution and use of this file is allowed according to the terms of the BSD license. 14 | # 15 | 16 | pkg_search_module(PC_UDEV QUIET libudev) 17 | 18 | find_path(UDEV_INCLUDE_DIR 19 | NAMES 20 | libudev.h 21 | HINTS 22 | ${PC_UDEV_INCLUDE_DIRS} 23 | ) 24 | 25 | find_library(UDEV_LIBRARY 26 | NAMES udev 27 | HINTS 28 | ${PC_UDEV_LIBRARY_DIRS} 29 | ) 30 | include(FindPackageHandleStandardArgs) 31 | find_package_handle_standard_args(UDev 32 | REQUIRED_VARS UDEV_LIBRARY UDEV_INCLUDE_DIR 33 | VERSION_VAR PC_UDEV_VERSION) 34 | 35 | if(UDEV_FOUND) 36 | if(PC_UDEV_VERSION GREATER_EQUAL "143") 37 | set(UDEV_STABLE TRUE) 38 | else() 39 | set(UDEV_STABLE FALSE) 40 | endif() 41 | 42 | set(UDEV_LIBRARIES ${UDEV_LIBRARY}) 43 | set(UDEV_INCLUDE_DIRS ${UDEV_INCLUDE_DIR}) 44 | 45 | message(STATUS "Libudev stable: ${UDEV_STABLE}") 46 | 47 | add_library(udev INTERFACE IMPORTED GLOBAL) 48 | set_target_properties(udev PROPERTIES INTERFACE_INCLUDE_DIRECTORIES ${UDEV_INCLUDE_DIRS}) 49 | target_link_libraries(udev INTERFACE ${UDEV_LIBRARIES}) 50 | else() 51 | set(UDEV_LIBRARIES) 52 | set(UDEV_INCLUDE_DIRS) 53 | endif() 54 | 55 | mark_as_advanced(UDEV_LIBRARIES UDEV_INCLUDE_DIRS) -------------------------------------------------------------------------------- /cmake/modules/asan-wrapper: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # The MIT License (MIT) 4 | # 5 | # Copyright (c) 6 | # 2013 Matthew Arsenault 7 | # 2015-2016 RWTH Aachen University, Federal Republic of Germany 8 | # 9 | # Permission is hereby granted, free of charge, to any person obtaining a copy 10 | # of this software and associated documentation files (the "Software"), to deal 11 | # in the Software without restriction, including without limitation the rights 12 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | # copies of the Software, and to permit persons to whom the Software is 14 | # furnished to do so, subject to the following conditions: 15 | # 16 | # The above copyright notice and this permission notice shall be included in all 17 | # copies or substantial portions of the Software. 18 | # 19 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | # SOFTWARE. 26 | 27 | # This script is a wrapper for AddressSanitizer. In some special cases you need 28 | # to preload AddressSanitizer to avoid error messages - e.g. if you're 29 | # preloading another library to your application. At the moment this script will 30 | # only do something, if we're running on a Linux platform. OSX might not be 31 | # affected. 32 | 33 | 34 | # Exit immediately, if platform is not Linux. 35 | if [ "$(uname)" != "Linux" ] 36 | then 37 | exec $@ 38 | fi 39 | 40 | 41 | # Get the used libasan of the application ($1). If a libasan was found, it will 42 | # be prepended to LD_PRELOAD. 43 | libasan=$(ldd $1 | grep libasan | sed "s/^[[:space:]]//" | cut -d' ' -f1) 44 | if [ -n "$libasan" ] 45 | then 46 | if [ -n "$LD_PRELOAD" ] 47 | then 48 | export LD_PRELOAD="$libasan:$LD_PRELOAD" 49 | else 50 | export LD_PRELOAD="$libasan" 51 | fi 52 | fi 53 | 54 | # Execute the application. 55 | exec $@ 56 | -------------------------------------------------------------------------------- /cmake/modules/sanitize-helpers.cmake: -------------------------------------------------------------------------------- 1 | # The MIT License (MIT) 2 | # 3 | # Copyright (c) 4 | # 2013 Matthew Arsenault 5 | # 2015-2016 RWTH Aachen University, Federal Republic of Germany 6 | # 7 | # Permission is hereby granted, free of charge, to any person obtaining a copy 8 | # of this software and associated documentation files (the "Software"), to deal 9 | # in the Software without restriction, including without limitation the rights 10 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | # copies of the Software, and to permit persons to whom the Software is 12 | # furnished to do so, subject to the following conditions: 13 | # 14 | # The above copyright notice and this permission notice shall be included in all 15 | # copies or substantial portions of the Software. 16 | # 17 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | # SOFTWARE. 24 | 25 | # Helper function to get the language of a source file. 26 | function (sanitizer_lang_of_source FILE RETURN_VAR) 27 | get_filename_component(LONGEST_EXT "${FILE}" EXT) 28 | # If extension is empty return. This can happen for extensionless headers 29 | if("${LONGEST_EXT}" STREQUAL "") 30 | set(${RETURN_VAR} "" PARENT_SCOPE) 31 | return() 32 | endif() 33 | # Get shortest extension as some files can have dot in their names 34 | string(REGEX REPLACE "^.*(\\.[^.]+)$" "\\1" FILE_EXT ${LONGEST_EXT}) 35 | string(TOLOWER "${FILE_EXT}" FILE_EXT) 36 | string(SUBSTRING "${FILE_EXT}" 1 -1 FILE_EXT) 37 | 38 | get_property(ENABLED_LANGUAGES GLOBAL PROPERTY ENABLED_LANGUAGES) 39 | foreach (LANG ${ENABLED_LANGUAGES}) 40 | list(FIND CMAKE_${LANG}_SOURCE_FILE_EXTENSIONS "${FILE_EXT}" TEMP) 41 | if (NOT ${TEMP} EQUAL -1) 42 | set(${RETURN_VAR} "${LANG}" PARENT_SCOPE) 43 | return() 44 | endif () 45 | endforeach() 46 | 47 | set(${RETURN_VAR} "" PARENT_SCOPE) 48 | endfunction () 49 | 50 | 51 | # Helper function to get compilers used by a target. 52 | function (sanitizer_target_compilers TARGET RETURN_VAR) 53 | # Check if all sources for target use the same compiler. If a target uses 54 | # e.g. C and Fortran mixed and uses different compilers (e.g. clang and 55 | # gfortran) this can trigger huge problems, because different compilers may 56 | # use different implementations for sanitizers. 57 | set(BUFFER "") 58 | get_target_property(TSOURCES ${TARGET} SOURCES) 59 | foreach (FILE ${TSOURCES}) 60 | # If expression was found, FILE is a generator-expression for an object 61 | # library. Object libraries will be ignored. 62 | string(REGEX MATCH "TARGET_OBJECTS:([^ >]+)" _file ${FILE}) 63 | if ("${_file}" STREQUAL "") 64 | sanitizer_lang_of_source(${FILE} LANG) 65 | if (LANG) 66 | list(APPEND BUFFER ${CMAKE_${LANG}_COMPILER_ID}) 67 | endif () 68 | endif () 69 | endforeach () 70 | 71 | list(REMOVE_DUPLICATES BUFFER) 72 | set(${RETURN_VAR} "${BUFFER}" PARENT_SCOPE) 73 | endfunction () 74 | 75 | 76 | # Helper function to check compiler flags for language compiler. 77 | function (sanitizer_check_compiler_flag FLAG LANG VARIABLE) 78 | if (${LANG} STREQUAL "C") 79 | include(CheckCCompilerFlag) 80 | check_c_compiler_flag("${FLAG}" ${VARIABLE}) 81 | 82 | elseif (${LANG} STREQUAL "CXX") 83 | include(CheckCXXCompilerFlag) 84 | check_cxx_compiler_flag("${FLAG}" ${VARIABLE}) 85 | 86 | elseif (${LANG} STREQUAL "Fortran") 87 | # CheckFortranCompilerFlag was introduced in CMake 3.x. To be compatible 88 | # with older Cmake versions, we will check if this module is present 89 | # before we use it. Otherwise we will define Fortran coverage support as 90 | # not available. 91 | include(CheckFortranCompilerFlag OPTIONAL RESULT_VARIABLE INCLUDED) 92 | if (INCLUDED) 93 | check_fortran_compiler_flag("${FLAG}" ${VARIABLE}) 94 | elseif (NOT CMAKE_REQUIRED_QUIET) 95 | message(STATUS "Performing Test ${VARIABLE}") 96 | message(STATUS "Performing Test ${VARIABLE}" 97 | " - Failed (Check not supported)") 98 | endif () 99 | endif() 100 | endfunction () 101 | 102 | 103 | # Helper function to test compiler flags. 104 | function (sanitizer_check_compiler_flags FLAG_CANDIDATES NAME PREFIX) 105 | set(CMAKE_REQUIRED_QUIET ${${PREFIX}_FIND_QUIETLY}) 106 | 107 | get_property(ENABLED_LANGUAGES GLOBAL PROPERTY ENABLED_LANGUAGES) 108 | foreach (LANG ${ENABLED_LANGUAGES}) 109 | # Sanitizer flags are not dependend on language, but the used compiler. 110 | # So instead of searching flags foreach language, search flags foreach 111 | # compiler used. 112 | set(COMPILER ${CMAKE_${LANG}_COMPILER_ID}) 113 | if (NOT DEFINED ${PREFIX}_${COMPILER}_FLAGS) 114 | foreach (FLAG ${FLAG_CANDIDATES}) 115 | if(NOT CMAKE_REQUIRED_QUIET) 116 | message(STATUS "Try ${COMPILER} ${NAME} flag = [${FLAG}]") 117 | endif() 118 | 119 | set(CMAKE_REQUIRED_FLAGS "${FLAG}") 120 | unset(${PREFIX}_FLAG_DETECTED CACHE) 121 | sanitizer_check_compiler_flag("${FLAG}" ${LANG} 122 | ${PREFIX}_FLAG_DETECTED) 123 | 124 | if (${PREFIX}_FLAG_DETECTED) 125 | # If compiler is a GNU compiler, search for static flag, if 126 | # SANITIZE_LINK_STATIC is enabled. 127 | if (SANITIZE_LINK_STATIC AND (${COMPILER} STREQUAL "GNU")) 128 | string(TOLOWER ${PREFIX} PREFIX_lower) 129 | sanitizer_check_compiler_flag( 130 | "-static-lib${PREFIX_lower}" ${LANG} 131 | ${PREFIX}_STATIC_FLAG_DETECTED) 132 | 133 | if (${PREFIX}_STATIC_FLAG_DETECTED) 134 | set(FLAG "-static-lib${PREFIX_lower} ${FLAG}") 135 | endif () 136 | endif () 137 | 138 | set(${PREFIX}_${COMPILER}_FLAGS "${FLAG}" CACHE STRING 139 | "${NAME} flags for ${COMPILER} compiler.") 140 | mark_as_advanced(${PREFIX}_${COMPILER}_FLAGS) 141 | break() 142 | endif () 143 | endforeach () 144 | 145 | if (NOT ${PREFIX}_FLAG_DETECTED) 146 | set(${PREFIX}_${COMPILER}_FLAGS "" CACHE STRING 147 | "${NAME} flags for ${COMPILER} compiler.") 148 | mark_as_advanced(${PREFIX}_${COMPILER}_FLAGS) 149 | 150 | message(WARNING "${NAME} is not available for ${COMPILER} " 151 | "compiler. Targets using this compiler will be " 152 | "compiled without ${NAME}.") 153 | endif () 154 | endif () 155 | endforeach () 156 | endfunction () 157 | 158 | 159 | # Helper to assign sanitizer flags for TARGET. 160 | function (sanitizer_add_flags TARGET NAME PREFIX) 161 | # Get list of compilers used by target and check, if sanitizer is available 162 | # for this target. Other compiler checks like check for conflicting 163 | # compilers will be done in add_sanitizers function. 164 | sanitizer_target_compilers(${TARGET} TARGET_COMPILER) 165 | list(LENGTH TARGET_COMPILER NUM_COMPILERS) 166 | if ("${${PREFIX}_${TARGET_COMPILER}_FLAGS}" STREQUAL "") 167 | return() 168 | endif() 169 | 170 | # Set compile- and link-flags for target. 171 | set_property(TARGET ${TARGET} APPEND_STRING 172 | PROPERTY COMPILE_FLAGS " ${${PREFIX}_${TARGET_COMPILER}_FLAGS}") 173 | set_property(TARGET ${TARGET} APPEND_STRING 174 | PROPERTY COMPILE_FLAGS " ${SanBlist_${TARGET_COMPILER}_FLAGS}") 175 | set_property(TARGET ${TARGET} APPEND_STRING 176 | PROPERTY LINK_FLAGS " ${${PREFIX}_${TARGET_COMPILER}_FLAGS}") 177 | endfunction () 178 | -------------------------------------------------------------------------------- /cmake/optimization_flags.cmake: -------------------------------------------------------------------------------- 1 | set(ADDITIONAL_DEBUG_COMPILE_OPTIONS 2 | "-Wall" 3 | #"-Wpedantic" 4 | "-Wextra" 5 | "-Waddress" 6 | "-Waggressive-loop-optimizations" 7 | #"-Wcast-qual" 8 | #"-Wcast-align" 9 | "-Wbad-function-cast" 10 | "-Wmissing-declarations" 11 | "-Wmissing-parameter-type" 12 | "-Wmissing-prototypes" 13 | "-Wnested-externs" 14 | "-Wold-style-declaration" 15 | "-Wold-style-definition" 16 | "-Wstrict-prototypes" 17 | "-Wpointer-sign" 18 | "-Wdouble-promotion" 19 | "-Wuninitialized" 20 | "-Winit-self" 21 | "-Wstrict-aliasing" 22 | "-Wsuggest-attribute=const" 23 | "-Wtrampolines" 24 | "-Wfloat-equal" 25 | "-Wshadow" 26 | "-Wunsafe-loop-optimizations" 27 | "-Wfloat-conversion" 28 | "-Wlogical-op" 29 | "-Wnormalized" 30 | "-Wdisabled-optimization" 31 | "-Whsa" 32 | #"-Wconversion" 33 | "-Wunused-result" 34 | "-Werror=implicit-function-declaration" 35 | #"-Wpadded" 36 | "-Wformat" 37 | "-Wformat-security" 38 | CACHE INTERNAL "String" 39 | ) 40 | 41 | set(ADDITIONAL_RELEASE_LINK_OPTIONS 42 | "-Wl,-z,relro") 43 | -------------------------------------------------------------------------------- /desktop/nvtop.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Name=nvtop 3 | GenericName=GPU Process Monitor 4 | Type=Application 5 | Terminal=true 6 | Exec=nvtop 7 | Icon=nvtop 8 | Categories=System;Monitor; 9 | X-AppImage-Integrate=false 10 | 11 | -------------------------------------------------------------------------------- /desktop/nvtop.metainfo.xml.in: -------------------------------------------------------------------------------- 1 | 2 | 3 | io.github.syllo.nvtop 4 | 5 | nvtop 6 | GPU process monitor for AMD, Intel and NVIDIA 7 | 8 | CC0-1.0 9 | GPL-3.0-or-later 10 | Maxime Schmitt 11 | 12 | 13 |

Nvtop stands for Neat Videocard TOP, a (h)top like task monitor for AMD, Intel and NVIDIA GPUs. It can handle multiple GPUs and print information about them in a htop familiar way.

14 |
15 | 16 | nvtop.desktop 17 | 18 | nvtop.svg 19 | 20 | 21 | System 22 | Monitor 23 | 24 | 25 | https://github.com/Syllo/nvtop 26 | 27 | 28 | 29 | The nvtop interface 30 | https://raw.githubusercontent.com/Syllo/nvtop/master/screenshot/NVTOP_ex1.png 31 | 32 | 33 | The nvtop option screen 34 | https://raw.githubusercontent.com/Syllo/nvtop/master/screenshot/Nvtop-config.png 35 | 36 | 37 | 38 | 39 | nvtop 40 | 41 | 42 | 43 | 44 |
45 | -------------------------------------------------------------------------------- /desktop/nvtop.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 19 | 41 | 44 | 45 | 47 | 52 | 60 | 61 | 65 | 69 | 77 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /include/ini.h: -------------------------------------------------------------------------------- 1 | /* inih -- simple .INI file parser 2 | 3 | SPDX-License-Identifier: BSD-3-Clause 4 | 5 | Copyright (C) 2009-2020, Ben Hoyt 6 | 7 | inih is released under the New BSD license (see LICENSE.txt). Go to the project 8 | home page for more info: 9 | 10 | https://github.com/benhoyt/inih 11 | 12 | */ 13 | 14 | #ifndef INI_H 15 | #define INI_H 16 | 17 | /* Make this header file easier to include in C++ code */ 18 | #ifdef __cplusplus 19 | extern "C" { 20 | #endif 21 | 22 | #include 23 | 24 | /* Nonzero if ini_handler callback should accept lineno parameter. */ 25 | #ifndef INI_HANDLER_LINENO 26 | #define INI_HANDLER_LINENO 0 27 | #endif 28 | 29 | /* Typedef for prototype of handler function. */ 30 | #if INI_HANDLER_LINENO 31 | typedef int (*ini_handler)(void* user, const char* section, 32 | const char* name, const char* value, 33 | int lineno); 34 | #else 35 | typedef int (*ini_handler)(void* user, const char* section, 36 | const char* name, const char* value); 37 | #endif 38 | 39 | /* Typedef for prototype of fgets-style reader function. */ 40 | typedef char* (*ini_reader)(char* str, int num, void* stream); 41 | 42 | /* Parse given INI-style file. May have [section]s, name=value pairs 43 | (whitespace stripped), and comments starting with ';' (semicolon). Section 44 | is "" if name=value pair parsed before any section heading. name:value 45 | pairs are also supported as a concession to Python's configparser. 46 | 47 | For each name=value pair parsed, call handler function with given user 48 | pointer as well as section, name, and value (data only valid for duration 49 | of handler call). Handler should return nonzero on success, zero on error. 50 | 51 | Returns 0 on success, line number of first error on parse error (doesn't 52 | stop on first error), -1 on file open error, or -2 on memory allocation 53 | error (only when INI_USE_STACK is zero). 54 | */ 55 | int ini_parse(const char* filename, ini_handler handler, void* user); 56 | 57 | /* Same as ini_parse(), but takes a FILE* instead of filename. This doesn't 58 | close the file when it's finished -- the caller must do that. */ 59 | int ini_parse_file(FILE* file, ini_handler handler, void* user); 60 | 61 | /* Same as ini_parse(), but takes an ini_reader function pointer instead of 62 | filename. Used for implementing custom or string-based I/O (see also 63 | ini_parse_string). */ 64 | int ini_parse_stream(ini_reader reader, void* stream, ini_handler handler, 65 | void* user); 66 | 67 | /* Same as ini_parse(), but takes a zero-terminated string with the INI data 68 | instead of a file. Useful for parsing INI data from a network socket or 69 | already in memory. */ 70 | int ini_parse_string(const char* string, ini_handler handler, void* user); 71 | 72 | /* Nonzero to allow multi-line value parsing, in the style of Python's 73 | configparser. If allowed, ini_parse() will call the handler with the same 74 | name for each subsequent line parsed. */ 75 | #ifndef INI_ALLOW_MULTILINE 76 | #define INI_ALLOW_MULTILINE 1 77 | #endif 78 | 79 | /* Nonzero to allow a UTF-8 BOM sequence (0xEF 0xBB 0xBF) at the start of 80 | the file. See https://github.com/benhoyt/inih/issues/21 */ 81 | #ifndef INI_ALLOW_BOM 82 | #define INI_ALLOW_BOM 1 83 | #endif 84 | 85 | /* Chars that begin a start-of-line comment. Per Python configparser, allow 86 | both ; and # comments at the start of a line by default. */ 87 | #ifndef INI_START_COMMENT_PREFIXES 88 | #define INI_START_COMMENT_PREFIXES ";#" 89 | #endif 90 | 91 | /* Nonzero to allow inline comments (with valid inline comment characters 92 | specified by INI_INLINE_COMMENT_PREFIXES). Set to 0 to turn off and match 93 | Python 3.2+ configparser behaviour. */ 94 | #ifndef INI_ALLOW_INLINE_COMMENTS 95 | #define INI_ALLOW_INLINE_COMMENTS 1 96 | #endif 97 | #ifndef INI_INLINE_COMMENT_PREFIXES 98 | #define INI_INLINE_COMMENT_PREFIXES ";" 99 | #endif 100 | 101 | /* Nonzero to use stack for line buffer, zero to use heap (malloc/free). */ 102 | #ifndef INI_USE_STACK 103 | #define INI_USE_STACK 1 104 | #endif 105 | 106 | /* Maximum line length for any line in INI file (stack or heap). Note that 107 | this must be 3 more than the longest line (due to '\r', '\n', and '\0'). */ 108 | #ifndef INI_MAX_LINE 109 | #define INI_MAX_LINE 200 110 | #endif 111 | 112 | /* Nonzero to allow heap line buffer to grow via realloc(), zero for a 113 | fixed-size buffer of INI_MAX_LINE bytes. Only applies if INI_USE_STACK is 114 | zero. */ 115 | #ifndef INI_ALLOW_REALLOC 116 | #define INI_ALLOW_REALLOC 0 117 | #endif 118 | 119 | /* Initial size in bytes for heap line buffer. Only applies if INI_USE_STACK 120 | is zero. */ 121 | #ifndef INI_INITIAL_ALLOC 122 | #define INI_INITIAL_ALLOC 200 123 | #endif 124 | 125 | /* Stop parsing on first error (default is to keep parsing). */ 126 | #ifndef INI_STOP_ON_FIRST_ERROR 127 | #define INI_STOP_ON_FIRST_ERROR 0 128 | #endif 129 | 130 | /* Nonzero to call the handler at the start of each new section (with 131 | name and value NULL). Default is to only call the handler on 132 | each name=value pair. */ 133 | #ifndef INI_CALL_HANDLER_ON_NEW_SECTION 134 | #define INI_CALL_HANDLER_ON_NEW_SECTION 0 135 | #endif 136 | 137 | /* Nonzero to allow a name without a value (no '=' or ':' on the line) and 138 | call the handler with value NULL in this case. Default is to treat 139 | no-value lines as an error. */ 140 | #ifndef INI_ALLOW_NO_VALUE 141 | #define INI_ALLOW_NO_VALUE 0 142 | #endif 143 | 144 | /* Nonzero to use custom ini_malloc, ini_free, and ini_realloc memory 145 | allocation functions (INI_USE_STACK must also be 0). These functions must 146 | have the same signatures as malloc/free/realloc and behave in a similar 147 | way. ini_realloc is only needed if INI_ALLOW_REALLOC is set. */ 148 | #ifndef INI_CUSTOM_ALLOCATOR 149 | #define INI_CUSTOM_ALLOCATOR 0 150 | #endif 151 | 152 | 153 | #ifdef __cplusplus 154 | } 155 | #endif 156 | 157 | #endif /* INI_H */ 158 | -------------------------------------------------------------------------------- /include/list.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2002 Free Software Foundation, Inc. 3 | * (originally part of the GNU C Library) 4 | * Contributed by Ulrich Drepper , 2002. 5 | * 6 | * Copyright (C) 2009 Pierre-Marc Fournier 7 | * Conversion to RCU list. 8 | * Copyright (C) 2010 Mathieu Desnoyers 9 | * 10 | * This library is free software; you can redistribute it and/or 11 | * modify it under the terms of the GNU Lesser General Public 12 | * License as published by the Free Software Foundation; either 13 | * version 2.1 of the License, or (at your option) any later version. 14 | * 15 | * This library is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 18 | * Lesser General Public License for more details. 19 | * 20 | * You should have received a copy of the GNU Lesser General Public 21 | * License along with this library; if not, write to the Free Software 22 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 23 | */ 24 | 25 | #ifndef _LIST_H 26 | #define _LIST_H 1 27 | 28 | #include 29 | 30 | /* 31 | * container_of - Get the address of an object containing a field. 32 | * 33 | * @ptr: pointer to the field. 34 | * @type: type of the object. 35 | * @member: name of the field within the object. 36 | */ 37 | #define container_of(ptr, type, member) \ 38 | __extension__ \ 39 | ({ \ 40 | const __typeof__(((type *) NULL)->member) * __ptr = (ptr); \ 41 | (type *)((char *)__ptr - offsetof(type, member)); \ 42 | }) 43 | 44 | /* 45 | * The definitions of this file are adopted from those which can be 46 | * found in the Linux kernel headers to enable people familiar with the 47 | * latter find their way in these sources as well. 48 | */ 49 | 50 | /* Basic type for the double-link list. */ 51 | struct list_head { 52 | struct list_head *next, *prev; 53 | }; 54 | 55 | /* Define a variable with the head and tail of the list. */ 56 | #define LIST_HEAD(name) \ 57 | struct list_head name = { &(name), &(name) } 58 | 59 | /* Initialize a new list head. */ 60 | #define INIT_LIST_HEAD(ptr) \ 61 | (ptr)->next = (ptr)->prev = (ptr) 62 | 63 | #define LIST_HEAD_INIT(name) { .next = &(name), .prev = &(name) } 64 | 65 | /* Add new element at the head of the list. */ 66 | static inline 67 | void list_add(struct list_head *newp, struct list_head *head) 68 | { 69 | head->next->prev = newp; 70 | newp->next = head->next; 71 | newp->prev = head; 72 | head->next = newp; 73 | } 74 | 75 | /* Add new element at the tail of the list. */ 76 | static inline 77 | void list_add_tail(struct list_head *newp, struct list_head *head) 78 | { 79 | head->prev->next = newp; 80 | newp->next = head; 81 | newp->prev = head->prev; 82 | head->prev = newp; 83 | } 84 | 85 | /* Remove element from list. */ 86 | static inline 87 | void __list_del(struct list_head *prev, struct list_head *next) 88 | { 89 | next->prev = prev; 90 | prev->next = next; 91 | } 92 | 93 | /* Remove element from list. */ 94 | static inline 95 | void list_del(struct list_head *elem) 96 | { 97 | __list_del(elem->prev, elem->next); 98 | } 99 | 100 | /* Remove element from list, initializing the element's list pointers. */ 101 | static inline 102 | void list_del_init(struct list_head *elem) 103 | { 104 | list_del(elem); 105 | INIT_LIST_HEAD(elem); 106 | } 107 | 108 | /* Delete from list, add to another list as head. */ 109 | static inline 110 | void list_move(struct list_head *elem, struct list_head *head) 111 | { 112 | __list_del(elem->prev, elem->next); 113 | list_add(elem, head); 114 | } 115 | 116 | /* Delete from list, add to another list as tail. */ 117 | static inline 118 | void list_move_tail(struct list_head *elem, struct list_head *head) 119 | { 120 | __list_del(elem->prev, elem->next); 121 | list_add_tail(elem, head); 122 | } 123 | 124 | /* Replace an old entry. */ 125 | static inline 126 | void list_replace(struct list_head *old, struct list_head *_new) 127 | { 128 | _new->next = old->next; 129 | _new->prev = old->prev; 130 | _new->prev->next = _new; 131 | _new->next->prev = _new; 132 | } 133 | 134 | /* Join two lists. */ 135 | static inline 136 | void list_splice(struct list_head *add, struct list_head *head) 137 | { 138 | /* Do nothing if the list which gets added is empty. */ 139 | if (add != add->next) { 140 | add->next->prev = head; 141 | add->prev->next = head->next; 142 | head->next->prev = add->prev; 143 | head->next = add->next; 144 | } 145 | } 146 | 147 | /* Get typed element from list at a given position. */ 148 | #define list_entry(ptr, type, member) container_of(ptr, type, member) 149 | 150 | 151 | /* Get first entry from a list. */ 152 | #define list_first_entry(ptr, type, member) \ 153 | list_entry((ptr)->next, type, member) 154 | 155 | /* Iterate forward over the elements of the list. */ 156 | #define list_for_each(pos, head) \ 157 | for (pos = (head)->next; (pos) != (head); pos = (pos)->next) 158 | 159 | /* 160 | * Iterate forward over the elements list. The list elements can be 161 | * removed from the list while doing this. 162 | */ 163 | #define list_for_each_safe(pos, p, head) \ 164 | for (pos = (head)->next, p = (pos)->next; \ 165 | (pos) != (head); \ 166 | pos = (p), p = (pos)->next) 167 | 168 | /* Iterate backward over the elements of the list. */ 169 | #define list_for_each_prev(pos, head) \ 170 | for (pos = (head)->prev; (pos) != (head); pos = (pos)->prev) 171 | 172 | /* 173 | * Iterate backwards over the elements list. The list elements can be 174 | * removed from the list while doing this. 175 | */ 176 | #define list_for_each_prev_safe(pos, p, head) \ 177 | for (pos = (head)->prev, p = (pos)->prev; \ 178 | (pos) != (head); \ 179 | pos = (p), p = (pos)->prev) 180 | 181 | #define list_for_each_entry(pos, head, member) \ 182 | for (pos = list_entry((head)->next, __typeof__(*(pos)), member); \ 183 | &(pos)->member != (head); \ 184 | pos = list_entry((pos)->member.next, __typeof__(*(pos)), member)) 185 | 186 | #define list_for_each_entry_reverse(pos, head, member) \ 187 | for (pos = list_entry((head)->prev, __typeof__(*(pos)), member); \ 188 | &(pos)->member != (head); \ 189 | pos = list_entry((pos)->member.prev, __typeof__(*(pos)), member)) 190 | 191 | #define list_for_each_entry_safe(pos, p, head, member) \ 192 | for (pos = list_entry((head)->next, __typeof__(*(pos)), member), \ 193 | p = list_entry((pos)->member.next, __typeof__(*(pos)), member); \ 194 | &(pos)->member != (head); \ 195 | pos = (p), p = list_entry((pos)->member.next, __typeof__(*(pos)), member)) 196 | 197 | #define list_for_each_entry_reverse_safe(pos, p, head, member) \ 198 | for (pos = list_entry((head)->prev, __typeof__(*(pos)), member), \ 199 | p = list_entry((pos)->member.prev, __typeof__(*(pos)), member); \ 200 | &(pos)->member != (head); pos = (p), p = list_entry((pos)->member.prev, __typeof__(*(pos)), member)) 201 | 202 | /* 203 | * Same as list_for_each_entry_safe, but starts from "pos" which should 204 | * point to an entry within the list. 205 | */ 206 | #define list_for_each_entry_safe_from(pos, p, head, member) \ 207 | for (p = list_entry((pos)->member.next, __typeof__(*(pos)), member); \ 208 | &(pos)->member != (head); \ 209 | pos = (p), p = list_entry((pos)->member.next, __typeof__(*(pos)), member)) 210 | 211 | static inline 212 | int list_empty(struct list_head *head) 213 | { 214 | return head == head->next; 215 | } 216 | 217 | static inline 218 | void list_replace_init(struct list_head *old, 219 | struct list_head *_new) 220 | { 221 | struct list_head *head = old->next; 222 | 223 | list_del(old); 224 | list_add_tail(_new, head); 225 | INIT_LIST_HEAD(old); 226 | } 227 | 228 | #endif /* _LIST_H */ 229 | -------------------------------------------------------------------------------- /include/nvtop/common.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Copyright (C) 2022 Maxime Schmitt 4 | * 5 | * This file is part of Nvtop. 6 | * 7 | * Nvtop is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * Nvtop is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with nvtop. If not, see . 19 | * 20 | */ 21 | 22 | #ifndef NVTOP_COMMON_H__ 23 | #define NVTOP_COMMON_H__ 24 | 25 | #if !defined(HAS_REALLOCARRAY) 26 | 27 | #include 28 | #include 29 | 30 | #undef reallocarray 31 | 32 | // Reallocarray from musl libc (https://git.musl-libc.org/cgit/musl/tree/src/malloc/reallocarray.c) 33 | static void *nvtop_reallocarray__(void *ptr, size_t nmemb, size_t size) { 34 | if (size && nmemb > -1 / size) { 35 | errno = ENOMEM; 36 | return NULL; 37 | } 38 | return realloc(ptr, nmemb * size); 39 | } 40 | #define reallocarray(ptr, nmemb, size) nvtop_reallocarray__(ptr, nmemb, size) 41 | 42 | #endif // !defined(HAS_REALLOCARRAY) 43 | 44 | // Increment for the number of tracked processes 45 | // 16 has been experimentally selected for being small while avoiding multipe allocations in most common cases 46 | #define COMMON_PROCESS_LINEAR_REALLOC_INC 16 47 | 48 | #define MAX_LINES_PER_PLOT 4 49 | 50 | // Helper macro to stringify an integer 51 | #define QUOTE(x) #x 52 | #define EXPAND_AND_QUOTE(x) QUOTE(x) 53 | 54 | #endif // NVTOP_COMMON_H__ 55 | -------------------------------------------------------------------------------- /include/nvtop/device_discovery.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Copyright (C) 2022 Maxime Schmitt 4 | * 5 | * This file is part of Nvtop. 6 | * 7 | * Nvtop is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * Nvtop is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with nvtop. If not, see . 19 | * 20 | */ 21 | 22 | #ifndef NVTOP_DEVICE_DISCOVERY_H__ 23 | #define NVTOP_DEVICE_DISCOVERY_H__ 24 | 25 | // Devices 26 | typedef struct nvtop_device nvtop_device; 27 | 28 | nvtop_device *nvtop_device_ref(nvtop_device *device); 29 | nvtop_device *nvtop_device_unref(nvtop_device *device); 30 | 31 | int nvtop_device_new_from_syspath(nvtop_device **ret, const char *syspath); 32 | int nvtop_device_get_parent(nvtop_device *child, nvtop_device **parent); 33 | int nvtop_device_get_driver(nvtop_device *device, const char **driver); 34 | int nvtop_device_get_devname(nvtop_device *device, const char **devname); 35 | int nvtop_device_get_property_value(nvtop_device *device, const char *key, const char **value); 36 | int nvtop_device_get_sysattr_value(nvtop_device *device, const char *sysattr, const char **value); 37 | int nvtop_device_get_syspath(nvtop_device *device, const char **sysPath); 38 | 39 | // Devices enumerator 40 | typedef struct nvtop_device_enumerator nvtop_device_enumerator; 41 | 42 | int nvtop_enumerator_new(nvtop_device_enumerator **enumerator); 43 | nvtop_device_enumerator *nvtop_enumerator_ref(nvtop_device_enumerator *enumerator); 44 | nvtop_device_enumerator *nvtop_enumerator_unref(nvtop_device_enumerator *enumerator); 45 | 46 | int nvtop_device_enumerator_add_match_subsystem(nvtop_device_enumerator *enumerator, const char *subsystem, int match); 47 | int nvtop_device_enumerator_add_match_property(nvtop_device_enumerator *enumerator, const char *property, 48 | const char *value); 49 | int nvtop_device_enumerator_add_match_parent(nvtop_device_enumerator *enumerator, nvtop_device *parent); 50 | 51 | nvtop_device *nvtop_enumerator_get_device_first(nvtop_device_enumerator *enumerator); 52 | nvtop_device *nvtop_enumerator_get_device_next(nvtop_device_enumerator *enumerator); 53 | 54 | typedef struct { 55 | unsigned width; 56 | unsigned speed; 57 | } nvtop_pcie_link; 58 | 59 | int nvtop_device_maximum_pcie_link(nvtop_device *dev, nvtop_pcie_link *pcie_info); 60 | int nvtop_device_current_pcie_link(nvtop_device *dev, nvtop_pcie_link *pcie_info); 61 | 62 | nvtop_device *nvtop_device_get_hwmon(nvtop_device *dev); 63 | 64 | #endif // NVTOP_DEVICE_DISCOVERY_H__ 65 | -------------------------------------------------------------------------------- /include/nvtop/extract_gpuinfo.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Copyright (C) 2017-2021 Maxime Schmitt 4 | * 5 | * This file is part of Nvtop. 6 | * 7 | * Nvtop is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * Nvtop is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with nvtop. If not, see . 19 | * 20 | */ 21 | 22 | #ifndef EXTRACT_GPUINFO_H_ 23 | #define EXTRACT_GPUINFO_H_ 24 | 25 | #include "nvtop/extract_gpuinfo_common.h" 26 | 27 | #include 28 | 29 | bool gpuinfo_init_info_extraction(unsigned *total_dev_count, struct list_head *devices); 30 | 31 | bool gpuinfo_shutdown_info_extraction(struct list_head *devices); 32 | 33 | bool gpuinfo_populate_static_infos(struct list_head *devices); 34 | 35 | bool gpuinfo_refresh_dynamic_info(struct list_head *devices); 36 | 37 | bool gpuinfo_fix_dynamic_info_from_process_info(struct list_head *devices); 38 | 39 | bool gpuinfo_refresh_processes(struct list_head *devices); 40 | 41 | bool gpuinfo_utilisation_rate(struct list_head *devices); 42 | 43 | void gpuinfo_clean(struct list_head *devices); 44 | 45 | void gpuinfo_clear_cache(void); 46 | 47 | #endif // EXTRACT_GPUINFO_H_ 48 | -------------------------------------------------------------------------------- /include/nvtop/extract_processinfo_fdinfo.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Copyright (C) 2022 Maxime Schmitt 4 | * 5 | * This file is part of Nvtop. 6 | * 7 | * Nvtop is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * Nvtop is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with nvtop. If not, see . 19 | * 20 | */ 21 | 22 | #ifndef NVTOP_EXTRACT_PROCESSINFO_FDINFO__ 23 | #define NVTOP_EXTRACT_PROCESSINFO_FDINFO__ 24 | 25 | #include "nvtop/extract_gpuinfo_common.h" 26 | 27 | #include 28 | 29 | /** 30 | * @brief A callback function that populates the \p process_info structure from 31 | * the information gathered while parsing the fdinfo file \p fdinfo_file. Return true if the data in process_info is 32 | * valid, false otherwise. 33 | */ 34 | typedef bool (*processinfo_fdinfo_callback)(struct gpu_info *info, FILE *fdinfo_file, struct gpu_process *process_info); 35 | 36 | /** 37 | * @brief Register a callback function to parse a fdinfo file opened to a DRM driver 38 | * 39 | * @param callback The callback function 40 | * @param info The struct gpu_info that will be updated when the callback succeeds. 41 | */ 42 | void processinfo_register_fdinfo_callback(processinfo_fdinfo_callback callback, struct gpu_info *info); 43 | 44 | /** 45 | * @brief Remove a previously registered callback. 46 | * 47 | * @param info The callback to this gpu_info will be removed 48 | */ 49 | void processinfo_drop_callback(const struct gpu_info *info); 50 | 51 | /** 52 | * @brief Enables or disables a fdinfo processing callback 53 | * 54 | * @param info Enabling/Disabling the callback to this gpu_info 55 | * @param enable True to enable the callback, false to disable 56 | */ 57 | void processinfo_enable_disable_callback_for(const struct gpu_info *info, bool enable); 58 | 59 | /** 60 | * @brief Scann all the processes in /proc. Call the registered callbacks on 61 | * each file descriptor to the DRM driver that can successfully be oppened. If a 62 | * callback succeeds, the gpu_info structure processes array will be updated 63 | * with the retrieved data. 64 | */ 65 | void processinfo_sweep_fdinfos(void); 66 | 67 | #endif // NVTOP_EXTRACT_PROCESSINFO_FDINFO__ 68 | -------------------------------------------------------------------------------- /include/nvtop/get_process_info.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Copyright (C) 2017-2021 Maxime Schmitt 4 | * 5 | * This file is part of Nvtop. 6 | * 7 | * Nvtop is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * Nvtop is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with nvtop. If not, see . 19 | * 20 | */ 21 | 22 | #ifndef GET_PROCESS_INFO_H_ 23 | #define GET_PROCESS_INFO_H_ 24 | 25 | #include 26 | #include 27 | #include 28 | 29 | #include "nvtop/time.h" 30 | 31 | struct process_cpu_usage { 32 | double total_user_time; // Seconds 33 | double total_kernel_time; // Seconds 34 | size_t virtual_memory; // Bytes 35 | size_t resident_memory; // Bytes 36 | nvtop_time timestamp; 37 | }; 38 | 39 | void get_username_from_pid(pid_t pid, char **buffer); 40 | 41 | void get_command_from_pid(pid_t pid, char **buffer); 42 | 43 | bool get_process_info(pid_t pid, struct process_cpu_usage *usage); 44 | 45 | #endif // GET_PROCESS_INFO_H_ 46 | -------------------------------------------------------------------------------- /include/nvtop/info_messages.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Copyright (C) 2022 Maxime Schmitt 4 | * 5 | * This file is part of Nvtop. 6 | * 7 | * Nvtop is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * Nvtop is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with nvtop. If not, see . 19 | * 20 | */ 21 | 22 | #ifndef NVTOP_INFO_MESSAGES_H__ 23 | #define NVTOP_INFO_MESSAGES_H__ 24 | 25 | void get_info_messages(struct list_head *devices, unsigned *num_messages, const char ***messages); 26 | 27 | #endif // NVTOP_INFO_MESSAGES_H__ 28 | -------------------------------------------------------------------------------- /include/nvtop/interface.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Copyright (C) 2017-2021 Maxime Schmitt 4 | * 5 | * This file is part of Nvtop. 6 | * 7 | * Nvtop is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * Nvtop is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with nvtop. If not, see . 19 | * 20 | */ 21 | 22 | #ifndef INTERFACE_H_ 23 | #define INTERFACE_H_ 24 | 25 | #include "nvtop/interface_options.h" 26 | 27 | #include 28 | 29 | struct nvtop_interface; 30 | 31 | struct nvtop_interface *initialize_curses(unsigned total_devices, unsigned num_devices, unsigned largest_device_name, 32 | nvtop_interface_option options); 33 | 34 | void clean_ncurses(struct nvtop_interface *interface); 35 | 36 | void interface_check_monitored_gpu_change(struct nvtop_interface **interface, unsigned allDevCount, 37 | unsigned *num_monitored_gpus, struct list_head *monitoredGpus, 38 | struct list_head *nonMonitoredGpus); 39 | 40 | unsigned interface_largest_gpu_name(struct list_head *devices); 41 | 42 | void draw_gpu_info_ncurses(unsigned monitored_dev_count, struct list_head *devices, struct nvtop_interface *interface); 43 | 44 | void save_current_data_to_ring(struct list_head *devices, struct nvtop_interface *interface); 45 | 46 | void update_window_size_to_terminal_size(struct nvtop_interface *inter); 47 | 48 | void interface_key(int keyId, struct nvtop_interface *inter); 49 | 50 | bool is_escape_for_quit(struct nvtop_interface *inter); 51 | 52 | bool interface_freeze_processes(struct nvtop_interface *interface); 53 | 54 | int interface_update_interval(const struct nvtop_interface *interface); 55 | 56 | bool show_information_messages(unsigned num_messages, const char **messages); 57 | 58 | void print_snapshot(struct list_head *devices, bool use_fahrenheit_option); 59 | 60 | #endif // INTERFACE_H_ 61 | -------------------------------------------------------------------------------- /include/nvtop/interface_common.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Copyright (C) 2021 Maxime Schmitt 4 | * 5 | * This file is part of Nvtop. 6 | * 7 | * Nvtop is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * Nvtop is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with nvtop. If not, see . 19 | * 20 | */ 21 | 22 | #ifndef INTERFACE_COMMON_H__ 23 | #define INTERFACE_COMMON_H__ 24 | 25 | enum plot_information { 26 | plot_gpu_rate = 0, 27 | plot_gpu_mem_rate, 28 | plot_encoder_rate, 29 | plot_decoder_rate, 30 | plot_gpu_temperature, 31 | plot_gpu_power_draw_rate, 32 | plot_fan_speed, 33 | plot_gpu_clock_rate, 34 | plot_gpu_mem_clock_rate, 35 | plot_information_count 36 | }; 37 | 38 | typedef int plot_info_to_draw; 39 | 40 | enum process_field { 41 | process_pid = 0, 42 | process_user, 43 | process_gpu_id, 44 | process_type, 45 | process_gpu_rate, 46 | process_enc_rate, 47 | process_dec_rate, 48 | process_memory, 49 | process_cpu_usage, 50 | process_cpu_mem_usage, 51 | process_command, 52 | process_field_count, 53 | }; 54 | 55 | typedef int process_field_displayed; 56 | 57 | #endif // INTERFACE_COMMON_H__ 58 | -------------------------------------------------------------------------------- /include/nvtop/interface_internal_common.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Copyright (C) 2021 Maxime Schmitt 4 | * 5 | * This file is part of Nvtop. 6 | * 7 | * Nvtop is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * Nvtop is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with nvtop. If not, see . 19 | * 20 | */ 21 | 22 | #ifndef INTERFACE_INTERNAL_COMMON_H__ 23 | #define INTERFACE_INTERNAL_COMMON_H__ 24 | 25 | #include "nvtop/common.h" 26 | #include "nvtop/interface_options.h" 27 | #include "nvtop/interface_ring_buffer.h" 28 | #include "nvtop/time.h" 29 | 30 | #include 31 | #include 32 | 33 | #define max(a, b) ((a) > (b) ? (a) : (b)) 34 | #define min(a, b) ((a) < (b) ? (a) : (b)) 35 | #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) 36 | 37 | enum nvtop_option_window_state { 38 | nvtop_option_state_hidden, 39 | nvtop_option_state_kill, 40 | nvtop_option_state_sort_by, 41 | }; 42 | 43 | enum interface_color { 44 | cyan_color = 1, 45 | yellow_color, 46 | magenta_color, 47 | green_color, 48 | red_color, 49 | blue_color, 50 | }; 51 | 52 | struct device_window { 53 | WINDOW *name_win; // Name of the GPU 54 | WINDOW *gpu_util_enc_dec; 55 | WINDOW *gpu_util_no_enc_or_dec; 56 | WINDOW *gpu_util_no_enc_and_dec; 57 | WINDOW *mem_util_enc_dec; 58 | WINDOW *mem_util_no_enc_or_dec; 59 | WINDOW *mem_util_no_enc_and_dec; 60 | WINDOW *encode_util; 61 | WINDOW *decode_util; 62 | WINDOW *encdec_util; 63 | WINDOW *fan_speed; 64 | WINDOW *temperature; 65 | WINDOW *power_info; 66 | WINDOW *gpu_clock_info; 67 | WINDOW *mem_clock_info; 68 | WINDOW *pcie_info; 69 | WINDOW *shader_cores; 70 | WINDOW *l2_cache_size; 71 | WINDOW *exec_engines; 72 | bool enc_was_visible; 73 | bool dec_was_visible; 74 | nvtop_time last_decode_seen; 75 | nvtop_time last_encode_seen; 76 | }; 77 | 78 | static const unsigned int option_window_size = 13; 79 | struct option_window { 80 | enum nvtop_option_window_state state; 81 | enum nvtop_option_window_state previous_state; 82 | unsigned int selected_row; 83 | unsigned int offset; 84 | WINDOW *option_win; 85 | }; 86 | 87 | struct process_window { 88 | unsigned offset; 89 | unsigned offset_column; 90 | WINDOW *process_win; 91 | WINDOW *process_with_option_win; 92 | unsigned selected_row; 93 | pid_t selected_pid; 94 | struct option_window option_window; 95 | }; 96 | 97 | struct plot_window { 98 | size_t num_data; 99 | double *data; 100 | WINDOW *win; 101 | WINDOW *plot_window; 102 | unsigned num_devices_to_plot; 103 | unsigned devices_ids[MAX_LINES_PER_PLOT]; 104 | }; 105 | 106 | enum setup_window_section { 107 | setup_general_selected, 108 | setup_header_selected, 109 | setup_chart_selected, 110 | setup_process_list_selected, 111 | setup_monitored_gpu_list_selected, 112 | setup_window_selection_count 113 | }; 114 | 115 | struct setup_window { 116 | unsigned indentation_level; 117 | enum setup_window_section selected_section; 118 | bool visible; 119 | WINDOW *clean_space; 120 | WINDOW *setup; 121 | WINDOW *single; 122 | WINDOW *split[2]; 123 | unsigned options_selected[2]; 124 | }; 125 | 126 | // Keep gpu information every 1 second for 10 minutes 127 | struct nvtop_interface { 128 | nvtop_interface_option options; 129 | unsigned total_dev_count; 130 | unsigned monitored_dev_count; 131 | struct device_window *devices_win; 132 | struct process_window process; 133 | WINDOW *shortcut_window; 134 | unsigned num_plots; 135 | struct plot_window *plots; 136 | interface_ring_buffer saved_data_ring; 137 | struct setup_window setup_win; 138 | }; 139 | 140 | enum device_field { 141 | device_name = 0, 142 | device_fan_speed, 143 | device_temperature, 144 | device_power, 145 | device_pcie, 146 | device_clock, 147 | device_shadercores, 148 | device_l2features, 149 | device_execengines, 150 | device_field_count, 151 | }; 152 | 153 | inline void set_attribute_between(WINDOW *win, int startY, int startX, int endX, attr_t attr, short pair) { 154 | int rows, cols; 155 | getmaxyx(win, rows, cols); 156 | (void)rows; 157 | if (startX >= cols || endX < 0) 158 | return; 159 | startX = startX < 0 ? 0 : startX; 160 | endX = endX > cols ? cols : endX; 161 | int size = endX - startX; 162 | mvwchgat(win, startY, startX, size, attr, pair, NULL); 163 | } 164 | 165 | #endif // INTERFACE_INTERNAL_COMMON_H__ 166 | -------------------------------------------------------------------------------- /include/nvtop/interface_layout_selection.h: -------------------------------------------------------------------------------- 1 | #ifndef INTERFACE_LAYOUT_SELECTION_H__ 2 | #define INTERFACE_LAYOUT_SELECTION_H__ 3 | 4 | #include "nvtop/interface_common.h" 5 | #include "nvtop/interface_options.h" 6 | 7 | #include 8 | 9 | struct window_position { 10 | unsigned posX, posY, sizeX, sizeY; 11 | }; 12 | 13 | // Should be fine 14 | #define MAX_CHARTS 64 15 | 16 | void compute_sizes_from_layout(unsigned monitored_dev_count, unsigned device_header_rows, unsigned device_header_cols, 17 | unsigned rows, unsigned cols, const nvtop_interface_gpu_opts *gpu_opts, 18 | process_field_displayed process_field_displayed, 19 | struct window_position *device_positions, unsigned *num_plots, 20 | struct window_position plot_positions[MAX_CHARTS], unsigned *map_device_to_plot, 21 | struct window_position *process_position, struct window_position *setup_position, 22 | bool process_win_hide); 23 | 24 | #endif // INTERFACE_LAYOUT_SELECTION_H__ 25 | -------------------------------------------------------------------------------- /include/nvtop/interface_options.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Copyright (C) 2021 Maxime Schmitt 4 | * 5 | * This file is part of Nvtop. 6 | * 7 | * Nvtop is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * Nvtop is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with nvtop. If not, see . 19 | * 20 | */ 21 | 22 | #ifndef INTERFACE_OPTIONS_H__ 23 | #define INTERFACE_OPTIONS_H__ 24 | 25 | #include "nvtop/common.h" 26 | #include "nvtop/extract_gpuinfo_common.h" 27 | #include "nvtop/interface_common.h" 28 | 29 | #include 30 | 31 | typedef struct { 32 | plot_info_to_draw to_draw; // The set of metrics to draw for this gpu 33 | bool doNotMonitor; // True if this GPU should not be monitored 34 | struct gpu_info *linkedGpu; // The gpu to which this option apply 35 | } nvtop_interface_gpu_opts; 36 | 37 | typedef struct nvtop_interface_option_struct { 38 | bool 39 | plot_left_to_right; // true to reverse the plot refresh direction defines inactivity (0 use rate) before hiding it 40 | bool temperature_in_fahrenheit; // Switch from celsius to fahrenheit temperature scale 41 | bool use_color; // Name self explanatory 42 | double encode_decode_hiding_timer; // Negative to always display, positive 43 | nvtop_interface_gpu_opts *gpu_specific_opts; // GPU specific options 44 | char *config_file_location; // Location of the config file 45 | enum process_field sort_processes_by; // Specify the field used to order the processes 46 | bool sort_descending_order; // Sort in descending order 47 | int update_interval; // Interval between interface update in milliseconds 48 | process_field_displayed process_fields_displayed; // Which columns of the 49 | // process list are displayed 50 | bool show_startup_messages; // True to show the startup messages 51 | bool filter_nvtop_pid; // Do not show nvtop pid in the processes list 52 | bool has_monitored_set_changed; // True if the set of monitored gpu was modified through the interface 53 | bool has_gpu_info_bar; // Show info bar with additional GPU parametres 54 | bool hide_processes_list; // Hide processes list 55 | } nvtop_interface_option; 56 | 57 | inline bool plot_isset_draw_info(enum plot_information check_info, plot_info_to_draw to_draw) { 58 | return (to_draw & (1 << check_info)) > 0; 59 | } 60 | 61 | inline unsigned plot_count_draw_info(plot_info_to_draw to_draw) { 62 | unsigned count = 0; 63 | for (int i = plot_gpu_rate; i < plot_information_count; ++i) { 64 | count += plot_isset_draw_info((enum plot_information)i, to_draw); 65 | } 66 | return count; 67 | } 68 | 69 | inline plot_info_to_draw plot_add_draw_info(enum plot_information set_info, plot_info_to_draw to_draw) { 70 | if (plot_count_draw_info(to_draw) < MAX_LINES_PER_PLOT) 71 | return to_draw | (1 << set_info); 72 | else 73 | return to_draw; 74 | } 75 | 76 | inline plot_info_to_draw plot_remove_draw_info(enum plot_information reset_info, plot_info_to_draw to_draw) { 77 | return to_draw & (~(1 << reset_info)); 78 | } 79 | 80 | inline plot_info_to_draw plot_default_draw_info(void) { return (1 << plot_gpu_rate) | (1 << plot_gpu_mem_rate); } 81 | 82 | void alloc_interface_options_internals(char *config_file_location, unsigned num_devices, struct list_head *devices, 83 | nvtop_interface_option *options); 84 | 85 | unsigned interface_check_and_fix_monitored_gpus(unsigned num_devices, struct list_head *monitoredGpus, 86 | struct list_head *nonMonitoredGpus, nvtop_interface_option *options); 87 | 88 | bool load_interface_options_from_config_file(unsigned num_devices, nvtop_interface_option *options); 89 | 90 | bool save_interface_options_to_config_file(unsigned total_dev_count, const nvtop_interface_option *options); 91 | 92 | inline bool process_is_field_displayed(enum process_field field, process_field_displayed fields_displayed) { 93 | return (fields_displayed & (1 << field)) > 0; 94 | } 95 | 96 | inline process_field_displayed process_remove_field_to_display(enum process_field field, 97 | process_field_displayed fields_displayed) { 98 | return fields_displayed & (~(1 << field)); 99 | } 100 | 101 | inline process_field_displayed process_add_field_to_display(enum process_field field, 102 | process_field_displayed fields_displayed) { 103 | return fields_displayed | (1 << field); 104 | } 105 | 106 | inline process_field_displayed process_default_displayed_field(void) { 107 | process_field_displayed to_display = 0; 108 | for (int field = process_pid; field < process_field_count; ++field) { 109 | to_display = process_add_field_to_display((enum process_field)field, to_display); 110 | } 111 | to_display = process_remove_field_to_display(process_enc_rate, to_display); 112 | to_display = process_remove_field_to_display(process_dec_rate, to_display); 113 | return to_display; 114 | } 115 | 116 | inline unsigned process_field_displayed_count(process_field_displayed fields_displayed) { 117 | unsigned displayed_count = 0; 118 | for (int field = process_pid; field < process_field_count; ++field) { 119 | if (process_is_field_displayed((enum process_field)field, fields_displayed)) 120 | displayed_count++; 121 | } 122 | return displayed_count; 123 | } 124 | 125 | enum process_field process_default_sort_by_from(process_field_displayed fields_displayed); 126 | 127 | #endif // INTERFACE_OPTIONS_H__ 128 | -------------------------------------------------------------------------------- /include/nvtop/interface_ring_buffer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Copyright (C) 2021 Maxime Schmitt 4 | * 5 | * This file is part of Nvtop. 6 | * 7 | * Nvtop is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * Nvtop is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with nvtop. If not, see . 19 | * 20 | */ 21 | 22 | #ifndef INTERFACE_RING_BUFFER_H__ 23 | #define INTERFACE_RING_BUFFER_H__ 24 | 25 | #include 26 | 27 | typedef struct interface_ring_buffer_st { 28 | unsigned monitored_dev_count; 29 | unsigned per_device_data_saved; 30 | unsigned buffer_size; 31 | void *ring_buffer[2]; 32 | } interface_ring_buffer; 33 | 34 | #define INTERFACE_RING_BUFFER_DATA(ring_buffer_ptr, name) \ 35 | unsigned(*name)[ring_buffer_ptr->per_device_data_saved][ring_buffer_ptr->buffer_size] = \ 36 | (unsigned(*)[ring_buffer_ptr->per_device_data_saved][ring_buffer_ptr->buffer_size]) \ 37 | ring_buffer_ptr->ring_buffer[1]; 38 | 39 | #define INTERFACE_RING_BUFFER_INDICES(ring_buffer_ptr, name) \ 40 | unsigned(*name)[ring_buffer_ptr->per_device_data_saved][2] = \ 41 | (unsigned(*)[ring_buffer_ptr->per_device_data_saved][2])ring_buffer_ptr->ring_buffer[0]; 42 | 43 | void interface_alloc_ring_buffer(unsigned monitored_dev_count, unsigned per_device_data, unsigned buffer_size, 44 | interface_ring_buffer *ring_buffer); 45 | 46 | void interface_free_ring_buffer(interface_ring_buffer *buffer); 47 | 48 | inline unsigned interface_ring_buffer_data_stored(const interface_ring_buffer *buff, unsigned device, 49 | unsigned which_data) { 50 | INTERFACE_RING_BUFFER_INDICES(buff, indices); 51 | unsigned start = indices[device][which_data][0]; 52 | unsigned end = indices[device][which_data][1]; 53 | unsigned length = end - start; 54 | if (end < start) { // Has wrapped around the buffer 55 | length += buff->buffer_size; 56 | } 57 | return length; 58 | } 59 | 60 | inline unsigned interface_index_in_ring(const interface_ring_buffer *buff, unsigned device, unsigned which_data, 61 | unsigned index) { 62 | assert(interface_ring_buffer_data_stored(buff, device, which_data) > index); 63 | INTERFACE_RING_BUFFER_INDICES(buff, indices); 64 | unsigned start = indices[device][which_data][0]; 65 | unsigned location = start + index; 66 | if (location >= buff->buffer_size) 67 | location -= buff->buffer_size; 68 | return location; 69 | } 70 | 71 | inline unsigned interface_ring_buffer_get(const interface_ring_buffer *buff, unsigned device, unsigned which_data, 72 | unsigned index) { 73 | INTERFACE_RING_BUFFER_DATA(buff, data); 74 | unsigned index_in_ring = interface_index_in_ring(buff, device, which_data, index); 75 | return data[device][which_data][index_in_ring]; 76 | } 77 | 78 | inline void interface_ring_buffer_push(interface_ring_buffer *buff, unsigned device, unsigned which_data, 79 | unsigned value) { 80 | INTERFACE_RING_BUFFER_INDICES(buff, indices); 81 | INTERFACE_RING_BUFFER_DATA(buff, data); 82 | unsigned start = indices[device][which_data][0]; 83 | unsigned end = indices[device][which_data][1]; 84 | // If ring full, move start index 85 | data[device][which_data][end] = value; 86 | end++; 87 | if (end == buff->buffer_size) 88 | end -= buff->buffer_size; 89 | if (end == start) { 90 | start++; 91 | if (start == buff->buffer_size) 92 | start -= buff->buffer_size; 93 | } 94 | indices[device][which_data][0] = start; 95 | indices[device][which_data][1] = end; 96 | } 97 | 98 | inline void interface_ring_buffer_pop(interface_ring_buffer *buff, unsigned device, unsigned which_data) { 99 | INTERFACE_RING_BUFFER_INDICES(buff, indices); 100 | unsigned start = indices[device][which_data][0]; 101 | unsigned end = indices[device][which_data][1]; 102 | if (start != end) { 103 | start++; 104 | if (start == buff->buffer_size) 105 | start -= buff->buffer_size; 106 | indices[device][which_data][0] = start; 107 | } 108 | } 109 | 110 | inline void interface_ring_buffer_empty_select(interface_ring_buffer *buff, unsigned device, unsigned which_data) { 111 | INTERFACE_RING_BUFFER_INDICES(buff, indices); 112 | indices[device][which_data][0] = 0; 113 | indices[device][which_data][1] = 0; 114 | } 115 | 116 | inline void interface_ring_buffer_empty(interface_ring_buffer *buff, unsigned device) { 117 | for (unsigned i = 0; i < buff->per_device_data_saved; ++i) { 118 | interface_ring_buffer_empty_select(buff, device, i); 119 | } 120 | } 121 | 122 | #endif // INTERFACE_RING_BUFFER_H__ 123 | -------------------------------------------------------------------------------- /include/nvtop/interface_setup_win.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Copyright (C) 2021 Maxime Schmitt 4 | * 5 | * This file is part of Nvtop. 6 | * 7 | * Nvtop is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * Nvtop is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with nvtop. If not, see . 19 | * 20 | */ 21 | 22 | #ifndef INTERFACE_SETUP_WIN_H__ 23 | #define INTERFACE_SETUP_WIN_H__ 24 | 25 | #include "nvtop/extract_gpuinfo.h" 26 | #include "nvtop/interface_internal_common.h" 27 | #include "nvtop/interface_layout_selection.h" 28 | 29 | void alloc_setup_window(struct window_position *position, struct setup_window *setup_win); 30 | 31 | void free_setup_window(struct setup_window *setup_win); 32 | 33 | void show_setup_window(struct nvtop_interface *interface); 34 | 35 | void hide_setup_window(struct nvtop_interface *interface); 36 | 37 | void draw_setup_window(unsigned monitored_dev_count, struct list_head *devices, struct nvtop_interface *interface); 38 | 39 | void draw_setup_window_shortcuts(struct nvtop_interface *interface); 40 | 41 | void handle_setup_win_keypress(int keyId, struct nvtop_interface *interface); 42 | 43 | #endif // INTERFACE_SETUP_WIN_H__ 44 | -------------------------------------------------------------------------------- /include/nvtop/plot.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Copyright (C) 2018 Maxime Schmitt 4 | * 5 | * This file is part of Nvtop. 6 | * 7 | * Nvtop is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * Nvtop is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with nvtop. If not, see . 19 | * 20 | */ 21 | 22 | #ifndef __PLOT_H_ 23 | #define __PLOT_H_ 24 | 25 | #include "nvtop/common.h" 26 | 27 | #include 28 | #include 29 | #include 30 | 31 | #define PLOT_MAX_LEGEND_SIZE 35 32 | 33 | void nvtop_line_plot(WINDOW *win, size_t num_data, const double *data, unsigned num_plots, bool legend_left, 34 | char legend[MAX_LINES_PER_PLOT][PLOT_MAX_LEGEND_SIZE]); 35 | 36 | void draw_rectangle(WINDOW *win, unsigned startX, unsigned startY, unsigned sizeX, unsigned sizeY); 37 | 38 | #endif // __PLOT_H_ 39 | -------------------------------------------------------------------------------- /include/nvtop/time.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Copyright (C) 2018-2022 Maxime Schmitt 4 | * 5 | * This file is part of Nvtop. 6 | * 7 | * Nvtop is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * Nvtop is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with nvtop. If not, see . 19 | * 20 | */ 21 | 22 | #ifndef NVTOP_TIME_H_ 23 | #define NVTOP_TIME_H_ 24 | 25 | #include 26 | #include 27 | #include 28 | 29 | #ifdef CLOCK_MONOTONIC_RAW 30 | #define NVTOP_CLOCK CLOCK_MONOTONIC_RAW 31 | #else 32 | #define NVTOP_CLOCK CLOCK_MONOTONIC 33 | #endif 34 | 35 | typedef struct timespec nvtop_time; 36 | 37 | inline void nvtop_get_current_time(nvtop_time *time) { clock_gettime(NVTOP_CLOCK, time); } 38 | 39 | inline double nvtop_difftime(nvtop_time t0, nvtop_time t1) { 40 | double secdiff = difftime(t1.tv_sec, t0.tv_sec); 41 | if (t1.tv_nsec < t0.tv_nsec) { 42 | long val = 1000000000l - t0.tv_nsec + t1.tv_nsec; 43 | secdiff += (double)val / 1e9 - 1.; 44 | } else { 45 | long val = t1.tv_nsec - t0.tv_nsec; 46 | secdiff += (double)val / 1e9; 47 | } 48 | return secdiff; 49 | } 50 | 51 | inline uint64_t nvtop_time_u64(nvtop_time t0) { return (uint64_t)(t0.tv_sec) * UINT64_C(1000000000) + t0.tv_nsec; } 52 | 53 | inline uint64_t nvtop_difftime_u64(nvtop_time t0, nvtop_time t1) { 54 | return (uint64_t)(t1.tv_sec - t0.tv_sec) * UINT64_C(1000000000) + (uint64_t)t1.tv_nsec - (uint64_t)t0.tv_nsec; 55 | } 56 | 57 | inline nvtop_time nvtop_hmns_to_time(unsigned hour, unsigned minutes, unsigned long nanosec) { 58 | nvtop_time t = {hour * 60 * 60 + 60 * minutes + nanosec / 1000000, nanosec % 1000000}; 59 | return t; 60 | } 61 | 62 | inline nvtop_time nvtop_substract_time(nvtop_time t0, nvtop_time t1) { 63 | nvtop_time t = t0.tv_nsec - t1.tv_nsec < 0 64 | ? (nvtop_time){t0.tv_sec - t1.tv_sec - 1, t0.tv_nsec - t1.tv_nsec + 1000000} 65 | : (nvtop_time){t0.tv_sec - t1.tv_sec, t0.tv_nsec - t1.tv_nsec}; 66 | return t; 67 | } 68 | 69 | inline nvtop_time nvtop_add_time(nvtop_time t0, nvtop_time t1) { 70 | nvtop_time t = t0.tv_nsec + t1.tv_nsec > 1000000 71 | ? (nvtop_time){t0.tv_sec + t1.tv_sec + 1, t0.tv_nsec + t1.tv_nsec - 1000000} 72 | : (nvtop_time){t0.tv_sec + t1.tv_sec, t0.tv_nsec + t1.tv_nsec}; 73 | return t; 74 | } 75 | 76 | #endif // NVTOP_TIME_H_ 77 | -------------------------------------------------------------------------------- /include/nvtop/version.h.in: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Copyright (C) 2018 Maxime Schmitt 4 | * 5 | * This file is part of Nvtop. 6 | * 7 | * Nvtop is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * Nvtop is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with nvtop. If not, see . 19 | * 20 | */ 21 | 22 | #ifndef __NVTOP_VERSION_H_ 23 | #define __NVTOP_VERSION_H_ 24 | 25 | #define NVTOP_VERSION_MAJOR @nvtop_VERSION_MAJOR@ 26 | #define NVTOP_VERSION_MINOR @nvtop_VERSION_MINOR@ 27 | #define NVTOP_VERSION_PATCH @nvtop_VERSION_PATCH@ 28 | 29 | #define NVTOP_VERSION_STRING "@nvtop_VERSION_MAJOR@.@nvtop_VERSION_MINOR@.@nvtop_VERSION_PATCH@" 30 | 31 | #endif // __NVTOP_VERSION_H_ 32 | -------------------------------------------------------------------------------- /manpage/nvtop.in: -------------------------------------------------------------------------------- 1 | .\" Manpage for nvtop 2 | .\" Contact maxime.schmitt91@gmail.com 3 | 4 | .TH nvtop 1 "@TODAY_MANPAGE@" "Version @nvtop_VERSION_MAJOR@.@nvtop_VERSION_MINOR@.@nvtop_VERSION_PATCH@" "nvtop command" 5 | 6 | .SH NAME 7 | nvtop \- interactive GPU process viewer 8 | 9 | .SH SYNOPSIS 10 | .B nvtop 11 | \fR[\fB\-hv\fR] 12 | \fR[\fB\-d\fR \fIdelay\fR] 13 | 14 | .SH DESCRIPTION 15 | nvtop is a ncurses\-based GPU status viewer for AMD, Intel and NVIDIA GPUs. 16 | 17 | .SH COMMAND\-LINE OPTIONS 18 | .TP 19 | .BR \-d ", " \-\-delay =\fIdelay\fR 20 | Delay between updates, in tenths of seconds (\fIdelay\fR * 0.1s). 21 | .TP 22 | .BR \-h ", " \-\-help 23 | Print the help and exit. 24 | .TP 25 | .BR \-C ", " \-\-no\-color 26 | Monochrome mode. 27 | .TP 28 | .BR \-f ", " \-\-freedom\-unit 29 | Use fahrenheit as temperature scale. 30 | .TP 31 | .BR \-E ", " \-\-encode\-hide =\fIseconds\fR 32 | Modify the setting for the encode/decode auto-hide timer. Always visible if negative. Default to 30 seconds. 33 | .TP 34 | .BR \-r ", " \-\-reverse\-abs 35 | Reverse abscissa: switch the plot data order from "old --- recent" (default) to "recent --- old". 36 | .TP 37 | .BR \-p ", " \-\-no\-plot 38 | Show only one bar plot corresponding to the maximum of all GPUs. 39 | .TP 40 | .BR \-v ", " \-\-version 41 | Print the version and exit. 42 | 43 | .SH INTERACTIVE SETUP WINDOW 44 | .TP 45 | You can enter the setup utility by pressing \fBF2\fR to view and modify the following interface options: 46 | .TP 47 | .I General 48 | This section deals with general interface options. \fBColor support\fR and \fBinterface update interval\fR can be modified. 49 | .TP 50 | .I Devices 51 | This section deals with the devices display (top of the interface). You can \fBswitch the temperature scale to fahrenheit\fR and \fBset the encoder/decoder hiding timer\fR. 52 | .TP 53 | .I Chart 54 | This section deals with the line plots (middle of the interface). You can \fBreverse the plot direction\fR and \fBselect which metric is being shown in the plots\fR. 55 | .TP 56 | .I Processes 57 | This section deals with the process list (bottom of the interface). You can \fBselect the sort order\fR, \fBselect the metric by which to sort the processes by\fR and \fBselect which metric is displayed\fR. 58 | 59 | .SH INTERACTIVE COMMANDS 60 | .TP 61 | The following commands are available while in nvtop: 62 | .TP 63 | .BR Up 64 | Select (highlight) the previous process. 65 | .TP 66 | .BR Down 67 | Select (highlight) the next process. 68 | .TP 69 | .BR Left\ /\ Right 70 | Scroll in the process row. 71 | .TP 72 | .BR + 73 | Sort increasingly. 74 | .TP 75 | .BR - 76 | Sort decreasingly. 77 | .TP 78 | .BR F2 79 | Enter the setup utility to modify the interface options. 80 | .TP 81 | .BR F12 82 | Save the current interface options to persistent storage. 83 | See the \fBCONFIGURATION FILE\fR section. 84 | .TP 85 | .BR F9 86 | "Kill" process: Select a signal to send to the highlighted process. 87 | .TP 88 | .BR F6 89 | Sort: Select the field for sorting. The current sort field is highlighted inside the header bar. 90 | .TP 91 | .BR F10 ", " q ", " Esc 92 | Quit. 93 | 94 | .SH DYNAMIC METERS 95 | .TP 96 | When the video encoder (ENC) and decoder (DEC) of the GPU are in use, new percentage meters will appear next to the GPU utilization bar. They will disappear automatically after some time of inactivity (see option -E). 97 | 98 | .SH CONFIGURATION FILE 99 | .LP 100 | The configuration file follows the \fIXDG Base Directory Specification\fR and is stored at \fI$XDG_CONFIG_HOME/nvtop/interface.ini\fR. The location defaults to \fI$HOME/.config/nvtop/interface.ini\fR if the XDG location is not defined. 101 | .LP 102 | Do not edit this file. The file is automatically created or updated upon toggling the interface saving key \fBF12\fR. 103 | .LP 104 | The configuration is loaded during program initialization. 105 | If no configuration file is present, default options are used. 106 | 107 | .SH MEMORY SIZES 108 | .TP 109 | Memory sizes in nvtop are displayed as multiples of 1024 bytes or 1 KiB. 110 | 111 | .SH BUGS 112 | .TP 113 | .BR "Some fields are shown as N/A" 114 | Ask AMD or NVIDIA for better support of your hardware! 115 | 116 | If your card uses the AMDGPU driver, a more recent kernel might have improved support. 117 | .TP 118 | .BR "Compatibility issues" 119 | Does not work with nouveau driver stack and older NVIDIA GPU for the time being. 120 | 121 | Does not work for AMD graphics card using the old radeon driver. 122 | .SH AUTHOR 123 | Written by Maxime Schmitt. 124 | -------------------------------------------------------------------------------- /screenshot/NVTOP_ex1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Syllo/nvtop/79592102699891161d81c59a8964c54349812d3f/screenshot/NVTOP_ex1.png -------------------------------------------------------------------------------- /screenshot/Nvtop-config.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Syllo/nvtop/79592102699891161d81c59a8964c54349812d3f/screenshot/Nvtop-config.png -------------------------------------------------------------------------------- /snap/snapcraft.yaml: -------------------------------------------------------------------------------- 1 | name: nvtop 2 | base: core22 3 | adopt-info: nvtop 4 | summary: 'GPUs monitoring tool for AMD, Intel and NVIDIA' 5 | description: | 6 | Nvtop stands for Neat Videocard TOP, a (h)top like task monitor for AMD, Intel and NVIDIA GPUs. It can handle multiple GPUs and print information about them in a htop familiar way. 7 | license: GPL-3.0-or-later 8 | issues: https://github.com/Syllo/nvtop/issues 9 | icon: desktop/nvtop.svg 10 | grade: stable 11 | confinement: strict 12 | architectures: 13 | - build-on: amd64 14 | - build-on: arm64 15 | - build-on: armhf 16 | - build-on: ppc64el 17 | - build-on: s390x 18 | compression: lzo 19 | apps: 20 | nvtop: 21 | command: usr/bin/nvtop 22 | desktop: usr/share/applications/nvtop.desktop 23 | plugs: 24 | - opengl 25 | - home 26 | - hardware-observe 27 | - process-control 28 | - system-observe 29 | # - kubernetes-support # Temporarily required for nvtop to display AMD GPU processes. Once apparmor rule to allow access to @{PROC}/[0-9]*/fdinfo/ is added to system-observe, this can be removed. 30 | # layout: 31 | # /usr/share/libdrm: 32 | # symlink: $SNAP/usr/share/libdrm 33 | parts: 34 | libdrm: 35 | source: https://gitlab.freedesktop.org/mesa/drm.git 36 | source-tag: libdrm-2.4.113 37 | plugin: meson 38 | meson-parameters: 39 | - --prefix=/usr 40 | - --sysconfdir=/etc 41 | - --libdir=lib/$CRAFT_ARCH_TRIPLET 42 | - -Dradeon=enabled 43 | - -Damdgpu=enabled 44 | - -Dudev=true 45 | - -Dnouveau=enabled 46 | - -Dintel=enabled 47 | build-packages: 48 | - meson 49 | - pkg-config 50 | - libudev-dev 51 | - libpciaccess-dev 52 | stage-packages: 53 | - libpciaccess0 54 | prime: 55 | - -usr/include 56 | - -usr/lib/$CRAFT_ARCH_TRIPLET/pkgconfig 57 | nvtop: 58 | after: [ libdrm ] 59 | source: . 60 | plugin: cmake 61 | cmake-parameters: 62 | - -DCMAKE_INSTALL_PREFIX=/usr 63 | - -DNVIDIA_SUPPORT=ON 64 | - -DAMDGPU_SUPPORT=ON 65 | - -DINTEL_SUPPORT=ON 66 | override-pull: | 67 | set -eux 68 | craftctl default 69 | VERSION="$(git describe --tags $(git rev-list --tags --max-count=1))" 70 | craftctl set version=$VERSION 71 | git checkout $VERSION 72 | build-snaps: 73 | - cmake 74 | build-packages: 75 | - gcc 76 | - libncurses-dev 77 | - libsystemd-dev 78 | stage-packages: 79 | - libncurses6 80 | - libncursesw6 81 | - libsystemd0 82 | prime: 83 | - -usr/share/doc 84 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | include(CheckCSourceCompiles) 2 | 3 | configure_file( 4 | "${PROJECT_SOURCE_DIR}/include/nvtop/version.h.in" 5 | "${PROJECT_BINARY_DIR}/include/nvtop/version.h" 6 | IMMEDIATE @ONLY) 7 | 8 | add_executable(nvtop 9 | nvtop.c 10 | interface.c 11 | interface_layout_selection.c 12 | interface_options.c 13 | interface_setup_win.c 14 | interface_ring_buffer.c 15 | extract_gpuinfo.c 16 | time.c 17 | plot.c 18 | ini.c 19 | ) 20 | 21 | check_c_source_compiles( 22 | " 23 | #include 24 | int main() { 25 | int *buf = NULL; 26 | buf = reallocarray(buf, 15, sizeof(*buf)); 27 | return EXIT_SUCCESS; 28 | } 29 | " 30 | HAS_REALLOCARRAY 31 | ) 32 | 33 | if(HAS_REALLOCARRAY) 34 | target_compile_definitions(nvtop PRIVATE HAS_REALLOCARRAY) 35 | endif() 36 | 37 | find_package(UDev) 38 | find_package(Systemd) 39 | option(USE_LIBUDEV_OVER_LIBSYSTEMD "Use libudev, even if libsystemd is present" OFF) 40 | 41 | if(UNIX AND NOT APPLE) 42 | target_sources(nvtop PRIVATE 43 | get_process_info_linux.c 44 | extract_processinfo_fdinfo.c 45 | info_messages_linux.c) 46 | elseif(APPLE) 47 | target_sources(nvtop PRIVATE 48 | get_process_info_mac.c 49 | extract_processinfo_mac.c 50 | info_messages_mac.c) 51 | endif() 52 | 53 | if(NVIDIA_SUPPORT) 54 | target_sources(nvtop PRIVATE extract_gpuinfo_nvidia.c) 55 | endif() 56 | 57 | if(ASCEND_SUPPORT) 58 | target_sources(nvtop PRIVATE extract_gpuinfo_ascend.c) 59 | set(DCMI_LIBRARY_PATH /usr/local/Ascend/driver/lib64/driver) 60 | target_link_libraries(nvtop PRIVATE "${DCMI_LIBRARY_PATH}/libdcmi.so") 61 | endif() 62 | 63 | if(AMDGPU_SUPPORT OR INTEL_SUPPORT OR V3D_SUPPORT) 64 | if((SYSTEMD_FOUND AND UDEV_FOUND AND USE_LIBUDEV_OVER_LIBSYSTEMD) OR(NOT SYSTEMD_FOUND AND UDEV_FOUND)) 65 | target_compile_definitions(nvtop PRIVATE USING_LIBUDEV) 66 | target_link_libraries(nvtop PRIVATE udev) 67 | elseif(SYSTEMD_FOUND) 68 | target_compile_definitions(nvtop PRIVATE USING_LIBSYSTEMD) 69 | target_link_libraries(nvtop PRIVATE systemd) 70 | else() 71 | message(FATAL_ERROR "Neither libsystemd nor libudev were found; These are required for AMDGPU, INTEL and V3D support") 72 | endif() 73 | 74 | target_sources(nvtop PRIVATE device_discovery_linux.c) 75 | endif() 76 | 77 | if(AMDGPU_SUPPORT OR INTEL_SUPPORT OR MSM_SUPPORT OR PANFROST_SUPPORT OR PANTHOR_SUPPORT) 78 | # Search for libdrm for AMDGPU support 79 | find_package(Libdrm) 80 | 81 | if(Libdrm_FOUND) 82 | message(STATUS "Found libdrm; Enabling support") 83 | target_include_directories(nvtop PRIVATE ${Libdrm_INCLUDE_DIRS}) 84 | else() 85 | message(FATAL_ERROR "libdrm not found; This library is required for AMDGPU, INTEL, MSM, PANFROST and PANTHOR support") 86 | # CMake will exit if libdrm is not found 87 | endif() 88 | endif() 89 | 90 | if (AMDGPU_SUPPORT) 91 | target_sources(nvtop PRIVATE extract_gpuinfo_amdgpu.c) 92 | target_sources(nvtop PRIVATE extract_gpuinfo_amdgpu_utils.c) 93 | endif() 94 | 95 | if (MSM_SUPPORT) 96 | target_sources(nvtop PRIVATE extract_gpuinfo_msm.c) 97 | target_sources(nvtop PRIVATE extract_gpuinfo_msm_utils.c) 98 | endif() 99 | 100 | if(INTEL_SUPPORT) 101 | target_sources(nvtop PRIVATE extract_gpuinfo_intel.c) 102 | target_sources(nvtop PRIVATE extract_gpuinfo_intel_i915.c) 103 | target_sources(nvtop PRIVATE extract_gpuinfo_intel_xe.c) 104 | endif() 105 | 106 | if(V3D_SUPPORT) 107 | target_sources(nvtop PRIVATE extract_gpuinfo_v3d.c) 108 | target_sources(nvtop PRIVATE extract_gpuinfo_v3d_utils.c) 109 | endif() 110 | 111 | if(APPLE_SUPPORT) 112 | target_sources(nvtop PRIVATE extract_gpuinfo_apple.m) 113 | target_link_libraries(nvtop PRIVATE 114 | "-framework Metal" 115 | "-framework AppKit" 116 | "-framework Foundation" 117 | "-framework QuartzCore" 118 | "-framework IOKit") 119 | endif() 120 | 121 | if (PANFROST_SUPPORT) 122 | target_sources(nvtop PRIVATE extract_gpuinfo_panfrost.c) 123 | target_sources(nvtop PRIVATE extract_gpuinfo_panfrost_utils.c) 124 | endif() 125 | 126 | if (PANTHOR_SUPPORT) 127 | target_sources(nvtop PRIVATE extract_gpuinfo_panthor.c) 128 | target_sources(nvtop PRIVATE extract_gpuinfo_panthor_utils.c) 129 | endif() 130 | 131 | if ((PANFROST_SUPPORT) OR (PANTHOR_SUPPORT)) 132 | target_sources(nvtop PRIVATE extract_gpuinfo_mali_common.c) 133 | endif() 134 | 135 | if(TPU_SUPPORT) 136 | find_library(LIBTPUINFO 137 | NAMES libtpuinfo.so 138 | PATHS /usr/lib /usr/lib64 /usr/local/lib /usr/local/lib64 139 | HINTS ${CMAKE_INSTALL_PREFIX}/lib ${CMAKE_INSTALL_PREFIX}/lib64 lib lib64 140 | ) 141 | if (NOT LIBTPUINFO) 142 | message(WARNING "TPU Support enabled, but libtpuinfo.so not found in ldconfig path, we will not be able to read TPU usage") 143 | set(TPU_SUPPORT_DEFAULT OFF) 144 | endif() 145 | target_sources(nvtop PRIVATE extract_gpuinfo_tpu.c) 146 | endif() 147 | 148 | target_include_directories(nvtop PRIVATE 149 | ${PROJECT_SOURCE_DIR}/include 150 | ${PROJECT_BINARY_DIR}/include) 151 | 152 | find_package(Sanitizers) 153 | 154 | add_sanitizers(nvtop) 155 | 156 | set_property(TARGET nvtop PROPERTY C_STANDARD 11) 157 | 158 | target_compile_definitions(nvtop PRIVATE _GNU_SOURCE) 159 | 160 | target_link_libraries(nvtop 161 | PRIVATE ncurses m ${CMAKE_DL_LIBS}) 162 | 163 | install(TARGETS nvtop 164 | RUNTIME DESTINATION bin) 165 | 166 | include(compile-flags-helpers) 167 | include(${PROJECT_SOURCE_DIR}/cmake/optimization_flags.cmake) 168 | 169 | add_compiler_option_to_target_type(nvtop Debug PRIVATE ${ADDITIONAL_DEBUG_COMPILE_OPTIONS}) 170 | add_linker_option_to_all_but_target_type(nvtop dummy PRIVATE ${ADDITIONAL_RELEASE_LINK_OPTIONS}) 171 | -------------------------------------------------------------------------------- /src/extract_gpuinfo_amdgpu_utils.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Advanced Micro Devices, Inc. All rights reserved. 3 | * 4 | * MIT License. 5 | */ 6 | 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include 17 | #include 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #include "amdgpu_ids.h" 25 | 26 | const char *amdgpu_parse_marketing_name(struct amdgpu_gpu_info *info); 27 | 28 | const char * amdgpu_parse_marketing_name(struct amdgpu_gpu_info *info) 29 | { 30 | int i; 31 | int ntypes = sizeof(amdgpu_ids) / sizeof(amdgpu_ids[0]); 32 | 33 | if (!info) 34 | return NULL; 35 | 36 | for (i = 0; i < ntypes; i++) { 37 | if (info->asic_id == amdgpu_ids[i].asic_id && info->pci_rev_id == amdgpu_ids[i].pci_rev_id) { 38 | return amdgpu_ids[i].name; 39 | } 40 | } 41 | 42 | return NULL; 43 | } 44 | -------------------------------------------------------------------------------- /src/extract_gpuinfo_intel.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define HASH_FIND_CLIENT(head, key_ptr, out_ptr) HASH_FIND(hh, head, key_ptr, sizeof(struct unique_cache_id), out_ptr) 5 | #define HASH_ADD_CLIENT(head, in_ptr) HASH_ADD(hh, head, client_id, sizeof(struct unique_cache_id), in_ptr) 6 | 7 | #define SET_INTEL_CACHE(cachePtr, field, value) SET_VALUE(cachePtr, field, value, intel_cache_) 8 | #define RESET_INTEL_CACHE(cachePtr, field) INVALIDATE_VALUE(cachePtr, field, intel_cache_) 9 | #define INTEL_CACHE_FIELD_VALID(cachePtr, field) VALUE_IS_VALID(cachePtr, field, intel_cache_) 10 | 11 | enum intel_process_info_cache_valid { 12 | intel_cache_engine_render_valid = 0, 13 | intel_cache_engine_copy_valid, 14 | intel_cache_engine_video_valid, 15 | intel_cache_engine_video_enhance_valid, 16 | intel_cache_engine_compute_valid, 17 | intel_cache_gpu_cycles_valid, 18 | intel_cache_total_cycles_valid, 19 | intel_cache_process_info_cache_valid_count 20 | }; 21 | 22 | struct __attribute__((__packed__)) unique_cache_id { 23 | unsigned client_id; 24 | pid_t pid; 25 | char *pdev; 26 | }; 27 | 28 | union intel_cycles { 29 | struct { 30 | uint64_t rcs; 31 | uint64_t vcs; 32 | uint64_t vecs; 33 | uint64_t bcs; 34 | uint64_t ccs; 35 | }; 36 | uint64_t array[5]; 37 | }; 38 | 39 | struct intel_process_info_cache { 40 | struct unique_cache_id client_id; 41 | uint64_t engine_render; 42 | uint64_t engine_copy; 43 | uint64_t engine_video; 44 | uint64_t engine_video_enhance; 45 | uint64_t engine_compute; 46 | union intel_cycles gpu_cycles; 47 | union intel_cycles total_cycles; 48 | nvtop_time last_measurement_tstamp; 49 | unsigned char valid[(intel_cache_process_info_cache_valid_count + CHAR_BIT - 1) / CHAR_BIT]; 50 | UT_hash_handle hh; 51 | }; 52 | 53 | struct gpu_info_intel { 54 | struct gpu_info base; 55 | enum { DRIVER_I915, DRIVER_XE } driver; 56 | 57 | struct nvtop_device *card_device; 58 | int card_fd; 59 | 60 | struct nvtop_device *driver_device; 61 | struct nvtop_device *hwmon_device; 62 | struct intel_process_info_cache *last_update_process_cache, *current_update_process_cache; // Cached processes info 63 | 64 | struct nvtop_device *bridge_device; 65 | 66 | struct { 67 | unsigned energy_uj; 68 | struct timespec time; 69 | } energy; 70 | }; 71 | 72 | extern void gpuinfo_intel_i915_refresh_dynamic_info(struct gpu_info *_gpu_info); 73 | extern void gpuinfo_intel_xe_refresh_dynamic_info(struct gpu_info *_gpu_info); 74 | 75 | extern bool parse_drm_fdinfo_intel_i915(struct gpu_info *info, FILE *fdinfo_file, struct gpu_process *process_info); 76 | extern bool parse_drm_fdinfo_intel_xe(struct gpu_info *info, FILE *fdinfo_file, struct gpu_process *process_info); 77 | -------------------------------------------------------------------------------- /src/extract_gpuinfo_msm_utils.c: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Copyright (C) 2023 Ryan Houdek 4 | * 5 | * Nvtop is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * Nvtop is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with nvtop. If not, see . 17 | * 18 | */ 19 | 20 | #include "nvtop/interface_internal_common.h" 21 | #include 22 | 23 | struct msm_id_struct { 24 | uint64_t id; 25 | const char *name; 26 | }; 27 | 28 | #define GetHundredDigit(coreid) (coreid / 100) 29 | #define GetHundred(coreid) (GetHundredDigit(coreid) * 100) 30 | #define GetTenDigit(coreid) ((coreid - GetHundred(coreid)) / 10) 31 | #define GetTen(coreid) (GetTenDigit(coreid) * 10) 32 | #define GetOneDigit(coreid) (coreid - (GetHundred(coreid) + GetTen(coreid))) 33 | 34 | #define CHIPID(coreid) \ 35 | (GetHundredDigit(coreid) << 24) | \ 36 | (GetTenDigit(coreid) << 16) | \ 37 | (GetOneDigit(coreid) << 8) 38 | 39 | static const struct msm_id_struct msm_ids[] = { 40 | // Adreno 2xx 41 | {CHIPID(200), "Adreno 200"}, 42 | {CHIPID(201), "Adreno 201"}, 43 | {CHIPID(205), "Adreno 205"}, 44 | {CHIPID(220), "Adreno 220"}, 45 | 46 | // Adreno 3xx 47 | {CHIPID(305), "Adreno 305"}, 48 | {CHIPID(307), "Adreno 307"}, 49 | {CHIPID(320), "Adreno 320"}, 50 | {CHIPID(330), "Adreno 330"}, 51 | 52 | // Adreno 4xx 53 | {CHIPID(405), "Adreno 405"}, 54 | {CHIPID(420), "Adreno 420"}, 55 | {CHIPID(430), "Adreno 430"}, 56 | 57 | // Adreno 5xx 58 | {CHIPID(508), "Adreno 508"}, 59 | {CHIPID(509), "Adreno 509"}, 60 | {CHIPID(510), "Adreno 510"}, 61 | {CHIPID(512), "Adreno 512"}, 62 | {CHIPID(530), "Adreno 530"}, 63 | {CHIPID(540), "Adreno 540"}, 64 | 65 | // Adreno 6xx 66 | {CHIPID(615), "Adreno 615"}, 67 | {CHIPID(616), "Adreno 616"}, 68 | {CHIPID(618), "Adreno 618"}, 69 | {CHIPID(619), "Adreno 619"}, 70 | {CHIPID(620), "Adreno 620"}, 71 | {CHIPID(630), "Adreno 630"}, 72 | {CHIPID(640), "Adreno 640"}, 73 | // QCM6490 74 | {0x00ac06030500, "Adreno 643"}, 75 | {CHIPID(650), "Adreno 650"}, 76 | {CHIPID(660), "Adreno 660"}, 77 | {CHIPID(680), "Adreno 680"}, 78 | {CHIPID(690), "Adreno 690"}, 79 | // no-speedbin Adreno 690 80 | {0xffff06090000, "Adreno 690"}, 81 | 82 | // Adreno 7xx 83 | {CHIPID(730), "Adreno 730"}, 84 | {CHIPID(740), "Adreno 740"}, 85 | {CHIPID(750), "Adreno 750"}, 86 | {CHIPID(790), "Adreno 750"}, 87 | 88 | // Misc 89 | {0x00be06030500, "Adreno 8c Gen 3"}, 90 | {0x007506030500, "Adreno 7c+ Gen 3"}, 91 | {0x006006030500, "Adreno 7c+ Gen 3 Lite"}, 92 | {0x000043051401, "Adreno 750"}, 93 | }; 94 | 95 | const char * msm_parse_marketing_name(uint64_t gpu_id); 96 | 97 | const char * msm_parse_marketing_name(uint64_t gpu_id) { 98 | for (unsigned i = 0; i < ARRAY_SIZE(msm_ids); i++) { 99 | if (gpu_id == msm_ids[i].id) { 100 | return msm_ids[i].name; 101 | } 102 | } 103 | 104 | return NULL; 105 | } 106 | -------------------------------------------------------------------------------- /src/extract_gpuinfo_panfrost_utils.c: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Copyright (C) 2023 Adrian Larumbe 4 | * 5 | * Nvtop is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * Nvtop is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with nvtop. If not, see . 17 | * 18 | */ 19 | 20 | #include 21 | #include "nvtop/interface_internal_common.h" 22 | #include "panfrost_utils.h" 23 | 24 | struct panfrost_model { 25 | const char *name; 26 | unsigned int id; 27 | unsigned int (*nengines) (int32_t core_count, uint32_t core_features, uint32_t thread_features); 28 | }; 29 | 30 | static uint32_t get_num_eng_g52(int core_count, 31 | uint32_t core_features, 32 | uint32_t thread_features) 33 | { 34 | (void) core_count; 35 | (void) thread_features; 36 | return core_features & 0xF; 37 | } 38 | 39 | #define GPU_MODEL(_name, _id, _nengines) \ 40 | { \ 41 | .name = #_name, \ 42 | .id = _id, \ 43 | .nengines = _nengines, \ 44 | } 45 | 46 | static const struct panfrost_model gpu_models[] = { 47 | GPU_MODEL(t600, 0x600, NULL), 48 | GPU_MODEL(t620, 0x620, NULL), 49 | GPU_MODEL(t720, 0x720, NULL), 50 | GPU_MODEL(t760, 0x750, NULL), 51 | GPU_MODEL(t820, 0x820, NULL), 52 | GPU_MODEL(t830, 0x830, NULL), 53 | GPU_MODEL(t860, 0x860, NULL), 54 | GPU_MODEL(t880, 0x880, NULL), 55 | GPU_MODEL(g71, 0x6000, NULL), 56 | GPU_MODEL(g72, 0x6001, NULL), 57 | GPU_MODEL(g51, 0x7000, NULL), 58 | GPU_MODEL(g76, 0x7001, NULL), 59 | GPU_MODEL(g52, 0x7002, get_num_eng_g52), 60 | GPU_MODEL(g31, 0x7003, NULL), 61 | GPU_MODEL(g57, 0x9001, NULL), 62 | GPU_MODEL(g57, 0x9003, NULL), 63 | }; 64 | 65 | static inline int panfrost_model_cmp(unsigned int match, unsigned int id) 66 | { 67 | if (match & 0xf000) 68 | match &= 0xf00f; 69 | return match - id; 70 | } 71 | 72 | const char * panfrost_parse_marketing_name(uint64_t gpu_id) 73 | { 74 | for (unsigned i = 0; i < ARRAY_SIZE(gpu_models); i++) { 75 | if (!panfrost_model_cmp(gpu_id, gpu_models[i].id)) { 76 | return gpu_models[i].name; 77 | } 78 | } 79 | return NULL; 80 | } 81 | 82 | unsigned int get_number_engines(uint32_t gpu_id, 83 | int core_count, 84 | uint32_t core_features, 85 | uint32_t thread_features) 86 | { 87 | for (unsigned i = 0; i < ARRAY_SIZE(gpu_models); i++) { 88 | if (!panfrost_model_cmp(gpu_id, gpu_models[i].id)) { 89 | if (gpu_models[i].nengines) 90 | return gpu_models[i].nengines(core_count, core_features, thread_features); 91 | else 92 | return 0; 93 | } 94 | } 95 | return 0; 96 | } 97 | 98 | unsigned int util_last_bit(unsigned int u) 99 | { 100 | #if defined(HAVE___BUILTIN_CLZ) 101 | return u == 0 ? 0 : 32 - __builtin_clz(u); 102 | #elif defined(_MSC_VER) && (_M_IX86 || _M_ARM || _M_AMD64 || _M_IA64) 103 | unsigned long index; 104 | if (_BitScanReverse(&index, u)) 105 | return index + 1; 106 | else 107 | return 0; 108 | #else 109 | unsigned r = 0; 110 | while (u) { 111 | r++; 112 | u >>= 1; 113 | } 114 | return r; 115 | #endif 116 | } 117 | -------------------------------------------------------------------------------- /src/extract_gpuinfo_panthor.c: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Copyright (C) 2023 Adrian Larumbe 4 | * 5 | * This file is part of Nvtop and adapted from the msm implementation. 6 | * 7 | * Nvtop is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * Nvtop is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with nvtop. If not, see . 19 | * 20 | */ 21 | #include 22 | 23 | #include "nvtop/device_discovery.h" 24 | #include "nvtop/extract_gpuinfo_common.h" 25 | #include "nvtop/extract_processinfo_fdinfo.h" 26 | #include "nvtop/time.h" 27 | 28 | #include "panthor_drm.h" 29 | #include "panthor_utils.h" 30 | #include "mali_common.h" 31 | 32 | static bool gpuinfo_panthor_init(void); 33 | static void gpuinfo_panthor_shutdown(void); 34 | static const char *gpuinfo_panthor_last_error_string(void); 35 | static bool gpuinfo_panthor_get_device_handles(struct list_head *devices, unsigned *count); 36 | static void gpuinfo_panthor_populate_static_info(struct gpu_info *_gpu_info); 37 | static void gpuinfo_panthor_refresh_dynamic_info(struct gpu_info *_gpu_info); 38 | static void gpuinfo_panthor_get_running_processes(struct gpu_info *_gpu_info); 39 | 40 | static struct gpu_vendor gpu_vendor_panthor = { 41 | .init = gpuinfo_panthor_init, 42 | .shutdown = gpuinfo_panthor_shutdown, 43 | .last_error_string = gpuinfo_panthor_last_error_string, 44 | .get_device_handles = gpuinfo_panthor_get_device_handles, 45 | .populate_static_info = gpuinfo_panthor_populate_static_info, 46 | .refresh_dynamic_info = gpuinfo_panthor_refresh_dynamic_info, 47 | .refresh_running_processes = gpuinfo_panthor_get_running_processes, 48 | .refresh_utilisation_rate = gpuinfo_refresh_utilisation_rate, 49 | .name = "panthor", 50 | }; 51 | 52 | static struct drmFuncTable drmFuncs; 53 | static struct mali_gpu_state mali_state; 54 | 55 | __attribute__((constructor)) static void init_extract_gpuinfo_panthor(void) { register_gpu_vendor(&gpu_vendor_panthor); } 56 | 57 | bool gpuinfo_panthor_init(void) { 58 | return mali_init_drm_funcs(&drmFuncs, &mali_state); 59 | } 60 | 61 | void gpuinfo_panthor_shutdown(void) { 62 | mali_shutdown_common(&mali_state, &drmFuncs); 63 | } 64 | 65 | static const char *gpuinfo_panthor_last_error_string(void) { 66 | static char driver_msg[MAX_ERR_STRING_LEN] = {0}; 67 | 68 | return mali_common_last_error_string(&mali_state, 69 | gpu_vendor_panthor.name, 70 | driver_msg); 71 | } 72 | 73 | static void panthor_check_fdinfo_keys (bool *is_engine, bool *is_cycles, 74 | bool *is_maxfreq, bool *is_curfreq, 75 | bool *is_resident, char *key) 76 | { 77 | static const char drm_panthor_engine[] = "drm-engine-panthor"; 78 | static const char drm_panthor_cycles[] = "drm-cycles-panthor"; 79 | static const char drm_panthor_maxfreq[] = "drm-maxfreq-panthor"; 80 | static const char drm_panthor_curfreq[] = "drm-curfreq-panthor"; 81 | static const char drm_panthor_resident_mem[] = "drm-resident-memory"; 82 | 83 | *is_engine = !strcmp(key, drm_panthor_engine); 84 | *is_cycles = !strcmp(key, drm_panthor_cycles); 85 | *is_maxfreq = !strcmp(key, drm_panthor_maxfreq); 86 | *is_curfreq = !strcmp(key, drm_panthor_curfreq); 87 | *is_resident = !strcmp(key, drm_panthor_resident_mem); 88 | } 89 | 90 | static bool parse_drm_fdinfo_panthor(struct gpu_info *info, FILE *fdinfo_file, struct gpu_process *process_info) { 91 | 92 | struct gpu_info_mali *gpu_info = container_of(info, struct gpu_info_mali, base); 93 | struct gpuinfo_dynamic_info *dynamic_info = &gpu_info->base.dynamic_info; 94 | struct fdinfo_data res = {0}; 95 | 96 | nvtop_time current_time; 97 | nvtop_get_current_time(¤t_time); 98 | 99 | if (!mali_common_parse_drm_fdinfo(info, fdinfo_file, process_info, dynamic_info, 100 | panthor_check_fdinfo_keys, &res)) 101 | return false; 102 | 103 | mali_common_parse_fdinfo_handle_cache(gpu_info, process_info, current_time, res.total_cycles, 104 | res.cid, res.engine_count >= 1 ? true : false); 105 | 106 | return true; 107 | } 108 | 109 | static bool gpuinfo_panthor_get_device_handles(struct list_head *devices, unsigned *count) { 110 | return mali_common_get_device_handles(&mali_state, &drmFuncs, &gpu_vendor_panthor, 111 | parse_drm_fdinfo_panthor, devices, count, 112 | NULL, MALI_PANTHOR); 113 | } 114 | 115 | void gpuinfo_panthor_populate_static_info(struct gpu_info *_gpu_info) { 116 | struct gpu_info_mali *gpu_info = container_of(_gpu_info, struct gpu_info_mali, base); 117 | struct gpuinfo_static_info *static_info = &gpu_info->base.static_info; 118 | 119 | if (gpu_info->version != MALI_PANTHOR) { 120 | fprintf(stderr, "Wrong device version: %u\n", gpu_info->version); 121 | abort(); 122 | } 123 | 124 | static_info->integrated_graphics = true; 125 | static_info->encode_decode_shared = true; 126 | RESET_ALL(static_info->valid); 127 | 128 | struct drm_panthor_gpu_info gpu_dev_info = {0}; 129 | struct drm_panthor_dev_query query = { 130 | .type = DRM_PANTHOR_DEV_QUERY_GPU_INFO, 131 | .size = sizeof(gpu_dev_info), 132 | .pointer = (uint64_t)(uintptr_t)&gpu_dev_info, 133 | }; 134 | 135 | int ret = drmFuncs.drmIoctl(gpu_info->fd, DRM_IOCTL_PANTHOR_DEV_QUERY, &query); 136 | if (ret) { 137 | fprintf(stderr, "Failed to query Panthor GPU device properties\n"); 138 | snprintf(static_info->device_name, sizeof(static_info->device_name), 139 | "Unknown Panthor %x", gpu_dev_info.gpu_id); 140 | SET_VALID(gpuinfo_device_name_valid, static_info->valid); 141 | return; 142 | } 143 | 144 | const char *name = panthor_device_name(gpu_dev_info.gpu_id); 145 | if (name) 146 | strncpy(static_info->device_name, name, sizeof(static_info->device_name)); 147 | else 148 | snprintf(static_info->device_name, sizeof(static_info->device_name), 149 | "Unknown Panthor %x", gpu_dev_info.gpu_id); 150 | 151 | SET_VALID(gpuinfo_device_name_valid, static_info->valid); 152 | } 153 | 154 | void gpuinfo_panthor_refresh_dynamic_info(struct gpu_info *_gpu_info) { 155 | static const char *meminfo_total = "MemTotal"; 156 | static const char *meminfo_available = "MemAvailable"; 157 | 158 | struct gpu_info_mali *gpu_info = container_of(_gpu_info, struct gpu_info_mali, base); 159 | struct gpuinfo_dynamic_info *dynamic_info = &gpu_info->base.dynamic_info; 160 | 161 | if (gpu_info->version != MALI_PANTHOR) { 162 | fprintf(stderr, "Wrong device version: %u\n", gpu_info->version); 163 | abort(); 164 | } 165 | 166 | mali_common_refresh_dynamic_info(dynamic_info, &mali_state, meminfo_total, meminfo_available); 167 | } 168 | 169 | void gpuinfo_panthor_get_running_processes(struct gpu_info *_gpu_info) { 170 | mali_common_get_running_processes(_gpu_info, MALI_PANTHOR); 171 | } 172 | -------------------------------------------------------------------------------- /src/extract_gpuinfo_panthor_utils.c: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Copyright (C) 2023 Adrian Larumbe 4 | * 5 | * Nvtop is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * Nvtop is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with nvtop. If not, see . 17 | * 18 | */ 19 | 20 | #include 21 | #include "nvtop/interface_internal_common.h" 22 | #include "panthor_utils.h" 23 | 24 | /** 25 | * struct panthor_model - GPU model description 26 | */ 27 | struct panthor_model { 28 | /** @name: Model name. */ 29 | const char *name; 30 | 31 | /** @arch_major: Major version number of architecture */ 32 | uint8_t arch_major; 33 | 34 | /* @product_major: Major version number of product */ 35 | uint8_t product_major; 36 | }; 37 | 38 | /** 39 | * GPU_MODEL() - Define a GPU model. A GPU product can be uniquely identified 40 | * by a combination of the major architecture version and the major product 41 | * version. 42 | */ 43 | #define GPU_MODEL(_name, _arch_major, _product_major) \ 44 | { \ 45 | .name = #_name, \ 46 | .arch_major = _arch_major, \ 47 | .product_major = _product_major, \ 48 | } 49 | 50 | static const struct panthor_model gpu_models[] = { 51 | GPU_MODEL(g610, 10, 7), 52 | GPU_MODEL(g310, 10, 4), 53 | {0}, 54 | }; 55 | 56 | const char * panthor_device_name(uint32_t gpu_id) 57 | { 58 | uint32_t arch_major, product_major; 59 | const struct panthor_model *model; 60 | 61 | arch_major = (gpu_id >> 28) & 0xf; 62 | product_major = (gpu_id >> 16) & 0xf; 63 | 64 | for (model = gpu_models; model->name; model++) { 65 | if (model->arch_major == arch_major && 66 | model->product_major == product_major) 67 | return model->name; 68 | } 69 | 70 | return NULL; 71 | } 72 | -------------------------------------------------------------------------------- /src/extract_gpuinfo_v3d_utils.c: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Copyright (C) 2022 Hoream Xiao 4 | * 5 | * This file is part of Nvtop and adapted from the vcgencmd implementation. 6 | * 7 | * Nvtop is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * Nvtop is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with nvtop. If not, see . 19 | * 20 | */ 21 | 22 | #include "nvtop/extract_gpuinfo_common.h" 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | /* 32 | * use ioctl to send mbox property message 33 | */ 34 | #define DEVICE_FILE_NAME "/dev/vcio" 35 | #define MAJOR_NUM 100 36 | #define IOCTL_MBOX_PROPERTY _IOWR(MAJOR_NUM, 0, char *) 37 | #define MAX_STRING 1024 38 | #define GET_GENCMD_RESULT 0x00030080 39 | #define MAX_DECODER_FREQUENCE 550006336 40 | 41 | int mbox_open(void); 42 | void mbox_close(int mb); 43 | void set_debug_files(int card_id); 44 | void set_gpuinfo_from_vcio(struct gpuinfo_dynamic_info *dynamic_info, int mb); 45 | void set_memory_gpuinfo(struct gpuinfo_dynamic_info *dynamic_info); 46 | void set_init_max_memory(int mb); 47 | 48 | static uint64_t max_gpu_memory_bytes = 128 << 20; 49 | 50 | static const char measure_temp[] = "measure_temp"; 51 | static const char measure_clock_v3d[] = "measure_clock v3d"; 52 | static const char measure_clock_h264[] = "measure_clock h264"; 53 | static const char get_mem_gpu[] = "get_mem gpu"; 54 | 55 | static char bo_stats_file[50]; 56 | 57 | void set_debug_files(int card_id) { 58 | snprintf(bo_stats_file, sizeof(bo_stats_file), "/sys/kernel/debug/dri/%d/bo_stats", card_id); 59 | if (access(bo_stats_file, F_OK)) 60 | printf("%s is not available.\n", bo_stats_file); 61 | } 62 | 63 | static int mbox_property(int mb, void *buf) { 64 | int ret_val = ioctl(mb, IOCTL_MBOX_PROPERTY, buf); 65 | 66 | if (ret_val < 0) { 67 | printf("ioctl_set_msg failed:%d\n", ret_val); 68 | } 69 | return ret_val; 70 | } 71 | 72 | int mbox_open(void) { 73 | int mb; 74 | 75 | // open a char device file used for communicating with kernel mbox driver 76 | mb = open(DEVICE_FILE_NAME, 0); 77 | if (mb < 0) { 78 | printf("Can't open device file: %s\n", DEVICE_FILE_NAME); 79 | printf("Try creating a device file with: sudo mknod %s c %d 0\n", DEVICE_FILE_NAME, MAJOR_NUM); 80 | } 81 | return mb; 82 | } 83 | 84 | void mbox_close(int mb) { close(mb); } 85 | 86 | static unsigned gencmd(int mb, const char *command, char *result, int result_len) { 87 | int i = 0; 88 | unsigned p[(MAX_STRING >> 2) + 7]; 89 | int len = strlen(command); 90 | // maximum length for command or response 91 | if (len + 1 >= MAX_STRING) { 92 | fprintf(stderr, "gencmd length too long : %d\n", len); 93 | return -1; 94 | } 95 | p[i++] = 0; // size 96 | p[i++] = 0x00000000; // process request 97 | 98 | p[i++] = GET_GENCMD_RESULT; // (the tag id) 99 | p[i++] = MAX_STRING; // buffer_len 100 | p[i++] = 0; // request_len (set to response length) 101 | p[i++] = 0; // error response 102 | 103 | memcpy(p + i, command, len + 1); 104 | i += MAX_STRING >> 2; 105 | 106 | p[i++] = 0x00000000; // end tag 107 | p[0] = i * sizeof *p; // actual size 108 | 109 | mbox_property(mb, p); 110 | result[0] = 0; 111 | 112 | size_t available_space = result_len - strlen(result) - 1; 113 | strncat(result, (const char *)(p + 6), available_space); 114 | 115 | return p[5]; 116 | } 117 | 118 | void set_init_max_memory(int mb) { 119 | char result[MAX_STRING] = {}; 120 | 121 | int ret = gencmd(mb, get_mem_gpu, result, sizeof result); 122 | if (!ret) { 123 | if (sscanf(result, "gpu=%luM", &max_gpu_memory_bytes) == 1) { 124 | max_gpu_memory_bytes <<= 20; 125 | } 126 | } 127 | } 128 | 129 | static unsigned cal_percentage_usage(unsigned usage, unsigned all) { return (unsigned)(100.0 * usage / all + 0.5); } 130 | 131 | static void set_gpuinfo_decode(struct gpuinfo_dynamic_info *dynamic_info, int mb) { 132 | unsigned int decode_usage = 0; 133 | char result[MAX_STRING] = {}; 134 | 135 | int ret = gencmd(mb, measure_clock_h264, result, sizeof result); 136 | if (!ret) { 137 | if (sscanf(result, "frequency(28)=%u", &decode_usage) == 1) 138 | // divide current frequency by max frequency; usage rate might not be accurate. 139 | SET_GPUINFO_DYNAMIC(dynamic_info, decoder_rate, cal_percentage_usage(decode_usage, MAX_DECODER_FREQUENCE)); 140 | } 141 | } 142 | 143 | static void set_gpuinfo_temp(struct gpuinfo_dynamic_info *dynamic_info, int mb) { 144 | float temperature = 0; 145 | char result[MAX_STRING] = {}; 146 | 147 | int ret = gencmd(mb, measure_temp, result, sizeof result); 148 | if (!ret) { 149 | if (sscanf(result, "temp=%f'C", &temperature) == 1) { 150 | SET_GPUINFO_DYNAMIC(dynamic_info, gpu_temp, (unsigned)temperature); 151 | } 152 | } 153 | } 154 | 155 | static void set_gpuinfo_clock(struct gpuinfo_dynamic_info *dynamic_info, int mb) { 156 | unsigned int clock = 0; 157 | char result[MAX_STRING] = {}; 158 | 159 | int ret = gencmd(mb, measure_clock_v3d, result, sizeof result); 160 | if (!ret) { 161 | if (sscanf(result, "frequency(46)=%u", &clock) == 1) { 162 | SET_GPUINFO_DYNAMIC(dynamic_info, gpu_clock_speed, clock >> 20); 163 | } 164 | } 165 | } 166 | 167 | void set_gpuinfo_from_vcio(struct gpuinfo_dynamic_info *dynamic_info, int mb) { 168 | set_gpuinfo_temp(dynamic_info, mb); 169 | set_gpuinfo_clock(dynamic_info, mb); 170 | set_gpuinfo_decode(dynamic_info, mb); 171 | } 172 | 173 | void set_memory_gpuinfo(struct gpuinfo_dynamic_info *dynamic_info) { 174 | FILE *fp = fopen(bo_stats_file, "rb"); 175 | if (fp == NULL) { 176 | return; 177 | } 178 | 179 | char line[256]; 180 | uint64_t allocated_bo_size_kb = 0; 181 | 182 | while (fgets(line, sizeof(line), fp)) { 183 | if (sscanf(line, "allocated bo size (kb): %lu", &allocated_bo_size_kb) == 1) { 184 | break; 185 | } 186 | } 187 | 188 | fclose(fp); 189 | 190 | uint64_t allocated_bo_size_bytes = allocated_bo_size_kb << 10; 191 | 192 | SET_GPUINFO_DYNAMIC(dynamic_info, used_memory, allocated_bo_size_bytes); 193 | if (allocated_bo_size_bytes >= max_gpu_memory_bytes) 194 | max_gpu_memory_bytes = allocated_bo_size_bytes; 195 | SET_GPUINFO_DYNAMIC(dynamic_info, total_memory, max_gpu_memory_bytes); 196 | SET_GPUINFO_DYNAMIC(dynamic_info, mem_util_rate, cal_percentage_usage(allocated_bo_size_bytes, max_gpu_memory_bytes)); 197 | } 198 | -------------------------------------------------------------------------------- /src/extract_processinfo_mac.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Robin Voetter 3 | * 4 | * This file is part of Nvtop. 5 | * 6 | * Nvtop is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * Nvtop is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with nvtop. If not, see . 18 | * 19 | */ 20 | 21 | #include "nvtop/extract_processinfo_fdinfo.h" 22 | 23 | void processinfo_drop_callback(const struct gpu_info *info) { 24 | (void) info; 25 | } 26 | 27 | void processinfo_register_fdinfo_callback(processinfo_fdinfo_callback callback, struct gpu_info *info) { 28 | (void) callback; 29 | (void) info; 30 | } 31 | 32 | void processinfo_sweep_fdinfos(void) { 33 | } 34 | 35 | void processinfo_enable_disable_callback_for(const struct gpu_info *info, bool enable) { 36 | (void)info; 37 | (void)enable; 38 | } 39 | -------------------------------------------------------------------------------- /src/get_process_info_linux.c: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Copyright (C) 2017-2021 Maxime Schmitt 4 | * 5 | * This file is part of Nvtop. 6 | * 7 | * Nvtop is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * Nvtop is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with nvtop. If not, see . 19 | * 20 | */ 21 | 22 | #include "nvtop/get_process_info.h" 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | #define pid_path_size 1024 34 | static char pid_path[pid_path_size]; 35 | 36 | void get_username_from_pid(pid_t pid, char **buffer) { 37 | int written = snprintf(pid_path, pid_path_size, "/proc/%" PRIdMAX, (intmax_t)pid); 38 | if (written == pid_path_size) { 39 | *buffer = NULL; 40 | return; 41 | } 42 | struct stat folder_stat; 43 | int starval = stat(pid_path, &folder_stat); 44 | if (starval == -1) { 45 | *buffer = NULL; 46 | return; 47 | } 48 | uid_t user_id = folder_stat.st_uid; 49 | struct passwd *user_info = getpwuid(user_id); 50 | if (user_info == NULL) { 51 | *buffer = NULL; 52 | return; 53 | } 54 | size_t namelen = strlen(user_info->pw_name) + 1; 55 | *buffer = malloc(namelen * sizeof(**buffer)); 56 | 57 | strncpy(*buffer, user_info->pw_name, namelen); 58 | } 59 | 60 | #define command_line_increment 32 61 | 62 | void get_command_from_pid(pid_t pid, char **buffer) { 63 | int written = snprintf(pid_path, pid_path_size, "/proc/%" PRIdMAX "/cmdline", (intmax_t)pid); 64 | if (written == pid_path_size) { 65 | *buffer = NULL; 66 | return; 67 | } 68 | FILE *pid_file = fopen(pid_path, "r"); 69 | if (!pid_file) { 70 | *buffer = NULL; 71 | return; 72 | } 73 | 74 | size_t size_buffer = command_line_increment; 75 | *buffer = malloc(size_buffer); 76 | char *current_buffer = *buffer; 77 | current_buffer[0] = '\0'; 78 | 79 | size_t total_read = 0; 80 | do { 81 | size_t num_read = fread(current_buffer, 1, command_line_increment, pid_file); 82 | total_read += num_read; 83 | if (num_read == command_line_increment) { 84 | size_buffer += command_line_increment; 85 | *buffer = realloc(*buffer, size_buffer); 86 | current_buffer = &((*buffer)[total_read]); 87 | } 88 | } while (!feof(pid_file) && !ferror(pid_file)); 89 | if (ferror(pid_file)) { 90 | fclose(pid_file); 91 | free(*buffer); 92 | *buffer = NULL; 93 | return; 94 | } 95 | fclose(pid_file); 96 | 97 | for (size_t i = 0; total_read && i < total_read - 1; ++i) { 98 | if ((*buffer)[i] == '\0') 99 | (*buffer)[i] = ' '; 100 | } 101 | } 102 | 103 | /* 104 | * 105 | * From man 5 proc of /proc//stat 106 | * For clock ticks per second use sysconf(_SC_CLK_TCK) 107 | * 108 | * enum process_state { 109 | * process_running = 'R', 110 | * process_sleeping = 'S', 111 | * process_sleeping_disk = 'D', 112 | * process_zombie = 'Z', 113 | * process_stopped = 'T', 114 | * process_stopped_tracing = 't', 115 | * process_dead = 'X', 116 | * process_dead2 = 'x', 117 | * process_wake_kill = 'K', 118 | * process_waking = 'W', 119 | * process_parked = 'P', 120 | * }; 121 | * 122 | * struct stat_parse { 123 | * int process_id; 124 | * char *executable_filename; 125 | * enum process_state process_state; 126 | * int parent_pid; 127 | * int process_group_id; 128 | * int process_session_id; 129 | * int process_tty; 130 | * int foreground_process_group_id; 131 | * unsigned kernel_flag; 132 | * unsigned long num_minor_fault; 133 | * unsigned long num_minor_fault_children; 134 | * unsigned long num_major_fault; 135 | * unsigned long num_major_fault_children; 136 | * unsigned long user_time; // in clock ticks 137 | * unsigned long kernel_time; // in clock ticks 138 | * long children_user_time; // in clock ticks 139 | * long children_kernel_time; // in clock ticks 140 | * long process_priority; 141 | * long process_niceness; 142 | * long process_num_threads; 143 | * long next_sigalarm_time; 144 | * unsigned long long process_start_time; 145 | * unsigned long process_virt_mem_usage; 146 | * long process_resident_mem_usage; 147 | * long process_resident_mem_limit; 148 | * unsigned long process_text_address_start; 149 | * unsigned long process_text_address_end; 150 | * unsigned long process_stack_address_start; 151 | * unsigned long process_stack_address_current; 152 | * unsigned long process_instruction_pointer; 153 | * unsigned long process_signals; // Obsolete 154 | * unsigned long process_signals_blocked; // Obsolete 155 | * unsigned long process_signals_ignored; // Obsolete 156 | * unsigned long process_signals_caught; // Obsolete 157 | * unsigned long wait_channel_id; 158 | * unsigned long process_num_page_swapped; 159 | * unsigned long process_and_child_num_page_swapped; 160 | * int process_exit_signal_to_parent; 161 | * int process_processor; 162 | * unsigned process_real_time_priority; 163 | * unsigned policy; 164 | * long long unsigned total_io_delays; 165 | * long unsigned process_guest_time; 166 | * long process_children_guest_time; 167 | * unsigned long process_data_address_start; 168 | * unsigned long process_data_address_end; 169 | * unsigned long process_brk_start; 170 | * unsigned long process_arguments_address_start; 171 | * unsigned long process_arguments_address_end; 172 | * unsigned long process_env_vars_address_start; 173 | * unsigned long process_env_vars_address_end; 174 | * int thread_exit_code; 175 | * }; 176 | * 177 | */ 178 | 179 | bool get_process_info(pid_t pid, struct process_cpu_usage *usage) { 180 | double clock_ticks_per_second = sysconf(_SC_CLK_TCK); 181 | size_t page_size = (size_t)sysconf(_SC_PAGESIZE); 182 | int written = snprintf(pid_path, pid_path_size, "/proc/%" PRIdMAX "/stat", (intmax_t)pid); 183 | if (written == pid_path_size) { 184 | return false; 185 | } 186 | FILE *stat_file = fopen(pid_path, "r"); 187 | if (!stat_file) { 188 | return false; 189 | } 190 | nvtop_get_current_time(&usage->timestamp); 191 | unsigned long total_user_time; // in clock_ticks 192 | unsigned long total_kernel_time; // in clock_ticks 193 | unsigned long virtual_memory; // In bytes 194 | long resident_memory; // In page number? 195 | 196 | int retval = fscanf(stat_file, 197 | "%*d %*[^)]) %*c %*d %*d %*d %*d %*d %*u %*u %*u %*u " 198 | "%*u %lu %lu %*d %*d %*d %*d %*d %*d %*u %lu %ld", 199 | &total_user_time, &total_kernel_time, &virtual_memory, &resident_memory); 200 | fclose(stat_file); 201 | if (retval != 4) 202 | return false; 203 | usage->total_user_time = total_user_time / clock_ticks_per_second; 204 | usage->total_kernel_time = total_kernel_time / clock_ticks_per_second; 205 | usage->virtual_memory = virtual_memory; 206 | usage->resident_memory = (size_t)resident_memory * page_size; 207 | return true; 208 | } 209 | -------------------------------------------------------------------------------- /src/get_process_info_mac.c: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Copyright (C) 2023 Robin Voetter 4 | * 5 | * This file is part of Nvtop. 6 | * 7 | * Nvtop is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * Nvtop is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with nvtop. If not, see . 19 | * 20 | */ 21 | 22 | #include "nvtop/get_process_info.h" 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #include 30 | #include 31 | 32 | void get_username_from_pid(pid_t pid, char **buffer) { 33 | struct proc_bsdshortinfo proc; 34 | const int st = proc_pidinfo(pid, PROC_PIDT_SHORTBSDINFO, 0, &proc, PROC_PIDT_SHORTBSDINFO_SIZE); 35 | if (st != PROC_PIDT_SHORTBSDINFO_SIZE) { 36 | goto error; 37 | } 38 | 39 | struct passwd *user_info = getpwuid(proc.pbsi_uid); 40 | if (user_info == NULL) { 41 | goto error; 42 | } 43 | 44 | const size_t namelen = strlen(user_info->pw_name) + 1; 45 | *buffer = malloc(namelen * sizeof(**buffer)); 46 | strncpy(*buffer, user_info->pw_name, namelen); 47 | return; 48 | error: 49 | *buffer = NULL; 50 | } 51 | 52 | void get_command_from_pid(pid_t pid, char **buffer) { 53 | // See https://chromium.googlesource.com/crashpad/crashpad/+/360e441c53ab4191a6fd2472cc57c3343a2f6944/util/posix/process_util_mac.cc 54 | size_t argmax; 55 | size_t argmax_estimate; 56 | char *procargs = NULL; 57 | int tries = 3; 58 | do { 59 | int mib[] = {CTL_KERN, KERN_PROCARGS2, pid}; 60 | if (sysctl(mib, 3, NULL, &argmax_estimate, NULL, 0) != 0) { 61 | goto error_free_procargs; 62 | } 63 | 64 | argmax = argmax_estimate + 1; 65 | procargs = realloc(procargs, argmax); 66 | if (sysctl(mib, 3, procargs, &argmax, NULL, 0) != 0) { 67 | goto error_free_procargs; 68 | } 69 | } while (argmax == argmax_estimate + 1 && --tries != 0); 70 | 71 | unsigned argc; 72 | memcpy(&argc, procargs, sizeof(argc)); 73 | 74 | size_t i = sizeof(argc); 75 | // Skip executable path. 76 | while (i < argmax && procargs[i] != 0) { 77 | ++i; 78 | } 79 | // Find the first string 80 | while (i < argmax && procargs[i] == 0) { 81 | ++i; 82 | } 83 | 84 | const size_t argv0 = i; 85 | // Count the total size of the args by finding the end. 86 | for (unsigned int arg = 0; arg < argc && i < argmax; ++arg) { 87 | while (i < argmax && procargs[i] != 0) { 88 | ++i; 89 | } 90 | ++i; // We are going to replace this null character with a space (or a null in the case of the last). 91 | } 92 | const size_t args_size = i - argv0; 93 | if (args_size == 0) { 94 | goto error_free_procargs; 95 | } 96 | char* args = malloc(args_size); 97 | *buffer = args; 98 | 99 | i = argv0; 100 | for (unsigned int arg = 0; arg < argc && i < argmax; ++arg) { 101 | while (i < argmax && procargs[i] != 0) { 102 | *args++ = procargs[i++]; 103 | } 104 | *args++ = ' '; 105 | ++i; 106 | } 107 | args[-1] = 0; 108 | 109 | free(procargs); 110 | return; 111 | error_free_procargs: 112 | free(procargs); 113 | *buffer = NULL; 114 | return; 115 | } 116 | 117 | bool get_process_info(pid_t pid, struct process_cpu_usage *usage) { 118 | struct proc_taskinfo proc; 119 | const int st = proc_pidinfo(pid, PROC_PIDTASKINFO, 0, &proc, PROC_PIDTASKINFO_SIZE); 120 | if (st != PROC_PIDTASKINFO_SIZE) { 121 | return false; 122 | } 123 | 124 | nvtop_get_current_time(&usage->timestamp); 125 | 126 | // TODO: Should we implement this workaround? 127 | // https://github.com/htop-dev/htop/blob/main/darwin/PlatformHelpers.c#L98 128 | mach_timebase_info_data_t info; 129 | mach_timebase_info(&info); 130 | const double nanoseconds_per_tick = (double)info.numer / (double)info.denom; 131 | 132 | usage->total_user_time = (proc.pti_total_user * nanoseconds_per_tick) / 1000000000.0; 133 | usage->total_kernel_time = (proc.pti_total_system * nanoseconds_per_tick) / 1000000000.0; 134 | usage->virtual_memory = proc.pti_virtual_size; 135 | usage->resident_memory = proc.pti_resident_size; 136 | return true; 137 | } 138 | -------------------------------------------------------------------------------- /src/info_messages_linux.c: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Copyright (C) 2022 Maxime Schmitt 4 | * 5 | * This file is part of Nvtop. 6 | * 7 | * Nvtop is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * Nvtop is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with nvtop. If not, see . 19 | * 20 | */ 21 | 22 | #include "list.h" 23 | #include "nvtop/extract_gpuinfo_common.h" 24 | #include "nvtop/info_messages.h" 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | static int get_linux_kernel_release(unsigned *major, unsigned *minor, unsigned *patch) { 32 | struct utsname uname_str; 33 | int retval = uname(&uname_str); 34 | if (retval) 35 | return retval; 36 | int nmatch = sscanf(uname_str.release, "%u.%u.%u", major, minor, patch); 37 | return nmatch != 3; 38 | } 39 | 40 | enum messages { 41 | AMD_GPU_514, 42 | INTEL_GPU_519, 43 | MSM_GPU, 44 | }; 45 | 46 | static const char *allMessages[] = { 47 | "Nvtop won't be able to show AMD GPU processes on your kernel version (requires Linux >= 5.14)", 48 | "Nvtop won't be able to show Intel GPU utilization and processes on your kernel version (requires Linux >= 5.19)", 49 | "This version of Nvtop does not yet support reporting all data for MSM GPUs, such as power, fan and temperature information", 50 | }; 51 | static const char *message_array[sizeof(allMessages) / sizeof(*allMessages)]; 52 | 53 | void get_info_messages(struct list_head *devices, unsigned *num_messages, const char ***messages) { 54 | *num_messages = 0; 55 | unsigned linux_major, linux_minor, linux_patch; 56 | if (get_linux_kernel_release(&linux_major, &linux_minor, &linux_patch)) 57 | return; 58 | 59 | *messages = message_array; 60 | bool hasIntel = false; 61 | bool hasMSM = false; 62 | bool hasAMD = false; 63 | struct gpu_info *gpuinfo; 64 | list_for_each_entry(gpuinfo, devices, list) { 65 | if (strcmp(gpuinfo->vendor->name, "Intel") == 0) { 66 | hasIntel = true; 67 | } 68 | if (strcmp(gpuinfo->vendor->name, "msm") == 0) { 69 | hasMSM = true; 70 | } 71 | if (strcmp(gpuinfo->vendor->name, "AMD") == 0) { 72 | hasAMD = true; 73 | } 74 | } 75 | if (hasAMD) { 76 | if (linux_major < 5 || (linux_major == 5 && linux_minor < 14)) { 77 | message_array[(*num_messages)++] = allMessages[AMD_GPU_514]; 78 | } 79 | } 80 | if (hasIntel) { 81 | if (linux_major < 5 || (linux_major == 5 && linux_minor < 19)) { 82 | message_array[(*num_messages)++] = allMessages[INTEL_GPU_519]; 83 | } 84 | } 85 | if (hasMSM) { 86 | message_array[(*num_messages)++] = allMessages[MSM_GPU]; 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/info_messages_mac.c: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Copyright (C) 2023 Robin Voetter 4 | * 5 | * This file is part of Nvtop. 6 | * 7 | * Nvtop is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * Nvtop is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with nvtop. If not, see . 19 | * 20 | */ 21 | 22 | #include "list.h" 23 | #include "nvtop/info_messages.h" 24 | 25 | void get_info_messages(struct list_head *devices, unsigned *num_messages, const char ***messages) { 26 | (void) devices; 27 | (void) messages; 28 | *num_messages = 0; 29 | } 30 | -------------------------------------------------------------------------------- /src/ini.c: -------------------------------------------------------------------------------- 1 | /* inih -- simple .INI file parser 2 | 3 | SPDX-License-Identifier: BSD-3-Clause 4 | 5 | Copyright (C) 2009-2020, Ben Hoyt 6 | 7 | inih is released under the New BSD license (see LICENSE.txt). Go to the project 8 | home page for more info: 9 | 10 | https://github.com/benhoyt/inih 11 | 12 | */ 13 | 14 | #if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS) 15 | #define _CRT_SECURE_NO_WARNINGS 16 | #endif 17 | 18 | #include 19 | #include 20 | #include 21 | 22 | #include "ini.h" 23 | 24 | #if !INI_USE_STACK 25 | #if INI_CUSTOM_ALLOCATOR 26 | #include 27 | void *ini_malloc(size_t size); 28 | void ini_free(void *ptr); 29 | void *ini_realloc(void *ptr, size_t size); 30 | #else 31 | #include 32 | #define ini_malloc malloc 33 | #define ini_free free 34 | #define ini_realloc realloc 35 | #endif 36 | #endif 37 | 38 | #define MAX_SECTION 50 39 | #define MAX_NAME 50 40 | 41 | /* Used by ini_parse_string() to keep track of string parsing state. */ 42 | typedef struct { 43 | const char *ptr; 44 | size_t num_left; 45 | } ini_parse_string_ctx; 46 | 47 | /* Strip whitespace chars off end of given string, in place. Return s. */ 48 | static char *rstrip(char *s) { 49 | char *p = s + strlen(s); 50 | while (p > s && isspace((unsigned char)(*--p))) 51 | *p = '\0'; 52 | return s; 53 | } 54 | 55 | /* Return pointer to first non-whitespace char in given string. */ 56 | static char *lskip(const char *s) { 57 | while (*s && isspace((unsigned char)(*s))) 58 | s++; 59 | return (char *)s; 60 | } 61 | 62 | /* Return pointer to first char (of chars) or inline comment in given string, 63 | or pointer to NUL at end of string if neither found. Inline comment must 64 | be prefixed by a whitespace character to register as a comment. */ 65 | static char *find_chars_or_comment(const char *s, const char *chars) { 66 | #if INI_ALLOW_INLINE_COMMENTS 67 | int was_space = 0; 68 | while (*s && (!chars || !strchr(chars, *s)) && !(was_space && strchr(INI_INLINE_COMMENT_PREFIXES, *s))) { 69 | was_space = isspace((unsigned char)(*s)); 70 | s++; 71 | } 72 | #else 73 | while (*s && (!chars || !strchr(chars, *s))) { 74 | s++; 75 | } 76 | #endif 77 | return (char *)s; 78 | } 79 | 80 | /* Similar to strncpy, but ensures dest (size bytes) is 81 | NUL-terminated, and doesn't pad with NULs. */ 82 | static char *strncpy0(char *dest, const char *src, size_t size) { 83 | /* Could use strncpy internally, but it causes gcc warnings (see issue #91) */ 84 | size_t i; 85 | for (i = 0; i < size - 1 && src[i]; i++) 86 | dest[i] = src[i]; 87 | dest[i] = '\0'; 88 | return dest; 89 | } 90 | 91 | /* See documentation in header file. */ 92 | int ini_parse_stream(ini_reader reader, void *stream, ini_handler handler, void *user) { 93 | /* Uses a fair bit of stack (use heap instead if you need to) */ 94 | #if INI_USE_STACK 95 | char line[INI_MAX_LINE]; 96 | int max_line = INI_MAX_LINE; 97 | #else 98 | char *line; 99 | size_t max_line = INI_INITIAL_ALLOC; 100 | #endif 101 | #if INI_ALLOW_REALLOC && !INI_USE_STACK 102 | char *new_line; 103 | size_t offset; 104 | #endif 105 | char section[MAX_SECTION] = ""; 106 | char prev_name[MAX_NAME] = ""; 107 | 108 | char *start; 109 | char *end; 110 | char *name; 111 | char *value; 112 | int lineno = 0; 113 | int error = 0; 114 | 115 | #if !INI_USE_STACK 116 | line = (char *)ini_malloc(INI_INITIAL_ALLOC); 117 | if (!line) { 118 | return -2; 119 | } 120 | #endif 121 | 122 | #if INI_HANDLER_LINENO 123 | #define HANDLER(u, s, n, v) handler(u, s, n, v, lineno) 124 | #else 125 | #define HANDLER(u, s, n, v) handler(u, s, n, v) 126 | #endif 127 | 128 | /* Scan through stream line by line */ 129 | while (reader(line, (int)max_line, stream) != NULL) { 130 | #if INI_ALLOW_REALLOC && !INI_USE_STACK 131 | offset = strlen(line); 132 | while (offset == max_line - 1 && line[offset - 1] != '\n') { 133 | max_line *= 2; 134 | if (max_line > INI_MAX_LINE) 135 | max_line = INI_MAX_LINE; 136 | new_line = ini_realloc(line, max_line); 137 | if (!new_line) { 138 | ini_free(line); 139 | return -2; 140 | } 141 | line = new_line; 142 | if (reader(line + offset, (int)(max_line - offset), stream) == NULL) 143 | break; 144 | if (max_line >= INI_MAX_LINE) 145 | break; 146 | offset += strlen(line + offset); 147 | } 148 | #endif 149 | 150 | lineno++; 151 | 152 | start = line; 153 | #if INI_ALLOW_BOM 154 | if (lineno == 1 && (unsigned char)start[0] == 0xEF && (unsigned char)start[1] == 0xBB && 155 | (unsigned char)start[2] == 0xBF) { 156 | start += 3; 157 | } 158 | #endif 159 | start = lskip(rstrip(start)); 160 | 161 | if (strchr(INI_START_COMMENT_PREFIXES, *start)) { 162 | /* Start-of-line comment */ 163 | } 164 | #if INI_ALLOW_MULTILINE 165 | else if (*prev_name && *start && start > line) { 166 | /* Non-blank line with leading whitespace, treat as continuation 167 | of previous name's value (as per Python configparser). */ 168 | if (!HANDLER(user, section, prev_name, start) && !error) 169 | error = lineno; 170 | } 171 | #endif 172 | else if (*start == '[') { 173 | /* A "[section]" line */ 174 | end = find_chars_or_comment(start + 1, "]"); 175 | if (*end == ']') { 176 | *end = '\0'; 177 | strncpy0(section, start + 1, sizeof(section)); 178 | *prev_name = '\0'; 179 | #if INI_CALL_HANDLER_ON_NEW_SECTION 180 | if (!HANDLER(user, section, NULL, NULL) && !error) 181 | error = lineno; 182 | #endif 183 | } else if (!error) { 184 | /* No ']' found on section line */ 185 | error = lineno; 186 | } 187 | } else if (*start) { 188 | /* Not a comment, must be a name[=:]value pair */ 189 | end = find_chars_or_comment(start, "=:"); 190 | if (*end == '=' || *end == ':') { 191 | *end = '\0'; 192 | name = rstrip(start); 193 | value = end + 1; 194 | #if INI_ALLOW_INLINE_COMMENTS 195 | end = find_chars_or_comment(value, NULL); 196 | if (*end) 197 | *end = '\0'; 198 | #endif 199 | value = lskip(value); 200 | rstrip(value); 201 | 202 | /* Valid name[=:]value pair found, call handler */ 203 | strncpy0(prev_name, name, sizeof(prev_name)); 204 | if (!HANDLER(user, section, name, value) && !error) 205 | error = lineno; 206 | } else if (!error) { 207 | /* No '=' or ':' found on name[=:]value line */ 208 | #if INI_ALLOW_NO_VALUE 209 | *end = '\0'; 210 | name = rstrip(start); 211 | if (!HANDLER(user, section, name, NULL) && !error) 212 | error = lineno; 213 | #else 214 | error = lineno; 215 | #endif 216 | } 217 | } 218 | 219 | #if INI_STOP_ON_FIRST_ERROR 220 | if (error) 221 | break; 222 | #endif 223 | } 224 | 225 | #if !INI_USE_STACK 226 | ini_free(line); 227 | #endif 228 | 229 | return error; 230 | } 231 | 232 | /* See documentation in header file. */ 233 | int ini_parse_file(FILE *file, ini_handler handler, void *user) { 234 | return ini_parse_stream((ini_reader)fgets, file, handler, user); 235 | } 236 | 237 | /* See documentation in header file. */ 238 | int ini_parse(const char *filename, ini_handler handler, void *user) { 239 | FILE *file; 240 | int error; 241 | 242 | file = fopen(filename, "r"); 243 | if (!file) 244 | return -1; 245 | error = ini_parse_file(file, handler, user); 246 | fclose(file); 247 | return error; 248 | } 249 | 250 | /* An ini_reader function to read the next line from a string buffer. This 251 | is the fgets() equivalent used by ini_parse_string(). */ 252 | static char *ini_reader_string(char *str, int num, void *stream) { 253 | ini_parse_string_ctx *ctx = (ini_parse_string_ctx *)stream; 254 | const char *ctx_ptr = ctx->ptr; 255 | size_t ctx_num_left = ctx->num_left; 256 | char *strp = str; 257 | char c; 258 | 259 | if (ctx_num_left == 0 || num < 2) 260 | return NULL; 261 | 262 | while (num > 1 && ctx_num_left != 0) { 263 | c = *ctx_ptr++; 264 | ctx_num_left--; 265 | *strp++ = c; 266 | if (c == '\n') 267 | break; 268 | num--; 269 | } 270 | 271 | *strp = '\0'; 272 | ctx->ptr = ctx_ptr; 273 | ctx->num_left = ctx_num_left; 274 | return str; 275 | } 276 | 277 | /* See documentation in header file. */ 278 | int ini_parse_string(const char *string, ini_handler handler, void *user) { 279 | ini_parse_string_ctx ctx; 280 | 281 | ctx.ptr = string; 282 | ctx.num_left = strlen(string); 283 | return ini_parse_stream((ini_reader)ini_reader_string, &ctx, handler, user); 284 | } 285 | -------------------------------------------------------------------------------- /src/interface_ring_buffer.c: -------------------------------------------------------------------------------- 1 | 2 | #include "nvtop/interface_ring_buffer.h" 3 | 4 | #include "stdio.h" 5 | #include "stdlib.h" 6 | 7 | void interface_alloc_ring_buffer(unsigned devices_count, unsigned per_device_data_saved, unsigned buffer_size, 8 | interface_ring_buffer *ring_buffer) { 9 | ring_buffer->ring_buffer[0] = calloc(1, sizeof(unsigned[devices_count][per_device_data_saved][2])); 10 | if (!ring_buffer->ring_buffer[0]) { 11 | perror("Cannot allocate memory: "); 12 | exit(EXIT_FAILURE); 13 | } 14 | ring_buffer->ring_buffer[1] = malloc(sizeof(unsigned[devices_count][per_device_data_saved][buffer_size])); 15 | if (!ring_buffer->ring_buffer[1]) { 16 | perror("Cannot allocate memory: "); 17 | exit(EXIT_FAILURE); 18 | } 19 | ring_buffer->buffer_size = buffer_size; 20 | ring_buffer->per_device_data_saved = per_device_data_saved; 21 | ring_buffer->monitored_dev_count = devices_count; 22 | } 23 | 24 | void interface_free_ring_buffer(interface_ring_buffer *buffer) { 25 | free(buffer->ring_buffer[0]); 26 | free(buffer->ring_buffer[1]); 27 | } 28 | 29 | extern inline unsigned interface_ring_buffer_data_stored(const interface_ring_buffer *buff, unsigned device, 30 | unsigned which_data); 31 | 32 | extern inline unsigned interface_index_in_ring(const interface_ring_buffer *buff, unsigned device, unsigned which_data, 33 | unsigned index); 34 | 35 | extern inline unsigned interface_ring_buffer_get(const interface_ring_buffer *buff, unsigned device, 36 | unsigned which_data, unsigned index); 37 | 38 | extern inline void interface_ring_buffer_push(interface_ring_buffer *buff, unsigned device, unsigned which_data, 39 | unsigned value); 40 | 41 | extern inline void interface_ring_buffer_pop(interface_ring_buffer *buff, unsigned device, unsigned which_data); 42 | 43 | extern inline void interface_ring_buffer_empty_select(interface_ring_buffer *buff, unsigned device, 44 | unsigned which_data); 45 | 46 | extern inline void interface_ring_buffer_empty(interface_ring_buffer *buff, unsigned device); 47 | -------------------------------------------------------------------------------- /src/mali_common.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Copyright (C) 2023 Adrian Larumbe 4 | * 5 | * This file is part of Nvtop and adapted from the msm implementation. 6 | * 7 | * Nvtop is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * Nvtop is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with nvtop. If not, see . 19 | * 20 | */ 21 | 22 | #include "nvtop/device_discovery.h" 23 | #include "nvtop/extract_gpuinfo_common.h" 24 | #include "nvtop/extract_processinfo_fdinfo.h" 25 | #include "nvtop/time.h" 26 | #include 27 | #include 28 | 29 | #define MAX_ERR_STRING_LEN 256 30 | 31 | // Declaration not present in xf86drm.h on Ubuntu 20.04 32 | extern int drmGetDeviceFromDevId(dev_t dev_id, uint32_t flags, drmDevicePtr *device); 33 | 34 | struct drmFuncTable { 35 | typeof(drmGetDevices) *drmGetDevices; 36 | typeof(drmGetDevices2) *drmGetDevices2; 37 | typeof(drmFreeDevices) *drmFreeDevices; 38 | typeof(drmGetVersion) *drmGetVersion; 39 | typeof(drmFreeVersion) *drmFreeVersion; 40 | typeof(drmGetMagic) *drmGetMagic; 41 | typeof(drmAuthMagic) *drmAuthMagic; 42 | typeof(drmDropMaster) *drmDropMaster; 43 | typeof(drmCommandWriteRead) *drmCommandWriteRead; 44 | typeof(drmGetDeviceFromDevId) *drmGetDeviceFromDevId; 45 | typeof(drmIoctl) *drmIoctl; 46 | }; 47 | 48 | enum mali_version { 49 | MALI_PANFROST, 50 | MALI_PANTHOR, 51 | MALI_VERSIONS, 52 | }; 53 | 54 | struct mali_process_info_cache; 55 | 56 | struct panfrost_driver_data { 57 | bool original_profiling_state; 58 | bool profiler_enabled; 59 | char *sysfs_filename; 60 | }; 61 | struct panthor_driver_data { 62 | uint32_t unused; 63 | }; 64 | 65 | struct gpu_info_mali { 66 | drmVersionPtr drmVersion; 67 | enum mali_version version; 68 | struct gpu_info base; 69 | int fd; 70 | 71 | // Cached processes info 72 | struct mali_process_info_cache *last_update_process_cache; 73 | struct mali_process_info_cache *current_update_process_cache; 74 | 75 | union { 76 | struct panfrost_driver_data panfrost; 77 | struct panthor_driver_data panthor; 78 | } model; 79 | }; 80 | 81 | struct mali_gpu_state { 82 | unsigned mali_gpu_count; 83 | struct gpu_info_mali *gpu_infos; 84 | 85 | void *libdrm_handle; 86 | FILE *meminfo_file; 87 | 88 | int last_libdrm_return_status; 89 | char *didnt_call_gpuinfo_init; 90 | char *local_error_string; 91 | }; 92 | 93 | typedef void (*check_fdinfo_keys)(bool *is_engine, bool *is_cycles, 94 | bool *is_maxfreq, bool *is_curfreq, 95 | bool *is_resident, char *key); 96 | 97 | struct fdinfo_data { 98 | uint64_t total_cycles; 99 | bool client_id_set; 100 | unsigned int engine_count; 101 | unsigned cid; 102 | }; 103 | 104 | #define HASH_FIND_CLIENT(head, key_ptr, out_ptr) HASH_FIND(hh, head, key_ptr, sizeof(struct unique_cache_id), out_ptr) 105 | #define HASH_ADD_CLIENT(head, in_ptr) HASH_ADD(hh, head, client_id, sizeof(struct unique_cache_id), in_ptr) 106 | 107 | #define SET_MALI_CACHE(cachePtr, field, value) SET_VALUE(cachePtr, field, value, mali_cache_) 108 | #define RESET_PANFROST_CACHE(cachePtr, field) INVALIDATE_VALUE(cachePtr, field, mali_cache_) 109 | #define MALI_CACHE_FIELD_VALID(cachePtr, field) VALUE_IS_VALID(cachePtr, field, mali_cache_) 110 | 111 | uint64_t parse_memory_multiplier(const char *str); 112 | 113 | bool mali_init_drm_funcs(struct drmFuncTable *drmFuncs, struct mali_gpu_state *state); 114 | void mali_deinit_drm(struct mali_gpu_state *state); 115 | void mali_shutdown_common(struct mali_gpu_state *state, struct drmFuncTable *funcs); 116 | const char *mali_common_last_error_string(struct mali_gpu_state *state, 117 | const char *drivername, 118 | char error_str[]); 119 | bool mali_common_get_device_handles(struct mali_gpu_state *state, 120 | struct drmFuncTable *funcs, 121 | struct gpu_vendor *vendor, 122 | processinfo_fdinfo_callback callback, 123 | struct list_head *devices, unsigned *count, 124 | bool (*handle_model) (struct gpu_info_mali *), 125 | enum mali_version version); 126 | void mali_common_refresh_dynamic_info(struct gpuinfo_dynamic_info *dynamic_info, 127 | struct mali_gpu_state *state, 128 | const char *meminfo_total, 129 | const char *meminfo_available); 130 | void mali_common_get_running_processes(struct gpu_info *_gpu_info, enum mali_version version); 131 | 132 | void mali_common_parse_fdinfo_handle_cache(struct gpu_info_mali *gpu_info, 133 | struct gpu_process *process_info, 134 | nvtop_time current_time, 135 | uint64_t total_cycles, 136 | unsigned cid, 137 | bool engine_count); 138 | 139 | bool mali_common_parse_drm_fdinfo(struct gpu_info *info, FILE *fdinfo_file, 140 | struct gpu_process *process_info, 141 | struct gpuinfo_dynamic_info *dynamic_info, 142 | check_fdinfo_keys match_keys, 143 | struct fdinfo_data *fid); 144 | -------------------------------------------------------------------------------- /src/panfrost_drm.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: MIT */ 2 | /* 3 | * Copyright © 2014-2018 Broadcom 4 | * Copyright © 2019 Collabora ltd. 5 | */ 6 | #ifndef _PANFROST_DRM_H_ 7 | #define _PANFROST_DRM_H_ 8 | 9 | #include "drm.h" 10 | 11 | #if defined(__cplusplus) 12 | extern "C" { 13 | #endif 14 | 15 | #define DRM_PANFROST_SUBMIT 0x00 16 | #define DRM_PANFROST_WAIT_BO 0x01 17 | #define DRM_PANFROST_CREATE_BO 0x02 18 | #define DRM_PANFROST_MMAP_BO 0x03 19 | #define DRM_PANFROST_GET_PARAM 0x04 20 | #define DRM_PANFROST_GET_BO_OFFSET 0x05 21 | #define DRM_PANFROST_PERFCNT_ENABLE 0x06 22 | #define DRM_PANFROST_PERFCNT_DUMP 0x07 23 | #define DRM_PANFROST_MADVISE 0x08 24 | 25 | #define DRM_IOCTL_PANFROST_SUBMIT DRM_IOW(DRM_COMMAND_BASE + DRM_PANFROST_SUBMIT, struct drm_panfrost_submit) 26 | #define DRM_IOCTL_PANFROST_WAIT_BO DRM_IOW(DRM_COMMAND_BASE + DRM_PANFROST_WAIT_BO, struct drm_panfrost_wait_bo) 27 | #define DRM_IOCTL_PANFROST_CREATE_BO DRM_IOWR(DRM_COMMAND_BASE + DRM_PANFROST_CREATE_BO, struct drm_panfrost_create_bo) 28 | #define DRM_IOCTL_PANFROST_MMAP_BO DRM_IOWR(DRM_COMMAND_BASE + DRM_PANFROST_MMAP_BO, struct drm_panfrost_mmap_bo) 29 | #define DRM_IOCTL_PANFROST_GET_PARAM DRM_IOWR(DRM_COMMAND_BASE + DRM_PANFROST_GET_PARAM, struct drm_panfrost_get_param) 30 | #define DRM_IOCTL_PANFROST_GET_BO_OFFSET DRM_IOWR(DRM_COMMAND_BASE + DRM_PANFROST_GET_BO_OFFSET, struct drm_panfrost_get_bo_offset) 31 | #define DRM_IOCTL_PANFROST_MADVISE DRM_IOWR(DRM_COMMAND_BASE + DRM_PANFROST_MADVISE, struct drm_panfrost_madvise) 32 | 33 | /* 34 | * Unstable ioctl(s): only exposed when the unsafe unstable_ioctls module 35 | * param is set to true. 36 | * All these ioctl(s) are subject to deprecation, so please don't rely on 37 | * them for anything but debugging purpose. 38 | */ 39 | #define DRM_IOCTL_PANFROST_PERFCNT_ENABLE DRM_IOW(DRM_COMMAND_BASE + DRM_PANFROST_PERFCNT_ENABLE, struct drm_panfrost_perfcnt_enable) 40 | #define DRM_IOCTL_PANFROST_PERFCNT_DUMP DRM_IOW(DRM_COMMAND_BASE + DRM_PANFROST_PERFCNT_DUMP, struct drm_panfrost_perfcnt_dump) 41 | 42 | #define PANFROST_JD_REQ_FS (1 << 0) 43 | /** 44 | * struct drm_panfrost_submit - ioctl argument for submitting commands to the 3D 45 | * engine. 46 | * 47 | * This asks the kernel to have the GPU execute a render command list. 48 | */ 49 | struct drm_panfrost_submit { 50 | 51 | /** Address to GPU mapping of job descriptor */ 52 | __u64 jc; 53 | 54 | /** An optional array of sync objects to wait on before starting this job. */ 55 | __u64 in_syncs; 56 | 57 | /** Number of sync objects to wait on before starting this job. */ 58 | __u32 in_sync_count; 59 | 60 | /** An optional sync object to place the completion fence in. */ 61 | __u32 out_sync; 62 | 63 | /** Pointer to a u32 array of the BOs that are referenced by the job. */ 64 | __u64 bo_handles; 65 | 66 | /** Number of BO handles passed in (size is that times 4). */ 67 | __u32 bo_handle_count; 68 | 69 | /** A combination of PANFROST_JD_REQ_* */ 70 | __u32 requirements; 71 | }; 72 | 73 | /** 74 | * struct drm_panfrost_wait_bo - ioctl argument for waiting for 75 | * completion of the last DRM_PANFROST_SUBMIT on a BO. 76 | * 77 | * This is useful for cases where multiple processes might be 78 | * rendering to a BO and you want to wait for all rendering to be 79 | * completed. 80 | */ 81 | struct drm_panfrost_wait_bo { 82 | __u32 handle; 83 | __u32 pad; 84 | __s64 timeout_ns; /* absolute */ 85 | }; 86 | 87 | /* Valid flags to pass to drm_panfrost_create_bo */ 88 | #define PANFROST_BO_NOEXEC 1 89 | #define PANFROST_BO_HEAP 2 90 | 91 | /** 92 | * struct drm_panfrost_create_bo - ioctl argument for creating Panfrost BOs. 93 | * 94 | * The flags argument is a bit mask of PANFROST_BO_* flags. 95 | */ 96 | struct drm_panfrost_create_bo { 97 | __u32 size; 98 | __u32 flags; 99 | /** Returned GEM handle for the BO. */ 100 | __u32 handle; 101 | /* Pad, must be zero-filled. */ 102 | __u32 pad; 103 | /** 104 | * Returned offset for the BO in the GPU address space. This offset 105 | * is private to the DRM fd and is valid for the lifetime of the GEM 106 | * handle. 107 | * 108 | * This offset value will always be nonzero, since various HW 109 | * units treat 0 specially. 110 | */ 111 | __u64 offset; 112 | }; 113 | 114 | /** 115 | * struct drm_panfrost_mmap_bo - ioctl argument for mapping Panfrost BOs. 116 | * 117 | * This doesn't actually perform an mmap. Instead, it returns the 118 | * offset you need to use in an mmap on the DRM device node. This 119 | * means that tools like valgrind end up knowing about the mapped 120 | * memory. 121 | * 122 | * There are currently no values for the flags argument, but it may be 123 | * used in a future extension. 124 | */ 125 | struct drm_panfrost_mmap_bo { 126 | /** Handle for the object being mapped. */ 127 | __u32 handle; 128 | __u32 flags; 129 | /** offset into the drm node to use for subsequent mmap call. */ 130 | __u64 offset; 131 | }; 132 | 133 | enum drm_panfrost_param { 134 | DRM_PANFROST_PARAM_GPU_PROD_ID, 135 | DRM_PANFROST_PARAM_GPU_REVISION, 136 | DRM_PANFROST_PARAM_SHADER_PRESENT, 137 | DRM_PANFROST_PARAM_TILER_PRESENT, 138 | DRM_PANFROST_PARAM_L2_PRESENT, 139 | DRM_PANFROST_PARAM_STACK_PRESENT, 140 | DRM_PANFROST_PARAM_AS_PRESENT, 141 | DRM_PANFROST_PARAM_JS_PRESENT, 142 | DRM_PANFROST_PARAM_L2_FEATURES, 143 | DRM_PANFROST_PARAM_CORE_FEATURES, 144 | DRM_PANFROST_PARAM_TILER_FEATURES, 145 | DRM_PANFROST_PARAM_MEM_FEATURES, 146 | DRM_PANFROST_PARAM_MMU_FEATURES, 147 | DRM_PANFROST_PARAM_THREAD_FEATURES, 148 | DRM_PANFROST_PARAM_MAX_THREADS, 149 | DRM_PANFROST_PARAM_THREAD_MAX_WORKGROUP_SZ, 150 | DRM_PANFROST_PARAM_THREAD_MAX_BARRIER_SZ, 151 | DRM_PANFROST_PARAM_COHERENCY_FEATURES, 152 | DRM_PANFROST_PARAM_TEXTURE_FEATURES0, 153 | DRM_PANFROST_PARAM_TEXTURE_FEATURES1, 154 | DRM_PANFROST_PARAM_TEXTURE_FEATURES2, 155 | DRM_PANFROST_PARAM_TEXTURE_FEATURES3, 156 | DRM_PANFROST_PARAM_JS_FEATURES0, 157 | DRM_PANFROST_PARAM_JS_FEATURES1, 158 | DRM_PANFROST_PARAM_JS_FEATURES2, 159 | DRM_PANFROST_PARAM_JS_FEATURES3, 160 | DRM_PANFROST_PARAM_JS_FEATURES4, 161 | DRM_PANFROST_PARAM_JS_FEATURES5, 162 | DRM_PANFROST_PARAM_JS_FEATURES6, 163 | DRM_PANFROST_PARAM_JS_FEATURES7, 164 | DRM_PANFROST_PARAM_JS_FEATURES8, 165 | DRM_PANFROST_PARAM_JS_FEATURES9, 166 | DRM_PANFROST_PARAM_JS_FEATURES10, 167 | DRM_PANFROST_PARAM_JS_FEATURES11, 168 | DRM_PANFROST_PARAM_JS_FEATURES12, 169 | DRM_PANFROST_PARAM_JS_FEATURES13, 170 | DRM_PANFROST_PARAM_JS_FEATURES14, 171 | DRM_PANFROST_PARAM_JS_FEATURES15, 172 | DRM_PANFROST_PARAM_NR_CORE_GROUPS, 173 | DRM_PANFROST_PARAM_THREAD_TLS_ALLOC, 174 | DRM_PANFROST_PARAM_AFBC_FEATURES, 175 | DRM_PANFROST_PARAM_MAX_FREQ, 176 | }; 177 | 178 | struct drm_panfrost_get_param { 179 | __u32 param; 180 | __u32 pad; 181 | __u64 value; 182 | }; 183 | 184 | /** 185 | * Returns the offset for the BO in the GPU address space for this DRM fd. 186 | * This is the same value returned by drm_panfrost_create_bo, if that was called 187 | * from this DRM fd. 188 | */ 189 | struct drm_panfrost_get_bo_offset { 190 | __u32 handle; 191 | __u32 pad; 192 | __u64 offset; 193 | }; 194 | 195 | struct drm_panfrost_perfcnt_enable { 196 | __u32 enable; 197 | /* 198 | * On bifrost we have 2 sets of counters, this parameter defines the 199 | * one to track. 200 | */ 201 | __u32 counterset; 202 | }; 203 | 204 | struct drm_panfrost_perfcnt_dump { 205 | __u64 buf_ptr; 206 | }; 207 | 208 | /* madvise provides a way to tell the kernel in case a buffers contents 209 | * can be discarded under memory pressure, which is useful for userspace 210 | * bo cache where we want to optimistically hold on to buffer allocate 211 | * and potential mmap, but allow the pages to be discarded under memory 212 | * pressure. 213 | * 214 | * Typical usage would involve madvise(DONTNEED) when buffer enters BO 215 | * cache, and madvise(WILLNEED) if trying to recycle buffer from BO cache. 216 | * In the WILLNEED case, 'retained' indicates to userspace whether the 217 | * backing pages still exist. 218 | */ 219 | #define PANFROST_MADV_WILLNEED 0 /* backing pages are needed, status returned in 'retained' */ 220 | #define PANFROST_MADV_DONTNEED 1 /* backing pages not needed */ 221 | 222 | struct drm_panfrost_madvise { 223 | __u32 handle; /* in, GEM handle */ 224 | __u32 madv; /* in, PANFROST_MADV_x */ 225 | __u32 retained; /* out, whether backing store still exists */ 226 | }; 227 | 228 | /* Definitions for coredump decoding in user space */ 229 | #define PANFROSTDUMP_MAJOR 1 230 | #define PANFROSTDUMP_MINOR 0 231 | 232 | #define PANFROSTDUMP_MAGIC 0x464E4150 /* PANF */ 233 | 234 | #define PANFROSTDUMP_BUF_REG 0 235 | #define PANFROSTDUMP_BUF_BOMAP (PANFROSTDUMP_BUF_REG + 1) 236 | #define PANFROSTDUMP_BUF_BO (PANFROSTDUMP_BUF_BOMAP + 1) 237 | #define PANFROSTDUMP_BUF_TRAILER (PANFROSTDUMP_BUF_BO + 1) 238 | 239 | /* 240 | * This structure is the native endianness of the dumping machine, tools can 241 | * detect the endianness by looking at the value in 'magic'. 242 | */ 243 | struct panfrost_dump_object_header { 244 | __u32 magic; 245 | __u32 type; 246 | __u32 file_size; 247 | __u32 file_offset; 248 | 249 | union { 250 | struct { 251 | __u64 jc; 252 | __u32 gpu_id; 253 | __u32 major; 254 | __u32 minor; 255 | __u64 nbos; 256 | } reghdr; 257 | 258 | struct { 259 | __u32 valid; 260 | __u64 iova; 261 | __u32 data[2]; 262 | } bomap; 263 | 264 | /* 265 | * Force same size in case we want to expand the header 266 | * with new fields and also keep it 512-byte aligned 267 | */ 268 | 269 | __u32 sizer[496]; 270 | }; 271 | }; 272 | 273 | /* Registers object, an array of these */ 274 | struct panfrost_dump_registers { 275 | __u32 reg; 276 | __u32 value; 277 | }; 278 | 279 | #if defined(__cplusplus) 280 | } 281 | #endif 282 | 283 | #endif /* _PANFROST_DRM_H_ */ 284 | -------------------------------------------------------------------------------- /src/panfrost_utils.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Copyright (C) 2023 Adrian Larumbe 4 | * 5 | * Nvtop is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * Nvtop is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with nvtop. If not, see . 17 | * 18 | */ 19 | 20 | #include 21 | 22 | const char * panfrost_parse_marketing_name(uint64_t gpu_id); 23 | unsigned int util_last_bit(unsigned int u); 24 | unsigned int get_number_engines(uint32_t gpu_id, int core_count, uint32_t core_features, uint32_t thread_features); 25 | -------------------------------------------------------------------------------- /src/panthor_utils.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Copyright (C) 2023 Adrian Larumbe 4 | * 5 | * Nvtop is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * Nvtop is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with nvtop. If not, see . 17 | * 18 | */ 19 | 20 | #include 21 | 22 | const char * panthor_device_name(uint32_t gpu_id); 23 | -------------------------------------------------------------------------------- /src/plot.c: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Copyright (C) 2019-2021 Maxime Schmitt 4 | * 5 | * This file is part of Nvtop. 6 | * 7 | * Nvtop is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * Nvtop is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with nvtop. If not, see . 19 | * 20 | */ 21 | 22 | #include "nvtop/plot.h" 23 | #include "nvtop/common.h" 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | static inline int data_level(double rows, double data, double increment) { 32 | return (int)(rows - round(data / increment)); 33 | } 34 | 35 | void nvtop_line_plot(WINDOW *win, size_t num_data, const double *data, unsigned num_lines, bool legend_left, 36 | char legend[MAX_LINES_PER_PLOT][PLOT_MAX_LEGEND_SIZE]) { 37 | if (num_data == 0) 38 | return; 39 | int rows, cols; 40 | getmaxyx(win, rows, cols); 41 | rows -= 1; 42 | double increment = 100. / (double)(rows); 43 | 44 | assert(num_lines <= MAX_LINES_PER_PLOT && "Cannot plot more than " EXPAND_AND_QUOTE(MAX_LINES_PER_PLOT) " lines"); 45 | unsigned lvl_before[MAX_LINES_PER_PLOT]; 46 | for (size_t k = 0; k < num_lines; ++k) 47 | lvl_before[k] = data_level(rows, data[k], increment); 48 | 49 | for (size_t i = 0; i < num_data || i < (size_t)cols; i += num_lines) { 50 | for (unsigned k = 0; k < num_lines; ++k) { 51 | unsigned lvl_now_k = data_level(rows, data[i + k], increment); 52 | wcolor_set(win, k + 1, NULL); 53 | // Three cases: has increased, has decreased and remained level 54 | if (lvl_before[k] < lvl_now_k || lvl_before[k] > lvl_now_k) { 55 | // Case 1 and 2: has increased/decreased 56 | 57 | // An increase goes down on the plot because (0,0) is top left 58 | bool drawing_down = lvl_before[k] < lvl_now_k; 59 | unsigned bottom = drawing_down ? lvl_before[k] : lvl_now_k; 60 | unsigned top = drawing_down ? lvl_now_k : lvl_before[k]; 61 | 62 | // Draw the vertical line corners 63 | mvwaddch(win, bottom, i + k, drawing_down ? ACS_URCORNER : ACS_ULCORNER); 64 | mvwaddch(win, top, i + k, drawing_down ? ACS_LLCORNER : ACS_LRCORNER); 65 | // Draw the vertical line between the corners 66 | if (top - bottom > 1) { 67 | mvwvline(win, bottom + 1, i + k, 0, top - bottom - 1); 68 | } 69 | 70 | // Draw the continuation of the other metrics 71 | for (unsigned j = 0; j < num_lines; ++j) { 72 | if (j != k) { 73 | if (lvl_before[j] == top) 74 | // The continuation is at the same level as the bottom corner 75 | mvwaddch(win, top, i + k, ACS_BTEE); 76 | else if (lvl_before[j] == bottom) 77 | // The continuation is at the same level as the top corner 78 | mvwaddch(win, bottom, i + k, ACS_TTEE); 79 | else if (lvl_before[j] > bottom && lvl_before[j] < top) 80 | // The continuation lies on the vertical line 81 | mvwaddch(win, lvl_before[j], i + k, ACS_PLUS); 82 | else { 83 | // The continuation lies outside the update interval so keep the 84 | // color 85 | wcolor_set(win, j + 1, NULL); 86 | mvwaddch(win, lvl_before[j], i + k, ACS_HLINE); 87 | wcolor_set(win, k + 1, NULL); 88 | } 89 | } 90 | } 91 | } else { 92 | // Case 3: stayed level 93 | mvwhline(win, lvl_now_k, i + k, 0, 1); 94 | for (unsigned j = 0; j < num_lines; ++j) { 95 | if (j != k) { 96 | if (lvl_before[j] != lvl_now_k) { 97 | // Add the continuation of other metric lines 98 | wcolor_set(win, j + 1, NULL); 99 | mvwaddch(win, lvl_before[j], i + k, ACS_HLINE); 100 | wcolor_set(win, k + 1, NULL); 101 | } 102 | } 103 | } 104 | } 105 | lvl_before[k] = lvl_now_k; 106 | } 107 | } 108 | int plot_y_position = 0; 109 | for (unsigned i = 0; i < num_lines && plot_y_position < rows; ++i) { 110 | wcolor_set(win, i + 1, NULL); 111 | if (legend_left) { 112 | mvwprintw(win, plot_y_position, 0, "%.*s", cols, legend[i]); 113 | } else { 114 | size_t length = strlen(legend[i]); 115 | if (length <= (size_t)cols) { 116 | mvwprintw(win, plot_y_position, cols - length, "%s", legend[i]); 117 | } else { 118 | mvwprintw(win, plot_y_position, 0, "%.*s", (int)(length - cols), legend[i]); 119 | } 120 | } 121 | plot_y_position++; 122 | } 123 | } 124 | 125 | void draw_rectangle(WINDOW *win, unsigned startX, unsigned startY, unsigned sizeX, unsigned sizeY) { 126 | mvwhline(win, startY, startX + 1, 0, sizeX - 2); 127 | mvwhline(win, startY + sizeY - 1, startX + 1, 0, sizeX - 2); 128 | 129 | mvwvline(win, startY + 1, startX, 0, sizeY - 2); 130 | mvwvline(win, startY + 1, startX + sizeX - 1, 0, sizeY - 2); 131 | 132 | mvwaddch(win, startY, startX, ACS_ULCORNER); 133 | mvwaddch(win, startY, startX + sizeX - 1, ACS_URCORNER); 134 | mvwaddch(win, startY + sizeY - 1, startX, ACS_LLCORNER); 135 | mvwaddch(win, startY + sizeY - 1, startX + sizeX - 1, ACS_LRCORNER); 136 | } 137 | -------------------------------------------------------------------------------- /src/time.c: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Copyright (C) 2018-2022 Maxime Schmitt 4 | * 5 | * This file is part of Nvtop. 6 | * 7 | * Nvtop is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * Nvtop is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with nvtop. If not, see . 19 | * 20 | */ 21 | 22 | #include "nvtop/time.h" 23 | 24 | extern inline void nvtop_get_current_time(nvtop_time *time); 25 | extern inline double nvtop_difftime(nvtop_time t0, nvtop_time t1); 26 | extern inline uint64_t nvtop_difftime_u64(nvtop_time t0, nvtop_time t1); 27 | extern inline uint64_t nvtop_time_u64(nvtop_time t0); 28 | extern inline nvtop_time nvtop_add_time(nvtop_time t0, nvtop_time t1); 29 | extern inline nvtop_time nvtop_substract_time(nvtop_time t0, nvtop_time t1); 30 | extern inline nvtop_time nvtop_hmns_to_time(unsigned hour, unsigned minutes, unsigned long nanosec); 31 | -------------------------------------------------------------------------------- /tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | find_package(GTest) 2 | if (BUILD_TESTING AND GTest_FOUND) 3 | 4 | option(THOROUGH_TESTING "Enable extensive testing (takes hours, e.g., use once per release)" OFF) 5 | 6 | # Create a library for testing 7 | add_library(testLib 8 | ${PROJECT_SOURCE_DIR}/src/interface_layout_selection.c 9 | ${PROJECT_SOURCE_DIR}/src/extract_processinfo_fdinfo.c 10 | ${PROJECT_SOURCE_DIR}/src/interface_options.c 11 | ${PROJECT_SOURCE_DIR}/src/ini.c 12 | ) 13 | target_include_directories(testLib PUBLIC 14 | ${PROJECT_SOURCE_DIR}/include 15 | ${PROJECT_BINARY_DIR}/include) 16 | 17 | # Tests 18 | add_executable( 19 | interfaceTests 20 | interfaceTests.cpp 21 | ) 22 | target_link_libraries(interfaceTests PRIVATE testLib GTest::gtest_main) 23 | gtest_discover_tests(interfaceTests) 24 | 25 | if (THOROUGH_TESTING) 26 | target_compile_definitions(interfaceTests PRIVATE THOROUGH_TESTING) 27 | endif() 28 | 29 | 30 | endif() 31 | --------------------------------------------------------------------------------