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