From patchwork Wed Aug 22 15:41:36 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yordan Karadzhov X-Patchwork-Id: 10759133 Return-Path: Received: from mail-wm0-f65.google.com ([74.125.82.65]:37256 "EHLO mail-wm0-f65.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728958AbeHVTH0 (ORCPT ); Wed, 22 Aug 2018 15:07:26 -0400 Received: by mail-wm0-f65.google.com with SMTP id n11-v6so2655746wmc.2 for ; Wed, 22 Aug 2018 08:42:02 -0700 (PDT) From: "Yordan Karadzhov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org, "Yordan Karadzhov (VMware)" Subject: [PATCH 1/5] kernel-shark-qt: Add OpenGL/GLUT as a third party dependency. Date: Wed, 22 Aug 2018 18:41:36 +0300 Message-Id: <20180822154140.3748-2-y.karadz@gmail.com> In-Reply-To: <20180822154140.3748-1-y.karadz@gmail.com> References: <20180822154140.3748-1-y.karadz@gmail.com> Sender: linux-trace-devel-owner@vger.kernel.org List-ID: Content-Length: 1633 This patch prepares the Cmake build infrastructure for the introduction of a KernelShark Ploting library, baset on OpenGl. The Ploting library will be added in the following patch. Signed-off-by: Yordan Karadzhov (VMware) --- kernel-shark-qt/CMakeLists.txt | 3 +++ kernel-shark-qt/README | 2 ++ 2 files changed, 5 insertions(+) diff --git a/kernel-shark-qt/CMakeLists.txt b/kernel-shark-qt/CMakeLists.txt index 3516caa..0187eb4 100644 --- a/kernel-shark-qt/CMakeLists.txt +++ b/kernel-shark-qt/CMakeLists.txt @@ -17,6 +17,9 @@ include(${KS_DIR}/build/FindJSONC.cmake) find_package(Doxygen) +find_package(OpenGL) +find_package(GLUT) + set(LIBRARY_OUTPUT_PATH "${KS_DIR}/lib") set(EXECUTABLE_OUTPUT_PATH "${KS_DIR}/bin") diff --git a/kernel-shark-qt/README b/kernel-shark-qt/README index e6818fc..f03288c 100644 --- a/kernel-shark-qt/README +++ b/kernel-shark-qt/README @@ -7,6 +7,7 @@ Third Party Software: The external dependencies: 1. In order to install the packages on Ubuntu do the following: sudo apt-get install build-essential git cmake libjson-c-dev -y + sudo apt-get install freeglut3-dev libxmu-dev libxi-dev -y 1.1 I you want to be able to generate Doxygen documentation: sudo apt-get install graphviz doxygen-gui -y @@ -14,6 +15,7 @@ The external dependencies: 2. In order to install the packages on Fedora, as root do the following: dnf install gcc gcc-c++ git cmake json-c-devel -y + dnf install freeglut-devel redhat-rpm-config -y 2.1 I you want to be able to generate Doxygen documentation: dnf install graphviz doxygen -y From patchwork Wed Aug 22 15:41:37 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yordan Karadzhov X-Patchwork-Id: 10759141 Return-Path: Received: from mail-wm0-f65.google.com ([74.125.82.65]:39903 "EHLO mail-wm0-f65.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728958AbeHVTHh (ORCPT ); Wed, 22 Aug 2018 15:07:37 -0400 Received: by mail-wm0-f65.google.com with SMTP id q8-v6so2668091wmq.4 for ; Wed, 22 Aug 2018 08:42:12 -0700 (PDT) From: "Yordan Karadzhov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org, "Yordan Karadzhov (VMware)" Subject: [PATCH 2/5] kernel-shark-qt: Add basic instruments for OpenGL plotting. Date: Wed, 22 Aug 2018 18:41:37 +0300 Message-Id: <20180822154140.3748-3-y.karadz@gmail.com> In-Reply-To: <20180822154140.3748-1-y.karadz@gmail.com> References: <20180822154140.3748-1-y.karadz@gmail.com> Sender: linux-trace-devel-owner@vger.kernel.org List-ID: Content-Length: 8607 This patch introduces tools for initializing OpenGL and for drawing the three basic geometrical primitives (point, line and polygon) used when plotting KernelShark's graphs. Signed-off-by: Yordan Karadzhov (VMware) --- kernel-shark-qt/src/CMakeLists.txt | 13 ++ kernel-shark-qt/src/libkshark-plot.c | 212 +++++++++++++++++++++++++++ kernel-shark-qt/src/libkshark-plot.h | 69 +++++++++ 3 files changed, 294 insertions(+) create mode 100644 kernel-shark-qt/src/libkshark-plot.c create mode 100644 kernel-shark-qt/src/libkshark-plot.h diff --git a/kernel-shark-qt/src/CMakeLists.txt b/kernel-shark-qt/src/CMakeLists.txt index a762da1..9c74bc0 100644 --- a/kernel-shark-qt/src/CMakeLists.txt +++ b/kernel-shark-qt/src/CMakeLists.txt @@ -13,5 +13,18 @@ target_link_libraries(kshark ${CMAKE_DL_LIBS} set_target_properties(kshark PROPERTIES SUFFIX ".so.${KS_VERSION_STRING}") +if (OPENGL_FOUND AND GLUT_FOUND) + + message(STATUS "libkshark-plot") + add_library(kshark-plot SHARED libkshark-plot.c) + + target_link_libraries(kshark-plot kshark + ${OPENGL_LIBRARIES} + ${GLUT_LIBRARY}) + + set_target_properties(kshark-plot PROPERTIES SUFFIX ".so.${KS_VERSION_STRING}") + +endif (OPENGL_FOUND AND GLUT_FOUND) + configure_file( ${KS_DIR}/build/deff.h.cmake ${KS_DIR}/src/KsDeff.h) diff --git a/kernel-shark-qt/src/libkshark-plot.c b/kernel-shark-qt/src/libkshark-plot.c new file mode 100644 index 0000000..17d3b90 --- /dev/null +++ b/kernel-shark-qt/src/libkshark-plot.c @@ -0,0 +1,212 @@ +/* SPDX-License-Identifier: LGPL-2.1 */ + +/* + * Copyright (C) 2018 VMware Inc, Yordan Karadzhov + */ + + /** + * @file libkshark-plot.c + * @brief Basic tools for OpenGL plotting. + */ + +// OpenGL +#include +#include + +// KernelShark +#include "libkshark-plot.h" + +/** + * @brief Create an empty scene for drawing. + * + * @param width: Width of the screen window in pixels. + * @param height: Height of the screen window in pixels. + */ +void ksplot_make_scene(int width, int height) +{ + /* Set Display mode. */ + glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB); + + /* Prevent the program from exiting when a window is closed. */ + glutSetOption(GLUT_ACTION_ON_WINDOW_CLOSE, + GLUT_ACTION_GLUTMAINLOOP_RETURNS); + + /* Set window size. */ + glutInitWindowSize(width, height); + + /* Set window position on screen. */ + glutInitWindowPosition(50, 50); + + /* Open the screen window. */ + glutCreateWindow("KernelShark Plot"); + + /* + * Set the origin of the coordinate system to be the top left corner. + * The "Y" coordinate is inverted. + */ + gluOrtho2D(0, width, height, 0); + glViewport(0, 0, width, height); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); +} + +/** + * @brief Initialize OpenGL. + * + * @param dpr: Device Pixel Ratio. + */ +void ksplot_init_opengl(int dpr) +{ + glDisable(GL_TEXTURE_2D); + glDisable(GL_DEPTH_TEST); + glDisable(GL_COLOR_MATERIAL); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glEnable(GL_POLYGON_SMOOTH); + glLineWidth(1.5 * dpr); + glPointSize(2.5 * dpr); + glClearColor(1, 1, 1, 1); +} + +/** + * @brief To be called whenever the OpenGL window has been resized. + * + * @param width: Width of the screen window in pixels. + * @param height: Height of the screen window in pixels. + */ +void ksplot_resize_opengl(int width, int height) +{ + glViewport(0, 0, width, height); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + + /* + * Set the origin of the coordinate system to be the top left corner. + * The "Y" coordinate is inverted. + */ + gluOrtho2D(0, width, height, 0); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); +} + +/** + * @brief Draw a point. + * + * @param p: Input location for the point object. + * @param col: The color of the point. + * @param size: The size of the point. + */ +void ksplot_draw_point(const struct ksplot_point *p, + const struct ksplot_color *col, + float size) +{ + if (!p || !col || size < .5f) + return; + + glPointSize(size); + glBegin(GL_POINTS); + glColor3ub(col->red, col->green, col->blue); + glVertex2i(p->x, p->y); + glEnd(); +} + +/** + * @brief Draw a line. + * + * @param a: Input location for the first finishing point of the line. + * @param b: Input location for the second finishing point of the line. + * @param col: The color of the line. + * @param size: The size of the line. + */ +void ksplot_draw_line(const struct ksplot_point *a, + const struct ksplot_point *b, + const struct ksplot_color *col, + float size) +{ + if (!a || !b || !col || size < .5f) + return; + + glLineWidth(size); + glBegin(GL_LINES); + glColor3ub(col->red, col->green, col->blue); + glVertex2i(a->x, a->y); + glVertex2i(b->x, b->y); + glEnd(); +} + +/** + * @brief Draw a polygon. + * + * @param points: Input location for the array of points defining the polygon. + * @param n_points: The size of the array of points. + * @param col: The color of the polygon. + * @param size: The size of the polygon. + */ +void ksplot_draw_polygon(const struct ksplot_point *points, + size_t n_points, + const struct ksplot_color *col, + float size) +{ + if (!points || !n_points || !col || size < .5f) + return; + + if (n_points == 1) { + ksplot_draw_point(points, col, size); + return; + } + + if (n_points == 2) { + ksplot_draw_line(points, points + 1, col, size); + return; + } + + /* Obtain a point inside the surface of the polygon. */ + struct ksplot_point in_point; + in_point.x = (points[0].x + points[2].x) / 2; + in_point.y = (points[0].y + points[2].y) / 2; + + /* + * Draw a Triangle Fan using the internal point as a central + * vertex. + */ + glBegin(GL_TRIANGLE_FAN); + glColor3ub(col->red, col->green, col->blue); + glVertex2i(in_point.x, in_point.y); + for (size_t i = 0; i < n_points; ++i) + glVertex2i(points[i].x, points[i].y); + + glVertex2i(points[0].x, points[0].y); + glEnd(); +} + +/** + * @brief Draw the contour of a polygon. + * + * @param points: Input location for the array of points defining the polygon. + * @param n_points: The size of the array of points. + * @param col: The color of the polygon. + * @param size: The size of the polygon. + */ +void ksplot_draw_polygon_contour(const struct ksplot_point *points, + size_t n_points, + const struct ksplot_color *col, + float size) +{ + if (!points || !n_points || !col || size < .5f) + return; + + /* Loop over the points of the polygon and draw connecting lines. */ + for(size_t i = 1; i < n_points; ++i) + ksplot_draw_line(&points[i - 1], + &points[i], + col, + size); + + /* Close the contour. */ + ksplot_draw_line(&points[0], + &points[n_points - 1], + col, + size); +} diff --git a/kernel-shark-qt/src/libkshark-plot.h b/kernel-shark-qt/src/libkshark-plot.h new file mode 100644 index 0000000..9a4dbc0 --- /dev/null +++ b/kernel-shark-qt/src/libkshark-plot.h @@ -0,0 +1,69 @@ +/* SPDX-License-Identifier: LGPL-2.1 */ + +/* + * Copyright (C) 2018 VMware Inc, Yordan Karadzhov + */ + + /** + * @file libkshark-plot.h + * @brief Basic tools for OpenGL plotting. + */ + +#ifndef _LIB_KSHARK_PLOT_H +#define _LIB_KSHARK_PLOT_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** Structure defining a RGB color. */ +struct ksplot_color { + /** The Red component of the color. */ + uint8_t red; + + /** The Green component of the color. */ + uint8_t green; + + /** The Blue component of the color. */ + uint8_t blue; +}; + +/** Structure defining a 2D point. */ +struct ksplot_point { + /** The horizontal coordinate of the point in pixels. */ + int x; + + /** The vertical coordinate of the pointin in pixels. */ + int y; +}; + +void ksplot_make_scene(int width, int height); + +void ksplot_init_opengl(int dpr); + +void ksplot_resize_opengl(int width, int height); + +void ksplot_draw_point(const struct ksplot_point *p, + const struct ksplot_color *col, + float size); + +void ksplot_draw_line(const struct ksplot_point *a, + const struct ksplot_point *b, + const struct ksplot_color *col, + float size); + +void ksplot_draw_polygon(const struct ksplot_point *points, + size_t n_points, + const struct ksplot_color *col, + float size); + +void ksplot_draw_polygon_contour(const struct ksplot_point *points, + size_t n_points, + const struct ksplot_color *col, + float size); + +#ifdef __cplusplus +} +#endif + +#endif From patchwork Wed Aug 22 15:41:38 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yordan Karadzhov X-Patchwork-Id: 10759143 Return-Path: Received: from mail-wr1-f68.google.com ([209.85.221.68]:42959 "EHLO mail-wr1-f68.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728958AbeHVTHk (ORCPT ); Wed, 22 Aug 2018 15:07:40 -0400 Received: by mail-wr1-f68.google.com with SMTP id v17-v6so1990523wrr.9 for ; Wed, 22 Aug 2018 08:42:15 -0700 (PDT) From: "Yordan Karadzhov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org, "Yordan Karadzhov (VMware)" Subject: [PATCH 3/5] kernel-shark-qt: Add C++ API for drawing of Graphs Date: Wed, 22 Aug 2018 18:41:38 +0300 Message-Id: <20180822154140.3748-4-y.karadz@gmail.com> In-Reply-To: <20180822154140.3748-1-y.karadz@gmail.com> References: <20180822154140.3748-1-y.karadz@gmail.com> Sender: linux-trace-devel-owner@vger.kernel.org List-ID: Content-Length: 33136 This patch extends the KernelShark Plotting library, by adding a C++ API for drawing CPU and Task Graphs. Signed-off-by: Yordan Karadzhov (VMware) --- kernel-shark-qt/src/CMakeLists.txt | 3 +- kernel-shark-qt/src/KsPlotTools.cpp | 1009 +++++++++++++++++++++++++++ kernel-shark-qt/src/KsPlotTools.hpp | 440 ++++++++++++ 3 files changed, 1451 insertions(+), 1 deletion(-) create mode 100644 kernel-shark-qt/src/KsPlotTools.cpp create mode 100644 kernel-shark-qt/src/KsPlotTools.hpp diff --git a/kernel-shark-qt/src/CMakeLists.txt b/kernel-shark-qt/src/CMakeLists.txt index 9c74bc0..ac2847a 100644 --- a/kernel-shark-qt/src/CMakeLists.txt +++ b/kernel-shark-qt/src/CMakeLists.txt @@ -16,7 +16,8 @@ set_target_properties(kshark PROPERTIES SUFFIX ".so.${KS_VERSION_STRING}") if (OPENGL_FOUND AND GLUT_FOUND) message(STATUS "libkshark-plot") - add_library(kshark-plot SHARED libkshark-plot.c) + add_library(kshark-plot SHARED libkshark-plot.c + KsPlotTools.cpp) target_link_libraries(kshark-plot kshark ${OPENGL_LIBRARIES} diff --git a/kernel-shark-qt/src/KsPlotTools.cpp b/kernel-shark-qt/src/KsPlotTools.cpp new file mode 100644 index 0000000..2e3029b --- /dev/null +++ b/kernel-shark-qt/src/KsPlotTools.cpp @@ -0,0 +1,1009 @@ +// SPDX-License-Identifier: LGPL-2.1 + +/* + * Copyright (C) 2017 VMware Inc, Yordan Karadzhov + */ + +/** + * @file KsPlotTools.cpp + * @brief KernelShark Plot tools. + */ + +// C +#include + +// C++ +#include +#include + +// OpenGL +#include +#include + +// KernelShark +#include "KsPlotTools.hpp" + +namespace KsPlot +{ + +float Color::_frequency = .75; + +/** + * @brief Create a default color (black). + */ +Color::Color() +{ + _col_c.red = _col_c.green = _col_c.blue = 0; +} + +/** + * @brief Constructs a RGB color object. + * + * @param r: The red component of the color. + * @param g: The green component of the color. + * @param b: The blue component of the color + */ +Color::Color(uint8_t r, uint8_t g, uint8_t b) +{ + set(r, g, b); +} + +/** + * @brief Constructs a RGB color object. + * + * @param rgb: RGB value. + */ +Color::Color(int rgb) +{ + set(rgb); +} + +/** + * @brief Sets the color. + * + * @param r: The red component of the color. + * @param g: The green component of the color. + * @param b: The blue component of the color + */ +void Color::set(uint8_t r, uint8_t g, uint8_t b) +{ + _col_c.red = r; + _col_c.green = g; + _col_c.blue = b; +} + +/** + * @brief Sets the color. + * + * @param rgb: RGB value. + */ +void Color::set(int rgb) +{ + int r = rgb & 0xFF; + int g = (rgb >> 8) & 0xFF; + int b = (rgb >> 16) & 0xFF; + + set(r, g, b); +} + +/** + * @brief The color is selected from the Rainbow palette. + * + * @param n: index of the color inside the Rainbow palette. + */ +void Color::setRainbowColor(int n) +{ + int r = sin(_frequency * n + 0) * 127 + 128; + int g = sin(_frequency * n + 2) * 127 + 128; + int b = sin(_frequency * n + 4) * 127 + 128; + + set(r, g, b); +} + +/** + * @brief Create a Hash table of Rainbow colors. The sorted Pid values are + * mapped to the palette of Rainbow colors. + * + * @returns ColorTable instance. + */ +ColorTable getColorTable() +{ + struct kshark_context *kshark_ctx(nullptr); + ColorTable colors; + int nTasks, pid, *pids; + + if (!kshark_instance(&kshark_ctx)) + return colors; + + nTasks = kshark_get_task_pids(kshark_ctx, &pids); + if (!nTasks) + return colors; + + std::vector temp_pids(pids, pids + nTasks); + std::sort(temp_pids.begin(), temp_pids.end()); + + /* The "Idle" process (pid = 0) will be plotted in black. */ + colors[0] = {}; + + for (int i = 1; i < nTasks; ++i) { + pid = temp_pids[i]; + colors[pid].setRainbowColor(i - 1); + } + + return colors; +} + +/** + * @brief Search the Hash table of Rainbow colors for a particular key (pid). + * + * @param colors: Input location for the ColorTable instance. + * @param pid: the Process Id to search for. + * + * @returns The Rainbow color of the key "pid". If "pid" does not exist, the + * returned color is Black. + */ +Color getPidColor(ColorTable *colors, int pid) +{ + auto item = colors->find(pid); + + if (item != colors->end()) + return item->second; + + return {}; +} + +/** + * @brief Create a default point. + */ +Point::Point() +{ + set(0, 0); +} + +/** + * @brief Create a point. + * + * @param x: X coordinate of the point in pixels. + * @param y: Y coordinate of the point in pixels. + */ +Point::Point(int x, int y) +{ + set(x, y); +} + +void Point::_draw(const Color &col, float size) const +{ + ksplot_draw_point(&_point_c, col.color_c_ptr(), size); +} + +/** + * @brief Draw a line between point "a" and point "b". + * + * @param a: The first finishing point of the line. + * @param b: The second finishing point of the line. + * @param col: The color of the line. + * @param size: The size of the line. + */ +void drawLine(const Point &a, const Point &b, + const Color &col, float size) +{ + ksplot_draw_line(a.point_c_ptr(), + b.point_c_ptr(), + col.color_c_ptr(), + size); +} + +/** + * @brief Create a default line. + */ +Line::Line() +{ + setA(0, 0); + setB(0, 0); +} + +/** + * @brief Create a line between the point "a" and point "b". + * + * @param a: first finishing point of the line. + * @param b: second finishing point of the line. + */ +Line::Line(const Point &a, const Point &b) +{ + setA(a.x(), a.y()); + setB(b.x(), b.y()); +} + +void Line::_draw(const Color &col, float size) const +{ + ksplot_draw_line(&_a, &_b, col.color_c_ptr(), size); +} + +/** + * @brief Create a default line. The polygon object has the ownership of the + * array of point used to define its shape. + * + * @param n: Number of edges in the polyhedron. + */ +Polygon::Polygon(size_t n) +: _nPoints(n), + _points(new ksplot_point[n]), + _fill(true) +{ + if (!_points) + _nPoints = 0; +} + +/** + * @brief Destroy the polygon object. + */ +Polygon::~Polygon() +{ + delete[] _points; +} + +/** + * @brief Set the point of the polygon indexed by "i". + * + * @param i: the indexed of the point to be set. + * @param x: X coordinate of the point in pixels. + * @param y: Y coordinate of the point in pixels. + */ +void Polygon::setPoint(size_t i, int x, int y) +{ + _points[i].x = x; + _points[i].y = y; +} + +/** + * @brief Set the point of the polygon indexed by "i". + * + * @param i: the indexed of the point to be set. + * @param p: A Point object used to provide coordinate values. + */ +void Polygon::setPoint(size_t i, const Point &p) +{ + setPoint(i, p.x(), p.y()); +} + +void Polygon::_draw(const Color &col, float size) const +{ + if (_fill) + ksplot_draw_polygon(_points, _nPoints, + col.color_c_ptr(), + size); + else + ksplot_draw_polygon_contour(_points, _nPoints, + col.color_c_ptr(), + size); +} + +/** + * @brief Create a default Mark. + */ +Mark::Mark() +{ + _visible = false; + _cpu._color = Color(225, 255, 100); + _cpu._size = 5.5f; + _task._color = Color(0, 255, 0); + _task._size = 5.5f; +} + +void Mark::_draw(const Color &col, float size) const +{ + drawLine(_a, _b, col, size); + _cpu.draw(); + _task.draw(); +} + +/** + * @brief Set the device pixel ratio. + * + * @param dpr: device pixel ratio value. + */ +void Mark::setDPR(int dpr) +{ + _size = 1.5 * dpr; + _task._size = _cpu._size = 1.5 + 4.0 * dpr; +} + +/** + * @brief Set the X coordinate (horizontal) of the Mark. + * + * @param x: X coordinate of the Makr in pixels. + */ +void Mark::setX(int x) +{ + _a.setX(x); + _b.setX(x); + _cpu.setX(x); + _task.setX(x); +} + +/** + * @brief Set the Y coordinates (vertical) of the Mark's finishing points. + * + * @param yA: Y coordinate of the first finishing point of the Mark's line. + * @param yB: Y coordinate of the second finishing point of the Mark's line. + */ +void Mark::setY(int yA, int yB) +{ + _a.setY(yA); + _b.setY(yB); +} + +/** + * @brief Set the Y coordinates (vertical) of the Mark's CPU points. + * + * @param yCPU: Y coordinate of the Mark's CPU point. + */ +void Mark::setCPUY(int yCPU) +{ + _cpu.setY(yCPU); +} + +/** + * @brief Set the visiblity of the Mark's CPU points. + * + * @param v: If True, the CPU point will be visible. + */ +void Mark::setCPUVisible(bool v) +{ + _cpu._visible = v; +} + +/** + * @brief Set the Y coordinates (vertical) of the Mark's Task points. + * + * @param yTask: Y coordinate of the Mark's Task point. + */ +void Mark::setTaskY(int yTask) +{ + _task.setY(yTask); +} + +/** + * @brief Set the visiblity of the Mark's Task points. + * + * @param v: If True, the Task point will be visible. + */ +void Mark::setTaskVisible(bool v) +{ + _task._visible = v; +} + +/** + * @brief Create a default Bin. + */ +Bin::Bin() +: _pidFront(KS_EMPTY_BIN), + _pidBack(KS_EMPTY_BIN) +{} + +void Bin::_draw(const Color &col, float size) const +{ + drawLine(_base, _val, col, size); +} + +/** + * @brief Draw only the "val" Point og the Bin. + * + * @param size: The size of the point. + */ +void Bin::drawVal(float size) +{ + _val._size = size; + _val.draw(); +} + +/** + * @brief Create a default (empty) Graph. + */ +Graph::Graph() +: _histoPtr(nullptr), + _bins(nullptr), + _size(0), + _hMargin(30), + _collectionPtr(nullptr), + _pidColors(nullptr) +{} + +/** + * @brief Create a Graph to represent the state of the Vis. model. + * + * @param histo: Input location for the model descriptor. + * @param ct: Input location for the Hash table of Task's colors. + */ +Graph::Graph(kshark_trace_histo *histo, KsPlot::ColorTable *ct) +: _histoPtr(histo), + _bins(new Bin[histo->n_bins]), + _size(histo->n_bins), + _hMargin(30), + _collectionPtr(nullptr), + _pidColors(ct) +{ + if (!_bins) { + _size = 0; + fprintf(stderr, "Failed to allocate memory graph's bins.\n"); + } + + _initBins(); +} + +/** + * @brief Destroy the Graph object. + */ +Graph::~Graph() +{ + delete[] _bins; +} + +void Graph::_initBins() +{ + for (int i = 0; i < _size; ++i) { + _bins[i]._base.setX(i + _hMargin); + _bins[i]._base.setY(0); + _bins[i]._val.setX(_bins[i]._base.x()); + _bins[i]._val.setY(_bins[i]._base.y()); + } +} + +/** + * Get the number of bins. + */ +int Graph::size() +{ + return _size; +} + +/** + * @brief Reinitialize the Graph according to the Vis. model. + * + * @param histo: Input location for the model descriptor. + */ +void Graph::setModelPtr(kshark_trace_histo *histo) +{ + if (_size != histo->n_bins) { + delete[] _bins; + _size = histo->n_bins; + _bins = new Bin[_size]; + if (!_bins) { + _size = 0; + fprintf(stderr, + "Failed to allocate memory graph's bins.\n"); + } + } + + _histoPtr = histo; + _initBins(); +} + +/** + * @brief This function will set the Y (vertical) coordinate of the Graph's + * base. It is safe to use this function even if the Graph contains + * data. + * + * @param b: Y coordinate of the Graph's base in pixels. + */ +void Graph::setBase(int b) +{ + int mod; + + if (!_size) + return; + + if (b == _bins[0]._base.y()) // Nothing to do. + return; + + for (int i = 0; i < _size; ++i) { + mod = _bins[i].mod(); + _bins[i]._base.setY(b); + _bins[i]._val.setY(b + mod); + } +} + +/** + * @brief Set the vertical size (height) of the Graph. + * + * @param h: the height of the Graph in pixels. + */ +void Graph::setHeight(int h) +{ + _height = h; +} + +/** + * @brief Set the size of the white space added on both sides of the Graph. + * + * @param hMargin: the size of the white space in pixels. + */ +void Graph::setHMargin(int hMargin) +{ + if (!_size) + return; + + if (hMargin == _bins[0]._base.x()) // Nothing to do. + return; + + for (int i = 0; i < _size; ++i) { + _bins[i]._base.setX(i + hMargin); + _bins[i]._val.setX(_bins[i]._base.x()); + } + + _hMargin = hMargin; +} + +/** + * @brief Set the value of a given bin. + * + * @param bin: Bin Id. + * @param val: Bin height in pixels. + */ +void Graph::setBinValue(int bin, int val) +{ + _bins[bin].setVal(val); +} + +/** + * @brief Set the Process Id (Front and Back) a given bin. + * + * @param bin: Bin Id. + * @param pidF: The Process Id detected at the from (first in time) edge of + * the bin. + * @param pidB: The Process Id detected at the back (last in time) edge of + * the bin. + */ +void Graph::setBinPid(int bin, int pidF, int pidB) +{ + _bins[bin]._pidFront = pidF; + _bins[bin]._pidBack = pidB; +} + +/** + * @brief Set the color of a given bin. + * + * @param bin: Bin Id. + * @param col: the color of the bin. + */ +void Graph::setBinColor(int bin, const Color &col) +{ + _bins[bin]._color = col; +} + +/** + * @brief Set the visiblity mask of a given bin. + * + * @param bin: Bin Id. + * @param m: the visiblity mask. + */ +void Graph::setBinVisMask(int bin, uint8_t m) +{ + _bins[bin]._visMask = m; +} + +/** + * @brief Set all fields of a given bin. + * + * @param bin: Bin Id. + * @param pidF: The Process Id detected at the from (first in time) edge of + * the bin. + * @param pidB: The Process Id detected at the back (last in time) edge of + * the bin. + * @param col: the color of the bin. + * @param m: the visiblity mask. + */ +void Graph::setBin(int bin, int pidF, int pidB, const Color &col, uint8_t m) +{ + setBinPid(bin, pidF, pidB); + setBinValue(bin, _height * .7); + setBinColor(bin, col); + setBinVisMask(bin, m); +} + +/** + * @brief Process a CPU Graph. + * + * @param cpu: The CPU core. + */ +void Graph::fillCPUGraph(int cpu) +{ + struct kshark_entry *eFront; + int pidFront(0), pidBack(0); + int pidBackNoFilter; + uint8_t visMask; + ssize_t index; + int bin; + + auto get_pid = [&] (int bin) + { + eFront = nullptr; + + pidFront = ksmodel_get_pid_front(_histoPtr, bin, + cpu, + true, + _collectionPtr, + &index); + + if (index >= 0) + eFront = _histoPtr->data[index]; + + pidBack = ksmodel_get_pid_back(_histoPtr, bin, + cpu, + true, + _collectionPtr, + nullptr); + + if (_collectionPtr && _collectionPtr->size) { + pidBackNoFilter = + ksmodel_get_pid_back(_histoPtr, bin, + cpu, + false, + _collectionPtr, + nullptr); + + if (pidBack != pidBackNoFilter) + pidBack = KS_FILTERED_BIN; + } + + visMask = 0x0; + if (ksmodel_cpu_visible_event_exist(_histoPtr, bin, + cpu, + _collectionPtr, + &index)) + + visMask = _histoPtr->data[index]->visible; + else if (eFront) + visMask = eFront->visible; + }; + + auto set_bin = [&] (int bin) + { + if (pidFront != KS_EMPTY_BIN || pidBack != KS_EMPTY_BIN) { + /* This is a regular process. */ + setBin(bin, pidFront, pidBack, + getPidColor(_pidColors, pidFront), visMask); + } else { + /* + * The bin contens no data from this Cpu or the data + * has been filtered. Whene the graph is ploter the + * Process Id of the bin will be derived from the + * previous bin. + */ + setBinPid(bin, KS_EMPTY_BIN, KS_EMPTY_BIN); + } + }; + + /* + * Check the content of the very firs bin and see if the Cpu is + * active. + */ + bin = 0; + get_pid(bin); + if (pidFront >= 0) { + /* + * The Cpu is active and this is a regular process. + * Set this bin. + */ + set_bin(bin); + } else { + /* + * No data from this Cpu in the very firs bin. Use the Lower + * Overflow Bin to retrieve the Process Id (if any). First + * get the Pid back, ignoring the filters. + */ + pidBackNoFilter = ksmodel_get_pid_back(_histoPtr, + LOWER_OVERFLOW_BIN, + cpu, + false, + _collectionPtr, + nullptr); + + /* Now get the Pid back, applying filters. */ + pidBack = ksmodel_get_pid_back(_histoPtr, + LOWER_OVERFLOW_BIN, + cpu, + true, + _collectionPtr, + nullptr); + + if (pidBack != pidBackNoFilter) { + /* The Lower Overflow Bin ends with filtered data. */ + setBinPid(bin, KS_FILTERED_BIN, KS_FILTERED_BIN); + } else { + /* + * The Lower Overflow Bin ends with data which has + * to be plotted. + */ + setBinPid(bin, pidBack, pidBack); + } + } + + /* + * The first bin is already processed. The loop starts from the second + * bin. + */ + for (bin = 1; bin < _histoPtr->n_bins; ++bin) { + /* + * Check the content of this bin and see if the Cpu is active. + * If yes, retrieve the Process Id. If not, derive from the + * previous bin. + */ + get_pid(bin); + set_bin(bin); + } +} + +/** + * @brief Process a Task Graph. + * + * @param pid: The Process Id of the Task. + */ +void Graph::fillTaskGraph(int pid) +{ + int cpu, pidFront(0), pidBack(0), lastCpu(-1), bin(0); + uint8_t visMask; + ssize_t index; + + auto set_bin = [&] (int bin) + { + if (cpu >= 0) { + KsPlot::Color col; + col.setRainbowColor(cpu); + + /* Data from the Task has been found in this bin. */ + if (pid == pidFront && pid == pidBack) { + /* No data from other tasks in this bin. */ + setBin(bin, pid, pid, col, visMask); + } else if (pid != pidFront && pid != pidBack) { + /* + * There is some data from another tasks at + * both front and back sides of this bin. But + * we still want to see this bin drawn. + */ + setBin(bin, pid, KS_FILTERED_BIN, col, + visMask); + } else { + if (pidFront != pid) { + /* + * There is some data from another + * task at the front side of this bin. + */ + pidFront = KS_FILTERED_BIN; + } + + if (pidBack != pid) { + /* + * There is some data from another + * task at the back side of this bin. + */ + pidBack = KS_FILTERED_BIN; + } + + setBin(bin, pidFront, pidBack, col, visMask); + } + + lastCpu = cpu; + } else { + /* + * No data from the Task in this bin. Check the Cpu, + * previously used by the task. + */ + int cpuPid = ksmodel_get_pid_back(_histoPtr, + bin, + lastCpu, + false, + _collectionPtr, + nullptr); + + if (cpuPid != KS_EMPTY_BIN) { + /* + * If the Cpu is active and works on another + * task break the graph here. + */ + setBinPid(bin, KS_FILTERED_BIN, KS_EMPTY_BIN); + } else { + /* + * No data from this Cpu in the bin. + * Continue the graph. + */ + setBinPid(bin, KS_EMPTY_BIN, KS_EMPTY_BIN); + } + } + }; + + auto get_pid_cpu = [&] (int bin) + { + /* Get the CPU used by this task. */ + cpu = ksmodel_get_cpu_front(_histoPtr, bin, + pid, + false, + _collectionPtr, + nullptr); + + if (cpu < 0) { + pidFront = pidBack = cpu; + } else { + /* + * Get the process Id at the begining and at the end + * of the bin. + */ + pidFront = ksmodel_get_pid_front(_histoPtr, + bin, + cpu, + false, + _collectionPtr, + nullptr); + + pidBack = ksmodel_get_pid_back(_histoPtr, + bin, + cpu, + false, + _collectionPtr, + nullptr); + + visMask = 0x0; + if (ksmodel_task_visible_event_exist(_histoPtr, + bin, + pid, + _collectionPtr, + &index)) { + visMask = _histoPtr->data[index]->visible; + } + } + }; + + /* + * Check the content of the very firs bin and see if the Task is + * active. + */ + get_pid_cpu(bin); + + if (cpu >= 0) { + /* The Task is active. Set this bin. */ + set_bin(bin); + } else { + /* + * No data from this Task in the very firs bin. Use the Lower + * Overflow Bin to retrieve the Cpu used by the task (if any). + */ + cpu = ksmodel_get_cpu_back(_histoPtr, LOWER_OVERFLOW_BIN, pid, + false, _collectionPtr, nullptr); + if (cpu >= 0) { + /* + * The Lower Overflow Bin contains data from this Task. + * Now look again in the Lower Overflow Bin and find + * the Pid of the last active task on the same Cpu. + */ + int pidCpu = ksmodel_get_pid_back(_histoPtr, + LOWER_OVERFLOW_BIN, + cpu, + false, + _collectionPtr, + nullptr); + if (pidCpu == pid) { + /* + * The Task is the last one running on this + * Cpu. Set the Pid of the bin. In this case + * the very firs bin is empty but we derive + * the Process Id from the Lower Overflow Bin. + */ + setBinPid(bin, pid, pid); + lastCpu = cpu; + } + } + } + + /* + * The first bin is already processed. The loop starts from the second + * bin. + */ + for (bin = 1; bin < _histoPtr->n_bins; ++bin) { + get_pid_cpu(bin); + + /* Set the bin accordingly. */ + set_bin(bin); + } +} + +/** + * @brief Draw the Graph + * + * @param size: The size of the lines of the individual Bins. + */ +void Graph::draw(float size) +{ + int lastPid(0), b(0), boxH(_height * .3); + Rectangle taskBox; + + /* + * Start by drawing a line between the base points of the first and + * the last bin. + */ + drawLine(_bins[0]._base, _bins[_size - 1]._base, {}, size); + + /* Draw as vartical lines all bins containing data. */ + for (int i = 0; i < _size; ++i) + if (_bins[i]._pidFront >= 0 || _bins[i]._pidBack >= 0) + if (_bins[i]._visMask & KS_EVENT_VIEW_FILTER_MASK) + _bins[i].draw(); + + /* + * Draw colored boxes for processes. First find the first bin, which + * contains data and determine its PID. + */ + for (; b < _size; ++b) { + if (_bins[b]._pidBack > 0) { + lastPid = _bins[b]._pidFront; + /* + * Initialize a box starting from this bin. + * The color of the taskBox corresponds to the Pid + * of the process. + */ + taskBox._color = getPidColor(_pidColors, lastPid); + taskBox.setPoint(0, _bins[b]._base.x(), + _bins[b]._base.y() - boxH); + taskBox.setPoint(1, _bins[b]._base.x(), + _bins[b]._base.y()); + break; + } + } + + for (; b < _size; ++b) { + if (_bins[b]._pidFront == KS_EMPTY_BIN && + _bins[b]._pidBack == KS_EMPTY_BIN) { + /* + * This bin is empty. If a colored taskBox is already + * initialized, it will be extended. + */ + continue; + } + + if (_bins[b]._pidFront != _bins[b]._pidBack || + _bins[b]._pidFront != lastPid || + _bins[b]._pidBack != lastPid) { + /* A new process starts here. */ + if (lastPid > 0 && b > 0) { + /* + * There is another process running up to this + * point. Close its colored box here and draw. + */ + taskBox.setPoint(3, _bins[b]._base.x() - 1, + _bins[b]._base.y() - boxH); + taskBox.setPoint(2, _bins[b]._base.x() - 1, + _bins[b]._base.y()); + taskBox.draw(); + } + + if (_bins[b]._pidBack > 0) { + /* + * This is a regular process. Initialize + * colored box starting from this bin. + */ + taskBox._color = getPidColor(_pidColors, + _bins[b]._pidBack); + + taskBox.setPoint(0, _bins[b]._base.x() - 1, + _bins[b]._base.y() - boxH); + taskBox.setPoint(1, _bins[b]._base.x() - 1, + _bins[b]._base.y()); + } + + lastPid = _bins[b]._pidBack; + } + } + + if (lastPid > 0) { + /* + * This is the end of the Graph and we have a process running. + * Close its colored box and draw. + */ + taskBox.setPoint(3, _bins[_size - 1]._base.x(), + _bins[_size - 1]._base.y() - boxH); + taskBox.setPoint(2, _bins[_size - 1]._base.x(), + _bins[_size - 1]._base.y()); + taskBox.draw(); + } +} + +}; // KsPlot diff --git a/kernel-shark-qt/src/KsPlotTools.hpp b/kernel-shark-qt/src/KsPlotTools.hpp new file mode 100644 index 0000000..0243cf3 --- /dev/null +++ b/kernel-shark-qt/src/KsPlotTools.hpp @@ -0,0 +1,440 @@ +/* SPDX-License-Identifier: LGPL-2.1 */ + +/* + * Copyright (C) 2017 VMware Inc, Yordan Karadzhov + */ + + /** + * @file KsPlotTools.hpp + * @brief KernelShark Plot tools. + */ + +#ifndef _KS_PLOT_TOOLS_H +#define _KS_PLOT_TOOLS_H + +// C++ +#include + +// KernelShark +#include "libkshark.h" +#include "libkshark-plot.h" +#include "libkshark-model.h" + +namespace KsPlot { + +/** This class represents a RGB color. */ +class Color { +public: + Color(); + + Color(uint8_t r, uint8_t g, uint8_t b); + + Color(int rgb); + + /** @brief Get the Red coordinate of the color. */ + uint8_t r() const {return _col_c.red;} + + /** @brief Get the Green coordinate of the color. */ + uint8_t g() const {return _col_c.green;} + + /** @brief Get the Blue coordinate of the color. */ + uint8_t b() const {return _col_c.blue;} + + void set(uint8_t r, uint8_t g, uint8_t b); + + void set(int rgb); + + void setRainbowColor(int n); + + /** + * @brief Get the C struct defining the RGB color. + */ + const ksplot_color *color_c_ptr() const {return &_col_c;} + + /** + * @brief Set the frequency value used to generate the Rainbow + * palette. + */ + static void setRainbowFrequency(float f) {_frequency = f;} + + /** + * @brief Get the frequency value used to generate the Rainbow + * palette. + */ + static float getRainbowFrequency() {return _frequency;} + +private: + ksplot_color _col_c; + + /** The frequency value used to generate the Rainbow palette. */ + static float _frequency; +}; + +/** Hash table of colors. */ +typedef std::unordered_map ColorTable; + +ColorTable getColorTable(); + +Color getPidColor(ColorTable *colors, int pid); + +/** Represents an abstract shape. */ +class Shape { +public: + Shape() : _visible(true), _size(2.) {} + + /** + * @brief Destroy the Line object. Keep this destructor virtual. + */ + virtual ~Shape() {} + + /** Generic function used to draw different shapes. */ + void draw() const { + if (_visible) + _draw(_color, _size); + } + + /** Is this shape visible. */ + bool _visible; + + /** The color of the shape. */ + Color _color; + + /** The size of the shape. */ + float _size; + +private: + virtual void _draw(const Color &col, float s) const = 0; +}; + +/** This class represents a 2D poin. */ +class Point : public Shape { +public: + Point(); + + Point(int x, int y); + + /** + * @brief Destroy the Line object. Keep this destructor virtual. + */ + virtual ~Point() {} + + /** @brief Get the horizontal coordinate of the point. */ + int x() const {return _point_c.x;} + + /** @brief Get the vertical coordinate of the point. */ + int y() const {return _point_c.y;} + + /** @brief Set the horizontal coordinate of the point. */ + void setX(int x) {_point_c.x = x;} + + /** @brief Set the vertical coordinate of the point. */ + void setY(int y) {_point_c.y = y;} + + /** + * @brief Set the coordinats of the point. + * + * @param x: horizontal coordinate of the point in pixels. + * @param y: vertical coordinate of the point in pixels. + */ + void set(int x, int y) { + _point_c.x = x; + _point_c.y = y; + } + + /** + * @brief Get the C struct defining the point. + */ + const ksplot_point *point_c_ptr() const {return &_point_c;} + +private: + /** The coordinates in pixels. */ + ksplot_point _point_c; + + void _draw(const Color &col, float size = 1.) const override; +}; + +void drawLine(const Point &a, const Point &b, + const Color &col, float s); + +/** This class represents a straight line. */ +class Line : public Shape { +public: + Line(); + + Line(const Point &a, const Point &b); + + /** + * @brief Destroy the Line object. Keep this destructor virtual. + */ + virtual ~Line() {} + + /** + * @brief Set the coordinats of point A. + * + * @param x: horizontal coordinate of the point in pixels. + * @param y: vertical coordinate of the point in pixels. + */ + void setA(int x, int y) { + _a.x = x; + _a.y = y; + } + + /** + * @brief Set the coordinats of point B. + * + * @param x: horizontal coordinate of the point in pixels. + * @param y: vertical coordinate of the point in pixels. + */ + void setB(int x, int y) { + _b.x = x; + _b.y = y; + } + + /** + * First finishing point of the line. + */ + ksplot_point _a; + + /** + *Second finishing point of the line. + */ + ksplot_point _b; + +private: + void _draw(const Color &col, float size = 1.) const override; +}; + +/** This class represents a polygon. */ +class Polygon : public Shape { +public: + Polygon(size_t n); + + /* Disable copying. */ + Polygon(const Polygon &) = delete; + + /* Disable moving. */ + Polygon(Polygon &&) = delete; + + virtual ~Polygon(); + + void setPoint(size_t i, int x, int y); + + void setPoint(size_t i, const Point &p); + + /** + * @brief Specify the way the polygon will be drawn. + * + * @param f: If True, the area of the polygon will be colored. + * Otherwise only the contour of the polygon will be plotted. + */ + void setFill(bool f) {_fill = f;} + + /** + * @brief Get the number of point used to define the polygon. + */ + size_t pointCount() const {return _nPoints;} + +private: + Polygon() = delete; + + void _draw(const Color &, float size = 1.) const override; + + /** The number of point used to define the polygon. */ + size_t _nPoints; + + /** The array of point used to define the polygon. */ + ksplot_point *_points; + + /** + * If True, the area of the polygon will be colored. Otherwise only + * the contour of the polygon will be plotted. + */ + bool _fill; +}; + +/** This class represents a triangle. */ +class Triangle : public Polygon { +public: + Triangle() : Polygon(3) {} +}; + +/** This class represents a rectangle. */ +class Rectangle : public Polygon { +public: + Rectangle() : Polygon(4) {} +}; + +/** + * This class represents the graphical element of the KernelShark GUI marker. + */ +class Mark : public Shape { +public: + Mark(); + + /** + * @brief Destroy the Mark object. Keep this destructor virtual. + */ + virtual ~Mark() {} + + void setDPR(int dpr); + + void setX(int x); + + void setY(int yA, int yB); + + void setCPUY(int yCPU); + + void setCPUVisible(bool v); + + void setTaskY(int yTask); + + void setTaskVisible(bool v); + +private: + void _draw(const Color &col, float size = 1.) const override; + + /** First finishing point of the Mark's line. */ + Point _a; + + /** Second finishing point of the Mark's line. */ + Point _b; + + /** A point indicating the position of the Mark in a CPU graph. */ + Point _cpu; + + /** A point indicating the position of the Mark in a Task graph. */ + Point _task; +}; + +/** This class represents a KernelShark graph's bin. */ +class Bin : public Shape { +public: + Bin(); + + void drawVal(float size = 2.); + + /** Get the height (module) of the line, representing the Bin. */ + int mod() {return _val.y() - _base.y();} + + /** @brief Set the vertical coordinate of the "val" Point. */ + void setVal(int v) {_val.setY(_base.y() - v); } + + /** + * The Process Id detected at the front (first in time) edge of + * the bin. + */ + int _pidFront; + + /** + * The Process Id detected at the back (last in time) edge of + * the bin. + */ + int _pidBack; + + /** + * Lower finishing point of the line, representing the Bin. + */ + Point _base; + + /** + * Upper finishing point of the line, representing the Bin. + */ + Point _val; + + /** A bit mask controlling the visibility of the Bin. */ + uint8_t _visMask; + +private: + void _draw(const Color &col, float size = 1.) const override; +}; + +/** This class represents a KernelShark graph. */ +class Graph { +public: + Graph(); + + /* Disable copying. */ + Graph(const Graph &) = delete; + + /* Disable moving. */ + Graph(Graph &&) = delete; + + Graph(kshark_trace_histo *histo, KsPlot::ColorTable *ct); + + ~Graph(); + + int size(); + + void setModelPtr(kshark_trace_histo *histo); + + /** + * @brief Provide the Graph with a Data Collection. The collection + * will be used to optimise the processing of the content of + * the bins. + * + * @param col: Input location for the data collection descriptor. + */ + void setDataCollectionPtr(kshark_entry_collection *col) { + _collectionPtr = col; + } + + /** @brief Set the Hash table of Task's colors. */ + void setColorTablePtr(KsPlot::ColorTable *ct) {_pidColors = ct;} + + void fillCPUGraph(int cpu); + + void fillTaskGraph(int pid); + + void draw(float s = 1); + + void setBase(int b); + + /** @brief Get the vertical coordinate of the Graph's base. */ + int getBase() const {return _bins[0]._base.y();} + + void setHeight(int h); + + void setBinValue(int bin, int val); + + void setBinPid(int bin, int pidF, int pidB); + + void setBinColor(int bin, const Color &col); + + void setBinVisMask(int bin, uint8_t m); + + void setBin(int bin, int pidF, int pidB, + const Color &col, uint8_t m); + + void setHMargin(int hMargin); + +private: + /** Pointer to the model descriptor object. */ + kshark_trace_histo *_histoPtr; + + /** An array of Bins. */ + Bin *_bins; + + /** The number of Bins. */ + int _size; + + /** + * The size (in pixels) of the white space added on both sides of + * the Graph. + */ + int _hMargin; + + /** The vertical size (height) of the Graph. */ + int _height; + + /** Pointer to the data collection object. */ + kshark_entry_collection *_collectionPtr; + + /** Hash table of Task's colors. */ + ColorTable *_pidColors; + + void _initBins(); +}; + +}; // KsPlot + +#endif /* _KS_PLOT_TOOLS_H */ From patchwork Wed Aug 22 15:41:39 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yordan Karadzhov X-Patchwork-Id: 10759139 Return-Path: Received: from mail-wr1-f68.google.com ([209.85.221.68]:35833 "EHLO mail-wr1-f68.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729208AbeHVTHl (ORCPT ); Wed, 22 Aug 2018 15:07:41 -0400 Received: by mail-wr1-f68.google.com with SMTP id j26-v6so2005618wre.2 for ; Wed, 22 Aug 2018 08:42:16 -0700 (PDT) From: "Yordan Karadzhov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org, "Yordan Karadzhov (VMware)" Subject: [PATCH 4/5] kernel-shark-qt: Add an example showing how to draw shapes and Graphs. Date: Wed, 22 Aug 2018 18:41:39 +0300 Message-Id: <20180822154140.3748-5-y.karadz@gmail.com> In-Reply-To: <20180822154140.3748-1-y.karadz@gmail.com> References: <20180822154140.3748-1-y.karadz@gmail.com> Sender: linux-trace-devel-owner@vger.kernel.org List-ID: Content-Length: 5723 This patch introduces a basic example, showing how to initialize OpenGL and how to use the C++ API in order to draw simple shapes or to show animated Graphs. Signed-off-by: Yordan Karadzhov (VMware) --- kernel-shark-qt/examples/CMakeLists.txt | 4 + kernel-shark-qt/examples/dataplot.cpp | 213 ++++++++++++++++++++++++ 2 files changed, 217 insertions(+) create mode 100644 kernel-shark-qt/examples/dataplot.cpp diff --git a/kernel-shark-qt/examples/CMakeLists.txt b/kernel-shark-qt/examples/CMakeLists.txt index a3745fa..0c83293 100644 --- a/kernel-shark-qt/examples/CMakeLists.txt +++ b/kernel-shark-qt/examples/CMakeLists.txt @@ -15,3 +15,7 @@ target_link_libraries(dhisto kshark) message(STATUS "confogio") add_executable(confio configio.c) target_link_libraries(confio kshark) + +message(STATUS "dataplot") +add_executable(dplot dataplot.cpp) +target_link_libraries(dplot kshark-plot) diff --git a/kernel-shark-qt/examples/dataplot.cpp b/kernel-shark-qt/examples/dataplot.cpp new file mode 100644 index 0000000..9c1eeca --- /dev/null +++ b/kernel-shark-qt/examples/dataplot.cpp @@ -0,0 +1,213 @@ +// SPDX-License-Identifier: GPL-2.0 + +/* + * Copyright (C) 2018 VMware Inc, Yordan Karadzhov + */ + +// C +#include +#include +#include +#include + +// C++ +#include + +// OpenGL +#include + +// KernelShark +#include "libkshark.h" +#include "KsPlotTools.hpp" + +using namespace std; + +#define GRAPH_HEIGHT 40 // width of the graph in pixels +#define GRAPH_H_MARGIN 50 // size of the white space surrounding the graph +#define WINDOW_WIDTH 800 // width of the screen window in pixels +#define WINDOW_HEIGHT 480 // height of the scrren window in pixels + +#define default_file (char*)"trace.dat" + +struct kshark_trace_histo histo; +vector graphs; + +/* An example function drawing something. */ +void drawShapes() +{ + /* Clear the screen. */ + glClear(GL_COLOR_BUFFER_BIT); + + KsPlot::Triangle t; + KsPlot::Point a(200, 100), b(200, 300), c(400, 100); + t.setPoint(0, a); + t.setPoint(1, b); + t.setPoint(2, c); + + /* Set RGB color. */ + t._color = {100, 200, 50}; + t.draw(); + + KsPlot::Rectangle r; + KsPlot::Point d(400, 200), e(400, 300), f(500, 300), g(500, 200); + r.setPoint(0, d); + r.setPoint(1, e); + r.setPoint(2, f); + r.setPoint(3, g); + + /* Set RGB color. */ + r._color = {150, 50, 250}; + + /** Do not fiil the rectangle. Draw the contour only. */ + r.setFill(false); + r.draw(); + + glFlush(); +} + +/* An example function demonstrating Zoom In and Zoom Out. */ +void play() +{ + KsPlot::ColorTable colors = KsPlot::getColorTable(); + vector CPUs, Tasks; + KsPlot::Graph *graph; + bool zoom_in(true); + + CPUs = {3, 4, 6}; + Tasks = {}; // Add valid pids here, if you want task plots. + + auto init_graph = [&graph, &colors] (int i) { + int base; + + /* Make a new Graph. */ + graph = new KsPlot::Graph(&histo, &colors); + + /* Set the dimensions of the Graph. */ + graph->setHeight(GRAPH_HEIGHT); + graph->setHMargin(GRAPH_H_MARGIN); + + /* + * Set the Y coordinate of the Graph's base. + * Remember that the "Y" coordinate is inverted. + */ + base = 1.7 * GRAPH_HEIGHT * (i + 1); + graph->setBase(base); + + /* Add the Graph. */ + graphs.push_back(graph); + }; + + for (size_t i = 0; i < CPUs.size() + Tasks.size(); ++i) + init_graph(i); + + auto draw_graphs = [&CPUs, &Tasks] () { + vector::iterator it = graphs.begin(); + + for (int const &cpu: CPUs) + (*it++)->fillCPUGraph(cpu); + + for (int const &pid: Tasks) + (*it++)->fillTaskGraph(pid); + + /* Clear the screen. */ + glClear(GL_COLOR_BUFFER_BIT); + + /* Draw all graphs. */ + for (auto &g: graphs) + g->draw(); + + glFlush(); + }; + + for (int i = 1; i < 1000; ++i) { + if (!(i % 250)) + zoom_in = !zoom_in; + + draw_graphs(); + + if (zoom_in) + ksmodel_zoom_in(&histo, .01, -1); + else + ksmodel_zoom_out(&histo, .01, -1); + } +} + +int main(int argc, char **argv) +{ + struct kshark_context *kshark_ctx(nullptr); + struct kshark_entry **data(nullptr); + static char *input_file; + bool status, shapes(false); + size_t r, n_rows; + int c, nBins; + + while ((c = getopt(argc, argv, "si")) != -1) { + switch(c) { + case 'i': + input_file = optarg; + break; + case 's': + shapes = true; + + default: + break; + } + } + + /* Create a new kshark session. */ + if (!kshark_instance(&kshark_ctx)) + return 1; + + /* Open a trace data file produced by trace-cmd. */ + if (input_file) + status = kshark_open(kshark_ctx, input_file); + else + status = kshark_open(kshark_ctx, default_file); + + if (!status) { + kshark_free(kshark_ctx); + return 1; + } + + /* Load the content of the file into an array of entries. */ + n_rows = kshark_load_data_entries(kshark_ctx, &data); + + /* Initialize the Visualization Model. */ + ksmodel_init(&histo); + + nBins = WINDOW_WIDTH - 2 * GRAPH_HEIGHT; + ksmodel_set_bining(&histo, nBins, data[0]->ts, + data[n_rows - 1]->ts); + + /* Fill the model with data and calculate its state. */ + ksmodel_fill(&histo, data, n_rows); + + /* Initialize OpenGL/Glut. */ + glutInit(&argc, argv); + ksplot_make_scene(WINDOW_WIDTH, WINDOW_HEIGHT); + ksplot_init_opengl(1); + + /* Display something. */ + if (shapes) + glutDisplayFunc(drawShapes); + else + glutDisplayFunc(play); + + glutMainLoop(); + + /* Free the memory. */ + for (auto &g: graphs) + delete g; + + for (r = 0; r < n_rows; ++r) + free(data[r]); + free(data); + + /* Close the file. */ + kshark_close(kshark_ctx); + + /* Close the session. */ + kshark_free(kshark_ctx); + + return 0; +} From patchwork Wed Aug 22 15:41:40 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yordan Karadzhov X-Patchwork-Id: 10759137 Return-Path: Received: from mail-wr1-f65.google.com ([209.85.221.65]:35834 "EHLO mail-wr1-f65.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729208AbeHVTHm (ORCPT ); Wed, 22 Aug 2018 15:07:42 -0400 Received: by mail-wr1-f65.google.com with SMTP id j26-v6so2005729wre.2 for ; Wed, 22 Aug 2018 08:42:18 -0700 (PDT) From: "Yordan Karadzhov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org, "Yordan Karadzhov (VMware)" Subject: [PATCH 5/5] kernel-shark-qt: Version 0.8.0 Date: Wed, 22 Aug 2018 18:41:40 +0300 Message-Id: <20180822154140.3748-6-y.karadz@gmail.com> In-Reply-To: <20180822154140.3748-1-y.karadz@gmail.com> References: <20180822154140.3748-1-y.karadz@gmail.com> Sender: linux-trace-devel-owner@vger.kernel.org List-ID: Signed-off-by: Yordan Karadzhov (VMware) --- kernel-shark-qt/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel-shark-qt/CMakeLists.txt b/kernel-shark-qt/CMakeLists.txt index 0187eb4..793a63b 100644 --- a/kernel-shark-qt/CMakeLists.txt +++ b/kernel-shark-qt/CMakeLists.txt @@ -5,8 +5,8 @@ cmake_minimum_required(VERSION 2.8.11 FATAL_ERROR) project(kernel-shark-qt) set(KS_VERSION_MAJOR 0) -set(KS_VERSION_MINOR 7) -set(KS_VERSION_PATCH 1) +set(KS_VERSION_MINOR 8) +set(KS_VERSION_PATCH 0) set(KS_VERSION_STRING ${KS_VERSION_MAJOR}.${KS_VERSION_MINOR}.${KS_VERSION_PATCH}) message("\n project: Kernel Shark: (version: ${KS_VERSION_STRING})\n")