linux-trace-devel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/5] Add drawing instrumentation to be used by the Qt-based KernelShark
@ 2018-08-22 15:41 Yordan Karadzhov (VMware)
  2018-08-22 15:41 ` [PATCH 1/5] kernel-shark-qt: Add OpenGL/GLUT as a third party dependency Yordan Karadzhov (VMware)
                   ` (4 more replies)
  0 siblings, 5 replies; 8+ messages in thread
From: Yordan Karadzhov (VMware) @ 2018-08-22 15:41 UTC (permalink / raw)
  To: rostedt; +Cc: linux-trace-devel, Yordan Karadzhov (VMware)

The KernelShark plotting library is introduced in this series of patches.
The library will be used  by the GUI to draw CPU and Task Graphs. This is
also the first time KernelShark enters the world of C++.

Yordan Karadzhov (VMware) (5):
  kernel-shark-qt: Add OpenGL/GLUT as a third party dependency.
  kernel-shark-qt: Add basic instruments for OpenGL plotting.
  kernel-shark-qt: Add C++ API for drawing of Graphs
  kernel-shark-qt: Add an example showing how to draw shapes and Graphs.
  kernel-shark-qt: Version 0.8.0

 kernel-shark-qt/CMakeLists.txt          |    7 +-
 kernel-shark-qt/README                  |    2 +
 kernel-shark-qt/examples/CMakeLists.txt |    4 +
 kernel-shark-qt/examples/dataplot.cpp   |  213 +++++
 kernel-shark-qt/src/CMakeLists.txt      |   14 +
 kernel-shark-qt/src/KsPlotTools.cpp     | 1009 +++++++++++++++++++++++
 kernel-shark-qt/src/KsPlotTools.hpp     |  440 ++++++++++
 kernel-shark-qt/src/libkshark-plot.c    |  212 +++++
 kernel-shark-qt/src/libkshark-plot.h    |   69 ++
 9 files changed, 1968 insertions(+), 2 deletions(-)
 create mode 100644 kernel-shark-qt/examples/dataplot.cpp
 create mode 100644 kernel-shark-qt/src/KsPlotTools.cpp
 create mode 100644 kernel-shark-qt/src/KsPlotTools.hpp
 create mode 100644 kernel-shark-qt/src/libkshark-plot.c
 create mode 100644 kernel-shark-qt/src/libkshark-plot.h

-- 
2.17.1

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH 1/5] kernel-shark-qt: Add OpenGL/GLUT as a third party dependency.
  2018-08-22 15:41 [PATCH 0/5] Add drawing instrumentation to be used by the Qt-based KernelShark Yordan Karadzhov (VMware)
