docs: @Override
      public synchronized Properties getEnvironmentInformation() {
          if (properties == null) {
              Properties props = super.getEnvironmentInformation();
  
              List<Map<String, Object>> devicesList = new ArrayList<>();
  
              // fill with per-device information: name, memory, versions
              for (int i = 0; i < nativeOps.getAvailableDevices(); i++) {
                  Map<String, Object> deviceProps = new HashMap<>();
  
                  deviceProps.put(Nd4jEnvironment.CUDA_DEVICE_NAME_KEY, nativeOps.getDeviceName(i));
                  deviceProps.put(Nd4jEnvironment.CUDA_FREE_MEMORY_KEY, nativeOps.getDeviceFreeMemory(i));
                  deviceProps.put(Nd4jEnvironment.CUDA_TOTAL_MEMORY_KEY, nativeOps.getDeviceTotalMemory(i));
                  deviceProps.put(Nd4jEnvironment.CUDA_DEVICE_MAJOR_VERSION_KEY, (long) nativeOps.getDeviceMajor(i));
                  deviceProps.put(Nd4jEnvironment.CUDA_DEVICE_MINOR_VERSION_KEY, (long) nativeOps.getDeviceMinor(i));
  
                  devicesList.add(i, deviceProps);
              }
  
              // fill with basic general info
              props.put(Nd4jEnvironment.BACKEND_KEY, "CUDA");
              props.put(Nd4jEnvironment.CUDA_NUM_GPUS_KEY, nativeOps.getAvailableDevices());
              props.put(Nd4jEnvironment.CUDA_DEVICE_INFORMATION_KEY, devicesList);
              props.put(Nd4jEnvironment.BLAS_VENDOR_KEY, (Nd4j.factory().blas()).getBlasVendor().toString());
              props.put(Nd4jEnvironment.HOST_FREE_MEMORY_KEY, Pointer.maxBytes() - Pointer.totalBytes());
  
              // fill bandwidth information
              props.put(Nd4jEnvironment.MEMORY_BANDWIDTH_KEY, PerformanceTracker.getInstance().getCurrentBandwidth());
  
              properties = props;
          } else {
  
              List<Map<String, Object>> devicesList = (List<Map<String, Object>>) properties.get(Nd4jEnvironment.CUDA_DEVICE_INFORMATION_KEY);
  
              // just update information that might change over time
              for (int i = 0; i < nativeOps.getAvailableDevices(); i++) {
                  Map<String, Object> dev = devicesList.get(i);
  
                  dev.put(Nd4jEnvironment.CUDA_FREE_MEMORY_KEY, nativeOps.getDeviceFreeMemory(i));
                  dev.put(Nd4jEnvironment.CUDA_TOTAL_MEMORY_KEY, nativeOps.getDeviceTotalMemory(i));
              }
  
              properties.put(Nd4jEnvironment.CUDA_DEVICE_INFORMATION_KEY, devicesList);
              properties.put(Nd4jEnvironment.HOST_FREE_MEMORY_KEY, Pointer.maxBytes() - Pointer.totalBytes());
  
              // fill bandwidth information
              properties.put(Nd4jEnvironment.MEMORY_BANDWIDTH_KEY, PerformanceTracker.getInstance().getCurrentBandwidth());
          }
          return properties;
      }