]> git.proxmox.com Git - pve-common.git/blob - data/PVE/ProcFSTools.pm
imported from svn 'pve-common/trunk'
[pve-common.git] / data / PVE / ProcFSTools.pm
1 package PVE::ProcFSTools;
2
3 use strict;
4 use POSIX;
5 use Time::HiRes qw (gettimeofday);
6 use IO::File;
7 use PVE::Tools;
8
9 my $clock_ticks = POSIX::sysconf(&POSIX::_SC_CLK_TCK);
10
11 my $cpuinfo;
12
13 # cycles_per_jiffy = frequency_of_your_cpu/jiffies_per_second
14 # jiffies_per_second = 1000
15
16 # frequency_of_your_cpu can be read from /proc/cpuinfo, as:
17 # cpu MHz : <frequency_of_your_cpu>
18
19 sub read_cpuinfo {
20 my $fn = '/proc/cpuinfo';
21
22 return $cpuinfo if $cpuinfo;
23
24 my $res = {
25 model => 'unknown',
26 mhz => 0,
27 cpus => 1,
28 cpu_cycles_per_jiffy => 0,
29 };
30
31 my $fh = IO::File->new ($fn, "r");
32 return $res if !$fh;
33
34 my $count = 0;
35 while (defined(my $line = <$fh>)) {
36 if ($line =~ m/^processor\s*:\s*\d+\s*$/i) {
37 $count++;
38 } elsif ($line =~ m/^model\s+name\s*:\s*(.*)\s*$/i) {
39 $res->{model} = $1 if $res->{model} eq 'unknown';
40 } elsif ($line =~ m/^cpu\s+MHz\s*:\s*(\d+\.\d+)\s*$/i) {
41 $res->{mhz} = $1 if !$res->{mhz};
42 $res->{cpu_cycles_per_jiffy} += $1 * 1000;
43 } elsif ($line =~ m/^flags\s*:.*(vmx|svm)/) {
44 $res->{hvm} = 1; # Hardware Virtual Machine (Intel VT / AMD-V)
45 }
46 }
47
48 $res->{cpus} = $count;
49
50 $fh->close;
51
52 $cpuinfo = $res;
53
54 return $res;
55 }
56
57 sub read_proc_uptime {
58 my $ticks = shift;
59
60 my $line = PVE::Tools::file_read_firstline("/proc/uptime");
61 if ($line && $line =~ m|^(\d+\.\d+)\s+(\d+\.\d+)\s*$|) {
62 if ($ticks) {
63 return (int($1*100), int($2*100));
64 } else {
65 return (int($1), int($2));
66 }
67 }
68
69 return (0, 0);
70 }
71
72 sub read_loadavg {
73
74 my $line = PVE::Tools::file_read_firstline('/proc/loadavg');
75
76 if ($line =~ m|^(\d+\.\d+)\s+(\d+\.\d+)\s+(\d+\.\d+)\s+\d+/\d+\s+\d+\s*$|) {
77 return wantarray ? ($1, $2, $3) : $1;
78 }
79
80 return wantarray ? (0, 0, 0) : 0;
81 }
82
83 my $last_proc_stat;
84
85 sub read_proc_stat {
86 my $res = { user => 0, nice => 0, system => 0, idle => 0 , sum => 0};
87
88 my $cpucount = 0;
89
90 if (my $fh = IO::File->new ("/proc/stat", "r")) {
91 while (defined (my $line = <$fh>)) {
92 if ($line =~ m|^cpu\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s|) {
93 $res->{user} = $1;
94 $res->{nice} = $2;
95 $res->{system} = $3;
96 $res->{idle} = $4;
97 $res->{used} = $1+$2+$3;
98 $res->{iowait} = $5;
99 } elsif ($line =~ m|^cpu\d+\s|) {
100 $cpucount++;
101 }
102 }
103 $fh->close;
104 }
105
106 $cpucount = 1 if !$cpucount;
107
108 my $ctime = gettimeofday; # floating point time in seconds
109
110 $res->{ctime} = $ctime;
111 $res->{cpu} = 0;
112 $res->{wait} = 0;
113
114 $last_proc_stat = $res if !$last_proc_stat;
115
116 my $diff = ($ctime - $last_proc_stat->{ctime}) * $clock_ticks * $cpucount;
117
118 if ($diff > 1000) { # don't update too often
119 my $useddiff = $res->{used} - $last_proc_stat->{used};
120 $useddiff = $diff if $useddiff > $diff;
121 $res->{cpu} = $useddiff/$diff;
122 my $waitdiff = $res->{iowait} - $last_proc_stat->{iowait};
123 $waitdiff = $diff if $waitdiff > $diff;
124 $res->{wait} = $waitdiff/$diff;
125 $last_proc_stat = $res;
126 } else {
127 $res->{cpu} = $last_proc_stat->{cpu};
128 $res->{wait} = $last_proc_stat->{wait};
129 }
130
131 return $res;
132 }
133
134 sub read_proc_starttime {
135 my $pid = shift;
136
137 my $statstr = PVE::Tools::file_read_firstline("/proc/$pid/stat");
138
139 if ($statstr && $statstr =~ m/^$pid \(.*\) \S (-?\d+) -?\d+ -?\d+ -?\d+ -?\d+ \d+ \d+ \d+ \d+ \d+ (\d+) (\d+) (-?\d+) (-?\d+) -?\d+ -?\d+ -?\d+ 0 (\d+) (\d+) (-?\d+) \d+ \d+ \d+ \d+ \d+ \d+ \d+ \d+ \d+ \d+ \d+ \d+ \d+ -?\d+ -?\d+ \d+ \d+ \d+/) {
140 my $starttime = $6;
141
142 return $starttime;
143 }
144
145 return 0;
146 }
147
148 sub read_meminfo {
149
150 my $res = {
151 memtotal => 0,
152 memfree => 0,
153 memused => 0,
154 swaptotal => 0,
155 swapfree => 0,
156 swapused => 0,
157 };
158
159 my $fh = IO::File->new ("/proc/meminfo", "r");
160 return $res if !$fh;
161
162 my $d = {};
163 while (my $line = <$fh>) {
164 if ($line =~ m/^(\S+):\s+(\d+)\s*kB/i) {
165 $d->{lc ($1)} = $2 * 1024;
166 }
167 }
168 close($fh);
169
170 $res->{memtotal} = $d->{memtotal};
171 $res->{memfree} = $d->{memfree} + $d->{buffers} + $d->{cached};
172 $res->{memused} = $res->{memtotal} - $res->{memfree};
173
174 $res->{swaptotal} = $d->{swaptotal};
175 $res->{swapfree} = $d->{swapfree};
176 $res->{swapused} = $res->{swaptotal} - $res->{swapfree};
177
178 return $res;
179 }
180
181 # memory usage of current process
182 sub read_memory_usage {
183
184 my $res = { size => 0, resident => 0, shared => 0 };
185
186 my $ps = 4096;
187
188 my $line = PVE::Tools::file_read_firstline("/proc/$$/statm");
189
190 if ($line =~ m/^(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+/) {
191 $res->{size} = $1*$ps;
192 $res->{resident} = $2*$ps;
193 $res->{shared} = $3*$ps;
194 }
195
196 return $res;
197 }
198
199 sub read_proc_net_dev {
200
201 my $res = {};
202
203 my $fh = IO::File->new ("/proc/net/dev", "r");
204 return $res if !$fh;
205
206 while (defined (my $line = <$fh>)) {
207 if ($line =~ m/^\s*(.*):\s*(\d+)\s+\d+\s+\d+\s+\d+\s+\d+\s+\d+\s+\d+\s+\d+\s+(\d+)\s+/) {
208 $res->{$1} = {
209 receive => $2,
210 transmit => $3,
211 };
212 }
213 }
214
215 close($fh);
216
217 return $res;
218 }
219
220 1;