r-lib / ps

R package to query, list, manipulate system processes
https://ps.r-lib.org/
Other
72 stars 18 forks source link

ps_system_cpu_times() value is inconsistent between OS's #144

Closed michaelwalshe closed 1 year ago

michaelwalshe commented 1 year ago

I have noticed an issue in ps::ps_system_cpu_times. On Linux (CentOS Linux 7) the CPU times appear to be in centiseconds, and so have to be divided by 100 to be equivalent to Windows:

Windows:

# Windows
ps::ps_system_cpu_times()["user"]
#>    user 
#> 43415.7

Created on 2023-04-20 with reprex v2.0.2

Session info ``` r sessionInfo() #> R version 4.2.2 (2022-10-31 ucrt) #> Platform: x86_64-w64-mingw32/x64 (64-bit) #> Running under: Windows 10 x64 (build 19045) #> #> Matrix products: default #> #> locale: #> [1] LC_COLLATE=English_United Kingdom.utf8 #> [2] LC_CTYPE=English_United Kingdom.utf8 #> [3] LC_MONETARY=English_United Kingdom.utf8 #> [4] LC_NUMERIC=C #> [5] LC_TIME=English_United Kingdom.utf8 #> #> attached base packages: #> [1] stats graphics grDevices utils datasets methods base #> #> loaded via a namespace (and not attached): #> [1] ps_1.7.1 digest_0.6.29 withr_2.5.0 lifecycle_1.0.1 #> [5] reprex_2.0.2 evaluate_0.20 rlang_1.0.6 cli_3.3.0 #> [9] rstudioapi_0.14 fs_1.6.1 rmarkdown_2.20 tools_4.2.2 #> [13] glue_1.6.2 xfun_0.37 yaml_2.3.7 fastmap_1.1.1 #> [17] compiler_4.2.2 htmltools_0.5.4 knitr_1.42 ```

Linux:

# Linux
ps::ps_system_cpu_times()["user"]
#>      user 
#> 668063502

Created on 2023-04-20 with reprex v2.0.2

Session info ``` r sessionInfo() #> R version 4.2.1 (2022-06-23) #> Platform: x86_64-pc-linux-gnu (64-bit) #> Running under: CentOS Linux 7 (Core) #> #> Matrix products: default #> BLAS/LAPACK: /usr/lib64/libopenblasp-r0.3.3.so #> #> locale: #> [1] LC_CTYPE=en_GB.UTF-8 LC_NUMERIC=C #> [3] LC_TIME=en_GB.UTF-8 LC_COLLATE=en_GB.UTF-8 #> [5] LC_MONETARY=en_GB.UTF-8 LC_MESSAGES=en_GB.UTF-8 #> [7] LC_PAPER=en_GB.UTF-8 LC_NAME=C #> [9] LC_ADDRESS=C LC_TELEPHONE=C #> [11] LC_MEASUREMENT=en_GB.UTF-8 LC_IDENTIFICATION=C #> #> attached base packages: #> [1] stats graphics grDevices utils datasets methods base #> #> loaded via a namespace (and not attached): #> [1] rstudioapi_0.13 knitr_1.39 magrittr_2.0.3 R.cache_0.16.0 #> [5] rlang_1.0.6 fastmap_1.1.0 fansi_1.0.3 stringr_1.4.0 #> [9] styler_1.7.0 highr_0.9 tools_4.2.1 xfun_0.31 #> [13] R.oo_1.25.0 utf8_1.2.2 cli_3.3.0 withr_2.5.0 #> [17] htmltools_0.5.3 ellipsis_0.3.2 yaml_2.3.5 digest_0.6.29 #> [21] tibble_3.1.7 lifecycle_1.0.1 crayon_1.5.1 purrr_0.3.4 #> [25] ps_1.7.1 R.utils_2.12.0 vctrs_0.4.1 fs_1.5.2 #> [29] glue_1.6.2 evaluate_0.15 rmarkdown_2.14 reprex_2.0.2 #> [33] stringi_1.7.6 compiler_4.2.1 pillar_1.7.0 R.methodsS3_1.8.2 #> [37] pkgconfig_2.0.3 ```

Created on 2023-04-20 with reprex v2.0.2

I can tell that they're in centiseconds (and not just a long uptime) as if you try to convert to percentages, you'll need to divide by 100 when on linux:

Windows:

library(ps)

ps_os_name <- function() {
  os <- ps::ps_os_type()
  os <- os[setdiff(names(os), c("BSD", "POSIX"))]
  names(os)[which(os)]
}

test_get_cpu_percs <- function() {
  # Get CPU times and record time
  initial_time <- Sys.time()
  initial_cpus <- ps_system_cpu_times()
  Sys.sleep(2)
  final_time <- Sys.time()
  final_cpus <- ps_system_cpu_times()

  # Difference in time
  delta_time <- as.numeric(initial_time - final_time, units = "secs")

  # Pre allocate percentages vector, and name
  cpu_percs <- vector(mode="numeric", length=length(initial_cpus))
  names(cpu_percs) <- names(initial_cpus)

  for (metric in names(initial_cpus)) {
    # CPU seconds
    delta_cpu <- initial_cpus[metric] - final_cpus[metric]
    # Divide CPU secs by time to get percentage, divide by no. CPUs
    # to ensure percentages are always below 100
    cpu_percs[metric] <- 100 * (delta_cpu / delta_time) / ps::ps_cpu_count()

    if (ps_os_name() != "WINDOWS") {
      # On linux divide by 100 to get to seconds from centiseconds
      print("Dividing...")
      cpu_percs[metric] <- cpu_percs[metric] / 100
    }
  }

  print(cpu_percs)
}
test_get_cpu_percs()
#>      user    system      idle 
#>  8.045197  6.417003 86.006989

