├── .github └── workflows │ ├── build-image.yml │ └── update-description.yml ├── .gitignore ├── .rspec ├── Dockerfile ├── Gemfile ├── Gemfile.lock ├── LICENSE ├── README.md ├── app ├── application.rb ├── exporter.rb ├── n_vidia_smi.rb └── n_vidia_smi_xml.rb └── spec ├── fixtures ├── nvidia-smi-1.csv ├── nvidia-smi-2.csv ├── nvidia-smi-3.xml ├── nvidia-smi-4.xml ├── parsed-1.json └── parsed-2.json ├── helpers └── fixture.rb ├── n_vidia_smi_spec.rb ├── n_vidia_smi_xml_spec.rb └── spec_helper.rb /.github/workflows/build-image.yml: -------------------------------------------------------------------------------- 1 | name: Docker image 2 | on: 3 | release: 4 | types: [published] 5 | jobs: 6 | build: 7 | name: rspec 8 | runs-on: ubuntu-latest 9 | 10 | steps: 11 | - uses: actions/checkout@v1 12 | - uses: actions/setup-ruby@v1 13 | with: 14 | ruby-version: 3.0.0 15 | 16 | - name: Run bundle install 17 | run: | 18 | gem install bundler 19 | bundle install --jobs 4 --retry 3 20 | 21 | - name: Build and test with rspec 22 | env: 23 | RAILS_ENV: test 24 | run: bundle exec rspec 25 | 26 | buildx: 27 | name: build and push image 28 | runs-on: ubuntu-latest 29 | 30 | steps: 31 | - name: Checkout 32 | uses: actions/checkout@v2 33 | 34 | - name: Variables 35 | id: variables 36 | run: | 37 | echo ::set-output name=SOURCE_NAME::${GITHUB_REF#refs/*/} 38 | echo ::set-output name=SOURCE_BRANCH::${GITHUB_REF#refs/heads/} 39 | echo ::set-output name=SOURCE_TAG::${GITHUB_REF#refs/tags/} 40 | echo ::set-output name=REPOSITORY_NAME::$(echo "$GITHUB_REPOSITORY" | awk -F / '{print $2}') 41 | echo ::set-output name=FULL_VERSION::$(git describe --tags --dirty --always) 42 | echo ::set-output name=TARGET_PLATFORMS::"linux/amd64" 43 | - name: Set up Docker Buildx 44 | id: buildx 45 | uses: crazy-max/ghaction-docker-buildx@v3 46 | with: 47 | buildx-version: latest 48 | qemu-version: latest 49 | 50 | - name: Available platforms 51 | run: echo ${{ steps.buildx.outputs.platforms }} 52 | 53 | - name: Login to DockerHub 54 | run: echo "${{ secrets.DOCKERHUB_PASSWORD }}" | docker login -u "${{ secrets.DOCKERHUB_USERNAME }}" --password-stdin 55 | 56 | - name: Build and push tag 57 | run: | 58 | docker buildx build \ 59 | --platform ${{ steps.variables.outputs.TARGET_PLATFORMS }} \ 60 | --build-arg FULL_VERSION=${{ steps.variables.outputs.FULL_VERSION }} \ 61 | -t a00s/${{ steps.variables.outputs.REPOSITORY_NAME }}:${{ steps.variables.outputs.SOURCE_TAG }} \ 62 | . \ 63 | --push 64 | - name: Build and push latest 65 | run: | 66 | docker buildx build \ 67 | --platform ${{ steps.variables.outputs.TARGET_PLATFORMS }} \ 68 | --build-arg FULL_VERSION=${{ steps.variables.outputs.FULL_VERSION }} \ 69 | -t a00s/${{ steps.variables.outputs.REPOSITORY_NAME }}:latest \ 70 | . \ 71 | --push 72 | -------------------------------------------------------------------------------- /.github/workflows/update-description.yml: -------------------------------------------------------------------------------- 1 | name: Update Docker Hub Description 2 | on: 3 | push: 4 | branches: 5 | - master 6 | paths: 7 | - README.md 8 | - .github/workflows/update-description.yml 9 | jobs: 10 | dockerHubDescription: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - name: Variables 14 | id: variables 15 | run: | 16 | echo ::set-output name=SOURCE_NAME::${GITHUB_REF#refs/*/} 17 | echo ::set-output name=SOURCE_BRANCH::${GITHUB_REF#refs/heads/} 18 | echo ::set-output name=SOURCE_TAG::${GITHUB_REF#refs/tags/} 19 | echo ::set-output name=REPOSITORY_NAME::$(echo "$GITHUB_REPOSITORY" | awk -F / '{print $2}') 20 | - name: Checkout 21 | uses: actions/checkout@v2 22 | 23 | - name: Docker Hub Description 24 | uses: peter-evans/dockerhub-description@v2 25 | env: 26 | DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }} 27 | DOCKERHUB_PASSWORD: ${{ secrets.DOCKERHUB_PASSWORD }} 28 | DOCKERHUB_REPOSITORY: a00s/${{ steps.variables.outputs.REPOSITORY_NAME }} 29 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .ruby-* 2 | .envrc 3 | .idea/ 4 | -------------------------------------------------------------------------------- /.rspec: -------------------------------------------------------------------------------- 1 | --require spec_helper 2 | --no-profile 3 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ruby:3.0.0-buster 2 | 3 | ENV LANG C.UTF-8 4 | ENV DEBIAN_FRONTEND noninteractive 5 | 6 | ARG NVIDIA_PUB_KEY="https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2004/x86_64/7fa2af80.pub" 7 | ARG NVIDIA_REPO="deb https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2004/x86_64 /" 8 | ARG NVIDIA_VERSION="460.32.03-0ubuntu1" 9 | 10 | WORKDIR /app 11 | COPY . /app 12 | 13 | RUN \ 14 | apt-get update \ 15 | && apt-get install -y --no-install-recommends build-essential wget \ 16 | && wget -qO - ${NVIDIA_PUB_KEY} | apt-key add - \ 17 | && echo ${NVIDIA_REPO} > /etc/apt/sources.list.d/cuda.list \ 18 | && apt-get update \ 19 | && apt-get install -y --no-install-recommends libnvidia-compute-460=${NVIDIA_VERSION} nvidia-utils-460=${NVIDIA_VERSION} \ 20 | && rm -rf /var/lib/apt/lists/* \ 21 | && bundle install --deployment --without test 22 | 23 | CMD ["bundle", "exec", "ruby", "app/application.rb", "1>&2"] 24 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gem 'sinatra' 4 | gem 'puma' 5 | gem 'activesupport' 6 | gem 'nokogiri' 7 | 8 | group :test do 9 | gem 'rspec' 10 | end 11 | 12 | group :development do 13 | gem 'pry' 14 | end 15 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | activesupport (6.1.3) 5 | concurrent-ruby (~> 1.0, >= 1.0.2) 6 | i18n (>= 1.6, < 2) 7 | minitest (>= 5.1) 8 | tzinfo (~> 2.0) 9 | zeitwerk (~> 2.3) 10 | coderay (1.1.3) 11 | concurrent-ruby (1.1.8) 12 | diff-lcs (1.4.4) 13 | i18n (1.8.9) 14 | concurrent-ruby (~> 1.0) 15 | method_source (1.0.0) 16 | mini_portile2 (2.8.0) 17 | minitest (5.14.4) 18 | mustermann (1.1.1) 19 | ruby2_keywords (~> 0.0.1) 20 | nio4r (2.5.8) 21 | nokogiri (1.13.6) 22 | mini_portile2 (~> 2.8.0) 23 | racc (~> 1.4) 24 | pry (0.14.0) 25 | coderay (~> 1.1) 26 | method_source (~> 1.0) 27 | puma (5.6.4) 28 | nio4r (~> 2.0) 29 | racc (1.6.0) 30 | rack (2.2.3.1) 31 | rack-protection (2.2.0) 32 | rack 33 | rspec (3.10.0) 34 | rspec-core (~> 3.10.0) 35 | rspec-expectations (~> 3.10.0) 36 | rspec-mocks (~> 3.10.0) 37 | rspec-core (3.10.1) 38 | rspec-support (~> 3.10.0) 39 | rspec-expectations (3.10.1) 40 | diff-lcs (>= 1.2.0, < 2.0) 41 | rspec-support (~> 3.10.0) 42 | rspec-mocks (3.10.2) 43 | diff-lcs (>= 1.2.0, < 2.0) 44 | rspec-support (~> 3.10.0) 45 | rspec-support (3.10.2) 46 | ruby2_keywords (0.0.5) 47 | sinatra (2.2.0) 48 | mustermann (~> 1.0) 49 | rack (~> 2.2) 50 | rack-protection (= 2.2.0) 51 | tilt (~> 2.0) 52 | tilt (2.0.10) 53 | tzinfo (2.0.4) 54 | concurrent-ruby (~> 1.0) 55 | zeitwerk (2.4.2) 56 | 57 | PLATFORMS 58 | ruby 59 | 60 | DEPENDENCIES 61 | activesupport 62 | nokogiri 63 | pry 64 | puma 65 | rspec 66 | sinatra 67 | 68 | BUNDLED WITH 69 | 2.2.3 70 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Nvidia SMI Exporter 2 | --------------------- 3 | Another one nvidia-smi data exporter for Prometheus. 4 | 5 | 6 | 7 | ```bash 8 | > curl localhost:9454/ping 9 | OK 10 | 11 | > curl localhost:9454/metrics 12 | nvidia_smi_attached_gpus 2 13 | nvidia_smi_display_mode{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 1 14 | nvidia_smi_display_active{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 0 15 | nvidia_smi_persistence_mode{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 1 16 | nvidia_smi_accounting_mode{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 0 17 | nvidia_smi_accounting_mode_buffer_size{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 4000 18 | nvidia_smi_minor_number{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 0 19 | nvidia_smi_multigpu_board{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 0 20 | nvidia_smi_inforom_version_oem_object{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 1.1 21 | nvidia_smi_pci_pci_sub_system_id{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 37021458 22 | nvidia_smi_pci_pci_gpu_link_info_pcie_gen_max_link_gen{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 3 23 | nvidia_smi_pci_pci_gpu_link_info_pcie_gen_current_link_gen{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 3 24 | nvidia_smi_pci_pci_gpu_link_info_link_widths_max_link_width{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 16 25 | nvidia_smi_pci_pci_gpu_link_info_link_widths_current_link_width{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 1 26 | nvidia_smi_pci_replay_counter{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 65535 27 | nvidia_smi_pci_replay_rollover_counter{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 0 28 | nvidia_smi_pci_tx_util_bytes_per_second{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 11264000 29 | nvidia_smi_pci_rx_util_bytes_per_second{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 31744000 30 | nvidia_smi_fan_speed_ratio{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 0.53 31 | nvidia_smi_performance_state{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 2 32 | nvidia_smi_clocks_throttle_reasons_clocks_throttle_reason_gpu_idle{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 0 33 | nvidia_smi_clocks_throttle_reasons_clocks_throttle_reason_applications_clocks_setting{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 0 34 | nvidia_smi_clocks_throttle_reasons_clocks_throttle_reason_sw_power_cap{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 1 35 | nvidia_smi_clocks_throttle_reasons_clocks_throttle_reason_hw_slowdown{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 0 36 | nvidia_smi_clocks_throttle_reasons_clocks_throttle_reason_hw_thermal_slowdown{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 0 37 | nvidia_smi_clocks_throttle_reasons_clocks_throttle_reason_hw_power_brake_slowdown{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 0 38 | nvidia_smi_clocks_throttle_reasons_clocks_throttle_reason_sync_boost{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 0 39 | nvidia_smi_clocks_throttle_reasons_clocks_throttle_reason_sw_thermal_slowdown{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 0 40 | nvidia_smi_clocks_throttle_reasons_clocks_throttle_reason_display_clocks_setting{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 0 41 | nvidia_smi_fb_memory_usage_total_bytes{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 8510242816 42 | nvidia_smi_fb_memory_usage_used_bytes{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 3040870400 43 | nvidia_smi_fb_memory_usage_free_bytes{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 5469372416 44 | nvidia_smi_bar1_memory_usage_total_bytes{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 268435456 45 | nvidia_smi_bar1_memory_usage_used_bytes{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 5242880 46 | nvidia_smi_bar1_memory_usage_free_bytes{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 263192576 47 | nvidia_smi_compute_mode{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 0 48 | nvidia_smi_utilization_gpu_util_ratio{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 1.0 49 | nvidia_smi_utilization_memory_util_ratio{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 1.0 50 | nvidia_smi_utilization_encoder_util_ratio{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 0.0 51 | nvidia_smi_utilization_decoder_util_ratio{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 0.0 52 | nvidia_smi_encoder_stats_session_count{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 0 53 | nvidia_smi_encoder_stats_average_fps{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 0 54 | nvidia_smi_encoder_stats_average_latency{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 0 55 | nvidia_smi_fbc_stats_session_count{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 0 56 | nvidia_smi_fbc_stats_average_fps{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 0 57 | nvidia_smi_fbc_stats_average_latency{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 0 58 | nvidia_smi_temperature_gpu_temp_celsius{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 67.0 59 | nvidia_smi_temperature_gpu_temp_max_threshold_celsius{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 96.0 60 | nvidia_smi_temperature_gpu_temp_slow_threshold_celsius{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 93.0 61 | nvidia_smi_temperature_gpu_target_temperature_celsius{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 83.0 62 | nvidia_smi_supported_gpu_target_temp_gpu_target_temp_min_celsius{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 60.0 63 | nvidia_smi_supported_gpu_target_temp_gpu_target_temp_max_celsius{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 92.0 64 | nvidia_smi_power_readings_power_state{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 2 65 | nvidia_smi_power_readings_power_management{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 1 66 | nvidia_smi_power_readings_power_draw_watts{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 211.86 67 | nvidia_smi_power_readings_power_limit_watts{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 216.0 68 | nvidia_smi_power_readings_default_power_limit_watts{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 200.0 69 | nvidia_smi_power_readings_enforced_power_limit_watts{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 216.0 70 | nvidia_smi_power_readings_min_power_limit_watts{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 100.0 71 | nvidia_smi_power_readings_max_power_limit_watts{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 216.0 72 | nvidia_smi_clocks_graphics_clock_hz{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 1784000000.0 73 | nvidia_smi_clocks_sm_clock_hz{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 1784000000.0 74 | nvidia_smi_clocks_mem_clock_hz{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 5514000000.0 75 | nvidia_smi_clocks_video_clock_hz{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 1594000000.0 76 | nvidia_smi_max_clocks_graphics_clock_hz{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 1999000000.0 77 | nvidia_smi_max_clocks_sm_clock_hz{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 1999000000.0 78 | nvidia_smi_max_clocks_mem_clock_hz{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 5005000000.0 79 | nvidia_smi_max_clocks_video_clock_hz{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 1708000000.0 80 | ``` 81 | 82 | Caveats 83 | ======= 84 | 85 | In XML mode (see below) the exporter skips all implicit arrays like this: 86 | 87 | ```xml 88 | 89 | 90 | 3504 MHz 91 | 1721 MHz <== will skip all supported_graphics_clock 92 | 1708 MHz 93 | 1695 MHz 94 | 1683 MHz 95 | 1670 MHz 96 | 1657 MHz 97 | 1645 MHz 98 | 1632 MHz 99 | ``` 100 | 101 | Also, it skips all empty and "N/A" values (and their keys accordingly). 102 | 103 | Prometheus is [not supporting](https://github.com/prometheus/prometheus/issues/2227) string values, thus exporter converts some strings to numbers: 104 | - `Disabled`, `Not Active`, `No`, `Not Supported` and `Unsupported` will convert to 0 105 | - `Enabled`, `Active`, `Yes`, `Supported` will convert to 1 106 | - `P0`..`P15` will convert to 0..15 107 | - `1x`, `2x`, `4x`, `8x`, `16x`, `32x` (pci lines) will convert to 1,2,4,8,16,32 108 | - `Default`, `Exclusive_Thread`, `Prohibited`, `Exclusive_Process` (_compute_mode) will convert to 0..3 109 | 110 | Other not integer/float strings will eliminate. 111 | 112 | Run in Docker 113 | ============= 114 | 115 | `nvidia-smi` requires using the same versions of packages (`libnvidia-compute-460` and `nvidia-utils-460`) inside the container and outside (on the host). 116 | 117 | 1) Get driver version on the host: 118 | 119 | ```shell 120 | > dpkg --list | grep nvidia-driver-460 121 | ii nvidia-driver-460 460.27.04-0ubuntu1 amd64 NVIDIA driver metapackage 122 | ``` 123 | 124 | 2) Build container with appropriate version of driver: 125 | 126 | ```shell 127 | > docker build . --tag nvidia-smi-exporter --build-arg NVIDIA_VERSION=460.27.04-0ubuntu1 128 | ``` 129 | 130 | All available versions can be found [in the Cuda repository](https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2004/x86_64/) 131 | 132 | 3) Run with `--privileged` flag (not recommended due to security) 133 | ```shell 134 | > docker run --rm --privileged -p 9454:9454 nvidia-smi-exporter 135 | ``` 136 | 137 | or enumerating (map inside container) all devices explicitly 138 | 139 | ```shell 140 | > docker run --rm \ 141 | --device /dev/nvidiactl:/dev/nvidiactl \ 142 | --device /dev/nvidia0:/dev/nvidia0 \ 143 | --device /dev/nvidia1:/dev/nvidia1 \ 144 | -p 9454:9454 nvidia-smi-exporter 145 | ``` 146 | 147 | Parameters 148 | ================== 149 | 150 | There are several environment variables to setting runtime parameters: 151 | 152 | - `NVIDIA_SMI_EXPORTER_BINARY` - path to nvidia-smi executive binary, default: `$(which nvidia-smi)` 153 | 154 | - `NVIDIA_SMI_EXPORTER_PORT` - a port where the server will be started, default: `9454` 155 | 156 | - `NVIDIA_SMI_EXPORTER_HOST` - a host where the server will be started, default: `0.0.0.0` 157 | 158 | - `NVIDIA_SMI_EXPORTER_NAME_PREFIX` - prefix for every parameter name in output, default: `nvidia_smi_` 159 | 160 | - `NVIDIA_SMI_EXPORTER_SOURCE` - source to processing - `xml` or `csv`, default: `xml`. 161 | 162 | 163 | When `NVIDIA_SMI_EXPORTER_SOURCE` == `csv`: 164 | 165 | - `NVIDIA_SMI_EXPORTER_QUERY` - comma-separated list to query parameters from nvidia-smi, default: `clocks.current.graphics,clocks.current.memory,clocks.current.sm,clocks.current.video,clocks.max.graphics,clocks.max.memory,clocks.max.sm,fan.speed,memory.total,memory.used,power.draw,power.limit,temperature.gpu,utilization.gpu,utilization.memory` 166 | -------------------------------------------------------------------------------- /app/application.rb: -------------------------------------------------------------------------------- 1 | require 'open3' 2 | require_relative 'exporter' 3 | 4 | class Application 5 | def initialize 6 | Thread.abort_on_exception = true 7 | 8 | ENV['NVIDIA_SMI_EXPORTER_SOURCE'] ||= 'xml' 9 | ENV['NVIDIA_SMI_EXPORTER_PORT'] ||= '9454' 10 | ENV['NVIDIA_SMI_EXPORTER_HOST'] ||= '0.0.0.0' 11 | ENV['NVIDIA_SMI_EXPORTER_NAME_PREFIX'] ||= 'nvidia_smi_' 12 | 13 | ENV['NVIDIA_SMI_EXPORTER_QUERY'] ||= %W( 14 | clocks.current.graphics 15 | clocks.current.memory 16 | clocks.current.sm 17 | clocks.current.video 18 | clocks.max.graphics 19 | clocks.max.memory 20 | clocks.max.sm 21 | fan.speed 22 | memory.total 23 | memory.used 24 | power.draw 25 | power.limit 26 | temperature.gpu 27 | utilization.gpu 28 | utilization.memory 29 | ).join(',') 30 | 31 | ENV['NVIDIA_SMI_EXPORTER_BINARY'] ||= begin 32 | stdout_str, status = Open3.capture2('which nvidia-smi') 33 | status.exitstatus.zero? ? stdout_str.strip : nil 34 | end 35 | end 36 | 37 | def run! 38 | Exporter.run! 39 | end 40 | end 41 | 42 | Application.new.run! 43 | -------------------------------------------------------------------------------- /app/exporter.rb: -------------------------------------------------------------------------------- 1 | require 'sinatra/base' 2 | require_relative 'n_vidia_smi' 3 | require_relative 'n_vidia_smi_xml' 4 | 5 | class Exporter < Sinatra::Base 6 | set :traps, false 7 | set :server, :puma 8 | set :port, proc { ENV['NVIDIA_SMI_EXPORTER_PORT'].to_i } 9 | set :bind, proc { ENV['NVIDIA_SMI_EXPORTER_HOST'] } 10 | set :show_exceptions, false 11 | 12 | not_found do 13 | halt 404 14 | end 15 | 16 | error do 17 | halt 500 18 | end 19 | 20 | get '/metrics' do 21 | content_type 'text/plain' 22 | 23 | processor = 24 | case ENV['NVIDIA_SMI_EXPORTER_SOURCE'] 25 | when 'csv' 26 | NVidiaSMI.new( 27 | binary_path: ENV['NVIDIA_SMI_EXPORTER_BINARY'], 28 | name_prefix: ENV['NVIDIA_SMI_EXPORTER_NAME_PREFIX'], 29 | query_list: ENV['NVIDIA_SMI_EXPORTER_QUERY'].to_s.split(',')) 30 | when 'xml' 31 | NVidiaSMI_XML.new( 32 | binary_path: ENV['NVIDIA_SMI_EXPORTER_BINARY'], 33 | name_prefix: ENV['NVIDIA_SMI_EXPORTER_NAME_PREFIX']) 34 | else 35 | raise("Unknown value `#{ENV['NVIDIA_SMI_EXPORTER_SOURCE']}' in NVIDIA_SMI_EXPORTER_SOURCE") 36 | end 37 | 38 | response = processor.query 39 | data = processor.parse(response) 40 | processor.format_prometheus(data) 41 | end 42 | 43 | get '/ping' do 44 | halt 200, 'OK' 45 | end 46 | end 47 | -------------------------------------------------------------------------------- /app/n_vidia_smi.rb: -------------------------------------------------------------------------------- 1 | require 'active_support/core_ext/object/blank' 2 | 3 | class NVidiaSMI 4 | attr_reader :binary_path, :name_prefix, :query_list 5 | 6 | def initialize(binary_path:, query_list:, name_prefix: nil) 7 | @binary_path = binary_path 8 | @name_prefix = name_prefix 9 | @query_list = query_list 10 | end 11 | 12 | def query(query_list = @query_list) 13 | unless @binary_path.present? 14 | raise("Don't know path to nvidia-smi binary") 15 | end 16 | 17 | # Move uuid to first position 18 | query_list = ['uuid'] + (query_list - ['uuid']) 19 | 20 | query_string = query_list.join(',') 21 | stdout_and_stderr_str, status = Open3.capture2e(@binary_path, '--format=csv', "--query-gpu=#{query_string}") 22 | 23 | unless status.exitstatus.zero? 24 | raise(stdout_and_stderr_str) 25 | end 26 | 27 | stdout_and_stderr_str 28 | end 29 | 30 | def parse(str) 31 | lines = str.strip.split("\n") 32 | arrs = lines.inject([]) { |arr, line| arr << line.split(',').map(&:strip) } 33 | 34 | result = {} 35 | 36 | headers, *line_arrs = arrs 37 | return result if line_arrs.blank? 38 | 39 | headers.each_with_index do |column, index| 40 | raise('First column is not uuid') if index.zero? && column != 'uuid' 41 | next if index.zero? 42 | 43 | case column 44 | when /\A([^\[]+)\[(%)\]\z/ 45 | multiplicator = 0.01 46 | unit = $2 47 | name_postfix = '' 48 | when /\A([^\[]+)\[(MiB)\]\z/ 49 | multiplicator = 1_048_576 50 | unit = $2 51 | name_postfix = '_bytes' 52 | when /\A([^\[]+)\[(W)\]\z/ 53 | multiplicator = 1 54 | unit = $2 55 | name_postfix = '_watts' 56 | when /\A([^\[]+)\[(MHz)\]\z/ 57 | multiplicator = 1_000_000 58 | unit = $2 59 | name_postfix = '_hz' 60 | when /\A([^\[\]]+)\z/ 61 | multiplicator = 1 62 | unit = '' 63 | name_postfix = '' 64 | else 65 | raise("Unknown what to do with string `#{column}'") 66 | end 67 | name = $1.strip.downcase.gsub('.', '_') 68 | if column.include?('temperature') && name_postfix.blank? 69 | name_postfix = '_celsius' 70 | end 71 | 72 | line_arrs.each do |line_arr| 73 | field_str = line_arr[index] 74 | field_value = 75 | begin 76 | Integer(field_str.sub(unit, '').strip) 77 | rescue ArgumentError 78 | Float(field_str.sub(unit, '').strip) 79 | end 80 | field_value *= multiplicator 81 | 82 | uuid = line_arr[0].sub(/\AGPU-/, '') 83 | result[uuid] ||= {} 84 | result[uuid]["#{name}#{name_postfix}"] = field_value 85 | end 86 | end 87 | result 88 | end 89 | 90 | def format_prometheus(data_hash) 91 | output_list = [] 92 | data_hash.each do |uuid, options| 93 | options.each do |name, value| 94 | output_list << "#{@name_prefix}#{name}{uuid=\"#{uuid}\"} #{value}" 95 | end 96 | end 97 | output_list.join("\n") + "\n" 98 | end 99 | end 100 | -------------------------------------------------------------------------------- /app/n_vidia_smi_xml.rb: -------------------------------------------------------------------------------- 1 | require 'active_support/core_ext/object/blank' 2 | require 'nokogiri' 3 | 4 | class NVidiaSMI_XML 5 | attr_reader :binary_path, :name_prefix 6 | 7 | def initialize(binary_path:, name_prefix: nil) 8 | @binary_path = binary_path 9 | @name_prefix = name_prefix 10 | end 11 | 12 | def query 13 | unless @binary_path.present? 14 | raise("Don't know path to nvidia-smi binary") 15 | end 16 | 17 | stdout_and_stderr_str, status = Open3.capture2e(@binary_path, '--query', '--xml-format') 18 | 19 | unless status.exitstatus.zero? 20 | raise(stdout_and_stderr_str) 21 | end 22 | 23 | stdout_and_stderr_str 24 | end 25 | 26 | def parse(str) 27 | doc = Nokogiri::XML(str) 28 | output = {} 29 | 30 | if (nodes = doc.xpath('/nvidia_smi_log/attached_gpus/text()')).size == 1 31 | path, data = 'attached_gpus', nodes[0].content.strip 32 | if (path, data = normalize_data(path, data)) 33 | output[path] = { {} => data } 34 | end 35 | end 36 | 37 | # traverse every node in every gpu branch 38 | doc.xpath('/nvidia_smi_log/gpu').each do |node| 39 | pci_bus_id = node.get_attribute('id') 40 | root_path = "#{node.path}/" 41 | uuid = node.xpath('./uuid')[0]&.content 42 | if uuid =~ /^GPU-/ 43 | uuid = uuid.slice(4..-1) 44 | end 45 | 46 | node.traverse do |sub_node| 47 | # skip not leaf 48 | if sub_node.element? && sub_node.children.size == 1 && (text_el = sub_node.children[0]).text? && 49 | # skip N/A мфдгу 50 | (data = text_el.content.strip) != 'N/A' && 51 | # skip empty value 52 | data != '' 53 | 54 | # cut common path /nvidia_smi_log/gpu[x] 55 | local_path = sub_node.path 56 | if local_path.slice(0, root_path.size) == root_path 57 | local_path = local_path.slice(root_path.size..-1) 58 | end 59 | 60 | # TODO don't skip paths within array like a 61 | # /nvidia_smi_log/gpu[2]/processes/process_info[1]/pid <= 450 62 | # /nvidia_smi_log/gpu[2]/processes/process_info[1]/type <= G 63 | # /nvidia_smi_log/gpu[2]/processes/process_info[1]/process_name <= /usr/lib/xorg/Xorg 64 | # /nvidia_smi_log/gpu[2]/processes/process_info[1]/used_memory <= 5 MiB 65 | if local_path !~ /\[\d+\]/ 66 | local_path, data = normalize_data(local_path, data) 67 | unless local_path.nil? 68 | output[local_path] ||= {} 69 | output[local_path][{ uuid: uuid }] = data 70 | end 71 | end 72 | end 73 | end 74 | end 75 | output 76 | end 77 | 78 | def format_prometheus(hash) 79 | output_list = [] 80 | hash.each do |path, values| 81 | values.each do |labels_hash, value| 82 | name = path.gsub('/', '_') 83 | labels = format_labels(labels_hash) 84 | output_list << "#{@name_prefix}#{name}#{labels} #{value}" 85 | end 86 | end 87 | output_list.join("\n") + "\n" 88 | end 89 | 90 | private 91 | 92 | def normalize_data(path, data) 93 | num = '\d+(?:\.\d+)?' 94 | 95 | case data 96 | 97 | when /^(#{num})\sB$/ 98 | return ["#{path}_bytes", ($1.to_f).to_i] 99 | when /^(#{num})\sKiB$/ 100 | return ["#{path}_bytes", ($1.to_f * 1024).to_i] 101 | when /^(#{num})\sMiB$/ 102 | return ["#{path}_bytes", ($1.to_f * 1024 * 1024).to_i] 103 | when /^(#{num})\sGiB$/ 104 | return ["#{path}_bytes", ($1.to_f * 1024 * 1024 * 1024).to_i] 105 | 106 | when /^(#{num})\sHz$/ 107 | return ["#{path}_hz", $1.to_f] 108 | when /^(#{num})\sKHz$/ 109 | return ["#{path}_hz", $1.to_f * 1000] 110 | when /^(#{num})\sMHz$/ 111 | return ["#{path}_hz", $1.to_f * 1000 * 1000] 112 | when /^(#{num})\sGHz$/ 113 | return ["#{path}_hz", $1.to_f * 1000 * 1000 * 1000] 114 | 115 | when /^(#{num})\s%$/ 116 | return ["#{path}_ratio", $1.to_f / 100.0] 117 | 118 | when /^(#{num})\sC$/ 119 | return ["#{path}_celsius", $1.to_f] 120 | 121 | when /^(#{num})\sW$/ 122 | return ["#{path}_watts", $1.to_f] 123 | when /^(#{num})\sKW$/ 124 | return ["#{path}_watts", $1.to_f * 1000.0] 125 | 126 | when /^(#{num})\sB\/s$/ 127 | return ["#{path}_bytes_per_second", ($1.to_f).to_i] 128 | when /^(#{num})\sKB\/s$/ 129 | return ["#{path}_bytes_per_second", ($1.to_f * 1024).to_i] 130 | when /^(#{num})\sMB\/s$/ 131 | return ["#{path}_bytes_per_second", ($1.to_f * 1024 * 1024).to_i] 132 | when /^(#{num})\sGB\/s$/ 133 | return ["#{path}_bytes_per_second", ($1.to_f * 1024 * 1024 * 1024).to_i] 134 | 135 | when /^P(\d{1,2})$/ 136 | return [path, $1.to_i] 137 | 138 | when 'Disabled', 'Not Active', 'No', 'Not Supported', 'Unsupported' 139 | return [path, 0] 140 | when 'Enabled', 'Active', 'Yes', 'Supported' 141 | return [path, 1] 142 | when '1x', '2x', '4x', '8x', '16x', '32x' 143 | return [path, data.to_i] 144 | 145 | # compute_mode = 0/Default, 1/Exclusive_Thread, 2/Prohibited, 3/Exclusive_Process 146 | 147 | else 148 | case path 149 | when /compute_mode$/ 150 | h = { 'Default' => 0, 'Exclusive_Thread' => 1, 'Prohibited' => 2, 'Exclusive_Process' => 3 } 151 | return nil unless h.key?(data) 152 | return [path, h[data]] 153 | 154 | else 155 | return [path, data] if data.to_f.to_s == data 156 | return [path, data] if data.to_i.to_s == data 157 | 158 | return nil 159 | end 160 | end 161 | end 162 | 163 | def format_labels(hash) 164 | list = hash.map do |k, v| 165 | "#{k}=\"#{v}\"" 166 | end 167 | list == [] ? '' : "{#{list.join(',')}}" 168 | end 169 | end 170 | -------------------------------------------------------------------------------- /spec/fixtures/nvidia-smi-1.csv: -------------------------------------------------------------------------------- 1 | uuid, memory.used [MiB], utilization.gpu [%], temperature.gpu, power.draw [W], clocks.current.sm [MHz] 2 | GPU-d86c351b-8f94-33ab-3b97-accb421fef6d, 754 MiB, 100 %, 71, 217.24 W, 1949 MHz 3 | GPU-683c6e09-3969-31a5-b7ca-cc88252b7fce, 641 MiB, 100 %, 71, 208.30 W, 2025 MHz 4 | -------------------------------------------------------------------------------- /spec/fixtures/nvidia-smi-2.csv: -------------------------------------------------------------------------------- 1 | uuid, fan.speed [%], temperature.gpu, power.draw [W], power.limit [W], utilization.gpu [%], utilization.memory [%], memory.used [MiB], memory.total [MiB], clocks.current.graphics [MHz], clocks.max.graphics [MHz], clocks.current.sm [MHz], clocks.current.memory [MHz], clocks.max.memory [MHz] 2 | GPU-20fe89bc-c8ef-5a9f-078e-efa3324d790b, 63 %, 73, 213.07 W, 216.00 W, 100 %, 87 %, 754 MiB, 8119 MiB, 1987 MHz, 1999 MHz, 1987 MHz, 5130 MHz, 5005 MHz 3 | GPU-68988cf6-8de9-6585-a263-d2e3ea96b75a, 81 %, 67, 187.04 W, 216.00 W, 100 %, 90 %, 586 MiB, 4043 MiB, 1453 MHz, 1606 MHz, 1453 MHz, 3004 MHz, 3505 MHz 4 | GPU-90e3dab0-b59d-8bf6-d909-d4fab8d2f29b, 55 %, 68, 206.44 W, 216.00 W, 100 %, 87 %, 641 MiB, 8119 MiB, 1949 MHz, 1936 MHz, 1949 MHz, 5130 MHz, 5005 MHz 5 | -------------------------------------------------------------------------------- /spec/fixtures/nvidia-smi-3.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Sat Feb 27 02:47:26 2021 5 | 460.27.04 6 | 11.2 7 | 2 8 | 9 | GeForce GTX 1080 10 | GeForce 11 | Enabled 12 | Disabled 13 | Enabled 14 | 15 | N/A 16 | N/A 17 | 18 | 19 | None 20 | 21 | Disabled 22 | 4000 23 | 24 | N/A 25 | N/A 26 | 27 | N/A 28 | GPU-683c6e09-3969-31a5-b7ca-cc88252b7fce 29 | 0 30 | 86.04.60.00.B4 31 | No 32 | 0x100 33 | N/A 34 | 35 | G001.0000.01.04 36 | 1.1 37 | N/A 38 | N/A 39 | 40 | 41 | N/A 42 | N/A 43 | 44 | 45 | None 46 | N/A 47 | 48 | 49 | N/A 50 | 51 | 52 | 01 53 | 00 54 | 0000 55 | 1B8010DE 56 | 00000000:01:00.0 57 | 37021458 58 | 59 | 60 | 3 61 | 3 62 | 63 | 64 | 16x 65 | 1x 66 | 67 | 68 | 69 | N/A 70 | N/A 71 | 72 | 65535 73 | 0 74 | 11000 KB/s 75 | 31000 KB/s 76 | 77 | 53 % 78 | P2 79 | 80 | Not Active 81 | Not Active 82 | 83 | Active 84 | Not Active 85 | Not Active 86 | Not Active 87 | Not Active 88 | Not Active 89 | Not Active 90 | 91 | 92 | 8116 MiB 93 | 2900 MiB 94 | 5216 MiB 95 | 96 | 97 | 256 MiB 98 | 5 MiB 99 | 251 MiB 100 | 101 | Default 102 | 103 | 100 % 104 | 100 % 105 | 0 % 106 | 0 % 107 | 108 | 109 | 0 110 | 0 111 | 0 112 | 113 | 114 | 0 115 | 0 116 | 0 117 | 118 | 119 | N/A 120 | N/A 121 | 122 | 123 | 124 | 125 | N/A 126 | N/A 127 | N/A 128 | N/A 129 | N/A 130 | N/A 131 | N/A 132 | N/A 133 | 134 | 135 | N/A 136 | N/A 137 | N/A 138 | N/A 139 | N/A 140 | N/A 141 | N/A 142 | N/A 143 | 144 | 145 | 146 | 147 | N/A 148 | N/A 149 | N/A 150 | N/A 151 | N/A 152 | N/A 153 | N/A 154 | N/A 155 | 156 | 157 | N/A 158 | N/A 159 | N/A 160 | N/A 161 | N/A 162 | N/A 163 | N/A 164 | N/A 165 | 166 | 167 | 168 | 169 | 170 | N/A 171 | N/A 172 | 173 | 174 | N/A 175 | N/A 176 | 177 | N/A 178 | N/A 179 | 180 | N/A 181 | 182 | 67 C 183 | 96 C 184 | 93 C 185 | N/A 186 | 83 C 187 | N/A 188 | N/A 189 | 190 | 191 | 60 C 192 | 92 C 193 | 194 | 195 | P2 196 | Supported 197 | 211.86 W 198 | 216.00 W 199 | 200.00 W 200 | 216.00 W 201 | 100.00 W 202 | 216.00 W 203 | 204 | 205 | 1784 MHz 206 | 1784 MHz 207 | 5514 MHz 208 | 1594 MHz 209 | 210 | 211 | N/A 212 | N/A 213 | 214 | 215 | N/A 216 | N/A 217 | 218 | 219 | 1999 MHz 220 | 1999 MHz 221 | 5005 MHz 222 | 1708 MHz 223 | 224 | 225 | N/A 226 | 227 | 228 | N/A 229 | N/A 230 | 231 | N/A 232 | 233 | 234 | N/A 235 | N/A 236 | 450 237 | G 238 | /usr/lib/xorg/Xorg 239 | 12 MiB 240 | 241 | 242 | N/A 243 | N/A 244 | 8991 245 | C 246 | /opt/nbminer/nbminer 247 | 2883 MiB 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | GeForce GTX 1080 256 | GeForce 257 | Disabled 258 | Disabled 259 | Enabled 260 | 261 | N/A 262 | N/A 263 | 264 | 265 | None 266 | 267 | Disabled 268 | 4000 269 | 270 | N/A 271 | N/A 272 | 273 | N/A 274 | GPU-90e3dab0-b59d-8bf6-d909-d4fab8d2f29b 275 | 1 276 | 86.04.60.00.BD 277 | No 278 | 0x300 279 | N/A 280 | 281 | G001.0000.01.04 282 | 1.1 283 | N/A 284 | N/A 285 | 286 | 287 | N/A 288 | N/A 289 | 290 | 291 | None 292 | N/A 293 | 294 | 295 | N/A 296 | 297 | 298 | 03 299 | 00 300 | 0000 301 | 1B8010DE 302 | 00000000:03:00.0 303 | 37171458 304 | 305 | 306 | 3 307 | 3 308 | 309 | 310 | 16x 311 | 1x 312 | 313 | 314 | 315 | N/A 316 | N/A 317 | 318 | 552 319 | 0 320 | 11000 KB/s 321 | 31000 KB/s 322 | 323 | 58 % 324 | P2 325 | 326 | Not Active 327 | Not Active 328 | 329 | Active 330 | Not Active 331 | Not Active 332 | Not Active 333 | Not Active 334 | Not Active 335 | Not Active 336 | 337 | 338 | 8119 MiB 339 | 2893 MiB 340 | 5226 MiB 341 | 342 | 343 | 256 MiB 344 | 5 MiB 345 | 251 MiB 346 | 347 | Default 348 | 349 | 100 % 350 | 100 % 351 | 0 % 352 | 0 % 353 | 354 | 355 | 0 356 | 0 357 | 0 358 | 359 | 360 | 0 361 | 0 362 | 0 363 | 364 | 365 | N/A 366 | N/A 367 | 368 | 369 | 370 | 371 | N/A 372 | N/A 373 | N/A 374 | N/A 375 | N/A 376 | N/A 377 | N/A 378 | N/A 379 | 380 | 381 | N/A 382 | N/A 383 | N/A 384 | N/A 385 | N/A 386 | N/A 387 | N/A 388 | N/A 389 | 390 | 391 | 392 | 393 | N/A 394 | N/A 395 | N/A 396 | N/A 397 | N/A 398 | N/A 399 | N/A 400 | N/A 401 | 402 | 403 | N/A 404 | N/A 405 | N/A 406 | N/A 407 | N/A 408 | N/A 409 | N/A 410 | N/A 411 | 412 | 413 | 414 | 415 | 416 | N/A 417 | N/A 418 | 419 | 420 | N/A 421 | N/A 422 | 423 | N/A 424 | N/A 425 | 426 | N/A 427 | 428 | 70 C 429 | 96 C 430 | 93 C 431 | N/A 432 | 83 C 433 | N/A 434 | N/A 435 | 436 | 437 | 60 C 438 | 92 C 439 | 440 | 441 | P2 442 | Supported 443 | 211.06 W 444 | 216.00 W 445 | 200.00 W 446 | 216.00 W 447 | 100.00 W 448 | 216.00 W 449 | 450 | 451 | 1657 MHz 452 | 1657 MHz 453 | 5514 MHz 454 | 1480 MHz 455 | 456 | 457 | N/A 458 | N/A 459 | 460 | 461 | N/A 462 | N/A 463 | 464 | 465 | 1936 MHz 466 | 1936 MHz 467 | 5005 MHz 468 | 1708 MHz 469 | 470 | 471 | N/A 472 | 473 | 474 | N/A 475 | N/A 476 | 477 | N/A 478 | 479 | 480 | N/A 481 | N/A 482 | 450 483 | G 484 | /usr/lib/xorg/Xorg 485 | 5 MiB 486 | 487 | 488 | N/A 489 | N/A 490 | 8991 491 | C 492 | /opt/nbminer/nbminer 493 | 2883 MiB 494 | 495 | 496 | 497 | 498 | 499 | 500 | 501 | -------------------------------------------------------------------------------- /spec/fixtures/nvidia-smi-4.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Fri Sep 27 11:00:44 2019 5 | 418.56 6 | 10.1 7 | 1 8 | 9 | Quadro P2000 10 | Quadro 11 | Disabled 12 | Disabled 13 | Disabled 14 | Disabled 15 | 4000 16 | 17 | N/A 18 | N/A 19 | 20 | 0324217004816 21 | GPU-1ffe36ef-ac55-60ad-f9cf-623871e7736d 22 | 0 23 | 86.06.3F.00.0D 24 | No 25 | 0x400 26 | 900-5G410-1700-000 27 | 28 | G410.0502.00.02 29 | 1.1 30 | N/A 31 | N/A 32 | 33 | 34 | N/A 35 | N/A 36 | 37 | 38 | None 39 | 40 | 41 | N/A 42 | 43 | 44 | 04 45 | 00 46 | 0000 47 | 1C3010DE 48 | 00000000:04:00.0 49 | 11B310DE 50 | 51 | 52 | 3 53 | 3 54 | 55 | 56 | 16x 57 | 16x 58 | 59 | 60 | 61 | N/A 62 | N/A 63 | 64 | 0 65 | 0 66 | 0 KB/s 67 | 0 KB/s 68 | 69 | 61 % 70 | P0 71 | 72 | Not Active 73 | Not Active 74 | 75 | Not Active 76 | Not Active 77 | Not Active 78 | Not Active 79 | Not Active 80 | Not Active 81 | Not Active 82 | 83 | 84 | 5059 MiB 85 | 319 MiB 86 | 4740 MiB 87 | 88 | 89 | 256 MiB 90 | 2 MiB 91 | 254 MiB 92 | 93 | Default 94 | 95 | 0 % 96 | 0 % 97 | 0 % 98 | 0 % 99 | 100 | 101 | 0 102 | 0 103 | 0 104 | 105 | 106 | 0 107 | 0 108 | 0 109 | 110 | 111 | N/A 112 | N/A 113 | 114 | 115 | 116 | 117 | N/A 118 | N/A 119 | N/A 120 | N/A 121 | N/A 122 | N/A 123 | N/A 124 | N/A 125 | 126 | 127 | N/A 128 | N/A 129 | N/A 130 | N/A 131 | N/A 132 | N/A 133 | N/A 134 | N/A 135 | 136 | 137 | 138 | 139 | N/A 140 | N/A 141 | N/A 142 | N/A 143 | N/A 144 | N/A 145 | N/A 146 | N/A 147 | 148 | 149 | N/A 150 | N/A 151 | N/A 152 | N/A 153 | N/A 154 | N/A 155 | N/A 156 | N/A 157 | 158 | 159 | 160 | 161 | 162 | N/A 163 | N/A 164 | 165 | 166 | N/A 167 | N/A 168 | 169 | N/A 170 | 171 | 172 | 62 C 173 | 104 C 174 | 101 C 175 | N/A 176 | N/A 177 | N/A 178 | 179 | 180 | P0 181 | Supported 182 | 20.32 W 183 | 75.00 W 184 | 75.00 W 185 | 75.00 W 186 | 75.00 W 187 | 75.00 W 188 | 189 | 190 | 1215 MHz 191 | 1215 MHz 192 | 3499 MHz 193 | 1101 MHz 194 | 195 | 196 | 1075 MHz 197 | 3504 MHz 198 | 199 | 200 | 1075 MHz 201 | 3504 MHz 202 | 203 | 204 | 1721 MHz 205 | 1721 MHz 206 | 3504 MHz 207 | 1556 MHz 208 | 209 | 210 | 1721 MHz 211 | 212 | 213 | N/A 214 | N/A 215 | 216 | 217 | 218 | 3504 MHz 219 | 1721 MHz 220 | 1708 MHz 221 | 1695 MHz 222 | 1683 MHz 223 | 1670 MHz 224 | 1657 MHz 225 | 1645 MHz 226 | 1632 MHz 227 | 1620 MHz 228 | 1607 MHz 229 | 1594 MHz 230 | 1582 MHz 231 | 1569 MHz 232 | 1556 MHz 233 | 1544 MHz 234 | 1531 MHz 235 | 1518 MHz 236 | 1506 MHz 237 | 1493 MHz 238 | 1480 MHz 239 | 1468 MHz 240 | 1455 MHz 241 | 1442 MHz 242 | 1430 MHz 243 | 1417 MHz 244 | 1404 MHz 245 | 1392 MHz 246 | 1379 MHz 247 | 1366 MHz 248 | 1354 MHz 249 | 1341 MHz 250 | 1328 MHz 251 | 1316 MHz 252 | 1303 MHz 253 | 1290 MHz 254 | 1278 MHz 255 | 1265 MHz 256 | 1252 MHz 257 | 1240 MHz 258 | 1227 MHz 259 | 1215 MHz 260 | 1202 MHz 261 | 1189 MHz 262 | 1177 MHz 263 | 1164 MHz 264 | 1151 MHz 265 | 1139 MHz 266 | 1126 MHz 267 | 1113 MHz 268 | 1101 MHz 269 | 1088 MHz 270 | 1075 MHz 271 | 1063 MHz 272 | 1050 MHz 273 | 1037 MHz 274 | 1025 MHz 275 | 1012 MHz 276 | 999 MHz 277 | 987 MHz 278 | 974 MHz 279 | 961 MHz 280 | 949 MHz 281 | 936 MHz 282 | 923 MHz 283 | 911 MHz 284 | 898 MHz 285 | 885 MHz 286 | 873 MHz 287 | 860 MHz 288 | 847 MHz 289 | 835 MHz 290 | 822 MHz 291 | 810 MHz 292 | 797 MHz 293 | 784 MHz 294 | 772 MHz 295 | 759 MHz 296 | 746 MHz 297 | 734 MHz 298 | 721 MHz 299 | 708 MHz 300 | 696 MHz 301 | 683 MHz 302 | 670 MHz 303 | 658 MHz 304 | 645 MHz 305 | 632 MHz 306 | 620 MHz 307 | 607 MHz 308 | 594 MHz 309 | 582 MHz 310 | 569 MHz 311 | 556 MHz 312 | 544 MHz 313 | 531 MHz 314 | 518 MHz 315 | 506 MHz 316 | 493 MHz 317 | 480 MHz 318 | 468 MHz 319 | 455 MHz 320 | 442 MHz 321 | 430 MHz 322 | 417 MHz 323 | 405 MHz 324 | 392 MHz 325 | 379 MHz 326 | 367 MHz 327 | 354 MHz 328 | 341 MHz 329 | 329 MHz 330 | 316 MHz 331 | 303 MHz 332 | 291 MHz 333 | 278 MHz 334 | 265 MHz 335 | 253 MHz 336 | 240 MHz 337 | 227 MHz 338 | 215 MHz 339 | 202 MHz 340 | 189 MHz 341 | 177 MHz 342 | 164 MHz 343 | 151 MHz 344 | 139 MHz 345 | 346 | 347 | 810 MHz 348 | 1721 MHz 349 | 1708 MHz 350 | 1695 MHz 351 | 1683 MHz 352 | 1670 MHz 353 | 1657 MHz 354 | 1645 MHz 355 | 1632 MHz 356 | 1620 MHz 357 | 1607 MHz 358 | 1594 MHz 359 | 1582 MHz 360 | 1569 MHz 361 | 1556 MHz 362 | 1544 MHz 363 | 1531 MHz 364 | 1518 MHz 365 | 1506 MHz 366 | 1493 MHz 367 | 1480 MHz 368 | 1468 MHz 369 | 1455 MHz 370 | 1442 MHz 371 | 1430 MHz 372 | 1417 MHz 373 | 1404 MHz 374 | 1392 MHz 375 | 1379 MHz 376 | 1366 MHz 377 | 1354 MHz 378 | 1341 MHz 379 | 1328 MHz 380 | 1316 MHz 381 | 1303 MHz 382 | 1290 MHz 383 | 1278 MHz 384 | 1265 MHz 385 | 1252 MHz 386 | 1240 MHz 387 | 1227 MHz 388 | 1215 MHz 389 | 1202 MHz 390 | 1189 MHz 391 | 1177 MHz 392 | 1164 MHz 393 | 1151 MHz 394 | 1139 MHz 395 | 1126 MHz 396 | 1113 MHz 397 | 1101 MHz 398 | 1088 MHz 399 | 1075 MHz 400 | 1063 MHz 401 | 1050 MHz 402 | 1037 MHz 403 | 1025 MHz 404 | 1012 MHz 405 | 999 MHz 406 | 987 MHz 407 | 974 MHz 408 | 961 MHz 409 | 949 MHz 410 | 936 MHz 411 | 923 MHz 412 | 911 MHz 413 | 898 MHz 414 | 885 MHz 415 | 873 MHz 416 | 860 MHz 417 | 847 MHz 418 | 835 MHz 419 | 822 MHz 420 | 810 MHz 421 | 797 MHz 422 | 784 MHz 423 | 772 MHz 424 | 759 MHz 425 | 746 MHz 426 | 734 MHz 427 | 721 MHz 428 | 708 MHz 429 | 696 MHz 430 | 683 MHz 431 | 670 MHz 432 | 658 MHz 433 | 645 MHz 434 | 632 MHz 435 | 620 MHz 436 | 607 MHz 437 | 594 MHz 438 | 582 MHz 439 | 569 MHz 440 | 556 MHz 441 | 544 MHz 442 | 531 MHz 443 | 518 MHz 444 | 506 MHz 445 | 493 MHz 446 | 480 MHz 447 | 468 MHz 448 | 455 MHz 449 | 442 MHz 450 | 430 MHz 451 | 417 MHz 452 | 405 MHz 453 | 392 MHz 454 | 379 MHz 455 | 367 MHz 456 | 354 MHz 457 | 341 MHz 458 | 329 MHz 459 | 316 MHz 460 | 303 MHz 461 | 291 MHz 462 | 278 MHz 463 | 265 MHz 464 | 253 MHz 465 | 240 MHz 466 | 227 MHz 467 | 215 MHz 468 | 202 MHz 469 | 189 MHz 470 | 177 MHz 471 | 164 MHz 472 | 151 MHz 473 | 139 MHz 474 | 475 | 476 | 405 MHz 477 | 607 MHz 478 | 594 MHz 479 | 582 MHz 480 | 569 MHz 481 | 556 MHz 482 | 544 MHz 483 | 531 MHz 484 | 518 MHz 485 | 506 MHz 486 | 493 MHz 487 | 480 MHz 488 | 468 MHz 489 | 455 MHz 490 | 442 MHz 491 | 430 MHz 492 | 417 MHz 493 | 405 MHz 494 | 392 MHz 495 | 379 MHz 496 | 367 MHz 497 | 354 MHz 498 | 341 MHz 499 | 329 MHz 500 | 316 MHz 501 | 303 MHz 502 | 291 MHz 503 | 278 MHz 504 | 265 MHz 505 | 253 MHz 506 | 240 MHz 507 | 227 MHz 508 | 215 MHz 509 | 202 MHz 510 | 189 MHz 511 | 177 MHz 512 | 164 MHz 513 | 151 MHz 514 | 139 MHz 515 | 516 | 517 | 518 | 519 | 7134 520 | C 521 | /usr/lib/plexmediaserver/Plex Transcoder 522 | 309 MiB 523 | 524 | 525 | 526 | 527 | 528 | 529 | -------------------------------------------------------------------------------- /spec/fixtures/parsed-1.json: -------------------------------------------------------------------------------- 1 | { 2 | "d86c351b-8f94-33ab-3b97-accb421fef6d": { 3 | "memory_used_bytes": 790626304, 4 | "utilization_gpu": 1.0, 5 | "temperature_gpu_celsius": 71, 6 | "power_draw_watts": 217.24, 7 | "clocks_current_sm_hz": 1949000000 8 | }, 9 | "683c6e09-3969-31a5-b7ca-cc88252b7fce": { 10 | "memory_used_bytes": 672137216, 11 | "utilization_gpu": 1.0, 12 | "temperature_gpu_celsius": 71, 13 | "power_draw_watts": 208.3, 14 | "clocks_current_sm_hz": 2025000000 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /spec/fixtures/parsed-2.json: -------------------------------------------------------------------------------- 1 | { 2 | "20fe89bc-c8ef-5a9f-078e-efa3324d790b": { 3 | "fan_speed": 0.63, 4 | "temperature_gpu_celsius": 73, 5 | "power_draw_watts": 213.07, 6 | "power_limit_watts": 216.0, 7 | "utilization_gpu": 1.0, 8 | "utilization_memory": 0.87, 9 | "memory_used_bytes": 790626304, 10 | "memory_total_bytes": 8513388544, 11 | "clocks_current_graphics_hz": 1987000000, 12 | "clocks_max_graphics_hz": 1999000000, 13 | "clocks_current_sm_hz": 1987000000, 14 | "clocks_current_memory_hz": 5130000000, 15 | "clocks_max_memory_hz": 5005000000 16 | }, 17 | "68988cf6-8de9-6585-a263-d2e3ea96b75a": { 18 | "fan_speed": 0.81, 19 | "temperature_gpu_celsius": 67, 20 | "power_draw_watts": 187.04, 21 | "power_limit_watts": 216.0, 22 | "utilization_gpu": 1.0, 23 | "utilization_memory": 0.9, 24 | "memory_used_bytes": 614465536, 25 | "memory_total_bytes": 4239392768, 26 | "clocks_current_graphics_hz": 1453000000, 27 | "clocks_max_graphics_hz": 1606000000, 28 | "clocks_current_sm_hz": 1453000000, 29 | "clocks_current_memory_hz": 3004000000, 30 | "clocks_max_memory_hz": 3505000000 31 | }, 32 | "90e3dab0-b59d-8bf6-d909-d4fab8d2f29b": { 33 | "fan_speed": 0.55, 34 | "temperature_gpu_celsius": 68, 35 | "power_draw_watts": 206.44, 36 | "power_limit_watts": 216.0, 37 | "utilization_gpu": 1.0, 38 | "utilization_memory": 0.87, 39 | "memory_used_bytes": 672137216, 40 | "memory_total_bytes": 8513388544, 41 | "clocks_current_graphics_hz": 1949000000, 42 | "clocks_max_graphics_hz": 1936000000, 43 | "clocks_current_sm_hz": 1949000000, 44 | "clocks_current_memory_hz": 5130000000, 45 | "clocks_max_memory_hz": 5005000000 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /spec/helpers/fixture.rb: -------------------------------------------------------------------------------- 1 | module Fixture 2 | def fixture_load(name) 3 | file_name = File.expand_path("../../fixtures/#{name}", __FILE__) 4 | File.read(file_name) 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /spec/n_vidia_smi_spec.rb: -------------------------------------------------------------------------------- 1 | RSpec.describe NVidiaSMI do 2 | subject { described_class.new(binary_path: nil, query_list: nil, name_prefix: nil) } 3 | 4 | describe '#parser' do 5 | it { expect(subject.parse(fixture_load('nvidia-smi-1.csv'))).to eq(JSON.load(fixture_load('parsed-1.json'))) } 6 | it { expect(subject.parse(fixture_load('nvidia-smi-2.csv'))).to eq(JSON.load(fixture_load('parsed-2.json'))) } 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /spec/n_vidia_smi_xml_spec.rb: -------------------------------------------------------------------------------- 1 | RSpec.describe NVidiaSMI_XML do 2 | subject { described_class.new(binary_path: nil, name_prefix: 'rspec_') } 3 | 4 | context 'nvidia-smi-3.xml' do 5 | let(:result) do 6 | <<~EOS 7 | rspec_attached_gpus 2 8 | rspec_display_mode{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 1 9 | rspec_display_mode{uuid="90e3dab0-b59d-8bf6-d909-d4fab8d2f29b"} 0 10 | rspec_display_active{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 0 11 | rspec_display_active{uuid="90e3dab0-b59d-8bf6-d909-d4fab8d2f29b"} 0 12 | rspec_persistence_mode{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 1 13 | rspec_persistence_mode{uuid="90e3dab0-b59d-8bf6-d909-d4fab8d2f29b"} 1 14 | rspec_accounting_mode{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 0 15 | rspec_accounting_mode{uuid="90e3dab0-b59d-8bf6-d909-d4fab8d2f29b"} 0 16 | rspec_accounting_mode_buffer_size{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 4000 17 | rspec_accounting_mode_buffer_size{uuid="90e3dab0-b59d-8bf6-d909-d4fab8d2f29b"} 4000 18 | rspec_minor_number{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 0 19 | rspec_minor_number{uuid="90e3dab0-b59d-8bf6-d909-d4fab8d2f29b"} 1 20 | rspec_multigpu_board{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 0 21 | rspec_multigpu_board{uuid="90e3dab0-b59d-8bf6-d909-d4fab8d2f29b"} 0 22 | rspec_inforom_version_oem_object{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 1.1 23 | rspec_inforom_version_oem_object{uuid="90e3dab0-b59d-8bf6-d909-d4fab8d2f29b"} 1.1 24 | rspec_pci_pci_sub_system_id{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 37021458 25 | rspec_pci_pci_sub_system_id{uuid="90e3dab0-b59d-8bf6-d909-d4fab8d2f29b"} 37171458 26 | rspec_pci_pci_gpu_link_info_pcie_gen_max_link_gen{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 3 27 | rspec_pci_pci_gpu_link_info_pcie_gen_max_link_gen{uuid="90e3dab0-b59d-8bf6-d909-d4fab8d2f29b"} 3 28 | rspec_pci_pci_gpu_link_info_pcie_gen_current_link_gen{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 3 29 | rspec_pci_pci_gpu_link_info_pcie_gen_current_link_gen{uuid="90e3dab0-b59d-8bf6-d909-d4fab8d2f29b"} 3 30 | rspec_pci_pci_gpu_link_info_link_widths_max_link_width{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 16 31 | rspec_pci_pci_gpu_link_info_link_widths_max_link_width{uuid="90e3dab0-b59d-8bf6-d909-d4fab8d2f29b"} 16 32 | rspec_pci_pci_gpu_link_info_link_widths_current_link_width{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 1 33 | rspec_pci_pci_gpu_link_info_link_widths_current_link_width{uuid="90e3dab0-b59d-8bf6-d909-d4fab8d2f29b"} 1 34 | rspec_pci_replay_counter{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 65535 35 | rspec_pci_replay_counter{uuid="90e3dab0-b59d-8bf6-d909-d4fab8d2f29b"} 552 36 | rspec_pci_replay_rollover_counter{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 0 37 | rspec_pci_replay_rollover_counter{uuid="90e3dab0-b59d-8bf6-d909-d4fab8d2f29b"} 0 38 | rspec_pci_tx_util_bytes_per_second{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 11264000 39 | rspec_pci_tx_util_bytes_per_second{uuid="90e3dab0-b59d-8bf6-d909-d4fab8d2f29b"} 11264000 40 | rspec_pci_rx_util_bytes_per_second{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 31744000 41 | rspec_pci_rx_util_bytes_per_second{uuid="90e3dab0-b59d-8bf6-d909-d4fab8d2f29b"} 31744000 42 | rspec_fan_speed_ratio{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 0.53 43 | rspec_fan_speed_ratio{uuid="90e3dab0-b59d-8bf6-d909-d4fab8d2f29b"} 0.58 44 | rspec_performance_state{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 2 45 | rspec_performance_state{uuid="90e3dab0-b59d-8bf6-d909-d4fab8d2f29b"} 2 46 | rspec_clocks_throttle_reasons_clocks_throttle_reason_gpu_idle{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 0 47 | rspec_clocks_throttle_reasons_clocks_throttle_reason_gpu_idle{uuid="90e3dab0-b59d-8bf6-d909-d4fab8d2f29b"} 0 48 | rspec_clocks_throttle_reasons_clocks_throttle_reason_applications_clocks_setting{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 0 49 | rspec_clocks_throttle_reasons_clocks_throttle_reason_applications_clocks_setting{uuid="90e3dab0-b59d-8bf6-d909-d4fab8d2f29b"} 0 50 | rspec_clocks_throttle_reasons_clocks_throttle_reason_sw_power_cap{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 1 51 | rspec_clocks_throttle_reasons_clocks_throttle_reason_sw_power_cap{uuid="90e3dab0-b59d-8bf6-d909-d4fab8d2f29b"} 1 52 | rspec_clocks_throttle_reasons_clocks_throttle_reason_hw_slowdown{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 0 53 | rspec_clocks_throttle_reasons_clocks_throttle_reason_hw_slowdown{uuid="90e3dab0-b59d-8bf6-d909-d4fab8d2f29b"} 0 54 | rspec_clocks_throttle_reasons_clocks_throttle_reason_hw_thermal_slowdown{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 0 55 | rspec_clocks_throttle_reasons_clocks_throttle_reason_hw_thermal_slowdown{uuid="90e3dab0-b59d-8bf6-d909-d4fab8d2f29b"} 0 56 | rspec_clocks_throttle_reasons_clocks_throttle_reason_hw_power_brake_slowdown{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 0 57 | rspec_clocks_throttle_reasons_clocks_throttle_reason_hw_power_brake_slowdown{uuid="90e3dab0-b59d-8bf6-d909-d4fab8d2f29b"} 0 58 | rspec_clocks_throttle_reasons_clocks_throttle_reason_sync_boost{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 0 59 | rspec_clocks_throttle_reasons_clocks_throttle_reason_sync_boost{uuid="90e3dab0-b59d-8bf6-d909-d4fab8d2f29b"} 0 60 | rspec_clocks_throttle_reasons_clocks_throttle_reason_sw_thermal_slowdown{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 0 61 | rspec_clocks_throttle_reasons_clocks_throttle_reason_sw_thermal_slowdown{uuid="90e3dab0-b59d-8bf6-d909-d4fab8d2f29b"} 0 62 | rspec_clocks_throttle_reasons_clocks_throttle_reason_display_clocks_setting{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 0 63 | rspec_clocks_throttle_reasons_clocks_throttle_reason_display_clocks_setting{uuid="90e3dab0-b59d-8bf6-d909-d4fab8d2f29b"} 0 64 | rspec_fb_memory_usage_total_bytes{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 8510242816 65 | rspec_fb_memory_usage_total_bytes{uuid="90e3dab0-b59d-8bf6-d909-d4fab8d2f29b"} 8513388544 66 | rspec_fb_memory_usage_used_bytes{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 3040870400 67 | rspec_fb_memory_usage_used_bytes{uuid="90e3dab0-b59d-8bf6-d909-d4fab8d2f29b"} 3033530368 68 | rspec_fb_memory_usage_free_bytes{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 5469372416 69 | rspec_fb_memory_usage_free_bytes{uuid="90e3dab0-b59d-8bf6-d909-d4fab8d2f29b"} 5479858176 70 | rspec_bar1_memory_usage_total_bytes{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 268435456 71 | rspec_bar1_memory_usage_total_bytes{uuid="90e3dab0-b59d-8bf6-d909-d4fab8d2f29b"} 268435456 72 | rspec_bar1_memory_usage_used_bytes{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 5242880 73 | rspec_bar1_memory_usage_used_bytes{uuid="90e3dab0-b59d-8bf6-d909-d4fab8d2f29b"} 5242880 74 | rspec_bar1_memory_usage_free_bytes{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 263192576 75 | rspec_bar1_memory_usage_free_bytes{uuid="90e3dab0-b59d-8bf6-d909-d4fab8d2f29b"} 263192576 76 | rspec_compute_mode{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 0 77 | rspec_compute_mode{uuid="90e3dab0-b59d-8bf6-d909-d4fab8d2f29b"} 0 78 | rspec_utilization_gpu_util_ratio{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 1.0 79 | rspec_utilization_gpu_util_ratio{uuid="90e3dab0-b59d-8bf6-d909-d4fab8d2f29b"} 1.0 80 | rspec_utilization_memory_util_ratio{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 1.0 81 | rspec_utilization_memory_util_ratio{uuid="90e3dab0-b59d-8bf6-d909-d4fab8d2f29b"} 1.0 82 | rspec_utilization_encoder_util_ratio{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 0.0 83 | rspec_utilization_encoder_util_ratio{uuid="90e3dab0-b59d-8bf6-d909-d4fab8d2f29b"} 0.0 84 | rspec_utilization_decoder_util_ratio{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 0.0 85 | rspec_utilization_decoder_util_ratio{uuid="90e3dab0-b59d-8bf6-d909-d4fab8d2f29b"} 0.0 86 | rspec_encoder_stats_session_count{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 0 87 | rspec_encoder_stats_session_count{uuid="90e3dab0-b59d-8bf6-d909-d4fab8d2f29b"} 0 88 | rspec_encoder_stats_average_fps{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 0 89 | rspec_encoder_stats_average_fps{uuid="90e3dab0-b59d-8bf6-d909-d4fab8d2f29b"} 0 90 | rspec_encoder_stats_average_latency{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 0 91 | rspec_encoder_stats_average_latency{uuid="90e3dab0-b59d-8bf6-d909-d4fab8d2f29b"} 0 92 | rspec_fbc_stats_session_count{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 0 93 | rspec_fbc_stats_session_count{uuid="90e3dab0-b59d-8bf6-d909-d4fab8d2f29b"} 0 94 | rspec_fbc_stats_average_fps{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 0 95 | rspec_fbc_stats_average_fps{uuid="90e3dab0-b59d-8bf6-d909-d4fab8d2f29b"} 0 96 | rspec_fbc_stats_average_latency{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 0 97 | rspec_fbc_stats_average_latency{uuid="90e3dab0-b59d-8bf6-d909-d4fab8d2f29b"} 0 98 | rspec_temperature_gpu_temp_celsius{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 67.0 99 | rspec_temperature_gpu_temp_celsius{uuid="90e3dab0-b59d-8bf6-d909-d4fab8d2f29b"} 70.0 100 | rspec_temperature_gpu_temp_max_threshold_celsius{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 96.0 101 | rspec_temperature_gpu_temp_max_threshold_celsius{uuid="90e3dab0-b59d-8bf6-d909-d4fab8d2f29b"} 96.0 102 | rspec_temperature_gpu_temp_slow_threshold_celsius{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 93.0 103 | rspec_temperature_gpu_temp_slow_threshold_celsius{uuid="90e3dab0-b59d-8bf6-d909-d4fab8d2f29b"} 93.0 104 | rspec_temperature_gpu_target_temperature_celsius{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 83.0 105 | rspec_temperature_gpu_target_temperature_celsius{uuid="90e3dab0-b59d-8bf6-d909-d4fab8d2f29b"} 83.0 106 | rspec_supported_gpu_target_temp_gpu_target_temp_min_celsius{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 60.0 107 | rspec_supported_gpu_target_temp_gpu_target_temp_min_celsius{uuid="90e3dab0-b59d-8bf6-d909-d4fab8d2f29b"} 60.0 108 | rspec_supported_gpu_target_temp_gpu_target_temp_max_celsius{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 92.0 109 | rspec_supported_gpu_target_temp_gpu_target_temp_max_celsius{uuid="90e3dab0-b59d-8bf6-d909-d4fab8d2f29b"} 92.0 110 | rspec_power_readings_power_state{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 2 111 | rspec_power_readings_power_state{uuid="90e3dab0-b59d-8bf6-d909-d4fab8d2f29b"} 2 112 | rspec_power_readings_power_management{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 1 113 | rspec_power_readings_power_management{uuid="90e3dab0-b59d-8bf6-d909-d4fab8d2f29b"} 1 114 | rspec_power_readings_power_draw_watts{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 211.86 115 | rspec_power_readings_power_draw_watts{uuid="90e3dab0-b59d-8bf6-d909-d4fab8d2f29b"} 211.06 116 | rspec_power_readings_power_limit_watts{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 216.0 117 | rspec_power_readings_power_limit_watts{uuid="90e3dab0-b59d-8bf6-d909-d4fab8d2f29b"} 216.0 118 | rspec_power_readings_default_power_limit_watts{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 200.0 119 | rspec_power_readings_default_power_limit_watts{uuid="90e3dab0-b59d-8bf6-d909-d4fab8d2f29b"} 200.0 120 | rspec_power_readings_enforced_power_limit_watts{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 216.0 121 | rspec_power_readings_enforced_power_limit_watts{uuid="90e3dab0-b59d-8bf6-d909-d4fab8d2f29b"} 216.0 122 | rspec_power_readings_min_power_limit_watts{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 100.0 123 | rspec_power_readings_min_power_limit_watts{uuid="90e3dab0-b59d-8bf6-d909-d4fab8d2f29b"} 100.0 124 | rspec_power_readings_max_power_limit_watts{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 216.0 125 | rspec_power_readings_max_power_limit_watts{uuid="90e3dab0-b59d-8bf6-d909-d4fab8d2f29b"} 216.0 126 | rspec_clocks_graphics_clock_hz{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 1784000000.0 127 | rspec_clocks_graphics_clock_hz{uuid="90e3dab0-b59d-8bf6-d909-d4fab8d2f29b"} 1657000000.0 128 | rspec_clocks_sm_clock_hz{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 1784000000.0 129 | rspec_clocks_sm_clock_hz{uuid="90e3dab0-b59d-8bf6-d909-d4fab8d2f29b"} 1657000000.0 130 | rspec_clocks_mem_clock_hz{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 5514000000.0 131 | rspec_clocks_mem_clock_hz{uuid="90e3dab0-b59d-8bf6-d909-d4fab8d2f29b"} 5514000000.0 132 | rspec_clocks_video_clock_hz{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 1594000000.0 133 | rspec_clocks_video_clock_hz{uuid="90e3dab0-b59d-8bf6-d909-d4fab8d2f29b"} 1480000000.0 134 | rspec_max_clocks_graphics_clock_hz{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 1999000000.0 135 | rspec_max_clocks_graphics_clock_hz{uuid="90e3dab0-b59d-8bf6-d909-d4fab8d2f29b"} 1936000000.0 136 | rspec_max_clocks_sm_clock_hz{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 1999000000.0 137 | rspec_max_clocks_sm_clock_hz{uuid="90e3dab0-b59d-8bf6-d909-d4fab8d2f29b"} 1936000000.0 138 | rspec_max_clocks_mem_clock_hz{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 5005000000.0 139 | rspec_max_clocks_mem_clock_hz{uuid="90e3dab0-b59d-8bf6-d909-d4fab8d2f29b"} 5005000000.0 140 | rspec_max_clocks_video_clock_hz{uuid="683c6e09-3969-31a5-b7ca-cc88252b7fce"} 1708000000.0 141 | rspec_max_clocks_video_clock_hz{uuid="90e3dab0-b59d-8bf6-d909-d4fab8d2f29b"} 1708000000.0 142 | EOS 143 | end 144 | 145 | it do 146 | hash = subject.parse(fixture_load('nvidia-smi-3.xml')) 147 | expect(subject.format_prometheus(hash)).to eq(result) 148 | end 149 | end 150 | 151 | context 'nvidia-smi-4.xml' do 152 | let(:result) do 153 | <<~EOS 154 | rspec_attached_gpus 1 155 | rspec_display_mode{uuid="1ffe36ef-ac55-60ad-f9cf-623871e7736d"} 0 156 | rspec_display_active{uuid="1ffe36ef-ac55-60ad-f9cf-623871e7736d"} 0 157 | rspec_persistence_mode{uuid="1ffe36ef-ac55-60ad-f9cf-623871e7736d"} 0 158 | rspec_accounting_mode{uuid="1ffe36ef-ac55-60ad-f9cf-623871e7736d"} 0 159 | rspec_accounting_mode_buffer_size{uuid="1ffe36ef-ac55-60ad-f9cf-623871e7736d"} 4000 160 | rspec_minor_number{uuid="1ffe36ef-ac55-60ad-f9cf-623871e7736d"} 0 161 | rspec_multigpu_board{uuid="1ffe36ef-ac55-60ad-f9cf-623871e7736d"} 0 162 | rspec_inforom_version_oem_object{uuid="1ffe36ef-ac55-60ad-f9cf-623871e7736d"} 1.1 163 | rspec_pci_pci_gpu_link_info_pcie_gen_max_link_gen{uuid="1ffe36ef-ac55-60ad-f9cf-623871e7736d"} 3 164 | rspec_pci_pci_gpu_link_info_pcie_gen_current_link_gen{uuid="1ffe36ef-ac55-60ad-f9cf-623871e7736d"} 3 165 | rspec_pci_pci_gpu_link_info_link_widths_max_link_width{uuid="1ffe36ef-ac55-60ad-f9cf-623871e7736d"} 16 166 | rspec_pci_pci_gpu_link_info_link_widths_current_link_width{uuid="1ffe36ef-ac55-60ad-f9cf-623871e7736d"} 16 167 | rspec_pci_replay_counter{uuid="1ffe36ef-ac55-60ad-f9cf-623871e7736d"} 0 168 | rspec_pci_replay_rollover_counter{uuid="1ffe36ef-ac55-60ad-f9cf-623871e7736d"} 0 169 | rspec_pci_tx_util_bytes_per_second{uuid="1ffe36ef-ac55-60ad-f9cf-623871e7736d"} 0 170 | rspec_pci_rx_util_bytes_per_second{uuid="1ffe36ef-ac55-60ad-f9cf-623871e7736d"} 0 171 | rspec_fan_speed_ratio{uuid="1ffe36ef-ac55-60ad-f9cf-623871e7736d"} 0.61 172 | rspec_performance_state{uuid="1ffe36ef-ac55-60ad-f9cf-623871e7736d"} 0 173 | rspec_clocks_throttle_reasons_clocks_throttle_reason_gpu_idle{uuid="1ffe36ef-ac55-60ad-f9cf-623871e7736d"} 0 174 | rspec_clocks_throttle_reasons_clocks_throttle_reason_applications_clocks_setting{uuid="1ffe36ef-ac55-60ad-f9cf-623871e7736d"} 0 175 | rspec_clocks_throttle_reasons_clocks_throttle_reason_sw_power_cap{uuid="1ffe36ef-ac55-60ad-f9cf-623871e7736d"} 0 176 | rspec_clocks_throttle_reasons_clocks_throttle_reason_hw_slowdown{uuid="1ffe36ef-ac55-60ad-f9cf-623871e7736d"} 0 177 | rspec_clocks_throttle_reasons_clocks_throttle_reason_hw_thermal_slowdown{uuid="1ffe36ef-ac55-60ad-f9cf-623871e7736d"} 0 178 | rspec_clocks_throttle_reasons_clocks_throttle_reason_hw_power_brake_slowdown{uuid="1ffe36ef-ac55-60ad-f9cf-623871e7736d"} 0 179 | rspec_clocks_throttle_reasons_clocks_throttle_reason_sync_boost{uuid="1ffe36ef-ac55-60ad-f9cf-623871e7736d"} 0 180 | rspec_clocks_throttle_reasons_clocks_throttle_reason_sw_thermal_slowdown{uuid="1ffe36ef-ac55-60ad-f9cf-623871e7736d"} 0 181 | rspec_clocks_throttle_reasons_clocks_throttle_reason_display_clocks_setting{uuid="1ffe36ef-ac55-60ad-f9cf-623871e7736d"} 0 182 | rspec_fb_memory_usage_total_bytes{uuid="1ffe36ef-ac55-60ad-f9cf-623871e7736d"} 5304745984 183 | rspec_fb_memory_usage_used_bytes{uuid="1ffe36ef-ac55-60ad-f9cf-623871e7736d"} 334495744 184 | rspec_fb_memory_usage_free_bytes{uuid="1ffe36ef-ac55-60ad-f9cf-623871e7736d"} 4970250240 185 | rspec_bar1_memory_usage_total_bytes{uuid="1ffe36ef-ac55-60ad-f9cf-623871e7736d"} 268435456 186 | rspec_bar1_memory_usage_used_bytes{uuid="1ffe36ef-ac55-60ad-f9cf-623871e7736d"} 2097152 187 | rspec_bar1_memory_usage_free_bytes{uuid="1ffe36ef-ac55-60ad-f9cf-623871e7736d"} 266338304 188 | rspec_compute_mode{uuid="1ffe36ef-ac55-60ad-f9cf-623871e7736d"} 0 189 | rspec_utilization_gpu_util_ratio{uuid="1ffe36ef-ac55-60ad-f9cf-623871e7736d"} 0.0 190 | rspec_utilization_memory_util_ratio{uuid="1ffe36ef-ac55-60ad-f9cf-623871e7736d"} 0.0 191 | rspec_utilization_encoder_util_ratio{uuid="1ffe36ef-ac55-60ad-f9cf-623871e7736d"} 0.0 192 | rspec_utilization_decoder_util_ratio{uuid="1ffe36ef-ac55-60ad-f9cf-623871e7736d"} 0.0 193 | rspec_encoder_stats_session_count{uuid="1ffe36ef-ac55-60ad-f9cf-623871e7736d"} 0 194 | rspec_encoder_stats_average_fps{uuid="1ffe36ef-ac55-60ad-f9cf-623871e7736d"} 0 195 | rspec_encoder_stats_average_latency{uuid="1ffe36ef-ac55-60ad-f9cf-623871e7736d"} 0 196 | rspec_fbc_stats_session_count{uuid="1ffe36ef-ac55-60ad-f9cf-623871e7736d"} 0 197 | rspec_fbc_stats_average_fps{uuid="1ffe36ef-ac55-60ad-f9cf-623871e7736d"} 0 198 | rspec_fbc_stats_average_latency{uuid="1ffe36ef-ac55-60ad-f9cf-623871e7736d"} 0 199 | rspec_temperature_gpu_temp_celsius{uuid="1ffe36ef-ac55-60ad-f9cf-623871e7736d"} 62.0 200 | rspec_temperature_gpu_temp_max_threshold_celsius{uuid="1ffe36ef-ac55-60ad-f9cf-623871e7736d"} 104.0 201 | rspec_temperature_gpu_temp_slow_threshold_celsius{uuid="1ffe36ef-ac55-60ad-f9cf-623871e7736d"} 101.0 202 | rspec_power_readings_power_state{uuid="1ffe36ef-ac55-60ad-f9cf-623871e7736d"} 0 203 | rspec_power_readings_power_management{uuid="1ffe36ef-ac55-60ad-f9cf-623871e7736d"} 1 204 | rspec_power_readings_power_draw_watts{uuid="1ffe36ef-ac55-60ad-f9cf-623871e7736d"} 20.32 205 | rspec_power_readings_power_limit_watts{uuid="1ffe36ef-ac55-60ad-f9cf-623871e7736d"} 75.0 206 | rspec_power_readings_default_power_limit_watts{uuid="1ffe36ef-ac55-60ad-f9cf-623871e7736d"} 75.0 207 | rspec_power_readings_enforced_power_limit_watts{uuid="1ffe36ef-ac55-60ad-f9cf-623871e7736d"} 75.0 208 | rspec_power_readings_min_power_limit_watts{uuid="1ffe36ef-ac55-60ad-f9cf-623871e7736d"} 75.0 209 | rspec_power_readings_max_power_limit_watts{uuid="1ffe36ef-ac55-60ad-f9cf-623871e7736d"} 75.0 210 | rspec_clocks_graphics_clock_hz{uuid="1ffe36ef-ac55-60ad-f9cf-623871e7736d"} 1215000000.0 211 | rspec_clocks_sm_clock_hz{uuid="1ffe36ef-ac55-60ad-f9cf-623871e7736d"} 1215000000.0 212 | rspec_clocks_mem_clock_hz{uuid="1ffe36ef-ac55-60ad-f9cf-623871e7736d"} 3499000000.0 213 | rspec_clocks_video_clock_hz{uuid="1ffe36ef-ac55-60ad-f9cf-623871e7736d"} 1101000000.0 214 | rspec_applications_clocks_graphics_clock_hz{uuid="1ffe36ef-ac55-60ad-f9cf-623871e7736d"} 1075000000.0 215 | rspec_applications_clocks_mem_clock_hz{uuid="1ffe36ef-ac55-60ad-f9cf-623871e7736d"} 3504000000.0 216 | rspec_default_applications_clocks_graphics_clock_hz{uuid="1ffe36ef-ac55-60ad-f9cf-623871e7736d"} 1075000000.0 217 | rspec_default_applications_clocks_mem_clock_hz{uuid="1ffe36ef-ac55-60ad-f9cf-623871e7736d"} 3504000000.0 218 | rspec_max_clocks_graphics_clock_hz{uuid="1ffe36ef-ac55-60ad-f9cf-623871e7736d"} 1721000000.0 219 | rspec_max_clocks_sm_clock_hz{uuid="1ffe36ef-ac55-60ad-f9cf-623871e7736d"} 1721000000.0 220 | rspec_max_clocks_mem_clock_hz{uuid="1ffe36ef-ac55-60ad-f9cf-623871e7736d"} 3504000000.0 221 | rspec_max_clocks_video_clock_hz{uuid="1ffe36ef-ac55-60ad-f9cf-623871e7736d"} 1556000000.0 222 | rspec_max_customer_boost_clocks_graphics_clock_hz{uuid="1ffe36ef-ac55-60ad-f9cf-623871e7736d"} 1721000000.0 223 | rspec_processes_process_info_pid{uuid="1ffe36ef-ac55-60ad-f9cf-623871e7736d"} 7134 224 | rspec_processes_process_info_used_memory_bytes{uuid="1ffe36ef-ac55-60ad-f9cf-623871e7736d"} 324009984 225 | EOS 226 | end 227 | 228 | it do 229 | hash = subject.parse(fixture_load('nvidia-smi-4.xml')) 230 | expect(subject.format_prometheus(hash)).to eq(result) 231 | end 232 | end 233 | end 234 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | require 'helpers/fixture' 2 | require_relative '../app/n_vidia_smi' 3 | require_relative '../app/n_vidia_smi_xml' 4 | require 'json' 5 | require 'pry' 6 | 7 | # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration 8 | RSpec.configure do |config| 9 | include Fixture 10 | 11 | config.expect_with :rspec do |expectations| 12 | expectations.include_chain_clauses_in_custom_matcher_descriptions = true 13 | end 14 | 15 | config.mock_with :rspec do |mocks| 16 | mocks.verify_partial_doubles = true 17 | end 18 | 19 | config.shared_context_metadata_behavior = :apply_to_host_groups 20 | 21 | # The settings below are suggested to provide a good initial experience 22 | # with RSpec, but feel free to customize to your heart's content. 23 | =begin 24 | # This allows you to limit a spec run to individual examples or groups 25 | # you care about by tagging them with `:focus` metadata. When nothing 26 | # is tagged with `:focus`, all examples get run. RSpec also provides 27 | # aliases for `it`, `describe`, and `context` that include `:focus` 28 | # metadata: `fit`, `fdescribe` and `fcontext`, respectively. 29 | config.filter_run_when_matching :focus 30 | 31 | # Allows RSpec to persist some state between runs in order to support 32 | # the `--only-failures` and `--next-failure` CLI options. We recommend 33 | # you configure your source control system to ignore this file. 34 | config.example_status_persistence_file_path = "spec/examples.txt" 35 | 36 | # Limits the available syntax to the non-monkey patched syntax that is 37 | # recommended. For more details, see: 38 | # - http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/ 39 | # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/ 40 | # - http://rspec.info/blog/2014/05/notable-changes-in-rspec-3/#zero-monkey-patching-mode 41 | config.disable_monkey_patching! 42 | 43 | # This setting enables warnings. It's recommended, but in some cases may 44 | # be too noisy due to issues in dependencies. 45 | config.warnings = true 46 | 47 | # Many RSpec users commonly either run the entire suite or an individual 48 | # file, and it's useful to allow more verbose output when running an 49 | # individual spec file. 50 | if config.files_to_run.one? 51 | # Use the documentation formatter for detailed output, 52 | # unless a formatter has already been configured 53 | # (e.g. via a command-line flag). 54 | config.default_formatter = "doc" 55 | end 56 | 57 | # Print the 10 slowest examples and example groups at the 58 | # end of the spec run, to help surface which specs are running 59 | # particularly slow. 60 | config.profile_examples = 10 61 | 62 | # Run specs in random order to surface order dependencies. If you find an 63 | # order dependency and want to debug it, you can fix the order by providing 64 | # the seed, which is printed after each run. 65 | # --seed 1234 66 | config.order = :random 67 | 68 | # Seed global randomization in this process using the `--seed` CLI option. 69 | # Setting this allows you to use `--seed` to deterministically reproduce 70 | # test failures related to randomization by passing the same `--seed` value 71 | # as the one that triggered the failure. 72 | Kernel.srand config.seed 73 | =end 74 | end 75 | --------------------------------------------------------------------------------