diff mbox

[RFC,v2,38/47] qapi-commands: De-duplicate output marshaling functions

Message ID 1435782155-31412-39-git-send-email-armbru@redhat.com
State New
Headers show

Commit Message

Markus Armbruster July 1, 2015, 8:22 p.m. UTC
gen_marshal_output() uses its parameter name only for name of the
generated function.  Name it after the type being marshaled instead of
its caller, and drop duplicates.

Saves 7 copies of qmp_marshal_output_int() in qemu-ga, and one copy of
qmp_marshal_output_str() in qemu-system-*.

Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
 scripts/qapi-commands.py | 16 +++++++++-------
 1 file changed, 9 insertions(+), 7 deletions(-)

Comments

Eric Blake July 23, 2015, 7:47 p.m. UTC | #1
On 07/01/2015 02:22 PM, Markus Armbruster wrote:
> gen_marshal_output() uses its parameter name only for name of the
> generated function.  Name it after the type being marshaled instead of
> its caller, and drop duplicates.
> 
> Saves 7 copies of qmp_marshal_output_int() in qemu-ga, and one copy of
> qmp_marshal_output_str() in qemu-system-*.

 qga/qapi-generated/qga-qmp-marshal.c |  227
+++++------------------------------
 qmp-marshal.c                        |  225
+++++++++++++++-------------------
 2 files changed, 134 insertions(+), 318 deletions(-)

Most changes look like:

-static void qmp_marshal_output_add_fd(AddfdInfo *ret_in, QObject
**ret_out, Error **errp)
+static void qmp_marshal_output_AddfdInfo(AddfdInfo *ret_in, QObject
**ret_out, Error **errp)
 {
     Error *local_err = NULL;
     QmpOutputVisitor *mo = qmp_output_visitor_new();
@@ -88,7 +88,7 @@ void qmp_marshal_add_fd(QDict *args, QOb
         goto out;
     }

-    qmp_marshal_output_add_fd(retval, ret, &local_err);
+    qmp_marshal_output_AddfdInfo(retval, ret, &local_err);

coupled with wholesale deletions of functions that previously had
identical bodies.  Nice.

[I suspect there might be ways to trim a LOT more code size, by
rewriting a generic marshaller helper that is passed a varargs or
array-of-struct list of operations to perform in order to visit an
arbitrary object, then having each command's marshaller generated with
the appropriate list of arguments for the generic helpers rather than
the current approach of calling out to one marshaller helper per type -
but exploring ideas like that is work for another series]

> 
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> ---
>  scripts/qapi-commands.py | 16 +++++++++-------
>  1 file changed, 9 insertions(+), 7 deletions(-)

Reviewed-by: Eric Blake <eblake@redhat.com>
Markus Armbruster July 28, 2015, 11:20 a.m. UTC | #2
Eric Blake <eblake@redhat.com> writes:

> On 07/01/2015 02:22 PM, Markus Armbruster wrote:
>> gen_marshal_output() uses its parameter name only for name of the
>> generated function.  Name it after the type being marshaled instead of
>> its caller, and drop duplicates.
>> 
>> Saves 7 copies of qmp_marshal_output_int() in qemu-ga, and one copy of
>> qmp_marshal_output_str() in qemu-system-*.
>
>  qga/qapi-generated/qga-qmp-marshal.c |  227
> +++++------------------------------
>  qmp-marshal.c                        |  225
> +++++++++++++++-------------------
>  2 files changed, 134 insertions(+), 318 deletions(-)
>
> Most changes look like:
>
> -static void qmp_marshal_output_add_fd(AddfdInfo *ret_in, QObject
> **ret_out, Error **errp)
> +static void qmp_marshal_output_AddfdInfo(AddfdInfo *ret_in, QObject
> **ret_out, Error **errp)
>  {
>      Error *local_err = NULL;
>      QmpOutputVisitor *mo = qmp_output_visitor_new();
> @@ -88,7 +88,7 @@ void qmp_marshal_add_fd(QDict *args, QOb
>          goto out;
>      }
>
> -    qmp_marshal_output_add_fd(retval, ret, &local_err);
> +    qmp_marshal_output_AddfdInfo(retval, ret, &local_err);
>
> coupled with wholesale deletions of functions that previously had
> identical bodies.  Nice.

Exactly.

> [I suspect there might be ways to trim a LOT more code size, by
> rewriting a generic marshaller helper that is passed a varargs or
> array-of-struct list of operations to perform in order to visit an
> arbitrary object, then having each command's marshaller generated with
> the appropriate list of arguments for the generic helpers rather than
> the current approach of calling out to one marshaller helper per type -
> but exploring ideas like that is work for another series]

Oh, but generating thousands of line of repetitive code is so much fun!

Seriously: yes, that's a far better way to do it.  Marshalling doesn't
have to be as fast as it could possibly be, space cost be damned.

>> Signed-off-by: Markus Armbruster <armbru@redhat.com>
>> ---
>>  scripts/qapi-commands.py | 16 +++++++++-------
>>  1 file changed, 9 insertions(+), 7 deletions(-)
>
> Reviewed-by: Eric Blake <eblake@redhat.com>

Thanks!
diff mbox

Patch

diff --git a/scripts/qapi-commands.py b/scripts/qapi-commands.py
index 2dae425..fcbb7d0 100644
--- a/scripts/qapi-commands.py
+++ b/scripts/qapi-commands.py
@@ -59,7 +59,7 @@  def gen_call(name, args, rets):
 
 qmp_marshal_output_%(c_name)s(retval, ret, &local_err);
 ''',
-                     c_name=c_name(name))
+                     c_name=rets.c_name())
     pop_indent()
     return ret
 
@@ -165,10 +165,10 @@  qapi_dealloc_visitor_cleanup(md);
     pop_indent()
     return ret
 
-def gen_marshal_output(name, rets):
+def gen_marshal_output(rets):
     return mcgen('''
 
-static void qmp_marshal_output_%(c_cmd_name)s(%(c_type)s ret_in, QObject **ret_out, Error **errp)
+static void qmp_marshal_output_%(c_name)s(%(c_type)s ret_in, QObject **ret_out, Error **errp)
 {
     Error *local_err = NULL;
     QmpOutputVisitor *mo = qmp_output_visitor_new();
@@ -191,8 +191,7 @@  out:
     qapi_dealloc_visitor_cleanup(md);
 }
 ''',
-                 c_type=rets.c_type(), c_cmd_name=c_name(name),
-                 c_name=rets.c_name())
+                 c_type=rets.c_type(), c_name=rets.c_name())
 
 def gen_marshal_proto(name):
     ret = 'void qmp_marshal_%s(QDict *args, QObject **ret, Error **errp)' % c_name(name)
@@ -265,10 +264,12 @@  class QAPISchemaGenCommandVisitor(QAPISchemaVisitor):
         self.decl = None
         self.defn = None
         self.regy = None
+        self.visited_rets = None
     def visit_begin(self):
         self.decl = ''
         self.defn = ''
         self.regy = ''
+        self.visited_rets = set()
     def visit_end(self):
         if not middle_mode:
             self.defn += gen_registry(self.regy)
@@ -277,8 +278,9 @@  class QAPISchemaGenCommandVisitor(QAPISchemaVisitor):
         if not gen:
             return
         self.decl += gen_command_decl(name, args, rets)
-        if rets:
-            self.defn += gen_marshal_output(name, rets)
+        if rets and rets not in self.visited_rets:
+            self.visited_rets.add(rets)
+            self.defn += gen_marshal_output(rets)
         if middle_mode:
             self.decl += gen_marshal_decl(name)
         self.defn += gen_marshal(name, args, rets)