use strict;
use Benchmark::Harness;
package Benchmark::Harness::Trace;
use base qw(Benchmark::Harness);
use Benchmark::Harness::Constants;

use vars qw($VERSION); $VERSION = sprintf("%d.%02d", q$Revision: 1.2 $ =~ /(\d+)\.(\d+)/);

### ###########################################################################
sub Initialize {
  my $self = Benchmark::Harness::Initialize(@_);

# Things we get for the ProcessInfo element:
#
# W32 Linux   attr : meaning
#  X    X      'm' : virtual memory size (kilobytes)
#       X      'r' : resident set size (kilobytes)
#       X      'u' : user mode time (milliseconds)
#       X      's' : kernel mode time (milliseconds)
#       X      'x' : user + kernal time
#  ?    ?      't' : system time, since process started, from time()
#       X      'p' : percent cpu used since process started

if ( $^O eq 'MSWin32' ) {

  $self->{XmlTempFilename} = 'C:/TEMP/benchmark_harness';
  eval 'use Win32::Process::Info';
  $self->{procInfo} = Win32::Process::Info->new(undef,'NT');

  *Benchmark::Harness::Handler::Trace::reportTraceInfo =
      sub {
            my $slf = shift;
            my $proc = ($slf->[HNDLR_HARNESS]->{procInfo}->GetProcInfo({no_user_info=>1},$$))[0];
            return Benchmark::Harness::Handler::reportTraceInfo($slf,
                {
                    'm' => $proc->{WorkingSetSize}/1024,
                    's' => $proc->{KernelModeTime} || '0',
                    't' => (time() - $slf->[HNDLR_HARNESS]->{_startTime}),
                    'u' => $proc->{UserModeTime},
                }
                ,@_
              );
          };
}
else { # Assume Linux, for now . . .

  $self->{XmlTempFilename} = '/tmp/benchmark_harness';

  *Benchmark::Harness::Handler::Trace::reportTraceInfo =
      sub {
          my $slf = shift;

          my $ps = `ps -l -p $$`;
          my ($pMem, $pTimeH, $pTimeM, $pTimeS) = ($ps =~ m{CMD(?:\s+\S+){9}\s+(\S+)(?:\s+\S+){2}\s+(\d+):(\d+):(\d+)}s);
          my $pTime = ( $pTimeH*60 + $pTimeM*60 ) + $pTimeS;

          return Benchmark::Harness::Handler::reportTraceInfo($slf,
            {
               'm' => $pMem
              ,'t' => (time() - $slf->[HNDLR_HARNESS]->{_startTime})
              ,'u' => $pTime
            }
            ,@_
          );
      };
}
  return $self;
}

package Benchmark::Harness::Handler::Trace;
use base qw(Benchmark::Harness::Handler);
use strict;


=pod

=head1 Benchmark::Harness::Trace

=head2 SYNOPSIS

A harness that records the time and sequence, and simple memory usage
of your program, at entries and exits of functions in the target program.

See Benchmark::Harness, "Parameters", for instruction on how to configure
a test harness, and use 'Trace' as your harness name.

=head2 REPORT

The report is an XML file with schema you can find in xsd/Trace.xsd,
or at http://schemas.benchmark-harness.org/Trace.xsd

For example:

  <Trace see-Benchmark::Harness-for-attributes-here>
    <T _i="0" _m="E" u="0.234375" m="0" s="0.109375" t="1"/>
    <T _i="2" _m="E" u="0.234375" m="0" s="0.109375" t="1"/>
    <T _i="2" _m="X" u="0.234375" m="0" s="0.109375" t="1"/>
    <T _i="0" _m="X" u="0.234375" m="0" s="0.109375" t="1"/>
  </Trace>

The @_i attribute is described in L<Benchmark::Harness|Benchmark::Harness>.
It identifies the name of the function being traced.

@_m will be 'E' or 'X', for entry or exit from the function.

@u is the user memory use at that moment, in megabytes.

@m is virtual memory size, in megabytes.

@s is kernal memory size, in megabytes.

@t is time since the Harness started, in seconds.

=head2 IMPACT

=over 8

=item1 MSWin32

Approximately 0.7 millisecond per trace.

=item1 Linux

=back

=head2 Available

=over 8

These process parameters are also available via this code, but are not transferred to the harness report.

=item1 MSWin32

  'Caption',
  'CommandLine',
  'CreationClassName',
  'CreationDate',
  'CSCreationClassName',
  'CSName',
  'Description',
  'ExecutablePath',
  'ExecutionState',
  'Handle',
  'HandleCount',
  'InstallDate',
  'KernelModeTime' => @s
  'MaximumWorkingSetSize',
  'MinimumWorkingSetSize',
  'Name',
  'OSCreationClassName',
  'OSName',
  'OtherOperationCount',
  'OtherTransferCount',
  'PageFaults',
  'PageFileUsage',
  'ParentProcessId',
  'PeakPageFileUsage',
  'PeakVirtualSize',
  'PeakWorkingSetSize',
  'Priority',
  'PrivatePageCount',
  'ProcessId',
  'QuotaNonPagedPoolUsage',
  'QuotaPagedPoolUsage',
  'QuotaPeakNonPagedPoolUsage',
  'QuotaPeakPagedPoolUsage',
  'ReadOperationCount',
  'ReadTransferCount',
  'SessionId',
  'Status',
  'TerminationDate',
  'ThreadCount',
  'UserModeTime' => @u
  'VirtualSize',
  'WindowsVersion',
  'WorkingSetSize' => @m
  'WriteOperationCount',
  'WriteTransferCount'

=item1 Linux

=back

=head2 SEE ALSO

L<Benchmark::Harness|Benchmark::Harness>

=cut

### ###########################################################################
sub reportValueInfo {
    return Benchmark::Harness::Handler::reportValueInfo(@_);
}

### ###########################################################################
sub OnSubEntry {
  my $self = shift;
  $self->reportTraceInfo();#(shift, caller(1));
  return @_; # return the input arguments unchanged.
}

### ###########################################################################
sub OnSubExit {
  my $self = shift;
  $self->reportTraceInfo();#(shift, caller(1));
  return @_; # return the input arguments unchanged.
}


### ###########################################################################

=head1 AUTHOR

Glenn Wood, <glennwood@cpan.org>

=head1 COPYRIGHT

Copyright (C) 2004 Glenn Wood. All rights reserved.
This program is free software; you can redistribute it and/or
modify it under the same terms as Perl itself.

=cut

1;