Projet

Général

Profil

Paste
Télécharger au format
Statistiques
| Branche: | Révision:

root / plugins / system / irq @ f14628ad

Historique | Voir | Annoter | Télécharger (14,4 ko)

1
#!/usr/bin/perl -w
2
# -*- perl -*-
3

    
4
=head1 NAME
5

    
6
irq - Plugin to monitor inerrupts.
7

    
8
=head1 APPLICABLE SYSTEMS
9

    
10
All Linux systems
11

    
12
=head1 CONFIGURATION
13

    
14
None need
15

    
16
=head2 WARNING AND CRITICAL SETTINGS
17

    
18
You can set warning and critical levels for each of the data
19
series the plugin reports.
20
'General' graph support cpu-irqtype limits and irqtype limits
21
Examples:
22
[irq]
23
env.warning_cpu1_sirq_total 550
24
env.critical_cpu0_irq_total 600
25
env.warning_irq_total 700
26
env.critical_sirq_total 700
27

    
28
'Child' graphs support cpu-irqtype-irqname and irqtype-irqname limits
29
Examples:
30
[irq]
31
env.warning_cpu0_irq_7 100
32
env.critical_cpu1_sirq_HI 100
33
env.warning_irq_LOC 100
34
env.critical_irq_12 200
35
env.warning_sirq_BLOCK 1000
36

    
37
Note: irqtype: sirq, irq; sirq - Software IRQ; irq name you can see in [] on graph
38

    
39
=head1 INTERPRETATION
40

    
41
The plugin shows each cpu interrupts: summary and IRQ/Software IRQ per CPU
42

    
43
=head1 MAGIC MARKERS
44

    
45
  #%# family=auto
46
  #%# capabilities=autoconf
47

    
48
=head1 VERSION
49

    
50
  1.0