Created on 2023-04-20 with reprex v2.0.2

Session info ``` r sessionInfo() #> R version 4.2.2 (2022-10-31 ucrt) #> Platform: x86_64-w64-mingw32/x64 (64-bit) #> Running under: Windows 10 x64 (build 19045) #> #> Matrix products: default #> #> locale: #> [1] LC_COLLATE=English_United Kingdom.utf8 #> [2] LC_CTYPE=English_United Kingdom.utf8 #> [3] LC_MONETARY=English_United Kingdom.utf8 #> [4] LC_NUMERIC=C #> [5] LC_TIME=English_United Kingdom.utf8 #> #> attached base packages: #> [1] stats graphics grDevices utils datasets methods base #> #> other attached packages: #> [1] ps_1.7.1 #> #> loaded via a namespace (and not attached): #> [1] digest_0.6.29 withr_2.5.0 lifecycle_1.0.1 reprex_2.0.2 #> [5] evaluate_0.20 rlang_1.0.6 cli_3.3.0 rstudioapi_0.14 #> [9] fs_1.6.1 rmarkdown_2.20 tools_4.2.2 glue_1.6.2 #> [13] xfun_0.37 yaml_2.3.7 fastmap_1.1.1 compiler_4.2.2 #> [17] htmltools_0.5.4 knitr_1.42 ```

Linux:

library(ps)

ps_os_name <- function() {
  os <- ps::ps_os_type()
  os <- os[setdiff(names(os), c("BSD", "POSIX"))]
  names(os)[which(os)]
}

test_get_cpu_percs <- function() {
  # Get CPU times and record time
  initial_time <- Sys.time()
  initial_cpus <- ps_system_cpu_times()
  Sys.sleep(2)
  final_time <- Sys.time()
  final_cpus <- ps_system_cpu_times()

  # Difference in time
  delta_time <- as.numeric(initial_time - final_time, units = "secs")

  # Pre allocate percentages vector, and name
  cpu_percs <- vector(mode="numeric", length=length(initial_cpus))
  names(cpu_percs) <- names(initial_cpus)

  for (metric in names(initial_cpus)) {
    # CPU seconds
    delta_cpu <- initial_cpus[metric] - final_cpus[metric]
    # Divide CPU secs by time to get percentage, divide by no. CPUs
    # to ensure percentages are always below 100
    cpu_percs[metric] <- 100 * (delta_cpu / delta_time) / ps::ps_cpu_count()

    if (ps_os_name() != "WINDOWS") {
      # On linux divide by 100 to get to seconds from centiseconds
      print("Dividing...")
      cpu_percs[metric] <- cpu_percs[metric] / 100
    }
  }

  print(cpu_percs)
}
test_get_cpu_percs()
#> [1] "Dividing..."
#> [1] "Dividing..."
#> [1] "Dividing..."
#> [1] "Dividing..."
#> [1] "Dividing..."
#> [1] "Dividing..."
#> [1] "Dividing..."
#> [1] "Dividing..."
#> [1] "Dividing..."
#> [1] "Dividing..."
#>       user       nice     system       idle     iowait        irq    softirq 
#> 10.3647238  0.0000000  8.4915809 80.1705138  0.0000000  0.0000000  0.1248762 
#>      steal      guest guest_nice 
#>  0.0000000  0.0000000  0.0000000

Created on 2023-04-20 with reprex v2.0.2

Session info ``` r sessionInfo() #> R version 4.2.1 (2022-06-23) #> Platform: x86_64-pc-linux-gnu (64-bit) #> Running under: CentOS Linux 7 (Core) #> #> Matrix products: default #> BLAS/LAPACK: /usr/lib64/libopenblasp-r0.3.3.so #> #> locale: #> [1] LC_CTYPE=en_GB.UTF-8 LC_NUMERIC=C #> [3] LC_TIME=en_GB.UTF-8 LC_COLLATE=en_GB.UTF-8 #> [5] LC_MONETARY=en_GB.UTF-8 LC_MESSAGES=en_GB.UTF-8 #> [7] LC_PAPER=en_GB.UTF-8 LC_NAME=C #> [9] LC_ADDRESS=C LC_TELEPHONE=C #> [11] LC_MEASUREMENT=en_GB.UTF-8 LC_IDENTIFICATION=C #> #> attached base packages: #> [1] stats graphics grDevices utils datasets methods base #> #> other attached packages: #> [1] ps_1.7.1 #> #> loaded via a namespace (and not attached): #> [1] rstudioapi_0.13 knitr_1.39 magrittr_2.0.3 R.cache_0.16.0 #> [5] rlang_1.0.6 fastmap_1.1.0 fansi_1.0.3 stringr_1.4.0 #> [9] styler_1.7.0 highr_0.9 tools_4.2.1 xfun_0.31 #> [13] R.oo_1.25.0 utf8_1.2.2 cli_3.3.0 withr_2.5.0 #> [17] htmltools_0.5.3 ellipsis_0.3.2 yaml_2.3.5 digest_0.6.29 #> [21] tibble_3.1.7 lifecycle_1.0.1 crayon_1.5.1 purrr_0.3.4 #> [25] R.utils_2.12.0 vctrs_0.4.1 fs_1.5.2 glue_1.6.2 #> [29] evaluate_0.15 rmarkdown_2.14 reprex_2.0.2 stringi_1.7.6 #> [33] compiler_4.2.1 pillar_1.7.0 R.methodsS3_1.8.2 pkgconfig_2.0.3 ```
gaborcsardi commented 1 year ago

Thanks! A PR is welcome, but no pressure! 😄

michaelwalshe commented 1 year ago

Okay great, will open a PR soon