blob: b3ff29ff78526acd0dc4bbbcc4e0e7443e759371 [file] [log] [blame]
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2018 VMware Inc, Yordan Karadzhov <y.karadz@gmail.com>
*/
// C
#include <getopt.h>
// C++
#include <vector>
#include <iostream>
#include <sstream>
// 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 15 // size of the white space surrounding
// the graph
#define GRAPH_LABEL_WIDTH 80 // width of the graph's label in pixels
#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;
struct ksplot_font font;
int stream_id;
void usage(const char *prog)
{
cout << "Usage: " << prog << endl;
cout << " -h Display this help message.\n";
cout << " -s Draw shapes. This demonstrates how to draw simple "
<< "geom. shapes.\n";
cout << " -i <file> Input file and draw animated graphs.\n";
cout << " No args. Import " << default_file
<< " and draw animated graphs.\n";
}
/* 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();
/* Print/draw "Hello Kernel!". */
KsPlot::Color col = {50, 150, 255};
KsPlot::TextBox tb(&font, "Hello Kernel!", col, {250, 70}, 250);
tb.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};
r._size = 3;
/* 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 taskColors = KsPlot::taskColorTable();
KsPlot::ColorTable cpuColors = KsPlot::CPUColorTable();
vector<KsPlot::Graph *>::iterator it;
KsPlot::Graph *graph;
vector<int> CPUs, Tasks;
bool zoomIn(true);
int base;
size_t i(1);
CPUs = {3, 4, 6};
Tasks = {}; // Add valid pids here, if you want task plots.
auto lamAddGraph = [&] (KsPlot::Graph *g) {
/* Set the dimensions of the Graph. */
g->setHeight(GRAPH_HEIGHT);
/*
* Set the Y coordinate of the Graph's base.
* Remember that the "Y" coordinate is inverted.
*/
base = 1.7 * GRAPH_HEIGHT * (i++);
g->setBase(base);
g->setLabelAppearance(&font, {160, 255, 255}, GRAPH_LABEL_WIDTH,
GRAPH_H_MARGIN);
/* Add the Graph. */
graphs.push_back(g);
};
for (auto const &cpu: CPUs) {
std::stringstream ss;
ss << "CPU " << cpu;
graph = new KsPlot::Graph(&histo, &taskColors, &taskColors);
graph->setLabelText(ss.str());
lamAddGraph(graph);
}
for (auto const &pid: Tasks) {
std::stringstream ss;
ss << "PID " << pid;
graph = new KsPlot::Graph(&histo, &taskColors, &cpuColors);
graph->setLabelText(ss.str());
lamAddGraph(graph);
}
for (i = 1; i < 1000; ++i) {
it = graphs.begin();
for (int const &cpu: CPUs)
(*it++)->fillCPUGraph(stream_id, cpu);
for (int const &pid: Tasks)
(*it++)->fillTaskGraph(stream_id, pid);
/* Clear the screen. */
glClear(GL_COLOR_BUFFER_BIT);
/* Draw all graphs. */
for (auto &g: graphs)
g->draw();
glFlush();
if (!(i % 250))
zoomIn = !zoomIn;
if (zoomIn)
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(nullptr);
bool shapes(false);
char *font_file;
size_t r, nRows;
int c, nBins;
while ((c = getopt(argc, argv, "hsi:")) != -1) {
switch(c) {
case 'h':
usage(argv[0]);
return 1;
case 'i':
input_file = optarg;
break;
case 's':
shapes = true;
default:
break;
}
}
font_file = ksplot_find_font_file("FreeMono", "FreeMonoBold");
if (!font_file)
return 1;
auto lamDraw = [&] (void (*func)(void)) {
/* Initialize Glut. */
glutInit(&argc, argv);
ksplot_make_scene(WINDOW_WIDTH, WINDOW_HEIGHT);
/* Initialize OpenGL. */
ksplot_init_opengl(1);
ksplot_resize_opengl(WINDOW_WIDTH, WINDOW_HEIGHT);
ksplot_init_font(&font, 18, font_file);
/* Display something. */
glutDisplayFunc(func);
glutMainLoop();
};
if (shapes) {
/* Draw simple shapes. */
lamDraw(drawShapes);
return 0;
}
/* Create a new kshark session. */
if (!kshark_instance(&kshark_ctx))
return 1;
/* Open a trace data file produced by trace-cmd. */
if (!input_file)
input_file = default_file;
stream_id = kshark_open(kshark_ctx, input_file);
if (stream_id < 0) {
kshark_free(kshark_ctx);
usage(argv[0]);
cerr << "\nFailed to open file " << input_file << endl;
return 1;
}
/* Load the content of the file into an array of entries. */
nRows = kshark_load_entries(kshark_ctx, stream_id, &data);
/* Initialize the Visualization Model. */
ksmodel_init(&histo);
nBins = WINDOW_WIDTH - GRAPH_LABEL_WIDTH - 3 * GRAPH_H_MARGIN;
ksmodel_set_bining(&histo, nBins, data[0]->ts,
data[nRows - 1]->ts);
/* Fill the model with data and calculate its state. */
ksmodel_fill(&histo, data, nRows);
/* Play animated Graph. */
lamDraw(play);
free(font_file);
/* Free the memory. */
for (auto &g: graphs)
delete g;
for (r = 0; r < nRows; ++r)
free(data[r]);
free(data);
/* Reset (clear) the model. */
ksmodel_clear(&histo);
/* Close the session. */
kshark_free(kshark_ctx);
return 0;
}