diff mbox

[ovs-dev] json: Use reference counting in json objects

Message ID AT5PR84MB02102B342FB9F085200FA1AFDC130@AT5PR84MB0210.NAMPRD84.PROD.OUTLOOK.COM
State Superseded
Headers show

Commit Message

Rodriguez Betancourt, Esteban Aug. 16, 2016, 9:50 p.m. UTC
After profiling OVSDB insert performance it was found
that some significant portion of its time OVSDB is
calling the function json_clone.

Also, most of the usages of json_clone never modify the json,
just keeps it to prevent it to be freed.

With that in mind the struct json, json_create, json_clone
and json_destroy were modified to keep a count of how many
references of the json struct are left. Only when that count
reaches zero the json struct is freed.

The old "json_clone" function was renamed as "json_deep_clone".

The change provides some performance improvement, depending
on the transactions performed in OVSDB.

Signed-off-by: Esteban Rodriguez Betancourt <estebarb@hpe.com>
---
 lib/json.c | 18 ++++++++++++++++--
 lib/json.h |  2 ++
 2 files changed, 18 insertions(+), 2 deletions(-)

Comments

Ryan Moats Aug. 25, 2016, 3:27 p.m. UTC | #1
"dev" <dev-bounces@openvswitch.org> wrote on 08/16/2016 04:50:37 PM:

> From: "Rodriguez Betancourt, Esteban" <estebarb@hpe.com>
> To: "dev@openvswitch.org" <dev@openvswitch.org>
> Date: 08/16/2016 04:50 PM
> Subject: [ovs-dev] [PATCH] json: Use reference counting in json objects
> Sent by: "dev" <dev-bounces@openvswitch.org>
>
> After profiling OVSDB insert performance it was found
> that some significant portion of its time OVSDB is
> calling the function json_clone.
>
> Also, most of the usages of json_clone never modify the json,
> just keeps it to prevent it to be freed.
>
> With that in mind the struct json, json_create, json_clone
> and json_destroy were modified to keep a count of how many
> references of the json struct are left. Only when that count
> reaches zero the json struct is freed.
>
> The old "json_clone" function was renamed as "json_deep_clone".
>
> The change provides some performance improvement, depending
> on the transactions performed in OVSDB.
>
> Signed-off-by: Esteban Rodriguez Betancourt <estebarb@hpe.com>
> ---

Can you add some quantification of the statement
"provides some performance improvement"?
Rodriguez Betancourt, Esteban Aug. 25, 2016, 6:31 p.m. UTC | #2
For example: 
50 process inserting each 1000 rows to a test table (4 columns: string * 2, bool, integer) using commit block

Master OVS
Test Duration			131 seconds
Average Inserts Per second	746.2687 inserts/s
Average Insert Duration	134.1382ms
Minimal Insert Duration	0.166202ms
Maximum Insert Duration	489.8593ms

JSON GC Patch
Test Duration			86 seconds
Average Inserts Per second	1176 inserts/s
Average Insert Duration	82.26761ms
Minimal Insert Duration	0.165448ms
Maximum Insert Duration	751.2111ms

5 process inserting 10000 rows each to the same test table

Master OVS
Test Duration			8 seconds
Average Inserts Per second	7142.857 inserts/s
Average Insert Duration	0.656431ms
Minimal Insert Duration	0.125197ms
Maximum Insert Duration	11.93203ms

JSON GC Patch
Test Duration			7 seconds
Average Inserts Per second	8333.333 inserts/s
Average Insert Duration	0.55688ms
Minimal Insert Duration	0.143233ms
Maximum Insert Duration	26.26319ms

Also, accordingly with profiling using callgrind functions like json_clone or json_destroy sometimes can take up to 20% and 36% of the ops executed inOVSDB (those functions and functions called by those ones...). Although, in one odd case it shows that json_clone takes 50% of the operations executed. We can't avoid calling json_destroy sometimes, but I didn't find any place where a cloned JSON object is updated: only cloned, passed the new pointer and release the old one. 

Regards,
Esteban


From: Ryan Moats [mailto:rmoats@us.ibm.com] 
Sent: jueves, 25 de agosto de 2016 9:28
To: Rodriguez Betancourt, Esteban <estebarb@hpe.com>
Cc: dev@openvswitch.org
Subject: Re: [ovs-dev] [PATCH] json: Use reference counting in json objects

"dev" <dev-bounces@openvswitch.org> wrote on 08/16/2016 04:50:37 PM:

> From: "Rodriguez Betancourt, Esteban" <estebarb@hpe.com>
> To: "dev@openvswitch.org" <dev@openvswitch.org>
> Date: 08/16/2016 04:50 PM
> Subject: [ovs-dev] [PATCH] json: Use reference counting in json objects
> Sent by: "dev" <dev-bounces@openvswitch.org>
> 
> After profiling OVSDB insert performance it was found
> that some significant portion of its time OVSDB is
> calling the function json_clone.
> 
> Also, most of the usages of json_clone never modify the json,
> just keeps it to prevent it to be freed.
> 
> With that in mind the struct json, json_create, json_clone
> and json_destroy were modified to keep a count of how many
> references of the json struct are left. Only when that count
> reaches zero the json struct is freed.
> 
> The old "json_clone" function was renamed as "json_deep_clone".
> 
> The change provides some performance improvement, depending
> on the transactions performed in OVSDB.
> 
> Signed-off-by: Esteban Rodriguez Betancourt <estebarb@hpe.com>
> ---

Can you add some quantification of the statement
"provides some performance improvement"?
Ben Pfaff Aug. 28, 2016, 4:49 p.m. UTC | #3
Hi, can you resubmit with performance data in the commit message?  It's
important information.

Thanks,

Ben.