51

    
52
=head1 BUGS
53

    
54
I can not understand, how set limit to mirrored fields, so they may not display correctly
55

    
56
=head1 AUTHOR
57

    
58
Gorlow Maxim aka Sheridan <sheridan@sheridan-home.ru> (email and jabber)
59

    
60
=head1 LICENSE
61

    
62
GPLv2
63

    
64
=cut
65

    
66
use strict;
67
use warnings;
68
use Munin::Plugin;
69
use Data::Dumper;
70
my $IRQi = {};
71

    
72

    
73
my $graphs =
74
{
75
  'irq_total' =>
76
  {
77
    'title'    => 'Interrupts per cpu',
78
    'args'     => '--base 1000',
79
    'vlabel'   => 'count of IRQ (+) / sIRQ (-) per secund',
80
    'info'     => 'This graph shows interrupts per secund from last update',
81
    'category' => 'system'
82
  },
83
  'irq_cpu' =>
84
  {
85
    'title'    => 'CPU:cpu: :irq_type:',
86
    'args'     => '--base 1000',
87
    'vlabel'   => 'count per secund',
88
    'info'     => 'This graph shows :irq_type: for CPU:cpu: per secund from last update',
89
    'category' => 'cpu :cpu:'
90
  }
91
};
92

    
93
my $fields =
94
{
95
  'irq' =>
96
  {
97
    'label' => '[:irq:] :irqinfo:',
98
    'info'  => ':irq:: :irqinfo:',
99
    'type'  => 'GAUGE',
100
    'draw'  => 'LINE1'
101
  },
102
  'irq_sirq' =>
103
  {
104
    'label' => 'CPU:cpu: sIRQ/IRQ',
105
    'info'  => 'Total sIRQ/IRQ for CPU:cpu:',
106
    'type'  => 'GAUGE',
107
    'draw'  => 'LINE1'
108
  }
109
};
110

    
111
my $irq_types =
112
{
113
  'irq'  => 'Interrupts',
114
  'sirq' => 'Software interrupts'
115
};
116

    
117
my $irq_descriptions = 
118
{
119
  'HI'      => 'High priority tasklets',
120
  'TIMER'   => 'Timer bottom half',
121
  'NET_TX'  => 'Transmit network packets',
122
  'NET_RX'  => 'Receive network packets',
123
  'SCSI'    => 'SCSI bottom half',
124
  'TASKLET' => 'Handles regular tasklets'
125
};
126

    
127
# ----------------- main ----------------
128
need_multigraph();
129
# -- autoconf --
130
if (defined($ARGV[0]) and ($ARGV[0] eq 'autoconf')) 
131
{
132
  printf("%s\n", (-e "/proc/interrupts" and -e "/proc/softirqs") ? "yes" : "no (stats not exists)");
133
  exit (0);
134
}
135
# -- config --
136
load_irq_info();
137
if (defined($ARGV[0]) and ($ARGV[0] eq 'config')) { print_config(); exit (0); }
138
# -- values --
139
print_values(); exit(0);
140

    
141
# ----------------- sub's ----------------
142

    
143
# ----------------------- trim whitespace at begin and end of string ------------
144
sub trim
145
{
146
  my    ($string) = @_;
147
  for   ($string) { s/^\s+//; s/\s+$//; }
148
  return $string;
149
}
150

    
151

    
152
# -------------------------- loading irq stats ---------------------------------
153
sub load_irq_info_file
154
{
155
  my $file      = $_[0];
156
  my $info      = {};
157
  my $cpu_count = 0;
158
  my $summ      = 0;
159
  open (FH, '<', $file) or die "$! $file \n";
160
  for my $line (<FH>)
161
  {
162
    chomp $line;
163
    if($line =~ m/:/)
164
    {
165
      my ($name, $stat) = split(/:/, trim($line));
166
      my @data = split(/\s+/, trim($stat));
167
      for (my $i=0; $i<$cpu_count; $i++)
168
      {
169
        if (defined $data[$i])
170
        {
171
          $info->{'info'}{$i}{$name} = $data[$i];
172
          $info->{'summ'}{$i}       += $data[$i];
173
        }
174
      }
175
      if(scalar(@data) > $cpu_count)
176
      {
177
        my $iname = '';
178
        ($iname = $line) =~ s/^.*:(\s+\d+)+\s+(.*)$/$2/;
179
        if ($iname ne '')
180
        {
181
          if ($iname =~ m/.*-.*-.*/)
182
          {
183
            my @parts = ($iname =~ /^((\w+-)*\w+)\s+(.*)\s*$/g);
184
            $iname = sprintf("%s (%s)", $parts[0], $parts[2]);
185
          }
186
          $info->{'description'}{$name} = $iname;
187
        }
188
      }
189
      elsif(exists ($irq_descriptions->{$name}))
190
      {
191
        $info->{'description'}{$name} = $irq_descriptions->{$name};
192
      }
193
    }
194
    else
195
    {
196
      my @cpus = split(/\s+/, trim($line));
197
      $cpu_count = scalar(@cpus);
198
      for (my $i=0; $i<$cpu_count; $i++)
199
      {
200
        $info->{'summ'}{$i} = 0;
201
      }
202
    }
203
  }
204
  close (FH);
205
  $info->{'cpu_count'} = $cpu_count;
206
  return $info;
207
}
208

    
209
# -------------- loading all IRQ statistics ---------------------------
210
sub load_irq_info
211
{
212
  my ($irq, $sirq) = (load_irq_info_file("/proc/interrupts"), load_irq_info_file("/proc/softirqs"));
213
  $IRQi->{'stat'}{'irq' } = $irq ->{'info'};
214
  $IRQi->{'stat'}{'sirq'} = $sirq->{'info'};
215
  $IRQi->{'summ'}{'irq' } = $irq ->{'summ'};
216
  $IRQi->{'summ'}{'sirq'} = $sirq->{'summ'};
217
  $IRQi->{'description'}{'irq' } = $irq ->{'description'} if exists($irq ->{'description'});
218
  $IRQi->{'description'}{'sirq'} = $sirq->{'description'} if exists($sirq->{'description'});
219
  $IRQi->{'cpu_count'} = $irq ->{'cpu_count'};
220
}
221

    
222
# ------------------ loading limits ---------------------
223
sub load_limits
224
{
225
  my $flags = {};
226
  my $limits = {};
227
  my $name = '';
228
  for my $irq_type (qw(irq sirq))
229
  {
230
    for my $t (qw(warning critical))
231
    {
232
      $name = sprintf("%s_%s_total", $t, $irq_type); # env.warning_irq_total 22
233
      $limits->{'irq_total'}{$irq_type}{$t} = $ENV{$name} || undef;
234
      for (my $i=0; $i < $IRQi->{'cpu_count'}; $i++)
235
      {
236
        $name = sprintf("%s_cpu%s_%s_total", $t, $i, $irq_type); # env.warning_cpu1_sirq_total 1112
237
        $limits->{'irq_total_percpu'}{$irq_type}{$t}{$i} = $ENV{$name} || undef;
238
        for my $irq_name (keys %{$IRQi->{'stat'}{$irq_type}{$i}})
239
        {
240
          $name = sprintf("%s_cpu%s_%s_%s", $t, $i, $irq_type, $irq_name); # env.warning_cpu0_irq_7 25
241
          $limits->{'percpu_perirq'}{$irq_type}{$t}{$i}{$irq_name} = $ENV{$name} || undef;
242
          $name = sprintf("%s_%s_%s", $t, $irq_type, $irq_name);
243
          unless (exists($flags->{$name}))
244
          {
245
            $limits->{'perirq'}{$irq_type}{$t}{$irq_name} = $ENV{$name} || undef; # env.critical_sirq_RCU 14
246
            $flags->{$name} = 1;
247
          }
248
        }
249
      }
250
    }
251
  }
252
  return $limits;
253
}
254

    
255
# -------------------------------- replacing strings ------------------------
256
sub replace
257
{
258
  my ($string, $needle, $replacement) = @_[0..2];
259
  $string =~ s/$needle/$replacement/g;
260
  return $string;
261
}
262

    
263
# ----------------- append limit values to general graph fields-----------------------------
264
sub append_total_limit
265
{
266
  my ($limits, $gr, $irq_type, $field_name, $cpu_num) = @_[0..4];
267
  for my $t (qw(warning critical))
268
  {
269
    my $limit = defined($limits->{'irq_total_percpu'}{$irq_type}{$t}{$cpu_num}) ? $limits->{'irq_total_percpu'}{$irq_type}{$t}{$cpu_num} :
270
                ($limits->{'irq_total'}{$irq_type}{$t} || undef);
271
    if (defined($limit))
272
    {
273
      $gr->{'irq'}{'fields'}{$field_name}{$t} = $limit;
274
    }
275
  }
276
}
277

    
278
# ----------------- append limit values to chields graphs fields-----------------------------
279
sub append_cpu_limit
280
{
281
  my ($limits, $gr, $irq_type, $field_name, $graph_name, $cpu_num, $irq_name) = @_[0..6];
282
  for my $t (qw(warning critical))
283
  {
284
    my $limit = defined($limits->{'percpu_perirq'}{$irq_type}{$t}{$cpu_num}{$irq_name}) ? $limits->{'percpu_perirq'}{$irq_type}{$t}{$cpu_num}{$irq_name} :
285
                ($limits->{'perirq'}{$irq_type}{$t}{$irq_name} || undef);
286
    if (defined($limit))
287
    {
288
      $gr->{$graph_name}{'fields'}{$field_name}{$t} = $limit;
289
    }
290
  }
291
}
292

    
293
# ------------------------------ preparing graphs configurations ------------------------------
294
sub prepare_graphs
295
{
296
  my $gr = {};
297
  my $limits = load_limits();
298
  # --- general graph ---
299
  $gr->{'irq'}{'graph'} = $graphs->{'irq_total'};
300
  $gr->{'irq'}{'graph'}{'order'} = "";
301
  for (my $i=0; $i < $IRQi->{'cpu_count'}; $i++)
302
  {
303
    # --- general fields ---
304
    my ($up_field_name, $down_field_name) = (sprintf("i%s", $i), sprintf("si%s", $i));
305
    append_total_limit($limits, $gr, 'irq',  $up_field_name,   $i);
306
    append_total_limit($limits, $gr, 'sirq', $down_field_name, $i);
307
    $gr->{'irq'}{'graph'}{'order'} .= sprintf(" %s %s", $down_field_name, $up_field_name);
308
    $gr->{'irq'}{'fields'}{$up_field_name}{'type'}   = $fields->{'irq_sirq'}{'type'};
309
    $gr->{'irq'}{'fields'}{$down_field_name}{'type'} = $fields->{'irq_sirq'}{'type'};
310
    $gr->{'irq'}{'fields'}{$up_field_name}{'draw'}   = $fields->{'irq_sirq'}{'draw'};
311
    $gr->{'irq'}{'fields'}{$down_field_name}{'draw'} = $fields->{'irq_sirq'}{'draw'};
312
    
313
    $gr->{'irq'}{'fields'}{$up_field_name}{'label'} = replace($fields->{'irq_sirq'}{'label'}, ':cpu:', $i);
314
    $gr->{'irq'}{'fields'}{$up_field_name}{'info'}  = replace($fields->{'irq_sirq'}{'info'} , ':cpu:', $i);
315
    $gr->{'irq'}{'fields'}{$down_field_name}{'label'} = 'NaN';
316
    $gr->{'irq'}{'fields'}{$down_field_name}{'info'}  = 'NaN';
317
    
318
    $gr->{'irq'}{'fields'}{$up_field_name}{'negative'} = $down_field_name;
319
    $gr->{'irq'}{'fields'}{$down_field_name}{'graph'}  = 'no';
320
    
321
    # --- child graphs ---
322
    for my $irq_type (qw(irq sirq))
323
    {
324
      my $graph_name = sprintf("irq.%s_cpu%s", $irq_type, $i);
325
      $gr->{$graph_name}{'graph'}{'order'} = "";
326
      $gr->{$graph_name}{'graph'}{'args'} = $graphs->{'irq_cpu'}{'args'};
327
      $gr->{$graph_name}{'graph'}{'vlabel'} = $graphs->{'irq_cpu'}{'vlabel'};
328
      for my $go (qw(title info))
329
      {
330
        $gr->{$graph_name}{'graph'}{$go} = replace($graphs->{'irq_cpu'}{$go}, ':irq_type:', $irq_types->{$irq_type});
331
        $gr->{$graph_name}{'graph'}{$go} = replace($gr->{$graph_name}{'graph'}{$go}, ':cpu:', $i);
332
      }
333
      $gr->{$graph_name}{'graph'}{'category'} = replace($graphs->{'irq_cpu'}{'category'}, ':cpu:', $i);
334
      # -- child fields --
335
      my @irq_names = keys %{$IRQi->{'stat'}{$irq_type}{$i}};
336
      # names splitted for better sorting
337
      for my $irq_name ((
338
                          (sort {int $a <=> int $b} grep{/^\d/}            @irq_names), 
339
                          (sort                     grep{!/(^\d|ERR|MIS)/} @irq_names),
340
                          (sort                     grep{/(ERR|MIS)/     } @irq_names)
341
                        ))
342
      {
343
        my $field_name = clean_fieldname(sprintf("irq_%s", $irq_name));
344
        append_cpu_limit($limits, $gr, $irq_type, $field_name, $graph_name, $i, $irq_name);
345
        $gr->{$graph_name}{'graph'}{'order'} .= ' '.$field_name;
346
        for my $fo (qw(label info))
347
        {
348
          $gr->{$graph_name}{'fields'}{$field_name}{$fo} = replace($fields->{'irq'}{$fo}, ':irq:', $irq_name);
349
          $gr->{$graph_name}{'fields'}{$field_name}{$fo} = replace($gr->{$graph_name}{'fields'}{$field_name}{$fo},
350
                                                                   ':irqinfo:', 
351
                                                                   exists($IRQi->{'description'}{$irq_type}{$irq_name}) ?
352
                                                                    $IRQi->{'description'}{$irq_type}{$irq_name} :
353
                                                                    '');
354
        }
355
        $gr->{$graph_name}{'fields'}{$field_name}{'type'} = $fields->{'irq'}{'type'};
356
        $gr->{$graph_name}{'fields'}{$field_name}{'draw'} = $fields->{'irq'}{'draw'};
357
      }
358
    }
359
  }
360
  return $gr;
361
}
362

    
363
# --------------------------------- graph configs ----------------------------
364
sub print_config
365
{
366
  my $config = prepare_graphs();
367
  for my $g (sort keys %{$config})
368
  {
369
    printf("multigraph %s\n", $g);
370
    for my $go (sort keys %{$config->{$g}{'graph'}}) { printf("graph_%s %s\n", $go, $config->{$g}{'graph'}{$go}); }
371
    for my $f (sort keys %{$config->{$g}{'fields'}}) { for my $fo (sort keys %{$config->{$g}{'fields'}{$f}}) { printf("%s.%s %s\n", $f, $fo, $config->{$g}{'fields'}{$f}{$fo}); } }
372
    print "\n";
373
  }
374
}
375

    
376
# ----------------------------------- saving state data using munin --------------------
377
sub save_state_data
378
{
379
  my $data = $_[0];
380
  my $d = Data::Dumper->new([$data]);
381
  $d->Indent(0);
382
  save_state($d->Dump);
383
}
384

    
385
# -------------------------------- loading previous state data using munin -------------------
386
sub restore_state_data
387
{
388
  my $VAR1;
389
  my $states = (restore_state())[0];
390
  eval $states if defined $states;
391
  return $VAR1;
392
}
393

    
394
# ----------------------------- loading statistic and save it for feature use--------------
395
sub load_stats
396
{
397
  delete ($IRQi->{'description'});
398
  $IRQi->{'timestamp'} = time();
399
  save_state_data($IRQi);
400
  return $IRQi;
401
}
402

    
403
# ----------- calculate current and previous values difference -----------------------
404
sub diff_value
405
{
406
  my ($pvalue, $cvalue, $timediff) = @_[0..2];
407
  return 'NaN' if $timediff <= 0 or $pvalue > $cvalue;
408
  return ($cvalue - $pvalue)/$timediff;
409
}
410

    
411
# -----------------  calculating values ---------------------
412
sub calculate
413
{
414
  my ($pstats, $cstats) = @_[0..1];
415
  my $data = {};
416
  my $timediff = $cstats->{'timestamp'} - $pstats->{'timestamp'};
417
  for my $irq_type (qw(irq sirq))
418
  {
419
    for (my $i=0; $i < $IRQi->{'cpu_count'}; $i++)
420
    {
421
      $data->{'summ'}{$irq_type}{$i} = diff_value($pstats->{'summ'}{$irq_type}{$i}, $cstats->{'summ'}{$irq_type}{$i}, $timediff);
422
      for my $irq_name (keys %{$cstats->{'stat'}{$irq_type}{$i}})
423
      {
424
        $data->{'stat'}{$irq_type}{$i}{$irq_name} = diff_value($pstats->{'stat'}{$irq_type}{$i}{$irq_name}, $cstats->{'stat'}{$irq_type}{$i}{$irq_name}, $timediff);
425
      }
426
    }
427
  }
428
  return $data;
429
}
430

    
431
# --------------------- preparing graphs values config ------------------------
432
sub prepare_graphs_values
433
{
434
  my $data = $_[0];
435
  my $values = {};
436
  for (my $i=0; $i < $IRQi->{'cpu_count'}; $i++)
437
  {
438
    $values->{'irq'}{sprintf("i%s",  $i)} = $data->{'summ'}{'irq'} {$i};
439
    $values->{'irq'}{sprintf("si%s", $i)} = $data->{'summ'}{'sirq'}{$i};
440
    for my $irq_type (qw(irq sirq))
441
    {
442
      my $graph_name = sprintf("irq.%s_cpu%s", $irq_type, $i);
443
      for my $irq_name (keys %{$data->{'stat'}{$irq_type}{$i}})
444
      {
445
        my $field_name = clean_fieldname(sprintf("irq_%s", $irq_name));
446
        $values->{$graph_name}{$field_name} = $data->{'stat'}{$irq_type}{$i}{$irq_name};
447
      }
448
    }
449
  }
450
  return $values;
451
}
452

    
453
# -------------------------------- printing values -----------------------------------
454
sub print_values
455
{
456
  my $pstats = restore_state_data();
457
  my $cstats = load_stats();
458
  if (exists ($pstats->{'timestamp'}))
459
  {
460
    my $values = prepare_graphs_values(calculate($pstats, $cstats));
461
    for my $g (sort keys %{$values})
462
    {
463
      printf("multigraph %s\n", $g);
464
      for my $f (sort keys %{$values->{$g}}) { printf("%s.value %s\n", $f, $values->{$g}{$f}); }
465
      print "\n";
466
    }
467
  }
468
}
469