TimelineTrack.cpp 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. /*
  2. * Copyright (c) 2018-2021, Andreas Kling <kling@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include "TimelineTrack.h"
  7. #include "Profile.h"
  8. #include "TimelineView.h"
  9. #include <LibGUI/Painter.h>
  10. #include <LibGfx/Palette.h>
  11. namespace Profiler {
  12. TimelineTrack::TimelineTrack(TimelineView const& view, Profile const& profile, Process const& process)
  13. : m_view(view)
  14. , m_profile(profile)
  15. , m_process(process)
  16. {
  17. set_fill_with_background_color(true);
  18. set_background_role(Gfx::ColorRole::Base);
  19. set_fixed_height(40);
  20. set_scale(view.scale());
  21. set_frame_thickness(1);
  22. }
  23. TimelineTrack::~TimelineTrack()
  24. {
  25. }
  26. void TimelineTrack::set_scale(float scale)
  27. {
  28. set_fixed_width(m_profile.length_in_ms() / scale);
  29. }
  30. void TimelineTrack::event(Core::Event& event)
  31. {
  32. switch (event.type()) {
  33. case GUI::Event::MouseUp:
  34. case GUI::Event::MouseDown:
  35. case GUI::Event::MouseMove:
  36. event.ignore();
  37. break;
  38. default:
  39. break;
  40. }
  41. GUI::Frame::event(event);
  42. }
  43. void TimelineTrack::paint_event(GUI::PaintEvent& event)
  44. {
  45. GUI::Frame::paint_event(event);
  46. GUI::Painter painter(*this);
  47. painter.add_clip_rect(event.rect());
  48. u64 const start_of_trace = m_profile.first_timestamp();
  49. u64 const end_of_trace = start_of_trace + m_profile.length_in_ms();
  50. auto const clamp_timestamp = [start_of_trace, end_of_trace](u64 timestamp) -> u64 {
  51. return min(end_of_trace, max(timestamp, start_of_trace));
  52. };
  53. float column_width = (float)frame_inner_rect().width() / (float)m_profile.length_in_ms();
  54. size_t columns = frame_inner_rect().width() / column_width;
  55. recompute_histograms_if_needed({ start_of_trace, end_of_trace, columns });
  56. float frame_height = (float)frame_inner_rect().height() / (float)m_max_value;
  57. for (size_t bucket = 0; bucket < m_kernel_histogram->size(); bucket++) {
  58. auto kernel_value = m_kernel_histogram->at(bucket);
  59. auto user_value = m_user_histogram->at(bucket);
  60. if (kernel_value + user_value == 0)
  61. continue;
  62. auto t = bucket;
  63. int x = (int)((float)t * column_width);
  64. int cw = max(1, (int)column_width);
  65. int kernel_column_height = frame_inner_rect().height() - (int)((float)kernel_value * frame_height);
  66. int user_column_height = frame_inner_rect().height() - (int)((float)(kernel_value + user_value) * frame_height);
  67. constexpr auto kernel_color = Color::from_rgb(0xc25e5a);
  68. constexpr auto user_color = Color::from_rgb(0x5a65c2);
  69. painter.fill_rect({ x, frame_thickness() + user_column_height, cw, height() - frame_thickness() * 2 }, user_color);
  70. painter.fill_rect({ x, frame_thickness() + kernel_column_height, cw, height() - frame_thickness() * 2 }, kernel_color);
  71. }
  72. u64 normalized_start_time = clamp_timestamp(min(m_view.select_start_time(), m_view.select_end_time()));
  73. u64 normalized_end_time = clamp_timestamp(max(m_view.select_start_time(), m_view.select_end_time()));
  74. u64 normalized_hover_time = clamp_timestamp(m_view.hover_time());
  75. int select_start_x = (int)((float)(normalized_start_time - start_of_trace) * column_width);
  76. int select_end_x = (int)((float)(normalized_end_time - start_of_trace) * column_width);
  77. int select_hover_x = (int)((float)(normalized_hover_time - start_of_trace) * column_width);
  78. painter.fill_rect({ select_start_x, frame_thickness(), select_end_x - select_start_x, height() - frame_thickness() * 2 }, Color(0, 0, 0, 60));
  79. painter.fill_rect({ select_hover_x, frame_thickness(), 1, height() - frame_thickness() * 2 }, Color::NamedColor::Black);
  80. }
  81. void TimelineTrack::recompute_histograms_if_needed(HistogramInputs const& inputs)
  82. {
  83. if (m_cached_histogram_inputs == inputs && m_kernel_histogram.has_value())
  84. return;
  85. auto const clamp_timestamp = [&inputs](u64 timestamp) -> u64 {
  86. return min(inputs.end, max(timestamp, inputs.start));
  87. };
  88. m_kernel_histogram = Histogram { inputs.start, inputs.end, inputs.columns };
  89. m_user_histogram = Histogram { inputs.start, inputs.end, inputs.columns };
  90. for (auto& event : m_profile.events()) {
  91. if (event.pid != m_process.pid)
  92. continue;
  93. if (!m_process.valid_at(event.serial))
  94. continue;
  95. auto& histogram = event.in_kernel ? *m_kernel_histogram : *m_user_histogram;
  96. histogram.insert(clamp_timestamp(event.timestamp), 1 + event.lost_samples);
  97. }
  98. for (size_t bucket = 0; bucket < m_kernel_histogram->size(); bucket++) {
  99. auto value = m_kernel_histogram->at(bucket) + m_user_histogram->at(bucket);
  100. if (value > m_max_value)
  101. m_max_value = value;
  102. }
  103. }
  104. }