diff options
Diffstat (limited to 'grapher')
-rw-r--r-- | grapher/Graph.cxx | 74 | ||||
-rw-r--r-- | grapher/Graph.hxx | 10 | ||||
-rw-r--r-- | grapher/GraphStyle.cxx | 59 | ||||
-rw-r--r-- | grapher/GraphWidget.cxx | 41 | ||||
-rw-r--r-- | grapher/GraphWidget.hxx | 1 | ||||
-rw-r--r-- | grapher/Time.hxx | 83 |
6 files changed, 164 insertions, 104 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 |