view src/profiler.cc @ 12784:c499d54796d6

Minor stylistic fixes to profiler code
author Jordi Gutiérrez Hermoso <jordigh@gmail.com>
date Thu, 14 Jul 2011 01:21:06 -0500
parents ad9263d965dc
children de9a9719e594
line wrap: on
line source

/*

Copyright (C) 2011 Daniel Kraft

This file is part of Octave.

Octave is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 3 of the License, or (at your
option) any later version.

Octave is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
for more details.

You should have received a copy of the GNU General Public License
along with Octave; see the file COPYING.  If not, see
<http://www.gnu.org/licenses/>.

*/

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <iostream>

#include "Cell.h"
#include "defun.h"
#include "oct-time.h"
#include "ov-fcn.h"
#include "ov-struct.h"
#include "pager.h"
#include "profiler.h"

profile_data_accumulator::enter::enter (profile_data_accumulator& a,
                                        const octave_function& f)
  : acc (a)
{
  if (acc.is_active ())
    {
      fcn = &f;
      acc.enter_function (*fcn);
    }
  else
    fcn = NULL;
}

profile_data_accumulator::enter::~enter ()
{
  if (fcn)
    acc.exit_function (*fcn);
}

profile_data_accumulator::profile_data_accumulator ()
  : enabled (false), call_stack (), times (), last_time (-1.0)
{}

void
profile_data_accumulator::set_active (bool value)
{
  // If we enable, clear the call-stack.  This ensures we freshly start
  // with collecting times now.
  if (value)
    {
      while (!call_stack.empty ())
        call_stack.pop ();
    }

  enabled = value;
}

void
profile_data_accumulator::enter_function (const octave_function& fcn)
{
  // The enter class will check and only call us if the profiler is active.
  assert (is_active ());

  // If there is already an active function, add to its time before
  // pushing the new one.
  if (!call_stack.empty ())
    add_current_time ();

  call_stack.push (&fcn);
  last_time = query_time ();
}

void
profile_data_accumulator::exit_function (const octave_function& fcn)
{
  assert (!call_stack.empty ());
  assert (&fcn == call_stack.top ());

  // Usually, if we are disabled this function is not even called.  But the
  // call disabling the profiler is an exception.  So also check here
  // and only record the time if enabled.
  if (is_active ())
    add_current_time ();

  call_stack.pop ();

  // If this was an "inner call", we resume executing the parent function
  // up the stack.  So note the start-time for this!
  last_time = query_time ();
}

void
profile_data_accumulator::reset (void)
{
  if (is_active ())
    {
      error ("Can't reset active profiler.");
      return;
    }

  times.clear ();
  last_time = -1.0;
}

Cell
profile_data_accumulator::get_data (void) const
{
  const int n = times.size ();

  Cell retval (1, n);
  int i = 0;
  for (timing_map::const_iterator p = times.begin (); p != times.end (); ++p)
    {
      octave_scalar_map entry;

      entry.contents ("name") = octave_value (p->first);
      entry.contents ("time") = octave_value (p->second);

      retval (i++) = entry;
    }
  assert (i == n);

  return retval;
}

double
profile_data_accumulator::query_time (void) const
{
  octave_time now;
  return now.double_value ();
}

void
profile_data_accumulator::add_current_time (void)
{
  const double t = query_time ();
  assert (last_time >= 0.0 && last_time <= t);

  assert (!call_stack.empty ());
  const std::string name = call_stack.top ()->profiler_name ();

  // If the key is not yet present in the map, it is constructed
  // with default value 0.
  times[name] += t - last_time;
}

profile_data_accumulator profiler;

DEFUN (profiler_enable, args, nargout,
  "-*- texinfo -*-\n\
@deftypefn  {Built-in Function} {} profiler_enable (enabled)\n\
Enable or disable the profiler data collection.\n\
@end deftypefn")
{
  octave_value_list retval;

  const int nargin = args.length ();
  if (nargin > 0)
    {
      if (nargin > 1)
        {
          print_usage ();
          return retval;
        }

      profiler.set_active (args(0).bool_value ());
    }

  retval(0) = profiler.is_active ();

  return retval;
}

DEFUN (profiler_reset, args, nargout,
  "-*- texinfo -*-\n\
@deftypefn  {Built-in Function} {} profiler_reset ()\n\
Clear all collected profiling data.\n\
@end deftypefn")
{
  octave_value_list retval;
  const int nargin = args.length ();

  if (nargin > 0)
    warning ("profiler_reset: ignoring extra arguments");

  profiler.reset ();

  return retval;
}

DEFUN (profiler_data, args, nargout,
  "-*- texinfo -*-\n\
@deftypefn  {Built-in Function} {} data = profiler_data ()\n\
Query the timings collected by the profiler.\n\
@end deftypefn")
{
  octave_value_list retval;
  const int nargin = args.length ();

  if (nargin > 0)
    warning ("profiler_data: ignoring extra arguments");

  retval(0) = profiler.get_data ();

  return retval;
}