@ 2018-08-22 15:41 ` Yordan Karadzhov (VMware)
  2018-08-22 15:41 ` [PATCH 2/5] kernel-shark-qt: Add basic instruments for OpenGL plotting Yordan Karadzhov (VMware)
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 8+ messages in thread
From: Yordan Karadzhov (VMware) @ 2018-08-22 15:41 UTC (permalink / raw)
  To: rostedt; +Cc: linux-trace-devel, Yordan Karadzhov (VMware)

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) <y.karadz@gmail.com>
---
 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
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 2/5] kernel-shark-qt: Add basic instruments for OpenGL plotting.
  2018-08-22 15:41 [PATCH 0/5] Add drawing instrumentation to be used by the Qt-based KernelShark Yordan Karadzhov (VMware)
  2018-08-22 15:41 ` [PATCH 1/5] kernel-shark-qt: Add OpenGL/GLUT as a third party dependency Yordan Karadzhov (VMware)
@ 2018-08-22 15:41 ` Yordan Karadzhov (VMware)
  2018-08-22 15:41 ` [PATCH 3/5] kernel-shark-qt: Add C++ API for drawing of Graphs Yordan Karadzhov (VMware)
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 8+ messages in thread
From: Yordan Karadzhov (VMware) @ 2018-08-22 15:41 UTC (permalink / raw)
  To: rostedt; +Cc: linux-trace-devel, Yordan Karadzhov (VMware)

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) <y.karadz@gmail.com>
---
 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 <y.karadz@gmail.com>
+ */
+
+ /**
+  *  @file    libkshark-plot.c
+  *  @brief   Basic tools for OpenGL plotting.
+  */
+
+// OpenGL
+#include <GL/freeglut.h>
+#include <GL/gl.h>
+
+// 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 <y.karadz@gmail.com>
+ */
+
+ /**
+  *  @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
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 3/5] kernel-shark-qt: Add C++ API for drawing of Graphs
  2018-08-22 15:41 [PATCH 0/5] Add drawing instrumentation to be used by the Qt-based KernelShark Yordan Karadzhov (VMware)
  2018-08-22 15:41 ` [PATCH 1/5] kernel-shark-qt: Add OpenGL/GLUT as a third party dependency Yordan Karadzhov (VMware)
  2018-08-22 15:41 ` [PATCH 2/5] kernel-shark-qt: Add basic instruments for OpenGL plotting Yordan Karadzhov (VMware)
@ 2018-08-22 15:41 ` Yordan Karadzhov (VMware)
  2018-08-23 20:20   ` Matthew Helsley
  2018-08-22 15:41 ` [PATCH 4/5] kernel-shark-qt: Add an example showing how to draw shapes and Graphs Yordan Karadzhov (VMware)
  2018-08-22 15:41 ` [PATCH 5/5] kernel-shark-qt: Version 0.8.0 Yordan Karadzhov (VMware)
  4 siblings, 1 reply; 8+ messages in thread
From: Yordan Karadzhov (VMware) @ 2018-08-22 15:41 UTC (permalink / raw)
  To: rostedt; +Cc: linux-trace-devel, Yordan Karadzhov (VMware)

This patch extends the KernelShark Plotting library, by adding
a C++ API for drawing CPU and Task Graphs.

Signed-off-by: Yordan Karadzhov (VMware) <y.karadz@gmail.com>
---
 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 <y.karadz@gmail.com>
+ */
+
+/**
+ *  @file    KsPlotTools.cpp
+ *  @brief   KernelShark Plot tools.
+ */
+
+// C
+#include <math.h>
+
+// C++
+#include <algorithm>
+#include <vector>
+
+// OpenGL
+#include <GL/freeglut.h>
+#include <GL/gl.h>
+
+// 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<int> 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 <y.karadz@gmail.com>
+ */
+
+ /**
+ *  @file    KsPlotTools.hpp
+ *  @brief   KernelShark Plot tools.
+ */
+
+#ifndef _KS_PLOT_TOOLS_H
+#define _KS_PLOT_TOOLS_H
+
+// C++
+#include <unordered_map>
+
+// 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<int, KsPlot::Color> 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 */
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 4/5] kernel-shark-qt: Add an example showing how to draw shapes and Graphs.
  2018-08-22 15:41 [PATCH 0/5] Add drawing instrumentation to be used by the Qt-based KernelShark Yordan Karadzhov (VMware)
                   ` (2 preceding siblings ...)
  2018-08-22 15:41 ` [PATCH 3/5] kernel-shark-qt: Add C++ API for drawing of Graphs Yordan Karadzhov (VMware)
@ 2018-08-22 15:41 ` Yordan Karadzhov (VMware)
  2018-08-22 15:41 ` [PATCH 5/5] kernel-shark-qt: Version 0.8.0 Yordan Karadzhov (VMware)
  4 siblings, 0 replies; 8+ messages in thread
From: Yordan Karadzhov (VMware) @ 2018-08-22 15:41 UTC (permalink / raw)
  To: rostedt; +Cc: linux-trace-devel, Yordan Karadzhov (VMware)

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) <y.karadz@gmail.com>
---
 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 <y.karadz@gmail.com>
+ */
+
+// C
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <getopt.h>
+
+// C++
+#include <vector>
+
+// OpenGL
+#include <GL/freeglut.h>
+
+// 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<KsPlot::Graph *>		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<int> 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<KsPlot::Graph *>::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;
+}
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 5/5] kernel-shark-qt: Version 0.8.0
  2018-08-22 15:41 [PATCH 0/5] Add drawing instrumentation to be used by the Qt-based KernelShark Yordan Karadzhov (VMware)
                   ` (3 preceding siblings ...)
  2018-08-22 15:41 ` [PATCH 4/5] kernel-shark-qt: Add an example showing how to draw shapes and Graphs Yordan Karadzhov (VMware)
@ 2018-08-22 15:41 ` Yordan Karadzhov (VMware)
  4 siblings, 0 replies; 8+ messages in thread