On Thu, Aug 25, 2016 at 06:31:18PM +0000, Rodriguez Betancourt, Esteban wrote:
> For example: 
> 50 process inserting each 1000 rows to a test table (4 columns: string * 2, bool, integer) using commit block
> 
> Master OVS
> Test Duration			131 seconds
> Average Inserts Per second	746.2687 inserts/s
> Average Insert Duration	134.1382ms
> Minimal Insert Duration	0.166202ms
> Maximum Insert Duration	489.8593ms
> 
> JSON GC Patch
> Test Duration			86 seconds
> Average Inserts Per second	1176 inserts/s
> Average Insert Duration	82.26761ms
> Minimal Insert Duration	0.165448ms
> Maximum Insert Duration	751.2111ms
> 
> 5 process inserting 10000 rows each to the same test table
> 
> Master OVS
> Test Duration			8 seconds
> Average Inserts Per second	7142.857 inserts/s
> Average Insert Duration	0.656431ms
> Minimal Insert Duration	0.125197ms
> Maximum Insert Duration	11.93203ms
> 
> JSON GC Patch
> Test Duration			7 seconds
> Average Inserts Per second	8333.333 inserts/s
> Average Insert Duration	0.55688ms
> Minimal Insert Duration	0.143233ms
> Maximum Insert Duration	26.26319ms
> 
> Also, accordingly with profiling using callgrind functions like json_clone or json_destroy sometimes can take up to 20% and 36% of the ops executed inOVSDB (those functions and functions called by those ones...). Although, in one odd case it shows that json_clone takes 50% of the operations executed. We can't avoid calling json_destroy sometimes, but I didn't find any place where a cloned JSON object is updated: only cloned, passed the new pointer and release the old one. 
> 
> Regards,
> Esteban
> 
> 
> From: Ryan Moats [mailto:rmoats@us.ibm.com] 
> Sent: jueves, 25 de agosto de 2016 9:28
> To: Rodriguez Betancourt, Esteban <estebarb@hpe.com>
> Cc: dev@openvswitch.org
> Subject: Re: [ovs-dev] [PATCH] json: Use reference counting in json objects
> 
> "dev" <dev-bounces@openvswitch.org> wrote on 08/16/2016 04:50:37 PM:
> 
> > From: "Rodriguez Betancourt, Esteban" <estebarb@hpe.com>
> > To: "dev@openvswitch.org" <dev@openvswitch.org>
> > Date: 08/16/2016 04:50 PM
> > Subject: [ovs-dev] [PATCH] json: Use reference counting in json objects
> > Sent by: "dev" <dev-bounces@openvswitch.org>
> > 
> > After profiling OVSDB insert performance it was found
> > that some significant portion of its time OVSDB is
> > calling the function json_clone.
> > 
> > Also, most of the usages of json_clone never modify the json,
> > just keeps it to prevent it to be freed.
> > 
> > With that in mind the struct json, json_create, json_clone
> > and json_destroy were modified to keep a count of how many
> > references of the json struct are left. Only when that count
> > reaches zero the json struct is freed.
> > 
> > The old "json_clone" function was renamed as "json_deep_clone".
> > 
> > The change provides some performance improvement, depending
> > on the transactions performed in OVSDB.
> > 
> > Signed-off-by: Esteban Rodriguez Betancourt <estebarb@hpe.com>
> > ---
> 
> Can you add some quantification of the statement
> "provides some performance improvement"?
> _______________________________________________
> dev mailing list
> dev@openvswitch.org
> http://openvswitch.org/mailman/listinfo/dev
diff mbox

Patch

diff --git a/lib/json.c b/lib/json.c
index 4ac250b..20909ed 100644
--- a/lib/json.c
+++ b/lib/json.c
@@ -333,7 +333,7 @@  static void json_destroy_array(struct json_array *array);
 void
 json_destroy(struct json *json)
 {
-    if (json) {
+    if (json && !--json->count) {
         switch (json->type) {
         case JSON_OBJECT:
             json_destroy_object(json->u.object);
@@ -390,9 +390,18 @@  json_destroy_array(struct json_array *array)
 static struct json *json_clone_object(const struct shash *object);
 static struct json *json_clone_array(const struct json_array *array);
 
+/* Increments the counter of the json instance */
+struct json *
+json_clone(const struct json *json_)
+{
+    struct json *json = CONST_CAST(struct json *, json_);
+    json->count++;
+    return json;
+}
+
 /* Returns a deep copy of 'json'. */
 struct json *
-json_clone(const struct json *json)
+json_deep_clone(const struct json *json)
 {
     switch (json->type) {
     case JSON_OBJECT:
@@ -547,6 +556,10 @@  json_equal_array(const struct json_array *a, const struct json_array *b)
 bool
 json_equal(const struct json *a, const struct json *b)
 {
+    if (a == b) {
+        return true;
+    }
+
     if (a->type != b->type) {
         return false;
     }
@@ -1405,6 +1418,7 @@  json_create(enum json_type type)
 {
     struct json *json = xmalloc(sizeof *json);
     json->type = type;
+    json->count = 1;
     return json;
 }
 
diff --git a/lib/json.h b/lib/json.h
index 3497035..a76c55d 100644
--- a/lib/json.h
+++ b/lib/json.h
@@ -61,6 +61,7 @@  struct json_array {
 
 /* A JSON value. */
 struct json {
+    size_t count;
     enum json_type type;
     union {
         struct shash *object;   /* Contains "struct json *"s. */
@@ -99,6 +100,7 @@  double json_real(const struct json *);
 int64_t json_integer(const struct json *);
 
 struct json *json_clone(const struct json *);
+struct json *json_deep_clone(const struct json *);
 void json_destroy(struct json *);
 
 size_t json_hash(const struct json *, size_t basis);