1# -*- cperl -*-
2# Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
3#
4# This program is free software; you can redistribute it and/or modify
5# it under the terms of the GNU General Public License as published by
6# the Free Software Foundation; version 2 of the License.
7#
8# This program is distributed in the hope that it will be useful,
9# but WITHOUT ANY WARRANTY; without even the implied warranty of
10# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11# GNU General Public License for more details.
12#
13# You should have received a copy of the GNU General Public License
14# along with this program; if not, write to the Free Software
15# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
16
17
18package My::SysInfo;
19
20use strict;
21use Carp;
22use My::Platform;
23
24use constant DEFAULT_BOGO_MIPS => 2000;
25
26sub _cpuinfo {
27  my ($self)= @_;
28
29  my $info_file= "/proc/cpuinfo";
30  if ( !(  -e $info_file and -f $info_file) ) {
31    return undef;
32  }
33
34  my $F= IO::File->new($info_file) or return undef;
35
36  # Set input separator to blank line
37  local $/ = '';
38
39  while ( my $cpu_chunk= <$F>) {
40    chomp($cpu_chunk);
41
42    my $cpuinfo = {};
43
44    foreach my $cpuline ( split(/\n/, $cpu_chunk) ) {
45      my ( $attribute, $value ) = split(/\s*:\s*/, $cpuline);
46
47      $attribute =~ s/\s+/_/;
48      $attribute = lc($attribute);
49
50      if ( $value =~ /^(no|not available|yes)$/ ) {
51	$value = $value eq 'yes' ? 1 : 0;
52      }
53
54      if ( $attribute eq 'flags' ) {
55	@{ $cpuinfo->{flags} } = split / /, $value;
56      } else {
57	$cpuinfo->{$attribute} = $value;
58      }
59    }
60
61    # Make sure bogomips is set to some value
62    $cpuinfo->{bogomips} ||= DEFAULT_BOGO_MIPS;
63
64    # Cpus reported once, but with 'cpu_count' set to the actual number
65    my $cpu_count= $cpuinfo->{cpu_count} || 1;
66    for(1..$cpu_count){
67      push(@{$self->{cpus}}, $cpuinfo);
68    }
69  }
70  $F= undef; # Close file
71  return $self;
72}
73
74
75sub _kstat {
76  my ($self)= @_;
77  while (1){
78    my $instance_num= $self->{cpus} ? @{$self->{cpus}} : 0;
79    my $list= `kstat -p -m cpu_info -i $instance_num 2> /dev/null`;
80    my @lines= split('\n', $list) or last; # Break loop
81
82    my $cpuinfo= {};
83    foreach my $line (@lines)
84    {
85      my ($module, $instance, $name, $statistic, $value)=
86	$line=~ /(\w*):(\w*):(\w*):(\w*)\t(.*)/;
87
88      $cpuinfo->{$statistic}= $value;
89    }
90
91    # Default value, the actual cpu values can be used to decrease this
92    # on slower cpus
93    $cpuinfo->{bogomips}= DEFAULT_BOGO_MIPS;
94
95    push(@{$self->{cpus}}, $cpuinfo);
96  }
97
98  # At least one cpu should have been found
99  # if this method worked
100  if ( $self->{cpus} ) {
101    return $self;
102  }
103  return undef;
104}
105
106
107sub _unamex {
108  my ($self)= @_;
109  # TODO
110  return undef;
111}
112
113
114sub new {
115  my ($class)= @_;
116
117
118  my $self= bless {
119		   cpus => (),
120		  }, $class;
121
122  my @info_methods =
123    (
124     \&_cpuinfo,
125     \&_kstat,
126     \&_unamex,
127   );
128
129  # Detect virtual machines
130  my $isvm= 0;
131
132  if (IS_WINDOWS) {
133    # Detect vmware service
134    $isvm= `tasklist` =~ /vmwareservice/i;
135  }
136  $self->{isvm}= $isvm;
137
138  foreach my $method (@info_methods){
139    if ($method->($self)){
140      return $self;
141    }
142  }
143
144  # Push a dummy cpu
145  push(@{$self->{cpus}},
146     {
147      bogomips => DEFAULT_BOGO_MIPS,
148      model_name => "unknown",
149     });
150
151  return $self;
152}
153
154
155# Return the list of cpus found
156sub cpus {
157  my ($self)= @_;
158  return @{$self->{cpus}} or
159    confess "INTERNAL ERROR: No cpus in list";
160}
161
162
163# Return the number of cpus found
164sub num_cpus {
165  my ($self)= @_;
166  return int(@{$self->{cpus}}) or
167    confess "INTERNAL ERROR: No cpus in list";
168}
169
170
171# Return the smallest bogomips value amongst the processors
172sub min_bogomips {
173  my ($self)= @_;
174
175  my $bogomips;
176
177  foreach my $cpu (@{$self->{cpus}}) {
178    if (!defined $bogomips or $bogomips > $cpu->{bogomips}) {
179      $bogomips= $cpu->{bogomips};
180    }
181  }
182
183  return $bogomips;
184}
185
186sub isvm {
187  my ($self)= @_;
188
189  return $self->{isvm};
190}
191
192
193# Prit the cpuinfo
194sub print_info {
195  my ($self)= @_;
196
197  foreach my $cpu (@{$self->{cpus}}) {
198    while ((my ($key, $value)) = each(%$cpu)) {
199      print " ", $key, "= ";
200      if (ref $value eq "ARRAY") {
201	print "[", join(", ", @$value), "]";
202      } else {
203	print $value;
204      }
205      print "\n";
206    }
207    print "\n";
208  }
209}
210
2111;
212