From 5f4f8b1129659adb2015ce42821faccf8fe6d8d5 Mon Sep 17 00:00:00 2001 From: Tim Moore Date: Wed, 27 May 2009 10:32:51 +0200 Subject: [PATCH] Templatize GraphData * grapher/GraphData.hxx (GraphDataBase): new superclass for GraphData. Split time data out as a separate vector. (GraphData): Rewrite as template. * grapher/GraphWidget.cxx (on_expose_event): Reflect GraphData templatization. Handle events with string values. * grapher/GraphWidget.hxx (GraphWidget): Keep pointers to GraphDataBase objects instead of GraphData. * grapher/StapParser.cxx (parseData): new member function (ioCallback): Handle new discreet event * grapher/StapParser.hxx (StapParser): keep pointers to GraphDataBase objects instead of GraphData * testsuite/systemtap.examples/general/grapher.stp: Display actual key pressed for keyboard event --- grapher/GraphData.hxx | 40 ++++----- grapher/GraphWidget.cxx | 85 ++++++++++++++----- grapher/GraphWidget.hxx | 4 +- grapher/StapParser.cxx | 77 +++++++++++++---- grapher/StapParser.hxx | 5 +- .../systemtap.examples/general/grapher.stp | 5 +- 6 files changed, 146 insertions(+), 70 deletions(-) diff --git a/grapher/GraphData.hxx b/grapher/GraphData.hxx index 2c0783c6d..9bf3b624d 100644 --- a/grapher/GraphData.hxx +++ b/grapher/GraphData.hxx @@ -7,44 +7,38 @@ namespace systemtap { - struct GraphData + struct GraphDataBase { - public: + virtual ~GraphDataBase() {} enum Style { BAR, - DOT + DOT, + EVENT }; - GraphData() : scale(1.0), style(BAR) + GraphDataBase() : scale(1.0), style(BAR) { color[0] = 0.0; color[1] = 1.0; color[2] = 0.0; } - typedef std::pair Datum; - typedef std::vector List; + typedef std::vector TimeList; // size of grid square at "normal" viewing double scale; double color[3]; Style style; - List data; - struct Compare - { - bool operator() (const Datum& lhs, const Datum& rhs) const - { - return lhs.first < rhs.first; - } - bool operator() (double lhs, const Datum& rhs) const - { - return lhs < rhs.first; - } - bool operator() (const Datum& lhs, double rhs) const - { - return lhs.first < rhs; - } - }; + TimeList times; }; + template + class GraphData : public GraphDataBase + { + public: + typedef T data_type; + typedef std::vector DataList; + DataList data; + }; struct CSVData { - typedef std::pair > Element; + typedef std::pair > + Element; std::vector elements; }; } diff --git a/grapher/GraphWidget.cxx b/grapher/GraphWidget.cxx index 34b4daf4d..d62ec4f32 100644 --- a/grapher/GraphWidget.cxx +++ b/grapher/GraphWidget.cxx @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include "GraphWidget.hxx" @@ -9,6 +10,8 @@ namespace systemtap { + using std::string; + GraphWidget::GraphWidget() : _left(0.0), _right(1.0), _top(1.0), _bottom(0.0), _lineWidth(10), _autoScaling(true), _autoScrolling(true), _zoomFactor(1.0), @@ -55,7 +58,7 @@ namespace systemtap { } - void GraphWidget::addGraphData(std::tr1::shared_ptr data) + void GraphWidget::addGraphData(std::tr1::shared_ptr data) { _datasets.push_back(data); } @@ -94,9 +97,9 @@ namespace systemtap ditr != de; ++ditr) { - if (!(*ditr)->data.empty()) + if (!(*ditr)->times.empty()) { - double lastDataTime = (*ditr)->data.back().first; + double lastDataTime = (*ditr)->times.back(); if (lastDataTime > latestTime) latestTime = lastDataTime; } @@ -108,16 +111,16 @@ namespace systemtap ditr != de; ++ditr) { - GraphData::List& gdata = (*ditr)->data; - if (gdata.size() <= 1) + GraphDataBase::TimeList& gtimes = (*ditr)->times; + if (gtimes.size() <= 1) continue; double totalDiff = 0.0; - for (GraphData::List::reverse_iterator ritr = gdata.rbegin(), - re = gdata.rend(); - ritr + 1 != gdata.rend(); + for (GraphDataBase::TimeList::reverse_iterator ritr = gtimes.rbegin(), + re = gtimes.rend(); + ritr + 1 != gtimes.rend(); ritr++) { - double timeDiff = ritr->first - (ritr + 1)->first; + double timeDiff = *ritr - *(ritr + 1); if (timeDiff < minDiff || (timeDiff != 0 && minDiff == 0)) minDiff = timeDiff; if (minDiff != 0 @@ -148,35 +151,71 @@ namespace systemtap itr != e; ++itr) { + std::tr1::shared_ptr > realData + = std::tr1::dynamic_pointer_cast >(*itr); + std::tr1::shared_ptr > stringData + = std::tr1::dynamic_pointer_cast >(*itr); cr->save(); cr->translate(0.0, height); cr->scale(1.0, -1.0); - GraphData::List::iterator lower - = std::lower_bound((*itr)->data.begin(), (*itr)->data.end(), _left, - GraphData::Compare()); - GraphData::List::iterator upper - = std::upper_bound((*itr)->data.begin(), (*itr)->data.end(), _right, - GraphData::Compare()); - for (GraphData::List::iterator ditr = lower, de = upper; + GraphDataBase::TimeList::iterator lower + = std::lower_bound((*itr)->times.begin(), (*itr)->times.end(), _left); + GraphDataBase::TimeList::iterator upper + = std::upper_bound((*itr)->times.begin(), (*itr)->times.end(), + _right); + // event bar + if ((*itr)->style == GraphDataBase::EVENT) + { + double eventHeight = height * ((*itr)->scale / 100.0); + cr->save(); + cr->set_line_width(3 * _lineWidth); + cr->set_source_rgba((*itr)->color[0], (*itr)->color[1], + (*itr)->color[2], .33); + cr->move_to(0, eventHeight); + cr->line_to(width, eventHeight); + cr->stroke(); + cr->restore(); + } + for (GraphDataBase::TimeList::iterator ditr = lower, de = upper; ditr != de; ++ditr) { + size_t dataIndex = ditr - (*itr)->times.begin(); cr->set_source_rgba((*itr)->color[0], (*itr)->color[1], (*itr)->color[2], 1.0); - if ((*itr)->style == GraphData::BAR) + if ((*itr)->style == GraphDataBase::BAR && realData) { - cr->move_to((ditr->first - _left) * horizScale, 0); - cr->line_to((ditr->first - _left) * horizScale, - ditr->second * height / (*itr)->scale); + cr->move_to((*ditr - _left) * horizScale, 0); + cr->line_to((*ditr - _left) * horizScale, + realData->data[dataIndex] * height / (*itr)->scale); cr->stroke(); } - else + else if ((*itr)->style == GraphDataBase::DOT && realData) { - cr->arc((ditr->first - _left) * horizScale, - ditr->second * height / (*itr)->scale, + cr->arc((*ditr - _left) * horizScale, + realData->data[dataIndex] * height / (*itr)->scale, _lineWidth / 2.0, 0.0, M_PI * 2.0); cr->fill(); } + else if ((*itr)->style == GraphDataBase::EVENT && stringData) + { + double eventHeight = height * ((*itr)->scale / 100.0); + cr->save(); + cr->select_font_face("Sans", Cairo::FONT_SLANT_NORMAL, + Cairo::FONT_WEIGHT_NORMAL); + cr->set_font_size(12.0); + cr->save(); + cr->scale(1.0, -1.0); + cr->move_to((*ditr - _left) * horizScale, + -eventHeight -3.0 * _lineWidth - 2.0); + cr->show_text(stringData->data[dataIndex]); + cr->restore(); + cr->rectangle((*ditr - _left) * horizScale - 1.5 * _lineWidth, + eventHeight - 1.5 * _lineWidth, + 3.0 * _lineWidth, 3.0 * _lineWidth); + cr->fill(); + cr->restore(); + } } cr->restore(); } diff --git a/grapher/GraphWidget.hxx b/grapher/GraphWidget.hxx index 46075b783..86ba771d5 100644 --- a/grapher/GraphWidget.hxx +++ b/grapher/GraphWidget.hxx @@ -17,7 +17,7 @@ namespace systemtap public: GraphWidget(); virtual ~GraphWidget(); - void addGraphData(std::tr1::shared_ptr data); + void addGraphData(std::tr1::shared_ptr data); void getExtents(double& left, double& right, double& top, double& bottom) const; void setExtents(double left, double right, double top, double bottom); double getLineWidth() { return _lineWidth; } @@ -38,7 +38,7 @@ namespace systemtap virtual bool on_button_release_event(GdkEventButton* event); virtual bool on_scroll_event(GdkEventScroll* event); bool on_timeout(); - typedef std::vector > DatasetList; + typedef std::vector > DatasetList; DatasetList _datasets; double _left; double _right; diff --git a/grapher/StapParser.cxx b/grapher/StapParser.cxx index c973b0aa8..8b72f93b5 100644 --- a/grapher/StapParser.cxx +++ b/grapher/StapParser.cxx @@ -1,6 +1,7 @@ #include "StapParser.hxx" #include +#include namespace systemtap { @@ -27,6 +28,29 @@ vector commaSplit(const string& inStr, size_t pos = 0) return result; } + void StapParser::parseData(std::tr1::shared_ptr gdata, + double time, const string& dataString) + { + std::istringstream stream(dataString); + std::tr1::shared_ptr > dblptr; + std::tr1::shared_ptr > strptr; + dblptr = std::tr1::dynamic_pointer_cast >(gdata); + if (dblptr) + { + double data; + stream >> data; + dblptr->times.push_back(time); + dblptr->data.push_back(data); + } + else if ((strptr = std::tr1 + ::dynamic_pointer_cast >(gdata)) + != 0) + { + strptr->times.push_back(time); + strptr->data.push_back(dataString); + } + } + bool StapParser::ioCallback(Glib::IOCondition ioCondition) { using namespace std; @@ -71,20 +95,38 @@ bool StapParser::ioCallback(Glib::IOCondition ioCondition) } else if ((found = dataString.find("%DataSet:") == 0)) { - std::tr1::shared_ptr dataSet(new GraphData); std::string setName; int hexColor; + double scale; std::string style; std::istringstream stream(dataString.substr(9)); - stream >> setName >> dataSet->scale >> std::hex >> hexColor + stream >> setName >> scale >> std::hex >> hexColor >> style; - dataSet->color[0] = (hexColor >> 16) / 255.0; - dataSet->color[1] = ((hexColor >> 8) & 0xff) / 255.0; - dataSet->color[2] = (hexColor & 0xff) / 255.0; - if (style == "dot") - dataSet->style = GraphData::DOT; - _dataSets.insert(std::make_pair(setName, dataSet)); - _widget.addGraphData(dataSet); + if (style == "bar" || style == "dot") + { + std::tr1::shared_ptr > + dataSet(new GraphData); + if (style == "dot") + dataSet->style = GraphDataBase::DOT; + dataSet->color[0] = (hexColor >> 16) / 255.0; + dataSet->color[1] = ((hexColor >> 8) & 0xff) / 255.0; + dataSet->color[2] = (hexColor & 0xff) / 255.0; + dataSet->scale = scale; + _dataSets.insert(std::make_pair(setName, dataSet)); + _widget.addGraphData(dataSet); + } + else if (style == "discreet") + { + std::tr1::shared_ptr > + dataSet(new GraphData); + dataSet->style = GraphDataBase::EVENT; + dataSet->color[0] = (hexColor >> 16) / 255.0; + dataSet->color[1] = ((hexColor >> 8) & 0xff) / 255.0; + dataSet->color[2] = (hexColor & 0xff) / 255.0; + dataSet->scale = scale; + _dataSets.insert(std::make_pair(setName, dataSet)); + _widget.addGraphData(dataSet); + } } else if ((found = dataString.find("%CSV:") == 0)) { @@ -96,8 +138,9 @@ bool StapParser::ioCallback(Glib::IOCondition ioCondition) { DataMap::iterator setIter = _dataSets.find(*tokIter); if (setIter != _dataSets.end()) - _csv.elements.push_back(CSVData::Element(*tokIter, - setIter->second)); + _csv.elements + .push_back(CSVData::Element(*tokIter, + setIter->second)); } } } @@ -115,23 +158,21 @@ bool StapParser::ioCallback(Glib::IOCondition ioCondition) tokIter != e; ++tokIter, ++i) { - std::istringstream stream(*tokIter); - double data; - stream >> data; - _csv.elements[i].second - ->data.push_back(std::make_pair(time, data)); + parseData(_csv.elements[i].second, time, *tokIter); } } else { std::string dataSet; double time; - double data; + string data; std::istringstream stream(dataString); stream >> dataSet >> time >> data; DataMap::iterator itr = _dataSets.find(dataSet); if (itr != _dataSets.end()) - itr->second->data.push_back(std::make_pair(time, data)); + { + parseData(itr->second, time, data); + } } } _buffer.erase(0, ret + 1); diff --git a/grapher/StapParser.hxx b/grapher/StapParser.hxx index 624accc78..e11e7302e 100644 --- a/grapher/StapParser.hxx +++ b/grapher/StapParser.hxx @@ -7,7 +7,7 @@ namespace systemtap class StapParser { std::string _buffer; - typedef std::map > DataMap; + typedef std::map > DataMap; DataMap _dataSets; CSVData _csv; Gtk::Window& _win; @@ -15,7 +15,8 @@ class StapParser public: StapParser(Gtk::Window& win, GraphWidget& widget) : _win(win), _widget(widget) {} - + void parseData(std::tr1::shared_ptr gdata, + double time, const std::string& dataString); bool ioCallback(Glib::IOCondition ioCondition); }; diff --git a/testsuite/systemtap.examples/general/grapher.stp b/testsuite/systemtap.examples/general/grapher.stp index 5d9b4bb54..26d35aca4 100644 --- a/testsuite/systemtap.examples/general/grapher.stp +++ b/testsuite/systemtap.examples/general/grapher.stp @@ -6,7 +6,7 @@ printf ("%%Title:CPU utilization\n"); printf ("%%XAxisTitle:Time\n"); printf ("%%YAxisTitle:Percent\n"); printf ("%%DataSet:cpu 100 00ff00 bar\n"); -printf ("%%DataSet:kbd 100 ff0000 dot\n"); +printf ("%%DataSet:kbd 75 ff0000 discreet\n"); } # CPU utilization @@ -28,5 +28,6 @@ probe timer.ms(100) { # collect utilization percentages frequently } probe kernel.function("kbd_event") { - printf("kbd %d %d\n", gettimeofday_ms(), 75) + if ($event_type == 1 && $value) + printf("kbd %d %d\n", gettimeofday_ms(), $event_code) } -- 2.43.5