Apache-VMonitor

 view release on metacpan or  search on metacpan

lib/Apache/VMonitor.pm  view on Meta::CPAN

    $data->{mem} = {
            size   => $mem->{size},
            share  => $mem->{share},
            vsize  => $mem->{vsize},
            rss    => $mem->{rss},
            fsize  => size_string($mem->{size}),
            fshare => size_string($mem->{share}),
            fvsize => size_string($mem->{vsize}),
            frss   => size_string($mem->{rss}),
    };

    if (my $parent_score = $self->pid2parent_score($pid)) {

        my $worker_score;
        if ($self->{tid}) {
            warn "tid: $self->{tid}\n";
            my $image = $self->scoreboard_image();
            my $parent_idx = $image->parent_idx_by_pid($pid);
            $worker_score = $image->worker_score($parent_idx, $self->{tid});
        }
        else {
            $worker_score = MP2 ? $parent_score->worker_score : $parent_score;
        }

        my $rec = $self->score2record($worker_score);
        my $lastreq = $rec->{lastreq} ? $rec->{lastreq}/1000 : 0;
        $data->{rec} = {
            is_httpd_proc => 1,
            proc_type => ($pid == getppid ? "Parent" : "Child"),
            mode_long => $Apache::VMonitor::longflags{$rec->{mode}},
            elapsed   => $rec->{elapsed},
            felapsed  => format_time($rec->{elapsed}),
            lastreq   => $lastreq,
            flastreq  => format_time($lastreq),
            fserved   => format_counts($rec->{served}),
            client    => $rec->{client},
            vhost     => $rec->{vhost},
            request   => $rec->{request},
            access_count     => $worker_score->access_count,
            my_access_count  => $worker_score->my_access_count,
            bytes_served     => $worker_score->bytes_served,
            fbytes_served    => size_string($worker_score->bytes_served),
            my_bytes_served  => $worker_score->my_bytes_served,
            fmy_bytes_served => size_string($worker_score->my_bytes_served),
        };

        my @cpu_cols  = qw(total utime stime cutime cstime);
        my @cpu_times = $worker_score->times();
        my $cpu_total = eval join "+", @cpu_times;
        for ($cpu_total, @cpu_times) {
            my $key = "cpu_" . shift @cpu_cols;
            $data->{rec}->{$key} = $_/100;
        }
    }

    ### generic process info
    my $proc_info;
    # UID and STATE
    my $state = $gtop->proc_state($pid);
    $proc_info->{uid} = scalar getpwuid $state->uid;
    $proc_info->{gid} = scalar getgrgid $state->gid;
    $proc_info->{state} = $state->state;
    # TTY
    my $proc_uid  = $gtop->proc_uid($pid);
    my $tty = $proc_uid->tty;
    $tty = 'None' if $tty == -1;
    $proc_info->{tty} = $tty;
    # ARGV
    $proc_info->{argv} = join " ", @{($gtop->proc_args($pid))[1]};
    $data->{proc} = $proc_info;

    ### memory segments usage
    my $proc_segment = $gtop->proc_segment($pid);
    no strict 'refs';
    for (qw(text_rss shlib_rss data_rss stack_rss)) {
        my $size = $proc_segment->$_($pid);
        $data->{mem_segm}->{$_} = $size;
        $data->{mem_segm}->{"f$_"} = size_string($size);
    }

    ### memory maps
    my($procmap, $maps) = $gtop->proc_map($pid);
    my $number = $procmap->number;
    my %libpaths = ();

    my @maps = ();
    for (my $i = 0; $i < $number; $i++) {
        my $filename = $maps->filename($i) || "-";
        $libpaths{$filename}++;
        my $device = $maps->device($i);
        push @maps, {
                start        => $maps->start($i),
                end          => $maps->end($i),
                offset       => $maps->offset($i),
                device_major => (($device >> 8) & 255),
                device_minor => ($device & 255),
                inode        => $maps->inode($i),
                perm         => $maps->perm_string($i),
                filename     => $filename,
            };

    }

    $data->{mem_maps} = {
        records  => \@maps,
        ptr_size => (length(pack("p", 0)) == 8 ? 16 : 8),
    };

    ### loaded shared libs sizes
    my %libsizes = map { $_  => -s $_ } 
        grep { -e $_} grep !/^-$/, keys %libpaths;

    my @lib_sizes = ();
    my $total = 0;
    for (sort { $libsizes{$b} <=> $libsizes{$a} } keys %libsizes) {
        $total +=  $libsizes{$_};
        push @lib_sizes, {
            size     => $libsizes{$_},
            fsize    => size_string($libsizes{$_}),
            filename => $_,
        };
    }

    $data->{libs} = {
        records  => \@lib_sizes,
        total    => $total,
        ftotal   => size_string($total),
    };

    return $data;
}

