83 m_frameTimeMetric = std::make_shared<MetricData>(
"Frame Time", wxColour(100, 200, 100),
"ms", 200);
84 m_fpsMetric = std::make_shared<MetricData>(
"FPS", wxColour(200, 100, 100),
"fps", 200);
85 m_cpuMetric = std::make_shared<MetricData>(
"CPU Usage", wxColour(100, 100, 200),
"%", 200);
86 m_memoryMetric = std::make_shared<MetricData>(
"App Memory", wxColour(200, 200, 100),
"MB", 200);
141 std::ifstream file(
"/proc/stat");
146 std::getline(file, line);
148 std::istringstream iss(line);
150 unsigned long long user, nice, system, idle, iowait, irq, softirq, steal, guest, guest_nice;
152 iss >> cpu >> user >> nice >> system >> idle >> iowait >> irq >> softirq >> steal >> guest >> guest_nice;
154 unsigned long long totalIdle = idle + iowait;
155 unsigned long long totalNonIdle = user + nice + system + irq + softirq + steal;
156 unsigned long long total = totalIdle + totalNonIdle;
158 if (m_lastCpuTotal == 0) {
159 m_lastCpuTotal = total;
160 m_lastCpuIdle = totalIdle;
164 unsigned long long totalDiff = total - m_lastCpuTotal;
165 unsigned long long idleDiff = totalIdle - m_lastCpuIdle;
167 float cpuPercent = 0.0f;
169 cpuPercent = ((float)(totalDiff - idleDiff) / totalDiff) * 100.0f;
172 m_lastCpuTotal = total;
173 m_lastCpuIdle = totalIdle;
215 static int colorIndex = 0;
216 wxColour colors[] = {wxColour(255, 100, 100), wxColour(100, 255, 100), wxColour(100, 100, 255),
217 wxColour(255, 255, 100), wxColour(255, 100, 255), wxColour(100, 255, 255),
218 wxColour(200, 150, 100), wxColour(150, 200, 100), wxColour(100, 150, 200)};
220 wxColour color = colors[colorIndex % (
sizeof(colors) /
sizeof(colors[0]))];
223 m_customMetrics[name] = std::make_shared<MetricData>(name, color, unit, 120);
352 wxPanel *toolbar =
new wxPanel(
this, wxID_ANY);
353 toolbar->SetBackgroundColour(wxColour(50, 50, 50));
355 wxBoxSizer *toolbarSizer =
new wxBoxSizer(wxHORIZONTAL);
370 toolbarSizer->AddSpacer(20);
373 wxStaticText *chartsLabel =
new wxStaticText(toolbar, wxID_ANY,
"Charts:");
374 chartsLabel->SetForegroundColour(wxColour(200, 200, 200));
375 toolbarSizer->Add(chartsLabel, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);
385 toolbarSizer->Add(
m_fpsCheckbox, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);
390 toolbarSizer->Add(
m_cpuCheckbox, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);
397 toolbarSizer->AddStretchSpacer();
400 toolbarSizer->AddSpacer(20);
403 wxStaticText *timeframeLabel =
new wxStaticText(toolbar, wxID_ANY,
"History:");
404 timeframeLabel->SetForegroundColour(wxColour(200, 200, 200));
405 toolbarSizer->Add(timeframeLabel, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 8);
409 minusFont.SetPointSize(14);
410 minusFont.SetWeight(wxFONTWEIGHT_BOLD);
415 wxDefaultSize, wxALIGN_CENTRE);
418 toolbarSizer->Add(
m_historyText, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_CENTER_HORIZONTAL, 0);
422 plusFont.SetPointSize(14);
423 plusFont.SetWeight(wxFONTWEIGHT_BOLD);
427 wxStaticText *secondsLabel =
new wxStaticText(toolbar, wxID_ANY,
"seconds");
428 secondsLabel->SetForegroundColour(wxColour(200, 200, 200));
429 toolbarSizer->Add(secondsLabel, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, 8);
431 toolbarSizer->AddStretchSpacer();
434 m_statusText =
new wxStaticText(toolbar, wxID_ANY,
"OFF");
436 toolbarSizer->Add(
m_statusText, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);
438 toolbar->SetSizer(toolbarSizer);
441 wxSizer *mainSizer = GetSizer();
443 mainSizer->Add(toolbar, 0, wxEXPAND | wxALL, 2);
517 if (!metric || metric->values.empty())
521 dc.SetBrush(wxBrush(wxColour(25, 25, 25)));
522 dc.SetPen(wxPen(wxColour(60, 60, 60)));
523 dc.DrawRectangle(rect);
526 DrawGrid(dc, rect, metric->min_value, metric->max_value);
529 wxRect infoRect = rect;
530 infoRect.height = 25;
534 if (metric->values.size() < 2)
537 wxRect dataRect = rect;
539 dataRect.height -= 25;
541 float range = metric->max_value - metric->min_value;
546 dc.SetPen(wxPen(metric->color, 2));
548 const auto &values = metric->values;
549 int numValues = values.size();
550 float xStep = (float)dataRect.width / (numValues - 1);
552 for (
int i = 1; i < numValues; ++i) {
553 float x1 = dataRect.x + (i - 1) * xStep;
554 float y1 = dataRect.y + dataRect.height - ((values[i - 1] - metric->min_value) / range) * dataRect.height;
555 float x2 = dataRect.x + i * xStep;
556 float y2 = dataRect.y + dataRect.height - ((values[i] - metric->min_value) / range) * dataRect.height;
558 dc.DrawLine(wxPoint(x1, y1), wxPoint(x2, y2));
564 dc.SetTextForeground(wxColour(200, 200, 200));
566 wxString info = wxString::Format(
567 "%s: %s (Avg: %s, Min: %s, Max: %s)", metric->name,
FormatValue(metric->current_value, metric->unit),
571 dc.DrawText(info, rect.x + 5, rect.y + 5);
656 wxFileDialog saveDialog(
this,
"Export Performance Data",
"",
"performance.csv",
657 "CSV files (*.csv)|*.csv|All files (*.*)|*.*", wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
659 if (saveDialog.ShowModal() == wxID_OK) {
660 wxString path = saveDialog.GetPath();
662 auto metrics =
m_monitor->GetAllMetrics();
667 size_t maxSamples = 0;
668 for (
const auto &metric : metrics) {
669 maxSamples = std::max(maxSamples, metric->values.size());
672 wxString content =
"Sample";
673 for (
const auto &metric : metrics) {
674 content +=
",%s (" + metric->name, metric->unit +
")";
678 for (
size_t i = 0; i < maxSamples; ++i) {
679 content += wxString::Format(
"%zu", i);
680 for (
const auto &metric : metrics) {
681 if (i < metric->values.size()) {
682 content += wxString::Format(
",%.3f", metric->values[i]);
690 wxFile file(path, wxFile::write);
691 if (file.IsOpened()) {
695 wxMessageBox(
"Performance data exported to " + path +
"",
"Export Complete", wxOK | wxICON_INFORMATION,
698 wxMessageBox(
"Failed to save performance data",
"Export Error", wxOK | wxICON_ERROR,
this);