! Copyright (C) 2013 Doug Coleman. ! See http://factorcode.org/license.txt for BSD license. USING: accessors arrays combinators combinators.smart io.encodings.utf8 io.files kernel math math.order math.parser memoize sequences sorting.slots splitting splitting.monotonic strings io.pathnames calendar ; IN: unix.linux.proc ! /proc/* ! /proc/buddyinfo ! /proc/cgroups TUPLE: proc-cmdline string ; C: proc-cmdline : parse-proc-cmdline ( -- obj ) "/proc/cmdline" utf8 file-lines first ; TUPLE: processor-info { processor integer } { vendor-id string } { cpu-family integer } { model integer } { model-name string } { stepping integer } { microcode integer } { cpu-mhz number } { cache-size integer } { fdiv-bug? boolean } { hlt-bug? boolean } { f00f-bug? boolean } { coma-bug? boolean } { physical-id integer } { siblings integer } { core-id integer } { cpu-cores integer } { apicid integer } { initial-apicid integer } { fpu? boolean } { fpu-exception? boolean } { cpuid-level integer } { wp? boolean } { flags array } { bogomips number } { clflush-size integer } { cache-alignment integer } { address-sizes array } { power-management string } ; ERROR: unknown-cpuinfo-line string ; : line>processor-info ( processor-info string -- processor-info ) ":" split first2 swap [ CHAR: \t = ] trim-tail [ [ CHAR: \s = ] trim ] bi@ { { "address sizes" [ "," split [ [ CHAR: \s = ] trim " " split first string>number ] map >>address-sizes ] } { "apicid" [ string>number >>apicid ] } { "bogomips" [ string>number >>bogomips ] } { "cache size" [ " " split first [ CHAR: \s = ] trim string>number 1024 * >>cache-size ] } { "cache_alignment" [ string>number >>cache-alignment ] } { "clflush size" [ string>number >>clflush-size ] } { "coma_bug" [ "yes" = >>coma-bug? ] } { "core id" [ string>number >>core-id ] } { "cpu MHz" [ string>number >>cpu-mhz ] } { "cpu cores" [ string>number >>cpu-cores ] } { "cpu family" [ string>number >>cpu-family ] } { "cpuid level" [ string>number >>cpuid-level ] } { "f00f_bug" [ "yes" = >>f00f-bug? ] } { "fdiv_bug" [ "yes" = >>fdiv-bug? ] } { "flags" [ " " split harvest >>flags ] } { "fpu" [ "yes" = >>fpu? ] } { "fpu_exception" [ "yes" = >>fpu-exception? ] } { "hlt_bug" [ "yes" = >>hlt-bug? ] } { "initial apicid" [ string>number >>initial-apicid ] } { "microcode" [ string>number >>microcode ] } { "model" [ string>number >>model ] } { "model name" [ >>model-name ] } { "physical id" [ string>number >>physical-id ] } { "power management" [ >>power-management ] } { "processor" [ string>number >>processor ] } { "siblings" [ string>number >>siblings ] } { "stepping" [ string>number >>stepping ] } { "vendor_id" [ >>vendor-id ] } { "wp" [ "yes" = >>wp? ] } [ unknown-cpuinfo-line ] } case ; ! Linux 2.6 has fewer values than new kernels : lines>processor-info ( strings -- processor-info ) [ processor-info new ] dip [ line>processor-info ] each ; : parse-proc-cpuinfo ( -- seq ) "/proc/cpuinfo" utf8 file-lines { "" } split harvest [ lines>processor-info ] map ; : sort-cpus ( seq -- seq ) { { physical-id>> <=> } { core-id>> <=> } } sort-by [ [ physical-id>> ] bi@ = ] monotonic-split [ [ [ core-id>> ] bi@ = ] monotonic-split ] map ; : cpu-counts ( seq -- #cpus #cores #hyperthread ) [ length ] [ [ length ] map-sum ] [ [ [ length ] map-sum ] map-sum ] tri ; TUPLE: proc-loadavg load-average-1 load-average-5 load-average-15 #processes-executing #processes-total last-pid ; : parse-proc-loadavg ( -- obj ) "/proc/loadavg" utf8 file-lines first " " split [ { [ string>number ] [ string>number ] [ string>number ] [ "/" split1 [ string>number ] bi@ ] [ string>number ] } spread ] inputnumber 1024 * ] map [ proc-meminfo boa ] inputcpu ( string -- cpu ) " " split unclip-slice [ [ [ CHAR: \s = ] trim string>number ] map ] dip prefix [ proc-cpu-stat boa ] inputcpu ] [ second [ line>cpu ] map ] [ third [ " " split1 nip " " split [ string>number ] map ] map [ { [ ] [ first ] [ first ] [ first ] [ first ] [ first ] [ ] } spread ] input> ; TUPLE: proc-partition major minor #blocks name ; : parse-proc-partitions ( -- partitions ) "/proc/partitions" utf8 file-lines 2 tail [ " \t" split harvest [ { [ string>number ] [ string>number ] [ string>number ] [ ] } spread ] inputnumber ] [ string>number ] [ string>number ] } spread ] inputnumber seconds ] bi@ proc-uptime boa ; ! /proc/pid/* GENERIC# proc-pid-path 1 ( object string -- path ) M: integer proc-pid-path ( pid string -- path ) [ "/proc/" ] 2dip [ number>string "/" append ] dip 3append ; M: string proc-pid-path ( pid-string string -- path ) [ "/proc/" ] 2dip [ append-path ] dip append-path ; : proc-file-lines ( path -- strings ) utf8 file-lines ; : proc-first-line ( path -- string/f ) proc-file-lines ?first ; : proc-pid-first-line ( pid string -- string ) proc-pid-path proc-first-line ; : parse-proc-pid-cmdline ( pid -- string/f ) "cmdline" proc-pid-path proc-first-line ; TUPLE: pid-stat pid filename state parent-pid group-id session-id terminal# terminal-group-id task-flags #minor-page-faults #minor-page-faults-child #major-page-faults #major-page-faults-child cpu-user cpu-kernel cpu-user-children cpu-kernel-children priority niceness #threads zero0 nanos-since-boot virtual-memory resident-set-size resident-set-limit start-address end-address stack-start-address current-stack-pointer current-instruction-pointer pending-signals blocked-signals ignored-signals handled-signals wait-address zero1 zero2 exit-signal task-cpu realtime-policy policy blkio-ticks guest-time children-guest-time start-data end-data start-brk arg-start arg-end env-start env-end exit-code ; : parse-proc-pid-stat ( pid -- stat ) "stat" proc-pid-path proc-first-line " " split harvest 52 "0" pad-tail ! XXX: Kernel 3.2 doesn't have enough entries [ dup string>number [ nip ] when* ] map [ pid-stat boa ] input