summaryrefslogtreecommitdiff
path: root/ui
diff options
context:
space:
mode:
authorPeter Wu <peter@lekensteyn.nl>2017-04-12 22:04:38 +0200
committerPeter Wu <peter@lekensteyn.nl>2017-04-20 15:18:36 +0000
commit9b0b2c3d59a698ac80c2d9911575d96c7803a08d (patch)
treecd7e08093a8794e03fc4b97964f734861992e9ca /ui
parent691d803037f777ff1bed025a48a48aa92956967f (diff)
downloadwireshark-9b0b2c3d59a698ac80c2d9911575d96c7803a08d.tar.gz
Qt: show relative time for the IO Graph in an appropriate unit
The GTK+ UI performs automatic formatting of the units (us, ms, s) based on the magnitude of the value (for MIN/MAX/SUM calculations). Internally the numbers are stored as integers (microseconds). The Qt UI did not have this formatting feature yet and would therefore display the values as-is (in microseconds). This patch rescales the Y value and appends an appropriate label (s, ms or us). With multiple graphs, rescaling is disabled completely for simplicity (GTK+ would still try to find an appropriate unit prefix if there are multiple time graphs). Bug: 12828 Change-Id: I26ed68fc3497e06ac283a618fee8b673b1b0cf71 Reviewed-on: https://code.wireshark.org/review/21062 Petri-Dish: Peter Wu <peter@lekensteyn.nl> Tested-by: Petri Dish Buildbot <buildbot-no-reply@wireshark.org> Reviewed-by: Peter Wu <peter@lekensteyn.nl>
Diffstat (limited to 'ui')
-rw-r--r--ui/qt/io_graph_dialog.cpp135
-rw-r--r--ui/qt/io_graph_dialog.h10
2 files changed, 127 insertions, 18 deletions
diff --git a/ui/qt/io_graph_dialog.cpp b/ui/qt/io_graph_dialog.cpp
index ba9174a1f3..bd76d42304 100644
--- a/ui/qt/io_graph_dialog.cpp
+++ b/ui/qt/io_graph_dialog.cpp
@@ -353,7 +353,7 @@ void IOGraphDialog::addGraph(bool checked, QString name, QString dfilter, int co
ti->setText(sma_period_col_, moving_average_to_name_[moving_average]);
ti->setData(sma_period_col_, Qt::UserRole, moving_average);
- connect(this, SIGNAL(recalcGraphData(capture_file *)), iog, SLOT(recalcGraphData(capture_file *)));
+ connect(this, SIGNAL(recalcGraphData(capture_file *, bool)), iog, SLOT(recalcGraphData(capture_file *, bool)));
connect(this, SIGNAL(reloadValueUnitFields()), iog, SLOT(reloadValueUnitField()));
connect(&cap_file_, SIGNAL(captureFileClosing()), iog, SLOT(captureFileClosing()));
connect(iog, SIGNAL(requestRetap()), this, SLOT(scheduleRetap()));
@@ -466,6 +466,9 @@ void IOGraphDialog::scheduleReplot(bool now)
{
need_replot_ = true;
if (now) updateStatistics();
+ // A plot finished, force an update of the legend now in case a time unit
+ // was involved (which might append "(ms)" to the label).
+ updateLegend();
}
void IOGraphDialog::scheduleRecalc(bool now)
@@ -788,7 +791,11 @@ void IOGraphDialog::updateLegend()
IOGraph *iog = NULL;
if (ti && ti->checkState(name_col_) == Qt::Checked) {
iog = VariantPointer<IOGraph>::asPtr(ti->data(name_col_, Qt::UserRole));
- vu_label_set.insert(iog->valueUnitLabel());
+ QString label(iog->valueUnitLabel());
+ if (!iog->scaledValueUnit().isEmpty()) {
+ label += " (" + iog->scaledValueUnit() + ")";
+ }
+ vu_label_set.insert(label);
}
}
@@ -1054,7 +1061,16 @@ void IOGraphDialog::updateStatistics()
if (need_recalc_ && !file_closed_) {
need_recalc_ = false;
need_replot_ = true;
- emit recalcGraphData(cap_file_.capFile());
+ int enabled_graphs = 0;
+ for (int i = 0; i < ui->graphTreeWidget->topLevelItemCount(); i++) {
+ QTreeWidgetItem *item = ui->graphTreeWidget->topLevelItem(i);
+ if (item && item->checkState(name_col_) == Qt::Checked) {
+ ++enabled_graphs;
+ }
+ }
+ // With multiple visible graphs, disable Y scaling to avoid
+ // multiple, distinct units.
+ emit recalcGraphData(cap_file_.capFile(), enabled_graphs == 1);
if (!tracer_->graph()) {
if (base_graph_ && base_graph_->data()->size() > 0) {
tracer_->setGraph(base_graph_);
@@ -2022,7 +2038,7 @@ QMap<int, QString> IOGraph::movingAveragesToNames()
return maton;
}
-void IOGraph::recalcGraphData(capture_file *cap_file)
+void IOGraph::recalcGraphData(capture_file *cap_file, bool enable_scaling)
{
/* Moving average variables */
unsigned int mavg_in_average_count = 0, mavg_left = 0, mavg_right = 0;
@@ -2102,9 +2118,98 @@ void IOGraph::recalcGraphData(capture_file *cap_file)
}
// qDebug() << "=rgd i" << i << ts << val;
}
+
+ // attempt to rescale time values to specific units
+ if (enable_scaling) {
+ calculateScaledValueUnit();
+ } else {
+ scaled_value_unit_.clear();
+ }
+
emit requestReplot();
}
+void IOGraph::calculateScaledValueUnit()
+{
+ // Reset unit and recalculate if needed.
+ scaled_value_unit_.clear();
+
+ // If there is no field, scaling is not possible.
+ if (hf_index_ < 0) {
+ return;
+ }
+
+ switch (val_units_) {
+ case IOG_ITEM_UNIT_CALC_SUM:
+ case IOG_ITEM_UNIT_CALC_MAX:
+ case IOG_ITEM_UNIT_CALC_MIN:
+ case IOG_ITEM_UNIT_CALC_AVERAGE:
+ // Unit is not yet known, continue detecting it.
+ break;
+ default:
+ // Unit is Packets, Bytes, Bits, etc.
+ return;
+ }
+
+ if (proto_registrar_get_ftype(hf_index_) == FT_RELATIVE_TIME) {
+ // find maximum absolute value and scale accordingly
+ double maxValue = 0;
+ if (graph_) {
+ maxValue = maxValueFromGraphData(*graph_->data());
+ } else if (bars_) {
+ maxValue = maxValueFromGraphData(*bars_->data());
+ }
+ // If the maximum value is zero, then either we have no data or
+ // everything is zero, do not scale the unit in this case.
+ if (maxValue == 0) {
+ return;
+ }
+
+ // XXX GTK+ always uses "ms" for log scale, should we do that too?
+ int value_multiplier;
+ if (maxValue >= 1.0) {
+ scaled_value_unit_ = "s";
+ value_multiplier = 1;
+ } else if (maxValue >= 0.001) {
+ scaled_value_unit_ = "ms";
+ value_multiplier = 1000;
+ } else {
+ scaled_value_unit_ = "us";
+ value_multiplier = 1000000;
+ }
+
+ if (graph_) {
+ scaleGraphData(*graph_->data(), value_multiplier);
+ } else if (bars_) {
+ scaleGraphData(*bars_->data(), value_multiplier);
+ }
+ }
+}
+
+template<class DataMap>
+double IOGraph::maxValueFromGraphData(const DataMap &map)
+{
+ double maxValue = 0;
+ typename DataMap::const_iterator it = map.constBegin();
+ while (it != map.constEnd()) {
+ maxValue = MAX(fabs((*it).value), maxValue);
+ ++it;
+ }
+ return maxValue;
+}
+
+template<class DataMap>
+void IOGraph::scaleGraphData(DataMap &map, int scalar)
+{
+ if (scalar != 1) {
+ typename DataMap::iterator it = map.begin();
+ while (it != map.end()) {
+ (*it).value *= scalar;
+ ++it;
+ }
+ }
+}
+
void IOGraph::captureFileClosing()
{
remove_tap_listener(this);
@@ -2238,34 +2343,32 @@ double IOGraph::getItemValue(int idx, const capture_file *cap_file) const
case FT_RELATIVE_TIME:
switch (val_units_) {
case IOG_ITEM_UNIT_CALC_MAX:
- value = (guint64) (item->time_max.secs*1000000 + item->time_max.nsecs/1000);
+ value = nstime_to_sec(&item->time_max);
break;
case IOG_ITEM_UNIT_CALC_MIN:
- value = (guint64) (item->time_min.secs*1000000 + item->time_min.nsecs/1000);
+ value = nstime_to_sec(&item->time_min);
break;
case IOG_ITEM_UNIT_CALC_SUM:
- value = (guint64) (item->time_tot.secs*1000000 + item->time_tot.nsecs/1000);
+ value = nstime_to_sec(&item->time_tot);
break;
case IOG_ITEM_UNIT_CALC_AVERAGE:
if (item->fields) {
- guint64 t; /* time in us */
-
- t = item->time_tot.secs;
- t = t*1000000+item->time_tot.nsecs/1000;
- value = (guint64) (t/item->fields);
+ value = nstime_to_sec(&item->time_tot) / item->fields;
} else {
value = 0;
}
break;
case IOG_ITEM_UNIT_CALC_LOAD:
- if (idx == (int)cur_idx_ && cap_file) {
- interval = (guint32)((cap_file->elapsed_time.secs*1000) +
- ((cap_file->elapsed_time.nsecs+500000)/1000000));
+ // "LOAD graphs plot the QUEUE-depth of the connection over time"
+ // (for response time fields such as smb.time, rpc.time, etc.)
+ // This interval is expressed in milliseconds.
+ if (idx == cur_idx_ && cap_file) {
+ interval = (guint32)(nstime_to_msec(&cap_file->elapsed_time) + 0.5);
interval -= (interval_ * idx);
} else {
interval = interval_;
}
- value = (guint64) ((item->time_tot.secs*1000000 + item->time_tot.nsecs/1000) / interval);
+ value = nstime_to_msec(&item->time_tot) / interval;
break;
default:
break;
diff --git a/ui/qt/io_graph_dialog.h b/ui/qt/io_graph_dialog.h
index d76c6cc638..13f3d7578e 100644
--- a/ui/qt/io_graph_dialog.h
+++ b/ui/qt/io_graph_dialog.h
@@ -86,6 +86,7 @@ public:
int packetFromTime(double ts);
double getItemValue(int idx, const capture_file *cap_file) const;
int maxInterval () const { return cur_idx_; }
+ QString scaledValueUnit() const { return scaled_value_unit_; }
void clearAllData();
@@ -96,7 +97,7 @@ public:
unsigned int moving_avg_period_;
public slots:
- void recalcGraphData(capture_file *cap_file);
+ void recalcGraphData(capture_file *cap_file, bool enable_scaling);
void captureFileClosing();
void reloadValueUnitField();
@@ -111,6 +112,10 @@ private:
static gboolean tapPacket(void *iog_ptr, packet_info *pinfo, epan_dissect_t *edt, const void *data);
static void tapDraw(void *iog_ptr);
+ void calculateScaledValueUnit();
+ template<class DataMap> double maxValueFromGraphData(const DataMap &map);
+ template<class DataMap> void scaleGraphData(DataMap &map, int scalar);
+
QCustomPlot *parent_;
QString config_err_;
QString name_;
@@ -124,6 +129,7 @@ private:
int hf_index_;
int interval_;
double start_time_;
+ QString scaled_value_unit_;
// Cached data. We should be able to change the Y axis without retapping as
// much as is feasible.
@@ -161,7 +167,7 @@ protected:
signals:
void goToPacket(int packet_num);
- void recalcGraphData(capture_file *);
+ void recalcGraphData(capture_file *cap_file, bool enable_scaling);
void intervalChanged(int interval);
void reloadValueUnitFields();