From: Yordan Karadzhov (VMware) @ 2018-08-22 15:41 UTC (permalink / raw)
  To: rostedt; +Cc: linux-trace-devel, Yordan Karadzhov (VMware)

Signed-off-by: Yordan Karadzhov (VMware) <y.karadz@gmail.com>
---
 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")
 
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH 3/5] kernel-shark-qt: Add C++ API for drawing of Graphs
  2018-08-22 15:41 ` [PATCH 3/5] kernel-shark-qt: Add C++ API for drawing of Graphs Yordan Karadzhov (VMware)
@ 2018-08-23 20:20   ` Matthew Helsley
  2018-08-24  1:43     ` Steven Rostedt
  0 siblings, 1 reply; 8+ messages in thread
From: Matthew Helsley @ 2018-08-23 20:20 UTC (permalink / raw)
  To: Yordan Karadzhov (VMware)
  Cc: Steven Rostedt, linux-trace-devel@vger.kernel.org



> On Aug 22, 2018, at 8:41 AM, Yordan Karadzhov (VMware) <y.karadz@gmail.com> wrote:
> 
> This patch extends the KernelShark Plotting library, by adding
> a C++ API for drawing CPU and Task Graphs.
> 
> Signed-off-by: Yordan Karadzhov (VMware) <y.karadz@gmail.com>
> ---
> 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 <y.karadz@gmail.com>
> + */
> +
> +/**
> + *  @file    KsPlotTools.cpp
> + *  @brief   KernelShark Plot tools.
> + */
> +
> +// C
> +#include <math.h>
> +
> +// C++
> +#include <algorithm>
> +#include <vector>
> +
> +// OpenGL
> +#include <GL/freeglut.h>
> +#include <GL/gl.h>
> +
> +// 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<int> 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 <y.karadz@gmail.com>
> + */
> +
> + /**
> + *  @file    KsPlotTools.hpp
> + *  @brief   KernelShark Plot tools.
> + */
> +
> +#ifndef _KS_PLOT_TOOLS_H
> +#define _KS_PLOT_TOOLS_H
> +
> +// C++
> +#include <unordered_map>
> +
> +// 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<int, KsPlot::Color> 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 */
> -- 
> 2.17.1
> 

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 3/5] kernel-shark-qt: Add C++ API for drawing of Graphs
  2018-08-23 20:20   ` Matthew Helsley
@ 2018-08-24  1:43     ` Steven Rostedt
  0 siblings, 0 replies; 8+ messages in thread
From: Steven Rostedt @ 2018-08-24  1:43 UTC (permalink / raw)
  To: Matthew Helsley
  Cc: Yordan Karadzhov (VMware), linux-trace-devel@vger.kernel.org


Hi Matt,

Did you expect to reply here?

-- Steve


On Thu, 23 Aug 2018 20:20:20 +0000
Matthew Helsley <mhelsley@vmware.com> wrote:

> > On Aug 22, 2018, at 8:41 AM, Yordan Karadzhov (VMware) <y.karadz@gmail.com> wrote:
> > 
> > This patch extends the KernelShark Plotting library, by adding
> > a C++ API for drawing CPU and Task Graphs.
> > 
> > Signed-off-by: Yordan Karadzhov (VMware) <y.karadz@gmail.com>
> > ---
> > 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

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2018-08-24  5:15 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2018-08-22 15:41 [PATCH 0/5] Add drawing instrumentation to be used by the Qt-based KernelShark Yordan Karadzhov (VMware)
2018-08-22 15:41 ` [PATCH 1/5] kernel-shark-qt: Add OpenGL/GLUT as a third party dependency Yordan Karadzhov (VMware)
2018-08-22 15:41 ` [PATCH 2/5] kernel-shark-qt: Add basic instruments for OpenGL plotting Yordan Karadzhov (VMware)
2018-08-22 15:41 ` [PATCH 3/5] kernel-shark-qt: Add C++ API for drawing of Graphs Yordan Karadzhov (VMware)
2018-08-23 20:20   ` Matthew Helsley
2018-08-24  1:43     ` Steven Rostedt
2018-08-22 15:41 ` [PATCH 4/5] kernel-shark-qt: Add an example showing how to draw shapes and Graphs Yordan Karadzhov (VMware)
2018-08-22 15:41 ` [PATCH 5/5] kernel-shark-qt: Version 0.8.0 Yordan Karadzhov (VMware)

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).