The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.

NAME

Linux::Smaps - a Perl interface to /proc/PID/smaps

SYNOPSIS

  use Linux::Smaps;
  my $map=Linux::Smaps->new($pid);
  my @maps=$map->maps;
  my $private_dirty=$map->private_dirty;
  ...

DESCRIPTION

The /proc/PID/smaps files in modern linuxes provides very detailed information about a processes memory consumption. It particularly includes a way to estimate the effect of copy-on-write. This module implements a Perl interface.

CONSTRUCTOR, OBJECT INITIALIZATION, etc.

Linux::Smaps->new($pid)

creates and initializes a Linux::Smaps object. Returns the object or undef if a PID was given and update has failed.

$self->pid($pid) or $self->pid=$pid

get/set the PID.

$self->update

reinitializes the object; rereads /proc/PID/smaps. Returns the object on success or undef otherwize.

$self->lasterror

update() and new() return undef on failure. lasterror() returns a more verbose reason. Also $! can be checked.

INFORMATION RETRIEVAL

$self->vmas

returns a list of Linux::Smaps::VMA objects each describing a vm area, see below.

$self->size
$self->rss
$self->shared_clean
$self->shared_dirty
$self->private_clean
$self->private_dirty

these methods compute the sums of the appropriate values of all vmas.

$self->stack
$self->heap
$self->vdso

these are shortcuts to the appropiate Linux::Smaps::VMA objects.

$self->all
$self->named
$self->unnamed

In array context these functions return a list of Linux::Smaps::VMA objects representing named or unnamed maps or simply all vmas. Thus, in array context all() is equivalent to vmas().

In scalar context these functions create a fake Linux::Smaps::VMA object containing the summaries of the size, rss, shared_clean, shared_dirty, private_clean and private_dirty fields.

$self->names

returns a list of vma names, i.e. the files that are mapped.

Linux::Smaps::VMA objects

normally these objects represent a single vm area:

$self->vma_start
$self->vma_end

start and end address

$self->r
$self->w
$self->x
$self->mayshare

these correspond to the VM_READ, VM_WRITE, VM_EXEC and VM_MAYSHARE flags. see Linux kernel for more information.

$self->file_off
$self->dev_major
$self->dev_minor
$self->inode
$self->filename

describe the file area that is mapped.

$self->size

the same as vma_end - vma_start.

$self->rss

what part is resident.

$self->shared_clean
$self->shared_dirty
$self->private_clean
$self->private_dirty

shared means page_count(page)>=2 (see Linux kernel), i.e. the page is shared between several processes. private pages belong only to one process.

dirty pages are written to in RAM but not to the corresponding file.

Example: The copy-on-write effect

 use strict;
 use Linux::Smaps;

 my $x="a"x(1024*1024);         # a long string of "a"
 if( fork ) {
   my $s=Linux::Smaps->new($$);
   my $before=$s->all;
   $x=~tr/a/b/;                 # change "a" to "b" in place
   #$x="b"x(1024*1024);         # assignment
   $s->update;
   my $after=$s->all;
   foreach my $n (qw{rss size shared_clean shared_dirty
                     private_clean private_dirty}) {
     print "$n: ",$before->$n," => ",$after->$n,": ",
            $after->$n-$before->$n,"\n";
   }
   wait;
 } else {
   sleep 1;
 }

This script may give the following output:

 rss: 4160 => 4252: 92
 size: 6916 => 7048: 132
 shared_clean: 1580 => 1596: 16
 shared_dirty: 2412 => 1312: -1100
 private_clean: 0 => 0: 0
 private_dirty: 168 => 1344: 1176

$x is changed in place. Hence, the overall process size (size and rss) would not grow much. But before the tr operation $x was shared by copy-on-write between the 2 processes. Hence, we see a loss of shared_dirty (only a little more than our 1024 kB string) and almost the same growth of private_dirty.

Exchanging the tr-operation to an assingment of a MB of "b" yields the following figures:

 rss: 4160 => 5276: 1116
 size: 6916 => 8076: 1160
 shared_clean: 1580 => 1592: 12
 shared_dirty: 2432 => 1304: -1128
 private_clean: 0 => 0: 0
 private_dirty: 148 => 2380: 2232

Now we see the overall process size grows a little more than a MB. shared_dirty drops almost a MB and private_dirty adds almost 2 MB. That means perl first constructs a 1 MB string of b. This adds 1 MB to size, rss and private_dirty and then copies it to $x. This takes another MB from shared_dirty and adds it to private_dirty.

EXPORT

Not an Exporter;

SEE ALSO

Linux Kernel.

AUTHOR

Torsten Foertsch, <torsten.foertsch@gmx.net>

COPYRIGHT AND LICENSE

Copyright (C) 2005 by Torsten Foertsch

This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself, either Perl version 5.8.5 or, at your option, any later version of Perl 5 you may have available.