I have an incomplete patch to fix bug 1961 (CPU profiler crashing squid
whenever AIO or other threads are used).
So far I have a timer class whose constructor/destructor perform the
timer setup and stats recording. That is attached.
The old profiler was done in a way which allowed live run-time snapshot
cachemgr report to be taken without stopping any timers. I've hooked
these classes into that reporting structure, but at present they will
result in the snapshots only recording *finished* timers, not the
currently active incomplete ones.
I'm thinking keeping the stack/list of timers from the old design but
only using it to dump a list of "currently incomplete" function calls
instead of using it to add incremental bits of timers to the report.
Does anyone have any other inspirational thoughts about how to keep
that kind of detail peeking using these classes in a multi-threaded soup
of code?
Amos
=== modified file 'lib/profiler/Profiler.cc'
--- lib/profiler/Profiler.cc 2012-01-20 18:55:04 +0000
+++ lib/profiler/Profiler.cc 2012-06-03 06:30:30 +0000
@@ -240,4 +240,26 @@
xp_UNACCOUNTED->start = tt;
}
+void
+XProfilerNode::stop()
+{
+ stopped_ = get_tick();
+
+ // calculate how long this timer was running.
+ hrtime_t delta = stopped_ - started_;
+
+ // kick initialization of timers statistics (just in case)
+ xprof_InitLib();
+
+ // Record timer details into global counters
+ xprof_stats_data * head = &(xprof_Timers[type_]->accu);
+ if (delta < head->best)
+ head->best = delta;
+ if (delta > head->worst)
+ head->worst = delta;
+ head->summ += delta;
+ head->count++;
+ head->overheads += get_tick() - stopped_;
+}
+
#endif /* USE_XPROF_STATS */
=== modified file 'lib/profiler/Profiler.h'
--- lib/profiler/Profiler.h 2011-01-11 07:31:04 +0000
+++ lib/profiler/Profiler.h 2012-06-03 06:31:34 +0000
@@ -32,6 +32,7 @@
hrtime_t worst;
hrtime_t count;
hrtime_t accum;
+ hrtime_t overheads;
int64_t summ;
};
@@ -47,12 +48,39 @@
extern TimersArray *xprof_Timers;
/* Exported functions */
- extern void xprof_start(xprof_type type, const char *timer);
- extern void xprof_stop(xprof_type type, const char *timer);
extern void xprof_event(void *data);
-#define PROF_start(probename) xprof_start(XPROF_##probename, #probename)
-#define PROF_stop(probename) xprof_stop(XPROF_##probename, #probename)
+/*
+/// This class provides a thread-safe timer for use in code profiling
+/// Timer kicks off when the class is creaated and terminates on destruct
+/// or if stop() method is called explicitly.
+///
+/// Use PROF_start(name) and PROF_stop(name) macros
+*/
+class XProfilerNode
+{
+public:
+ XProfilerNode(xprof_type aType, const char *aName) : type_(aType),
name_(aName), running_(true), overheads_(0) {
+ // init stopped to prevent negative times occuring if anything goes
wrong.
+ stopped_ = started_ = get_tick();
+ }
+ ~XProfilerNode() { stop(); }
+
+ // stop the timer.
+ void stop();
+
+private:
+ xprof_type type_; ///< which profile type to update when stopped
+ const char *name_; ///< printable version of the timers type name
+ bool running_; ///< whether this timer is still active, or been
stopped already
+ hrtime_t started_; ///< when this timer was started
+ hrtime_t stopped_; ///< when this timer was stopped
+ hrtime_t overheads_; ///< how much time has measurably been spent on
profiler internal code.
+};
+
+#define PROF_start(probename) XProfilerNode
XProfTimer_##probename(XPROF_##probename, #probename)
+// explicitly stop the timer. This is now optional.
+#define PROF_stop(probename) XProfTimer_##probename.stop()
#endif /* USE_XPROF_STATS */