mirror of
https://github.com/yse/easy_profiler.git
synced 2024-12-26 08:01:51 +08:00
#31 [Gui] Complexity charts for arbitrary value viewer
This commit is contained in:
parent
b50a5bcbb3
commit
9860a565d3
@ -53,6 +53,7 @@
|
||||
************************************************************************/
|
||||
|
||||
#include <QPainter>
|
||||
#include <QPainterPath>
|
||||
#include <QGraphicsScene>
|
||||
#include <QColor>
|
||||
#include <QHeaderView>
|
||||
@ -63,6 +64,7 @@
|
||||
#include <QSettings>
|
||||
#include <QToolBar>
|
||||
#include <QAction>
|
||||
#include <QActionGroup>
|
||||
#include <list>
|
||||
#include <cmath>
|
||||
#include "arbitrary_value_inspector.h"
|
||||
@ -74,6 +76,39 @@
|
||||
EASY_CONSTEXPR int ChartBound = 2; ///< Top and bottom bounds for chart
|
||||
EASY_CONSTEXPR int ChartBounds = ChartBound << 1;
|
||||
|
||||
template <size_t window_size>
|
||||
std::vector<QPointF> gauss(const std::vector<QPointF>& _points)
|
||||
{
|
||||
if (_points.size() < 3)
|
||||
return _points;
|
||||
|
||||
std::vector<QPointF> out;
|
||||
out.reserve(_points.size());
|
||||
|
||||
for (size_t i = 0, size = _points.size(); i < size; ++i)
|
||||
{
|
||||
const auto next = i + 1;
|
||||
if (next < window_size)
|
||||
{
|
||||
qreal sum = 0;
|
||||
for (size_t j = 0; j <= i; ++j)
|
||||
sum += _points[j].y();
|
||||
sum /= i + 1;
|
||||
out.emplace_back(_points[i].x(), sum);
|
||||
}
|
||||
else
|
||||
{
|
||||
qreal sum = 0;
|
||||
for (size_t j = next - window_size; j <= i; ++j)
|
||||
sum += _points[j].y();
|
||||
sum /= window_size;
|
||||
out.emplace_back(_points[i].x(), sum);
|
||||
}
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
void getChartPoints(const ArbitraryValuesCollection& _collection, Points& _points, qreal& _minValue, qreal& _maxValue)
|
||||
{
|
||||
_minValue = 1e300;
|
||||
@ -144,8 +179,11 @@ void getChartPoints(const ArbitraryValuesCollection& _collection, Points& _point
|
||||
|
||||
ArbitraryValuesCollection::ArbitraryValuesCollection()
|
||||
: m_beginTime(0)
|
||||
, m_minDuration(profiler_gui::numeric_max<decltype(m_minDuration)>())
|
||||
, m_maxDuration(0)
|
||||
, m_minValue(1e300)
|
||||
, m_maxValue(-1e300)
|
||||
, m_chartType(ChartType::Regular)
|
||||
, m_jobType(0)
|
||||
{
|
||||
m_status = ATOMIC_VAR_INIT(Idle);
|
||||
@ -157,11 +195,21 @@ ArbitraryValuesCollection::~ArbitraryValuesCollection()
|
||||
|
||||
}
|
||||
|
||||
ChartType ArbitraryValuesCollection::chartType() const
|
||||
{
|
||||
return m_chartType;
|
||||
}
|
||||
|
||||
const ArbitraryValuesMap& ArbitraryValuesCollection::valuesMap() const
|
||||
{
|
||||
return m_values;
|
||||
}
|
||||
|
||||
const ComplexityValuesMap& ArbitraryValuesCollection::complexityMap() const
|
||||
{
|
||||
return m_complexityMap;
|
||||
}
|
||||
|
||||
const Points& ArbitraryValuesCollection::points() const
|
||||
{
|
||||
return m_points;
|
||||
@ -180,6 +228,16 @@ size_t ArbitraryValuesCollection::size() const
|
||||
return totalSize;
|
||||
}
|
||||
|
||||
profiler::timestamp_t ArbitraryValuesCollection::minDuration() const
|
||||
{
|
||||
return m_minDuration;
|
||||
}
|
||||
|
||||
profiler::timestamp_t ArbitraryValuesCollection::maxDuration() const
|
||||
{
|
||||
return m_maxDuration;
|
||||
}
|
||||
|
||||
qreal ArbitraryValuesCollection::minValue() const
|
||||
{
|
||||
return m_minValue;
|
||||
@ -190,23 +248,30 @@ qreal ArbitraryValuesCollection::maxValue() const
|
||||
return m_maxValue;
|
||||
}
|
||||
|
||||
void ArbitraryValuesCollection::collectValues(profiler::thread_id_t _threadId, profiler::vin_t _valueId, const char* _valueName
|
||||
, profiler::block_id_t _parentBlockId, bool _directParent)
|
||||
void ArbitraryValuesCollection::collectValues(ChartType _chartType, profiler::thread_id_t _threadId, profiler::vin_t _valueId
|
||||
, const char* _valueName, profiler::block_id_t _parentBlockId, bool _directParent)
|
||||
{
|
||||
interrupt();
|
||||
|
||||
setStatus(InProgress);
|
||||
m_points.clear();
|
||||
m_chartType = _chartType;
|
||||
m_jobType = ValuesJob;
|
||||
|
||||
if (m_chartType == ChartType::Complexity && profiler_gui::is_max(_parentBlockId))
|
||||
{
|
||||
setStatus(Ready);
|
||||
return;
|
||||
}
|
||||
|
||||
if (_valueId == 0)
|
||||
m_worker.enqueue([=] { collectByName(_threadId, _valueName, _parentBlockId, _directParent); }, m_bInterrupt);
|
||||
else
|
||||
m_worker.enqueue([=] { collectById(_threadId, _valueId, _parentBlockId, _directParent); }, m_bInterrupt);
|
||||
}
|
||||
|
||||
void ArbitraryValuesCollection::collectValues(profiler::thread_id_t _threadId, profiler::vin_t _valueId, const char* _valueName
|
||||
, profiler::timestamp_t _beginTime, profiler::block_id_t _parentBlockId, bool _directParent)
|
||||
void ArbitraryValuesCollection::collectValuesAndPoints(ChartType _chartType, profiler::thread_id_t _threadId, profiler::vin_t _valueId
|
||||
, const char* _valueName, profiler::timestamp_t _beginTime, profiler::block_id_t _parentBlockId, bool _directParent)
|
||||
{
|
||||
interrupt();
|
||||
|
||||
@ -215,8 +280,15 @@ void ArbitraryValuesCollection::collectValues(profiler::thread_id_t _threadId, p
|
||||
m_beginTime = _beginTime;
|
||||
m_minValue = 1e300;
|
||||
m_maxValue = -1e300;
|
||||
m_chartType = _chartType;
|
||||
m_jobType = ValuesJob | PointsJob;
|
||||
|
||||
if (m_chartType == ChartType::Complexity && profiler_gui::is_max(_parentBlockId))
|
||||
{
|
||||
setStatus(Ready);
|
||||
return;
|
||||
}
|
||||
|
||||
if (_valueId == 0)
|
||||
m_worker.enqueue([=] { collectByName(_threadId, _valueName, _parentBlockId, _directParent); }, m_bInterrupt);
|
||||
else
|
||||
@ -252,6 +324,9 @@ void ArbitraryValuesCollection::interrupt()
|
||||
setStatus(Idle);
|
||||
m_jobType = None;
|
||||
m_values.clear();
|
||||
m_complexityMap.clear();
|
||||
profiler_gui::set_max(m_minDuration);
|
||||
m_maxDuration = 0;
|
||||
}
|
||||
|
||||
void ArbitraryValuesCollection::setStatus(JobStatus _status)
|
||||
@ -262,25 +337,30 @@ void ArbitraryValuesCollection::setStatus(JobStatus _status)
|
||||
void ArbitraryValuesCollection::collectById(profiler::thread_id_t _threadId, profiler::vin_t _valueId
|
||||
, profiler::block_id_t _parentBlockId, bool _directParent)
|
||||
{
|
||||
const bool doCalculatePoints = (m_jobType & PointsJob) != 0;
|
||||
|
||||
if (_threadId == 0)
|
||||
{
|
||||
const auto threadsCount = EASY_GLOBALS.profiler_blocks.size();
|
||||
const bool calculatePointsInner = (m_jobType & PointsJob) != 0 && threadsCount == 1;
|
||||
|
||||
for (const auto& it : EASY_GLOBALS.profiler_blocks)
|
||||
if (threadsCount != 0)
|
||||
{
|
||||
if (!collectByIdForThread(it.second, _valueId, calculatePointsInner, _parentBlockId, _directParent))
|
||||
return;
|
||||
}
|
||||
const bool calculatePointsInner = doCalculatePoints && threadsCount == 1;
|
||||
|
||||
if ((m_jobType & PointsJob) != 0 && threadsCount > 1)
|
||||
getChartPoints(*this, m_points, m_minValue, m_maxValue);
|
||||
for (const auto& it : EASY_GLOBALS.profiler_blocks)
|
||||
{
|
||||
if (!collectByIdForThread(it.second, _valueId, calculatePointsInner, _parentBlockId, _directParent))
|
||||
return;
|
||||
}
|
||||
|
||||
if (doCalculatePoints && !calculatePointsInner)
|
||||
getChartPoints(*this, m_points, m_minValue, m_maxValue);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto t = EASY_GLOBALS.profiler_blocks.find(_threadId);
|
||||
if (t != EASY_GLOBALS.profiler_blocks.end() &&
|
||||
!collectByIdForThread(t->second, _valueId, (m_jobType & PointsJob) != 0, _parentBlockId, _directParent))
|
||||
!collectByIdForThread(t->second, _valueId, doCalculatePoints, _parentBlockId, _directParent))
|
||||
{
|
||||
return;
|
||||
}
|
||||
@ -292,62 +372,64 @@ void ArbitraryValuesCollection::collectById(profiler::thread_id_t _threadId, pro
|
||||
bool ArbitraryValuesCollection::collectByIdForThread(const profiler::BlocksTreeRoot& _threadRoot
|
||||
, profiler::vin_t _valueId, bool _calculatePoints, profiler::block_id_t _parentBlockId, bool _directParent)
|
||||
{
|
||||
auto& valuesList = m_values[_threadRoot.thread_id];
|
||||
|
||||
for (auto i : _threadRoot.events)
|
||||
if (profiler_gui::is_max(_parentBlockId))
|
||||
{
|
||||
if (m_bInterrupt.load(std::memory_order_acquire))
|
||||
return false;
|
||||
// All values
|
||||
|
||||
const auto& block = easyBlock(i).tree;
|
||||
const auto& desc = easyDescriptor(block.node->id());
|
||||
if (desc.type() != profiler::BlockType::Value)
|
||||
continue;
|
||||
|
||||
const auto value = block.value;
|
||||
if (value->value_id() != _valueId)
|
||||
continue;
|
||||
|
||||
valuesList.push_back(value);
|
||||
|
||||
if (_calculatePoints)
|
||||
auto& valuesList = m_values[_threadRoot.thread_id];
|
||||
for (auto i : _threadRoot.events)
|
||||
{
|
||||
const auto p = point(*block.value);
|
||||
if (m_bInterrupt.load(std::memory_order_acquire))
|
||||
return false;
|
||||
|
||||
if (p.y() > m_maxValue)
|
||||
m_maxValue = p.y();
|
||||
if (p.y() < m_minValue)
|
||||
m_minValue = p.y();
|
||||
const auto& block = easyBlock(i).tree;
|
||||
const auto& desc = easyDescriptor(block.node->id());
|
||||
if (desc.type() != profiler::BlockType::Value)
|
||||
continue;
|
||||
|
||||
m_points.push_back(p);
|
||||
const auto value = block.value;
|
||||
if (value->value_id() != _valueId)
|
||||
continue;
|
||||
|
||||
valuesList.push_back(value);
|
||||
if (_calculatePoints)
|
||||
addPoint(*value);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
return depthFirstSearch(_threadRoot, _calculatePoints, _parentBlockId, _directParent
|
||||
, [=] (profiler::vin_t _id, const char*) -> bool { return _id == _valueId; });
|
||||
}
|
||||
|
||||
void ArbitraryValuesCollection::collectByName(profiler::thread_id_t _threadId, const std::string _valueName
|
||||
, profiler::block_id_t _parentBlockId, bool _directParent)
|
||||
{
|
||||
const bool doCalculatePoints = (m_jobType & PointsJob) != 0;
|
||||
|
||||
if (_threadId == 0)
|
||||
{
|
||||
const auto threadsCount = EASY_GLOBALS.profiler_blocks.size();
|
||||
const bool calculatePointsInner = (m_jobType & PointsJob) != 0 && threadsCount == 1;
|
||||
|
||||
for (const auto& it : EASY_GLOBALS.profiler_blocks)
|
||||
if (threadsCount != 0)
|
||||
{
|
||||
if (!collectByNameForThread(it.second, _valueName, calculatePointsInner, _parentBlockId, _directParent))
|
||||
return;
|
||||
}
|
||||
const bool calculatePointsInner = doCalculatePoints && threadsCount == 1;
|
||||
|
||||
if ((m_jobType & PointsJob) != 0 && threadsCount > 1)
|
||||
getChartPoints(*this, m_points, m_minValue, m_maxValue);
|
||||
for (const auto& it : EASY_GLOBALS.profiler_blocks)
|
||||
{
|
||||
if (!collectByNameForThread(it.second, _valueName, calculatePointsInner, _parentBlockId, _directParent))
|
||||
return;
|
||||
}
|
||||
|
||||
if (doCalculatePoints && !calculatePointsInner)
|
||||
getChartPoints(*this, m_points, m_minValue, m_maxValue);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto t = EASY_GLOBALS.profiler_blocks.find(_threadId);
|
||||
if (t != EASY_GLOBALS.profiler_blocks.end() &&
|
||||
!collectByNameForThread(t->second, _valueName, (m_jobType & PointsJob) != 0, _parentBlockId, _directParent))
|
||||
!collectByNameForThread(t->second, _valueName, doCalculatePoints, _parentBlockId, _directParent))
|
||||
{
|
||||
return;
|
||||
}
|
||||
@ -359,36 +441,146 @@ void ArbitraryValuesCollection::collectByName(profiler::thread_id_t _threadId, c
|
||||
bool ArbitraryValuesCollection::collectByNameForThread(const profiler::BlocksTreeRoot& _threadRoot
|
||||
, const std::string& _valueName, bool _calculatePoints, profiler::block_id_t _parentBlockId, bool _directParent)
|
||||
{
|
||||
if (profiler_gui::is_max(_parentBlockId))
|
||||
{
|
||||
// All values
|
||||
|
||||
auto& valuesList = m_values[_threadRoot.thread_id];
|
||||
for (auto i : _threadRoot.events)
|
||||
{
|
||||
if (m_bInterrupt.load(std::memory_order_acquire))
|
||||
return false;
|
||||
|
||||
const auto& block = easyBlock(i).tree;
|
||||
const auto& desc = easyDescriptor(block.node->id());
|
||||
if (desc.type() != profiler::BlockType::Value || _valueName != desc.name())
|
||||
continue;
|
||||
|
||||
valuesList.push_back(block.value);
|
||||
if (_calculatePoints)
|
||||
addPoint(*block.value);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return depthFirstSearch(_threadRoot, _calculatePoints, _parentBlockId, _directParent
|
||||
, [&_valueName] (profiler::vin_t, const char* _name) -> bool { return _valueName == _name; });
|
||||
}
|
||||
|
||||
bool ArbitraryValuesCollection::depthFirstSearch(const profiler::BlocksTreeRoot& _threadRoot, bool _calculatePoints
|
||||
, profiler::block_id_t _parentBlockId, bool _directParent, std::function<bool(profiler::vin_t, const char*)> _isSuitableValue)
|
||||
{
|
||||
if (_threadRoot.children.empty())
|
||||
return true;
|
||||
|
||||
auto& valuesList = m_values[_threadRoot.thread_id];
|
||||
|
||||
for (auto i : _threadRoot.events)
|
||||
using StackEntry = std::pair<profiler::block_index_t, profiler::block_index_t>;
|
||||
using Stack = std::vector<StackEntry>;
|
||||
|
||||
Stack stack;
|
||||
for (const auto index : _threadRoot.children)
|
||||
{
|
||||
if (m_bInterrupt.load(std::memory_order_acquire))
|
||||
return false;
|
||||
|
||||
const auto& block = easyBlock(i).tree;
|
||||
const auto& desc = easyDescriptor(block.node->id());
|
||||
if (desc.type() != profiler::BlockType::Value || _valueName != desc.name())
|
||||
continue;
|
||||
stack.clear();
|
||||
stack.emplace_back(index, static_cast<profiler::block_index_t>(0));
|
||||
|
||||
valuesList.push_back(block.value);
|
||||
|
||||
if (_calculatePoints)
|
||||
profiler::timestamp_t lastMatchedParentDuration = 0;
|
||||
size_t matchedParentIdStackDepth = 0;
|
||||
bool matchedParentId = false;
|
||||
while (!stack.empty())
|
||||
{
|
||||
const auto p = point(*block.value);
|
||||
if (m_bInterrupt.load(std::memory_order_acquire))
|
||||
return false;
|
||||
|
||||
if (p.y() > m_maxValue)
|
||||
m_maxValue = p.y();
|
||||
if (p.y() < m_minValue)
|
||||
m_minValue = p.y();
|
||||
auto& top = stack.back();
|
||||
auto& first = top.second;
|
||||
const auto i = top.first;
|
||||
|
||||
m_points.push_back(p);
|
||||
const auto parent = stack.size() > 1 ? (++stack.rbegin())->first :
|
||||
profiler_gui::numeric_max<profiler::block_index_t>();
|
||||
|
||||
const auto& block = easyBlock(i).tree;
|
||||
const auto& desc = easyDescriptor(block.node->id());
|
||||
|
||||
if (desc.type() == profiler::BlockType::Value && matchedParentId)
|
||||
{
|
||||
const auto value = block.value;
|
||||
if (_isSuitableValue(value->value_id(), desc.name()))
|
||||
{
|
||||
bool hit = false;
|
||||
if (!_directParent)
|
||||
{
|
||||
hit = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto parentId = easyBlock(parent).tree.node->id();
|
||||
hit = parentId == _parentBlockId || easyDescriptor(parentId).id() == _parentBlockId;
|
||||
}
|
||||
|
||||
if (hit)
|
||||
{
|
||||
valuesList.push_back(value);
|
||||
if (_calculatePoints)
|
||||
{
|
||||
const auto val = addPoint(*value);
|
||||
if (m_chartType == ChartType::Complexity)
|
||||
{
|
||||
m_complexityMap[val].push_back(lastMatchedParentDuration);
|
||||
if (lastMatchedParentDuration < m_minDuration)
|
||||
m_minDuration = lastMatchedParentDuration;
|
||||
if (lastMatchedParentDuration > m_maxDuration)
|
||||
m_maxDuration = lastMatchedParentDuration;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (first < block.children.size())
|
||||
{
|
||||
if (block.node->id() == _parentBlockId || desc.id() == _parentBlockId)
|
||||
{
|
||||
if (!matchedParentId)
|
||||
matchedParentIdStackDepth = stack.size();
|
||||
matchedParentId = true;
|
||||
lastMatchedParentDuration = block.node->duration();
|
||||
}
|
||||
|
||||
const auto child = block.children[first++];
|
||||
stack.emplace_back(child, static_cast<profiler::block_index_t>(0));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (stack.size() == matchedParentIdStackDepth)
|
||||
matchedParentId = false;
|
||||
stack.pop_back();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
double ArbitraryValuesCollection::addPoint(const profiler::ArbitraryValue& _value)
|
||||
{
|
||||
const auto p = point(_value);
|
||||
|
||||
if (p.y() > m_maxValue)
|
||||
m_maxValue = p.y();
|
||||
|
||||
if (p.y() < m_minValue)
|
||||
m_minValue = p.y();
|
||||
|
||||
m_points.push_back(p);
|
||||
|
||||
return p.y();
|
||||
}
|
||||
|
||||
QPointF ArbitraryValuesCollection::point(const profiler::ArbitraryValue& _value) const
|
||||
{
|
||||
const qreal x = PROF_MICROSECONDS(qreal(_value.begin() - m_beginTime));
|
||||
@ -402,6 +594,11 @@ ArbitraryValuesChartItem::ArbitraryValuesChartItem()
|
||||
: Parent()
|
||||
, m_workerMaxValue(0)
|
||||
, m_workerMinValue(0)
|
||||
, m_workerMaxDuration(0)
|
||||
, m_workerMinDuration(0)
|
||||
, m_maxDuration(0)
|
||||
, m_minDuration(0)
|
||||
, m_chartType(ChartType::Regular)
|
||||
{
|
||||
}
|
||||
|
||||
@ -537,10 +734,23 @@ bool ArbitraryValuesChartItem::updateImage()
|
||||
const auto bindMode = widget->bindMode();
|
||||
const auto beginTime = EASY_GLOBALS.begin_time;
|
||||
const auto autoHeight = EASY_GLOBALS.auto_adjust_chart_height;
|
||||
m_worker.enqueue([=] {
|
||||
updateImageAsync(rect, scale, left, right, right - left, value, window, bindMode,
|
||||
beginTime, autoHeight);
|
||||
}, m_bReady);
|
||||
|
||||
if (m_chartType == ChartType::Regular)
|
||||
{
|
||||
m_worker.enqueue([=]
|
||||
{
|
||||
updateRegularImageAsync(rect, scale, left, right, right - left, value, window, bindMode, beginTime,
|
||||
autoHeight);
|
||||
}, m_bReady);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_worker.enqueue([=]
|
||||
{
|
||||
updateComplexityImageAsync(rect, scale, left, right, right - left, value, window, bindMode, beginTime,
|
||||
autoHeight);
|
||||
}, m_bReady);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -551,8 +761,36 @@ void ArbitraryValuesChartItem::onImageUpdated()
|
||||
m_minValue = m_workerMinValue;
|
||||
}
|
||||
|
||||
void ArbitraryValuesChartItem::updateImageAsync(QRectF _boundingRect, qreal _current_scale, qreal _minimum, qreal _maximum, qreal _range,
|
||||
qreal _value, qreal _width, bool _bindMode, profiler::timestamp_t _begin_time, bool _autoAdjust)
|
||||
void ArbitraryValuesChartItem::drawGrid(QPainter& _painter, int _width, int _height) const
|
||||
{
|
||||
auto pen = _painter.pen();
|
||||
pen.setColor(Qt::darkGray);
|
||||
pen.setStyle(Qt::DotLine);
|
||||
_painter.setPen(pen);
|
||||
|
||||
const int left = 0;
|
||||
const int top = 0;
|
||||
|
||||
const int hlines = _height / 20;
|
||||
for (int i = 0; i < hlines; ++i)
|
||||
{
|
||||
const auto y = top + 20 + i * 20;
|
||||
_painter.drawLine(left, y, left + _width, y);
|
||||
}
|
||||
|
||||
const int vlines = _width / 20;
|
||||
for (int i = 0; i < vlines; ++i)
|
||||
{
|
||||
const auto x = left + 20 + i * 20;
|
||||
_painter.drawLine(x, top, x, top + _height);
|
||||
}
|
||||
|
||||
_painter.setPen(Qt::SolidLine);
|
||||
}
|
||||
|
||||
void ArbitraryValuesChartItem::updateRegularImageAsync(QRectF _boundingRect, qreal _current_scale, qreal _minimum
|
||||
, qreal _maximum, qreal _range, qreal _value, qreal _width, bool _bindMode, profiler::timestamp_t _begin_time
|
||||
, bool _autoAdjust)
|
||||
{
|
||||
const auto screenWidth = _boundingRect.width() * _current_scale;
|
||||
//const auto maxColumnHeight = _boundingRect.height();
|
||||
@ -577,33 +815,7 @@ void ArbitraryValuesChartItem::updateImageAsync(QRectF _boundingRect, qreal _cur
|
||||
p.setRenderHint(QPainter::Antialiasing, true);
|
||||
|
||||
// Draw grid
|
||||
{
|
||||
auto pen = p.pen();
|
||||
pen.setColor(Qt::darkGray);
|
||||
pen.setStyle(Qt::DotLine);
|
||||
p.setPen(pen);
|
||||
|
||||
const int left = 0;
|
||||
const int top = 0;
|
||||
const int w = m_workerImage->width();
|
||||
const int h = m_workerImage->height();
|
||||
|
||||
const int hlines = h / 20;
|
||||
for (int i = 0; i < hlines; ++i)
|
||||
{
|
||||
const auto y = top + 20 + i * 20;
|
||||
p.drawLine(left, y, left + w, y);
|
||||
}
|
||||
|
||||
const int vlines = w / 20;
|
||||
for (int i = 0; i < vlines; ++i)
|
||||
{
|
||||
const auto x = left + 20 + i * 20;
|
||||
p.drawLine(x, top, x, top + h);
|
||||
}
|
||||
|
||||
p.setPen(Qt::SolidLine);
|
||||
}
|
||||
drawGrid(p, m_workerImage->width(), m_workerImage->height());
|
||||
|
||||
if (m_collections.empty() || isReady())
|
||||
{
|
||||
@ -668,12 +880,8 @@ void ArbitraryValuesChartItem::updateImageAsync(QRectF _boundingRect, qreal _cur
|
||||
continue;
|
||||
|
||||
const auto value = it->y();
|
||||
|
||||
if (minValue > value)
|
||||
minValue = value;
|
||||
|
||||
if (maxValue < value)
|
||||
maxValue = value;
|
||||
minValue = std::min(minValue, value);
|
||||
maxValue = std::max(maxValue, value);
|
||||
}
|
||||
|
||||
continue;
|
||||
@ -684,11 +892,8 @@ void ArbitraryValuesChartItem::updateImageAsync(QRectF _boundingRect, qreal _cur
|
||||
leftBounds.emplace_back(points.begin());
|
||||
}
|
||||
|
||||
if (minValue > collection.minValue())
|
||||
minValue = collection.minValue();
|
||||
|
||||
if (maxValue < collection.maxValue())
|
||||
maxValue = collection.maxValue();
|
||||
minValue = std::min(minValue, collection.minValue());
|
||||
maxValue = std::max(maxValue, collection.maxValue());
|
||||
}
|
||||
|
||||
if (minValue > maxValue)
|
||||
@ -754,7 +959,7 @@ void ArbitraryValuesChartItem::updateImageAsync(QRectF _boundingRect, qreal _cur
|
||||
|
||||
const auto first = leftBounds[i];
|
||||
|
||||
if (c.chartType == ChartViewType::Points)
|
||||
if (c.chartPenStyle == ChartPenStyle::Points)
|
||||
{
|
||||
qreal prevX = 1e300, prevY = 1e300;
|
||||
for (auto it = first; it != points.end() && it->x() < _maximum; ++it)
|
||||
@ -852,6 +1057,219 @@ void ArbitraryValuesChartItem::updateImageAsync(QRectF _boundingRect, qreal _cur
|
||||
setReady(true);
|
||||
}
|
||||
|
||||
void ArbitraryValuesChartItem::updateComplexityImageAsync(QRectF _boundingRect, qreal _current_scale, qreal _minimum
|
||||
, qreal _maximum, qreal _range, qreal _value, qreal _width, bool _bindMode, profiler::timestamp_t _begin_time
|
||||
, bool _autoAdjust)
|
||||
{
|
||||
const auto rectHeight = _boundingRect.height();
|
||||
const auto screenWidth = _boundingRect.width() * _current_scale;
|
||||
//const auto maxColumnHeight = _boundingRect.height();
|
||||
|
||||
m_workerImageScale = 1;
|
||||
m_workerImageOrigin = _minimum;
|
||||
m_workerImage = new QImage(screenWidth + 0.5, rectHeight, QImage::Format_ARGB32);
|
||||
|
||||
m_workerImage->fill(0);
|
||||
QPainter p(m_workerImage);
|
||||
p.setBrush(Qt::NoBrush);
|
||||
p.setRenderHint(QPainter::Antialiasing, true);
|
||||
|
||||
// Draw grid
|
||||
drawGrid(p, m_workerImage->width(), m_workerImage->height());
|
||||
|
||||
if (m_collections.empty() || isReady())
|
||||
{
|
||||
setReady(true);
|
||||
return;
|
||||
}
|
||||
|
||||
using LeftBounds = std::vector<Points::const_iterator>;
|
||||
qreal realScale = _current_scale, offset = 0;
|
||||
|
||||
const auto right = std::min(_value + _width, _maximum);
|
||||
qreal minValue = 1e300, maxValue = -1e300;
|
||||
profiler::timestamp_t minDuration = profiler_gui::numeric_max<profiler::timestamp_t>(), maxDuration = 0;
|
||||
for (const auto& c : m_collections)
|
||||
{
|
||||
if (isReady())
|
||||
return;
|
||||
|
||||
const auto& collection = *c.ptr;
|
||||
const auto& complexityMap = collection.complexityMap();
|
||||
|
||||
if (complexityMap.empty())
|
||||
continue;
|
||||
|
||||
minValue = std::min(minValue, collection.minValue());
|
||||
maxValue = std::max(maxValue, collection.maxValue());
|
||||
|
||||
minDuration = std::min(minDuration, collection.minDuration());
|
||||
maxDuration = std::max(maxDuration, collection.maxDuration());
|
||||
}
|
||||
|
||||
if (minValue > maxValue || minDuration > maxDuration)
|
||||
{
|
||||
// No points
|
||||
m_workerMaxValue = 0;
|
||||
m_workerMinValue = 0;
|
||||
m_workerMaxDuration = 0;
|
||||
m_workerMinDuration = 0;
|
||||
setReady(true);
|
||||
return;
|
||||
}
|
||||
|
||||
m_workerMaxValue = maxValue;
|
||||
m_workerMinValue = minValue;
|
||||
m_workerMaxDuration = maxDuration;
|
||||
m_workerMinDuration = minDuration;
|
||||
|
||||
if (isReady())
|
||||
return;
|
||||
|
||||
const auto ymiddle = rectHeight * 0.5;
|
||||
const auto dt = maxDuration - minDuration;
|
||||
bool singleValue = dt == 0;
|
||||
|
||||
const qreal height = std::max(static_cast<qreal>(dt), 0.01);
|
||||
const auto gety = [=] (profiler::timestamp_t duration)
|
||||
{
|
||||
qreal y;
|
||||
if (singleValue)
|
||||
{
|
||||
y = ymiddle;
|
||||
}
|
||||
else
|
||||
{
|
||||
y = static_cast<qreal>(maxDuration - duration);
|
||||
y /= height;
|
||||
y *= rectHeight - ChartBounds;
|
||||
y += ChartBound;
|
||||
}
|
||||
|
||||
return y;
|
||||
};
|
||||
|
||||
const auto xmiddle = screenWidth * 0.5;
|
||||
singleValue = fabs(maxValue - minValue) < 2 * std::numeric_limits<qreal>::epsilon();
|
||||
const qreal width = std::max(maxValue - minValue, 0.01);
|
||||
const auto getx = [=] (qreal x)
|
||||
{
|
||||
if (singleValue)
|
||||
{
|
||||
x = xmiddle;
|
||||
}
|
||||
else
|
||||
{
|
||||
x -= minValue;
|
||||
x *= screenWidth / width;
|
||||
}
|
||||
|
||||
return x;
|
||||
};
|
||||
|
||||
std::vector<QPointF> averages;
|
||||
for (const auto& c : m_collections)
|
||||
{
|
||||
if (isReady())
|
||||
return;
|
||||
|
||||
const auto& complexityMap = c.ptr->complexityMap();
|
||||
if (complexityMap.empty())
|
||||
continue;
|
||||
|
||||
if (c.selected)
|
||||
{
|
||||
auto pen = p.pen();
|
||||
pen.setColor(QColor::fromRgba(c.color));
|
||||
pen.setWidth(2);
|
||||
p.setPen(pen);
|
||||
}
|
||||
else
|
||||
{
|
||||
p.setPen(QColor::fromRgba(c.color));
|
||||
}
|
||||
|
||||
averages.clear();
|
||||
averages.reserve(complexityMap.size());
|
||||
|
||||
auto it = complexityMap.begin();
|
||||
|
||||
qreal x = getx(it->first);
|
||||
|
||||
profiler::timestamp_t average = 0;
|
||||
for (auto duration : it->second)
|
||||
{
|
||||
average += duration;
|
||||
p.drawPoint(QPointF {x, gety(duration)});
|
||||
}
|
||||
average /= it->second.size();
|
||||
averages.emplace_back(x, gety(average));
|
||||
|
||||
for (++it; it != complexityMap.end(); ++it)
|
||||
{
|
||||
if (isReady())
|
||||
return;
|
||||
|
||||
x = getx(it->first);
|
||||
average = 0;
|
||||
for (auto duration : it->second)
|
||||
{
|
||||
average += duration;
|
||||
p.drawPoint(QPointF {x, gety(duration)});
|
||||
}
|
||||
average /= it->second.size();
|
||||
averages.emplace_back(x, gety(average));
|
||||
}
|
||||
|
||||
//if (c.selected)
|
||||
{
|
||||
p.drawPolyline(averages.data(), static_cast<int>(averages.size()));
|
||||
|
||||
auto color = profiler_gui::darken(c.color, 0.65f);
|
||||
if (profiler_gui::alpha(color) < 0xc0)
|
||||
p.setPen(QColor::fromRgba(profiler::colors::modify_alpha32(0xc0000000, color)));
|
||||
else
|
||||
p.setPen(QColor::fromRgba(color));
|
||||
p.setBrush(QColor::fromRgba(0xc8ffffff));
|
||||
|
||||
QPointF prev {-500., -500.};
|
||||
for (const auto& point : averages)
|
||||
{
|
||||
if (isReady())
|
||||
return;
|
||||
|
||||
const auto line = point - prev;
|
||||
const auto delta = estd::sqr(line.x()) + estd::sqr(line.y());
|
||||
|
||||
if (delta > 25)
|
||||
{
|
||||
p.drawEllipse(point, 3, 3);
|
||||
prev = point;
|
||||
}
|
||||
}
|
||||
|
||||
p.setBrush(Qt::NoBrush);
|
||||
auto pen = p.pen();
|
||||
pen.setWidth(2);
|
||||
p.setPen(pen);
|
||||
|
||||
//averages = std::move(gauss<8>(averages));
|
||||
|
||||
QPainterPath pp;
|
||||
pp.moveTo(averages.front());
|
||||
const size_t step = std::max(averages.size() / (size_t)40, (size_t)1);
|
||||
for (size_t k = 3 * step; k < averages.size(); k += 4 * step)
|
||||
{
|
||||
pp.cubicTo(averages[k - 2 * step], averages[k - 1 * step], averages[k]);
|
||||
}
|
||||
|
||||
p.drawPath(pp);
|
||||
}
|
||||
}
|
||||
|
||||
setReady(true);
|
||||
}
|
||||
|
||||
void ArbitraryValuesChartItem::clear()
|
||||
{
|
||||
cancelAnyJob();
|
||||
@ -877,6 +1295,21 @@ void ArbitraryValuesChartItem::update(const ArbitraryValuesCollection* _selected
|
||||
updateImage();
|
||||
}
|
||||
|
||||
void ArbitraryValuesChartItem::setChartType(ChartType _chartType)
|
||||
{
|
||||
if (m_chartType != _chartType)
|
||||
{
|
||||
cancelImageUpdate();
|
||||
m_chartType = _chartType;
|
||||
updateImage();
|
||||
}
|
||||
}
|
||||
|
||||
ChartType ArbitraryValuesChartItem::chartType() const
|
||||
{
|
||||
return m_chartType;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
GraphicsChart::GraphicsChart(QWidget* _parent)
|
||||
@ -927,6 +1360,16 @@ void GraphicsChart::update(const ArbitraryValuesCollection* _selected)
|
||||
m_chartItem->update(_selected);
|
||||
}
|
||||
|
||||
void GraphicsChart::setChartType(ChartType _chartType)
|
||||
{
|
||||
m_chartItem->setChartType(_chartType);
|
||||
}
|
||||
|
||||
ChartType GraphicsChart::chartType() const
|
||||
{
|
||||
return m_chartItem->chartType();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
enum class ArbitraryColumns : uint8_t
|
||||
@ -994,7 +1437,7 @@ ArbitraryValuesCollection* ArbitraryTreeWidgetItem::collection()
|
||||
return m_collection.get();
|
||||
}
|
||||
|
||||
void ArbitraryTreeWidgetItem::collectValues(profiler::thread_id_t _threadId)
|
||||
void ArbitraryTreeWidgetItem::collectValues(profiler::thread_id_t _threadId, ChartType _chartType)
|
||||
{
|
||||
if (!m_collection)
|
||||
m_collection = CollectionPtr(new ArbitraryValuesCollection);
|
||||
@ -1011,8 +1454,9 @@ void ArbitraryTreeWidgetItem::collectValues(profiler::thread_id_t _threadId)
|
||||
directParent = true;
|
||||
}
|
||||
|
||||
m_collection->collectValues(_threadId, m_vin, text(int_cast(ArbitraryColumns::Name)).toStdString().c_str(),
|
||||
EASY_GLOBALS.begin_time, parentBlockId, directParent);
|
||||
m_collection->collectValuesAndPoints(_chartType, _threadId, m_vin
|
||||
, text(int_cast(ArbitraryColumns::Name)).toStdString().c_str(), EASY_GLOBALS.begin_time
|
||||
, parentBlockId, directParent);
|
||||
}
|
||||
|
||||
void ArbitraryTreeWidgetItem::interrupt()
|
||||
@ -1047,9 +1491,24 @@ ArbitraryValuesWidget::ArbitraryValuesWidget(QWidget* _parent)
|
||||
|
||||
auto tb = new QToolBar(this);
|
||||
tb->setIconSize(applicationIconsSize());
|
||||
auto refreshButton = tb->addAction(QIcon(imagePath("reload")), tr("Refresh values list"));
|
||||
refreshButton->setToolTip(tr("Refresh arbitrary values list."));
|
||||
connect(refreshButton, &QAction::triggered, this, &This::rebuild);
|
||||
|
||||
auto action = tb->addAction(QIcon(imagePath("reload")), tr("Refresh values list"));
|
||||
action->setToolTip(tr("Refresh arbitrary values list."));
|
||||
connect(action, &QAction::triggered, this, &This::rebuild);
|
||||
|
||||
auto actionGroup = new QActionGroup(this);
|
||||
actionGroup->setExclusive(true);
|
||||
|
||||
action = new QAction(tr("Regular chart"), actionGroup);
|
||||
action->setCheckable(true);
|
||||
action->setChecked(true);
|
||||
connect(action, &QAction::triggered, this, &This::onRegularChartTypeChecked);
|
||||
tb->addAction(action);
|
||||
|
||||
action = new QAction(tr("Complexity chart"), actionGroup);
|
||||
action->setCheckable(true);
|
||||
connect(action, &QAction::triggered, this, &This::onComplexityChartTypeChecked);
|
||||
tb->addAction(action);
|
||||
|
||||
auto layout = new QVBoxLayout(this);
|
||||
layout->setContentsMargins(0, 0, 0, 0);
|
||||
@ -1097,7 +1556,11 @@ void ArbitraryValuesWidget::clear()
|
||||
{
|
||||
if (m_collectionsTimer.isActive())
|
||||
m_collectionsTimer.stop();
|
||||
|
||||
// Warning! Cancel image update first because it uses POINTERS which will be destroyed
|
||||
// in m_treeWidget->clear()
|
||||
m_chart->cancelImageUpdate();
|
||||
|
||||
m_checkedItems.clear();
|
||||
m_treeWidget->clear();
|
||||
m_boldItem = nullptr;
|
||||
@ -1154,15 +1617,23 @@ void ArbitraryValuesWidget::onItemChanged(QTreeWidgetItem* _item, int _column)
|
||||
if (item->checkState(CheckColumn) == Qt::Checked)
|
||||
{
|
||||
m_checkedItems.push_back(item);
|
||||
item->collectValues(EASY_GLOBALS.selected_thread);
|
||||
item->collectValues(EASY_GLOBALS.selected_thread, m_chart->chartType());
|
||||
if (!m_collectionsTimer.isActive())
|
||||
m_collectionsTimer.start(100);
|
||||
}
|
||||
else
|
||||
{
|
||||
// !!!
|
||||
// Warning! Spaghetti-code detected! :)
|
||||
//
|
||||
// m_chart passes POINTERS to updateImage() so at first we MUST cancel image update
|
||||
// and only then we can invoke item->interrupt() because passed pointer will be destroyed
|
||||
// in interrupt().
|
||||
// !!!
|
||||
|
||||
m_checkedItems.removeOne(item);
|
||||
item->interrupt();
|
||||
onCollectionsTimeout();
|
||||
item->interrupt();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1206,7 +1677,7 @@ void ArbitraryValuesWidget::onCollectionsTimeout()
|
||||
if (item->collection()->status() != ArbitraryValuesCollection::InProgress)
|
||||
{
|
||||
collections.push_back(CollectionPaintData {item->collection(), item->color(),
|
||||
ChartViewType::Line, item == m_treeWidget->currentItem()});
|
||||
ChartPenStyle::Line, item == m_treeWidget->currentItem()});
|
||||
}
|
||||
}
|
||||
|
||||
@ -1218,6 +1689,38 @@ void ArbitraryValuesWidget::onCollectionsTimeout()
|
||||
}
|
||||
}
|
||||
|
||||
void ArbitraryValuesWidget::repaint()
|
||||
{
|
||||
if (!m_checkedItems.empty())
|
||||
{
|
||||
m_chart->cancelImageUpdate();
|
||||
|
||||
for (auto item : m_checkedItems)
|
||||
item->collectValues(EASY_GLOBALS.selected_thread, m_chart->chartType());
|
||||
|
||||
if (!m_collectionsTimer.isActive())
|
||||
m_collectionsTimer.start(100);
|
||||
}
|
||||
}
|
||||
|
||||
void ArbitraryValuesWidget::onRegularChartTypeChecked(bool _checked)
|
||||
{
|
||||
if (!_checked)
|
||||
return;
|
||||
|
||||
m_chart->setChartType(ChartType::Regular);
|
||||
repaint();
|
||||
}
|
||||
|
||||
void ArbitraryValuesWidget::onComplexityChartTypeChecked(bool _checked)
|
||||
{
|
||||
if (!_checked)
|
||||
return;
|
||||
|
||||
m_chart->setChartType(ChartType::Complexity);
|
||||
repaint();
|
||||
}
|
||||
|
||||
void ArbitraryValuesWidget::buildTree(profiler::thread_id_t _threadId, profiler::block_index_t _blockIndex, profiler::block_id_t _blockId)
|
||||
{
|
||||
m_treeWidget->clear();
|
||||
|
@ -65,8 +65,10 @@
|
||||
#include <easy/reader.h>
|
||||
#include <easy/utility.h>
|
||||
#include <unordered_map>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <functional>
|
||||
#include <atomic>
|
||||
#include <memory>
|
||||
#include "graphics_slider_area.h"
|
||||
@ -77,6 +79,32 @@
|
||||
using Points = std::vector<QPointF>;
|
||||
using ArbitraryValues = std::vector<const profiler::ArbitraryValue*>;
|
||||
using ArbitraryValuesMap = std::unordered_map<profiler::thread_id_t, ArbitraryValues, estd::hash<profiler::thread_id_t> >;
|
||||
using Durations = std::vector<profiler::timestamp_t>;
|
||||
using ComplexityValuesMap = std::map<double, Durations>;
|
||||
|
||||
enum class ChartType : uint8_t
|
||||
{
|
||||
Regular = 0, ///< Regular chart; X axis = time, Y axis = value
|
||||
Complexity ///< Complexity chart; X axis = value, Y axis = duration
|
||||
};
|
||||
|
||||
enum class ComplexityType : uint8_t
|
||||
{
|
||||
Constant = 0, ///< O(1)
|
||||
Logarithmic, ///< O(logN)
|
||||
Linear, ///< O(N)
|
||||
Quasilinear, ///< O(N*logN)
|
||||
Quadratic, ///< O(N^2)
|
||||
Cubic, ///< O(N^3)
|
||||
Exponential, ///< O(2^N)
|
||||
Factorial, ///< O(N!)
|
||||
};
|
||||
|
||||
enum class ChartPenStyle : uint8_t
|
||||
{
|
||||
Line = 0,
|
||||
Points
|
||||
};
|
||||
|
||||
class ArbitraryValuesCollection EASY_FINAL
|
||||
{
|
||||
@ -89,32 +117,42 @@ private:
|
||||
|
||||
using This = ArbitraryValuesCollection;
|
||||
|
||||
ArbitraryValuesMap m_values;
|
||||
Points m_points;
|
||||
ThreadPoolTask m_worker;
|
||||
profiler::timestamp_t m_beginTime;
|
||||
qreal m_minValue;
|
||||
qreal m_maxValue;
|
||||
std::atomic<uint8_t> m_status;
|
||||
std::atomic_bool m_bInterrupt;
|
||||
uint8_t m_jobType;
|
||||
ArbitraryValuesMap m_values;
|
||||
ComplexityValuesMap m_complexityMap;
|
||||
Points m_points;
|
||||
ThreadPoolTask m_worker;
|
||||
profiler::timestamp_t m_beginTime;
|
||||
profiler::timestamp_t m_minDuration;
|
||||
profiler::timestamp_t m_maxDuration;
|
||||
qreal m_minValue;
|
||||
qreal m_maxValue;
|
||||
std::atomic<uint8_t> m_status;
|
||||
std::atomic_bool m_bInterrupt;
|
||||
ChartType m_chartType;
|
||||
uint8_t m_jobType;
|
||||
|
||||
public:
|
||||
|
||||
explicit ArbitraryValuesCollection();
|
||||
~ArbitraryValuesCollection();
|
||||
|
||||
ChartType chartType() const;
|
||||
const ArbitraryValuesMap& valuesMap() const;
|
||||
const ComplexityValuesMap& complexityMap() const;
|
||||
const Points& points() const;
|
||||
JobStatus status() const;
|
||||
size_t size() const;
|
||||
|
||||
profiler::timestamp_t minDuration() const;
|
||||
profiler::timestamp_t maxDuration() const;
|
||||
|
||||
qreal minValue() const;
|
||||
qreal maxValue() const;
|
||||
|
||||
void collectValues(profiler::thread_id_t _threadId, profiler::vin_t _valueId, const char* _valueName, profiler::block_id_t _parentBlockId, bool _directParent);
|
||||
void collectValues(profiler::thread_id_t _threadId, profiler::vin_t _valueId, const char* _valueName, profiler::timestamp_t _beginTime, profiler::block_id_t _parentBlockId, bool _directParent);
|
||||
void collectValues(ChartType _chartType, profiler::thread_id_t _threadId, profiler::vin_t _valueId, const char* _valueName, profiler::block_id_t _parentBlockId, bool _directParent);
|
||||
bool calculatePoints(profiler::timestamp_t _beginTime);
|
||||
|
||||
void collectValuesAndPoints(ChartType _chartType, profiler::thread_id_t _threadId, profiler::vin_t _valueId, const char* _valueName, profiler::timestamp_t _beginTime, profiler::block_id_t _parentBlockId, bool _directParent);
|
||||
void interrupt();
|
||||
|
||||
private:
|
||||
@ -125,27 +163,19 @@ private:
|
||||
bool collectByIdForThread(const profiler::BlocksTreeRoot& _threadRoot, profiler::vin_t _valueId, bool _calculatePoints, profiler::block_id_t _parentBlockId, bool _directParent);
|
||||
bool collectByNameForThread(const profiler::BlocksTreeRoot& _threadRoot, const std::string& _valueName, bool _calculatePoints, profiler::block_id_t _parentBlockId, bool _directParent);
|
||||
|
||||
bool depthFirstSearch(const profiler::BlocksTreeRoot& _threadRoot, bool _calculatePoints
|
||||
, profiler::block_id_t _parentBlockId, bool _directParent, std::function<bool(profiler::vin_t, const char*)> _isSuitableValue);
|
||||
|
||||
double addPoint(const profiler::ArbitraryValue& _value);
|
||||
QPointF point(const profiler::ArbitraryValue& _value) const;
|
||||
|
||||
}; // end of class ArbitraryValuesCollection.
|
||||
|
||||
enum class ChartType : uint8_t
|
||||
{
|
||||
Vt = 0, ///< V(t) chart; X axis = time, Y axis = value
|
||||
Dv ///< D(v) chart; X axis = value, Y axis = duration
|
||||
};
|
||||
|
||||
enum class ChartViewType : uint8_t
|
||||
{
|
||||
Line = 0,
|
||||
Points
|
||||
};
|
||||
|
||||
struct CollectionPaintData EASY_FINAL
|
||||
{
|
||||
const ArbitraryValuesCollection* ptr;
|
||||
QRgb color;
|
||||
ChartViewType chartType;
|
||||
ChartPenStyle chartPenStyle;
|
||||
bool selected;
|
||||
};
|
||||
|
||||
@ -158,9 +188,14 @@ class ArbitraryValuesChartItem : public GraphicsImageItem
|
||||
using Parent = GraphicsImageItem;
|
||||
using This = ArbitraryValuesChartItem;
|
||||
|
||||
Collections m_collections;
|
||||
qreal m_workerMaxValue;
|
||||
qreal m_workerMinValue;
|
||||
Collections m_collections;
|
||||
qreal m_workerMaxValue;
|
||||
qreal m_workerMinValue;
|
||||
profiler::timestamp_t m_workerMaxDuration;
|
||||
profiler::timestamp_t m_workerMinDuration;
|
||||
profiler::timestamp_t m_maxDuration;
|
||||
profiler::timestamp_t m_minDuration;
|
||||
ChartType m_chartType;
|
||||
|
||||
public:
|
||||
|
||||
@ -180,14 +215,21 @@ public:
|
||||
void clear();
|
||||
void update(Collections _collections);
|
||||
void update(const ArbitraryValuesCollection* _selected);
|
||||
void setChartType(ChartType _chartType);
|
||||
ChartType chartType() const;
|
||||
|
||||
private:
|
||||
|
||||
void paintMouseIndicator(QPainter* _painter, qreal _top, qreal _bottom, qreal _width, qreal _height, int _font_h,
|
||||
qreal _visibleRegionLeft, qreal _visibleRegionWidth);
|
||||
|
||||
void updateImageAsync(QRectF _boundingRect, qreal _current_scale, qreal _minimum, qreal _maximum, qreal _range,
|
||||
qreal _value, qreal _width, bool _bindMode, profiler::timestamp_t _begin_time, bool _autoAdjust);
|
||||
void updateRegularImageAsync(QRectF _boundingRect, qreal _current_scale, qreal _minimum, qreal _maximum
|
||||
, qreal _range, qreal _value, qreal _width, bool _bindMode, profiler::timestamp_t _begin_time, bool _autoAdjust);
|
||||
|
||||
void updateComplexityImageAsync(QRectF _boundingRect, qreal _current_scale, qreal _minimum, qreal _maximum
|
||||
, qreal _range, qreal _value, qreal _width, bool _bindMode, profiler::timestamp_t _begin_time, bool _autoAdjust);
|
||||
|
||||
void drawGrid(QPainter& _painter, int _width, int _height) const;
|
||||
|
||||
}; // end of class ArbitraryValuesChartItem.
|
||||
|
||||
@ -220,6 +262,8 @@ public:
|
||||
void cancelImageUpdate();
|
||||
void update(Collections _collections);
|
||||
void update(const ArbitraryValuesCollection* _selected);
|
||||
void setChartType(ChartType _chartType);
|
||||
ChartType chartType() const;
|
||||
|
||||
private slots:
|
||||
|
||||
@ -253,7 +297,7 @@ public:
|
||||
|
||||
const ArbitraryValuesCollection* collection() const;
|
||||
ArbitraryValuesCollection* collection();
|
||||
void collectValues(profiler::thread_id_t _threadId);
|
||||
void collectValues(profiler::thread_id_t _threadId, ChartType _chartType);
|
||||
void interrupt();
|
||||
|
||||
profiler::color_t color() const;
|
||||
@ -296,9 +340,13 @@ private slots:
|
||||
void onItemChanged(QTreeWidgetItem* _item, int _column);
|
||||
void onCurrentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*);
|
||||
void onCollectionsTimeout();
|
||||
void onRegularChartTypeChecked(bool _checked);
|
||||
void onComplexityChartTypeChecked(bool _checked);
|
||||
|
||||
private:
|
||||
|
||||
void repaint();
|
||||
|
||||
void buildTree(profiler::thread_id_t _threadId, profiler::block_index_t _blockIndex, profiler::block_id_t _blockId);
|
||||
QTreeWidgetItem* buildTreeForThread(const profiler::BlocksTreeRoot& _threadRoot, profiler::block_index_t _blockIndex, profiler::block_id_t _blockId);
|
||||
|
||||
|
@ -22,7 +22,7 @@ int RESOURCE_LOADING_COUNT = 50;
|
||||
|
||||
#define SAMPLE_NETWORK_TEST
|
||||
|
||||
void localSleep(int magic=200000)
|
||||
void localSleep(uint64_t magic=200000)
|
||||
{
|
||||
//PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Blue);
|
||||
volatile int i = 0;
|
||||
@ -136,10 +136,20 @@ void calculatePhysics(){
|
||||
//std::this_thread::sleep_for(std::chrono::milliseconds(8));
|
||||
}
|
||||
|
||||
void frame(){
|
||||
void quadratic_loop(uint64_t n)
|
||||
{
|
||||
EASY_FUNCTION(profiler::colors::Blue);
|
||||
EASY_VALUE("N", n);
|
||||
volatile int i = 0;
|
||||
for (; i < n; ++i)
|
||||
localSleep(n);
|
||||
}
|
||||
|
||||
void frame(uint64_t n){
|
||||
EASY_FUNCTION(profiler::colors::Magenta);
|
||||
prepareRender();
|
||||
calculatePhysics();
|
||||
quadratic_loop(n);
|
||||
}
|
||||
|
||||
void loadingResourcesThread(){
|
||||
@ -189,13 +199,17 @@ void renderThread(){
|
||||
//std::unique_lock<std::mutex> lk(cv_m);
|
||||
//cv.wait(lk, []{return g_i == 1; });
|
||||
EASY_THREAD("Render");
|
||||
uint64_t n = 20;
|
||||
#ifdef SAMPLE_NETWORK_TEST
|
||||
while (true) {
|
||||
#else
|
||||
for (int i = 0; i < RENDER_STEPS; i++){
|
||||
#endif
|
||||
frame();
|
||||
frame(n);
|
||||
localSleep(1200000);
|
||||
n += 20;
|
||||
if (n >= 700)
|
||||
n = 20;
|
||||
//std::this_thread::sleep_for(std::chrono::milliseconds(20));
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user