[Spice-devel] [PATCH spice-gtk 03/10] display: replace ring with hashtable

Marc-André Lureau marcandre.lureau at gmail.com
Sun Sep 8 11:59:26 PDT 2013


With a Spice replay (a tool not yet merged, but available in dev
branches), the following commit improves a little bit performance by not
spending so much CPU time in looking up surfaces. I found initially
hotspot with "perf", and get a consistant ~200ms speedup with "time
spicy-stats" after replacing the ring.

before:
real     0m5.147s
user     0m3.506s
sys      0m1.949s

after:
real     0m5.008s
user     0m3.253s
sys      0m2.015s
---
 gtk/channel-display-priv.h |  1 -
 gtk/channel-display.c      | 33 ++++++++++++---------------------
 2 files changed, 12 insertions(+), 22 deletions(-)

diff --git a/gtk/channel-display-priv.h b/gtk/channel-display-priv.h
index 09683be..92cd231 100644
--- a/gtk/channel-display-priv.h
+++ b/gtk/channel-display-priv.h
@@ -37,7 +37,6 @@ G_BEGIN_DECLS
 
 
 typedef struct display_surface {
-    RingItem                    link;
     guint32                     surface_id;
     bool                        primary;
     enum SpiceSurfaceFmt        format;
diff --git a/gtk/channel-display.c b/gtk/channel-display.c
index eab1742..7a66558 100644
--- a/gtk/channel-display.c
+++ b/gtk/channel-display.c
@@ -66,7 +66,7 @@
 #define MONITORS_MAX 256
 
 struct _SpiceDisplayChannelPrivate {
-    Ring                        surfaces;
+    GHashTable                  *surfaces;
     display_cache               *images;
     display_cache               *palettes;
     SpiceImageCache             image_cache;
@@ -141,6 +141,7 @@ static void spice_display_channel_finalize(GObject *object)
 
     g_clear_pointer(&c->monitors, g_array_unref);
     clear_surfaces(SPICE_CHANNEL(object), FALSE);
+    g_hash_table_unref(c->surfaces);
     clear_streams(SPICE_CHANNEL(object));
 
     if (G_OBJECT_CLASS(spice_display_channel_parent_class)->finalize)
@@ -705,7 +706,7 @@ static void spice_display_channel_init(SpiceDisplayChannel *channel)
 
     c = channel->priv = SPICE_DISPLAY_CHANNEL_GET_PRIVATE(channel);
 
-    ring_init(&c->surfaces);
+    c->surfaces = g_hash_table_new(NULL, NULL);
     c->image_cache.ops = &image_cache_ops;
     c->palette_cache.ops = &palette_cache_ops;
     c->image_surfaces.ops = &image_surfaces_ops;
@@ -740,7 +741,8 @@ static int create_canvas(SpiceChannel *channel, display_surface *surface)
             }
 
             emit_main_context(channel, SPICE_DISPLAY_PRIMARY_DESTROY);
-            ring_remove(&primary->link);
+
+            g_hash_table_remove(c->surfaces, 0);
             destroy_canvas(primary);
             free(primary);
         }
@@ -792,7 +794,7 @@ static int create_canvas(SpiceChannel *channel, display_surface *surface)
                                              surface->zlib_decoder);
 
     g_return_val_if_fail(surface->canvas != NULL, 0);
-    ring_add(&c->surfaces, &surface->link);
+    g_hash_table_insert(c->surfaces, GINT_TO_POINTER(surface->surface_id), surface);
 
     if (surface->primary) {
         emit_main_context(channel, SPICE_DISPLAY_PRIMARY_CREATE,
@@ -839,35 +841,24 @@ static void destroy_canvas(display_surface *surface)
 
 static display_surface *find_surface(SpiceDisplayChannelPrivate *c, guint32 surface_id)
 {
-    display_surface *surface;
-    RingItem *item;
-
-    for (item = ring_get_head(&c->surfaces);
-         item != NULL;
-         item = ring_next(&c->surfaces, item)) {
-        surface = SPICE_CONTAINEROF(item, display_surface, link);
-        if (surface->surface_id == surface_id)
-            return surface;
-    }
-    return NULL;
+    return g_hash_table_lookup(c->surfaces, GINT_TO_POINTER(surface_id));
 }
 
 static void clear_surfaces(SpiceChannel *channel, gboolean keep_primary)
 {
     SpiceDisplayChannelPrivate *c = SPICE_DISPLAY_CHANNEL(channel)->priv;
+    GHashTableIter iter;
     display_surface *surface;
-    RingItem *item;
 
-    for (item = ring_get_head(&c->surfaces); item != NULL; ) {
-        surface = SPICE_CONTAINEROF(item, display_surface, link);
-        item = ring_next(&c->surfaces, item);
+    g_hash_table_iter_init(&iter, c->surfaces);
+    while (g_hash_table_iter_next(&iter, NULL, (gpointer*)&surface)) {
 
         if (keep_primary && surface->primary) {
             CHANNEL_DEBUG(channel, "keeping exisiting primary surface, migration or reset");
             continue;
         }
 
-        ring_remove(&surface->link);
+        g_hash_table_iter_remove(&iter);
         destroy_canvas(surface);
         free(surface);
     }
@@ -1792,7 +1783,7 @@ static void display_handle_surface_destroy(SpiceChannel *channel, SpiceMsgIn *in
         emit_main_context(channel, SPICE_DISPLAY_PRIMARY_DESTROY);
     }
 
-    ring_remove(&surface->link);
+    g_hash_table_remove(c->surfaces, GINT_TO_POINTER(surface->surface_id));
     destroy_canvas(surface);
     free(surface);
 }
-- 
1.8.3.1



More information about the Spice-devel mailing list