Performance Timing

- Change the was performance measurements are taken.  This in preparation
  to automated daily perf charts, leading to efforts to speed up certain
  operations.
This commit is contained in:
Paul Beckingham 2011-08-15 21:53:01 -04:00
parent ad38d5b92e
commit ac9d1f3bfa
11 changed files with 182 additions and 53 deletions

View file

@ -27,6 +27,7 @@
#include <iostream> #include <iostream>
#include <fstream> #include <fstream>
#include <sstream>
#include <algorithm> #include <algorithm>
#include <pwd.h> #include <pwd.h>
#include <stdlib.h> #include <stdlib.h>
@ -35,12 +36,14 @@
#include <Context.h> #include <Context.h>
#include <Directory.h> #include <Directory.h>
#include <File.h> #include <File.h>
#include <Timer.h>
#include <text.h> #include <text.h>
#include <util.h> #include <util.h>
#include <main.h> #include <main.h>
#include <i18n.h> #include <i18n.h>
#include <../cmake.h> #include <cmake.h>
#ifdef HAVE_COMMIT
#include <commit.h>
#endif
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
Context::Context () Context::Context ()
@ -67,7 +70,7 @@ Context::~Context ()
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
int Context::initialize (int argc, const char** argv) int Context::initialize (int argc, const char** argv)
{ {
Timer t ("Context::initialize"); timer_init.start ();
int rc = 0; int rc = 0;
try try
@ -202,6 +205,8 @@ int Context::initialize (int argc, const char** argv)
else else
std::cout << *f << "\n"; std::cout << *f << "\n";
} }
timer_init.stop ();
return rc; return rc;
} }
@ -214,6 +219,37 @@ int Context::run ()
try try
{ {
rc = dispatch (output); rc = dispatch (output);
std::stringstream s;
s << "Perf "
<< PACKAGE_STRING
<< " "
#ifdef HAVE_COMMIT
<< COMMIT
#else
<< "-"
#endif
<< " "
<< Date ().toISO ()
<< " init:" << timer_init.total ()
<< " load:" << timer_load.total ()
<< " synch:" << timer_synch.total ()
<< " gc:" << timer_gc.total ()
<< " filter:" << timer_filter.total ()
<< " commit:" << timer_commit.total ()
<< " sort:" << timer_sort.total ()
<< " render:" << timer_render.total ()
<< " total:" << (timer_init.total () +
timer_load.total () +
timer_synch.total () +
timer_gc.total () +
timer_filter.total () +
timer_commit.total () +
timer_sort.total () +
timer_render.total ())
<< "\n";
debug (s.str ());
} }
catch (const std::string& error) catch (const std::string& error)
@ -273,8 +309,6 @@ int Context::run ()
// with the earliest argument. // with the earliest argument.
int Context::dispatch (std::string &out) int Context::dispatch (std::string &out)
{ {
Timer t ("Context::dispatch");
// Autocomplete args against keywords. // Autocomplete args against keywords.
std::string command; std::string command;
if (a3.find_command (command)) if (a3.find_command (command))

View file

@ -40,6 +40,7 @@
#include <File.h> #include <File.h>
#include <Directory.h> #include <Directory.h>
#include <A3.h> #include <A3.h>
#include <Timer.h>
class Context class Context
{ {
@ -112,6 +113,15 @@ public:
int terminal_width; int terminal_width;
int terminal_height; int terminal_height;
Timer timer_init;
Timer timer_load;
Timer timer_synch;
Timer timer_gc;
Timer timer_filter;
Timer timer_commit;
Timer timer_sort;
Timer timer_render;
}; };
#endif #endif

View file

@ -41,7 +41,6 @@
#include <Directory.h> #include <Directory.h>
#include <File.h> #include <File.h>
#include <ViewText.h> #include <ViewText.h>
#include <Timer.h>
#include <Color.h> #include <Color.h>
#include <main.h> #include <main.h>
@ -275,8 +274,6 @@ int TDB::load (std::vector <Task>& tasks)
// multiple files. // multiple files.
int TDB::loadPending (std::vector <Task>& tasks) int TDB::loadPending (std::vector <Task>& tasks)
{ {
Timer t ("TDB::loadPending");
std::string file; std::string file;
int line_number = 1; int line_number = 1;
@ -346,8 +343,6 @@ int TDB::loadPending (std::vector <Task>& tasks)
// multiple files. // multiple files.
int TDB::loadCompleted (std::vector <Task>& tasks) int TDB::loadCompleted (std::vector <Task>& tasks)
{ {
Timer t ("TDB::loadCompleted");
std::string file; std::string file;
int line_number = 1; int line_number = 1;
@ -456,7 +451,7 @@ void TDB::update (const Task& task)
// only modified by TDB::gc. // only modified by TDB::gc.
int TDB::commit () int TDB::commit ()
{ {
Timer t ("TDB::commit"); context.timer_gc.start ();
int quantity = mNew.size () + mModified.size (); int quantity = mNew.size () + mModified.size ();
@ -542,6 +537,7 @@ int TDB::commit ()
mNew.clear (); mNew.clear ();
} }
context.timer_gc.stop ();
return quantity; return quantity;
} }
@ -552,11 +548,14 @@ int TDB::commit ()
// Now cleans up dangling dependencies. // Now cleans up dangling dependencies.
int TDB::gc () int TDB::gc ()
{ {
Timer t ("TDB::gc"); context.timer_gc.start ();
// Allowed as a temporary override. // Allowed as a temporary override.
if (!context.config.getBoolean ("gc")) if (!context.config.getBoolean ("gc"))
{
context.timer_gc.stop ();
return 0; return 0;
}
int count_pending_changes = 0; int count_pending_changes = 0;
int count_completed_changes = 0; int count_completed_changes = 0;
@ -662,6 +661,8 @@ int TDB::gc ()
std::stringstream s; std::stringstream s;
s << "gc " << (count_pending_changes + count_completed_changes) << " tasks"; s << "gc " << (count_pending_changes + count_completed_changes) << " tasks";
context.debug (s.str ()); context.debug (s.str ());
context.timer_gc.stop ();
return count_pending_changes + count_completed_changes; return count_pending_changes + count_completed_changes;
} }

View file

@ -27,7 +27,6 @@
//#include <iostream> // TODO Remove. //#include <iostream> // TODO Remove.
#include <Context.h> #include <Context.h>
#include <Timer.h>
#include <text.h> #include <text.h>
#include <TDB2.h> #include <TDB2.h>
@ -62,7 +61,6 @@ void TF2::target (const std::string& f)
const std::vector <Task>& TF2::get_tasks () const std::vector <Task>& TF2::get_tasks ()
{ {
// std::cout << "# TF2::get_tasks " << _file.data << "\n"; // std::cout << "# TF2::get_tasks " << _file.data << "\n";
Timer timer ("TF2::get_tasks " + _file.data);
if (! _loaded_tasks) if (! _loaded_tasks)
load_tasks (); load_tasks ();
@ -242,6 +240,7 @@ void TF2::commit ()
void TF2::load_tasks () void TF2::load_tasks ()
{ {
// std::cout << "# TF2::load_tasks " << _file.data << "\n"; // std::cout << "# TF2::load_tasks " << _file.data << "\n";
context.timer_load.start ();
if (! _loaded_lines) if (! _loaded_lines)
load_lines (); load_lines ();
@ -281,6 +280,8 @@ void TF2::load_tasks ()
{ {
throw e + format (" in {1} at line {2}", _file.data, line_number); throw e + format (" in {1} at line {2}", _file.data, line_number);
} }
context.timer_load.stop ();
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -413,15 +414,28 @@ void TDB2::modify (const Task& task)
void TDB2::commit () void TDB2::commit ()
{ {
dump (); dump ();
Timer timer ("TDB2::commit");
context.timer_gc.start ();
pending.commit (); pending.commit ();
completed.commit (); completed.commit ();
undo.commit (); undo.commit ();
backlog.commit (); backlog.commit ();
synch_key.commit (); synch_key.commit ();
context.timer_gc.stop ();
dump (); dump ();
} }
////////////////////////////////////////////////////////////////////////////////
void TDB2::synch ()
{
context.timer_synch.start ();
context.timer_synch.stop ();
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Scans the pending tasks for any that are completed or deleted, and if so, // Scans the pending tasks for any that are completed or deleted, and if so,
// moves them to the completed.data file. Returns a count of tasks moved. // moves them to the completed.data file. Returns a count of tasks moved.
@ -429,28 +443,34 @@ void TDB2::commit ()
// Now cleans up dangling dependencies. // Now cleans up dangling dependencies.
int TDB2::gc () int TDB2::gc ()
{ {
Timer timer ("TDB2::gc"); context.timer_gc.start ();
// Allowed as a temporary override.
if (context.config.getBoolean ("gc"))
{
/* /*
pending.load_tasks pending.load_tasks
completed.load_tasks completed.load_tasks
for each pending for each pending
if status == completed || status == deleted if status == completed || status == deleted
pending.remove pending.remove
completed.add completed.add
if status == waiting && wait < now if status == waiting && wait < now
status = pending status = pending
wait.clear wait.clear
for each completed for each completed
if status == pending || status == waiting if status == pending || status == waiting
completed.remove completed.remove
pending.add pending.add
*/ */
// TODO Remove dangling dependencies // TODO Remove dangling dependencies
// TODO Wake up expired waiting tasks // TODO Wake up expired waiting tasks
}
context.timer_gc.stop ();
return 0; return 0;
} }

View file

@ -92,6 +92,7 @@ public:
void add (const Task&); void add (const Task&);
void modify (const Task&); void modify (const Task&);
void commit (); void commit ();
void synch ();
int gc (); int gc ();
int next_id (); int next_id ();

View file

@ -37,36 +37,72 @@ extern Context context;
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Timer starts when the object is constructed. // Timer starts when the object is constructed.
Timer::Timer (const std::string& description) Timer::Timer ()
: mDescription (description) : _description ("-")
, _running (false)
, _total (0)
{ {
gettimeofday (&mStart, NULL); }
////////////////////////////////////////////////////////////////////////////////
// Timer starts when the object is constructed with a description.
Timer::Timer (const std::string& description)
: _description (description)
, _running (false)
, _total (0)
{
start ();
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Timer stops when the object is destructed. // Timer stops when the object is destructed.
Timer::~Timer () Timer::~Timer ()
{ {
struct timeval end; stop ();
gettimeofday (&end, NULL);
std::stringstream s; std::stringstream s;
s << "Timer " // No i18n s << "Timer " // No i18n
<< mDescription << _description
<< " " << " "
<< std::setprecision (6) << std::setprecision (6)
#ifndef HAIKU #ifndef HAIKU
// Haiku fails on this - don't know why. // Haiku fails on this - don't know why.
<< std::fixed << std::fixed
#endif #endif
<< _total / 1000000.0
<< ((end.tv_sec - mStart.tv_sec) + ((end.tv_usec - mStart.tv_usec )
/ 1000000.0))
<< " sec"; << " sec";
context.debug (s.str ()); context.debug (s.str ());
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void Timer::start ()
{
if (!_running)
{
gettimeofday (&_start, NULL);
_running = true;
}
}
////////////////////////////////////////////////////////////////////////////////
void Timer::stop ()
{
if (_running)
{
struct timeval end;
gettimeofday (&end, NULL);
_running = false;
_total += (end.tv_sec - _start.tv_sec) * 1000000.0
+ (end.tv_usec - _start.tv_usec);
}
}
////////////////////////////////////////////////////////////////////////////////
unsigned long Timer::total () const
{
return _total;
}
////////////////////////////////////////////////////////////////////////////////

View file

@ -34,14 +34,21 @@
class Timer class Timer
{ {
public: public:
Timer ();
Timer (const std::string&); Timer (const std::string&);
~Timer (); ~Timer ();
Timer (const Timer&); Timer (const Timer&);
Timer& operator= (const Timer&); Timer& operator= (const Timer&);
void start ();
void stop ();
unsigned long total () const;
private: private:
std::string mDescription; std::string _description;
struct timeval mStart; bool _running;
struct timeval _start;
unsigned long _total;
}; };
#endif #endif

View file

@ -101,7 +101,7 @@ ViewTask::ViewTask ()
// //
std::string ViewTask::render (std::vector <Task>& data, std::vector <int>& sequence) std::string ViewTask::render (std::vector <Task>& data, std::vector <int>& sequence)
{ {
Timer timer ("ViewTask::render"); context.timer_render.start ();
// Determine minimal, ideal column widths. // Determine minimal, ideal column widths.
std::vector <int> minimal; std::vector <int> minimal;
@ -228,7 +228,10 @@ std::string ViewTask::render (std::vector <Task>& data, std::vector <int>& seque
// Stop if the line limit is exceeded. // Stop if the line limit is exceeded.
if (++_lines >= _truncate_lines && _truncate_lines != 0) if (++_lines >= _truncate_lines && _truncate_lines != 0)
{
context.timer_render.stop ();
return out; return out;
}
} }
// Compose, render columns, in sequence. // Compose, render columns, in sequence.
@ -289,16 +292,23 @@ std::string ViewTask::render (std::vector <Task>& data, std::vector <int>& seque
// Stop if the line limit is exceeded. // Stop if the line limit is exceeded.
if (++_lines >= _truncate_lines && _truncate_lines != 0) if (++_lines >= _truncate_lines && _truncate_lines != 0)
{
context.timer_render.stop ();
return out; return out;
}
} }
cells.clear (); cells.clear ();
// Stop if the row limit is exceeded. // Stop if the row limit is exceeded.
if (++_rows >= _truncate_rows && _truncate_rows != 0) if (++_rows >= _truncate_rows && _truncate_rows != 0)
{
context.timer_render.stop ();
return out; return out;
}
} }
context.timer_render.stop ();
return out; return out;
} }

View file

@ -31,7 +31,6 @@
#include <vector> #include <vector>
#include <stdlib.h> #include <stdlib.h>
#include <E9.h> #include <E9.h>
#include <Timer.h>
#include <text.h> #include <text.h>
#include <i18n.h> #include <i18n.h>
#include <Command.h> #include <Command.h>
@ -270,7 +269,7 @@ bool Command::displays_id () const
// Filter a specific list of tasks. // Filter a specific list of tasks.
void Command::filter (std::vector <Task>& input, std::vector <Task>& output) void Command::filter (std::vector <Task>& input, std::vector <Task>& output)
{ {
Timer timer ("Command::filter"); context.timer_filter.start ();
A3 filt = context.a3.extract_filter (); A3 filt = context.a3.extract_filter ();
filt.dump ("extract_filter"); filt.dump ("extract_filter");
@ -286,32 +285,38 @@ void Command::filter (std::vector <Task>& input, std::vector <Task>& output)
} }
else else
output = input; output = input;
context.timer_filter.stop ();
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Filter all tasks. // Filter all tasks.
void Command::filter (std::vector <Task>& output) void Command::filter (std::vector <Task>& output)
{ {
context.timer_filter.start ();
A3 filt = context.a3.extract_filter (); A3 filt = context.a3.extract_filter ();
filt.dump ("extract_filter"); filt.dump ("extract_filter");
if (filt.size ()) if (filt.size ())
{ {
context.timer_filter.stop ();
const std::vector <Task>& pending = context.tdb2.pending.get_tasks (); const std::vector <Task>& pending = context.tdb2.pending.get_tasks ();
context.timer_filter.start ();
E9 e (filt); E9 e (filt);
output.clear (); output.clear ();
std::vector <Task>::const_iterator task; std::vector <Task>::const_iterator task;
Timer timer ("Command::filter");
for (task = pending.begin (); task != pending.end (); ++task) for (task = pending.begin (); task != pending.end (); ++task)
if (e.evalFilter (*task)) if (e.evalFilter (*task))
output.push_back (*task); output.push_back (*task);
if (! filter_shortcut (filt)) if (! filter_shortcut (filt))
{ {
context.timer_filter.stop ();
const std::vector <Task>& completed = context.tdb2.completed.get_tasks (); // TODO Optional const std::vector <Task>& completed = context.tdb2.completed.get_tasks (); // TODO Optional
Timer timer ("Command::filter"); context.timer_filter.start ();
for (task = completed.begin (); task != completed.end (); ++task) for (task = completed.begin (); task != completed.end (); ++task)
if (e.evalFilter (*task)) if (e.evalFilter (*task))
output.push_back (*task); output.push_back (*task);
@ -321,8 +326,10 @@ void Command::filter (std::vector <Task>& output)
} }
else else
{ {
context.timer_filter.stop ();
const std::vector <Task>& pending = context.tdb2.pending.get_tasks (); const std::vector <Task>& pending = context.tdb2.pending.get_tasks ();
const std::vector <Task>& completed = context.tdb2.completed.get_tasks (); const std::vector <Task>& completed = context.tdb2.completed.get_tasks ();
context.timer_filter.start ();
std::vector <Task>::const_iterator task; std::vector <Task>::const_iterator task;
for (task = pending.begin (); task != pending.end (); ++task) for (task = pending.begin (); task != pending.end (); ++task)
@ -331,6 +338,8 @@ void Command::filter (std::vector <Task>& output)
for (task = completed.begin (); task != completed.end (); ++task) for (task = completed.begin (); task != completed.end (); ++task)
output.push_back (*task); output.push_back (*task);
} }
context.timer_filter.stop ();
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////

View file

@ -33,7 +33,6 @@
#include <Context.h> #include <Context.h>
#include <Duration.h> #include <Duration.h>
#include <Task.h> #include <Task.h>
#include <Timer.h>
#include <text.h> #include <text.h>
extern Context context; extern Context context;
@ -48,7 +47,7 @@ void sort_tasks (
std::vector <int>& order, std::vector <int>& order,
const std::string& keys) const std::string& keys)
{ {
Timer t ("Sort"); context.timer_sort.start ();
global_data = &data; global_data = &data;
@ -59,6 +58,8 @@ void sort_tasks (
// Only sort if necessary. // Only sort if necessary.
if (order.size ()) if (order.size ())
std::stable_sort (order.begin (), order.end (), sort_compare); std::stable_sort (order.begin (), order.end (), sort_compare);
context.timer_sort.stop ();
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////

View file

@ -63,9 +63,9 @@ for my $i (1 .. 1000)
diag ("1000 tasks added in " . (time () - $cursor) . " seconds"); diag ("1000 tasks added in " . (time () - $cursor) . " seconds");
$cursor = time (); $cursor = time ();
qx{../src/task rc:bench.rc modify /with/WITH/} for 1 .. 200; qx{../src/task rc:bench.rc $_ modify /with/WITH/} for 1 .. 200;
qx{../src/task rc:bench.rc $_ done} for 201 .. 400; qx{../src/task rc:bench.rc $_ done} for 201 .. 400;
qx{../src/task rc:bench.rc $_ start} for 401 .. 600; qx{../src/task rc:bench.rc $_ start} for 401 .. 600;
diag ("600 tasks altered in " . (time () - $cursor) . " seconds"); diag ("600 tasks altered in " . (time () - $cursor) . " seconds");
$cursor = time (); $cursor = time ();