# given the pid return the corresponding parent score object or undef
# if it's not an httpd proc.
sub pid2parent_score {
    my($self, $pid) = @_;

    my $image = $self->scoreboard_image();
    if (MP2) {
        my $parent_idx = $image->parent_idx_by_pid($pid);
        return $parent_idx == -1 ? undef : $image->parent_score($parent_idx);
    }
    else {
        # XXX: mp1 untested
        my $i;
        my $is_httpd_child = 0;
        for ($i = 0; $i < $Apache::Constants::HARD_SERVER_LIMIT; $i++) {
            $is_httpd_child = 1, last if $pid == $image->parent($i)->pid;
        }
        $i = -1 if $pid == getppid();
        if ($is_httpd_child || $i == -1) {
            return $image->servers($i);
        }
    }
}


sub tmpl_apache_single {
#return \'';
    return \ <<'EOT';
<hr>
[%-

   "[ <a href=\"$link_back\">Back to multiproc mode</a> ]";
   IF proc_is_dead;
       "Sorry, the process $pid ($cmd) doesn't exist anymore!";
   ELSE;
       "<h3 align='middle'>Extensive Status for PID $pid ($cmd)&nbsp; &nbsp;</h3>";
       PROCESS single_process;
   END;
-%]

[% BLOCK single_process %]
<pre>
[%-

  PROCESS single_httpd_process IF rec.is_httpd_proc;

  "<hr><b>General process info:</b>\n";
  USE format_proc_item = format("  <b>%-25s</b> : %s\n");
  format_proc_item("UID",   proc.uid);
  format_proc_item("GID",   proc.gid);
  format_proc_item("State", proc.state);
  format_proc_item("TTY",   proc.tty);
  format_proc_item("Command line arguments", proc.argv);

  # memory usage
  "\n<hr><b>Memory Usage</b> (in bytes):\n\n";
  USE format_mem_item = format("  %-10.10s : %10d (%s)\n");
  format_mem_item("Size",  mem.size,  mem.fsize);
  format_mem_item("Share", mem.share, mem.fshare);
  format_mem_item("VSize", mem.vsize, mem.fvsize);
  format_mem_item("RSS",   mem.rss,   mem.frss);

  # memory segments usage
  "\n<HR><B>Memory Segments Usage</B> (in bytes):\n\n";
  USE format_mem_segment_item = format("  %-10.10s : %10d (%s)\n");
  format_mem_segment_item("Text",  mem_segm.text_rss,  mem_segm.ftext_rss);
  format_mem_segment_item("Shlib", mem_segm.shlib_rss, mem_segm.fshlib_rss);
  format_mem_segment_item("Data",  mem_segm.data_rss,  mem_segm.fdata_rss);
  format_mem_segment_item("Stack", mem_segm.stack_rss, mem_segm.fstack_rss);

  # memory maps
  "<hr><b>Memory Maps:</b>\n\n";
   ptr_size = mem_maps.ptr_size;
   USE format_map_header = format("  <b>%${ptr_size}s-%-${ptr_size}s %${ptr_size}s  %3s:%3s %7s - %4s  - %s</b>\n");
   format_map_header("start", "end", "offset", "maj", "min", "inode", "perm", "filename");
   USE format_map_item = 
       format("  %0${ptr_size}lx-%0${ptr_size}lx %0${ptr_size}lx - %02x:%02x %08lu - %4s - %s\n");
   FOR rec = mem_maps.records.sort('filename');
       format_map_item(rec.start, rec.end, rec.offset, rec.device_major, rec.device_minor, rec.inode, rec.perm, rec.filename);
   END;

  # loaded shared libs sizes
  "<hr><b>Loaded Libs Sizes:</b> (in bytes)\n\n";
   USE format_shared_lib = format("%10d (%s): %s\n");
   FOR rec = libs.records.sort('filename');
       format_shared_lib(rec.size, rec.fsize, rec.filename);
   END;
   USE format_shared_lib_total = format("\n<b>%10d (%s): %s</b>\n");
   format_shared_lib_total(libs.total, libs.ftotal, "Total");

-%]
</pre>
[% END %]

[% BLOCK single_httpd_process %]
[%-
  USE HTML;

  "<hr><b>httpd-specific Info:</b>\n\n";

  USE format_item = format("  <b>%-25s</b> : %s\n");
  format_item("Process type", rec.proc_type);

  format_item("Status", rec.mode_long);

  IF rec.elapsed;
      elapsed_class = rec.elapsed > 15 ? "alert" : "normal";
      rec.felapsed = "<span class=\"$elapsed_class\"><b>${rec.felapsed}</b></span>";
      format_item("Cur. req. is running for", rec.felapsed);
  ELSE;



( run in 1.054 second using v1.01-cache-2.11-cpan-ceb78f64989 )