├── Cython ├── .gitignore ├── setup.py ├── Makefile └── swapview.pyx ├── benchmark ├── .gitignore ├── Cargo.toml └── Cargo.lock ├── run_benchmark ├── .clang-format ├── Rust_parallel ├── .swapview │ ├── src │ │ └── main.rs │ ├── Cargo.toml │ └── Cargo.lock ├── Makefile └── swapview.rs ├── Chicken ├── .gitignore ├── Makefile └── swapview.scm ├── Haskell ├── stack.yaml ├── setup.hs ├── Makefile ├── swapview.cabal └── swapview.hs ├── Crystal ├── .gitignore ├── shard.yml ├── shard.lock ├── swapview.cr ├── Makefile ├── swapview_process.cr ├── swapview_fiber.cr └── common.cr ├── Haskell_parallel ├── .gitignore ├── setup.hs ├── Makefile ├── package.yaml ├── stack.yaml └── swapview.hs ├── Dart ├── pubspec.yaml ├── Makefile └── swapview.dart ├── Go ├── Makefile └── swapview.go ├── Go_goroutine ├── Makefile └── swapview.go ├── Vala ├── Makefile └── swapview.vala ├── Rust ├── Makefile └── swapview.rs ├── FreePascal ├── Makefile └── swapview.pas ├── Nim ├── Makefile └── swapview.nim ├── OCaml ├── Makefile └── swapview.ml ├── test.toml ├── Scala ├── Makefile └── swapview.scala ├── C++11 ├── Makefile └── swapview.cc ├── Erlang ├── Makefile └── swapview.erl ├── Zig ├── Makefile └── swapview.zig ├── C++14 ├── Makefile └── swapview.cpp ├── C++17 ├── Makefile └── swapview.cpp ├── C ├── Makefile └── swapview.c ├── NodeJS ├── Makefile ├── package.json └── swapview.js ├── C++14_boost ├── Makefile └── swapview.cpp ├── ChezScheme ├── Makefile └── swapview.ss ├── NodeJS_async ├── Makefile ├── package.json └── swapview.js ├── broken ├── README.md └── OCaml_lwt │ ├── Makefile │ └── swapview.ml ├── NodeJS_cluster ├── Makefile ├── package.json └── swapview.js ├── Typed_Racket ├── Makefile └── swapview.rkt ├── Racket_parallel ├── Makefile └── swapview.rkt ├── Racket ├── Makefile └── swapview.rkt ├── D ├── Makefile └── swapview.d ├── D_parallel ├── Makefile └── swapview.d ├── CoffeeScript ├── Makefile ├── package.json └── swapview.coffee ├── Java ├── Makefile └── SwapView.java ├── CoffeeScript_parallel ├── Makefile ├── package.json └── swapview.coffee ├── C++98 ├── Makefile └── swapview.cpp ├── CSharp ├── Makefile └── SwapView.cs ├── CommonLisp_opt ├── Makefile └── swapview.lisp ├── .gitignore ├── countlines ├── Makefile ├── rankchange ├── PowerShell └── swapview.ps1 ├── Ruby └── swapview.rb ├── Python3_bytes └── swapview.py ├── Ruby_ractor └── swapview.rb ├── Julia └── swapview.jl ├── Tcl └── swapview.tcl ├── Python └── swapview.py ├── Bash └── swapview.sh ├── Python_mp └── swapview.py ├── Bash_parallel └── swapview.sh ├── Elixir └── swapview.exs ├── R └── swapview.r ├── PHP └── swapview.php ├── Guile └── swapview.scm ├── Lua └── swapview.lua ├── POSIX_shell └── swapview.sh ├── changes ├── Perl └── swapview.pl ├── newlisp └── swapview.lsp ├── CommonLisp_old └── swapview.lisp ├── newlisp_mp └── swapview.lsp ├── Perl_parallel └── swapview.pl ├── benchmark.toml ├── bench.py ├── result-20160630.txt └── result-20170714.txt /Cython/.gitignore: -------------------------------------------------------------------------------- 1 | *.c 2 | -------------------------------------------------------------------------------- /benchmark/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /run_benchmark: -------------------------------------------------------------------------------- 1 | benchmark/target/release/benchmark -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | BasedOnStyle: LLVM 3 | --- 4 | -------------------------------------------------------------------------------- /Rust_parallel/.swapview/src/main.rs: -------------------------------------------------------------------------------- 1 | ../../swapview.rs -------------------------------------------------------------------------------- /Chicken/.gitignore: -------------------------------------------------------------------------------- 1 | swapview 2 | deps/* 3 | swapview.link 4 | -------------------------------------------------------------------------------- /Haskell/stack.yaml: -------------------------------------------------------------------------------- 1 | resolver: lts-13.26 2 | packages: 3 | - . 4 | -------------------------------------------------------------------------------- /Haskell/setup.hs: -------------------------------------------------------------------------------- 1 | import Distribution.Simple 2 | main = defaultMain 3 | -------------------------------------------------------------------------------- /Crystal/.gitignore: -------------------------------------------------------------------------------- 1 | lib/ 2 | swapview 3 | swapview_fiber 4 | swapview_process 5 | -------------------------------------------------------------------------------- /Haskell_parallel/.gitignore: -------------------------------------------------------------------------------- 1 | .stack-work/ 2 | swapview.cabal 3 | *~ 4 | swapview 5 | -------------------------------------------------------------------------------- /Haskell_parallel/setup.hs: -------------------------------------------------------------------------------- 1 | import Distribution.Simple 2 | main = defaultMain 3 | -------------------------------------------------------------------------------- /Crystal/shard.yml: -------------------------------------------------------------------------------- 1 | name: swapview 2 | version: 0.0.1 3 | 4 | dependencies: 5 | parallel_worker: 6 | github: aligo/parallel_worker 7 | -------------------------------------------------------------------------------- /Dart/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: 'swapview' 2 | version: 0.0.1 3 | description: View swap usage for each process 4 | 5 | dependencies: 6 | path: "^1.3.9" 7 | -------------------------------------------------------------------------------- /Go/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: all clean 2 | 3 | %: %.go 4 | go build -ldflags "-w -s" $< 5 | 6 | all: swapview 7 | 8 | clean: 9 | -rm -f swapview 10 | -------------------------------------------------------------------------------- /Cython/setup.py: -------------------------------------------------------------------------------- 1 | from distutils.core import setup 2 | from Cython.Build import cythonize 3 | 4 | setup( 5 | ext_modules=cythonize("swapview.pyx"), 6 | ) 7 | -------------------------------------------------------------------------------- /Go_goroutine/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: all clean 2 | 3 | %: %.go 4 | go build -ldflags "-w -s" $< 5 | 6 | all: swapview 7 | 8 | clean: 9 | -rm -f swapview 10 | -------------------------------------------------------------------------------- /Vala/Makefile: -------------------------------------------------------------------------------- 1 | default: swapview 2 | 3 | swapview: swapview.vala 4 | valac --pkg gio-2.0 --Xcc=-O4 $^ -o $@ 5 | strip swapview 6 | 7 | clean: 8 | -rm -f swapview 9 | -------------------------------------------------------------------------------- /Rust/Makefile: -------------------------------------------------------------------------------- 1 | CC=rustc 2 | 3 | .PHONY: all clean 4 | 5 | %: %.rs 6 | $(CC) -O -C lto $< 7 | strip $@ 8 | 9 | all: swapview 10 | 11 | clean: 12 | -rm -f swapview 13 | -------------------------------------------------------------------------------- /FreePascal/Makefile: -------------------------------------------------------------------------------- 1 | FPFLAGS=-O3 2 | FPC=fpc 3 | 4 | swapview: swapview.pas 5 | $(FPC) swapview.pas $(FPFLAGS) 6 | strip swapview 7 | 8 | clean: 9 | -rm -f swapview{,.o} 10 | -------------------------------------------------------------------------------- /Nim/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: all clean 2 | 3 | %: %.nim 4 | nim c -d:release $< 5 | strip $@ 6 | 7 | all: swapview 8 | 9 | clean: 10 | -rm -f swapview 11 | -rm -rf nimcache 12 | -------------------------------------------------------------------------------- /OCaml/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: all clean 2 | 3 | %: %.ml 4 | ocamlopt -ccopt -O3 -noassert -unsafe $< -o $@ 5 | strip $@ 6 | 7 | all: swapview 8 | 9 | clean: 10 | -rm -f *.cm* swapview{,.o} 11 | -------------------------------------------------------------------------------- /test.toml: -------------------------------------------------------------------------------- 1 | [item.default] 2 | cmd = ['./swapview'] 3 | dir = '$name' 4 | time_limit = 30 5 | count_limit = 20 6 | valid_percent = 50 7 | 8 | [item.C] 9 | 10 | [item.Rust] 11 | 12 | [item.Fail] 13 | -------------------------------------------------------------------------------- /Scala/Makefile: -------------------------------------------------------------------------------- 1 | default: SwapView.class 2 | 3 | SwapView.class: swapview.scala 4 | scalac swapview.scala 5 | 6 | clean: 7 | -rm -f SwapView.class 8 | 9 | run: SwapView.class 10 | scala SwapView 11 | -------------------------------------------------------------------------------- /C++11/Makefile: -------------------------------------------------------------------------------- 1 | CPPFLAGS=-O4 -flto -Wall 2 | CPPC=g++ 3 | 4 | swapview: swapview.cc 5 | $(CPPC) --std=c++11 swapview.cc -o swapview $(CPPFLAGS) 6 | strip swapview 7 | 8 | clean: 9 | -rm -f swapview 10 | -------------------------------------------------------------------------------- /Cython/Makefile: -------------------------------------------------------------------------------- 1 | default: cython.timestamp 2 | 3 | cython.timestamp: swapview.pyx 4 | python setup.py build_ext --inplace && touch cython.timestamp 5 | 6 | run: cython.timestamp 7 | python -c "import swapview" 8 | -------------------------------------------------------------------------------- /Erlang/Makefile: -------------------------------------------------------------------------------- 1 | TARGET = swapview.beam 2 | all:: $(TARGET) 3 | 4 | swapview.beam: swapview.erl 5 | erlc $^ 6 | 7 | test:: all 8 | ./swapview 9 | 10 | clean:: 11 | -rm -f $(TARGET) erl_crash.dump 12 | -------------------------------------------------------------------------------- /Zig/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: all clean 2 | 3 | %: %.zig 4 | zig build-exe -O ReleaseSafe -fstrip $< 5 | 6 | all: swapview 7 | 8 | clean: 9 | -rm -f swapview 10 | -rm -f swapview.o 11 | 12 | test: 13 | zig test swapview.zig 14 | -------------------------------------------------------------------------------- /C++14/Makefile: -------------------------------------------------------------------------------- 1 | CPPFLAGS=-O4 -flto -Wall -fno-exceptions -fno-rtti -std=c++14 2 | CPPC=g++ 3 | 4 | swapview: swapview.cpp 5 | $(CPPC) swapview.cpp -o swapview $(CPPFLAGS) 6 | strip swapview 7 | 8 | clean: 9 | -rm -f swapview 10 | -------------------------------------------------------------------------------- /C++17/Makefile: -------------------------------------------------------------------------------- 1 | CPPFLAGS=-O4 -flto -Wall -fno-exceptions -fno-rtti -std=c++17 -lstdc++fs 2 | CPPC=g++ 3 | 4 | swapview: swapview.cpp 5 | $(CPPC) swapview.cpp -o swapview $(CPPFLAGS) 6 | strip swapview 7 | 8 | clean: 9 | -rm -f swapview 10 | -------------------------------------------------------------------------------- /Dart/Makefile: -------------------------------------------------------------------------------- 1 | .packages: 2 | pub get 3 | 4 | swapview: swapview.dart .packages 5 | dart2native swapview.dart -o swapview 6 | 7 | all: swapview-native 8 | 9 | clean: 10 | rm -rf .dart_tool/ packages/ .packages pubspec.lock swapview 11 | -------------------------------------------------------------------------------- /C/Makefile: -------------------------------------------------------------------------------- 1 | CFLAGS:=-O4 -flto -Wall -std=c11 2 | CC:=gcc 3 | EXT:= 4 | STRIP:=strip 5 | 6 | BIN=swapview$(EXT) 7 | 8 | $(BIN): swapview.c 9 | $(CC) swapview.c -o $(BIN) $(CFLAGS) 10 | $(STRIP) $(BIN) 11 | 12 | clean: 13 | -rm -f $(BIN) 14 | -------------------------------------------------------------------------------- /Rust_parallel/.swapview/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "swapview" 3 | version = "0.0.1" 4 | authors = ["lilydjwg "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | rayon = "1" 9 | 10 | [profile.release] 11 | lto = true 12 | -------------------------------------------------------------------------------- /benchmark/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "benchmark" 3 | version = "0.0.2" 4 | authors = ["lilydjwg "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | toml = "*" 9 | glob = "*" 10 | 11 | [profile.release] 12 | lto = true 13 | -------------------------------------------------------------------------------- /NodeJS/Makefile: -------------------------------------------------------------------------------- 1 | default: node_modules/.timestamp 2 | 3 | node_modules/.timestamp: package.json 4 | npm install && touch node_modules/.timestamp 5 | 6 | clean: 7 | -rm -rf node_modules 8 | 9 | run: node_modules/.timestamp 10 | node swapview.js 11 | -------------------------------------------------------------------------------- /C++14_boost/Makefile: -------------------------------------------------------------------------------- 1 | CPPFLAGS=-O4 -flto -Wall -lboost_filesystem -lboost_system -fno-rtti -std=c++14 2 | CPPC=g++ 3 | 4 | swapview: swapview.cpp 5 | $(CPPC) swapview.cpp -o swapview $(CPPFLAGS) 6 | strip swapview 7 | 8 | clean: 9 | -rm -f swapview 10 | -------------------------------------------------------------------------------- /ChezScheme/Makefile: -------------------------------------------------------------------------------- 1 | default: swapview.so 2 | 3 | swapview.so: swapview.ss 4 | echo '(compile-program "swapview.ss")' | scheme -q --optimize-level 3 5 | 6 | run: swapview.so 7 | scheme --program swapview.so 8 | 9 | clean: 10 | -rm -f swapview.so 11 | -------------------------------------------------------------------------------- /NodeJS_async/Makefile: -------------------------------------------------------------------------------- 1 | default: node_modules/.timestamp 2 | 3 | node_modules/.timestamp: package.json 4 | npm install && touch node_modules/.timestamp 5 | 6 | clean: 7 | -rm -rf node_modules 8 | 9 | run: node_modules/.timestamp 10 | node swapview.js 11 | -------------------------------------------------------------------------------- /broken/README.md: -------------------------------------------------------------------------------- 1 | These implementations were working but are currently broken, needing a fix not so trivial that I can't work out. 2 | 3 | * OCaml_lwt: lwt does not build and no error messages 4 | 5 | You may want to not consider these things for your projects. 6 | -------------------------------------------------------------------------------- /Haskell/Makefile: -------------------------------------------------------------------------------- 1 | all: swapview 2 | 3 | .PHONY: all clean deps cleandeps 4 | 5 | swapview: swapview.hs 6 | stack build 7 | ln -sfr $$(stack path --local-install-root)/bin/swapview 8 | strip swapview 9 | 10 | clean: 11 | stack clean 12 | rm swapview 13 | -------------------------------------------------------------------------------- /Crystal/shard.lock: -------------------------------------------------------------------------------- 1 | version: 1.0 2 | shards: 3 | msgpack: 4 | github: crystal-community/msgpack-crystal 5 | version: 0.14.2 6 | 7 | parallel_worker: 8 | github: aligo/parallel_worker 9 | commit: 9fd802c70a6249daa94cd5d64f62251e5c233605 10 | 11 | -------------------------------------------------------------------------------- /Haskell_parallel/Makefile: -------------------------------------------------------------------------------- 1 | all: swapview 2 | 3 | .PHONY: all clean deps cleandeps 4 | 5 | swapview: swapview.hs 6 | stack build 7 | ln -sfr $$(stack path --local-install-root)/bin/swapview 8 | strip swapview 9 | 10 | clean: 11 | stack clean 12 | rm swapview 13 | -------------------------------------------------------------------------------- /NodeJS_cluster/Makefile: -------------------------------------------------------------------------------- 1 | default: node_modules/.timestamp 2 | 3 | node_modules/.timestamp: package.json 4 | npm install && \ 5 | touch node_modules/.timestamp 6 | 7 | clean: 8 | -rm -rf node_modules 9 | 10 | run: node_modules/.timestamp 11 | node swapview.js 12 | -------------------------------------------------------------------------------- /Typed_Racket/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: all clean 2 | 3 | all: compiled/swapview_rkt.zo 4 | 5 | compiled/swapview_rkt.zo: swapview.rkt 6 | raco make --no-deps swapview.rkt 7 | 8 | run: all 9 | racket -t compiled/swapview_rkt.zo 10 | 11 | clean: 12 | -rm -rf compiled 13 | -------------------------------------------------------------------------------- /Racket_parallel/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: all clean 2 | 3 | all: compiled/swapview_rkt.zo 4 | 5 | compiled/swapview_rkt.zo: swapview.rkt 6 | raco make --no-deps swapview.rkt 7 | 8 | run: all 9 | racket -t compiled/swapview_rkt.zo 10 | 11 | clean: 12 | -rm -rf compiled 13 | -------------------------------------------------------------------------------- /Racket/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: all clean 2 | 3 | all: compiled/swapview_rkt.zo 4 | 5 | compiled/swapview_rkt.zo: swapview.rkt ../Racket_parallel/swapview.rkt 6 | raco make --no-deps swapview.rkt 7 | 8 | run: all 9 | racket swapview.rkt 10 | 11 | clean: 12 | -rm -rf compiled 13 | -------------------------------------------------------------------------------- /D/Makefile: -------------------------------------------------------------------------------- 1 | all: swapview swapview-llvm 2 | 3 | swapview: swapview.d 4 | dmd -O -release -inline -boundscheck=off $< 5 | strip $@ 6 | 7 | swapview-llvm: swapview.d 8 | ldc2 -g -O4 --flto=full $< -of=$@ 9 | strip $@ 10 | 11 | clean: 12 | -rm -f swapview{,-llvm} *.o 13 | 14 | -------------------------------------------------------------------------------- /D_parallel/Makefile: -------------------------------------------------------------------------------- 1 | all: swapview swapview-llvm 2 | 3 | swapview: swapview.d 4 | dmd -O -release -inline -boundscheck=off $< 5 | strip $@ 6 | 7 | swapview-llvm: swapview.d 8 | ldc2 -O3 --flto=full $< -of$@ 9 | strip $@ 10 | 11 | clean: 12 | -rm -f swapview{,-llvm} *.o 13 | 14 | -------------------------------------------------------------------------------- /Haskell/swapview.cabal: -------------------------------------------------------------------------------- 1 | Name: swapview 2 | Version: 0.1 3 | Cabal-Version: >= 1.2 4 | Build-Type: Simple 5 | 6 | Executable swapview 7 | Build-Depends: base, directory, bytestring 8 | Main-Is: swapview.hs 9 | Hs-Source-Dirs: . 10 | GHC-Options: -O2 11 | -------------------------------------------------------------------------------- /CoffeeScript/Makefile: -------------------------------------------------------------------------------- 1 | default: swapview.js node_modules/.timestamp 2 | 3 | %.js: %.coffee 4 | coffee -bc $< 5 | 6 | node_modules/.timestamp: package.json 7 | npm install && touch node_modules/.timestamp 8 | 9 | clean: 10 | -rm -rf node_modules *.js 11 | 12 | run: default 13 | node swapview.js 14 | -------------------------------------------------------------------------------- /Java/Makefile: -------------------------------------------------------------------------------- 1 | default: SwapView.class 2 | 3 | SwapView.class: SwapView.java 4 | javac -g:none SwapView.java 5 | 6 | clean: 7 | -rm -f SwapView.class 8 | 9 | run: SwapView.class 10 | java -dsa -Xmixed -XX:CompileThreshold=4096 -XX:+TieredCompilation -XX:TieredStopAtLevel=1 -XX:+UseSerialGC SwapView 11 | -------------------------------------------------------------------------------- /CoffeeScript_parallel/Makefile: -------------------------------------------------------------------------------- 1 | default: swapview.js node_modules/.timestamp 2 | 3 | %.js: %.coffee 4 | coffee -bc $< 5 | 6 | node_modules/.timestamp: package.json 7 | npm install && touch node_modules/.timestamp 8 | 9 | clean: 10 | -rm -rf node_modules *.js 11 | 12 | run: node_modules 13 | node swapview.js 14 | -------------------------------------------------------------------------------- /C++98/Makefile: -------------------------------------------------------------------------------- 1 | all: swapview swapview_omp 2 | 3 | CPPFLAGS=-O4 -flto -Wall -fno-exceptions -fno-rtti -std=c++98 4 | CPPC=g++ 5 | 6 | swapview: swapview.cpp 7 | $(CPPC) $^ -o $@ $(CPPFLAGS) 8 | strip $@ 9 | 10 | swapview_omp: swapview.cpp 11 | $(CPPC) -DUSE_OMP -fopenmp $^ -o $@ $(CPPFLAGS) 12 | strip $@ 13 | 14 | clean: 15 | -rm -f swapview{,_omp} 16 | -------------------------------------------------------------------------------- /NodeJS/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "swapview", 3 | "version": "1.0.0", 4 | "description": "view swap for each process", 5 | "main": "swapview.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "", 10 | "license": "ISC", 11 | "dependencies": { 12 | "sprintf-js": "" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /NodeJS_cluster/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "swapview", 3 | "version": "1.0.0", 4 | "description": "view swap for each process", 5 | "main": "swapview.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "", 10 | "license": "ISC", 11 | "dependencies": { 12 | "sprintf-js": "" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /broken/OCaml_lwt/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: all clean 2 | 3 | %: %.ml 4 | opam init -n 5 | opam install -y lwt.3.0.0 6 | ocamlfind \ 7 | ocamlopt -ccopt -O3 -noassert -unsafe \ 8 | -linkpkg \ 9 | -package lwt.unix \ 10 | -package lwt.ppx -ppxopt lwt.ppx,-no-debug \ 11 | -o $@ $< 12 | strip $@ 13 | 14 | all: swapview 15 | 16 | clean: 17 | -rm -f *.cm* swapview{,.o} 18 | -------------------------------------------------------------------------------- /NodeJS_async/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "swapview", 3 | "version": "1.0.0", 4 | "description": "view swap for each process", 5 | "main": "swapview.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "", 10 | "license": "ISC", 11 | "dependencies": { 12 | "sprintf-js": "", 13 | "async": "" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Haskell_parallel/package.yaml: -------------------------------------------------------------------------------- 1 | name: swapview 2 | version: 0.1.0.0 3 | 4 | dependencies: 5 | - base >= 4.7 && < 5 6 | - directory 7 | - bytestring 8 | - monad-parallel 9 | 10 | executables: 11 | swapview: 12 | main: swapview.hs 13 | ghc-options: 14 | - -threaded 15 | - -rtsopts 16 | - -with-rtsopts=-maxN4 17 | - -O2 18 | -------------------------------------------------------------------------------- /CSharp/Makefile: -------------------------------------------------------------------------------- 1 | MONOFLAGS=--desktop 2 | MONO=mono-sgen 3 | 4 | default: SwapView.exe.so 5 | 6 | SwapView.exe: SwapView.cs 7 | dmcs -clscheck- -debug- -optimize+ SwapView.cs 8 | 9 | SwapView.exe.so: SwapView.exe 10 | $(MONO) --aot -O=all,-shared $(MONOFLAGS) SwapView.exe 11 | 12 | clean: 13 | -rm -f SwapView.exe{,.so} 14 | 15 | run: SwapView.exe.so 16 | $(MONO) $(MONOFLAGS) SwapView.exe 17 | -------------------------------------------------------------------------------- /CoffeeScript/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "swapview", 3 | "version": "0.0.2", 4 | "description": "small script to show linux swap", 5 | "scripts": { 6 | "test": "coffee swapview.coffee" 7 | }, 8 | "keywords": [ 9 | "swap", 10 | "linux" 11 | ], 12 | "author": "jiyinyiyong", 13 | "license": "MIT", 14 | "dependencies": { 15 | "denodeify": "^1.2.1" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /CoffeeScript_parallel/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "swapview", 3 | "version": "0.0.2", 4 | "description": "small script to show linux swap", 5 | "scripts": { 6 | "test": "coffee swapview.coffee" 7 | }, 8 | "keywords": [ 9 | "swap", 10 | "linux" 11 | ], 12 | "author": "jiyinyiyong", 13 | "license": "MIT", 14 | "dependencies": { 15 | "denodeify": "^1.2.1" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /CommonLisp_opt/Makefile: -------------------------------------------------------------------------------- 1 | all: swapview 2 | 3 | swapview: swapview.lisp 4 | sbcl --noinform --quit --eval "(progn (load (compile-file \"swapview.lisp\"))(save-lisp-and-die \"swapview\" :toplevel #'main :executable t))" 5 | 6 | sprof: swapview.lisp 7 | sbcl --noinform --quit --eval "(progn (require :sb-sprof) (load (compile-file \"swapview.lisp\")))" 8 | 9 | clean: 10 | -rm -f swapview *.fasl *.fas *.lib 11 | 12 | 13 | -------------------------------------------------------------------------------- /Racket/swapview.rkt: -------------------------------------------------------------------------------- 1 | #lang racket/base 2 | (require (submod "../Racket_parallel/swapview.rkt" shared)) 3 | (provide main) 4 | (define (main) 5 | (define tbl (make-table)) 6 | (parameterize ((current-directory "/proc")) 7 | (for ((pid (in-directory #f (lambda (_) #f)))) 8 | (define pair (resolve-pid pid)) 9 | (cond (pair (table-update! tbl (car pair) (cdr pair)))))) 10 | (print-table tbl)) 11 | 12 | (main) 13 | -------------------------------------------------------------------------------- /Crystal/swapview.cr: -------------------------------------------------------------------------------- 1 | require "./common.cr" 2 | 3 | module SwapView 4 | def get_swap 5 | pids = get_pids 6 | 7 | result = [] of Tuple(Int32, Int32, String | Nil) 8 | pids.each do |pid| 9 | swap_info = get_swap_for(pid) 10 | if swap_info[1] > 0 11 | result << swap_info 12 | end 13 | end 14 | 15 | result.sort_by! { |x| x[1] } 16 | result 17 | end 18 | 19 | def main 20 | results = get_swap 21 | report(results) 22 | end 23 | end 24 | 25 | SwapView.main 26 | -------------------------------------------------------------------------------- /Crystal/Makefile: -------------------------------------------------------------------------------- 1 | CRYSTAL_BIN ?= $(shell which crystal) 2 | SHARDS_BIN ?= $(shell which shards) 3 | 4 | .PHONY: all clean 5 | 6 | default: all 7 | 8 | %: %.cr 9 | $(CRYSTAL_BIN) build --release --no-debug $< 10 | strip $@ 11 | 12 | lib/.shard_installed: swapview_process.cr 13 | $(SHARDS_BIN) install 14 | touch lib/.shard_installed 15 | 16 | swapview_process: swapview_process.cr lib/.shard_installed 17 | 18 | all: swapview swapview_fiber swapview_process 19 | 20 | clean: 21 | -rm -rf swapview{,_fiber,_process} lib/ 22 | -------------------------------------------------------------------------------- /Rust_parallel/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: all clean 2 | 3 | target = $(shell \ 4 | cd .swapview; \ 5 | if type jshon >/dev/null 2>&1; then \ 6 | cargo metadata --format-version=1 | jshon -e target_directory -u; \ 7 | elif type jq >/dev/null 2>&1; then \ 8 | cargo metadata --format-version=1 | jq -r .target_directory; \ 9 | else \ 10 | echo .swapview/target; \ 11 | fi; \ 12 | ) 13 | 14 | %: %.rs 15 | cd .swapview && cargo build --release 16 | strip $(target)/release/swapview 17 | ln -srf $(target)/release/swapview 18 | 19 | all: swapview 20 | 21 | clean: 22 | -rm -rf $(target)/release/swapview 23 | -------------------------------------------------------------------------------- /Crystal/swapview_process.cr: -------------------------------------------------------------------------------- 1 | require "system" 2 | 3 | require "parallel_worker" 4 | require "./common.cr" 5 | 6 | module SwapView 7 | def get_swap 8 | pids = get_pids 9 | 10 | worker = ParallelWorker::Process(Int32, Tuple(Int32, Int32, String | Nil)).new(System.cpu_count.to_i32) do |pid| 11 | get_swap_for(pid) 12 | end 13 | 14 | result = worker.perform_all(pids) 15 | result.select! { |swap_info| swap_info && swap_info[1] > 0 } 16 | 17 | result.sort_by! { |x| x[1] } 18 | result 19 | end 20 | 21 | def main 22 | results = get_swap 23 | report(results) 24 | end 25 | end 26 | 27 | SwapView.main 28 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # general 2 | *.cm? 3 | *.hi 4 | *.stamp 5 | *.class 6 | *.fasl 7 | *.beam 8 | *.o 9 | *.exe 10 | *.so 11 | erl_crash.dump 12 | node_modules/ 13 | .cabal-sandbox/ 14 | .stack-work/ 15 | dist/ 16 | cabal.sandbox.config 17 | packages/ 18 | .packages 19 | pubspec.lock 20 | .dart_tool 21 | 22 | # swapview specific 23 | */swapview 24 | broken/*/swapview 25 | CoffeeScript*/*.js 26 | D/swapview-llvm 27 | D_parallel/swapview-llvm 28 | C++98/swapview_omp 29 | Racket/compiled 30 | Racket_parallel/compiled 31 | Racket_parallel/swapview 32 | Nim/nimcache/ 33 | maketime 34 | Rust_parallel/.swapview/target 35 | 36 | package-lock.json 37 | *.timestamp 38 | stack.yaml.lock 39 | -------------------------------------------------------------------------------- /Chicken/Makefile: -------------------------------------------------------------------------------- 1 | default: swapview 2 | 3 | CHICKEN_INSTALL_REPOSITORY:=$(shell pwd)/deps 4 | CHICKEN_REPOSITORY_PATH:=$(shell pwd)/deps:$(shell chicken-install -repository) 5 | export CHICKEN_INSTALL_REPOSITORY 6 | export CHICKEN_REPOSITORY_PATH 7 | 8 | 9 | deps/.timestamp: 10 | mkdir -p $(CHICKEN_INSTALL_REPOSITORY) 11 | chicken-install format 12 | chicken-install srfi-1 13 | touch deps/.timestamp 14 | 15 | swapview: deps/.timestamp swapview.scm 16 | chicken-csc -O5 swapview.scm -include-path $(CHICKEN_INSTALL_REPOSITORY) -static 17 | strip swapview 18 | 19 | run: swapview 20 | ./swapview 21 | 22 | clean: 23 | -rm -f swapview swapview.link 24 | -rm -r deps 25 | -------------------------------------------------------------------------------- /countlines: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import os 4 | from subprocess import check_output 5 | 6 | def countlines(d): 7 | files = check_output(['git', 'ls-files', d]).decode('utf-8').splitlines() 8 | c = 0 9 | for f in files: 10 | if f.endswith('/Makefile'): 11 | continue 12 | with open(f, 'rb') as fobj: 13 | c += fobj.read().count(b'\n') 14 | return c 15 | 16 | def main(): 17 | os.chdir(os.path.dirname(os.path.abspath(__file__))) 18 | result = {} 19 | for d in os.listdir(): 20 | if d[0].isupper() and os.path.isdir(d): 21 | result[d] = countlines(d) 22 | for name, lines in sorted(result.items(), key=lambda x: x[1]): 23 | print('%24s: %4d' % (name, lines)) 24 | 25 | if __name__ == '__main__': 26 | main() 27 | -------------------------------------------------------------------------------- /Crystal/swapview_fiber.cr: -------------------------------------------------------------------------------- 1 | require "./common.cr" 2 | 3 | module SwapView 4 | def get_swap 5 | pids = get_pids 6 | 7 | channel = Channel(Tuple(Int32, Int32, String | Nil)).new(pids.size) 8 | 9 | pids.each do |pid| 10 | spawn do 11 | swap_info = get_swap_for(pid) 12 | channel.send(swap_info) 13 | end 14 | end 15 | 16 | result = [] of {Int32, Int32, String | Nil} 17 | pids.size.times do 18 | swap_info = channel.receive 19 | if swap_info && swap_info[1] > 0 20 | result << swap_info 21 | end 22 | end 23 | 24 | result.sort_by! { |x| x[1] } 25 | result 26 | end 27 | 28 | def main 29 | results = get_swap 30 | report(results) 31 | end 32 | end 33 | 34 | SwapView.main 35 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: all clean 2 | 3 | languages = C C++11 C++14 C++14_boost C++17 C++98 \ 4 | Chicken CoffeeScript CoffeeScript_parallel \ 5 | CommonLisp_opt Crystal CSharp Cython \ 6 | D D_parallel Dart Erlang FreePascal \ 7 | Haskell Haskell_parallel \ 8 | Go Go_goroutine \ 9 | Java Nim NodeJS NodeJS_async NodeJS_cluster \ 10 | OCaml Racket Racket_parallel Typed_Racket Rust Rust_parallel \ 11 | Scala Vala ChezScheme Zig 12 | # OCaml_lwt 13 | 14 | all: $(languages) 15 | 16 | .PHONY: $(languages) 17 | $(languages): %: 18 | $(MAKE) -C $* 19 | 20 | clean: 21 | for d in $(languages); do $(MAKE) clean -C "$$d"; done 22 | 23 | maketime: clean 24 | > $@ 25 | for d in $(languages); do time -f "%e $$d" -a -o $@ $(MAKE) -C "$$d"; done 26 | sort $@ -o $@ -t" " -k1 -n 27 | cat $@ 28 | -------------------------------------------------------------------------------- /benchmark/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "benchmark" 7 | version = "0.0.2" 8 | dependencies = [ 9 | "glob", 10 | "toml", 11 | ] 12 | 13 | [[package]] 14 | name = "glob" 15 | version = "0.3.0" 16 | source = "registry+https://github.com/rust-lang/crates.io-index" 17 | checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" 18 | 19 | [[package]] 20 | name = "serde" 21 | version = "1.0.127" 22 | source = "registry+https://github.com/rust-lang/crates.io-index" 23 | checksum = "f03b9878abf6d14e6779d3f24f07b2cfa90352cfec4acc5aab8f1ac7f146fae8" 24 | 25 | [[package]] 26 | name = "toml" 27 | version = "0.5.8" 28 | source = "registry+https://github.com/rust-lang/crates.io-index" 29 | checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa" 30 | dependencies = [ 31 | "serde", 32 | ] 33 | -------------------------------------------------------------------------------- /rankchange: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | import re 4 | import sys 5 | 6 | color_esc_re = re.compile(r'\x1b[\[0-9;]*[mK]') 7 | 8 | def get_rank(path): 9 | ret = {} 10 | with open(path) as f: 11 | for i, l in enumerate(f): 12 | l = color_esc_re.sub('', l) 13 | lang = l.split(None, 1)[0].strip() 14 | ret[lang] = i 15 | return ret 16 | 17 | def show_changes(a, b): 18 | for lang, cur_rank in b.items(): 19 | old_rank = a.get(lang) 20 | if not old_rank: 21 | change = '*' 22 | elif cur_rank < old_rank: 23 | change = f'↑ {old_rank - cur_rank}' 24 | elif cur_rank > old_rank: 25 | change = f'↓ {cur_rank - old_rank}' 26 | else: 27 | change = '=' 28 | print('%30s %-4s' % (lang, change)) 29 | 30 | def main(filea, fileb): 31 | a = get_rank(filea) 32 | b = get_rank(fileb) 33 | show_changes(a, b) 34 | 35 | if __name__ == '__main__': 36 | main(sys.argv[1], sys.argv[2]) 37 | -------------------------------------------------------------------------------- /PowerShell/swapview.ps1: -------------------------------------------------------------------------------- 1 | #!/usr/bin/pwsh -nop 2 | 3 | $ErrorActionPreference= 'SilentlyContinue' 4 | 5 | function FileSize($size) { 6 | if ($size -gt 1GB) { 7 | "{0}GiB" -f [Math]::Round($size / 1GB, 1) 8 | } elseif ($size -gt 1MB) { 9 | "{0}MiB" -f [Math]::Round($size / 1MB, 1) 10 | } else { 11 | "{0}KiB" -f [Math]::Round($size / 1KB, 1) 12 | } 13 | } 14 | 15 | function GetSwapFor($_pid) { 16 | $sum = ForEach-Object -InputObject (Select-String -Path /proc/$_pid/smaps -Pattern "(?<=Swap: +)\d+") { $_.Matches.Value } | Measure-Object -Sum 17 | $sum.Sum * 1KB 18 | } 19 | 20 | $total = 0 21 | 22 | Get-ChildItem /proc | Where-Object { $_.Name -match '^[0-9]+$' } | ForEach-Object { 23 | $cmd = Get-Content -Path /proc/$($_.Name)/cmdline 24 | if ($cmd -eq $null) { 25 | return 26 | } 27 | $size = GetSwapFor $_.Name 28 | 29 | $total += $size 30 | [PSCustomObject]@{ 31 | "Pid" = $_.Name 32 | "Size" = $size 33 | "Cmd" = $cmd 34 | } 35 | } | Sort-Object -Property Size | ForEach-Object { 36 | Write-Output ("{0,7} {1,9} {2}" -f $_.Pid, (FileSize $_.Size), $_.Cmd) 37 | } 38 | 39 | Write-Output ("Total: {0,10}" -f (FileSize $total)) 40 | -------------------------------------------------------------------------------- /Ruby/swapview.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | # for Ruby 2.4+ 5 | 6 | FORMAT = '%7s %9s %s' 7 | TOTALFMT = 'Total: %10s' 8 | 9 | UNITS = %w[B KiB MiB GiB TiB].freeze 10 | def filesize(size) 11 | left = size.abs 12 | num, unit = UNITS.each_with_index do |_, i| 13 | l = left / 1024.0**i 14 | break l, i if (l <= 1100) || (i == UNITS.length - 1) 15 | end 16 | return "#{size}B" if unit.zero? 17 | 18 | format('%.1f%s', size.negative? ? -num : num, UNITS[unit]) 19 | end 20 | 21 | def get_swap_for(pid) 22 | comm = File.read("/proc/#{pid}/cmdline").chomp("\0").tr("\0", ' ') 23 | s = File.read("/proc/#{pid}/smaps").split("\n") 24 | .select { |l| l.start_with? 'Swap: ' } 25 | .map { |l| l[6..-1].to_i } 26 | .sum.to_i 27 | [s * 1024, pid, comm] 28 | rescue StandardError 29 | [0, pid, nil] 30 | end 31 | 32 | def get_swap 33 | Dir.entries('/proc') 34 | .map { |dir| get_swap_for dir unless dir.to_i.zero? } 35 | .select { |s| s&.first&.positive? } 36 | .sort_by(&:first) 37 | end 38 | 39 | results = get_swap 40 | puts format(FORMAT, 'PID', 'SWAP', 'COMMAND') 41 | results.each do |(swap, pid, comm)| 42 | puts format(FORMAT, pid, filesize(swap), comm) 43 | end 44 | t = results.map(&:first).sum.to_i 45 | puts TOTALFMT % filesize(t) 46 | -------------------------------------------------------------------------------- /Python3_bytes/swapview.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import os 4 | 5 | format = "%7s %9s %s" 6 | totalFmt = "Total: %10s" 7 | 8 | def filesize(size): 9 | units = 'KMGT' 10 | left = abs(size) 11 | unit = -1 12 | while left > 1100 and unit < 3: 13 | left = left / 1024 14 | unit += 1 15 | if unit == -1: 16 | return '%dB' % size 17 | else: 18 | if size < 0: 19 | left = -left 20 | return '%.1f%siB' % (left, units[unit]) 21 | 22 | def getSwapFor(pid): 23 | try: 24 | comm = open('/proc/%s/cmdline' % pid, 'rb').read() 25 | if comm.endswith(b'\x00'): 26 | comm = comm[:-1] 27 | comm = comm.replace(b'\x00', b' ') 28 | with open('/proc/%s/smaps' % pid, 'rb') as f: 29 | s = sum(int(l.split()[1].decode()) for l in f if l.startswith(b'Swap:')) 30 | return pid, s * 1024, comm.decode() 31 | except (IOError, OSError): 32 | return pid, 0, '' 33 | 34 | def getSwap(): 35 | ret = [] 36 | for pid in os.listdir('/proc'): 37 | if pid.isdigit(): 38 | s = getSwapFor(pid) 39 | if s[1] > 0: 40 | ret.append(s) 41 | ret.sort(key=lambda x: x[1]) 42 | return ret 43 | 44 | def main(): 45 | results = getSwap() 46 | print(format % ('PID', 'SWAP', 'COMMAND')) 47 | for pid, swap, comm in results: 48 | print(format % (pid, filesize(swap), comm)) 49 | t = filesize(sum(x[1] for x in results)) 50 | print(totalFmt % t) 51 | 52 | if __name__ == '__main__': 53 | main() 54 | -------------------------------------------------------------------------------- /Ruby_ractor/swapview.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | # for Ruby 3+ 5 | 6 | FORMAT = '%7s %9s %s' 7 | TOTALFMT = 'Total: %10s' 8 | 9 | UNITS = %w[B KiB MiB GiB TiB].freeze 10 | def filesize(size) 11 | left = size.abs 12 | num, unit = UNITS.each_with_index do |_, i| 13 | l = left / 1024.0**i 14 | break l, i if (l <= 1100) || (i == UNITS.length - 1) 15 | end 16 | return "#{size}B" if unit.zero? 17 | 18 | format('%.1f%s', size.negative? ? -num : num, UNITS[unit]) 19 | end 20 | 21 | def get_swap_for(pid) 22 | comm = File.read("/proc/#{pid}/cmdline").chomp("\0").tr("\0", ' ') 23 | s = File.read("/proc/#{pid}/smaps").split("\n") 24 | .select { |l| l.start_with? 'Swap: ' } 25 | .map { |l| l[6..-1].to_i } 26 | .sum.to_i 27 | [s * 1024, pid, comm] 28 | rescue StandardError 29 | [0, pid, nil] 30 | end 31 | 32 | def get_swap 33 | ractors = [] 34 | Dir.entries('/proc') 35 | .map do |pid| 36 | ractors << Ractor.new(pid) do |pid| 37 | get_swap_for pid unless pid.to_i.zero? 38 | end 39 | end 40 | ractors.map(&:take) 41 | .select { |s| s&.first&.positive? } 42 | .sort_by(&:first) 43 | end 44 | 45 | results = get_swap 46 | puts format(FORMAT, 'PID', 'SWAP', 'COMMAND') 47 | results.each do |(swap, pid, comm)| 48 | puts format(FORMAT, pid, filesize(swap), comm) 49 | end 50 | t = results.map(&:first).sum.to_i 51 | puts TOTALFMT % filesize(t) 52 | -------------------------------------------------------------------------------- /Julia/swapview.jl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/julia 2 | 3 | using Printf 4 | 5 | function filesizeKB(size::Int) 6 | left = float(size) 7 | unit = 1 8 | while left > 1100 && unit < 4 9 | left /= 1024 10 | unit += 1 11 | end 12 | @inbounds u = ("KMGT")[unit] 13 | @sprintf("%.1f%siB", left, u)::AbstractString 14 | end 15 | 16 | function getSwapFor(pid::AbstractString) 17 | s::Int = 0 18 | for m in eachmatch(r"Swap: *([0-9]*)", read("/proc/$pid/smaps", String)) 19 | s += parse(Int, m.captures[1]) 20 | end 21 | s 22 | end 23 | 24 | function getCmd(pid::AbstractString) 25 | comm::String = read("/proc/$pid/cmdline", String) 26 | !isempty(comm) && comm[end] == '\x00' && (comm = comm[1:end - 1]) 27 | return replace(comm, "\x00" => " ") 28 | end 29 | 30 | function getSwap() 31 | ret = Any[] 32 | @inbounds for f in readdir("/proc") 33 | all(isdigit, f) && try 34 | s = getSwapFor(f) 35 | s > 0 && push!(ret, (f, s, getCmd(f))) 36 | catch 37 | end 38 | end 39 | sort!(ret, by=(x) -> x[2]) 40 | return ret 41 | end 42 | 43 | function main() 44 | results = getSwap() 45 | @printf("%7s %9s %s\n", "PID", "SWAP", "COMMAND") 46 | totalsize = 0 47 | @inbounds for (pid, swap, comm) in results 48 | @printf("%7s %9s %s\n", pid, filesizeKB(swap), comm) 49 | end 50 | @printf("Total: %10s\n", isempty(results) ? "0B" : 51 | filesizeKB(sum((x) -> x[2], results))) 52 | end 53 | 54 | main() 55 | -------------------------------------------------------------------------------- /Tcl/swapview.tcl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env tclsh 2 | 3 | proc fileSize {bytes {level 0}} { 4 | set units {B KiB MiB GiB} 5 | if {$bytes >= 1100 && $level < 3} { 6 | return [fileSize [expr $bytes/1024.0] [expr $level+1]] 7 | } 8 | if {$level == 0} { 9 | return [format "%dB" $bytes] 10 | } else { 11 | return [format "%.1lf%s" $bytes [lindex $units $level]] 12 | } 13 | } 14 | 15 | proc readFile {path} { 16 | set fd [open $path] 17 | set contents [read $fd] 18 | close $fd 19 | return $contents 20 | } 21 | 22 | proc getSwapInfo {pid} { 23 | # return {pid swap-use cmdline} 24 | if {![string is digit $pid]} {error error} 25 | set cmdline [string trim [string map {\0 " "} [readFile "/proc/$pid/cmdline"]]] 26 | set fd [open "/proc/$pid/smaps"] 27 | set totalswap 0 28 | while {1} { 29 | if {[eof $fd]} break 30 | if {[scan [gets $fd] "Swap: %lld" swapuse]} { 31 | incr totalswap $swapuse 32 | } 33 | } 34 | close $fd 35 | return [list $pid [expr $totalswap*1024] $cmdline] 36 | } 37 | 38 | set total 0 39 | set all {} 40 | foreach pid [lmap dir [glob /proc/*] {file tail $dir}] { 41 | if {![catch {getSwapInfo $pid} info] && [llength $info] == 3 && [lindex $info 1] != 0} { 42 | lappend all $info 43 | incr total [lindex $info 1] 44 | } 45 | } 46 | puts [format "%7s %9s %s" PID SWAP COMMAND] 47 | foreach i [lsort -integer -index 1 $all] { 48 | puts [format "%7s %9s %s" [lindex $i 0] [fileSize [lindex $i 1]] [lindex $i 2]] 49 | } 50 | puts [format "Total: %10s" [fileSize $total]] 51 | 52 | -------------------------------------------------------------------------------- /Python/swapview.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | from __future__ import print_function 4 | from __future__ import division 5 | 6 | import os 7 | import re 8 | 9 | format = "%7s %9s %s" 10 | totalFmt = "Total: %10s" 11 | 12 | def filesize(size): 13 | units = 'KMGT' 14 | left = abs(size) 15 | unit = -1 16 | while left > 1100 and unit < 3: 17 | left /= 1024 18 | unit += 1 19 | if unit == -1: 20 | return '%dB' % size 21 | else: 22 | if size < 0: 23 | left = -left 24 | return '%.1f%siB' % (left, units[unit]) 25 | 26 | def getSwapFor(pid): 27 | try: 28 | comm = open('/proc/%s/cmdline' % pid).read() 29 | if comm and comm[-1] == '\x00': 30 | comm = comm[:-1] 31 | comm = comm.replace('\x00', ' ') 32 | with open('/proc/%s/smaps' % pid) as f: 33 | s = sum(int(m.group(1)) for m in 34 | re.finditer(r'\nSwap:\s+(\d+)', f.read())) 35 | return pid, s * 1024, comm 36 | except (IOError, OSError): 37 | return pid, 0, '' 38 | 39 | def getSwap(): 40 | ret = [] 41 | for pid in os.listdir('/proc'): 42 | if pid.isdigit(): 43 | s = getSwapFor(pid) 44 | if s[1] > 0: 45 | ret.append(s) 46 | ret.sort(key=lambda x: x[1]) 47 | return ret 48 | 49 | def main(): 50 | results = getSwap() 51 | print(format % ('PID', 'SWAP', 'COMMAND')) 52 | for pid, swap, comm in results: 53 | print(format % (pid, filesize(swap), comm)) 54 | t = filesize(sum(x[1] for x in results)) 55 | print(totalFmt % t) 56 | 57 | if __name__ == '__main__': 58 | main() 59 | -------------------------------------------------------------------------------- /Bash/swapview.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # globalized consts 3 | base=1024 4 | unit=(K M G T) nunit=4 # assert nunit == ${#unit[@]} 5 | filesize(){ 6 | local pos powed # int64, also declare -i 7 | declare -i size="$1" 8 | if ((size < 1100)); then 9 | printf '%s\n' "${size}B" 10 | return 11 | fi 12 | # See also ``base ** pow`` (bash) and ``base ^ pow`` (bc). 13 | # Should this be precomputed? 14 | for ((pos=0, powed=1024; size / powed > 1100 && pos < nunit; pos++, powed *= 1024)); do :; done 15 | printf '%.1f%siB\n' "$(bc <<< "scale=1; $size / ($powed)")" "${unit[pos]}" 16 | } 17 | 18 | getSwap(){ 19 | local sumfile=/tmp/sum.$$.$RANDOM 20 | cd /proc 21 | 22 | (declare -i sum=0; for pid in [0-9]*; do 23 | # FIXME: better if printf('%q ', read(/proc/$pid/cmdline).split(NUL)) 24 | # splitnul: https://stackoverflow.com/questions/8677546/ 25 | command=$(tr '\0' ' ' 2>/dev/null /dev/null 35 | ) && 36 | 37 | if (( swap > 0 )); then 38 | sum+=swap 39 | printf '%7s %9s %s\n' "$pid" "$(filesize $((swap*1024)))" "$command" 40 | fi || continue 41 | done; printf '%s\n' $((sum * 1024)) > $sumfile) | sort -k2 -h 42 | printf "Total: %10s\n" "$(filesize "$(<$sumfile)")" 43 | rm "$sumfile" 44 | } 45 | 46 | printf "%7s %9s %s\n" PID SWAP COMMAND 47 | getSwap 48 | -------------------------------------------------------------------------------- /Python_mp/swapview.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | from __future__ import print_function 4 | from __future__ import division 5 | 6 | from concurrent.futures import ProcessPoolExecutor 7 | import os 8 | 9 | format = "%7s %9s %s" 10 | totalFmt = "Total: %10s" 11 | 12 | def filesize(size): 13 | units = 'KMGT' 14 | left = abs(size) 15 | unit = -1 16 | while left > 1100 and unit < 3: 17 | left /= 1024 18 | unit += 1 19 | if unit == -1: 20 | return '%dB' % size 21 | else: 22 | if size < 0: 23 | left = -left 24 | return '%.1f%siB' % (left, units[unit]) 25 | 26 | def getSwapFor(pid): 27 | try: 28 | comm = open('/proc/%s/cmdline' % pid).read() 29 | if comm and comm[-1] == '\x00': 30 | comm = comm[:-1] 31 | comm = comm.replace('\x00', ' ') 32 | with open('/proc/%s/smaps' % pid) as f: 33 | s = sum(int(l.split()[1]) for l in f if l.startswith('Swap:')) 34 | return pid, s * 1024, comm 35 | except (IOError, OSError): 36 | return pid, 0, '' 37 | 38 | def getSwap(): 39 | futures = [] 40 | with ProcessPoolExecutor() as executor: 41 | for pid in os.listdir('/proc'): 42 | if pid.isdigit(): 43 | future = executor.submit(getSwapFor, pid) 44 | futures.append(future) 45 | 46 | ret = [] 47 | for future in futures: 48 | s = future.result() 49 | if s[1] > 0: 50 | ret.append(s) 51 | ret.sort(key=lambda x: x[1]) 52 | return ret 53 | 54 | def main(): 55 | results = getSwap() 56 | print(format % ('PID', 'SWAP', 'COMMAND')) 57 | for pid, swap, comm in results: 58 | print(format % (pid, filesize(swap), comm)) 59 | t = filesize(sum(x[1] for x in results)) 60 | print(totalFmt % t) 61 | 62 | if __name__ == '__main__': 63 | main() 64 | -------------------------------------------------------------------------------- /Crystal/common.cr: -------------------------------------------------------------------------------- 1 | module SwapView 2 | extend self 3 | 4 | FORMAT = "%7s %9s %s" 5 | TOTALFMT = "Total: %10s" 6 | SWAP = "Swap: " 7 | 8 | def filesize(size) 9 | units = %w(B KiB MiB GiB TiB) 10 | left = size.abs 11 | unit = 0 12 | num = 0 13 | units.each_with_index do |_, i| 14 | unit = i 15 | num = left / 1024.0 ** i 16 | break if num <= 1100 || i == units.size - 1 17 | end 18 | if unit == 0 19 | "#{size}B" 20 | else 21 | "%.1f%s" % [size < 0 ? -num : num, units[unit]] 22 | end 23 | end 24 | 25 | def get_pids 26 | pids = [] of Int32 27 | Dir.entries("/proc").each do |entry| 28 | pid = entry.to_i? 29 | if pid 30 | pids << pid 31 | end 32 | end 33 | pids 34 | end 35 | 36 | def get_swap_for(pid) 37 | comm = File.read("/proc/#{pid}/cmdline") 38 | comm = comm.rchop if comm != "" && comm[-1] == '\0' 39 | comm = comm.tr("\0", " ") 40 | result = File.read("/proc/#{pid}/smaps").split('\n') 41 | result.select! { |l| l.starts_with? SWAP } 42 | if result.empty? 43 | {pid, 0, nil} 44 | else 45 | res = result.map { |l| l[6..-3].to_i } 46 | s = res.reduce { |acc, i| acc + i } 47 | {pid, s * 1024, comm} 48 | end 49 | rescue File::AccessDeniedError | File::NotFoundError 50 | {pid, 0, nil} 51 | end 52 | 53 | def report(results) 54 | puts FORMAT % %w(PID SWAP COMMAND) 55 | results.each do |value| 56 | pid, swap, comm = value 57 | puts FORMAT % [pid, filesize(swap), comm] 58 | end 59 | res = results.map { |x| x[1] } 60 | if res.empty? 61 | t = 0 62 | else 63 | t = res.reduce { |acc, i| acc + i } 64 | end 65 | puts TOTALFMT % filesize(t) 66 | end 67 | end 68 | -------------------------------------------------------------------------------- /Bash_parallel/swapview.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Although the near-plain-bash one in bash looks more elegant, 4 | # the two implementations basically run at the same speed. 5 | function filesize(){ 6 | size=$1 7 | if ((size < 1100)) ; then 8 | echo "${size}B" 9 | return 10 | fi 11 | arr=($(bc -l <1100 && unit<3){ 15 | left /= 1024 16 | unit += 1 17 | } 18 | left 19 | unit 20 | EOF 21 | )) 22 | left=${arr[0]} 23 | unit=${arr[1]} 24 | units="KMGT" 25 | printf "%.1f%siB\n" "$left" "${units:$unit:1}" 26 | } 27 | 28 | function getSwapFor(){ 29 | pid=$1 30 | command=$(tr '\0' ' ' 2>/dev/null /dev/null 40 | ) 41 | [[ $? -ne 0 ]] && return 42 | 43 | if (( swap > 0 )); then 44 | fs=$(filesize $((swap*1024))) 45 | printf '%s\n' "$swap" >> "$sumfile" 46 | printf "%7s %9s %s\n" "$pid" "$fs" "$command" 47 | fi 48 | } 49 | 50 | function getSwap(){ 51 | sumfile=/tmp/sum$RAMDOM 52 | > $sumfile 53 | export -f getSwapFor 54 | export -f filesize 55 | export sumfile 56 | cd /proc 57 | parallel --jobs 400% --no-notice -I% "getSwapFor %" ::: [0-9]*/ | sort -k2 -h 58 | sumsize=$(paste -sd+ <$sumfile) 59 | if [[ ! $sumsize ]]; then 60 | sumsize=0 61 | fi 62 | total=$(filesize $(( $(echo "$sumsize" | bc) *1024))) 63 | printf "Total: %10s\n" "$total" 64 | rm "$sumfile" 65 | } 66 | 67 | printf "%7s %9s %s\n" PID SWAP COMMAND 68 | getSwap 69 | -------------------------------------------------------------------------------- /NodeJS/swapview.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | "use strict" 3 | const sprintf = require('sprintf-js').sprintf 4 | const fs = require("fs") 5 | 6 | function filesize(size) { 7 | const units = "KMGT" 8 | let left = size 9 | let unit = -1 10 | for (; left > 1100 && unit < 3; unit++) { 11 | left /= 1024 12 | } 13 | if (unit === -1) { 14 | return sprintf("%dB", size) 15 | } else { 16 | if (size < 0) left = -left 17 | return sprintf('%.1f%siB', left, units[unit]) 18 | } 19 | } 20 | 21 | function getSwapFor(pid){ 22 | try { 23 | let comm = fs.readFileSync(`/proc/${pid}/cmdline`, "utf-8") 24 | if(comm[comm.length-1] === '\0'){ 25 | comm = comm.slice(0, -1) 26 | } 27 | comm = comm.replace(/\0/g," ") 28 | let s = 0 29 | const smaps = fs.readFileSync(`/proc/${pid}/smaps`, "utf-8") 30 | const re = /\nSwap:\s+(\d+)/g 31 | let result 32 | while (result = re.exec(smaps)) { 33 | s += result[1] | 0 34 | } 35 | return [pid, s*1024, comm] 36 | } catch(e) { 37 | if(e.code === 'EACCES' || e.code === 'ENOENT') { 38 | return [pid, 0, ""] 39 | } else { 40 | throw e 41 | } 42 | } 43 | } 44 | 45 | function getSwap() { 46 | const ret = [] 47 | fs.readdirSync("/proc").forEach(spid => { 48 | const pid = spid | 0 49 | if (pid > 0) { 50 | const s = getSwapFor(pid) 51 | if (s[1] > 0) { 52 | ret.push(s) 53 | } 54 | } 55 | }) 56 | ret.sort((a, b) => a[1] - b[1]) 57 | return ret 58 | } 59 | 60 | const results = getSwap() 61 | console.log(sprintf("%7s %9s %s", "PID", "SWAP", "COMMAND")) 62 | let t = 0 63 | results.forEach(s => { 64 | console.log(sprintf("%7s %9s %s", s[0], filesize(s[1]), s[2])) 65 | t += s[1] 66 | }) 67 | 68 | console.log(sprintf("Total: %10s", filesize(t))) 69 | -------------------------------------------------------------------------------- /Scala/swapview.scala: -------------------------------------------------------------------------------- 1 | import java.io.File 2 | import scala.io.Source 3 | 4 | class SwapView(val pid: Int = 0, val size: Double = 0, val comm: String = "") { 5 | def filesize(size: Double): String = { 6 | val units = "KMGT" 7 | var left = Math.abs(size) 8 | var unit = -1 9 | 10 | while (left > 1100 && unit < 3) { 11 | left /= 1024 12 | unit += 1 13 | } 14 | 15 | if (unit == -1) f"${size.asInstanceOf[Int]}%dB" 16 | else if (size < 0) f"${-left}%.1f${units(unit)}%ciB" 17 | else f"${left}%.1f${units(unit)}%ciB" 18 | } 19 | 20 | def getSwapFor(pid: Int): SwapView = { 21 | try { 22 | val comm = Source.fromFile(f"/proc/${pid}%d/cmdline", "UTF-8").getLines.reduceLeft(_+_).replaceAll("\u0000" , " ").init 23 | var s = 0.0 24 | for (line <- Source.fromFile(f"/proc/${pid}%d/smaps", "UTF-8").getLines if line.startsWith("Swap:")) { 25 | var a = line split " " 26 | s += a(a.size - 2).toInt 27 | } 28 | new SwapView(pid, s*1024, comm) 29 | } catch { 30 | case e: Exception => new SwapView(pid, 0, "") 31 | } 32 | } 33 | 34 | def getSwap: List[SwapView] = { 35 | var ret = List[SwapView]() 36 | for (fpid <- (new File("/proc").listFiles)) { 37 | try { 38 | var pid = fpid.getName.toInt 39 | var s = getSwapFor(pid) 40 | if (s.size > 0) ret = s :: ret 41 | } catch { 42 | case e: NumberFormatException => () 43 | } // do nothing for parse error 44 | } 45 | ret.sortBy(_.size) 46 | } 47 | } 48 | 49 | object SwapView extends App { 50 | val swapview = new SwapView 51 | val results = swapview.getSwap 52 | printf("%7s %9s %s\n", "PID", "SWAP", "COMMAND") 53 | var x = 0.0 54 | for (res <- results) { 55 | printf("%7d %9s %s\n", res.pid, swapview.filesize(res.size), res.comm) 56 | x += res.size 57 | } 58 | printf("Total: %10s\n", swapview.filesize(x)) 59 | } 60 | -------------------------------------------------------------------------------- /Elixir/swapview.exs: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env elixir 2 | 3 | defmodule SwapView do 4 | defp filesize(size) when size < 1100, do: "#{size}B" 5 | defp filesize(size), do: filesize(size / 1024, ~w(KiB MiB GiB TiB)) 6 | defp filesize(size, [h]), do: "#{size |> Float.round(1)}#{h}" 7 | defp filesize(size, [h|_]) when size < 1100, do: "#{size |> Float.round(1)}#{h}" 8 | defp filesize(size, [_|t]), do: filesize(size / 1024, t) 9 | 10 | defp get_swap_for(pid) do 11 | try do 12 | comm = File.open!("/proc/#{pid}/cmdline", [:read], &IO.read(&1, :line)) 13 | comm = comm |> binary_part(0, byte_size(comm) - 1) |> String.replace(<<0>>, " ") 14 | s = File.stream!("/proc/#{pid}/smaps", [:read]) 15 | |> Stream.filter(&String.starts_with?(&1, "Swap:")) 16 | |> Stream.map(&(&1 |> String.split |> Enum.at(1) |> String.to_integer)) 17 | |> Enum.reduce(0, &+/2) 18 | {pid, s * 1024, comm} 19 | rescue 20 | _ -> 21 | {:err, pid} 22 | end 23 | end 24 | 25 | 26 | defp get_swap do 27 | File.ls!("/proc") 28 | |> Stream.filter(fn pid -> pid =~ ~r/^[0-9]+$/ end) 29 | |> Stream.map(fn(x) -> Task.async(fn -> get_swap_for(x) end) end) 30 | |> Stream.map(fn(x) -> Task.await(x) end) 31 | |> Stream.filter(fn {_, s, _} when s > 0 -> true; _ -> false end) 32 | |> Enum.sort(fn ({_, s1, _}, {_, s2, _}) -> s1 < s2 end) 33 | end 34 | 35 | defp format({pid, size, comm}) do 36 | IO.puts "#{pid |> String.pad_leading(7)} #{size |> String.pad_leading(9)} #{comm}" 37 | end 38 | 39 | def main do 40 | result = get_swap() 41 | format {"PID", "SWAP", "COMMAND"} 42 | result |> Enum.each(fn {pid, size, comm} -> 43 | format {pid, size |> filesize, comm} 44 | end) 45 | total = result |> Enum.map(fn {_, size, _} -> size end) |> Enum.sum |> filesize 46 | IO.puts "Total: #{total |> String.pad_leading(10)}" 47 | end 48 | end 49 | 50 | SwapView.main 51 | -------------------------------------------------------------------------------- /R/swapview.r: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env Rscript 2 | 3 | filesize <- function (size){ 4 | left = abs(size) 5 | unit = 0 6 | units = unlist(strsplit("KMGT","")) 7 | while ( left > 1100 && unit < 4){ 8 | left = left / 1024 9 | unit = unit + 1 10 | } 11 | ret = "" 12 | if( unit == 0 ){ 13 | sprintf("%dB", size) 14 | }else{ 15 | sprintf("%.1f%siB", left, units[unit]) 16 | } 17 | } 18 | 19 | getComm <- function (pid){ 20 | fcomm = file(sprintf('/proc/%d/cmdline', pid), "rb") 21 | on.exit(close(fcomm)) 22 | comm = NULL 23 | rawspace = charToRaw(" ") 24 | while(length(cbin <- readBin(fcomm, raw())) != 0){ 25 | comm = c(comm, if(cbin[1] == raw(1)) rawspace else cbin[1]) 26 | } 27 | comm = rawToChar(comm[1:length(comm) - (if(comm[length(comm)]==rawspace) 1 else 0)]) 28 | comm 29 | } 30 | 31 | getSize <- function(pid){ 32 | fsmaps = file(sprintf('/proc/%d/smaps', pid), "rb") 33 | on.exit(close(fsmaps)) 34 | smaps = readLines(fsmaps) 35 | sum(sapply(smaps[grepl("Swap:", smaps)], 36 | function(a) as.numeric(rev(unlist(strsplit(a, " ")[[1]]))[2])) 37 | )*1024 38 | } 39 | 40 | getSwapFor <- function(pid){ 41 | tryCatch(list(pid, getSize(pid), getComm(pid)), 42 | error=function(e) list(pid, 0, "")) 43 | } 44 | 45 | getSwap <- function(){ 46 | all = sapply(sapply(list.files("/proc", pattern="^[0-9]+$"), strtoi), getSwapFor) 47 | all = all[, all[2,] > 0] 48 | all = data.frame(pid=unlist(unname(all[1,])), 49 | size=unlist(unname(all[2,])), 50 | comm=unlist(unname(all[3,]))) 51 | if(length(all)>0){ 52 | all = all[order(all[,2]),] 53 | } 54 | all 55 | } 56 | 57 | result = getSwap() 58 | write(sprintf("%7s %9s %s", "PID", "SWAP", "COMMAND"), stdout()) 59 | t = 0 60 | for(i in 1:nrow(result)){ 61 | size = as.numeric(result[i,2]) 62 | if(length(size)>0){ 63 | write(sprintf("%7s %9s %s", result[i,1], filesize(size), result[i,3]), stdout()) 64 | t = t + size 65 | } 66 | } 67 | write(sprintf("Total: %10s", filesize(t)), stdout()) 68 | -------------------------------------------------------------------------------- /CoffeeScript/swapview.coffee: -------------------------------------------------------------------------------- 1 | #!/usr/bin/coffee 2 | "use strict" 3 | fs = require 'fs' 4 | denodeify = require 'denodeify' 5 | 6 | readdir = denodeify fs.readdir 7 | read = denodeify fs.readFile 8 | 9 | addString = (sum, line) -> sum + (Number (line.match /\d+/)[0]) 10 | addSecond = (sum, x) -> sum + x[1] 11 | 12 | formatSize = (acc, n) -> 13 | if (n > 1100) and (acc <= 3) 14 | then formatSize (acc + 1), (n /= 1024) 15 | else 16 | unit = 'KMGT'[acc] 17 | num = n.toFixed(1) 18 | "#{num}#{unit}iB" 19 | formatSize0 = (n) -> formatSize 0, n 20 | 21 | fillLength = (n, str) -> 22 | str.padStart n, ' ' 23 | 24 | readdir('/proc') 25 | .then (files) -> 26 | list = files 27 | .filter (file) -> file.match /\d+/ 28 | .map (file) -> 29 | (read "/proc/#{file}/smaps", 'ascii') 30 | .then (text) -> 31 | text.split('\n').filter (line) -> line[..4] is 'Swap:' 32 | .then (lines) -> 33 | (read "/proc/#{file}/cmdline", 'utf-8') 34 | .then (text) -> 35 | cmdline = text 36 | .replace(/\0$/, '') 37 | .replace(/\0/g, ' ') 38 | [file, lines, cmdline] 39 | .then null, (error) -> 40 | [file, [], ''] 41 | (Promise.all list) 42 | .then (res) -> 43 | out = res 44 | .filter (swapsize) -> swapsize[1].length > 0 45 | .map (procEntry) -> 46 | procEntry[1] = procEntry[1].reduce(addString, 0) 47 | procEntry 48 | .filter (procEntry) -> procEntry[1] > 0 49 | .sort (a, b) -> a[1] - b[1] 50 | prettyPrint out 51 | .then null, (error) -> 52 | console.error error.stack 53 | process.exit 1 54 | 55 | prettyPrint = (res) -> 56 | console.log [ 57 | fillLength 7, 'PID' 58 | fillLength 9, 'SWAP' 59 | 'COMMAND' 60 | ].join(' ') 61 | 62 | str = res 63 | .map (procEntry) -> 64 | [ 65 | fillLength 7, procEntry[0] 66 | fillLength 9, (formatSize0 procEntry[1]) 67 | procEntry[2] 68 | ].join(' ') 69 | .join('\n') 70 | console.log str 71 | 72 | console.log [ 73 | 'Total: ' 74 | fillLength 10, (formatSize0 (res.reduce addSecond, 0)) 75 | ].join('') 76 | -------------------------------------------------------------------------------- /NodeJS_async/swapview.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | "use strict" 3 | var sprintf = require('sprintf-js').sprintf; 4 | var fs = require("fs"); 5 | var async = require("async"); 6 | 7 | function filesize(size){ 8 | var units = "KMGT"; 9 | var left = Math.abs(size); 10 | var unit = -1; 11 | for(;left > 1100 && unit < 3;unit++){ 12 | left /= 1024; 13 | } 14 | if(unit == -1){ 15 | return sprintf("%dB", size); 16 | }else{ 17 | if(size<0) left= -left; 18 | return sprintf('%.1f%siB', left, units[unit]); 19 | } 20 | } 21 | 22 | 23 | function getSwapFor(pid, callback){ 24 | async.map(["cmdline", "smaps"], 25 | function(name, c){ 26 | fs.readFile("/proc/"+pid+"/"+name, "utf-8", c); 27 | }, 28 | function(err, results){ 29 | if(err){ 30 | callback(null, null); 31 | return; 32 | } 33 | var comm = results[0]; 34 | if(comm[comm.length-1] == '\0'){ 35 | comm = comm.substr(0, comm.length - 1) 36 | } 37 | comm = comm.replace(/\0/g, " "); 38 | var s=0.0; 39 | var smaps = results[1]; 40 | smaps.split(/\n/).forEach(function (l){ 41 | if(l.substr(0,5) == "Swap:"){ 42 | s += parseInt(l.split(/[ ]+/)[1]); 43 | } 44 | }); 45 | if(s>0){ 46 | callback(null, [pid, s*1024, comm]); 47 | }else{ 48 | callback(null, null); 49 | } 50 | }); 51 | } 52 | 53 | function getSwap(callback){ 54 | fs.readdir("/proc", function(err, data){ 55 | async.map(data, function(spid, callback){ 56 | var pid = parseInt(spid); 57 | if(pid > 0){ 58 | getSwapFor(pid, callback); 59 | }else{ 60 | callback(null, null); 61 | } 62 | }, function(err, results) { 63 | results = results.filter(function (x) {return x!=null;}); 64 | results.sort(function (a, b){return a[1] - b[1];}) 65 | callback(null, results); 66 | }); 67 | }); 68 | } 69 | 70 | getSwap(function(err, results){ 71 | console.log(sprintf("%7s %9s %s", "PID", "SWAP", "COMMAND")); 72 | var t=0.0; 73 | results.forEach(function (s){ 74 | console.log(sprintf("%7s %9s %s", s[0], filesize(s[1]), s[2])); 75 | t += s[1]; 76 | }); 77 | console.log(sprintf("Total: %10s", filesize(t))); 78 | }); 79 | -------------------------------------------------------------------------------- /PHP/swapview.php: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | 1100 && $unit < 3) { 11 | $left /= 1024; 12 | $unit++; 13 | } 14 | 15 | if ($unit === -1) { 16 | return sprintf("%dB", $size); 17 | } else { 18 | if ($size < 0) { 19 | $left = -1 * $left; 20 | } 21 | 22 | return sprintf('%.1f%siB', $left, $units[$unit]); 23 | } 24 | } 25 | 26 | 27 | function getSwapFor($pid) 28 | { 29 | $fallback = [$pid, 0, '']; 30 | $commFile = '/proc/' . $pid . '/cmdline'; 31 | if(!($comm = @file_get_contents($commFile))) { 32 | return $fallback; 33 | } 34 | if ("\0" == substr($comm, -1)) { 35 | $comm = substr($comm, 0, strlen($comm) - 1); 36 | } 37 | 38 | $comm = str_replace("\0", " ", $comm); 39 | $smapsFile = '/proc/' . $pid . '/smaps'; 40 | if (!($smaps = @file_get_contents($smapsFile))) { 41 | return $fallback; 42 | } 43 | 44 | $matchCount = preg_match_all('/\nSwap:\s+(\d+)/', $smaps, $matches); 45 | if (!$matchCount) { 46 | return $fallback; 47 | } else { 48 | $sum = array_sum($matches[1]); 49 | return array($pid, $sum * 1024, $comm); 50 | } 51 | } 52 | 53 | 54 | function getSwap() 55 | { 56 | $ret = []; 57 | $dirs = scandir('/proc'); 58 | foreach($dirs as $item) 59 | { 60 | $pid = intval($item); 61 | if($pid) 62 | { 63 | $swap = getSwapFor($pid); 64 | if($swap[1]) 65 | { 66 | $ret[] = $swap; 67 | } 68 | } 69 | } 70 | array_multisort(array_column($ret, 1), SORT_ASC, $ret); 71 | return $ret; 72 | } 73 | 74 | 75 | $results = getSwap(); 76 | printf("%7s %9s %s", "PID", "SWAP", "COMMAND" . PHP_EOL); 77 | 78 | $totalSize = 0; 79 | foreach ($results as $result) { 80 | printf("%7s %9s %s" . PHP_EOL, $result[0], renderSize($result[1]), $result[2]); 81 | $totalSize += $result[1]; 82 | } 83 | 84 | printf("Total: %10s" . PHP_EOL, renderSize($totalSize)); 85 | -------------------------------------------------------------------------------- /Dart/swapview.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | import 'package:path/path.dart'; 3 | 4 | class SwapInfo implements Comparable { 5 | String pid; 6 | int swap; 7 | String cmdline; 8 | 9 | SwapInfo(this.pid, this.swap, this.cmdline); 10 | int compareTo(SwapInfo other) => this.swap.compareTo(other.swap); 11 | } 12 | 13 | bool isDigit(String s) { 14 | return s.codeUnits.every((int element) => (element ^ 0x30) <= 9); 15 | } 16 | 17 | toHumanReadable(int size) { 18 | final units = "KMGT"; 19 | var unit = -1; 20 | var left = size * 1.0; 21 | while (left > 1100 && unit < 3) { 22 | left /= 1024; 23 | unit++; 24 | } 25 | if (unit == -1) { 26 | return "${size}B"; 27 | } else { 28 | return "${left.toStringAsFixed(1)}${units[unit]}iB"; 29 | } 30 | } 31 | 32 | getSwapFor(String pid) { 33 | var swap = 0; 34 | var cmdline = ''; 35 | final regex = new RegExp(r"Swap:\s+(\d+)"); 36 | try { 37 | cmdline = new File('/proc/${pid}/cmdline').readAsStringSync(); 38 | if (cmdline.endsWith('\x00')) 39 | cmdline = cmdline.substring(0, cmdline.length - 1); 40 | cmdline = cmdline.replaceAll('\x00', ' '); 41 | var smaps = new File('/proc/${pid}/smaps').readAsStringSync().split('\n'); 42 | for (String line in smaps.where((l) => l.startsWith('Swap:'))) { 43 | swap += int.parse(regex.firstMatch(line).group(1)); 44 | } 45 | } on FileSystemException { 46 | return new SwapInfo(pid, 0, ''); 47 | } 48 | return new SwapInfo(pid, swap * 1024, cmdline); 49 | } 50 | 51 | main() { 52 | var procDir = new Directory('/proc'); 53 | var processes = procDir.listSync(); 54 | var total = 0; 55 | var results = new List.from(processes 56 | .map((fse) => basename(fse.path)) 57 | .where((pid) => isDigit(pid)) 58 | .map((pid) => getSwapFor(pid)) 59 | .where((info) => info.swap != 0)); 60 | results.sort(); 61 | 62 | print("${"PID".padLeft(7)} ${"SWAP".padLeft(9)} COMMAND"); 63 | for (SwapInfo result in results) { 64 | total += result.swap; 65 | print( 66 | "${result.pid.padLeft(7)} ${toHumanReadable(result.swap).padLeft(9)} ${result.cmdline}"); 67 | } 68 | print("Total: ${toHumanReadable(total).padLeft(10)}"); 69 | } 70 | -------------------------------------------------------------------------------- /Nim/swapview.nim: -------------------------------------------------------------------------------- 1 | import os, strutils, pegs, algorithm 2 | 3 | type 4 | swap_info = tuple[pid: int, swap: float, cmd: string] 5 | 6 | const TARGET = "Swap:" 7 | const units = "KMGT" 8 | 9 | proc filesize(size: float): string = 10 | var unit = -1 11 | var left = abs(size) 12 | 13 | while left > 1100 and unit < 3: 14 | left /= 1024 15 | unit += 1 16 | if unit == -1: return $int(size) & "B" 17 | 18 | if size < 0: 19 | left = -left 20 | return formatFloat(left, ffDecimal, 1) & units[unit] & "iB" 21 | 22 | proc get_swap_for(pid: int): swap_info = 23 | var cmdfs: File 24 | var str: string = "" 25 | 26 | result = (pid, 0.0, "") 27 | if not open(cmdfs, "/proc/" & $pid & "/cmdline"): 28 | return 29 | if readLine(cmdfs, result.cmd): 30 | var i = 0 31 | while i < result.cmd.len: 32 | if result.cmd[i] == '\0': result.cmd[i] = ' ' 33 | inc(i) 34 | delete(result.cmd, i, i) 35 | close(cmdfs) 36 | 37 | var smapsfs: File 38 | if open(smapsfs, "/proc/" & $pid & "/smaps"): 39 | while readLine(smapsfs, str): 40 | # it'll be too slow with pegs 41 | if startsWith(str, TARGET): 42 | var r = @[""] 43 | if match(str, peg"@' '+ {[0-9]+}", r): 44 | result.swap += parseFloat(r[0]) 45 | close(smapsfs) 46 | result.swap *= 1024.0 47 | 48 | proc get_swap(): seq[swap_info] = 49 | result = @[] 50 | for s in walkDirs("/proc/*"): 51 | var tail = splitPath(s).tail 52 | if allCharsInSet(tail, Digits): 53 | var pid = parseInt(tail) 54 | var si = get_swap_for(pid) 55 | if si.swap > 0: 56 | result.add(si) 57 | 58 | result.sort(proc (x, y: swap_info): int = cmp(x.swap, y.swap)) 59 | 60 | proc `$` (x: swap_info): string = 61 | var pidstr = $x.pid 62 | var swapstr = filesize(x.swap) 63 | spaces(max(0, 7 - pidstr.len)) & pidstr & " " & 64 | spaces(max(0, 9 - swapstr.len)) & swapstr & " " & x.cmd 65 | 66 | # main 67 | echo " PID SWAP COMMAND" 68 | var infos = get_swap() 69 | var t: float = 0 70 | for i in infos: 71 | echo i 72 | t += i.swap 73 | var total = filesize(t) 74 | echo "Total: " & spaces(max(0, 10 - total.len)) & total 75 | -------------------------------------------------------------------------------- /Cython/swapview.pyx: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # cython: language_level=3 4 | 5 | from __future__ import print_function 6 | from __future__ import division 7 | 8 | from libc.stdio cimport fopen, getline, fclose, FILE 9 | from libc.stdlib cimport atoi 10 | from libc.string cimport strncmp, memmove 11 | import os 12 | 13 | format = "%7s %9s %s" 14 | totalFmt = "Total: %10s" 15 | 16 | cdef int find_size(char *s): 17 | cdef char *s_tmp = s + 5 18 | while s_tmp[0] == b' ': 19 | s_tmp += 1 20 | memmove(s, s_tmp, s_tmp - s) 21 | s = s_tmp 22 | while s_tmp[0] != b' ': 23 | s_tmp += 1 24 | s_tmp[0] = 0 25 | return atoi(s) 26 | 27 | def filesize(size_t size): 28 | cdef int unit 29 | cdef float left 30 | 31 | units = 'KMGT' 32 | left = abs(size) 33 | unit = -1 34 | while left > 1100 and unit < 3: 35 | left /= 1024 36 | unit += 1 37 | if unit == -1: 38 | return '%dB' % size 39 | else: 40 | if size < 0: 41 | left = -left 42 | return '%.1f%siB' % (left, units[unit]) 43 | 44 | def getSwapFor(int pid): 45 | cdef int s = 0 46 | cdef char * line = NULL 47 | cdef size_t l = 0 48 | cdef FILE* cfile 49 | cdef ssize_t read 50 | 51 | try: 52 | comm = open('/proc/%d/cmdline' % pid).read() 53 | if comm and comm[-1] == '\x00': 54 | comm = comm[:-1] 55 | comm = comm.replace('\x00', ' ') 56 | 57 | cfile = fopen(b'/proc/%d/smaps' % pid, 'rb') 58 | if cfile == NULL: 59 | raise IOError 60 | 61 | while True: 62 | read = getline(&line, &l, cfile) 63 | if read == -1: 64 | break 65 | if strncmp(line, b'Swap:', 5) == 0: 66 | s += find_size(line) 67 | fclose(cfile) 68 | return pid, s * 1024, comm 69 | except (IOError, OSError): 70 | return pid, 0, '' 71 | 72 | def getSwap(): 73 | ret = [] 74 | for pid in os.listdir('/proc'): 75 | if pid.isdigit(): 76 | s = getSwapFor(int(pid)) 77 | if s[1] > 0: 78 | ret.append(s) 79 | ret.sort(key=lambda x: x[1]) 80 | return ret 81 | 82 | def main(): 83 | cdef int pid, swap 84 | 85 | results = getSwap() 86 | print(format % ('PID', 'SWAP', 'COMMAND')) 87 | for pid, swap, comm in results: 88 | print(format % (pid, filesize(swap), comm)) 89 | t = filesize(sum(x[1] for x in results)) 90 | print(totalFmt % t) 91 | 92 | main() 93 | -------------------------------------------------------------------------------- /Java/SwapView.java: -------------------------------------------------------------------------------- 1 | import java.util.*; 2 | import java.math.*; 3 | import java.nio.charset.*; 4 | import java.nio.file.*; 5 | import java.io.*; 6 | 7 | public class SwapView{ 8 | public int pid; 9 | public double size; 10 | public String comm; 11 | public SwapView(int p, double s, String c){ pid = p; size = s; comm = c; } 12 | 13 | public static String filesize(double size){ 14 | String units = "KMGT"; 15 | double left = Math.abs(size); 16 | int unit = -1; 17 | while(left > 1100 && unit < 3){ 18 | left /= 1024; 19 | unit++; 20 | } 21 | if(unit == -1){ 22 | return String.format("%dB", (int)size); 23 | }else{ 24 | if(size < 0) left = -left; 25 | return String.format("%.1f%ciB", left, units.charAt(unit)); 26 | } 27 | } 28 | 29 | public static SwapView getSwapFor(int pid){ 30 | try{ 31 | String comm = new String(Files.readAllBytes( 32 | Paths.get(String.format("/proc/%d/cmdline", pid))), 33 | StandardCharsets.UTF_8); 34 | comm = comm.replace('\0',' '); 35 | if(comm.charAt(comm.length() - 1) == ' ') 36 | comm = comm.substring(0, comm.length() - 1); 37 | double s = 0; 38 | for(String l: Files.readAllLines( 39 | Paths.get(String.format("/proc/%d/smaps", pid)), 40 | StandardCharsets.UTF_8)){ 41 | if(l.startsWith("Swap:")){ 42 | String[] a=l.split(" "); 43 | s += Integer.parseInt(a[a.length-2]); 44 | } 45 | } 46 | return new SwapView(pid, s*1024, comm); 47 | }catch(Exception e){ 48 | return new SwapView(pid, 0, ""); 49 | } 50 | } 51 | 52 | public static List getSwap(){ 53 | List ret= new ArrayList<>(); 54 | for(File fpid: new File("/proc").listFiles()){ 55 | try{ 56 | int pid = Integer.parseInt(fpid.getName()); 57 | SwapView s = getSwapFor(pid); 58 | if(s.size > 0) ret.add(s); 59 | }catch(NumberFormatException e){} // do nothing for parse error 60 | } 61 | ret.sort((a, b) -> Double.compare(a.size, b.size)); 62 | return ret; 63 | } 64 | 65 | public static void main (String [] argv){ 66 | List results = getSwap(); 67 | System.out.printf("%7s %9s %s\n", "PID", "SWAP", "COMMAND"); 68 | double t=0.0; 69 | for(SwapView s: results){ 70 | System.out.printf("%7d %9s %s\n", s.pid, filesize(s.size), s.comm); 71 | t += s.size; 72 | } 73 | System.out.printf("Total: %10s\n", filesize(t)); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /CoffeeScript_parallel/swapview.coffee: -------------------------------------------------------------------------------- 1 | #!/usr/bin/coffee 2 | # This version decouples the smap and cmdline reading into two independent 3 | # sets of promises. No threads are involved. 4 | "use strict" 5 | fs = require 'fs' 6 | denodeify = require 'denodeify' 7 | 8 | readdir = denodeify fs.readdir 9 | read = denodeify fs.readFile 10 | 11 | addString = (sum, line) -> sum + (Number (line.match /\d+/)[0]) 12 | addSecond = (sum, x) -> sum + x[1] 13 | 14 | formatSize = (acc, n) -> 15 | if (n > 1100) and (acc <= 3) 16 | then formatSize (acc + 1), (n /= 1024) 17 | else 18 | unit = 'KMGT'[acc] 19 | num = n.toFixed(1) 20 | "#{num}#{unit}iB" 21 | formatSize0 = (n) -> formatSize 0, n 22 | 23 | fillLength = (n, str) -> 24 | str.padStart n, ' ' 25 | 26 | readdir('/proc') 27 | .then (files) -> 28 | ###* 29 | * @type Promise pid, swapsize, cmdline 30 | ### 31 | list = files 32 | .filter (file) -> file.match /\d+/ 33 | .map (file) -> 34 | readSmaps = (read "/proc/#{file}/smaps", 'ascii') 35 | .then (text) -> 36 | text.split('\n').filter (line) -> line[..4] is 'Swap:' 37 | readCmdline = (read "/proc/#{file}/cmdline", 'utf-8') 38 | .then (text) -> 39 | cmdline = text 40 | .replace(/\0$/, '') 41 | .replace(/\0/g, ' ') 42 | cmdline 43 | (Promise.all [readSmaps, readCmdline]) 44 | .then (pair) -> 45 | [file].concat pair 46 | .then null, (error) -> 47 | [file, [], ''] 48 | (Promise.all list) 49 | .then (res) -> 50 | out = res 51 | .filter (swapsize) -> swapsize[1].length > 0 52 | .map (procEntry) -> 53 | procEntry[1] = procEntry[1].reduce(addString, 0) 54 | procEntry 55 | .filter (procEntry) -> procEntry[1] > 0 56 | .sort (a, b) -> a[1] - b[1] 57 | prettyPrint out 58 | .then null, (error) -> 59 | console.error error.stack 60 | process.exit 1 61 | 62 | prettyPrint = (res) -> 63 | console.log [ 64 | fillLength 7, 'PID' 65 | fillLength 9, 'SWAP' 66 | 'COMMAND' 67 | ].join(' ') 68 | 69 | str = res 70 | .map (procEntry) -> 71 | [ 72 | fillLength 7, procEntry[0] 73 | fillLength 9, (formatSize0 procEntry[1]) 74 | procEntry[2] 75 | ].join(' ') 76 | .join('\n') 77 | console.log str 78 | 79 | console.log [ 80 | 'Total: ' 81 | fillLength 10, (formatSize0 (res.reduce addSecond, 0)) 82 | ].join('') 83 | -------------------------------------------------------------------------------- /Guile/swapview.scm: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env guile 2 | !# 3 | (use-modules (ice-9 rdelim) 4 | (ice-9 ftw) 5 | (ice-9 futures) 6 | (srfi srfi-1)) 7 | (define get-string-all (@ (rnrs io ports) get-string-all)) 8 | 9 | (define G (ash 1 30)) 10 | (define M (ash 1 20)) 11 | (define K (ash 1 10)) 12 | (define (filesize size) 13 | (cond 14 | ((>= size G) 15 | (format #f "~,1fGiB" (/ size G))) 16 | ((>= size M) 17 | (format #f "~,1fMiB" (/ size M))) 18 | ((>= size K) 19 | (format #f "~,1fKiB" (/ size K))) 20 | (else (format #f "~aB" size)))) 21 | 22 | (define (getSwapFor pid) 23 | (define (getswapsize) 24 | (define smaps (format #f "/proc/~a/smaps" pid)) 25 | (define (getsize l) 26 | (and (string= (substring/shared l 0 5) "Swap:") 27 | (list->string (string-fold-right (lambda (x p) (if (char-numeric? x) (cons x p) p)) '() l)))) 28 | (when (not (file-exists? smaps)) (error "File doesn't exist!" smaps)) 29 | (call-with-input-file smaps 30 | (lambda (port) 31 | (let lp((line (read-line port)) (total 0)) 32 | (cond 33 | ((eof-object? line) total) 34 | ((getsize line) 35 | => (lambda (n) 36 | (lp (read-line port) (+ total (string->number n))))) 37 | (else (lp (read-line port) total))))))) 38 | (catch #t 39 | (lambda () 40 | (let ((c (call-with-input-file (format #f "/proc/~a/cmdline" pid) get-string-all)) 41 | (s (getswapsize))) 42 | (and s (> s 0) (list pid (ash s 10) c)))) 43 | (lambda (key . value) #f))) 44 | 45 | (define (getSwap) 46 | (sort! 47 | (filter-map touch (map! (lambda (x) (future (and=> (string->number x) getSwapFor))) (scandir "/proc"))) 48 | (lambda (a b) (< (cadr a) (cadr b))))) 49 | 50 | (define (main . args) 51 | (let ((results (getSwap)) 52 | (FORMATSTR "~7@a ~9@a ~@a~%")) 53 | (format #t FORMATSTR "PID" "SWAP" "COMMAND") 54 | (let lp((next results) (total 0)) 55 | (cond 56 | ((null? next) (format #t "Total: ~10@a~%" (filesize total))) 57 | (else 58 | (let ((item (car next))) 59 | (format #t FORMATSTR 60 | (car item) 61 | (filesize (cadr item)) 62 | (caddr item)) 63 | (lp (cdr next) (+ total (cadr item))))))))) 64 | 65 | (main) 66 | -------------------------------------------------------------------------------- /Haskell_parallel/stack.yaml: -------------------------------------------------------------------------------- 1 | # This file was automatically generated by 'stack init' 2 | # 3 | # Some commonly used options have been documented as comments in this file. 4 | # For advanced use and comprehensive documentation of the format, please see: 5 | # https://docs.haskellstack.org/en/stable/yaml_configuration/ 6 | 7 | # Resolver to choose a 'specific' stackage snapshot or a compiler version. 8 | # A snapshot resolver dictates the compiler version and the set of packages 9 | # to be used for project dependencies. For example: 10 | # 11 | # resolver: lts-3.5 12 | # resolver: nightly-2015-09-21 13 | # resolver: ghc-7.10.2 14 | # 15 | # The location of a snapshot can be provided as a file or url. Stack assumes 16 | # a snapshot provided as a file might change, whereas a url resource does not. 17 | # 18 | # resolver: ./custom-snapshot.yaml 19 | # resolver: https://example.com/snapshots/2018-01-01.yaml 20 | resolver: lts-13.26 21 | 22 | # User packages to be built. 23 | # Various formats can be used as shown in the example below. 24 | # 25 | # packages: 26 | # - some-directory 27 | # - https://example.com/foo/bar/baz-0.0.2.tar.gz 28 | # - location: 29 | # git: https://github.com/commercialhaskell/stack.git 30 | # commit: e7b331f14bcffb8367cd58fbfc8b40ec7642100a 31 | # - location: https://github.com/commercialhaskell/stack/commit/e7b331f14bcffb8367cd58fbfc8b40ec7642100a 32 | # subdirs: 33 | # - auto-update 34 | # - wai 35 | packages: 36 | - . 37 | # Dependency packages to be pulled from upstream that are not in the resolver 38 | # using the same syntax as the packages field. 39 | # (e.g., acme-missiles-0.3) 40 | # extra-deps: [] 41 | 42 | # Override default flag values for local packages and extra-deps 43 | # flags: {} 44 | 45 | # Extra package databases containing global packages 46 | # extra-package-dbs: [] 47 | 48 | # Control whether we use the GHC we find on the path 49 | # system-ghc: true 50 | # 51 | # Require a specific version of stack, using version ranges 52 | # require-stack-version: -any # Default 53 | # require-stack-version: ">=1.9" 54 | # 55 | # Override the architecture used by stack, especially useful on Windows 56 | # arch: i386 57 | # arch: x86_64 58 | # 59 | # Extra directories used by stack for building 60 | # extra-include-dirs: [/path/to/dir] 61 | # extra-lib-dirs: [/path/to/dir] 62 | # 63 | # Allow a newer minor version of GHC than the snapshot specifies 64 | # compiler-check: newer-minor 65 | -------------------------------------------------------------------------------- /Lua/swapview.lua: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env lua 2 | 3 | require 'lfs' 4 | 5 | local format = string.format 6 | local nullstr 7 | 8 | -- http://www.freelists.org/post/luajit/BUG-stringgsub-is-not-8bit-pure,1 9 | if jit then 10 | nullstr = '%z' 11 | else 12 | nullstr = '\x00' 13 | end 14 | 15 | function filesize(size) 16 | local units = {'K', 'M', 'G', 'T'} 17 | local value = math.abs(size) 18 | local uint = 0 19 | while value > 1100 and uint < 4 do 20 | value = value / 1024 21 | uint = uint + 1 22 | end 23 | if uint == 0 then 24 | return format('%dB', size) 25 | else 26 | if size < 0 then 27 | value = -value 28 | end 29 | return format('%.1f%siB', value, units[uint]) 30 | end 31 | end 32 | 33 | function getSwapFor(pid) 34 | local open = io.open 35 | local swapfile = open(format('/proc/%s/smaps', pid), 'r') 36 | if not swapfile then return 0, '' end 37 | 38 | -- file:lines() fails when it doesn't have the permissions to read the file 39 | -- (but does have when opening the file, e.g. /proc/1/smaps) 40 | local ok, size = pcall(function() 41 | local size = 0 42 | for line in swapfile:lines() do 43 | if line:sub(1, 5) == 'Swap:' then 44 | size = size + tonumber(line:match('%d+')) 45 | end 46 | end 47 | return size 48 | end) 49 | swapfile:close() 50 | if not ok then return 0, '' end 51 | 52 | local cmdfile = open(format('/proc/%s/cmdline', pid), 'r') 53 | if not cmdfile then return 0, '' end 54 | 55 | local cmd = cmdfile:read('*a') 56 | cmdfile:close() 57 | if cmd and cmd:byte(#cmd) == 0 then 58 | cmd = cmd:sub(1, #cmd-1) 59 | end 60 | cmd = cmd:gsub(nullstr, ' ') 61 | 62 | return size * 1024, cmd 63 | end 64 | 65 | function getSwap() 66 | local ret = {} 67 | local insert = table.insert 68 | for pid in lfs.dir('/proc') do 69 | if tonumber(pid) then 70 | size, cmd = getSwapFor(pid) 71 | if size > 0 then 72 | insert(ret, {pid, size, cmd}) 73 | end 74 | end 75 | end 76 | table.sort(ret, function(a, b) 77 | return a[2] < b[2] 78 | end) 79 | return ret 80 | end 81 | 82 | local fmt = "%7s %9s %s" 83 | local totalFmt = "Total: %10s" 84 | local results = getSwap() 85 | local sum = 0 86 | print(format(fmt, 'PID', 'SWAP', 'COMMAND')) 87 | for _, v in ipairs(results) do 88 | print(format(fmt, v[1], filesize(v[2]), v[3])) 89 | sum = sum + v[2] 90 | end 91 | print(format(totalFmt, filesize(sum))) 92 | -------------------------------------------------------------------------------- /POSIX_shell/swapview.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | readonly PRINTF_FORMAT='%7s %9s %s\n' 3 | 4 | third_slash() { 5 | # let argv[1...] = argv[1].split(/\//g); puts argv[3]. 6 | local IFS=/ 7 | set -- $1 8 | printf %s "$3" 9 | } 10 | 11 | main() { 12 | printf "$PRINTF_FORMAT" 'PID' 'SWAP' 'COMMAND' 13 | find '/proc' -maxdepth 2 -regextype posix-basic -regex '^/proc/[[:digit:]]\+$' -type d -print 2>/dev/null | \ 14 | while read dir_path || [ -n "$dir_path" ] 15 | do 16 | # We had `find` check over the filename already. 17 | # So just chop it. 18 | local pid=$(third_slash "$dir_path") 19 | local smaps_file="${dir_path}/smaps" 20 | local cmdline_file="${dir_path}/cmdline" 21 | local swap_size=0 22 | local cmd='' 23 | 24 | swap_size="$(grep -F 'Swap:' "$smaps_file" 2>/dev/null | \ 25 | awk 'BEGIN{ sum = 0 } 26 | { sum += $2 } 27 | END{ print sum }')" || continue 28 | 29 | if [ $((swap_size == 0)) -eq 1 ] 30 | then 31 | continue 32 | fi 33 | 34 | cmd="$(tr '\0' ' ' < "$cmdline_file")" || continue 35 | printf "$PRINTF_FORMAT" "$pid" "$swap_size" "$cmd" 36 | done | sort -k2n | \ 37 | awk -v "printf_format=${PRINTF_FORMAT}" \ 38 | 'function convert_file_size_from_kB(size, _ARGV_END_, unit, units) { 39 | split("KMGT", units, "") 40 | unit=1 41 | while (size > 1100 && unit < 4) { 42 | size /= 1024 43 | unit += 1 44 | } 45 | return sprintf("%.1f%siB", size, units[unit]) 46 | } 47 | function join_field(start, end, sep, _ARGV_END_, i, str) { 48 | str=$start 49 | for (i = start+1; i <= end; i++) { 50 | str = str sep $i 51 | } 52 | return str 53 | } 54 | BEGIN{ 55 | total=0 56 | } 57 | { 58 | total += $2 59 | printf(printf_format, $1, convert_file_size_from_kB($2), join_field(3, NF, " ")) 60 | } 61 | END{ 62 | printf("Total: %10s\n", convert_file_size_from_kB(total)) 63 | }' 64 | } 65 | 66 | main "$@" 67 | -------------------------------------------------------------------------------- /CSharp/SwapView.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Collections.Generic; 4 | 5 | namespace SwapView 6 | { 7 | public struct SwapView: IComparable 8 | { 9 | public int pid; 10 | public double size; 11 | public string comm; 12 | 13 | public SwapView(int p, double s, string c) 14 | { 15 | pid = p; 16 | size = s; 17 | comm = c; 18 | } 19 | 20 | public int CompareTo(SwapView s) 21 | { 22 | return size.CompareTo (s.size); 23 | } 24 | } 25 | 26 | class MainClass 27 | { 28 | public static string filesize(double size) 29 | { 30 | string units = "KMGT"; 31 | double left = Math.Abs (size); 32 | int unit = -1; 33 | while(left > 1100 && unit < 3){ 34 | left /= 1024; 35 | unit++; 36 | } 37 | if(unit == -1){ 38 | return String.Format ("{0:D}B", (int)size); 39 | }else{ 40 | if(size < 0) left = -left; 41 | return String.Format ("{0:F1}{1:C}iB", left, units[unit]); 42 | } 43 | } 44 | 45 | public static SwapView getSwapFor(int pid) 46 | { 47 | try{ 48 | string comm = File.ReadAllText (String.Format ("/proc/{0:D}/cmdline", pid)); 49 | comm = comm.Replace('\0',' '); 50 | if(comm[comm.Length - 1] == ' ') 51 | comm = comm.Substring(0, comm.Length - 1); 52 | double s = 0; 53 | foreach(string l in File.ReadLines (String.Format ("/proc/{0:D}/smaps", pid))){ 54 | if(l.StartsWith("Swap:")){ 55 | string[] a=l.Split(' '); 56 | s += int.Parse(a[a.Length-2]); 57 | } 58 | } 59 | return new SwapView(pid, s*1024, comm); 60 | }catch(Exception){ 61 | return new SwapView(pid, 0, ""); 62 | } 63 | } 64 | 65 | public static IList getSwap() 66 | { 67 | List ret = new List(); 68 | foreach(string fpid in Directory.EnumerateDirectories ("/proc/")){ 69 | int pid; 70 | if(int.TryParse(fpid.Substring (6), out pid)){ 71 | SwapView s = getSwapFor (pid); 72 | if(s.size > 0) ret.Add (s); 73 | } 74 | } 75 | ret.Sort (); 76 | return ret; 77 | } 78 | 79 | public static void Main (string[] args) 80 | { 81 | IList results = getSwap (); 82 | Console.WriteLine ("{0,7} {1,9} {2}", "PID", "SWAP", "COMMAND"); 83 | double t=0.0; 84 | foreach(SwapView s in results){ 85 | Console.WriteLine ("{0,7:D} {1,9} {2}", s.pid, filesize (s.size), s.comm); 86 | t += s.size; 87 | } 88 | Console.WriteLine ("Total: {0,10}", filesize (t)); 89 | } 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /C++14_boost/swapview.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | using namespace std; 13 | 14 | constexpr const char * TARGET = "Swap:"; 15 | constexpr size_t TARGETLEN = 5; 16 | 17 | using swap_info = tuple; 18 | 19 | auto filesize(double size) { 20 | constexpr const char * units = "KMGT"; 21 | auto left = abs(size); 22 | int unit = -1; 23 | while( left > 1100 && unit < 3 ){ 24 | left /= 1024; 25 | unit++; 26 | } 27 | return (unit == -1) ? boost::format("%dB") % size 28 | : boost::format("%|.1f|%||iB") % (size > 0 ? left : -left) % units[unit]; 29 | } 30 | 31 | swap_info getSwapFor(int pid){ 32 | ifstream cmd_inf("/proc/" + to_string(pid) + "/cmdline"); 33 | string comm((istreambuf_iterator(cmd_inf)), istreambuf_iterator()); 34 | if(!comm.empty()) { 35 | if(comm.back() == 0) comm.pop_back(); 36 | replace(comm.begin(), comm.end(), '\0' , ' '); 37 | } 38 | double s=0.0; 39 | ifstream inf("/proc/" + to_string(pid) + "/smaps"); 40 | string l; 41 | while(getline(inf, l)) 42 | if(boost::starts_with(l, TARGET)) 43 | s += strtol(l.c_str() + TARGETLEN, nullptr, 10); 44 | return make_tuple(pid, s*1024.0, comm); 45 | } 46 | 47 | vector getSwap() { 48 | vector ret; 49 | for(auto const& entry : boost::make_iterator_range(boost::filesystem::directory_iterator("/proc"), boost::filesystem::directory_iterator())) 50 | if(int pid = strtol(entry.path().filename().c_str(), nullptr, 10)) { 51 | auto item = getSwapFor(pid); 52 | if(get<1>(item) > 0) 53 | ret.push_back(item); 54 | } 55 | sort(ret.begin(), ret.end(), [](auto const& i, auto const& j){return get<1>(i) < get<1>(j);}); 56 | return ret; 57 | } 58 | 59 | int main(int argc, char * argv[]){ 60 | std::ios::sync_with_stdio(false); 61 | boost::format format("%|7| %|9| %||"); 62 | cout << format % "PID" % "SWAP" % "COMMAND" << "\n"; 63 | double t=0.0; 64 | for(auto const& item: getSwap()){ 65 | cout << format % get<0>(item) % filesize(get<1>(item)) % get<2>(item) << "\n"; 66 | t+=get<1>(item); 67 | } 68 | cout<< boost::format("Total: %|10|") % filesize(t)<<"\n"; 69 | return 0; 70 | } 71 | -------------------------------------------------------------------------------- /Vala/swapview.vala: -------------------------------------------------------------------------------- 1 | string filesize(double size){ 2 | string units = "KMGT"; 3 | double left = Math.fabs(size); 4 | int unit = -1; 5 | while(left > 1100 && unit < 3){ 6 | left /= 1024; 7 | unit++; 8 | } 9 | if(unit == -1){ 10 | return "%dB".printf((int)size); 11 | }else{ 12 | if(size < 0) left = -left; 13 | return "%.1f%ciB".printf(left, units[unit]); 14 | } 15 | } 16 | 17 | struct SwapView{ 18 | int64 pid; 19 | double size; 20 | string comm; 21 | } 22 | 23 | SwapView getSwapFor(int64 pid){ 24 | try{ 25 | DataInputStream dis = new DataInputStream( 26 | File.new_for_path(@"/proc/$(pid)/cmdline").read()); 27 | size_t len; 28 | string? comm = dis.read_upto("", 0,out len); 29 | if(comm!=null) 30 | for(int i=0; i getSwap(){ 49 | List ret = new List(); 50 | try{ 51 | FileEnumerator enumerator = File.new_for_path("/proc/") 52 | .enumerate_children("standard::*", FileQueryInfoFlags.NONE); 53 | FileInfo fpid; 54 | while((fpid = enumerator.next_file()) != null){ 55 | int64 pid = 0; 56 | if(fpid.get_file_type () == FileType.DIRECTORY && 57 | int64.try_parse(fpid.get_name(), out pid)){ 58 | SwapView s = getSwapFor(pid); 59 | if(s.size > 0) 60 | ret.append(s); 61 | } 62 | } 63 | }catch(Error e){} // do nothing for errors 64 | ret.sort((a, b) => (a.size < b.size) ? -1 : (a.size > b.size) ? 1 : 0); 65 | return ret; 66 | } 67 | 68 | static int main (string[] args){ 69 | List results = getSwap(); 70 | stdout.printf("%7s %9s %s\n", "PID", "SWAP", "COMMAND"); 71 | double t = 0.0; 72 | foreach(SwapView s in results){ 73 | stdout.printf("%7lld %9s %s\n", s.pid, filesize(s.size), s.comm); 74 | t += s.size; 75 | } 76 | stdout.printf("Total: %10s\n", filesize(t)); 77 | return 0; 78 | } 79 | -------------------------------------------------------------------------------- /C++17/swapview.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | using swap_info = std::tuple; 10 | 11 | auto starts_with(const std::string &self, const std::string &prefix) -> bool { 12 | return self.length() >= prefix.length() && 13 | std::equal(prefix.begin(), prefix.end(), self.begin()); 14 | } 15 | 16 | auto filesize(double size) -> std::string { 17 | constexpr char units[]{"KMGT"}; 18 | int unit = -1; 19 | for (; size > 1100 && unit < 3; ++unit) size /= 1024; 20 | if (unit == -1) 21 | return std::to_string(static_cast(size)) + 'B'; 22 | std::ostringstream oss; 23 | oss << std::fixed << std::setprecision(1) 24 | << size << units[unit] << "iB"; 25 | return oss.str(); 26 | } 27 | 28 | auto get_comm_for(const std::filesystem::path &p) -> std::string { 29 | std::ifstream file{p}; 30 | std::string buf{std::istreambuf_iterator{file}, {}}; 31 | if (!buf.empty() && buf.back() == '\0') buf.pop_back(); 32 | std::replace(buf.begin(), buf.end(), '\0', ' '); 33 | return buf; 34 | } 35 | 36 | auto get_swap_for(const std::filesystem::path &p) -> size_t { 37 | constexpr char TARGET[]{"Swap:"}; 38 | std::ifstream file{p}; 39 | std::string buf; 40 | size_t s = 0; 41 | while (getline(file, buf)) 42 | if (starts_with(buf, TARGET)) 43 | s += std::strtol(buf.c_str() + std::size(TARGET), nullptr, 10); 44 | return 1024 * s; 45 | } 46 | 47 | auto get_swap() -> std::vector { 48 | std::vector result; 49 | for (const auto &entry: std::filesystem::directory_iterator{"/proc"}) 50 | if (int pid = std::strtol(entry.path().filename().c_str(), nullptr, 10)) 51 | if (size_t swp = get_swap_for(entry.path() / "smaps")) 52 | result.emplace_back(pid, swp, get_comm_for(entry.path() / "cmdline")); 53 | std::sort(result.begin(), result.end(), [](const auto &lhs, const auto &rhs) { 54 | return std::get<1>(lhs) < std::get<1>(rhs); 55 | }); 56 | return result; 57 | } 58 | 59 | int main() { 60 | std::ios::sync_with_stdio(false); 61 | std::cout << std::setw(7) << "PID" << ' ' 62 | << std::setw(9) << "SWAP" << ' ' 63 | << std::setw(0) << "COMMAND" << '\n'; 64 | size_t total = 0; 65 | for (const auto &[pid, swp, cmd]: get_swap()) { 66 | std::cout << std::setw(7) << pid << ' ' 67 | << std::setw(9) << filesize(swp) << ' ' 68 | << std::setw(0) << cmd << '\n'; 69 | total += swp; 70 | } 71 | std::cout << "Total: " << std::setw(10) << filesize(total) << std::endl; 72 | } 73 | -------------------------------------------------------------------------------- /Rust/swapview.rs: -------------------------------------------------------------------------------- 1 | use std::fs::{File,read_dir}; 2 | use std::io::Read; 3 | 4 | const UNITS: [char; 4] = ['K', 'M', 'G', 'T']; 5 | 6 | fn filesize(size: isize) -> String { 7 | let mut left = size.abs() as f64; 8 | let mut unit = -1; 9 | 10 | while left > 1100. && unit < 3 { 11 | left /= 1024.; 12 | unit += 1; 13 | } 14 | if unit == -1 { 15 | format!("{}B", size) 16 | } else { 17 | if size < 0 { 18 | left = -left; 19 | } 20 | format!("{:.1}{}iB", left, UNITS[unit as usize]) 21 | } 22 | } 23 | 24 | fn chop_null(s: String) -> String { 25 | let last = s.len() - 1; 26 | let mut s = s; 27 | if !s.is_empty() && s.as_bytes()[last] == 0 { 28 | s.truncate(last); 29 | } 30 | s.replace("\0", " ") 31 | } 32 | 33 | fn get_comm_for(pid: usize) -> String { 34 | let cmdline_path = format!("/proc/{}/cmdline", pid); 35 | let mut buf = String::new(); 36 | let mut file = match File::open(&cmdline_path) { 37 | Ok(f) => f, 38 | Err(_) => return String::new(), 39 | }; 40 | match file.read_to_string(&mut buf) { 41 | Ok(_) => (), 42 | Err(_) => return String::new(), 43 | }; 44 | chop_null(buf) 45 | } 46 | 47 | fn get_swap_for(pid: usize) -> isize { 48 | let mut s = 0; 49 | let smaps_path = format!("/proc/{}/smaps", pid); 50 | let mut file = match File::open(&smaps_path) { 51 | Ok(f) => f, 52 | Err(_) => return 0, 53 | }; 54 | 55 | let mut vec = vec![]; 56 | file.read_to_end(&mut vec).unwrap(); 57 | for line in vec.split(|&c| c == b'\n') { 58 | if line.starts_with(b"Swap:") { 59 | let string = line[5..] 60 | .iter() 61 | .skip_while(|&&c| c == b' ') 62 | .take_while(|&&c| c != b' ') 63 | .map(|&c| c as char) 64 | .collect::(); 65 | s += string.parse::().unwrap(); 66 | } 67 | } 68 | s * 1024 69 | } 70 | 71 | fn get_swap() -> Vec<(usize, isize, String)> { 72 | read_dir("/proc").unwrap().filter_map(|d| { 73 | let path = d.unwrap().path(); 74 | path.file_name().unwrap().to_str().unwrap() 75 | .parse().ok().and_then(|pid| 76 | match get_swap_for(pid) { 77 | 0 => None, 78 | swap => Some((pid, swap, get_comm_for(pid))), 79 | } 80 | ) 81 | }).collect() 82 | } 83 | 84 | fn main() { 85 | let mut swapinfo = get_swap(); 86 | swapinfo.sort_unstable_by(|&(_, a, _), &(_, b, _)| { a.cmp(&b) }); 87 | 88 | println!("{:>7} {:>9} {}", "PID", "SWAP", "COMMAND"); 89 | let mut total = 0; 90 | for &(pid, swap, ref comm) in &swapinfo { 91 | total += swap; 92 | println!("{:>7} {:>9} {}", pid, filesize(swap), comm); 93 | } 94 | println!("Total: {:>10}", filesize(total)); 95 | } 96 | 97 | // vim: se sw=2: 98 | -------------------------------------------------------------------------------- /changes: -------------------------------------------------------------------------------- 1 | Rust_parallel: * 2 | C++98_omp: = 3 | Go_goroutine: = 4 | Crystal_process: * 5 | C++17: * 6 | C++98: = 7 | C++14: ↓ 3 8 | C++14_boost: ↓ 3 9 | C: ↓ 1 10 | Rust: ↓ 3 11 | PHP: ↓ 1 12 | Go: ↑ 6 13 | C++11: ↓ 4 14 | Cython: * 15 | Crystal: * 16 | Crystal_fiber: * 17 | Nim: ↓ 5 18 | OCaml: ↓ 7 19 | D_parallel: ↓ 5 20 | D_parallel_llvm: ↓ 7 21 | Python3_mp: * 22 | LuaJIT: ↓ 5 23 | D_llvm: ↓ 7 24 | Python2: ↓ 3 25 | D: ↓ 6 26 | Vala: ↓ 4 27 | NodeJS: ↑ 10 28 | PyPy: ↓ 13 29 | Lua51: ↓ 5 30 | Python3: = 31 | Python3_bytes: ↓ 5 32 | Lua52: ↓ 7 33 | Erlang: ↓ 10 34 | Lua53: ↓ 7 35 | Perl: ↓ 7 36 | FreePascal: ↓ 7 37 | NodeJS_cluster: * 38 | Ruby: ↓ 7 39 | Guile: ↓ 5 40 | CoffeeScript: ↑ 4 41 | Java: ↓ 5 42 | PyPy3_bytes: ↓ 9 43 | NodeJS_async: ↑ 3 44 | CoffeeScript_parallel: ↑ 1 45 | Tcl: ↓ 4 46 | CSharp: ↑ 13 47 | PyPy3: ↓ 4 48 | Julia: ↑ 12 49 | CommonLisp_opt: ↓ 9 50 | CommonLisp_old: ↓ 8 51 | Racket: ↓ 3 52 | Racket_compiled: ↓ 5 53 | Elixir: = 54 | Scala: ↓ 4 55 | R: ↓ 1 56 | Bash_parallel: ↓ 5 57 | POSIX_dash: ↓ 1 58 | Haskell: ↓ 6 59 | POSIX_zsh: ↓ 2 60 | POSIX_bash: ↓ 2 61 | Bash: ↓ 6 62 | ChezScheme: ↓ 27 63 | Chicken: ↓ 31 64 | Dart: ↓ 26 65 | Haskell2: ↓ 45 66 | OCaml_lwt: * 67 | Ruby_rubinius: ↓ 28 68 | -------------------------------------------------------------------------------- /Perl/swapview.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env perl 2 | 3 | use strict; 4 | use warnings; 5 | use utf8; 6 | use autodie; 7 | use 5.010; 8 | 9 | use English qw{ -no_match_vars }; # Avoids regex performance penalty in perl 5.16 and earlier. 10 | 11 | sub get_swap_info_from { 12 | my ( $pid_dirs_ref ) = @_; 13 | my @results = (); 14 | for my $pid ( @{$pid_dirs_ref} ) { 15 | my $smaps_file = join q{/}, $pid, q{smaps}; 16 | my $swap_size = 0; 17 | if ( -f $smaps_file and 18 | -r $smaps_file and 19 | ( $EUID == 0 or -O $smaps_file ) 20 | ) { 21 | open my $smaps_file_fh, '<', $smaps_file; 22 | while (my $line = <$smaps_file_fh>) { 23 | if ( $line =~ /Swap:/ ) { 24 | $swap_size += ( split( /[[:space:]]+/, $line ) )[1]; 25 | } 26 | } 27 | close $smaps_file_fh; 28 | } 29 | next if ( $swap_size == 0 ); 30 | my $cmdline_file = join q{/}, $pid, q{cmdline}; 31 | my $cmdline; 32 | if ( -f $cmdline_file and 33 | -r $cmdline_file and 34 | ( $EUID == 0 or -O $cmdline_file ) 35 | ) { 36 | open my $cmdline_file_fh, '<', $cmdline_file; 37 | $cmdline = do { 38 | local $RS; 39 | <$cmdline_file_fh>; 40 | }; 41 | close $cmdline_file_fh; 42 | $cmdline =~ s/\0$//; 43 | $cmdline =~ s/\0/ /g; 44 | } 45 | push @results, { pid => $pid, 46 | swap => $swap_size, 47 | cmd => $cmdline, 48 | }; 49 | } 50 | return @results; 51 | } 52 | 53 | sub convert_file_size_from_kB { 54 | my ( $size ) = @_; 55 | my @units = qw{K M G T}; 56 | my $unit = 0; 57 | while ( $size > 1100 and $unit < 3 ) { 58 | $size /= 1024; 59 | $unit += 1; 60 | } 61 | return sprintf( "%.1f%siB", $size, $units[$unit] ); 62 | } 63 | 64 | sub main { 65 | my $printf_format = qq{%7s %9s %s\n}; 66 | opendir( my $proc_dh, q{/proc} ); 67 | chdir $proc_dh; 68 | my @pid_dirs = grep { -d && /^[[:digit:]]+$/xms } readdir $proc_dh; 69 | closedir $proc_dh; 70 | my @results = sort { $a->{'swap'} <=> $b->{'swap'} } get_swap_info_from( \@pid_dirs ); 71 | my $total_swap_size = 0; 72 | printf $printf_format, qw{PID SWAP COMMAND}; 73 | for my $result ( @results ) { 74 | $total_swap_size += $result->{'swap'}; 75 | printf $printf_format, $result->{'pid'}, convert_file_size_from_kB( $result->{'swap'} ), $result->{'cmd'}; 76 | } 77 | printf qq{Total: %10s\n}, convert_file_size_from_kB( $total_swap_size ); 78 | } 79 | 80 | main 81 | -------------------------------------------------------------------------------- /Go/swapview.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bufio" 5 | "bytes" 6 | "fmt" 7 | "io/ioutil" 8 | "log" 9 | "os" 10 | "sort" 11 | "strconv" 12 | "strings" 13 | ) 14 | 15 | type Info struct { 16 | Pid int 17 | Size int64 18 | Comm string 19 | } 20 | 21 | var ( 22 | nullBytes = []byte{0x0} 23 | emptyBytes = []byte(" ") 24 | swapPrefix = "Swap:" 25 | ) 26 | 27 | func main() { 28 | slist := GetInfos() 29 | sort.Slice(slist, func(i, j int) bool { 30 | return slist[i].Size < slist[j].Size 31 | }) 32 | 33 | fmt.Printf("%7s %9s %s\n", "PID", "SWAP", "COMMAND") 34 | var total int64 35 | for _, v := range slist { 36 | fmt.Printf("%7d %9s %s\n", v.Pid, FormatSize(v.Size), v.Comm) 37 | total += v.Size 38 | } 39 | fmt.Printf("Total: %10s\n", FormatSize(total)) 40 | } 41 | 42 | func GetInfos() (list []Info) { 43 | f, _ := os.Open("/proc") 44 | defer f.Close() 45 | names, err := f.Readdirnames(0) 46 | if err != nil { 47 | log.Fatalf("read /proc: %v", err) 48 | } 49 | for _, name := range names { 50 | pid, err := strconv.Atoi(name) 51 | if err != nil { 52 | continue 53 | } 54 | info, err := GetInfo(pid) 55 | if err != nil || info.Size == 0 { 56 | continue 57 | } 58 | list = append(list, info) 59 | } 60 | return 61 | } 62 | 63 | func GetInfo(pid int) (info Info, err error) { 64 | info.Pid = pid 65 | var bs []byte 66 | bs, err = ioutil.ReadFile(fmt.Sprintf("/proc/%d/cmdline", pid)) 67 | if err != nil { 68 | return 69 | } 70 | if bytes.HasSuffix(bs, nullBytes) { 71 | bs = bs[:len(bs)-1] 72 | } 73 | info.Comm = string(bytes.Replace(bs, nullBytes, emptyBytes, -1)) 74 | bs, err = ioutil.ReadFile(fmt.Sprintf("/proc/%d/smaps", pid)) 75 | if err != nil { 76 | return 77 | } 78 | 79 | var total, size int64 80 | var b string 81 | 82 | r := bufio.NewScanner(bytes.NewReader(bs)) 83 | for r.Scan() { 84 | b = r.Text() 85 | if !strings.HasPrefix(b, swapPrefix) { 86 | continue 87 | } 88 | 89 | x := strings.Split(b, string(emptyBytes)) 90 | size, err = strconv.ParseInt(string(x[len(x)-2]), 10, 64) 91 | if err != nil { 92 | return info, err 93 | } 94 | 95 | total += size 96 | } 97 | 98 | // No swap pid info should be ignored. 99 | if total == 0 { 100 | return 101 | } 102 | info.Size = total * 1024 103 | return 104 | } 105 | 106 | var units = []string{"", "K", "M", "G", "T"} 107 | 108 | func FormatSize(s int64) string { 109 | unit := 0 110 | f := float64(s) 111 | for unit < len(units) && f > 1100.0 { 112 | f /= 1024.0 113 | unit++ 114 | } 115 | if unit == 0 { 116 | return fmt.Sprintf("%dB", int64(f)) 117 | } else { 118 | return fmt.Sprintf("%.1f%siB", f, units[unit]) 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /newlisp/swapview.lsp: -------------------------------------------------------------------------------- 1 | #!/usr/bin/newlisp 2 | 3 | (define item-format "%7s %9s %s") 4 | (define total-format "Total: %10s") 5 | 6 | (define (file-size size) 7 | (let ((units "KMGT") 8 | (left (abs size)) 9 | (unit -1)) 10 | (while (and (> left 1100) (< unit 3)) 11 | (setq left (div left 1024)) 12 | (++ unit)) 13 | (if (= unit -1) 14 | (format "%dB" size) 15 | (begin 16 | (if (< size 0) 17 | (setq left (- left))) 18 | (format "%.1f%siB" left (units unit)))))) 19 | 20 | (define (get-pid-dir pid dir) 21 | (append "/proc/" pid "/" dir)) 22 | 23 | (context 'with-open) 24 | (define-macro (with-open:with-open fname mode fhandle lst-if lst-else) 25 | (if (set fhandle (eval (expand '(open fname mode) 'fname 'mode))) 26 | (begin 27 | (if lst-if 28 | (dolist (x lst-if) 29 | (eval x))) 30 | (close (eval fhandle))) 31 | (begin 32 | (if lst-else 33 | (dolist (x lst-else) 34 | (eval x)))))) 35 | 36 | (context MAIN) 37 | 38 | (define (read-proc-file pid fname) 39 | (let ((fname (get-pid-dir pid fname)) 40 | (fcontent "")) 41 | (with-open fname "r" f 42 | ((while (read f buf 4096) 43 | (extend fcontent buf)))) 44 | (let (size (length fcontent)) 45 | (if (> size 0) 46 | (if (= (slice fcontent -1) "\000") 47 | (setq fcontent (slice fcontent 0 (- size 1)))))) 48 | 49 | (let (size (length fcontent)) 50 | (if (> size 0) 51 | (replace "\000" fcontent " ") 52 | nil)))) 53 | 54 | (define (get-swap-for pid) 55 | (let ((comm (read-proc-file pid "cmdline")) 56 | (fs (read-proc-file pid "smaps")) 57 | (off 0) 58 | (sum 0) 59 | (found '())) 60 | (if fs 61 | (while (setf found (regex {\nSwap:\s+(\d+)} fs 0 off)) 62 | (setq off (+ (found 1) (found 2))) 63 | (setq sum (+ sum (int (found 3)))))) 64 | (list pid (* sum 1024) comm))) 65 | 66 | (define (get-swap) 67 | (let (ret '()) 68 | (dolist (x (directory "/proc/" "[0-9]+")) 69 | (let (s (get-swap-for x)) 70 | (if (> (s 1) 0) 71 | (begin 72 | (extend ret (list s)))))) 73 | (sort ret (fn (s1 s2) (<= (s1 1) (s2 1)))))) 74 | 75 | (define (main) 76 | (let ((results (get-swap)) 77 | (sum 0)) 78 | (println (format item-format "PID" "SWAP" "COMMAND")) 79 | (dolist (s results) 80 | (println (format item-format (s 0) (file-size (s 1)) (s 2))) 81 | (setq sum (+ sum (s 1)))) 82 | (println (format total-format (file-size sum))))) 83 | 84 | (main) 85 | (exit) 86 | -------------------------------------------------------------------------------- /OCaml/swapview.ml: -------------------------------------------------------------------------------- 1 | type swap_t = (string * int * string) (*pid, size, comm*) 2 | 3 | let is_pid (file:string) : bool = 4 | try ignore (int_of_string file); true 5 | with _ -> false 6 | 7 | let filesize (size:int) : string = 8 | let rec aux = function 9 | | (size, []) when size < 1100. -> Printf.sprintf "%.0fB" size 10 | | (size, []) -> aux (size /. 1024., ["KiB"; "MiB"; "GiB"; "TiB"]) 11 | | (size, h :: []) -> Printf.sprintf "%.1f%s" size h 12 | | (size, h :: _) when size < 1100. -> Printf.sprintf "%.1f%s" size h 13 | | (size, _ :: t) -> aux (size /. 1024., t) 14 | in aux (float_of_int size, []) 15 | 16 | let read_dir (dir:string) : string list = 17 | Array.to_list (Sys.readdir dir) 18 | 19 | let read_file (filename:string) : string list = 20 | try 21 | let ic = open_in filename in 22 | let rec loop acc = 23 | try 24 | let line = input_line ic in 25 | loop (line :: acc) 26 | with _ -> close_in ic; acc 27 | in 28 | List.rev (loop []) 29 | with _ -> [] 30 | 31 | let chop_null (s:string) : string = 32 | let len = String.length s in 33 | let ss = if (len <> 0) && (s.[len - 1] = '\000') 34 | then String.sub s 0 (len - 1) 35 | else s 36 | in 37 | String.map (function '\000' -> ' ' | x -> x) ss 38 | 39 | let get_comm_for (pid:string) : string = 40 | match read_file ("/proc/" ^ pid ^ "/cmdline") with 41 | | h :: _ -> chop_null h 42 | | _ -> "" 43 | 44 | let get_swap_for (pid:string) : swap_t = 45 | match read_file ("/proc/" ^ pid ^ "/smaps") with 46 | | [] -> (pid, 0, "") 47 | | lines -> 48 | List.filter (fun line -> String.sub line 0 5 = "Swap:") lines 49 | |> List.map (fun line -> 50 | let len = (String.rindex line ' ') - 5 in 51 | String.sub line 5 len 52 | |> String.trim 53 | |> int_of_string) 54 | |> List.fold_left (fun acc x -> acc + x) 0 55 | |> fun swap -> (pid, swap * 1024, get_comm_for pid) 56 | 57 | let get_swaps () : swap_t list = 58 | read_dir "/proc" 59 | |> List.filter is_pid 60 | |> List.map get_swap_for 61 | |> List.filter (fun (_, s, _) -> s <> 0) 62 | |> List.sort (fun (_,a,_) (_,b,_) -> compare a b) 63 | 64 | let main = 65 | let print' = Printf.printf "%7s %9s %s\n" in 66 | let print_swap (pid, swap, comm) = print' pid (filesize swap) comm in 67 | let print_total total = Printf.printf "Total: %10s\n" (filesize total) in 68 | 69 | let swaps = get_swaps () in 70 | let total = List.fold_left (fun acc (_, x, _) -> acc + x) 0 swaps in 71 | 72 | print' "PID" "SWAP" "COMMAND"; 73 | List.iter print_swap swaps; 74 | print_total total 75 | -------------------------------------------------------------------------------- /CommonLisp_old/swapview.lisp: -------------------------------------------------------------------------------- 1 | #!/usr/bin/sbcl --script 2 | 3 | (defun number-string-p (str) 4 | (= (length str) (second (multiple-value-list (parse-integer str :junk-allowed t))))) 5 | 6 | (defun path-check (path) 7 | "Check the directory and files in the directory" 8 | (and (number-string-p (subseq path 6 (position #\/ path :from-end t))) 9 | (probe-file (concatenate 'string path "smaps")) 10 | (probe-file (concatenate 'string path "cmdline")))) 11 | 12 | (defun get-swap-size (path) 13 | "Calculate the swap in smaps of the path" 14 | (let ((size (ignore-errors 15 | (with-open-file (stream path :if-does-not-exist nil) 16 | (if stream 17 | (loop for line = (read-line stream nil nil) 18 | while line 19 | when (search "Swap:" line) 20 | summing (parse-integer (subseq line (1+ (position #\: line))) :junk-allowed t))))))) 21 | (if size size 0))) 22 | 23 | (defun convert-size (size) 24 | "For human beings" 25 | (cond 26 | ((> size (* 1024 1024)) (format nil "~1$GiB" (float (/ size 1024 1024)))) 27 | ((> size 1024) (format nil "~1$MiB" (float (/ size 1024)))) 28 | (t (format nil "~1$KiB" size)))) 29 | 30 | (defun print-result (list) 31 | "Print the result in list, which item: (id swap cmdline)" 32 | (let ((format-string "~7@A~7T~9@A~9T~A~%")) 33 | (progn 34 | (format t format-string "PID" "SWAP" "COMMAND") 35 | (loop for item in list 36 | summing (second item) into total 37 | do (format t format-string (first item) (convert-size (second item)) (third item)) 38 | finally (format t "Total: ~10@A~%" (convert-size total)))))) 39 | 40 | (defun get-process-id (path) 41 | "Return process id from the path" 42 | (subseq path 6 (position #\/ path :from-end t))) 43 | 44 | (defun get-cmdline (path) 45 | "Return process cmdline" 46 | (with-open-file (stream path :if-does-not-exist nil) 47 | (if stream 48 | (substitute #\Space #\Nul (read-line stream nil nil)) 49 | ""))) 50 | 51 | (defun process (path) 52 | "The main process function which read with path string, return multi-value" 53 | (let ((id (get-process-id path)) 54 | (size (get-swap-size (concatenate 'string path "smaps"))) 55 | (cmdline (get-cmdline (concatenate 'string path "cmdline")))) 56 | (values id size cmdline))) 57 | 58 | (defun main () 59 | (loop for x in (directory "/proc/*/") 60 | ; do (print x) 61 | if (and (path-check (namestring x)) 62 | (> (get-swap-size (concatenate 'string (namestring x) "smaps")) 0)) 63 | collecting (multiple-value-list (process (namestring x))) into result-list 64 | finally (if (not (null result-list)) 65 | (print-result (sort result-list #'< :key #'second))))) 66 | 67 | (main) 68 | -------------------------------------------------------------------------------- /CommonLisp_opt/swapview.lisp: -------------------------------------------------------------------------------- 1 | ;#!/usr/bin/sbcl --script 2 | ;(declaim (optimize speed)) 3 | 4 | (defun number-string-p (str) 5 | ; (declare (type (simple-array character) str)) 6 | (= (length str) (second (multiple-value-list (parse-integer str :junk-allowed t))))) 7 | 8 | (defun path-check (path) 9 | "Check the directory and files in the directory" 10 | (and (number-string-p (subseq path 6 (position #\/ path :from-end t))) 11 | (probe-file (concatenate 'string path "smaps")) 12 | (probe-file (concatenate 'string path "cmdline")))) 13 | 14 | (defun get-swap-size (path) 15 | "Calculate the swap in smaps of the path" 16 | (or (ignore-errors 17 | (with-open-file (stream path :if-does-not-exist nil) 18 | (if stream 19 | (loop for line = (read-line stream nil nil) 20 | while line 21 | when (search "Swap:" line) 22 | summing (parse-integer (subseq line (1+ (position #\: line))) :junk-allowed t)) 23 | 0))) 24 | 0)) 25 | 26 | (defun convert-size (size) 27 | "For human beings" 28 | (cond 29 | ((> size 1048576) (format nil "~1$GiB" (/ size 1048576))) 30 | ((> size 1024) (format nil "~1$MiB" (/ size 1024))) 31 | (t (format nil "~1$KiB" size)))) 32 | 33 | (defun print-result (lis) 34 | "Print the result in list, which item: (id swap cmdline)" 35 | (let ((format-string "~7@A~7T~9@A~9T~A~%")) 36 | (format t format-string "PID" "SWAP" "COMMAND") 37 | (loop for item in lis 38 | summing (second item) into total 39 | do (format t format-string (first item) (convert-size (second item)) (third item)) 40 | finally (format t "Total: ~10@A~%" (convert-size total))))) 41 | 42 | (defun get-process-id (path) 43 | "Return process id from the path" 44 | (subseq path 6 (position #\/ path :from-end t))) 45 | 46 | (defun get-cmdline (path) 47 | "Return process cmdline" 48 | (with-open-file (stream path :if-does-not-exist nil) 49 | (if stream 50 | (substitute #\Space #\Nul (read-line stream nil nil)) 51 | ""))) 52 | 53 | (defun process (path) 54 | "The main process function which read with path string, return: id, size, cmdline" 55 | (values (get-process-id path) 56 | (get-swap-size (concatenate 'string path "smaps")) 57 | (get-cmdline (concatenate 'string path "cmdline")))) 58 | 59 | (defun main () 60 | (loop for x in (directory "/proc/*/") 61 | ; do (print x) 62 | if (and (path-check (native-namestring x)) 63 | (> (the fixnum (get-swap-size (concatenate 'string (native-namestring x) "smaps"))) 0)) 64 | collecting (multiple-value-list (process (native-namestring x))) into result-list 65 | finally (if result-list 66 | (print-result (sort result-list #'< :key #'second))))) 67 | ;(main) 68 | -------------------------------------------------------------------------------- /C++14/swapview.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | using namespace std; 15 | 16 | constexpr const char * TARGET = "Swap:"; 17 | constexpr const size_t TARGETLEN = 5; 18 | 19 | using swap_info = tuple; 20 | 21 | string filesize(double size) { 22 | static const char * units = "KMGT"; 23 | auto left = abs(size); 24 | int unit = -1; 25 | while( left > 1100 && unit < 3 ){ 26 | left /= 1024; 27 | unit++; 28 | } 29 | if(unit == -1) return (to_string((int)size) + 'B'); 30 | 31 | ostringstream sout; 32 | sout << fixed << setprecision(1) << (size > 0 ? left : -left) << units[unit] << "iB"; 33 | return sout.str(); 34 | } 35 | 36 | bool starts_with (string const& s1, string const& s2) { 37 | if(s1.size() < s2.size()) return false; 38 | auto r = mismatch(s2.begin(), s2.end(), s1.begin()); 39 | return (r.first == s2.end()); 40 | } 41 | 42 | swap_info getSwapFor(int pid){ 43 | ifstream cmd_inf("/proc/" + to_string(pid) + "/cmdline"); 44 | string comm((istreambuf_iterator(cmd_inf)), istreambuf_iterator()); 45 | if(!comm.empty()) { 46 | if(comm.back() == 0) comm.pop_back(); 47 | replace(comm.begin(), comm.end(), '\0' , ' '); 48 | } 49 | double s=0.0; 50 | ifstream inf("/proc/" + to_string(pid) + "/smaps"); 51 | string l; 52 | while(getline(inf, l)) { 53 | if(starts_with(l, TARGET)) { 54 | s += strtol(l.c_str() + TARGETLEN, nullptr, 10); 55 | } 56 | } 57 | return make_tuple(pid, s*1024.0, comm); 58 | } 59 | 60 | vector getSwap(){ 61 | vector ret; 62 | DIR * dp = opendir("/proc"); 63 | if(dp) { 64 | while(struct dirent * dirp = readdir(dp)) { 65 | if(int pid = strtol(dirp->d_name, nullptr, 10)) { 66 | auto item = getSwapFor(pid); 67 | if(get<1>(item) > 0) 68 | ret.push_back(item); 69 | } 70 | } 71 | closedir(dp); 72 | } 73 | sort(ret.begin(), ret.end(), 74 | [](auto const& i, auto const& j){return get<1>(i) < get<1>(j);}); 75 | return ret; 76 | } 77 | 78 | int main(int argc, char * argv[]){ 79 | std::ios::sync_with_stdio(false); 80 | double t=0.0; 81 | cout << setw(7) << "PID" << ' ' << setw(9) << "SWAP" << ' ' << "COMMAND" << "\n"; 82 | for(auto const& item: getSwap()){ 83 | cout << setw(7) << get<0>(item) 84 | << ' ' << setw(9) << filesize(get<1>(item)) 85 | << ' ' << get<2>(item) 86 | << "\n"; 87 | t+=get<1>(item); 88 | } 89 | cout<<"Total: "<)) 3 | import Control.Exception (catch, SomeException) 4 | import Control.Monad (mapM, liftM2) 5 | import Data.Char (isDigit) 6 | import Data.List (sortBy) 7 | import Data.Function (on) 8 | import System.Directory (getDirectoryContents) 9 | import Text.Printf (printf) 10 | import Data.ByteString.Lazy.Char8 (ByteString) 11 | import qualified Data.ByteString.Lazy.Char8 as BS 12 | import Data.Either (fromRight) 13 | 14 | type Pid = Int 15 | 16 | format = "%7d %9s %s" 17 | formatHead = "%7s %9s %s" 18 | totalFmt = "Total: %10s" 19 | firstLine = printf formatHead ("PID" :: String) ("SWAP" :: String) ("COMMAND" :: String) 20 | 21 | main = do 22 | d <- mapM swapusedWithPid =<< pids 23 | let printResult r = do 24 | putStrLn firstLine 25 | BS.putStr . BS.unlines $ r 26 | putStrLn $ printf totalFmt $ BS.unpack . filesize $ (* 1024) $ total d 27 | printResult =<< mapM formatResult (transformData d) 28 | where swapused' p = swapused p `catch` handler 29 | handler :: SomeException -> IO Int 30 | handler e = return 0 31 | swapusedWithPid p = liftM2 (,) (return p) $ swapused' p 32 | 33 | pids :: IO [Pid] 34 | pids = map read . filter (all isDigit) <$> getDirectoryContents "/proc" 35 | 36 | swapused :: Pid -> IO Int 37 | swapused pid = sum . map getNumber . filter (BS.isPrefixOf "Swap:") . BS.lines <$> BS.readFile ("/proc/" ++ show pid ++ "/smaps") 38 | where getNumber = (read @Int) . BS.unpack . BS.takeWhile isDigit . BS.dropWhile (not . isDigit) 39 | 40 | transformData :: [(Pid, Int)] -> [(Pid, ByteString)] 41 | transformData = map (mapSnd humanSize) . sortBy (compare `on` snd) . filter ((/=) 0 . snd) 42 | where humanSize = filesize . (* 1024) 43 | 44 | formatResult :: (Pid, ByteString) -> IO ByteString 45 | formatResult (pid, size) = do 46 | cmd <- getCommand pid 47 | return . BS.pack $ printf format pid (BS.unpack size) (BS.unpack cmd) 48 | 49 | getCommand :: Pid -> IO ByteString 50 | getCommand pid = BS.map transnul . dropLastNull <$> BS.readFile ("/proc/" ++ show pid ++ "/cmdline") 51 | where dropLastNull s 52 | | BS.null s = s 53 | | BS.last s == '\0' = BS.init s 54 | | otherwise = s 55 | transnul ch = if ch == '\0' then ' ' else ch 56 | 57 | total :: [(Pid, Int)] -> Int 58 | total = sum . map snd 59 | 60 | units = "KMGTP" 61 | 62 | liftUnit :: Double -> String -> Char -> (Double, Char) 63 | liftUnit n u l = 64 | if n > 1100 && not (null u) 65 | then liftUnit (n / 1024) (tail u) (head u) 66 | else (n, l) 67 | 68 | filesize :: (Integral a, Show a) => a -> ByteString 69 | filesize n = BS.pack $ 70 | if unit /= '\0' 71 | then printf "%.1f%ciB" m unit 72 | else show n ++ "B" 73 | where (m, unit) = liftUnit (fromIntegral n) units '\0' 74 | 75 | mapSnd :: (a -> b) -> (c, a) -> (c, b) 76 | mapSnd f (a, b) = (a, f b) 77 | -------------------------------------------------------------------------------- /D_parallel/swapview.d: -------------------------------------------------------------------------------- 1 | #!/usr/bin/dmd -run 2 | 3 | import std.stdio, std.file, std.path, std.string, std.conv, std.math, std.container, std.algorithm, std.parallelism, std.range; 4 | 5 | string filesize(double size){ 6 | string units = "KMGT"; 7 | double left = cast(double)size.abs(); 8 | int unit = -1; 9 | 10 | while(left > 1100 && unit < 3){ 11 | left /=1024; 12 | unit += 1; 13 | } 14 | 15 | if(unit == -1){ 16 | return format("%dB", to!int(size)); 17 | }else{ 18 | if(size < 0) 19 | left = -left; 20 | return format("%.1f%siB", left, units[unit]); 21 | } 22 | } 23 | 24 | string getcmdln(string pid){ 25 | auto ret = cast(ubyte[]) read(pid~"/cmdline"); 26 | if(ret[$-1] == '\0') 27 | ret.length--; 28 | foreach(ref ubyte c; ret){ 29 | if(c=='\0') c=' '; 30 | } 31 | return cast(string) ret; 32 | } 33 | 34 | string read_to_end(File file) { 35 | static ubyte[65536] buffer; 36 | ubyte[] ret; 37 | while (!file.eof()) { 38 | ret ~= file.rawRead(buffer[]); 39 | } 40 | return cast(string)ret; 41 | } 42 | 43 | ulong checkswap(string pid){ 44 | import std.array : join, split; 45 | import std.algorithm : startsWith, findSplitBefore; 46 | import std.string : stripLeft; 47 | ulong size = 0; 48 | File file = File(pid~"/smaps", "r"); 49 | auto data = file.read_to_end; 50 | foreach(line; data.split("\n")) { 51 | if(line.startsWith("Swap:")){ 52 | line = line[5..$].stripLeft; 53 | size += to!int(cast(string)line.findSplitBefore(" ")[0]); 54 | } 55 | } 56 | return size * 1024; 57 | } 58 | 59 | struct SwapInfo 60 | { 61 | string pid; 62 | ulong size; 63 | string comm; 64 | }; 65 | 66 | SwapInfo swap_thread(string dir) { 67 | string pid = dir.baseName; 68 | if (pid.isNumeric) { 69 | try { 70 | ulong size = checkswap(dir); 71 | if (size) 72 | return SwapInfo(pid, size, getcmdln(dir)); 73 | }catch(Exception) { } 74 | } 75 | return SwapInfo(null, 0, null); 76 | } 77 | 78 | auto getSwap(){ 79 | string[] dir; 80 | foreach(string d; dirEntries("/proc", SpanMode.shallow)) 81 | dir ~= [d]; 82 | 83 | auto map = taskPool.amap!swap_thread(dir, 1); 84 | return sort!"a.size < b.size"(map); 85 | } 86 | 87 | 88 | void main(){ 89 | string m = "%7s %9s %s"; 90 | double total = 0; 91 | auto result = getSwap(); 92 | writeln(format(m, "PID", "SWAP", "COMMAND")); 93 | foreach(ref item; result){ 94 | if (item.pid is null) 95 | continue; 96 | total += item.size; 97 | writeln(format(m, item.pid, filesize(item.size), item.comm)); 98 | } 99 | writeln(format("Total: %10s", filesize(total))); 100 | } 101 | 102 | // vim: set et ts=4 sw=4 103 | -------------------------------------------------------------------------------- /newlisp_mp/swapview.lsp: -------------------------------------------------------------------------------- 1 | #!/usr/bin/newlisp 2 | 3 | (define item-format "%7s %9s %s") 4 | (define total-format "Total: %10s") 5 | 6 | (define (file-size size) 7 | (let ((units "KMGT") 8 | (left (abs size)) 9 | (unit -1)) 10 | (while (and (> left 1100) (< unit 3)) 11 | (setq left (div left 1024)) 12 | (++ unit)) 13 | (if (= unit -1) 14 | (format "%dB" size) 15 | (begin 16 | (if (< size 0) 17 | (setq left (- left))) 18 | (format "%.1f%siB" left (units unit)))))) 19 | 20 | (define (get-pid-dir pid dir) 21 | (append "/proc/" pid "/" dir)) 22 | 23 | (context 'with-open) 24 | (define-macro (with-open:with-open fname mode fhandle lst-if lst-else) 25 | (if (set fhandle (eval (expand '(open fname mode) 'fname 'mode))) 26 | (begin 27 | (if lst-if 28 | (dolist (x lst-if) 29 | (eval x))) 30 | (close (eval fhandle))) 31 | (begin 32 | (if lst-else 33 | (dolist (x lst-else) 34 | (eval x)))))) 35 | 36 | (context MAIN) 37 | 38 | (define (read-proc-file pid fname) 39 | (let ((fname (get-pid-dir pid fname)) 40 | (fcontent "")) 41 | (with-open fname "r" f 42 | ((while (read f buf 4096) 43 | (extend fcontent buf)))) 44 | (let (size (length fcontent)) 45 | (if (> size 0) 46 | (if (= (slice fcontent -1) "\000") 47 | (setq fcontent (slice fcontent 0 (- size 1)))))) 48 | 49 | (let (size (length fcontent)) 50 | (if (> size 0) 51 | (replace "\000" fcontent " ") 52 | nil)))) 53 | 54 | (define (get-swap-for pid) 55 | (let ((comm (read-proc-file pid "cmdline")) 56 | (fs (read-proc-file pid "smaps")) 57 | (off 0) 58 | (sum 0) 59 | (found '())) 60 | (if fs 61 | (while (setf found (regex {\nSwap:\s+(\d+)} fs 0 off)) 62 | (setq off (+ (found 1) (found 2))) 63 | (setq sum (+ sum (int (found 3)))))) 64 | (list pid (* sum 1024) comm))) 65 | 66 | (define (get-swap) 67 | (let ((ret '()) 68 | (pids (list))) 69 | (dolist (x (directory "/proc/" "[0-9]+")) 70 | (let (pid (sym (append "pid" x))) 71 | (spawn (sym pid) (get-swap-for x)) 72 | (extend pids (list (sym pid))))) 73 | (sync 30000) 74 | (dolist (x pids) 75 | (let (s (eval (sym x))) 76 | (if (> (s 1) 0) 77 | (begin 78 | (extend ret (list s)))))) 79 | (sort ret (fn (s1 s2) (<= (s1 1) (s2 1)))))) 80 | 81 | (define (main) 82 | (let ((results (get-swap)) 83 | (sum 0)) 84 | (println (format item-format "PID" "SWAP" "COMMAND")) 85 | (dolist (s results) 86 | (println (format item-format (s 0) (file-size (s 1)) (s 2))) 87 | (setq sum (+ sum (s 1)))) 88 | (println (format total-format (file-size sum))))) 89 | 90 | (main) 91 | (exit) 92 | -------------------------------------------------------------------------------- /ChezScheme/swapview.ss: -------------------------------------------------------------------------------- 1 | (import (chezscheme)) 2 | 3 | (define-record process-info (pid swap-usage command-line)) 4 | 5 | (define (filesize size) 6 | (let lp ((units '(B KiB MiB GiB TiB)) 7 | (size size)) 8 | (if (and (> size 1100) (not (null? units))) 9 | (lp (cdr units) (/ size 1024)) 10 | (if (eq? (car units) 'B) 11 | (format #f "~dB" (inexact->exact size)) 12 | (format #f "~,1f~a" size (car units)))))) 13 | 14 | (define-syntax try 15 | (syntax-rules (catch) 16 | ((_ body (catch catcher)) 17 | (call-with-current-continuation 18 | (lambda (exit) 19 | (with-exception-handler 20 | (lambda (condition) 21 | (exit catcher)) 22 | (lambda () body))))))) 23 | 24 | (define (get-command-line pid) 25 | (let* [(port (open-input-file (format #f "/proc/~a/cmdline" pid))) 26 | (raw-commandline (get-string-all port)) 27 | (raw (if (eof-object? raw-commandline) "" raw-commandline)) 28 | (len (- (string-length raw) 1)) 29 | (_ (if (char=? (string-ref raw len) #\nul) 30 | (string-truncate! raw len)))] 31 | (list->string 32 | (map (lambda (x) (if (char=? x #\nul) #\space x)) 33 | (string->list raw))))) 34 | 35 | (define (find-number str) 36 | (list->string 37 | (filter (lambda (x) (and (char>=? x #\0) (char<=? x #\9))) 38 | (string->list str)))) 39 | 40 | (define (getSwapFor pid) 41 | (try 42 | (let ((smaps (open-input-file (format #f "/proc/~a/smaps" pid)))) 43 | (let lp ((size 0) 44 | (line (get-line smaps))) 45 | (cond ((eof-object? line) 46 | (close-input-port smaps) 47 | (and (not (zero? size)) 48 | (make-process-info 49 | pid (* 1024 size) (get-command-line pid)))) 50 | (else 51 | (lp (if (string=? (substring line 0 5) "Swap:") 52 | (+ size (string->number (find-number line))) 53 | size) 54 | (get-line smaps)))))) 55 | (catch #f))) 56 | 57 | (define (getSwap) 58 | (sort (lambda (a b) (< (process-info-swap-usage a) (process-info-swap-usage b))) 59 | (filter (lambda (x) (and x (> (process-info-swap-usage x) 0))) 60 | (map (lambda (x) (and (string->number x) (getSwapFor x))) 61 | (directory-list "/proc"))))) 62 | 63 | (define (main) 64 | (let ([FORMATSTR "~7@a ~9@a ~@a~%"] 65 | [total 0.0]) 66 | (format #t FORMATSTR "PID" "SWAP" "COMMAND") 67 | (for-each 68 | (lambda (item) 69 | (begin 70 | (set! total (+ total (process-info-swap-usage item))) 71 | (format #t FORMATSTR 72 | (process-info-pid item) 73 | (filesize (process-info-swap-usage item)) 74 | (process-info-command-line item)))) 75 | (getSwap)) 76 | (format #t "Total: ~10@a~%" (filesize total)))) 77 | 78 | (main) 79 | -------------------------------------------------------------------------------- /D/swapview.d: -------------------------------------------------------------------------------- 1 | #!/usr/bin/dmd -run 2 | 3 | import std.stdio, std.file, std.path, std.conv, std.math, std.container, std.algorithm; 4 | 5 | string filesize(double size){ 6 | import std.format : format; 7 | string units = "KMGT"; 8 | double left = size.fabs(); 9 | int unit = -1; 10 | 11 | while(left > 1100 && unit < 3){ 12 | left /=1024; 13 | unit += 1; 14 | } 15 | 16 | if(unit == -1){ 17 | return format("%dB", to!int(size)); 18 | }else{ 19 | if(size < 0) 20 | left = -left; 21 | return format("%.1f%siB", left, units[unit]); 22 | } 23 | } 24 | 25 | string getcmdln(string pid){ 26 | auto ret = cast(ubyte[]) read("/proc/"~pid~"/cmdline"); 27 | if(ret[$-1] == '\0') 28 | ret.length--; 29 | foreach(ref ubyte c; ret){ 30 | if(c=='\0') c=' '; 31 | } 32 | return cast(string) ret; 33 | } 34 | 35 | string read_to_end(File file) { 36 | static ubyte[65536] buffer; 37 | ubyte[] ret; 38 | while (!file.eof()) { 39 | ret ~= file.rawRead(buffer[]); 40 | } 41 | return cast(string)ret; 42 | } 43 | 44 | double checkswap(string pid){ 45 | import std.array : join, split; 46 | import std.algorithm : startsWith, findSplitBefore; 47 | import std.string : stripLeft; 48 | double size = 0; 49 | File file = File("/proc/"~pid~"/smaps", "r"); 50 | auto data = file.read_to_end; 51 | foreach(line; data.split("\n")) { 52 | if(line.startsWith("Swap:")){ 53 | line = line[5..$].stripLeft; 54 | size += to!int(cast(string)line.findSplitBefore(" ")[0]); 55 | } 56 | } 57 | return size * 1024; 58 | } 59 | 60 | struct SwapInfo 61 | { 62 | int pid; 63 | double size; 64 | string comm; 65 | 66 | int opCmp(ref const SwapInfo s) const { 67 | double r = size - s.size; 68 | return (r > 0) - (r < 0); 69 | } 70 | }; 71 | 72 | SwapInfo[] getSwap(){ 73 | import std.string : isNumeric; 74 | SwapInfo[] ret; 75 | foreach(DirEntry dirs; dirEntries("/proc", SpanMode.shallow)){ 76 | string pid = baseName(dirs.name); 77 | if(pid.isNumeric()){ 78 | try{ 79 | double size = checkswap(pid); 80 | if(size) 81 | ret ~= SwapInfo(to!int(pid), size, getcmdln(pid)); 82 | }catch(Exception){} // do nothing for error 83 | } 84 | } 85 | sort(ret); 86 | return ret; 87 | } 88 | 89 | 90 | void main() { 91 | import std.format : format; 92 | string m = "%7s %9s %s"; 93 | double total=0; 94 | auto result=getSwap(); 95 | writeln(format(m , "PID", "SWAP", "COMMAND")); 96 | foreach(SwapInfo item; result){ 97 | total += item.size; 98 | writeln(format(m , item.pid, filesize(item.size), item.comm)); 99 | } 100 | writeln(format("Total: %10s", filesize(total))); 101 | } 102 | -------------------------------------------------------------------------------- /Haskell_parallel/swapview.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE OverloadedStrings, Strict, TypeApplications #-} 2 | import Control.Applicative ((<$>)) 3 | import Control.Exception (catch, SomeException) 4 | import Control.Monad (mapM, liftM2) 5 | import qualified Control.Monad.Parallel as MP 6 | import Data.Char (isDigit) 7 | import Data.List (sortBy) 8 | import Data.Function (on) 9 | import System.Directory (getDirectoryContents) 10 | import Text.Printf (printf) 11 | import Data.ByteString.Char8 (ByteString) 12 | import qualified Data.ByteString.Char8 as BS 13 | import Data.Either (fromRight) 14 | 15 | type Pid = Int 16 | 17 | format = "%7d %9s %s" 18 | formatHead = "%7s %9s %s" 19 | totalFmt = "Total: %10s" 20 | firstLine = printf formatHead ("PID" :: String) ("SWAP" :: String) ("COMMAND" :: String) 21 | 22 | main = do 23 | d <- MP.mapM swapusedWithPid =<< pids 24 | let printResult r = do 25 | putStrLn firstLine 26 | BS.putStr . BS.unlines $ r 27 | putStrLn $ printf totalFmt $ BS.unpack . filesize $ (* 1024) $ total d 28 | printResult =<< mapM formatResult (transformData d) 29 | where swapused' p = swapused p `catch` handler 30 | handler :: SomeException -> IO Int 31 | handler e = return 0 32 | swapusedWithPid p = liftM2 (,) (return p) $ swapused' p 33 | 34 | pids :: IO [Pid] 35 | pids = map read . filter (all isDigit) <$> getDirectoryContents "/proc" 36 | 37 | swapused :: Pid -> IO Int 38 | swapused pid = sum . map getNumber . filter (BS.isPrefixOf "Swap:") . BS.lines <$> BS.readFile ("/proc/" ++ show pid ++ "/smaps") 39 | where getNumber = (read @Int) . BS.unpack . BS.takeWhile isDigit . BS.dropWhile (not . isDigit) 40 | 41 | transformData :: [(Pid, Int)] -> [(Pid, ByteString)] 42 | transformData = map (mapSnd humanSize) . sortBy (compare `on` snd) . filter ((/=) 0 . snd) 43 | where humanSize = filesize . (* 1024) 44 | 45 | formatResult :: (Pid, ByteString) -> IO ByteString 46 | formatResult (pid, size) = do 47 | cmd <- getCommand pid 48 | return . BS.pack $ printf format pid (BS.unpack size) (BS.unpack cmd) 49 | 50 | getCommand :: Pid -> IO ByteString 51 | getCommand pid = BS.map transnul . dropLastNull <$> BS.readFile ("/proc/" ++ show pid ++ "/cmdline") 52 | where dropLastNull s 53 | | BS.null s = s 54 | | BS.last s == '\0' = BS.init s 55 | | otherwise = s 56 | transnul ch = if ch == '\0' then ' ' else ch 57 | 58 | total :: [(Pid, Int)] -> Int 59 | total = sum . map snd 60 | 61 | units = "KMGTP" 62 | 63 | liftUnit :: Double -> String -> Char -> (Double, Char) 64 | liftUnit n u l = 65 | if n > 1100 && not (null u) 66 | then liftUnit (n / 1024) (tail u) (head u) 67 | else (n, l) 68 | 69 | filesize :: (Integral a, Show a) => a -> ByteString 70 | filesize n = BS.pack $ 71 | if unit /= '\0' 72 | then printf "%.1f%ciB" m unit 73 | else show n ++ "B" 74 | where (m, unit) = liftUnit (fromIntegral n) units '\0' 75 | 76 | mapSnd :: (a -> b) -> (c, a) -> (c, b) 77 | mapSnd f (a, b) = (a, f b) 78 | -------------------------------------------------------------------------------- /broken/OCaml_lwt/swapview.ml: -------------------------------------------------------------------------------- 1 | type swap_t = (string * int * string) (*pid, size, comm*) 2 | 3 | let is_pid (file:string) : bool = 4 | try ignore (int_of_string file); true 5 | with _ -> false 6 | 7 | let filesize (size:int) : string = 8 | let rec aux = function 9 | | (size, []) when size < 1100. -> Printf.sprintf "%.0fB" size 10 | | (size, []) -> aux (size /. 1024., ["KiB"; "MiB"; "GiB"; "TiB"]) 11 | | (size, h :: []) -> Printf.sprintf "%.1f%s" size h 12 | | (size, h :: _) when size < 1100. -> Printf.sprintf "%.1f%s" size h 13 | | (size, _ :: t) -> aux (size /. 1024., t) 14 | in aux (float_of_int size, []) 15 | 16 | let read_dir (dir:string) : string list Lwt.t = 17 | Lwt_unix.files_of_directory dir 18 | |> Lwt_stream.to_list 19 | 20 | let read_file (filename:string) : string list Lwt.t = 21 | try%lwt 22 | let read ic = 23 | Lwt_io.read_lines ic 24 | |> Lwt_stream.to_list 25 | in Lwt_io.with_file Lwt_io.Input filename read 26 | with _ -> Lwt.return [] 27 | 28 | let chop_null (s:string) : string = 29 | let len = String.length s in 30 | let ss = if (len <> 0) && (s.[len - 1] = '\000') 31 | then String.sub s 0 (len - 1) 32 | else s 33 | in 34 | String.map (function '\000' -> ' ' | x -> x) ss 35 | 36 | let get_comm_for (pid:string) : string Lwt.t = 37 | match%lwt read_file ("/proc/" ^ pid ^ "/cmdline") with 38 | | h :: _ -> Lwt.return (chop_null h) 39 | | _ -> Lwt.return "" 40 | 41 | let get_swap_for (pid:string) : swap_t Lwt.t = 42 | match%lwt read_file ("/proc/" ^ pid ^ "/smaps") with 43 | | [] -> Lwt.return (pid, 0, "") 44 | | lines -> 45 | List.filter (fun line -> String.sub line 0 5 = "Swap:") lines 46 | |> List.map (fun line -> 47 | let len = (String.rindex line ' ') - 5 in 48 | String.sub line 5 len 49 | |> String.trim 50 | |> int_of_string) 51 | |> List.fold_left (fun acc x -> acc + x) 0 52 | |> fun swap -> ( 53 | let%lwt comm = get_comm_for pid in 54 | Lwt.return (pid, swap * 1024, comm)) 55 | 56 | let get_swaps () : swap_t list Lwt.t = 57 | let open Lwt.Infix in 58 | read_dir "/proc" 59 | >|= List.filter is_pid 60 | >>= fun pids -> Lwt_list.map_p get_swap_for pids 61 | >|= List.filter (fun (_, s, _) -> (s <> 0)) 62 | >|= List.sort (fun (_,a,_) (_,b,_) -> compare a b) 63 | 64 | let%lwt main = 65 | let print' = Lwt_io.printf "%7s %9s %s\n" in 66 | let print_swap (pid, swap, comm) = print' pid (filesize swap) comm in 67 | let print_total total = Lwt_io.printf "Total: %10s\n" (filesize total) in 68 | 69 | let%lwt swaps = get_swaps () in 70 | let total = List.fold_left (fun acc (_, x, _) -> acc + x) 0 swaps in 71 | 72 | let%lwt _ = print' "PID" "SWAP" "COMMAND" in 73 | let%lwt _ = Lwt_list.iter_s print_swap swaps in 74 | let%lwt _ = print_total total in 75 | 76 | Lwt.return_unit 77 | -------------------------------------------------------------------------------- /Go_goroutine/swapview.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bufio" 5 | "bytes" 6 | "fmt" 7 | "io/ioutil" 8 | "log" 9 | "os" 10 | "sort" 11 | "strconv" 12 | "strings" 13 | "sync" 14 | // "time" 15 | ) 16 | 17 | type Info struct { 18 | Pid int 19 | Size int64 20 | Comm string 21 | } 22 | 23 | var ( 24 | nullBytes = []byte{0x0} 25 | emptyBytes = []byte(" ") 26 | swapPrefix = "Swap:" 27 | ) 28 | 29 | func main() { 30 | slist := GetInfos() 31 | sort.Slice(slist, func(i, j int) bool { 32 | return slist[i].Size < slist[j].Size 33 | }) 34 | 35 | fmt.Printf("%7s %9s %s\n", "PID", "SWAP", "COMMAND") 36 | var total int64 37 | for _, v := range slist { 38 | fmt.Printf("%7d %9s %s\n", v.Pid, FormatSize(v.Size), v.Comm) 39 | total += v.Size 40 | } 41 | fmt.Printf("Total: %10s\n", FormatSize(total)) 42 | } 43 | 44 | func GetInfos() (list []Info) { 45 | f, _ := os.Open("/proc") 46 | defer f.Close() 47 | names, err := f.Readdirnames(0) 48 | if err != nil { 49 | log.Fatalf("read /proc: %v", err) 50 | } 51 | 52 | length := len(names) 53 | 54 | list = make([]Info, 0, length) 55 | infoCh := make(chan Info, length) 56 | 57 | wg := &sync.WaitGroup{} 58 | wg.Add(length) 59 | 60 | go func() { 61 | defer close(infoCh) 62 | defer wg.Wait() 63 | 64 | for _, name := range names { 65 | go GetInfo(name, infoCh, wg) 66 | } 67 | }() 68 | 69 | for v := range infoCh { 70 | list = append(list, v) 71 | } 72 | return 73 | } 74 | 75 | func GetInfo(name string, infoCh chan<- Info, wg *sync.WaitGroup) { 76 | defer wg.Done() 77 | 78 | pid, err := strconv.Atoi(name) 79 | if err != nil { 80 | return 81 | } 82 | 83 | info := Info{ 84 | Pid: pid, 85 | } 86 | 87 | var bs []byte 88 | bs, err = ioutil.ReadFile(fmt.Sprintf("/proc/%d/cmdline", pid)) 89 | if err != nil { 90 | return 91 | } 92 | if bytes.HasSuffix(bs, nullBytes) { 93 | bs = bs[:len(bs)-1] 94 | } 95 | info.Comm = string(bytes.Replace(bs, nullBytes, emptyBytes, -1)) 96 | 97 | bs, err = ioutil.ReadFile(fmt.Sprintf("/proc/%d/smaps", pid)) 98 | if err != nil { 99 | return 100 | } 101 | 102 | var total, size int64 103 | var b string 104 | 105 | r := bufio.NewScanner(bytes.NewReader(bs)) 106 | for r.Scan() { 107 | b = r.Text() 108 | if !strings.HasPrefix(b, swapPrefix) { 109 | continue 110 | } 111 | 112 | x := strings.Split(b, string(emptyBytes)) 113 | size, err = strconv.ParseInt(x[len(x)-2], 10, 64) 114 | if err != nil { 115 | return 116 | } 117 | 118 | total += size 119 | } 120 | 121 | // No swap pid info should be ignored. 122 | if total == 0 { 123 | return 124 | } 125 | info.Size = total * 1024 126 | infoCh <- info 127 | return 128 | } 129 | 130 | var units = []string{"", "K", "M", "G", "T"} 131 | 132 | func FormatSize(s int64) string { 133 | if s <= 1100 { 134 | return fmt.Sprintf("%dB", s) 135 | } 136 | 137 | unit := 0 138 | f := float64(s) 139 | for unit < len(units) && f > 1100.0 { 140 | f /= 1024.0 141 | unit++ 142 | } 143 | return fmt.Sprintf("%.1f%siB", f, units[unit]) 144 | } 145 | -------------------------------------------------------------------------------- /Chicken/swapview.scm: -------------------------------------------------------------------------------- 1 | (import (chicken sort)) 2 | (import (chicken file)) 3 | (import (chicken io)) 4 | (import (chicken string)) 5 | (import (chicken flonum)) 6 | (import (chicken format)) ; for sprintf 7 | (import format) ; for clisp style format from SRFI-28 instead of simple format from chicken.format 8 | (import (srfi 1)) ; for filter-map 9 | 10 | 11 | ;;;; Copy from chicken4-core/utils.scm 12 | ;;; Read file as string from given filename or port: 13 | (define (read-all . file) 14 | (let ([file (optional file ##sys#standard-input)]) 15 | (if (port? file) 16 | (read-string #f file) 17 | (with-input-from-file file (cut read-string #f) #:binary) ) ) ) 18 | 19 | (define-record process-info pid swap-usage command-line) 20 | 21 | 22 | (define (filesize size) 23 | (let lp ((units '(B KiB MiB GiB TiB)) 24 | (size size)) 25 | (if (and (> size 1100) (not (null? units))) 26 | (lp (cdr units) (/ size 1024.0)) 27 | (if (eq? (car units) 'B) 28 | (conc size "B") 29 | (format #f "~,1f~a" size (car units)))))) 30 | 31 | (define (get-command-line pid) 32 | (let* ((cmdline-file (sprintf "/proc/~a/cmdline" pid)) 33 | (raw-commandline (with-input-from-file cmdline-file read-all))) 34 | (string-translate 35 | (string-chomp raw-commandline "\x00") #\nul #\space))) 36 | 37 | (define (get-process-swap-usage pid) 38 | (condition-case 39 | (let ((smaps (open-input-file (sprintf "/proc/~a/smaps" pid)))) 40 | (let lp ((size 0) 41 | (line (read-line smaps))) 42 | (cond ((eof-object? line) 43 | (close-input-port smaps) 44 | (and (not (zero? size)) 45 | (make-process-info 46 | pid (* 1024 size) (get-command-line pid)))) 47 | (else 48 | (lp (if (substring=? "Swap:" line) 49 | (+ size 50 | (string->number 51 | (cadr (reverse (string-split line))))) 52 | size) 53 | (read-line smaps)))))) 54 | ((exn file) #f))) 55 | 56 | (define (get-swapped-processes) 57 | (sort 58 | (filter-map 59 | (lambda (file-name) 60 | (and (string->number file-name) 61 | (get-process-swap-usage file-name))) 62 | (directory "/proc")) 63 | (lambda (a b) 64 | (< (process-info-swap-usage a) (process-info-swap-usage b))))) 65 | 66 | (define (main) 67 | (let* ((results (get-swapped-processes)) 68 | (FORMATSTR "~7@a ~9@a ~@a~%") 69 | (total-swap 0)) 70 | (format #t FORMATSTR "PID" "SWAP" "COMMAND") 71 | (map 72 | (lambda (swapped-process-info) 73 | (set! total-swap 74 | (+ total-swap (process-info-swap-usage swapped-process-info))) 75 | (format #t FORMATSTR 76 | (process-info-pid swapped-process-info) 77 | (filesize (process-info-swap-usage swapped-process-info)) 78 | (process-info-command-line swapped-process-info))) 79 | results) 80 | (format #t "Total: ~10@a~%" (filesize total-swap)))) 81 | 82 | (main) 83 | -------------------------------------------------------------------------------- /Rust_parallel/swapview.rs: -------------------------------------------------------------------------------- 1 | extern crate rayon; 2 | 3 | use std::fs::{File,read_dir}; 4 | use std::io::Read; 5 | use std::sync::mpsc::channel; 6 | use rayon::prelude::*; 7 | 8 | const UNITS: [char; 4] = ['K', 'M', 'G', 'T']; 9 | 10 | fn filesize(size: isize) -> String { 11 | let mut left = size.abs() as f64; 12 | let mut unit = -1; 13 | 14 | while left > 1100. && unit < 3 { 15 | left /= 1024.; 16 | unit += 1; 17 | } 18 | if unit == -1 { 19 | format!("{}B", size) 20 | } else { 21 | if size < 0 { 22 | left = -left; 23 | } 24 | format!("{:.1}{}iB", left, UNITS[unit as usize]) 25 | } 26 | } 27 | 28 | fn chop_null(s: String) -> String { 29 | let last = s.len() - 1; 30 | let mut s = s; 31 | if !s.is_empty() && s.as_bytes()[last] == 0 { 32 | s.truncate(last); 33 | } 34 | s.replace("\0", " ") 35 | } 36 | 37 | fn get_comm_for(pid: usize) -> String { 38 | let cmdline_path = format!("/proc/{}/cmdline", pid); 39 | let mut buf = String::new(); 40 | let mut file = match File::open(&cmdline_path) { 41 | Ok(f) => f, 42 | Err(_) => return String::new(), 43 | }; 44 | match file.read_to_string(&mut buf) { 45 | Ok(_) => (), 46 | Err(_) => return String::new(), 47 | }; 48 | chop_null(buf) 49 | } 50 | 51 | fn get_swap_for(pid: usize) -> isize { 52 | let mut s = 0; 53 | let smaps_path = format!("/proc/{}/smaps", pid); 54 | let mut file = match File::open(&smaps_path) { 55 | Ok(f) => f, 56 | Err(_) => return 0, 57 | }; 58 | 59 | let mut vec = vec![]; 60 | file.read_to_end(&mut vec).unwrap(); 61 | for line in vec.split(|&c| c == b'\n') { 62 | if line.starts_with(b"Swap:") { 63 | let string = line[5..] 64 | .iter() 65 | .skip_while(|&&c| c == b' ') 66 | .take_while(|&&c| c != b' ') 67 | .map(|&c| c as char) 68 | .collect::(); 69 | s += string.parse::().unwrap(); 70 | } 71 | } 72 | s * 1024 73 | } 74 | 75 | fn get_swap() -> Vec<(usize, isize, String)> { 76 | rayon::in_place_scope(|pool| { 77 | let (tx, rx) = channel(); 78 | for d in read_dir("/proc").unwrap() { 79 | let tx = tx.clone(); 80 | pool.spawn(move |_| { 81 | let path = d.unwrap().path(); 82 | if let Ok(pid) = path.file_name().unwrap().to_str().unwrap().parse() { 83 | tx.send(match get_swap_for(pid) { 84 | 0 => None, 85 | swap => Some((pid, swap, get_comm_for(pid))), 86 | }).unwrap(); 87 | } else { 88 | tx.send(None).unwrap(); 89 | } 90 | }); 91 | } 92 | drop(tx); 93 | rx.iter().filter_map(|x| x).collect() 94 | }) 95 | } 96 | 97 | fn main() { 98 | // let format = "{:>5} {:>9} {}"; 99 | // let totalFmt = "Total: {:8}"; 100 | let mut swapinfo = get_swap(); 101 | swapinfo.par_sort_unstable_by_key(|&(_, size, _)| size); 102 | 103 | println!("{:>7} {:>9} {}", "PID", "SWAP", "COMMAND"); 104 | let mut total = 0; 105 | for &(pid, swap, ref comm) in &swapinfo { 106 | total += swap; 107 | println!("{:>7} {:>9} {}", pid, filesize(swap), comm); 108 | } 109 | println!("Total: {:>10}", filesize(total)); 110 | } 111 | 112 | // vim: se sw=2: 113 | -------------------------------------------------------------------------------- /Erlang/swapview.erl: -------------------------------------------------------------------------------- 1 | -module(swapview). 2 | -export([swap_print/0, getswapfor/2]). 3 | 4 | is_integer(S) -> 5 | case string:to_integer(S) of 6 | {_, []} -> 7 | true; 8 | _ -> 9 | false 10 | end. 11 | 12 | filesize(Size) -> 13 | Units = "KMGT", 14 | case filesize(Size, 0) of 15 | {Fixsize, 0} -> 16 | io_lib:format("~BB", [Fixsize]); 17 | {Fixsize, Unit} when Unit > 0 -> 18 | io_lib:format("~.1f~ciB", [Fixsize, lists:nth(Unit, Units)]) 19 | end. 20 | 21 | filesize(Size, Unit) 22 | when Size < 0 -> 23 | {Size1, Unit1} = filesize(-Size, Unit), 24 | {-Size1, Unit1}; 25 | filesize(Size, Unit) 26 | when Unit < 4, Size > 1100 -> 27 | filesize(Size / 1024, Unit + 1); 28 | filesize(Size, Unit) -> 29 | {Size, Unit}. 30 | 31 | swap_print() -> 32 | Ret = getswap(), 33 | io:format("~7s ~9s ~s~n", ["PID", "SWAP", "COMMAND"]), 34 | [io:format("~7s ~9s ~s~n", [Pid, filesize(Size), Cmd]) || {Pid, Cmd, Size} <- Ret], 35 | Total = lists:sum([Size || {_,_,Size} <- Ret]), 36 | io:format("Total: ~10s~n", [filesize(Total)]). 37 | 38 | getswap() -> 39 | {ok, F} = file:list_dir_all("/proc"), 40 | Pids = lists:filter(fun is_integer/1, F), 41 | [spawn(?MODULE, getswapfor, [self(), Pid]) || Pid <- Pids], 42 | S = [read_result() || _ <- Pids], 43 | lists:keysort(3, [E || E = {_,_,Size} <- S, Size > 0]). 44 | 45 | read_result() -> 46 | receive 47 | Data -> 48 | Data 49 | end. 50 | 51 | read_file(File) -> 52 | case file:read(File, 4096) of 53 | {ok, Data} -> 54 | Data ++ read_file(File); 55 | eof -> 56 | [] 57 | end. 58 | 59 | convert_cmdline([]) -> 60 | []; 61 | convert_cmdline(Cmd) -> 62 | Cmd_ = case lists:last(Cmd) of 63 | 0 -> lists:sublist(Cmd, length(Cmd)-1); 64 | _ -> Cmd 65 | end, 66 | lists:map(fun(0) -> 32; (C) -> C end, Cmd_). 67 | 68 | getswapfor(Master, Pid) -> 69 | case file:open("/proc/"++Pid++"/cmdline", [read, raw, read_ahead]) of 70 | {ok, File} -> 71 | Cmd = 72 | try 73 | convert_cmdline(read_file(File)) 74 | after 75 | file:close(File) 76 | end, 77 | 78 | case file:open("/proc/"++Pid++"/smaps", [read, raw, read_ahead]) of 79 | {ok, File2} -> 80 | Size = 81 | try 82 | getswapsize(File2, 0) * 1024 83 | after 84 | file:close(File2) 85 | end, 86 | Master ! {Pid, Cmd, Size}; 87 | {error, _} -> 88 | Master ! 0 89 | end; 90 | {error, _} -> 91 | Master ! 0 92 | end. 93 | 94 | getswapsize(File, Acc) -> 95 | case file:read_line(File) of 96 | eof -> Acc; 97 | {ok, "Swap:" ++ Rest} -> 98 | {Size, _} = string:to_integer(string:strip(Rest, left, 32)), 99 | getswapsize(File, Acc+Size); 100 | {ok, _} -> 101 | getswapsize(File, Acc); 102 | {error, _} -> 0 103 | end. 104 | -------------------------------------------------------------------------------- /Perl_parallel/swapview.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env perl 2 | 3 | use strict; 4 | use warnings; 5 | use utf8; 6 | use autodie; 7 | use 5.010; 8 | use threads; 9 | use threads::shared; 10 | use Thread::Queue; 11 | 12 | # Avoids regex performance penalty in perl 5.16 and earlier. 13 | use English qw{ -no_match_vars }; 14 | 15 | my $results = Thread::Queue->new(); 16 | my $count : shared = 0; 17 | 18 | sub get_process_swap ($) { 19 | my $q = shift; 20 | while (1) { 21 | my $pid = $q->dequeue(); 22 | last unless ($pid); 23 | my $smaps_file = join q{/}, $pid, q{smaps}; 24 | my $swap_size = 0; 25 | if ( -f $smaps_file 26 | and -r $smaps_file 27 | and ( $EUID == 0 or -O $smaps_file ) ) 28 | { 29 | open my $smaps_file_fh, '<', $smaps_file; 30 | while ( my $line = <$smaps_file_fh> ) { 31 | if ( $line =~ /Swap:/ ) { 32 | $swap_size += ( split( /[[:space:]]+/, $line ) )[1]; 33 | } 34 | } 35 | close $smaps_file_fh; 36 | } 37 | next if ( $swap_size == 0 ); 38 | my $cmdline_file = join q{/}, $pid, q{cmdline}; 39 | my $cmdline; 40 | if ( -f $cmdline_file 41 | and -r $cmdline_file 42 | and ( $EUID == 0 or -O $cmdline_file ) ) 43 | { 44 | open my $cmdline_file_fh, '<', $cmdline_file; 45 | $cmdline = do { 46 | local $RS; 47 | <$cmdline_file_fh>; 48 | }; 49 | close $cmdline_file_fh; 50 | $cmdline =~ s/\0$//; 51 | $cmdline =~ s/\0/ /g; 52 | } 53 | { 54 | lock($count); 55 | $count = $count + 1; 56 | } 57 | $pid = $pid =~ s/\D+//r; 58 | $results->enqueue( 59 | { pid => $pid, swap => $swap_size, cmd => $cmdline, } ); 60 | } 61 | 62 | } 63 | 64 | sub get_swap_info_from ($) { 65 | my $q = Thread::Queue->new(); 66 | my $cpus = do { local @ARGV = '/proc/cpuinfo'; grep /^processor\s+:/, <>; }; 67 | foreach ( 1 .. $cpus ) { 68 | threads->create( \&get_process_swap, $q ); 69 | } 70 | $q->enqueue($_) foreach ( @{ $_[0] } ); 71 | $q->end(); 72 | $_->join() foreach ( threads->list() ); 73 | if ($count) { 74 | return $results->extract( 0, $count ); 75 | } 76 | else { 77 | return (); 78 | } 79 | } 80 | 81 | sub convert_file_size_from_kB ($) { 82 | my $size = shift; 83 | my @units = qw{K M G T}; 84 | my $unit = 0; 85 | while ( $size > 1100 and $unit < 3 ) { 86 | $size /= 1024; 87 | $unit += 1; 88 | } 89 | return sprintf( "%.1f%siB", $size, $units[$unit] ); 90 | } 91 | 92 | sub main { 93 | my $printf_format = qq{%7s %9s %s\n}; 94 | my @pid_dirs = glob "/proc/[0123456789]*"; 95 | my @sorted_results = 96 | sort { $a->{'swap'} <=> $b->{'swap'} } get_swap_info_from( \@pid_dirs ); 97 | my $total_swap_size = 0; 98 | printf $printf_format, qw{PID SWAP COMMAND}; 99 | for my $result (@sorted_results) { 100 | $total_swap_size += $result->{'swap'}; 101 | printf $printf_format, $result->{'pid'}, 102 | convert_file_size_from_kB( $result->{'swap'} ), $result->{'cmd'}; 103 | } 104 | printf qq{Total: %10s\n}, convert_file_size_from_kB($total_swap_size); 105 | } 106 | 107 | main 108 | -------------------------------------------------------------------------------- /C++11/swapview.cc: -------------------------------------------------------------------------------- 1 | #define _POSIX_C_SOURCE 200809L 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | 17 | //#define TARGET "Size" // for test 18 | #define TARGET "Swap" 19 | 20 | 21 | std::vector read_dir(std::string path){ 22 | std::unique_ptr dp(opendir(path.c_str()), closedir); 23 | struct dirent *dirp = nullptr; 24 | auto rv = std::vector{}; 25 | while((dirp = readdir(dp.get())) != nullptr){ 26 | rv.push_back(dirp->d_name); 27 | } 28 | return rv; 29 | } 30 | 31 | std::string read_file(std::string const & fn){ 32 | try{ 33 | std::ifstream in(fn); 34 | return std::string(std::istreambuf_iterator(in), 35 | std::istreambuf_iterator()); 36 | } 37 | catch(const std::ios_base::failure &){ 38 | return ""; 39 | } 40 | } 41 | 42 | struct SwapInfo{ 43 | int pid {}; 44 | long long int size{}; 45 | std::string comm; 46 | }; 47 | std::string output_size(long long int size){ 48 | std::ostringstream out; 49 | static const char units [] = "KMGT"; 50 | double left = fabs(size); 51 | int unit = -1; 52 | while( left > 1100 && unit < 3 ){ 53 | left /= 1024; 54 | unit++; 55 | } 56 | if(unit == -1){ 57 | out << static_cast(size) << 'B'; 58 | }else{ 59 | if(size<0){ 60 | left = -left; 61 | } 62 | out << std::fixed << std::setprecision(1) << left << units[unit] << "iB"; 63 | } 64 | return out.str(); 65 | } 66 | 67 | std::ostream & operator<<(std::ostream & out, SwapInfo const & si){ 68 | auto size = output_size(si.size); 69 | out << std::setw(7) << si.pid; 70 | out << " " << std::setw(9) << size; 71 | out << " " << si.comm; 72 | return out; 73 | } 74 | 75 | SwapInfo get_swap_info(std::string const & pid){ 76 | auto rv = SwapInfo{}; 77 | rv.pid = std::atoi(pid.c_str()); 78 | if(rv.pid == 0) 79 | return rv; 80 | auto cmdline = read_file(std::string("/proc/") + pid + "/cmdline"); 81 | if(cmdline.length() == 0) 82 | return rv; 83 | if(cmdline[cmdline.length() - 1] == '\0') 84 | cmdline.pop_back(); 85 | std::replace(cmdline.begin(), cmdline.end(), '\0', ' '); 86 | rv.comm = std::move(cmdline); 87 | std::unique_ptr fp(fopen((std::string("/proc/") + pid + "/smaps").c_str(), "r"), fclose); 88 | if(fp.get() == nullptr) 89 | return rv; 90 | char * line_tmp = nullptr; 91 | size_t size = 0; 92 | auto deleter = [](char ** ptr){std::free(*ptr);}; 93 | std::unique_ptr line(&line_tmp, deleter); 94 | while(true){ 95 | auto len = getline(&line_tmp, &size, fp.get()); 96 | if(len <= 0) 97 | break; 98 | long long int size; 99 | if(sscanf(line_tmp, TARGET ": %lld", &size)){ 100 | rv.size += size * 1024; 101 | } 102 | } 103 | return rv; 104 | } 105 | 106 | int main(){ 107 | std::ios::sync_with_stdio(false); 108 | std::vector all_swap_info; 109 | for(auto const & n : read_dir("/proc/")){ 110 | if(n[0] == '.') 111 | continue; 112 | auto tmp = get_swap_info(n); 113 | if(tmp.size > 0){ 114 | all_swap_info.push_back(std::move(tmp)); 115 | } 116 | } 117 | auto sorter = [](SwapInfo const & a,SwapInfo const &b){ 118 | return a.size < b.size; 119 | }; 120 | std::sort(all_swap_info.begin(), all_swap_info.end(), sorter); 121 | long long int total = 0; 122 | printf("%7s %9s %s\n", "PID", "SWAP", "COMMAND"); 123 | for(auto const & x : all_swap_info){ 124 | std::cout << x << "\n"; 125 | total += x.size; 126 | } 127 | auto size = output_size(total); 128 | std::printf("Total: %10s\n", size.c_str()); 129 | return 0; 130 | } 131 | -------------------------------------------------------------------------------- /Rust_parallel/.swapview/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "autocfg" 7 | version = "1.1.0" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" 10 | 11 | [[package]] 12 | name = "cfg-if" 13 | version = "1.0.0" 14 | source = "registry+https://github.com/rust-lang/crates.io-index" 15 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 16 | 17 | [[package]] 18 | name = "crossbeam-channel" 19 | version = "0.5.2" 20 | source = "registry+https://github.com/rust-lang/crates.io-index" 21 | checksum = "e54ea8bc3fb1ee042f5aace6e3c6e025d3874866da222930f70ce62aceba0bfa" 22 | dependencies = [ 23 | "cfg-if", 24 | "crossbeam-utils", 25 | ] 26 | 27 | [[package]] 28 | name = "crossbeam-deque" 29 | version = "0.8.1" 30 | source = "registry+https://github.com/rust-lang/crates.io-index" 31 | checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e" 32 | dependencies = [ 33 | "cfg-if", 34 | "crossbeam-epoch", 35 | "crossbeam-utils", 36 | ] 37 | 38 | [[package]] 39 | name = "crossbeam-epoch" 40 | version = "0.9.7" 41 | source = "registry+https://github.com/rust-lang/crates.io-index" 42 | checksum = "c00d6d2ea26e8b151d99093005cb442fb9a37aeaca582a03ec70946f49ab5ed9" 43 | dependencies = [ 44 | "cfg-if", 45 | "crossbeam-utils", 46 | "lazy_static", 47 | "memoffset", 48 | "scopeguard", 49 | ] 50 | 51 | [[package]] 52 | name = "crossbeam-utils" 53 | version = "0.8.7" 54 | source = "registry+https://github.com/rust-lang/crates.io-index" 55 | checksum = "b5e5bed1f1c269533fa816a0a5492b3545209a205ca1a54842be180eb63a16a6" 56 | dependencies = [ 57 | "cfg-if", 58 | "lazy_static", 59 | ] 60 | 61 | [[package]] 62 | name = "either" 63 | version = "1.6.1" 64 | source = "registry+https://github.com/rust-lang/crates.io-index" 65 | checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" 66 | 67 | [[package]] 68 | name = "hermit-abi" 69 | version = "0.1.19" 70 | source = "registry+https://github.com/rust-lang/crates.io-index" 71 | checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" 72 | dependencies = [ 73 | "libc", 74 | ] 75 | 76 | [[package]] 77 | name = "lazy_static" 78 | version = "1.4.0" 79 | source = "registry+https://github.com/rust-lang/crates.io-index" 80 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 81 | 82 | [[package]] 83 | name = "libc" 84 | version = "0.2.119" 85 | source = "registry+https://github.com/rust-lang/crates.io-index" 86 | checksum = "1bf2e165bb3457c8e098ea76f3e3bc9db55f87aa90d52d0e6be741470916aaa4" 87 | 88 | [[package]] 89 | name = "memoffset" 90 | version = "0.6.5" 91 | source = "registry+https://github.com/rust-lang/crates.io-index" 92 | checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" 93 | dependencies = [ 94 | "autocfg", 95 | ] 96 | 97 | [[package]] 98 | name = "num_cpus" 99 | version = "1.13.1" 100 | source = "registry+https://github.com/rust-lang/crates.io-index" 101 | checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" 102 | dependencies = [ 103 | "hermit-abi", 104 | "libc", 105 | ] 106 | 107 | [[package]] 108 | name = "rayon" 109 | version = "1.5.1" 110 | source = "registry+https://github.com/rust-lang/crates.io-index" 111 | checksum = "c06aca804d41dbc8ba42dfd964f0d01334eceb64314b9ecf7c5fad5188a06d90" 112 | dependencies = [ 113 | "autocfg", 114 | "crossbeam-deque", 115 | "either", 116 | "rayon-core", 117 | ] 118 | 119 | [[package]] 120 | name = "rayon-core" 121 | version = "1.9.1" 122 | source = "registry+https://github.com/rust-lang/crates.io-index" 123 | checksum = "d78120e2c850279833f1dd3582f730c4ab53ed95aeaaaa862a2a5c71b1656d8e" 124 | dependencies = [ 125 | "crossbeam-channel", 126 | "crossbeam-deque", 127 | "crossbeam-utils", 128 | "lazy_static", 129 | "num_cpus", 130 | ] 131 | 132 | [[package]] 133 | name = "scopeguard" 134 | version = "1.1.0" 135 | source = "registry+https://github.com/rust-lang/crates.io-index" 136 | checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" 137 | 138 | [[package]] 139 | name = "swapview" 140 | version = "0.0.1" 141 | dependencies = [ 142 | "rayon", 143 | ] 144 | -------------------------------------------------------------------------------- /C++98/swapview.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #ifdef USE_OMP 18 | #include 19 | #endif 20 | using namespace std; 21 | 22 | // #define TARGET "Size:" // test with Size: when swap is empty 23 | #define TARGETLEN 5 24 | #define TARGET "Swap:" 25 | 26 | ///////////////////////////////////////////////////////////////////////////// 27 | 28 | vector inline lsdir(const string & path){ 29 | vector ret; 30 | DIR *dp; 31 | struct dirent *dirp; 32 | if((dp = opendir(path.c_str())) == NULL) { 33 | error(errno, errno, "opening %s \n", path.c_str()); 34 | } 35 | while ((dirp = readdir(dp)) != NULL) { 36 | ret.push_back(string(dirp->d_name)); 37 | } 38 | closedir(dp); 39 | return ret; 40 | } 41 | 42 | struct swap_info{ 43 | int pid; string comm; double size; 44 | int operator< (const swap_info& other){ 45 | return size < other.size; 46 | } 47 | }; 48 | 49 | ///////////////////////////////////////////////////////////////////////////// 50 | 51 | string filesize(double size){ 52 | char units [] = "KMGT"; 53 | double left = fabs(size); 54 | int unit = -1; 55 | while( left > 1100 && unit < 3 ){ 56 | left /= 1024; 57 | unit++; 58 | } 59 | ostringstream sout; 60 | if(unit == -1){ 61 | sout << static_cast(size) << 'B'; 62 | }else{ 63 | if(size<0){ 64 | left = -left; 65 | } 66 | sout << fixed << setprecision(1) << left << units[unit] << "iB"; 67 | } 68 | return sout.str(); 69 | } 70 | 71 | swap_info getSwapFor(int pid, const string & spid){ 72 | ifstream fs((string("/proc/") + spid + string("/cmdline")).c_str()); 73 | string comm((istreambuf_iterator(fs)), istreambuf_iterator()); 74 | if(comm.length() > 0){ 75 | replace(comm.begin(), comm.end(), '\0' , ' '); 76 | if(*(comm.end()-1) == ' ') 77 | comm.erase(comm.end()-1); 78 | } 79 | 80 | double s=0.0; 81 | ifstream sfs((string("/proc/") + spid + string("/smaps")).c_str()); 82 | for(string buf; getline(sfs, buf);){ 83 | if(buf.size() > TARGETLEN && 84 | mismatch(TARGET, TARGET + TARGETLEN, buf.begin()) 85 | .first == TARGET + TARGETLEN){ 86 | s += atoi(buf.c_str()+TARGETLEN); 87 | } 88 | } 89 | swap_info ret = {pid, comm, s*1024.0}; 90 | return ret; 91 | } 92 | 93 | struct not_digit { bool operator() (char x){ return !isdigit(x); } }; 94 | 95 | vector getSwap(){ 96 | vector ret; 97 | vector dir = lsdir("/proc"); 98 | #ifdef USE_OMP 99 | #pragma omp parallel for 100 | #endif 101 | for(vector::iterator itr=dir.begin(); itrbegin(), itr->end(), not_digit()) == itr->end()){ 103 | int pid = atoi(itr->c_str()); 104 | assert(pid > 0); 105 | swap_info item = getSwapFor(pid, *itr); 106 | if(item.size > 0) 107 | #ifdef USE_OMP 108 | #pragma omp critical 109 | #endif 110 | { 111 | ret.push_back(item); 112 | } 113 | } 114 | } 115 | sort(ret.begin(), ret.end()); 116 | return ret; 117 | } 118 | 119 | template 120 | void format_print(const T1 & pid, const T2 & swap, const T3 & command){ 121 | cout< result = getSwap(); 135 | format_print("PID", "SWAP", "COMMAND"); 136 | for(vector::iterator itr = result.begin(); itr < result.end(); ++itr){ 137 | format_print(*itr); 138 | t += itr->size; 139 | } 140 | cout<<"Total: "< 1100 && unit < 3; unit++) { 19 | left /= 1024; 20 | } 21 | if (unit === -1) { 22 | return sprintf('%dB', size); 23 | } else { 24 | if (size < 0) left = -left; 25 | return sprintf('%.1f%siB', left, units[unit]); 26 | } 27 | } 28 | 29 | const splitArrayToChunks = function(chunkCount, arr) { 30 | if (chunkCount < 2) { 31 | return [arr]; 32 | } 33 | 34 | const chunks = []; // result chunks 35 | const length = arr.length; 36 | let chunkSize; 37 | let i; // loop variable 38 | 39 | if (length % chunkCount === 0) { 40 | chunkSize = Math.floor(length / chunkCount); 41 | i = 0; 42 | while (i < length) { 43 | chunks.push(arr.slice(i, i += chunkSize)); 44 | } 45 | } else { 46 | i = 0; 47 | while (i < length) { 48 | chunkSize = Math.ceil((length - i) / chunkCount--); 49 | chunks.push(arr.slice(i, i += chunkSize)); 50 | } 51 | } 52 | return chunks; 53 | } 54 | 55 | const getPids = function() { 56 | const ret = []; 57 | const pids = []; 58 | fs.readdirSync("/proc").forEach(function(spid) { 59 | const pid = spid|0; 60 | if (pid > 0) { 61 | pids.push(pid); 62 | } 63 | }); 64 | 65 | return pids; 66 | } 67 | 68 | const printSwapChunks = function(chunks) { 69 | const results = Array.prototype.concat.apply([], chunks) 70 | .sort(function(a, b) { return a[1] - b[1]; }) 71 | console.log(sprintf('%7s %9s %s', 'PID', 'SWAP', 'COMMAND')); 72 | let t = 0; 73 | results.forEach(function(s) { 74 | console.log(sprintf('%7s %9s %s', s[0], filesize(s[1]), s[2])); 75 | t += s[1]; 76 | }); 77 | console.log(sprintf('Total: %10s', filesize(t))); 78 | } 79 | 80 | // fork workers 81 | for (let i = 0; i < coreCount; i++) { 82 | cluster.fork(); 83 | } 84 | 85 | const pidChunks = splitArrayToChunks(coreCount, getPids()); 86 | const swapChunks = []; 87 | 88 | const messageHandler = function(worker, message) { 89 | if (message.type === 'chunk_swap') { 90 | swapChunks.push(message.chunk); 91 | 92 | // all chunks ok 93 | if (swapChunks.length === coreCount) { 94 | // disconnect all workers. 95 | cluster.disconnect(); 96 | 97 | // print sorted swap info 98 | printSwapChunks(swapChunks); 99 | } 100 | } 101 | } 102 | 103 | cluster.on('message', messageHandler); 104 | 105 | // pass pid chunks to each worker 106 | Object.keys(cluster.workers).forEach((workerId, index) => { 107 | cluster.workers[workerId].send({type: 'chunk_pid', chunk: pidChunks[index]}); 108 | }); 109 | 110 | } else if (cluster.isWorker) { 111 | //////////////////// 112 | // Worker process 113 | //////////////////// 114 | 115 | const getSwapForChunk = function(pids) { 116 | const fs = require('fs'); 117 | return pids.map(function(pid) { // split this func 118 | try { 119 | let comm = fs.readFileSync('/proc/' + pid + '/cmdline', 'utf-8'); 120 | if(comm[comm.length-1] === '\0') { 121 | comm = comm.slice(0, -1) 122 | } 123 | comm = comm.replace(/\0/g,' '); 124 | let s = 0; 125 | const smaps = fs.readFileSync('/proc/'+ pid +'/smaps', 'utf-8'); 126 | const re = /\nSwap:\s+(\d+)/g; 127 | let result; 128 | while (result = re.exec(smaps)) { 129 | s += result[1] | 0; 130 | } 131 | return [pid, s*1024, comm]; 132 | } catch(e) { 133 | return [pid, 0, '']; 134 | } 135 | }).filter(function(p) { 136 | return p[1] > 0; 137 | }) 138 | } 139 | 140 | const messageHandler = (message) => { 141 | if (message.type === 'chunk_pid') { 142 | process.send({type: 'chunk_swap', chunk: getSwapForChunk(message.chunk)}); 143 | } 144 | } 145 | 146 | process.on('message', messageHandler); 147 | } 148 | -------------------------------------------------------------------------------- /FreePascal/swapview.pas: -------------------------------------------------------------------------------- 1 | Program swapview; 2 | {$mode objfpc} 3 | {I+} 4 | Uses sysutils; 5 | 6 | Type 7 | SwapInfo = Record 8 | pid : Integer; 9 | size : Real; 10 | comm : AnsiString 11 | end; 12 | ArraySwapInfo = array of SwapInfo; 13 | ArrayString = array of AnsiString; 14 | 15 | 16 | Function filesize(size : Real): AnsiString; 17 | Var units : AnsiString; 18 | left : Real; 19 | u : Integer; 20 | Begin 21 | units := 'KMGT'; 22 | left := abs(size); 23 | u := 0; 24 | While (left > 1100) And (u < 4) Do Begin 25 | left := left / 1024; 26 | Inc(u); 27 | End; 28 | If u = 0 Then 29 | filesize := Format('%DB', [round(size)]) 30 | Else Begin 31 | If size < 0 Then 32 | left := - left; 33 | filesize := Format('%.1F%SiB', [left, units[u]]); 34 | End; 35 | End; 36 | 37 | 38 | Function ReadAll(path: AnsiString): AnsiString; 39 | Var c: char; 40 | ret: AnsiString; 41 | f: Text; 42 | Begin 43 | ret := ''; 44 | Assign(f, path); 45 | Reset(f); 46 | While Not Eof(f) do 47 | Begin 48 | Read(f, c); 49 | ret := ret + c; 50 | End; 51 | ReadAll := ret 52 | End; 53 | 54 | Function ReadLines(path: AnsiString): ArrayString; 55 | Var c: AnsiString; 56 | f: Text; 57 | ret: ArrayString = NIL; 58 | Begin 59 | Assign(f, path); 60 | Reset(f); 61 | While Not Eof(f) do 62 | Begin 63 | ReadLn(f, c); 64 | SetLength(ret, Length(ret) + 1); 65 | ret[Length(ret)-1] := c; 66 | End; 67 | ReadLines := ret 68 | End; 69 | 70 | Function NoisyStrToInt(str : AnsiString): Integer; 71 | Var ret: Integer = 0; 72 | i : Integer; 73 | Begin 74 | For i:= 1 To Length(str) Do 75 | If (str[i] >= '0') And (str[i] <= '9') Then 76 | Begin 77 | ret := ret * 10 ; 78 | ret := ret + ord(str[i]) - ord('0') 79 | End; 80 | NoisyStrToInt := ret 81 | End; 82 | 83 | 84 | Function getSwapFor(pid : Integer): SwapInfo; 85 | Var comm : AnsiString; 86 | s : Real; 87 | lines : ArrayString; 88 | i : Integer; 89 | Begin 90 | Try 91 | comm := ReadAll(Format('/proc/%D/cmdline', [pid])); 92 | For i := 1 To Length(comm) Do 93 | If comm[i] = #0 Then comm[i] := #32; 94 | If Length(comm) > 0 Then 95 | comm := LeftStr(comm, Length(comm) - 1); 96 | lines := ReadLines(Format('/proc/%D/smaps', [pid])); 97 | s := 0 ; 98 | For i:= 0 to Length(lines) - 1 Do 99 | if CompareStr(LeftStr(Lines[i], 5), 'Swap:') = 0 Then 100 | s := s + NoisyStrToInt(Lines[i]); 101 | getSwapFor.pid := pid; 102 | getSwapFor.comm := comm; 103 | getSwapFor.size := s*1024; 104 | Except 105 | On E:EInOutError do 106 | Begin 107 | getSwapFor.pid := pid; 108 | getSwapFor.comm := ''; 109 | getSwapFor.size := 0; 110 | End 111 | End 112 | End; 113 | 114 | Function readdir(path : String): ArrayString; 115 | Var info : TSearchRec; 116 | ret : ArrayString = NIL; 117 | Begin 118 | If FindFirst (path+'/*', faDirectory, info)=0 then 119 | begin 120 | Repeat 121 | With Info do 122 | begin 123 | SetLength(ret, Length(ret) + 1); 124 | ret[Length(ret)-1] := name; 125 | end; 126 | Until FindNext(info)<>0; 127 | end; 128 | FindClose(Info); 129 | readdir := ret 130 | End; 131 | 132 | Procedure bubblesort(var items : ArraySwapInfo); 133 | Var i,j,l : Integer; 134 | t : SwapInfo; 135 | Begin 136 | l := Length(items) - 1; 137 | for i := 0 to l do 138 | for j := i+1 to l do 139 | If items[i].size > items[j].size Then 140 | Begin 141 | t := items[i]; 142 | items[i] := items[j]; 143 | items[j] := t 144 | End 145 | End; 146 | 147 | Function getSwap: ArraySwapInfo; 148 | Var dirs : ArrayString ; 149 | i, pid : Integer; 150 | ret : ArraySwapInfo = NIL; 151 | swap : SwapInfo; 152 | Begin 153 | dirs := readdir('/proc'); 154 | For i:=0 To Length(dirs) - 1 Do 155 | Begin 156 | pid := NoisyStrToInt(dirs[i]); 157 | If pid > 0 Then 158 | Begin 159 | swap := getSwapFor(pid); 160 | if swap.size > 0.0 Then 161 | Begin 162 | SetLength(ret, Length(ret)+1); 163 | ret[Length(ret)-1] := swap 164 | End 165 | End 166 | End; 167 | bubblesort(ret); 168 | getSwap := ret 169 | End; 170 | 171 | 172 | Var 173 | results : ArraySwapInfo; 174 | i : Integer; 175 | t : Real = 0; 176 | Begin 177 | results := getSwap(); 178 | WriteLn(Format('%7S %9S %S', ['PID', 'SWAP', 'COMMAND'])); 179 | For i := 0 To Length(results) - 1 Do 180 | Begin 181 | t := t + results[i].size; 182 | WriteLn(Format('%7D %9S %S', [results[i].pid, filesize(results[i].size), results[i].comm])); 183 | End; 184 | WriteLn(Format('Total: %10S', [filesize(t)])); 185 | End. 186 | -------------------------------------------------------------------------------- /C/swapview.c: -------------------------------------------------------------------------------- 1 | #define _POSIX_C_SOURCE 200809L 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #define FORMAT "%7d %9s %s\n" 13 | #define FORMAT_H "%7s %9s %s\n" 14 | #define BUFSIZE 512 15 | //#define TARGET "Size:" // For Test 16 | #define TARGET "Swap:" 17 | #define TARGETLEN (sizeof(TARGET) - 1) 18 | 19 | #ifdef __GLIBC__ 20 | #include 21 | #define assure(exp) \ 22 | if (!(exp)) \ 23 | error(1, errno, "\"%s\" failed in %d", #exp, __LINE__) 24 | #else 25 | #define assure(exp) \ 26 | if (!(exp)) { \ 27 | fprintf(stderr, "\"%s\" failed in %d (%s)", #exp, __LINE__, \ 28 | strerror(errno)); \ 29 | exit(1); \ 30 | } 31 | #endif 32 | 33 | char *filesize(double size) { 34 | char units[] = "KMGT"; 35 | double left = fabs(size); 36 | int unit = -1; 37 | 38 | char *buf; 39 | assure(buf = malloc(BUFSIZE)); 40 | 41 | while (left > 1100 && unit < 3) { 42 | left /= 1024; 43 | unit++; 44 | } 45 | if (unit == -1) { 46 | assure(snprintf(buf, BUFSIZE, "%dB", (int)size) > 0); 47 | } else { 48 | if (size < 0) 49 | left = -left; 50 | assure(snprintf(buf, BUFSIZE, "%.1f%ciB", left, units[unit]) > 0); 51 | } 52 | return buf; 53 | } 54 | 55 | typedef struct { 56 | int pid; 57 | double size; 58 | char *comm; 59 | } swap_info; 60 | 61 | swap_info *getSwapFor(int pid) { 62 | char filename[BUFSIZE]; 63 | FILE *fd = 0; 64 | size_t size = BUFSIZE; 65 | char *comm = malloc(size + 1); // +1 for last \0 66 | ssize_t len = 0; 67 | double s = 0.0; 68 | 69 | assure(snprintf(filename, BUFSIZE, "/proc/%d/cmdline", pid) > 0); 70 | if (!(fd = fopen(filename, "r"))) 71 | goto err; 72 | for (int got; (got = fread(comm + len, 1, size - len, fd)) > 0; len += got) { 73 | assure(comm = realloc(comm, (size <<= 1) + 1)); // +1 for last \0 74 | } 75 | fclose(fd); 76 | 77 | for (char *p = comm; p < comm + len - 1; ++p) 78 | *p || (*p = ' '); // comm[len-1] is \0 or non-space 79 | comm[len] = '\0'; // assure string is terminated 80 | 81 | assure(snprintf(filename, BUFSIZE, "/proc/%d/smaps", pid) > 0); 82 | if (!(fd = fopen(filename, "r"))) 83 | goto err; 84 | char line[PATH_MAX]; 85 | while (fgets(line, PATH_MAX, fd) != NULL) { 86 | if (strncmp(line, TARGET, TARGETLEN) == 0) 87 | s += atoi(line + TARGETLEN); 88 | } 89 | err: 90 | if (fd) 91 | fclose(fd); 92 | swap_info *ret; 93 | assure(ret = malloc(sizeof(swap_info))); 94 | ret->pid = pid; 95 | ret->size = s * 1024; 96 | ret->comm = comm; 97 | return ret; 98 | } 99 | 100 | int comp(const void *va, const void *vb) { 101 | double a = (**(swap_info **)va).size; 102 | double b = (**(swap_info **)vb).size; 103 | return (a > b) - (a < b); 104 | } 105 | 106 | swap_info **getSwap() { 107 | int size = 16; 108 | int length = 0; 109 | 110 | DIR *dp; 111 | struct dirent *dirp; 112 | assure(dp = opendir("/proc")); 113 | 114 | swap_info **ret; 115 | assure(ret = malloc(sizeof(swap_info *) * size)); 116 | while ((dirp = readdir(dp)) != NULL) { 117 | char *end; 118 | int pid = (int)strtol(dirp->d_name, &end, 10); 119 | if (*end == '\0') { 120 | swap_info *swapfor = getSwapFor(pid); 121 | if (swapfor->size > 0) { 122 | if (length == size) 123 | assure(ret = realloc(ret, sizeof(swap_info *) * (size <<= 1))); 124 | ret[length++] = swapfor; 125 | } else { 126 | free(swapfor->comm); 127 | free(swapfor); 128 | } 129 | } 130 | } 131 | closedir(dp); 132 | 133 | qsort(ret, length, sizeof(swap_info *), comp); 134 | 135 | if (length == size) 136 | assure(ret = realloc(ret, sizeof(swap_info *) * (++size))); 137 | ret[length] = 0; // mark for end 138 | return ret; 139 | } 140 | 141 | int main() { 142 | swap_info **infos = getSwap(), **p = infos; 143 | double total = 0; 144 | printf(FORMAT_H, "PID", "SWAP", "COMMAND"); 145 | for (; *p; ++p) { 146 | char *size = filesize((*p)->size); 147 | printf(FORMAT, (*p)->pid, size, (*p)->comm); 148 | total += (*p)->size; 149 | free(size); 150 | free((*p)->comm); 151 | free(*p); 152 | } 153 | free(infos); 154 | char *stotal = filesize(total); 155 | printf("Total: %10s\n", stotal); 156 | free(stotal); 157 | return 0; 158 | } 159 | -------------------------------------------------------------------------------- /benchmark.toml: -------------------------------------------------------------------------------- 1 | [options] 2 | # only valid for bench.py: 3 | ref_result = "C" 4 | time_field = "elapsed" 5 | show_diff_below = 0.9 6 | verbose = true 7 | 8 | [item.default] 9 | cmd = ["./swapview"] 10 | dir = "$name" 11 | time_limit = 30 12 | count_limit = 20 13 | valid_percent = 50 14 | 15 | 16 | [item.Bash] 17 | cmd = ["./swapview.sh"] 18 | 19 | [item.Bash_parallel] 20 | cmd = ["./swapview.sh"] 21 | 22 | [item.POSIX_dash] 23 | dir = "POSIX_shell" 24 | cmd = ["dash", "./swapview.sh"] 25 | 26 | [item.POSIX_bash] 27 | dir = "POSIX_shell" 28 | cmd = ["bash", "./swapview.sh"] 29 | 30 | [item.POSIX_zsh] 31 | dir = "POSIX_shell" 32 | cmd = ["zsh", "./swapview.sh"] 33 | 34 | [item.C] 35 | 36 | [item."C++11"] 37 | 38 | [item."C++14"] 39 | 40 | [item."C++14_boost"] 41 | 42 | [item."C++17"] 43 | 44 | [item."C++98"] 45 | 46 | [item."C++98_omp"] 47 | cmd = ["./swapview_omp"] 48 | dir = "C++98" 49 | 50 | [item.Crystal] 51 | 52 | [item.Crystal_fiber] 53 | cmd = ["./swapview_fiber"] 54 | dir = "Crystal" 55 | 56 | [item.Crystal_process] 57 | cmd = ["./swapview_process"] 58 | dir = "Crystal" 59 | 60 | [item.CSharp] 61 | cmd = ["mono-sgen", "--desktop", "SwapView.exe"] 62 | 63 | [item.ChezScheme] 64 | cmd = ["scheme", "--program", "swapview.so"] 65 | 66 | [item.Chicken] 67 | 68 | [item.CoffeeScript] 69 | cmd = ["node", "swapview.js"] 70 | 71 | [item.CoffeeScript_parallel] 72 | cmd = ["node", "swapview.js"] 73 | 74 | [item.CommonLisp_old] 75 | cmd = ["./swapview.lisp"] 76 | 77 | [item.CommonLisp_opt] 78 | 79 | [item.Cython] 80 | cmd = ["python", "-c", "import swapview"] 81 | 82 | [item.D] 83 | 84 | [item.D_llvm] 85 | cmd = ["./swapview-llvm"] 86 | dir = "D" 87 | 88 | [item.D_parallel] 89 | 90 | [item.D_parallel_llvm] 91 | cmd = ["./swapview-llvm"] 92 | dir = "D_parallel" 93 | 94 | [item.Dart] 95 | cmd = ["dart", "swapview.dart"] 96 | 97 | [item.Dart_native] 98 | cmd = ["./swapview"] 99 | dir = "Dart" 100 | 101 | [item.Elixir] 102 | cmd = ["./swapview.exs"] 103 | 104 | [item.Erlang] 105 | 106 | [item.FreePascal] 107 | 108 | [item.Go] 109 | 110 | [item.Go_goroutine] 111 | 112 | [item.Guile] 113 | cmd = ["./swapview.scm"] 114 | 115 | [item.Haskell] 116 | 117 | [item.Haskell_parallel] 118 | 119 | [item.Java] 120 | cmd = ["java", "-dsa", "-Xmixed", "-XX:CompileThreshold=4096", "-XX:+TieredCompilation", "-XX:TieredStopAtLevel=1", "-XX:+UseSerialGC", "SwapView"] 121 | 122 | [item.Julia] 123 | cmd = ["./swapview.jl"] 124 | 125 | [item.Lua51] 126 | cmd = ["lua5.1", "swapview.lua"] 127 | dir = "Lua" 128 | 129 | [item.Lua52] 130 | cmd = ["lua5.2", "swapview.lua"] 131 | dir = "Lua" 132 | 133 | [item.Lua53] 134 | cmd = ["lua5.3", "swapview.lua"] 135 | dir = "Lua" 136 | 137 | [item.Lua54] 138 | cmd = ["lua5.4", "swapview.lua"] 139 | dir = "Lua" 140 | 141 | [item.LuaJIT] 142 | cmd = ["luajit", "swapview.lua"] 143 | dir = "Lua" 144 | 145 | [item.newlisp] 146 | cmd = ["./swapview.lsp"] 147 | 148 | [item.newlisp_mp] 149 | cmd = ["./swapview.lsp"] 150 | 151 | [item.Nim] 152 | 153 | [item.NodeJS] 154 | cmd = ["./swapview.js"] 155 | 156 | [item.NodeJS_async] 157 | cmd = ["./swapview.js"] 158 | 159 | [item.NodeJS_cluster] 160 | cmd = ["node", "swapview.js"] 161 | 162 | [item.OCaml] 163 | 164 | [item.OCaml_lwt] 165 | 166 | [item.Perl] 167 | cmd = ["./swapview.pl"] 168 | 169 | [item.Perl_parallel] 170 | cmd = ["./swapview.pl"] 171 | 172 | [item.PHP] 173 | cmd = ["./swapview.php"] 174 | 175 | [item.PowerShell] 176 | cmd = ["./swapview.ps1"] 177 | 178 | [item.Python2] 179 | cmd = ["python2", "swapview.py"] 180 | dir = "Python" 181 | 182 | [item.Python3] 183 | cmd = ["python3", "swapview.py"] 184 | dir = "Python" 185 | 186 | [item.Python3_bytes] 187 | cmd = ["python3", "swapview.py"] 188 | 189 | [item.Python3_mp] 190 | cmd = ["python3", "swapview.py"] 191 | dir = "Python_mp" 192 | 193 | [item.PyPy] 194 | cmd = ["pypy", "swapview.py"] 195 | dir = "Python" 196 | 197 | [item.PyPy3] 198 | cmd = ["pypy3", "swapview.py"] 199 | dir = "Python" 200 | 201 | [item.PyPy3_bytes] 202 | cmd = ["pypy3", "swapview.py"] 203 | dir = "Python3_bytes" 204 | 205 | [item.R] 206 | cmd = ["./swapview.r"] 207 | 208 | [item.Racket] 209 | cmd = ["racket", "--no-compiled", "./swapview.rkt"] 210 | 211 | [item.Racket_compiled] 212 | dir = "Racket" 213 | cmd = ["racket", "swapview.rkt"] 214 | 215 | [item.Racket_parallel] 216 | dir = "Racket_parallel" 217 | cmd = ["racket", "compiled/swapview_rkt.zo"] 218 | 219 | [item.Ruby] 220 | cmd = ["./swapview.rb"] 221 | 222 | [item.Ruby_ractor] 223 | cmd = ["./swapview.rb"] 224 | 225 | [item.Ruby_rubinius] 226 | dir = "Ruby" 227 | cmd = ["rbx", "swapview.rb"] 228 | 229 | [item.Rust] 230 | 231 | [item.Rust_parallel] 232 | 233 | [item.Scala] 234 | cmd = ["scala", "SwapView"] 235 | 236 | [item.Tcl] 237 | cmd = ["./swapview.tcl"] 238 | 239 | [item.Typed_Racket] 240 | dir = "Typed_Racket" 241 | cmd = ["racket", "compiled/swapview_rkt.zo"] 242 | 243 | [item.Vala] 244 | 245 | [item.Zig] 246 | -------------------------------------------------------------------------------- /Typed_Racket/swapview.rkt: -------------------------------------------------------------------------------- 1 | #lang typed/racket/base 2 | 3 | (module shared typed/racket 4 | (require typed/racket/flonum) 5 | (provide resolve-pid make-table table-update! print-table 6 | Record Table PID) 7 | 8 | ;; types 9 | (define-type PID (U Exact-Positive-Integer Path-String)) 10 | (define-type Record (Pairof Exact-Positive-Integer String)) 11 | (define-type Table (HashTable Exact-Nonnegative-Integer (Listof String))) 12 | 13 | ;; bytes and integers 14 | (: get-integer (-> Bytes Exact-Nonnegative-Integer)) 15 | (define (get-integer bstr) 16 | (for/fold ((c : Exact-Nonnegative-Integer 0)) 17 | ((b (in-bytes bstr))) 18 | (define d (- b 48)) 19 | (if (and (>= d 0) (<= d 9)) (+ (* c 10) d) c))) 20 | (: bytes-prefix? (-> Bytes Bytes Boolean)) 21 | (define (bytes-prefix? b p) 22 | (and (>= (bytes-length b) (bytes-length p)) 23 | (for/and ((b1 (in-bytes b)) 24 | (b2 (in-bytes p))) 25 | (= b1 b2)))) 26 | ;; strings 27 | (: string-substitute! (-> String Char Char String)) 28 | (define (string-substitute! str o a) 29 | (for ((i (in-range 0 (string-length str))) 30 | #:when (char=? (string-ref str i) o)) 31 | (string-set! str i a)) 32 | str) 33 | 34 | ;; basic formatters 35 | (: format-pid (-> PID String)) 36 | (define (format-pid pid) (~a pid #:width 7 #:align 'right)) 37 | (: filesize (-> Exact-Nonnegative-Integer String)) 38 | (define (filesize size) 39 | (define n (* 1024 size)) 40 | (if (< n 1100) (format "~aB" n) 41 | (letrec ([const-base (fllog 1024.0)] 42 | [fn (->fl n)] 43 | [p (flfloor (fl/ (fllog (fl/ fn 1100.0)) const-base))] 44 | [s (~r (fl/ fn (flexpt 1024.0 (fl+ 1.0 p))) #:precision '(= 1))] 45 | [unit (string-ref "KMGT" (fl->exact-integer p))]) 46 | (format "~a~aiB" s unit)))) 47 | (: format-size (-> String String)) 48 | (define (format-size size) (~a size #:width 9 #:align 'right)) 49 | (: resolve-cmdline (-> String String)) 50 | (define (resolve-cmdline s) 51 | (let ([l (string-length s)] 52 | [o #\u0] 53 | [c #\ ]) 54 | (if (zero? l) 55 | s 56 | (string-substitute! (substring s 0 (- l 1)) o c)))) 57 | (: fmt1 (-> String String String String)) 58 | (define (fmt1 s1 s2 s3) 59 | (string-append-immutable s1 " " s2 " " s3)) 60 | (: total (-> String String)) 61 | (define (total n) 62 | (string-append "Total: " (~a n #:min-width 10 #:align 'right))) 63 | 64 | (: get-smaps (-> PID String)) 65 | (define (get-smaps pid) (format "/proc/~a/smaps" pid)) 66 | 67 | ;; readers 68 | (: get-size (-> Input-Port Exact-Nonnegative-Integer)) 69 | (define (get-size input) 70 | (for/fold ((r : Exact-Nonnegative-Integer 0)) 71 | ((l (in-bytes-lines input 'any)) 72 | #:when (bytes-prefix? l #"Swap: ")) 73 | (+ r (get-integer l)))) 74 | (define (get-cmdline pid) (file->string (format "/proc/~a/cmdline" pid))) 75 | 76 | (: resolve-pid (-> PID (U False Record))) 77 | (define (resolve-pid pid) 78 | (with-handlers ([exn:fail:filesystem? (lambda (exn) #f)]) 79 | (let ((v (call-with-input-file (get-smaps pid) get-size))) 80 | (if (zero? v) 81 | #f 82 | (cons v (fmt1 (format-pid pid) (format-size (filesize v)) (resolve-cmdline (get-cmdline pid)))))))) 83 | 84 | (: make-table (-> Table)) 85 | (define (make-table) 86 | (make-hasheq)) 87 | (: table-update! (-> Table Exact-Nonnegative-Integer String AnyValues)) 88 | (define (table-update! tbl k v) 89 | (define o (hash-ref tbl k #f)) 90 | (cond (o (hash-set*! tbl k (cons v o))) 91 | (else (hash-set*! tbl k (list v))))) 92 | (: print-table (-> Table AnyValues)) 93 | (define (print-table tbl) 94 | (define k-box ((inst box Exact-Nonnegative-Integer) 0)) 95 | (displayln (fmt1 (format-pid "PID") (format-size "SWAP") "COMMAND")) 96 | (hash-for-each 97 | tbl 98 | (lambda ((k : Exact-Nonnegative-Integer) (v : (Listof String))) 99 | ((inst for-each String) displayln v) 100 | (set-box! k-box (+ (unbox k-box) (* (length v) k)))) 101 | #t) 102 | (displayln (total (filesize (unbox k-box)))))) 103 | 104 | (module* main typed/racket 105 | (require (submod ".." shared)) 106 | (require/typed racket/base 107 | (in-directory (-> (U Path-String False) (-> Path-String Boolean) (Sequenceof Path-String)))) 108 | 109 | (: main (-> AnyValues)) 110 | (define (main) 111 | (define tbl (make-table)) 112 | (parameterize ((current-directory "/proc")) 113 | (for ((pid : Path-String (in-directory #f (lambda ((_ : Path-String)) #f)))) 114 | (define pair (resolve-pid pid)) 115 | (cond (pair (table-update! tbl (car pair) (cdr pair)))))) 116 | (print-table tbl)) 117 | 118 | (main) 119 | ) 120 | -------------------------------------------------------------------------------- /Zig/swapview.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | const ArrayList = std.ArrayList; 3 | 4 | const SwapInfo = struct { 5 | pid: usize, 6 | size: isize, 7 | comm: []const u8, 8 | }; 9 | const SwapInfoList = ArrayList(SwapInfo); 10 | const UNITS: [4]u8 = .{ 'K', 'M', 'G', 'T' }; 11 | 12 | fn getSwapSizeForProcess(allocator: std.mem.Allocator, pid: usize) !isize { 13 | var sum: isize = 0; 14 | 15 | var b: [40]u8 = undefined; 16 | const smaps_path = try std.fmt.bufPrint(&b, "/proc/{d}/smaps", .{pid}); 17 | const smaps_file = try std.fs.cwd().openFile(smaps_path, .{ .mode = .read_only }); 18 | defer smaps_file.close(); 19 | 20 | try smaps_file.seekTo(0); 21 | const content = try smaps_file.readToEndAlloc(allocator, std.math.maxInt(usize)); 22 | defer allocator.free(content); 23 | 24 | var iter = std.mem.split(u8, content, "\n"); 25 | while (iter.next()) |line| { 26 | if (std.mem.startsWith(u8, line, "Swap:")) { 27 | const string = line[5..(line.len-3)]; 28 | const value = std.mem.trim(u8, string, " "); 29 | const size = try std.fmt.parseInt(isize, value, 10); 30 | sum += size; 31 | } 32 | } 33 | return sum * 1024; 34 | } 35 | 36 | fn sanitizeCommandLine(allocator: std.mem.Allocator, str: []const u8) ![]const u8 { 37 | const len = str.len; 38 | var result = if ((len > 0) and (str[len-1] == '\x00')) 39 | str[0..(len-1)] 40 | else 41 | str; 42 | var buf = try allocator.alloc(u8, result.len); 43 | _ = std.mem.replace(u8, result, "\x00", " ", buf[0..]); 44 | return buf[0..result.len]; 45 | } 46 | 47 | test "sanitize command line" { 48 | const allocator = std.testing.allocator; 49 | const expect = std.testing.expect; 50 | var str = "This\x00is the\x00good!\x00\x00"; 51 | var result = try sanitizeCommandLine(allocator, str[0..]); 52 | defer allocator.free(result); 53 | try expect(std.mem.eql(u8, result, "This is the good! ")); 54 | } 55 | 56 | fn getCommandLineForProcess(allocator: std.mem.Allocator, pid: usize) ![]const u8 { 57 | var b: [40]u8 = undefined; 58 | const cmdline_path = try std.fmt.bufPrint(&b, "/proc/{d}/cmdline", .{pid}); 59 | const cmdline_file = try std.fs.cwd().openFile(cmdline_path, .{ .mode = .read_only }); 60 | defer cmdline_file.close(); 61 | 62 | try cmdline_file.seekTo(0); 63 | const content = try cmdline_file.readToEndAlloc(allocator, std.math.maxInt(usize)); 64 | defer allocator.free(content); 65 | 66 | return try sanitizeCommandLine(allocator, content); 67 | } 68 | 69 | fn getSwapInfoList(allocator: std.mem.Allocator, results: *SwapInfoList) !void { 70 | const dir = try std.fs.cwd().openIterableDir("/proc", .{}); 71 | var iter = dir.iterate(); 72 | while (try iter.next()) |entry| { 73 | // NOTE: skip unreadable files 74 | const pid = std.fmt.parseInt(usize, entry.name, 10) catch continue; 75 | const size = getSwapSizeForProcess(allocator, pid) catch continue; 76 | if (size > 0) { 77 | const comm = getCommandLineForProcess(allocator, pid) catch continue; 78 | const info = SwapInfo{ 79 | .pid = pid, 80 | .size = size, 81 | .comm = comm, 82 | }; 83 | try results.append(info); 84 | } 85 | } 86 | } 87 | 88 | fn lessThan(_:void, lhs: SwapInfo, rhs: SwapInfo) bool { 89 | return lhs.size < rhs.size; 90 | } 91 | 92 | fn formatFileSize(allocator: std.mem.Allocator, size: isize) ![]const u8 { 93 | var left = @as(f64, @floatFromInt(size)); 94 | var unit: i4 = -1; 95 | while ((left > 1100) and (unit < 3)) { 96 | left /= 1024; 97 | unit +=1; 98 | } 99 | if (unit == -1) { 100 | return try std.fmt.allocPrint(allocator, "{d}B", .{size}); 101 | } else { 102 | if (size < 0) left = -left; 103 | const index: u4 = @as(*u4, @ptrCast(&unit)).*; 104 | return try std.fmt.allocPrint(allocator, "{d:.1}{c}iB", .{left, UNITS[index]}); 105 | } 106 | } 107 | 108 | fn perform(allocator: std.mem.Allocator) !void { 109 | var results = SwapInfoList.init(allocator); 110 | try getSwapInfoList(allocator, &results); 111 | defer results.deinit(); 112 | 113 | std.sort.block(SwapInfo, results.items, {}, lessThan); 114 | var total: isize = 0; 115 | 116 | const stdout = std.io.getStdOut().writer(); 117 | 118 | try stdout.print("{s:>7} {s:>9} {s}\n", .{"PID", "SWAP", "COMMAND"}); 119 | for (results.items) |info| { 120 | defer allocator.free(info.comm); 121 | 122 | const size_h = try formatFileSize(allocator, info.size); 123 | defer allocator.free(size_h); 124 | 125 | try stdout.print("{d:>7} {s:>9} {s}\n", .{info.pid, size_h, info.comm}); 126 | total += info.size; 127 | } 128 | const file_size_text = try formatFileSize(allocator, total); 129 | defer allocator.free(file_size_text); 130 | try stdout.print("Total: {s:>10}\n", .{file_size_text}); 131 | } 132 | 133 | test "perform" { 134 | const allocator = std.testing.allocator; 135 | 136 | try perform(allocator); 137 | } 138 | 139 | pub fn main() !void { 140 | var gpa = std.heap.GeneralPurposeAllocator(.{}){}; 141 | const allocator = gpa.allocator(); 142 | 143 | try perform(allocator); 144 | } 145 | -------------------------------------------------------------------------------- /Racket_parallel/swapview.rkt: -------------------------------------------------------------------------------- 1 | #lang racket/base 2 | 3 | (module shared racket/base 4 | (#%declare #:unsafe) 5 | (require (only-in racket/flonum fllog fl/ fl+ flexpt flfloor ->fl fl->exact-integer) 6 | (submod racket/performance-hint begin-encourage-inline) 7 | (only-in racket/file file->string) 8 | (only-in racket/format ~a ~r)) 9 | (provide resolve-pid make-table table-update! print-table) 10 | 11 | (begin-encourage-inline 12 | ;; bytes and integers 13 | (define (digit? byte) 14 | (and (>= byte 48) (<= byte 57))) 15 | (define (get-integer bstr) 16 | (for/fold ((c 0)) 17 | ((b (in-bytes bstr)) 18 | #:when (digit? b)) 19 | (+ (* c 10) (- b 48)))) 20 | (define (bytes-prefix? b p) 21 | (and (>= (bytes-length b) (bytes-length p)) 22 | (for/and ((b1 (in-bytes b)) 23 | (b2 (in-bytes p))) 24 | (= b1 b2)))) 25 | 26 | ;; strings 27 | (define (string-substitute! str o a) 28 | (for ((i (in-range 0 (string-length str))) 29 | #:when (char=? (string-ref str i) o)) 30 | (string-set! str i a)) 31 | str) 32 | 33 | ;; basic formatters 34 | (define (format-pid pid) (~a pid #:width 7 #:align 'right)) 35 | (define (filesize size) 36 | (define n (* 1024 size)) 37 | (if (< n 1100) (format "~aB" n) 38 | (letrec ([const-base (fllog 1024.0)] 39 | [fn (->fl n)] 40 | [p (flfloor (fl/ (fllog (fl/ fn 1100.0)) const-base))] 41 | [s (~r (fl/ fn (flexpt 1024.0 (fl+ 1.0 p))) #:precision '(= 1))] 42 | [unit (string-ref "KMGT" (fl->exact-integer p))]) 43 | (format "~a~aiB" s unit)))) 44 | (define (format-size size) (~a size #:width 9 #:align 'right)) 45 | (define (resolve-cmdline s) 46 | (let ([l (string-length s)] 47 | [o #\u0] 48 | [c #\ ]) 49 | (if (zero? l) 50 | s 51 | (string-substitute! (substring s 0 (- l 1)) o c)))) 52 | (define (fmt1 s1 s2 s3) 53 | (string-append-immutable s1 " " s2 " " s3)) 54 | (define (total n) 55 | (string-append "Total: " (~a n #:min-width 10 #:align 'right))) 56 | 57 | (define (get-smaps pid) (format "/proc/~a/smaps" pid)) 58 | 59 | ;; readers 60 | (define (get-size input) 61 | (for/fold ((r 0)) 62 | ((l (in-bytes-lines input 'any)) 63 | #:when (bytes-prefix? l #"Swap: ")) 64 | (+ r (get-integer l)))) 65 | (define (get-cmdline pid) (file->string (format "/proc/~a/cmdline" pid))) 66 | 67 | (define (resolve-pid pid) 68 | (with-handlers ([exn:fail:filesystem? (lambda (exn) #f)]) 69 | (let ((v (call-with-input-file (get-smaps pid) get-size))) 70 | (if (zero? v) 71 | #f 72 | (cons v (fmt1 (format-pid pid) (format-size (filesize v)) (resolve-cmdline (get-cmdline pid)))))))) 73 | 74 | ;; (hash/c exact-positive-integer? (listof string?)) 75 | (define (make-table) 76 | (make-hasheq)) 77 | (define (table-update! tbl k v) 78 | (define o (hash-ref tbl k #f)) 79 | (cond (o (hash-set*! tbl k (cons v o))) 80 | (else (hash-set*! tbl k (list v))))) 81 | (define (print-table tbl) 82 | (define k-box (box 0)) 83 | (displayln (fmt1 (format-pid "PID") (format-size "SWAP") "COMMAND")) 84 | (hash-for-each 85 | tbl 86 | (lambda (k v) 87 | (for-each displayln v) 88 | (set-box*! k-box (+ (unbox* k-box) (* (length v) k)))) 89 | #t) 90 | (displayln (total (filesize (unbox* k-box))))))) 91 | 92 | (module* helper racket/base 93 | (#%declare #:unsafe) 94 | (require (submod ".." shared) 95 | (only-in racket/place place/context place-channel-put place-channel)) 96 | (provide main) 97 | 98 | (define (main) 99 | (define (make-place com-ch) 100 | (let ((pl (place/context ch 101 | (for ((pid (in-producer sync #f ch))) 102 | (define v (resolve-pid pid)) 103 | (cond (v (place-channel-put com-ch v)))) 104 | (place-channel-put com-ch #f)))) 105 | pl)) 106 | 107 | (define-values (out-channel in-channel) (place-channel)) 108 | 109 | (define (send chp v) 110 | (place-channel-put chp v)) 111 | (define (make-recv n) 112 | (let ((cnt-box (box n))) 113 | (lambda (chp) 114 | (let loop () 115 | (sync 116 | (handle-evt 117 | chp 118 | (lambda (v) 119 | (cond (v) 120 | ((= (unbox* cnt-box) 1) #f) 121 | (else (set-box*! cnt-box (- (unbox* cnt-box) 1)) 122 | (loop)))))))))) 123 | 124 | (define place-number 2) 125 | 126 | (let ((chp-lst (build-list place-number (lambda (_) (make-place out-channel))))) 127 | (parameterize ((current-directory "/proc")) 128 | (for ((v (in-directory #f (lambda (_) #f))) (chp (in-cycle (in-list chp-lst)))) 129 | (send chp v))) 130 | (for-each (lambda (chp) (send chp #f)) chp-lst)) 131 | 132 | (define tbl (make-table)) 133 | 134 | (for ((v (in-producer (make-recv place-number) #f in-channel))) 135 | (table-update! tbl (car v) (cdr v))) 136 | (print-table tbl))) 137 | 138 | (module* main racket/base 139 | (require (submod ".." helper)) 140 | 141 | (main)) 142 | -------------------------------------------------------------------------------- /bench.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from __future__ import print_function 4 | 5 | import sys 6 | import resource 7 | import time 8 | from difflib import (SequenceMatcher, unified_diff) 9 | from string import Template 10 | from subprocess import Popen, PIPE 11 | from statistics import (mean, stdev) 12 | 13 | import pytoml 14 | 15 | rusage_names = """ru_utime 16 | ru_stime 17 | ru_maxrss 18 | ru_ixrss 19 | ru_idrss 20 | ru_isrss 21 | ru_minflt 22 | ru_majflt 23 | ru_nswap 24 | ru_inblock 25 | ru_oublock 26 | ru_msgsnd 27 | ru_msgrcv 28 | ru_nsignals 29 | ru_nvcsw 30 | ru_nivcsw""".split('\n') 31 | 32 | 33 | def die(msg): 34 | print(msg, file=sys.stderr) 35 | sys.exit(1) 36 | 37 | 38 | def run_profile(cmd, dir, time_limit, **kwargs): 39 | start_usage = resource.getrusage(resource.RUSAGE_CHILDREN) 40 | out, err = '', '' 41 | returncode = 0 42 | start_time = time.time() 43 | proc = Popen(cmd, stdout=PIPE, stderr=PIPE, 44 | cwd=dir, shell=False, universal_newlines=True) 45 | out, err = proc.communicate(timeout=time_limit) 46 | returncode = proc.returncode 47 | end_usage = resource.getrusage(resource.RUSAGE_CHILDREN) 48 | end_time = time.time() 49 | usage = dict(zip(rusage_names, 50 | map(lambda x: x[1] - x[0], zip(start_usage, end_usage)))) 51 | usage['elapsed'] = end_time - start_time 52 | return out, err, returncode, usage 53 | 54 | 55 | def _key(l): 56 | pid, data, cmd = l.split(None, 2) 57 | return data, cmd, pid 58 | 59 | 60 | def stable_sort(lines): 61 | if len(lines) < 2: 62 | return 63 | lines[1:-2] = sorted(lines[1:-2], key=_key) 64 | 65 | 66 | def bench_profile(profile, ref_result_out, verbose, 67 | time_field, show_diff_below, **kwargs): 68 | try: 69 | out, err, ret, usage = run_profile(**profile) 70 | except KeyboardInterrupt: 71 | die("Keyboard Interrupt from user") 72 | except: 73 | out, err, ret, usage = ( 74 | "", ('Error cmd: %s\n' % " ".join(profile['cmd'])), 1, dict(elapsed=0)) 75 | outlines = out.split('\n') 76 | stable_sort(outlines) 77 | ref_outlines = ref_result_out.split('\n') 78 | stable_sort(ref_outlines) 79 | ratio = SequenceMatcher(None, outlines, ref_outlines).ratio() 80 | profile['ratio'] = ratio 81 | if verbose: 82 | print('\033[1;%dm%-24s\033[m(%3d%%): %8.2f %s' % 83 | (32 if ret == 0 else 31, 84 | profile['name'], int(ratio * 100), 85 | usage[time_field] * 1000, err[: -1])) 86 | if ret == 0 and ratio < show_diff_below: 87 | print('$\n'.join(unified_diff( 88 | ref_outlines, outlines, fromfile='reference result', 89 | tofile=profile['name'], n=0, lineterm='')), 90 | end = '$\n', 91 | ) 92 | return out, err[:-1], ret, usage 93 | 94 | 95 | def load_config(): 96 | filename = sys.argv[1] if len(sys.argv) > 1 else 'benchmark.toml' 97 | with open(filename) as configfile: 98 | config = pytoml.loads(configfile.read()) 99 | items = config['item'] 100 | default = items['default'] 101 | if 'options' in config: 102 | options = config['options'] 103 | else: 104 | options = dict(ref_result="C", 105 | time_field="elapsed", 106 | show_diff_below=0.9, 107 | verbose=True) 108 | ret_items = {} 109 | for name, item in zip(items, items.values()): 110 | if name == 'default': 111 | continue 112 | if name.startswith('"') and name.endswith('"'): 113 | import ast 114 | name = ast.literal_eval(name) 115 | profile = dict(default) 116 | profile.update(item) 117 | profile['name'] = name 118 | for k, v in zip(profile, profile.values()): 119 | if type(v) is str: 120 | profile[k] = Template(v).safe_substitute(**profile) 121 | ret_items[name] = profile 122 | return ret_items, options 123 | 124 | 125 | def times2str(item): 126 | time = item['time'] 127 | valid = sorted(time)[:int(item['valid_percent'] * len(time) / 100)] 128 | avgv = mean(valid) 129 | return "%s %s %4d" % ('%8.2f' % (avgv * 1000), 130 | ' '.join(('%8.2f' % (x(time) * 1000)) 131 | for x in (min, mean, max, stdev)), 132 | len(time)) 133 | 134 | 135 | def main(): 136 | items, options = load_config() 137 | succ, fails = [], [] 138 | for item in sorted(items.values(), key=lambda x: x['name']): 139 | ref_out, err, ret, _ = run_profile(**items[options["ref_result"]]) 140 | if ret != 0: 141 | die("reference implementation failed") 142 | out, err, ret, usage = bench_profile(item, ref_out, **options) 143 | item['time'] = [usage[options['time_field']]] 144 | if ret == 0: 145 | for i in range(item['count_limit'] - 1): 146 | _, err, _, usage = bench_profile(item, ref_out, **options) 147 | item['time'].append(usage[options['time_field']]) 148 | succ.append(item) 149 | else: 150 | item['error'] = err 151 | fails.append(item) 152 | 153 | print(("---------Results--------(Diff):" + 154 | " KMinAvg Min Avg Max Stdev Cnt")) 155 | 156 | succ.sort(key=lambda x: 157 | sum(sorted(x['time']) 158 | [:int(x['valid_percent'] * x['count_limit'] / 100)])) 159 | for item in succ: 160 | print('\033[1;%dm%-24s\033[m(%3d%%): %s' % 161 | (33 if item['ratio'] < options['show_diff_below'] else 32, 162 | item['name'], int(item['ratio'] * 100), times2str(item))) 163 | 164 | print("------------Fails-------------------") 165 | for item in fails: 166 | print('\033[1;31m%-24s\033[m : %s' % 167 | (item['name'], item['error'])) 168 | 169 | if __name__ == '__main__': 170 | main() 171 | -------------------------------------------------------------------------------- /result-20160630.txt: -------------------------------------------------------------------------------- 1 |  C++98_omp: top:  74.73, min: 66.75, avg: 80.83, max: 98.24, mdev: 7.60, cnt: 20 2 |  C: top:  127.29, min: 126.11, avg: 129.39, max: 135.80, mdev: 2.52, cnt: 20 3 |  C++98: top:  130.31, min: 129.05, avg: 132.34, max: 139.47, mdev: 2.64, cnt: 20 4 |  Nim: top:  130.38, min: 128.58, avg: 137.71, max: 175.65, mdev: 13.85, cnt: 20 5 |  C++14: top:  130.71, min: 129.39, avg: 136.72, max: 160.87, mdev: 9.22, cnt: 20 6 |  C++14_boost: top:  131.28, min: 130.52, avg: 133.39, max: 141.74, mdev: 2.85, cnt: 20 7 |  Rust_parallel: top:  140.81, min: 112.09, avg: 152.31, max: 181.36, mdev: 15.86, cnt: 20 8 |  Go_goroutine: top:  144.36, min: 120.02, avg: 162.45, max: 236.54, mdev: 25.14, cnt: 20 9 |  D_parallel_llvm: top:  156.60, min: 147.47, avg: 181.32, max: 241.03, mdev: 30.52, cnt: 20 10 |  D_parallel: top:  157.24, min: 150.02, avg: 172.33, max: 221.68, mdev: 19.69, cnt: 20 11 |  Rust: top:  163.32, min: 141.11, avg: 180.63, max: 254.20, mdev: 26.55, cnt: 20 12 |  OCaml: top:  174.59, min: 167.63, avg: 184.09, max: 209.87, mdev: 12.69, cnt: 20 13 |  PHP: top:  185.03, min: 176.63, avg: 193.54, max: 228.99, mdev: 12.23, cnt: 20 14 |  LuaJIT: top:  185.23, min: 183.01, avg: 189.70, max: 208.75, mdev: 6.57, cnt: 20 15 |  D_llvm: top:  188.85, min: 185.56, avg: 194.24, max: 226.12, mdev: 9.13, cnt: 20 16 |  Go: top:  188.96, min: 185.57, avg: 195.25, max: 218.36, mdev: 8.92, cnt: 20 17 |  Haskell2: top:  200.23, min: 196.68, avg: 210.17, max: 303.74, mdev: 24.02, cnt: 20 18 |  D: top:  206.18, min: 202.35, avg: 212.35, max: 240.61, mdev: 10.08, cnt: 20 19 |  Lua51: top:  219.65, min: 217.46, avg: 227.44, max: 282.32, mdev: 15.12, cnt: 20 20 |  Python2: top:  221.80, min: 216.60, avg: 231.70, max: 292.08, mdev: 16.51, cnt: 20 21 |  Lua52: top:  225.89, min: 220.27, avg: 230.43, max: 252.03, mdev: 6.89, cnt: 20 22 |  NodeJS: top:  231.00, min: 227.71, avg: 234.71, max: 242.62, mdev: 4.22, cnt: 20 23 |  Lua53: top:  235.73, min: 232.38, avg: 242.27, max: 278.49, mdev: 10.49, cnt: 20 24 |  Vala: top:  238.68, min: 235.69, avg: 248.14, max: 296.29, mdev: 14.87, cnt: 20 25 |  FreePascal: top:  239.32, min: 236.86, avg: 251.10, max: 288.25, mdev: 15.65, cnt: 20 26 |  Perl: top:  261.46, min: 257.73, avg: 278.10, max: 340.33, mdev: 25.94, cnt: 20 27 |  Python3_bytes: top:  261.76, min: 259.26, avg: 269.99, max: 299.11, mdev: 11.54, cnt: 20 28 |  PyPy3_bytes: top:  277.98, min: 273.41, avg: 297.01, max: 410.77, mdev: 38.60, cnt: 20 29 |  PyPy: top:  290.85, min: 284.78, avg: 317.91, max: 434.03, mdev: 39.05, cnt: 20 30 |  Python3: top:  305.46, min: 301.06, avg: 315.28, max: 357.00, mdev: 14.32, cnt: 20 31 |  Ruby: top:  309.99, min: 304.72, avg: 327.48, max: 372.77, mdev: 21.87, cnt: 20 32 |  NodeJS_parallel: top:  326.85, min: 316.24, avg: 347.25, max: 451.25, mdev: 34.91, cnt: 20 33 |  Chicken: top:  329.45, min: 322.71, avg: 353.39, max: 513.69, mdev: 42.01, cnt: 20 34 |  Erlang: top:  366.50, min: 339.11, avg: 390.16, max: 476.80, mdev: 31.00, cnt: 20 35 |  ChezScheme: top:  406.35, min: 399.14, avg: 429.98, max: 528.54, mdev: 33.57, cnt: 20 36 |  PyPy3: top:  422.61, min: 418.73, avg: 427.92, max: 450.91, mdev: 7.45, cnt: 20 37 |  Tcl: top:  466.96, min: 459.65, avg: 475.79, max: 522.68, mdev: 14.41, cnt: 20 38 |  CSharp: top:  468.89, min: 396.01, avg: 500.82, max: 631.11, mdev: 47.88, cnt: 20 39 |  CoffeeScript_parallel: top:  564.80, min: 351.00, avg: 613.40, max: 752.75, mdev: 77.55, cnt: 20 40 |  CoffeeScript: top:  567.97, min: 471.83, avg: 601.48, max: 661.47, mdev: 43.20, cnt: 20 41 |  NodeJS_async: top:  660.61, min: 633.43, avg: 687.55, max: 796.57, mdev: 36.33, cnt: 20 42 |  Java: top:  853.59, min: 824.68, avg: 887.36, max: 1016.02, mdev: 45.10, cnt: 20 43 |  Dart: top:  918.39, min: 705.92, avg: 987.41, max: 1084.45, mdev: 4187.41, cnt: 20 44 |  Racket: top: 1022.06, min: 755.98, avg: 1068.39, max: 1166.63, mdev: 4187.11, cnt: 20 45 |  CommonLisp_old: top: 1070.15, min: 896.43, avg: 1113.44, max: 1243.69, mdev: 4186.87, cnt: 20 46 |  CommonLisp_opt: top: 1086.13, min: 1067.23, avg: 1107.29, max: 1199.43, mdev: 4186.33, cnt: 20 47 |  Racket_compiled: top: 1088.63, min: 1059.70, avg: 1118.23, max: 1239.85, mdev: 4186.42, cnt: 20 48 |  Scala: top: 1139.17, min: 929.79, avg: 1192.92, max: 1406.76, mdev: 4187.09, cnt: 20 49 |  Guile: top: 1188.32, min: 1167.39, avg: 1225.72, max: 1393.59, mdev: 4186.66, cnt: 20 50 |  Haskell: top: 1192.15, min: 1013.50, avg: 1227.01, max: 1314.85, mdev: 4186.65, cnt: 20 51 |  Elixir: top: 1247.25, min: 1212.52, avg: 1322.45, max: 1615.08, mdev: 4187.53, cnt: 20 52 |  Julia: top: 1270.19, min: 984.37, avg: 1342.39, max: 1462.14, mdev: 4187.93, cnt: 20 53 |  Bash: top: 1783.38, min: 1769.13, avg: 1811.78, max: 1913.25, mdev: 3897.83, cnt: 17 54 |  Ruby_rubinius: top: 1968.79, min: 1864.61, avg: 2019.64, max: 2141.07, mdev: 3842.18, cnt: 15 55 |  POSIX_dash: top: 2011.66, min: 1955.63, avg: 2145.52, max: 2454.85, mdev: 3810.43, cnt: 14 56 |  R: top: 2063.77, min: 2047.02, avg: 2127.87, max: 2529.48, mdev: 3843.32, cnt: 15 57 |  POSIX_zsh: top: 2197.11, min: 2161.49, avg: 2271.15, max: 2425.82, mdev: 3808.04, cnt: 14 58 |  Bash_parallel: top: 2242.45, min: 2204.63, avg: 2357.10, max: 2647.63, mdev: 3770.02, cnt: 13 59 |  POSIX_bash: top: 2427.49, min: 2370.05, avg: 2506.06, max: 2835.54, mdev: 3508.84, cnt: 12 60 | -------------------------------------------------------------------------------- /result-20170714.txt: -------------------------------------------------------------------------------- 1 |  Rust_parallel: top:  30.48, min: 27.76, avg: 32.48, max: 37.80, mdev: 2.78, cnt: 20 2 |  C++98_omp: top:  31.24, min: 29.04, avg: 34.42, max: 49.48, mdev: 4.52, cnt: 20 3 |  Go_goroutine: top:  68.30, min: 61.87, avg: 75.89, max: 142.91, mdev: 16.39, cnt: 20 4 |  C++14: top:  83.17, min: 82.23, avg: 84.71, max: 92.58, mdev: 2.76, cnt: 20 5 |  C++14_boost: top:  83.58, min: 83.20, avg: 84.58, max: 91.00, mdev: 1.72, cnt: 20 6 |  C++98: top:  83.71, min: 83.09, avg: 85.19, max: 91.48, mdev: 2.44, cnt: 20 7 |  Rust: top:  91.45, min: 90.81, avg: 93.08, max: 99.38, mdev: 2.07, cnt: 20 8 |  C: top:  91.49, min: 90.49, avg: 93.41, max: 99.44, mdev: 2.53, cnt: 20 9 |  C++11: top:  91.81, min: 91.33, avg: 93.52, max: 102.80, mdev: 3.04, cnt: 20 10 |  PHP: top:  93.91, min: 93.37, avg: 94.98, max: 99.42, mdev: 1.47, cnt: 20 11 |  OCaml: top:  106.85, min: 105.75, avg: 109.34, max: 118.03, mdev: 3.37, cnt: 20 12 |  Nim: top:  109.28, min: 108.44, avg: 110.75, max: 117.43, mdev: 2.13, cnt: 20 13 |  D_parallel_llvm: top:  111.25, min: 109.43, avg: 113.21, max: 117.26, mdev: 2.33, cnt: 20 14 |  D_parallel: top:  116.77, min: 114.69, avg: 118.95, max: 125.45, mdev: 2.87, cnt: 20 15 |  PyPy: top:  126.23, min: 124.29, avg: 128.34, max: 134.07, mdev: 2.79, cnt: 20 16 |  D_llvm: top:  129.63, min: 128.52, avg: 131.32, max: 137.65, mdev: 2.41, cnt: 20 17 |  LuaJIT: top:  132.68, min: 131.31, avg: 134.36, max: 143.07, mdev: 2.57, cnt: 20 18 |  Go: top:  135.57, min: 132.37, avg: 139.25, max: 148.37, mdev: 4.50, cnt: 20 19 |  D: top:  146.30, min: 145.00, avg: 149.14, max: 159.02, mdev: 3.85, cnt: 20 20 |  Haskell2: top:  150.92, min: 149.41, avg: 153.25, max: 164.60, mdev: 3.53, cnt: 20 21 |  Python2: top:  155.36, min: 152.26, avg: 158.55, max: 170.20, mdev: 4.60, cnt: 20 22 |  Vala: top:  159.55, min: 157.87, avg: 161.40, max: 166.52, mdev: 2.26, cnt: 20 23 |  Erlang: top:  163.00, min: 158.63, avg: 168.76, max: 181.77, mdev: 7.09, cnt: 20 24 |  Lua51: top:  166.58, min: 164.58, avg: 168.89, max: 181.71, mdev: 3.69, cnt: 20 25 |  Lua52: top:  168.48, min: 167.40, avg: 170.82, max: 178.11, mdev: 3.36, cnt: 20 26 |  Python3_bytes: top:  174.30, min: 172.65, avg: 176.83, max: 181.64, mdev: 2.91, cnt: 20 27 |  Lua53: top:  180.20, min: 177.79, avg: 185.01, max: 199.41, mdev: 6.07, cnt: 20 28 |  Perl: top:  180.22, min: 177.30, avg: 182.21, max: 186.09, mdev: 2.44, cnt: 20 29 |  FreePascal: top:  180.85, min: 179.35, avg: 184.23, max: 197.83, mdev: 4.84, cnt: 20 30 |  Python3: top:  181.72, min: 178.47, avg: 184.09, max: 189.67, mdev: 2.99, cnt: 20 31 |  Ruby: top:  199.82, min: 197.16, avg: 203.62, max: 218.32, mdev: 4.92, cnt: 20 32 |  Chicken: top:  234.69, min: 232.11, avg: 239.61, max: 248.39, mdev: 5.63, cnt: 20 33 |  PyPy3_bytes: top:  238.55, min: 237.18, avg: 242.08, max: 253.68, mdev: 4.53, cnt: 20 34 |  Guile: top:  254.49, min: 249.14, avg: 260.40, max: 275.83, mdev: 7.12, cnt: 20 35 |  ChezScheme: top:  265.63, min: 262.52, avg: 268.56, max: 278.53, mdev: 3.94, cnt: 20 36 |  Java: top:  291.35, min: 283.94, avg: 302.36, max: 324.82, mdev: 12.38, cnt: 20 37 |  NodeJS: top:  317.01, min: 314.61, avg: 321.04, max: 332.05, mdev: 4.71, cnt: 20 38 |  Dart: top:  329.39, min: 325.63, avg: 334.57, max: 351.19, mdev: 6.92, cnt: 20 39 |  Ruby_rubinius: top:  359.76, min: 357.74, avg: 363.13, max: 373.02, mdev: 4.45, cnt: 20 40 |  CommonLisp_opt: top:  360.57, min: 358.41, avg: 365.15, max: 378.44, mdev: 5.76, cnt: 20 41 |  Tcl: top:  367.38, min: 363.28, avg: 372.89, max: 388.57, mdev: 6.65, cnt: 20 42 |  CommonLisp_old: top:  376.27, min: 371.99, avg: 379.66, max: 390.55, mdev: 4.33, cnt: 20 43 |  PyPy3: top:  384.12, min: 376.60, avg: 390.16, max: 401.39, mdev: 7.32, cnt: 20 44 |  CoffeeScript: top:  414.40, min: 393.13, avg: 432.25, max: 466.42, mdev: 20.64, cnt: 20 45 |  CoffeeScript_parallel: top:  451.12, min: 425.11, avg: 464.92, max: 491.52, mdev: 17.05, cnt: 20 46 |  NodeJS_async: top:  454.78, min: 437.13, avg: 465.18, max: 489.06, mdev: 13.02, cnt: 20 47 |  Racket_compiled: top:  510.97, min: 505.22, avg: 516.20, max: 527.69, mdev: 6.23, cnt: 20 48 |  Racket: top:  520.70, min: 515.11, avg: 525.28, max: 533.79, mdev: 5.87, cnt: 20 49 |  NodeJS_parallel: top:  673.38, min: 664.38, avg: 687.60, max: 724.04, mdev: 16.32, cnt: 20 50 |  Scala: top:  719.27, min: 698.23, avg: 740.32, max: 815.95, mdev: 27.27, cnt: 20 51 |  Bash_parallel: top:  769.14, min: 751.56, avg: 775.91, max: 791.40, mdev: 8.82, cnt: 20 52 |  Haskell: top: 1036.33, min: 1013.27, avg: 1048.70, max: 1090.21, mdev: 4186.25, cnt: 20 53 |  Elixir: top: 1097.32, min: 1075.24, avg: 1113.36, max: 1144.80, mdev: 4186.26, cnt: 20 54 |  R: top: 1141.37, min: 1120.69, avg: 1156.42, max: 1177.79, mdev: 4186.26, cnt: 20 55 |  Bash: top: 1368.00, min: 1323.22, avg: 1479.66, max: 1994.19, mdev: 4077.71, cnt: 20 56 |  POSIX_dash: top: 1841.09, min: 1833.25, avg: 1851.09, max: 1881.68, mdev: 3897.64, cnt: 17 57 |  POSIX_zsh: top: 2124.79, min: 2110.81, avg: 2134.32, max: 2156.40, mdev: 3841.56, cnt: 15 58 |  POSIX_bash: top: 2200.64, min: 2195.09, avg: 2206.75, max: 2221.41, mdev: 3807.09, cnt: 14 59 |  CSharp: FAILED with entity not found 60 |  Julia: FAILED with entity not found 61 | --------------------------------------------------------------------------------