summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--content/fetchers/about.c87
-rw-r--r--image/image_cache.c167
-rw-r--r--image/image_cache.h25
3 files changed, 277 insertions, 2 deletions
diff --git a/content/fetchers/about.c b/content/fetchers/about.c
index 5c33c1881..cb533bc54 100644
--- a/content/fetchers/about.c
+++ b/content/fetchers/about.c
@@ -54,6 +54,7 @@
#include "utils/utils.h"
#include "utils/ring.h"
#include "utils/testament.h"
+#include "image/image_cache.h"
struct fetch_about_context;
@@ -159,7 +160,88 @@ static bool fetch_about_licence_handler(struct fetch_about_context *ctx)
return true;
}
+/** Handler to generate about:cache page.
+ *
+ * Shows details of current iamge cache
+ *
+ */
+static bool fetch_about_imagecache_handler(struct fetch_about_context *ctx)
+{
+ char buffer[1024]; /* output buffer */
+ int code = 200;
+ int slen;
+ unsigned int cent_loop = 0;
+ int res = 0;
+ /* content is going to return ok */
+ fetch_set_http_code(ctx->fetchh, code);
+
+ /* content type */
+ if (fetch_about_send_header(ctx, "Content-Type: text/html"))
+ goto fetch_about_imagecache_handler_aborted;
+
+ slen = snprintf(buffer, sizeof buffer,
+ "<html>\n<head>\n"
+ "<title>NetSurf Browser Image Cache Status</title>\n"
+ "<link rel=\"stylesheet\" type=\"text/css\" "
+ "href=\"resource:internal.css\">\n"
+ "</head>\n"
+ "<body id =\"cachelist\">\n"
+ "<p class=\"banner\">"
+ "<a href=\"http://www.netsurf-browser.org/\">"
+ "<img src=\"resource:netsurf.png\" alt=\"NetSurf\"></a>"
+ "</p>\n"
+ "<h1>NetSurf Browser Image Cache Status</h1>\n" );
+ if (fetch_about_send_callback(FETCH_DATA, ctx, buffer,
+ slen, FETCH_ERROR_NO_ERROR))
+ goto fetch_about_imagecache_handler_aborted;
+
+ slen = image_cache_snsummaryf(buffer, sizeof(buffer), NULL);
+
+ if (fetch_about_send_callback(FETCH_DATA, ctx, buffer,
+ slen, FETCH_ERROR_NO_ERROR))
+ goto fetch_about_imagecache_handler_aborted;
+
+ slen = snprintf(buffer, sizeof buffer,
+ "<table class=\"config\">\n"
+ "<tr><th>Entry</th><th>Content Key</th><th>Redraw Count</th><th>Conversion Count</th><th>Last Redraw</th><th>Bitmap Age</th><th>Bitmap Size</th></tr>\n");
+ do {
+ res = image_cache_snentryf(buffer + slen, sizeof buffer - slen,
+ cent_loop,
+ "<tr><td>%e</td><td>%k</td><td>%r</td><td>%c</td><td>%a</td><td>%g</td><td>%s</td></tr>\n");
+ if (res <= 0)
+ break; /* last option */
+
+ if (res >= (int) (sizeof buffer - slen)) {
+ /* last entry would not fit in buffer, submit buffer */
+ if (fetch_about_send_callback(FETCH_DATA, ctx, buffer,
+ slen, FETCH_ERROR_NO_ERROR))
+ goto fetch_about_imagecache_handler_aborted;
+ slen = 0;
+ } else {
+ /* normal addition */
+ slen += res;
+ cent_loop++;
+ }
+ } while (res > 0);
+
+ slen += snprintf(buffer + slen, sizeof buffer - slen,
+ "</table>\n</body>\n</html>\n");
+
+ if (fetch_about_send_callback(FETCH_DATA, ctx, buffer, slen,
+ FETCH_ERROR_NO_ERROR))
+ goto fetch_about_imagecache_handler_aborted;
+
+ fetch_about_send_callback(FETCH_FINISHED, ctx, 0, 0,
+ FETCH_ERROR_NO_ERROR);
+
+ return true;
+
+fetch_about_imagecache_handler_aborted:
+ return false;
+}
+
+/** Handler to generate about:config page */
static bool fetch_about_config_handler(struct fetch_about_context *ctx)
{
char buffer[1024];
@@ -226,6 +308,7 @@ fetch_about_config_handler_aborted:
return false;
}
+
/** Generate the text of a Choices file which represents the current
* in use options.
*/
@@ -408,7 +491,9 @@ struct about_handlers about_handler_list[] = {
{ "testament", SLEN("testament"), NULL, fetch_about_testament_handler, false },
{ "about", SLEN("about"), NULL, fetch_about_about_handler, true },
{ "logo", SLEN("logo"), NULL, fetch_about_logo_handler, true },
- /* The default */
+ /* details about the cache */
+ { "imagecache", SLEN("iamgecache"), NULL, fetch_about_imagecache_handler, true },
+ /* The default blank page */
{ "blank", SLEN("blank"), NULL, fetch_about_blank_handler, true }
};
diff --git a/image/image_cache.c b/image/image_cache.c
index 32fe74571..e060c2303 100644
--- a/image/image_cache.c
+++ b/image/image_cache.c
@@ -22,6 +22,7 @@
#include <string.h>
#include "utils/errors.h"
+#include "utils/utils.h"
#include "utils/log.h"
#include "utils/config.h"
#include "utils/schedule.h"
@@ -124,6 +125,20 @@ struct image_cache_s {
static struct image_cache_s *image_cache = NULL;
+/** Find the nth cache entry
+ */
+static struct image_cache_entry_s *image_cache__findn(int entryn)
+{
+ struct image_cache_entry_s *found;
+
+ found = image_cache->entries;
+ while ((found != NULL) && (entryn > 0)) {
+ entryn--;
+ found = found->next;
+ }
+ return found;
+}
+
/** Find the cache entry for a content
*/
static struct image_cache_entry_s *image_cache__find(const struct content *c)
@@ -512,6 +527,158 @@ nserror image_cache_remove(struct content *content)
}
/* exported interface documented in image_cache.h */
+int image_cache_snsummaryf(char *string, size_t size, const char *fmt)
+{
+ size_t slen = 0; /* current output string length */
+ unsigned int op_count;
+
+ slen += snprintf(string + slen, size - slen,
+ "<p>Configured limit of %ld hysteresis of %ld",
+ image_cache->params.limit, image_cache->params.hysteresis);
+
+ slen += snprintf(string + slen, size - slen,
+ "<p>Total bitmap size in use %ld (in %d)",
+ image_cache->total_bitmap_size,
+ image_cache->bitmap_count);
+
+ op_count = image_cache->hit_count +
+ image_cache->miss_count +
+ image_cache->fail_count;
+
+ slen += snprintf(string + slen, size - slen,
+ "<p>Age %ds", image_cache->current_age / 1000);
+
+ slen += snprintf(string + slen, size - slen,
+ "<p>Peak size %ld (in %d)",
+ image_cache->max_bitmap_size,
+ image_cache->max_bitmap_size_count );
+ slen += snprintf(string + slen, size - slen,
+ "<p>Peak image count %d (size %ld)",
+ image_cache->max_bitmap_count,
+ image_cache->max_bitmap_count_size);
+
+ if (op_count > 0) {
+ uint64_t op_size;
+
+ op_size = image_cache->hit_size +
+ image_cache->miss_size +
+ image_cache->fail_size;
+
+ slen += snprintf(string + slen, size - slen,
+ "<p>Cache total/hit/miss/fail (counts) %d/%d/%d/%d (100%%/%d%%/%d%%/%d%%)",
+ op_count,
+ image_cache->hit_count,
+ image_cache->miss_count,
+ image_cache->fail_count,
+ (image_cache->hit_count * 100) / op_count,
+ (image_cache->miss_count * 100) / op_count,
+ (image_cache->fail_count * 100) / op_count);
+
+ slen += snprintf(string + slen, size - slen,
+ "<p>Cache total/hit/miss/fail (size) %"PRIu64"/%"PRIu64"/%"PRIu64"/%"PRIu64" (100%%/%"PRIu64"%%/%"PRIu64"%%/%"PRIu64"%%)",
+ op_size,
+ image_cache->hit_size,
+ image_cache->miss_size,
+ image_cache->fail_size,
+ (image_cache->hit_size * 100) / op_size,
+ (image_cache->miss_size * 100) / op_size,
+ (image_cache->fail_size * 100) / op_size);
+ }
+
+ slen += snprintf(string + slen, size - slen,
+ "<p>Total images never rendered: %d (includes %d that were converted)",
+ image_cache->total_unrendered,
+ image_cache->specultive_miss_count);
+
+ slen += snprintf(string + slen, size - slen,
+ "<p>Total number of excessive conversions: %d (from %d images converted more than once)",
+ image_cache->total_extra_conversions,
+ image_cache->total_extra_conversions_count);
+
+ slen += snprintf(string + slen, size - slen,
+ "<p>Bitmap of size %d had most (%d) conversions",
+ image_cache->peak_conversions_size,
+ image_cache->peak_conversions);
+
+ return slen;
+}
+
+/* exported interface documented in image_cache.h */
+int image_cache_snentryf(char *string, size_t size, unsigned int entryn,
+ const char *fmt)
+{
+ struct image_cache_entry_s *centry;
+ size_t slen = 0; /* current output string length */
+ int fmtc = 0; /* current index into format string */
+
+ centry = image_cache__findn(entryn);
+ if (centry == NULL)
+ return -1;
+
+ while((slen < size) && (fmt[fmtc] != 0)) {
+ if (fmt[fmtc] == '%') {
+ fmtc++;
+ switch (fmt[fmtc]) {
+ case 'e':
+ slen += snprintf(string + slen, size - slen,
+ "%d", entryn);
+ break;
+
+ case 'r':
+ slen += snprintf(string + slen, size - slen,
+ "%u", centry->redraw_count);
+ break;
+
+ case 'a':
+ slen += snprintf(string + slen, size - slen,
+ "%.2f", (float)((image_cache->current_age - centry->redraw_age)) / 1000);
+ break;
+
+
+ case 'c':
+ slen += snprintf(string + slen, size - slen,
+ "%d", centry->conversion_count);
+ break;
+
+ case 'g':
+ slen += snprintf(string + slen, size - slen,
+ "%.2f", (float)((image_cache->current_age - centry->bitmap_age)) / 1000);
+ break;
+
+ case 'k':
+ slen += snprintf(string + slen, size - slen,
+ "%p", centry->content);
+ break;
+
+ case 's':
+ if (centry->bitmap != NULL) {
+ slen += snprintf(string + slen,
+ size - slen,
+ "%ld",
+ centry->bitmap_size);
+ } else {
+ slen += snprintf(string + slen,
+ size - slen,
+ "0");
+ }
+ break;
+ }
+ fmtc++;
+ } else {
+ string[slen] = fmt[fmtc];
+ slen++;
+ fmtc++;
+ }
+ }
+
+ /* Ensure that we NUL-terminate the output */
+ string[min(slen, size - 1)] = '\0';
+
+ return slen;
+}
+
+
+/* exported interface documented in image_cache.h */
bool image_cache_redraw(struct content *c,
struct content_redraw_data *data,
const struct rect *clip,
diff --git a/image/image_cache.h b/image/image_cache.h
index e879c740d..e1ae24e3a 100644
--- a/image/image_cache.h
+++ b/image/image_cache.h
@@ -96,7 +96,30 @@ struct bitmap *image_cache_find_bitmap(struct content *c);
*/
bool image_cache_speculate(struct content *c);
-/* Image content handler generic cache callbacks */
+/**
+ * Fill a buffer with an option using a format.
+ *
+ * The format string is copied into the output buffer with the
+ * following replaced:
+ * %e - The entry number
+ * %k - The content key
+ * %r - The number of redraws of this bitmap
+ * %c - The number of times this bitmap has been converted
+ * %s - The size of the current bitmap allocation
+ *
+ * \param string The buffer in which to place the results.
+ * \param size The size of the string buffer.
+ * \param entryn The opaque entry number.
+ * \param fmt The format string.
+ * \return The number of bytes written to \a string or -1 on error
+ */
+int image_cache_snentryf(char *string, size_t size, unsigned int entryn,
+ const char *fmt);
+
+/** cache summary */
+int image_cache_snsummaryf(char *string, size_t size, const char *fmt);
+
+/********* Image content handler generic cache callbacks ************/
/** Generic content redraw callback
*