diff options
Diffstat (limited to '')
-rw-r--r-- | lib/tools/meson.build | 24 | ||||
-rw-r--r-- | lib/tools/profile-key-colors.c | 175 |
2 files changed, 199 insertions, 0 deletions
diff --git a/lib/tools/meson.build b/lib/tools/meson.build new file mode 100644 index 0000000..6844775 --- /dev/null +++ b/lib/tools/meson.build @@ -0,0 +1,24 @@ +# Test program to profile performance of the key-colors functions +executable( + 'profile-key-colors', + sources : [ + 'profile-key-colors.c', + '../gs-key-colors.c', + '../gs-key-colors.h', + ], + include_directories : [ + include_directories('..'), + include_directories('../..'), + ], + dependencies : [ + glib, + gtk, + gdk_pixbuf, + libm, + ], + c_args : [ + '-Wall', + '-Wextra', + ], + install: false, +) diff --git a/lib/tools/profile-key-colors.c b/lib/tools/profile-key-colors.c new file mode 100644 index 0000000..44df6a4 --- /dev/null +++ b/lib/tools/profile-key-colors.c @@ -0,0 +1,175 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + * vi:set noexpandtab tabstop=8 shiftwidth=8: + * + * Copyright (C) 2021 Endless OS Foundation LLC + * + * Authors: + * - Philip Withnall <pwithnall@endlessos.org> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <glib.h> +#include <gdk-pixbuf/gdk-pixbuf.h> +#include <gdk/gdk.h> +#include <locale.h> +#include <math.h> + +#include "gs-key-colors.h" + +/* Test program which can be used to check the output and performance of the + * gs_calculate_key_colors() function. It is linked against libgnomesoftware, so + * will use the function implementation from there. It outputs a HTML page which + * lists each icon from the flathub appstream data in your home directory, along + * with its extracted key colors and how long extraction took. */ + +static void +print_colours (GString *html_output, + GArray *colours) +{ + g_string_append_printf (html_output, "<table class='colour-swatch'><tr>"); + for (guint i = 0; i < colours->len; i++) { + GdkRGBA *rgba = &g_array_index (colours, GdkRGBA, i); + + g_string_append_printf (html_output, + "<td style='background-color: rgb(%u, %u, %u)'></td>", + (guint) (rgba->red * 255), + (guint) (rgba->green * 255), + (guint) (rgba->blue * 255)); + + if (i % 3 == 2) + g_string_append (html_output, "</tr><tr>"); + } + g_string_append_printf (html_output, "</tr></table>"); +} + +static void +print_summary_statistics (GString *html_output, + GArray *durations /* (element-type gint64) */) +{ + gint64 sum = 0, min = G_MAXINT64, max = G_MININT64; + guint n_measurements = durations->len; + gint64 mean, stddev; + gint64 sum_of_square_deviations = 0; + + for (guint i = 0; i < durations->len; i++) { + gint64 duration = g_array_index (durations, gint64, i); + sum += duration; + min = MIN (min, duration); + max = MAX (max, duration); + } + + mean = sum / n_measurements; + + for (guint i = 0; i < durations->len; i++) { + gint64 duration = g_array_index (durations, gint64, i); + gint64 diff = duration - mean; + sum_of_square_deviations += diff * diff; + } + + stddev = sqrt (sum_of_square_deviations / n_measurements); + + g_string_append_printf (html_output, + "[%" G_GINT64_FORMAT ", %" G_GINT64_FORMAT "]μs, mean %" G_GINT64_FORMAT "±%" G_GINT64_FORMAT "μs, n = %u", + min, max, mean, stddev, n_measurements); +} + +int +main (void) +{ + const gchar *icons_subdir = ".local/share/flatpak/appstream/flathub/x86_64/active/icons/128x128"; + g_autofree gchar *icons_dir = g_build_filename (g_get_home_dir (), icons_subdir, NULL); + g_autoptr(GDir) dir = NULL; + const gchar *entry; + g_autoptr(GPtrArray) filenames = g_ptr_array_new_with_free_func (g_free); + g_autoptr(GPtrArray) pixbufs = g_ptr_array_new_with_free_func (g_object_unref); + g_autoptr(GString) html_output = g_string_new (""); + g_autoptr(GArray) durations = g_array_new (FALSE, FALSE, sizeof (gint64)); + + setlocale (LC_ALL, ""); + + /* Load pixbufs from the icons directory. */ + dir = g_dir_open (icons_dir, 0, NULL); + if (dir == NULL) + return 1; + + while ((entry = g_dir_read_name (dir)) != NULL) { + g_autofree gchar *filename = g_build_filename (icons_dir, entry, NULL); + g_autoptr(GdkPixbuf) pixbuf = gdk_pixbuf_new_from_file (filename, NULL); + + if (pixbuf == NULL) + continue; + + g_ptr_array_add (filenames, g_steal_pointer (&filename)); + g_ptr_array_add (pixbufs, g_steal_pointer (&pixbuf)); + } + + if (!pixbufs->len) + return 2; + + /* Set up an output page */ + g_string_append (html_output, + "<!DOCTYPE html>\n" + "<html>\n" + " <head>\n" + " <meta charset='UTF-8'>\n" + " <style>\n" + " #main-table, #main-table th, #main-table td { border: 1px solid black; border-collapse: collapse }\n" + " #main-table th, #main-table td { padding: 4px }\n" + " td.number { text-align: right }\n" + " table.colour-swatch td { width: 30px; height: 30px }\n" + " .faster { background-color: rgb(190, 236, 57) }\n" + " .slower { background-color: red }\n" + " </style>\n" + " </head>\n" + " <body>\n" + " <table id='main-table'>\n" + " <thead>\n" + " <tr>\n" + " <td>Filename</td>\n" + " <td>Icon</td>\n" + " <td>Code duration (μs)</td>\n" + " <td>Code colours</td>\n" + " </tr>\n" + " </thead>\n"); + + /* For each pixbuf, run both algorithms. */ + for (guint i = 0; i < pixbufs->len; i++) { + GdkPixbuf *pixbuf = pixbufs->pdata[i]; + const gchar *filename = filenames->pdata[i]; + g_autofree gchar *basename = g_path_get_basename (filename); + g_autoptr(GArray) colours = NULL; + gint64 start_time, duration; + + g_message ("Processing %u of %u, %s", i + 1, pixbufs->len, filename); + + start_time = g_get_real_time (); + colours = gs_calculate_key_colors (pixbuf); + duration = g_get_real_time () - start_time; + + g_string_append_printf (html_output, + "<tr>\n" + "<th>%s</th>\n" + "<td><img src='file:%s'></td>\n" + "<td class='number'>%" G_GINT64_FORMAT "</td>\n" + "<td>", + basename, filename, duration); + print_colours (html_output, colours); + g_string_append (html_output, + "</td>\n" + "</tr>\n"); + + g_array_append_val (durations, duration); + } + + /* Summary statistics for the timings. */ + g_string_append (html_output, "<tfoot><tr><td></td><td></td><td>"); + print_summary_statistics (html_output, durations); + g_string_append (html_output, "</td><td></td></tr></tfoot>"); + + g_string_append (html_output, "</table></body></html>"); + + g_print ("%s\n", html_output->str); + + return 0; +} |