summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--grapher/Graph.cxx74
-rw-r--r--grapher/Graph.hxx10
-rw-r--r--grapher/GraphStyle.cxx59
-rw-r--r--grapher/GraphWidget.cxx41
-rw-r--r--grapher/GraphWidget.hxx1
-rw-r--r--grapher/Time.hxx83
-rwxr-xr-xtestsuite/systemtap.examples/general/grapher.stp10
7 files changed, 167 insertions, 111 deletions
diff --git a/grapher/Graph.cxx b/grapher/Graph.cxx
index dc808fa4..079cd63e 100644
--- a/grapher/Graph.cxx
+++ b/grapher/Graph.cxx
@@ -19,7 +19,9 @@ using namespace std::tr1;
GraphDataList GraphDataBase::graphData;
sigc::signal<void> GraphDataBase::graphDataChanged;
-
+
+int64_t Graph::_currentTime = 0;
+
Graph::Graph(double x, double y)
: _width(600), _height(200), _graphX(0), _graphY(0),
_graphWidth(580), _graphHeight(180),
@@ -39,59 +41,13 @@ void Graph::draw(Cairo::RefPtr<Cairo::Context> cr)
if (_autoScaling)
{
- // line separation
- int linesPossible = (int)(_graphWidth / (_lineWidth + 2.0));
// Find latest time.
- int64_t latestTime = 0;
- for (GraphDataList::iterator ditr = _datasets.begin(),
- de = _datasets.end();
- ditr != de;
- ++ditr)
- {
- if (!(*ditr)->times.empty())
- {
- int64_t lastDataTime = (*ditr)->times.back();
- if (lastDataTime > latestTime)
- latestTime = lastDataTime;
- }
- }
- int64_t minDiff = 0;
- int64_t maxTotal = 0;
- for (GraphDataList::iterator ditr = _datasets.begin(),
- de = _datasets.end();
- ditr != de;
- ++ditr)
- {
- GraphDataBase::TimeList& gtimes = (*ditr)->times;
- if (gtimes.size() <= 1)
- continue;
- double totalDiff = 0.0;
- for (GraphDataBase::TimeList::reverse_iterator ritr = gtimes.rbegin(),
- re = gtimes.rend();
- ritr + 1 != gtimes.rend();
- ritr++)
- {
- int64_t timeDiff = *ritr - *(ritr + 1);
- if (timeDiff < minDiff || (timeDiff != 0 && minDiff == 0))
- minDiff = timeDiff;
- if (minDiff != 0
- && ((totalDiff + timeDiff) / minDiff + 1) > linesPossible)
- break;
- totalDiff += timeDiff;
- }
- if (totalDiff > maxTotal)
- maxTotal = totalDiff;
- }
- // Now we have a global scale.
- _right = latestTime;
- if (maxTotal != 0)
- _left = latestTime - maxTotal;
- else
- _left = _right - 1;
+ _right = _currentTime / 1000;
+ // Assume 1 pixel = 5 milliseconds
+ _left = _right - static_cast<int64_t>(5000 / _zoomFactor);
}
cr->save();
- double horizScale
- = _zoomFactor * _graphWidth / static_cast<double>(_right - _left);
+ double horizScale = getHorizontalScale();
cr->translate(_xOffset, _yOffset);
cr->set_line_width(_lineWidth);
@@ -138,7 +94,7 @@ void Graph::draw(Cairo::RefPtr<Cairo::Context> cr)
double diff = static_cast<double>(_right - _left);
int64_t majorUnit
= static_cast<int64_t>(pow(10.0, floor(log(diff) / log(10.0))));
- int64_t startTime = (_left / majorUnit) * majorUnit;
+ int64_t startTime = ((_left - _timeBase) / majorUnit) * majorUnit + _timeBase;
cr->save();
cr->set_source_rgba(1.0, 1.0, 1.0, .9);
cr->set_line_cap(Cairo::LINE_CAP_BUTT);
@@ -146,10 +102,11 @@ void Graph::draw(Cairo::RefPtr<Cairo::Context> cr)
cr->select_font_face("Sans", Cairo::FONT_SLANT_NORMAL,
Cairo::FONT_WEIGHT_NORMAL);
cr->set_font_size(10.0);
- cr->move_to(_xOffset, _yOffset);
- cr->line_to(_xOffset, _height);
- cr->move_to(_xOffset, _graphHeight);
- cr->line_to(_graphWidth, _graphHeight);
+ cr->translate(_xOffset, 0.0);
+ cr->move_to(0.0, _yOffset);
+ cr->line_to(0.0, _height);
+ cr->move_to(0.0, _graphHeight);
+ cr->line_to(_graphWidth - _xOffset, _graphHeight);
cr->stroke();
std::valarray<double> dash(1);
dash[0] = _graphHeight / 10;
@@ -157,7 +114,7 @@ void Graph::draw(Cairo::RefPtr<Cairo::Context> cr)
double prevTextAdvance = 0;
for (int64_t tickVal = startTime; tickVal <= _right; tickVal += majorUnit)
{
- double x = (tickVal - _left) * horizScale + _xOffset;
+ double x = (tickVal - _right) * horizScale + _graphWidth;
cr->move_to(x, _yOffset);
cr->line_to(x, _graphHeight);
std::ostringstream stream;
@@ -213,8 +170,7 @@ bool Graph::containsPoint(double x, double y)
int64_t Graph::getTimeAtPoint(double x)
{
- return (_left
- + (_right - _left) * ((x - _xOffset)/(_zoomFactor * _graphWidth)));
+ return (x - _graphWidth) / getHorizontalScale() + _right;
}
void Graph::window2GraphCoords(double x, double y,
diff --git a/grapher/Graph.hxx b/grapher/Graph.hxx
index efabd22d..7037efa9 100644
--- a/grapher/Graph.hxx
+++ b/grapher/Graph.hxx
@@ -50,12 +50,22 @@ public:
GraphDataList& getDatasets() { return _datasets; }
int64_t getTimeAtPoint(double x);
void window2GraphCoords(double x, double y, double& xgraph, double& ygraph);
+ static void setCurrentTime(int64_t time) { _currentTime = time; }
+
+ /*
+ * universal horizontal factor
+ */
+ double getHorizontalScale()
+ {
+ return _graphWidth / static_cast<double>(_right - _left);
+ }
protected:
GraphDataList _datasets;
int64_t _left;
int64_t _right;
double _top;
double _bottom;
+ static int64_t _currentTime;
};
}
#endif
diff --git a/grapher/GraphStyle.cxx b/grapher/GraphStyle.cxx
index 6bf4e109..86cb823c 100644
--- a/grapher/GraphStyle.cxx
+++ b/grapher/GraphStyle.cxx
@@ -31,8 +31,15 @@ void GraphStyleBar::draw(std::tr1::shared_ptr<GraphDataBase> graphData,
int64_t left, right;
double top, bottom;
graph->getExtents(left, right, top, bottom);
- double horizScale = (graph->_zoomFactor * graph->_graphWidth
- / static_cast<double>(right - left));
+ double horizScale = graph->getHorizontalScale();
+ cr->save();
+ double lineWidth = cr->get_line_width();
+ cr->translate(graph->_graphWidth, 0.0);
+ cr->scale(horizScale, 1.0);
+ cr->translate(left - right, 0.0);
+ cr->set_line_width(lineWidth / horizScale);
+ cr->set_source_rgba(graphData->color[0], graphData->color[1],
+ graphData->color[2], 1.0);
GraphDataBase::TimeList::iterator lower
= lower_bound(graphData->times.begin(), graphData->times.end(), left);
GraphDataBase::TimeList::iterator upper
@@ -42,14 +49,13 @@ void GraphStyleBar::draw(std::tr1::shared_ptr<GraphDataBase> graphData,
++ditr)
{
size_t dataIndex = ditr - graphData->times.begin();
- cr->set_source_rgba(graphData->color[0], graphData->color[1],
- graphData->color[2], 1.0);
- cr->move_to((*ditr - left) * horizScale, 0);
- cr->line_to((*ditr - left) * horizScale,
+ cr->move_to((*ditr - left), 0);
+ cr->line_to((*ditr - left),
realData->data[dataIndex] * graph->_graphHeight
/ graphData->scale);
cr->stroke();
}
+ cr->restore();
}
ssize_t GraphStyleBar::dataIndexAtPoint(double x, double y,
@@ -63,7 +69,7 @@ ssize_t GraphStyleBar::dataIndexAtPoint(double x, double y,
int64_t left, right;
double top, bottom;
graph->getExtents(left, right, top, bottom);
- double t = graph->getTimeAtPoint(x);
+ int64_t t = graph->getTimeAtPoint(x);
TimeListPair range
= equal_range(graphData->times.begin(), graphData->times.end(), t);
if (range.first == graphData->times.end())
@@ -89,12 +95,14 @@ void GraphStyleDot::draw(std::tr1::shared_ptr<GraphDataBase> graphData,
int64_t left, right;
double top, bottom;
graph->getExtents(left, right, top, bottom);
- double horizScale = (graph->_zoomFactor * graph->_graphWidth
- / static_cast<double>(right - left));
+ double horizScale = graph->getHorizontalScale();;
GraphDataBase::TimeList::iterator lower
= lower_bound(graphData->times.begin(), graphData->times.end(), left);
GraphDataBase::TimeList::iterator upper
= upper_bound(graphData->times.begin(), graphData->times.end(), right);
+ cr->translate(graph->_graphWidth, 0.0);
+ cr->scale(horizScale, 1.0);
+ cr->translate(left - right, 0.0);
cr->set_source_rgba(graphData->color[0], graphData->color[1],
graphData->color[2], 1.0);
@@ -103,12 +111,14 @@ void GraphStyleDot::draw(std::tr1::shared_ptr<GraphDataBase> graphData,
++ditr)
{
size_t dataIndex = ditr - graphData->times.begin();
- cr->arc((*ditr - left) * horizScale,
+ // XXX Fix unequal scale in x, y
+ cr->arc((*ditr - left),
(realData->data[dataIndex]
* graph->_graphHeight / graphData->scale),
- graph->_lineWidth / 2.0, 0.0, M_PI * 2.0);
+ (graph->_lineWidth / (2.0 * horizScale)), 0.0, M_PI * 2.0);
cr->fill();
}
+ cr->restore();
}
GraphStyleEvent GraphStyleEvent::instance;
@@ -123,8 +133,7 @@ void GraphStyleEvent::draw(std::tr1::shared_ptr<GraphDataBase> graphData,
int64_t left, right;
double top, bottom;
graph->getExtents(left, right, top, bottom);
- double horizScale = (graph->_zoomFactor * graph->_graphWidth
- / static_cast<double>(right - left));
+ double horizScale = graph->getHorizontalScale();
double eventHeight = graph->_graphHeight * (graphData->scale / 100.0);
cr->save();
cr->set_line_width(3 * graph->_lineWidth);
@@ -134,6 +143,12 @@ void GraphStyleEvent::draw(std::tr1::shared_ptr<GraphDataBase> graphData,
cr->line_to(graph->_graphWidth, eventHeight);
cr->stroke();
cr->restore();
+ cr->save();
+ // Global translation for user scaling
+ cr->translate(graph->_graphWidth, 0.0);
+ cr->scale(horizScale, 1.0);
+ cr->translate(left - right, 0.0);
+
GraphDataBase::TimeList::iterator lower
= lower_bound(graphData->times.begin(), graphData->times.end(), left);
GraphDataBase::TimeList::iterator upper
@@ -147,12 +162,15 @@ void GraphStyleEvent::draw(std::tr1::shared_ptr<GraphDataBase> graphData,
cr->save();
cr->set_source_rgba(graphData->color[0], graphData->color[1],
graphData->color[2], 1.0);
- cr->rectangle((*ditr - left) * horizScale - 1.5 * graph->_lineWidth,
+ // Do cairo transformations here instead of our own math?
+ cr->rectangle((*ditr - left) - (1.5 * graph->_lineWidth / horizScale),
eventHeight - 1.5 * graph->_lineWidth,
- 3.0 * graph->_lineWidth, 3.0 * graph->_lineWidth);
+ 3.0 * (graph->_lineWidth / horizScale),
+ 3.0 * graph->_lineWidth);
cr->fill();
cr->restore();
}
+ cr->restore();
}
ssize_t GraphStyleEvent::dataIndexAtPoint(double x, double y,
@@ -166,8 +184,7 @@ ssize_t GraphStyleEvent::dataIndexAtPoint(double x, double y,
int64_t left, right;
double top, bottom;
graph->getExtents(left, right, top, bottom);
- double horizScale = (graph->_zoomFactor * graph->_graphWidth
- / static_cast<double>(right - left));
+ double horizScale = graph->getHorizontalScale();
double eventHeight = graph->_graphHeight * (graphData->scale / 100.0);
GraphDataBase::TimeList::iterator lower
= lower_bound(graphData->times.begin(), graphData->times.end(), left);
@@ -177,14 +194,16 @@ ssize_t GraphStyleEvent::dataIndexAtPoint(double x, double y,
double xgraph, ygraph;
graph->window2GraphCoords(x, y, xgraph, ygraph);
double yrect = eventHeight - 1.5 * graph->_lineWidth;
+ double rectWidth = 3 * graph->_lineWidth;
for (GraphDataBase::TimeList::iterator ditr = lower, de = upper;
ditr != de;
++ditr)
{
- double xrect = (*ditr - left) * horizScale - 1.5 * graph->_lineWidth;
- if (xrect <= xgraph && xgraph < xrect + 3.0 * graph->_lineWidth
+ double xrect = ((*ditr - right) * horizScale + graph->_graphWidth
+ - .5 * rectWidth);
+ if (xrect <= xgraph && xgraph < xrect + rectWidth
&& yrect <= ygraph && ygraph < yrect + 3.0 * graph->_lineWidth)
- return static_cast<ssize_t>(distance(lower, ditr));
+ return static_cast<ssize_t>(distance(graphData->times.begin(), ditr));
}
return -1;
}
diff --git a/grapher/GraphWidget.cxx b/grapher/GraphWidget.cxx
index db7493fb..ce2f934f 100644
--- a/grapher/GraphWidget.cxx
+++ b/grapher/GraphWidget.cxx
@@ -23,6 +23,7 @@
#include "GraphWidget.hxx"
#include "CairoWidget.hxx"
+#include "Time.hxx"
namespace systemtap
{
@@ -33,7 +34,7 @@ using namespace std::tr1;
GraphWidget::GraphWidget()
: _trackingDrag(false), _width(600), _height(200), _mouseX(0.0),
- _mouseY(0.0), _globalTimeBase(0), _timeBaseInitialized(false)
+ _mouseY(0.0), _globalTimeBase(Time::getAbs() / 1000)
{
add_events(Gdk::POINTER_MOTION_MASK | Gdk::BUTTON_PRESS_MASK
| Gdk::BUTTON_RELEASE_MASK | Gdk::SCROLL_MASK);
@@ -157,27 +158,11 @@ bool GraphWidget::on_expose_event(GdkEventExpose* event)
cr->save();
cr->set_source_rgba(0.0, 0.0, 0.0, 1.0);
cr->paint();
- if (!_timeBaseInitialized && !getGraphData().empty())
- {
- GraphDataList& graphData = getGraphData();
- int64_t earliest = INT64_MAX;
- for (GraphDataList::iterator gd = graphData.begin(),
- end = graphData.end();
- gd != end;
- ++gd)
- {
- if (!(*gd)->times.empty() && (*gd)->times[0] < earliest)
- earliest = (*gd)->times[0];
- }
- if (earliest != INT64_MAX)
- {
- _globalTimeBase = earliest;
- _timeBaseInitialized = true;
- }
- }
+ int64_t currentTime = Time::getAbs();
+ Graph::setCurrentTime(currentTime);
for (GraphList::iterator g = _graphs.begin(); g != _graphs.end(); ++g)
{
- if (_displayRelativeTimes && _timeBaseInitialized)
+ if (_displayRelativeTimes)
(*g)->_timeBase = _globalTimeBase;
else
(*g)->_timeBase = 0.0;
@@ -256,8 +241,10 @@ bool GraphWidget::on_motion_notify_event(GdkEventMotion* event)
const int width = allocation.get_width();
double motion = (_mouseX - _dragOriginX) / (double) width;
double increment = motion * (_dragOrigLeft - _dragOrigRight);
- _activeGraph->_left = _dragOrigLeft + increment;
- _activeGraph->_right = _dragOrigRight + increment;
+ _activeGraph->_left
+ = _dragOrigLeft + increment / _activeGraph->_zoomFactor;
+ _activeGraph->_right
+ = _dragOrigRight + increment / _activeGraph->_zoomFactor;
queue_draw();
}
if (_hoverText && _hoverText->isVisible())
@@ -278,10 +265,16 @@ bool GraphWidget::on_scroll_event(GdkEventScroll* event)
{
if ((*gitr)->containsPoint(event->x, event->y))
{
+ double oldZoom = (*gitr)->_zoomFactor;
if (event->direction == GDK_SCROLL_UP)
- (*gitr)->_zoomFactor += .1;
+ (*gitr)->_zoomFactor *= 1.1;
else if (event->direction == GDK_SCROLL_DOWN)
- (*gitr)->_zoomFactor -= .1;
+ (*gitr)->_zoomFactor /= 1.1;
+ int64_t left, right;
+ double top, bottom;
+ (*gitr)->getExtents(left, right, top, bottom);
+ right = left - (left - right) * (oldZoom / (*gitr)->_zoomFactor);
+ (*gitr)->setExtents(left, right, top, bottom);
queue_draw();
break;
}
diff --git a/grapher/GraphWidget.hxx b/grapher/GraphWidget.hxx
index f90da361..f2801cd2 100644
--- a/grapher/GraphWidget.hxx
+++ b/grapher/GraphWidget.hxx
@@ -81,7 +81,6 @@ protected:
double _mouseX;
double _mouseY;
int64_t _globalTimeBase;
- bool _timeBaseInitialized;
std::tr1::shared_ptr<Graph> getGraphUnderPoint(double x, double y);
void establishHoverTimeout();
Gtk::CheckButton* _relativeTimesButton;
diff --git a/grapher/Time.hxx b/grapher/Time.hxx
new file mode 100644
index 00000000..7e16b7b2
--- /dev/null
+++ b/grapher/Time.hxx
@@ -0,0 +1,83 @@
+// systemtap grapher
+// Copyright (C) 2009 Red Hat Inc.
+//
+// This file is part of systemtap, and is free software. You can
+// redistribute it and/or modify it under the terms of the GNU General
+// Public License (GPL); either version 2, or (at your option) any
+// later version.
+
+#ifndef SYSTEMTAP_GRAPHER_TIME_HXX
+#define SYSTEMTAP_GRAPHER_TIME_HXX 1
+
+#include <stdint.h>
+#include <sys/time.h>
+
+namespace systemtap
+{
+
+template<typename T>
+class Singleton
+{
+public:
+ static T& instance()
+ {
+ static T _instance;
+ return _instance;
+ }
+protected:
+ Singleton() {}
+private:
+ // Insure that singleton is constructed before main() is called.
+ struct InstanceBuilder
+ {
+ InstanceBuilder()
+ {
+ instance();
+ }
+ };
+ static InstanceBuilder _instanceBuilder;
+};
+
+template<typename T>
+typename Singleton<T>::InstanceBuilder Singleton<T>::_instanceBuilder;
+
+class Time : public Singleton<Time>
+{
+public:
+ Time()
+ : origin(0)
+ {
+ origin = getTime();
+ }
+
+ int64_t getTime()
+ {
+ timeval tval;
+ gettimeofday(&tval, 0);
+ int64_t now = toUs(tval);
+ return now - origin;
+ }
+
+ static int64_t get()
+ {
+ return instance().getTime();
+ }
+
+ static int64_t getAbs()
+ {
+ timeval tval;
+ gettimeofday(&tval, 0);
+ return toUs(tval);
+ }
+
+ static int64_t toUs(const timeval& t)
+ {
+ int64_t result = t.tv_sec * 1000000;
+ result += t.tv_usec;
+ return result;
+ }
+
+ int64_t origin;
+};
+}
+#endif
diff --git a/testsuite/systemtap.examples/general/grapher.stp b/testsuite/systemtap.examples/general/grapher.stp
index 46f5063c..a830b153 100755
--- a/testsuite/systemtap.examples/general/grapher.stp
+++ b/testsuite/systemtap.examples/general/grapher.stp
@@ -38,17 +38,13 @@ probe kernel.function("pty_write") {
count = %(kernel_v>="2.6.31" %? $c %: $count %)
if (count > 0) {
printf("pty %d ", gettimeofday_ms())
- str = kernel_string($buf)
+ str = $buf
for (i = 0; i < count; ++i) {
if (i > 1)
printf("\n")
- # yes it's gross
- c = substr(str, i, 1)
- printf("%s", text_str(c))
+ c = kernel_char(str + i)
+ printf("%c", c)
}
printf("%c", 0)
}
}
-
-
-