[gnumeric] Evaluation: cache largish ranges.
- From: Morten Welinder <mortenw src gnome org>
- To: svn-commits-list gnome org
- Subject: [gnumeric] Evaluation: cache largish ranges.
- Date: Sat, 9 May 2009 21:23:25 -0400 (EDT)
commit 96dbf55e4c544018b86f6badcfe378543e187df0
Author: Morten Welinder <terra gnome org>
Date: Sat May 9 21:23:09 2009 -0400
Evaluation: cache largish ranges.
---
ChangeLog | 4 +
NEWS | 1 +
src/collect.c | 257 +++++++++++++++++++++++++++++++++++++++++++++++++++++----
3 files changed, 247 insertions(+), 15 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index 99b4d3c..709969d 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,9 @@
2009-05-09 Morten Welinder <terra gnome org>
+ * src/collect.c (collect_floats): Introduce a cache for the
+ important argc==1 case. Add extra argument to avoid copying
+ the result unnecessarily. All callers changed.
+
* src/sheet-style.c (cell_tile_optimize): Remove extraneous
"break;" Fixes #582027.
diff --git a/NEWS b/NEWS
index 880ef51..74f748e 100644
--- a/NEWS
+++ b/NEWS
@@ -15,6 +15,7 @@ Morten:
* Prune fn-lookup caches in case someone is being silly.
* Plug leak in HTML paste.
* Respect the sheet size prefs for new blank workbooks.
+ * Cache large ranges, possibly sorted.
--------------------------------------------------------------------------
Gnumeric 1.9.7
diff --git a/src/collect.c b/src/collect.c
index ac765e5..8ee60b3 100644
--- a/src/collect.c
+++ b/src/collect.c
@@ -11,15 +11,187 @@
#include "collect.h"
#include "func.h"
+#include "application.h"
#include "value.h"
#include "expr.h"
#include "expr-impl.h"
#include "gnm-datetime.h"
#include "workbook.h"
#include "sheet.h"
+#include "ranges.h"
#include "number-match.h"
#include <goffice/utils/go-glib-extras.h>
#include <stdlib.h>
+#include <string.h>
+
+/* ------------------------------------------------------------------------- */
+
+typedef struct {
+ /* key */
+ GnmValue *value;
+ CollectFlags flags;
+
+ /* result */
+ int n;
+ gnm_float *data;
+ GnmValue *error;
+} SingleFloatsCacheEntry;
+
+static void
+single_floats_cache_entry_free (SingleFloatsCacheEntry *entry)
+{
+ value_release (entry->value);
+ if (entry->error)
+ value_release (entry->error);
+ g_free (entry->data);
+ g_free (entry);
+}
+
+static guint
+single_floats_cache_entry_hash (const SingleFloatsCacheEntry *entry)
+{
+ return value_hash (entry->value) ^ (guint)entry->flags;
+}
+
+static gboolean
+single_floats_cache_entry_equal (const SingleFloatsCacheEntry *a,
+ const SingleFloatsCacheEntry *b)
+
+{
+ return (a->flags == b->flags &&
+ value_equal (a->value, b->value));
+}
+
+static gulong cache_handler;
+static GHashTable *single_floats_cache;
+static size_t total_cache_size;
+
+static void
+clear_caches (void)
+{
+ if (!cache_handler)
+ return;
+
+ g_signal_handler_disconnect (gnm_app_get_app (), cache_handler);
+ cache_handler = 0;
+
+ g_hash_table_destroy (single_floats_cache);
+ single_floats_cache = NULL;
+
+ total_cache_size = 0;
+}
+
+static void
+create_caches (void)
+{
+ if (cache_handler)
+ return;
+
+ cache_handler =
+ g_signal_connect (gnm_app_get_app (), "recalc-finished",
+ G_CALLBACK (clear_caches), NULL);
+
+ single_floats_cache = g_hash_table_new_full
+ ((GHashFunc)single_floats_cache_entry_hash,
+ (GEqualFunc)single_floats_cache_entry_equal,
+ (GDestroyNotify)single_floats_cache_entry_free,
+ NULL);
+
+ total_cache_size = 0;
+}
+
+static gboolean
+cb_prune (gpointer key, gpointer value, gpointer user)
+{
+ return TRUE;
+}
+
+static void
+prune_caches (void)
+{
+ if (total_cache_size > GNM_DEFAULT_ROWS * 10) {
+ if (0) g_printerr ("Pruning collect cache from size %ld.\n",
+ (long)total_cache_size);
+
+ total_cache_size = 0;
+ g_hash_table_foreach_remove (single_floats_cache,
+ cb_prune,
+ NULL);
+ }
+}
+
+static SingleFloatsCacheEntry *
+get_single_floats_cache_entry (GnmValue const *value, CollectFlags flags)
+{
+ SingleFloatsCacheEntry key;
+
+ if (flags & (COLLECT_INFO | COLLECT_IGNORE_SUBTOTAL))
+ return NULL;
+
+ create_caches ();
+
+ key.value = (GnmValue *)value;
+ key.flags = flags;
+
+ return g_hash_table_lookup (single_floats_cache, &key);
+}
+
+static SingleFloatsCacheEntry *
+get_or_fake_cache_entry (GnmValue const *key, CollectFlags flags,
+ GnmEvalPos const *ep)
+{
+ SingleFloatsCacheEntry *ce;
+
+ ce = get_single_floats_cache_entry (key, flags);
+ if (ce) return ce;
+
+ if (flags & COLLECT_ORDER_IRRELEVANT) {
+ ce = get_single_floats_cache_entry (key, flags | COLLECT_SORT);
+ if (ce)
+ return ce;
+ }
+
+ if (flags & COLLECT_SORT) {
+ /* FIXME: Try unsorted. */
+ }
+
+ return NULL;
+}
+
+
+static GnmValue *
+get_single_cache_key (GnmExpr const *e, GnmEvalPos const *ep)
+{
+ GnmValue *r, *key;
+ GnmSheetRange sr;
+ GnmRangeRef const *rr;
+ Sheet *end_sheet;
+ int h, w;
+ const int min_size = 25;
+
+ r = gnm_expr_get_range (e);
+ if (!r)
+ return NULL;
+
+ rr = value_get_rangeref (r);
+ gnm_rangeref_normalize (rr, ep, &sr.sheet, &end_sheet, &sr.range);
+ if (sr.sheet != end_sheet) {
+ value_release (r);
+ return NULL; /* 3D */
+ }
+
+ h = range_height (&sr.range);
+ w = range_width (&sr.range);
+ if (h < min_size && w < min_size && h * w < min_size) {
+ value_release (r);
+ return NULL;
+ }
+
+ key = value_new_cellrange_r (sr.sheet, &sr.range);
+ value_release (r);
+
+ return key;
+}
/* ------------------------------------------------------------------------- */
@@ -157,15 +329,21 @@ callback_function_collect (GnmEvalPos const *ep, GnmValue const *value,
static gnm_float *
collect_floats (int argc, GnmExprConstPtr const *argv,
GnmEvalPos const *ep, CollectFlags flags,
- int *n, GnmValue **error, GSList **info)
+ int *n, GnmValue **error, GSList **info,
+ gboolean *constp)
{
collect_floats_t cl;
CellIterFlags iter_flags = CELL_ITER_ALL;
+ GnmValue *key = NULL;
+ CollectFlags keyflags = flags & ~COLLECT_ORDER_IRRELEVANT;
+
+ if (constp)
+ *constp = FALSE;
if (info) {
+ *info = NULL;
g_return_val_if_fail (!(flags & COLLECT_SORT), NULL);
flags |= COLLECT_INFO;
- *info = NULL;
} else {
if (flags & COLLECT_IGNORE_BLANKS)
iter_flags = CELL_ITER_IGNORE_BLANK;
@@ -182,6 +360,33 @@ collect_floats (int argc, GnmExprConstPtr const *argv,
cl.info = NULL;
cl.date_conv = workbook_date_conv (ep->sheet->workbook);
+ /* ---------------------------------------- */
+ /* Try cache. */
+
+ if (argc == 1 &&
+ (flags & (COLLECT_INFO | COLLECT_IGNORE_SUBTOTAL)) == 0) {
+ key = get_single_cache_key (argv[0], ep);
+ }
+ if (key) {
+ SingleFloatsCacheEntry *ce =
+ get_or_fake_cache_entry (key, keyflags, ep);
+ if (ce) {
+ value_release (key);
+ if (ce->error) {
+ *error = value_dup (ce->error);
+ return NULL;
+ }
+ *n = ce->n;
+ if (constp) {
+ *constp = TRUE;
+ return ce->data;
+ }
+ return g_memdup (ce->data, *n * sizeof (gnm_float));
+ }
+ }
+
+ /* ---------------------------------------- */
+
*error = function_iterate_argument_values
(ep, &callback_function_collect, &cl,
argc, argv,
@@ -189,23 +394,43 @@ collect_floats (int argc, GnmExprConstPtr const *argv,
if (*error) {
g_assert (VALUE_IS_ERROR (*error));
g_free (cl.data);
+ cl.data = NULL;
+ cl.count = 0;
g_slist_free (cl.info);
- return NULL;
- }
-
- if (cl.data == NULL) {
- cl.alloc_count = 1;
- cl.data = g_new (gnm_float, cl.alloc_count);
- }
+ cl.info = NULL;
+ } else {
+ if (cl.data == NULL) {
+ cl.alloc_count = 1;
+ cl.data = g_new (gnm_float, cl.alloc_count);
+ }
- if (flags & COLLECT_SORT) {
- qsort (cl.data, cl.count, sizeof (cl.data[0]), float_compare);
+ if (flags & COLLECT_SORT) {
+ qsort (cl.data, cl.count, sizeof (cl.data[0]),
+ float_compare);
+ }
}
if (info)
*info = cl.info;
*n = cl.count;
+ if (key) {
+ SingleFloatsCacheEntry *ce = g_new (SingleFloatsCacheEntry, 1);
+ ce->value = key;
+ ce->flags = keyflags;
+ ce->n = *n;
+ ce->error = *error ? value_dup (*error) : NULL;
+ if (cl.data == NULL)
+ ce->data = NULL;
+ else if (constp) {
+ *constp = TRUE;
+ ce->data = cl.data;
+ } else
+ ce->data = g_memdup (cl.data, MAX (1, *n) * sizeof (gnm_float));
+ prune_caches ();
+ g_hash_table_insert (single_floats_cache, ce, ce);
+ total_cache_size += 1 + *n;
+ }
return cl.data;
}
@@ -221,7 +446,7 @@ collect_floats_value (GnmValue const *val, GnmEvalPos const *ep,
GnmExprConstPtr argv[1] = { &expr_val };
gnm_expr_constant_init (&expr_val.constant, val);
- return collect_floats (1, argv, ep, flags, n, error, NULL);
+ return collect_floats (1, argv, ep, flags, n, error, NULL, NULL);
}
/* ------------------------------------------------------------------------- */
@@ -237,7 +462,7 @@ collect_floats_value_with_info (GnmValue const *val, GnmEvalPos const *ep,
gnm_float *res;
gnm_expr_constant_init (&expr_val.constant, val);
- res = collect_floats (1, argv, ep, flags, n, error, info);
+ res = collect_floats (1, argv, ep, flags, n, error, info, NULL);
if (info)
*info = g_slist_reverse (*info);
@@ -258,13 +483,15 @@ float_range_function (int argc, GnmExprConstPtr const *argv,
GnmValue *error = NULL;
gnm_float *vals, res;
int n, err;
+ gboolean constp;
- vals = collect_floats (argc, argv, ei->pos, flags, &n, &error, NULL);
+ vals = collect_floats (argc, argv, ei->pos, flags, &n, &error,
+ NULL, &constp);
if (!vals)
return error;
err = func (vals, n, &res);
- g_free (vals);
+ if (!constp) g_free (vals);
if (err)
return value_new_error_std (ei->pos, func_error);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]