Re: [PATCH v2 2/4] scripts/qapi/commands: gen_commands(): add add_trace_points argument

2022-01-17 Thread Kevin Wolf
Am 17.01.2022 um 09:45 hat Vladimir Sementsov-Ogievskiy geschrieben:
> 12.01.2022 13:50, Stefan Hajnoczi wrote:
> > On Tue, Jan 11, 2022 at 07:32:52PM -0500, John Snow wrote:
> > > On Tue, Jan 11, 2022 at 6:53 PM John Snow  wrote:
> > > > 
> > > > On Thu, Dec 23, 2021 at 6:08 AM Vladimir Sementsov-Ogievskiy
> > > >  wrote:
> > > > > 
> > > > > Add possibility to generate trace points for each qmp command.
> > > > > 
> > > > > We should generate both trace points and trace-events file, for 
> > > > > further
> > > > > trace point code generation.
> > > > > 
> > > > > Signed-off-by: Vladimir Sementsov-Ogievskiy 
> > > > > ---
> > > > >   scripts/qapi/commands.py | 84 
> > > > > ++--
> > > > >   1 file changed, 73 insertions(+), 11 deletions(-)
> > > > > 
> > > > > diff --git a/scripts/qapi/commands.py b/scripts/qapi/commands.py
> > > > > index 21001bbd6b..9691c11f96 100644
> > > > > --- a/scripts/qapi/commands.py
> > > > > +++ b/scripts/qapi/commands.py
> > > > > @@ -53,7 +53,8 @@ def gen_command_decl(name: str,
> > > > >   def gen_call(name: str,
> > > > >arg_type: Optional[QAPISchemaObjectType],
> > > > >boxed: bool,
> > > > > - ret_type: Optional[QAPISchemaType]) -> str:
> > > > > + ret_type: Optional[QAPISchemaType],
> > > > > + add_trace_points: bool) -> str:
> > > > >   ret = ''
> > > > > 
> > > > >   argstr = ''
> > > > > @@ -71,21 +72,65 @@ def gen_call(name: str,
> > > > >   if ret_type:
> > > > >   lhs = 'retval = '
> > > > > 
> > > > > -ret = mcgen('''
> > > > > +qmp_name = f'qmp_{c_name(name)}'
> > > > > +upper = qmp_name.upper()
> > > > > +
> > > > > +if add_trace_points:
> > > > > +ret += mcgen('''
> > > > > +
> > > > > +if (trace_event_get_state_backends(TRACE_%(upper)s)) {
> > > > > +g_autoptr(GString) req_json = qobject_to_json(QOBJECT(args));
> > > > > +trace_%(qmp_name)s("", req_json->str);
> > > > > +}
> > > > > +''',
> > > > > + upper=upper, qmp_name=qmp_name)
> > > > > +
> > > > > +ret += mcgen('''
> > > > > 
> > > > >   %(lhs)sqmp_%(c_name)s(%(args)s&err);
> > > > > -error_propagate(errp, err);
> > > > >   ''',
> > > > >   c_name=c_name(name), args=argstr, lhs=lhs)
> > > > > -if ret_type:
> > > > > -ret += mcgen('''
> > > > > +
> > > > > +ret += mcgen('''
> > > > >   if (err) {
> > > > > +''')
> > > > > +
> > > > > +if add_trace_points:
> > > > > +ret += mcgen('''
> > > > > +trace_%(qmp_name)s("FAIL: ", error_get_pretty(err));
> > > > > +''',
> > > > > + qmp_name=qmp_name)
> > > > > +
> > > > > +ret += mcgen('''
> > > > > +error_propagate(errp, err);
> > > > >   goto out;
> > > > >   }
> > > > > +''')
> > > > > +
> > > > > +if ret_type:
> > > > > +ret += mcgen('''
> > > > > 
> > > > >   qmp_marshal_output_%(c_name)s(retval, ret, errp);
> > > > >   ''',
> > > > >c_name=ret_type.c_name())
> > > > > +
> > > > > +if add_trace_points:
> > > > > +if ret_type:
> > > > > +ret += mcgen('''
> > > > > +
> > > > > +if (trace_event_get_state_backends(TRACE_%(upper)s)) {
> > > > > +g_autoptr(GString) ret_json = qobject_to_json(*ret);
> > > > > +trace_%(qmp_name)s("RET:", ret_json->str);
> > > > > +}
> > > > > +''',
> > > > > + upper=upper, qmp_name=qmp_name)
> > > > > +else:
> > > > > +ret += mcgen('''
> > > > > +
> > > > > +trace_%(qmp_name)s("SUCCESS", "");
> > > > > +''',
> > > > > + qmp_name=qmp_name)
> > > > > +
> > > > >   return ret
> > > > > 
> > > > > 
> > > > > @@ -122,10 +167,14 @@ def gen_marshal_decl(name: str) -> str:
> > > > >proto=build_marshal_proto(name))
> > > > > 
> > > > > 
> > > > > +def gen_trace(name: str) -> str:
> > > > > +return f'qmp_{c_name(name)}(const char *tag, const char *json) 
> > > > > "%s%s"\n'
> > > > > +
> > > > >   def gen_marshal(name: str,
> > > > >   arg_type: Optional[QAPISchemaObjectType],
> > > > >   boxed: bool,
> > > > > -ret_type: Optional[QAPISchemaType]) -> str:
> > > > > +ret_type: Optional[QAPISchemaType],
> > > > > +add_trace_points: bool) -> str:
> > > > >   have_args = boxed or (arg_type and not arg_type.is_empty())
> > > > >   if have_args:
> > > > >   assert arg_type is not None
> > > > > @@ -180,7 +229,7 @@ def gen_marshal(name: str,
> > > > >   }
> > > > >   ''')
> > > > > 
> > > > > -ret += gen_call(name, arg_type, boxed, ret_type)
> > > > > +ret += gen_call(name, arg_type, boxed, ret_type, 
> > > > > add_trace_points)
> > > > > 
> > > > >   ret += mcgen('''
> > > > > 
> > > > > @@ -238,11 +287,12 @@ def gen_register_command(name: str,
> >

Re: [PATCH v2 2/4] scripts/qapi/commands: gen_commands(): add add_trace_points argument

2022-01-17 Thread Vladimir Sementsov-Ogievskiy

10.01.2022 19:22, Stefan Hajnoczi wrote:

On Thu, Dec 23, 2021 at 12:07:54PM +0100, Vladimir Sementsov-Ogievskiy wrote:

Add possibility to generate trace points for each qmp command.

We should generate both trace points and trace-events file, for further
trace point code generation.

Signed-off-by: Vladimir Sementsov-Ogievskiy 
---
  scripts/qapi/commands.py | 84 ++--
  1 file changed, 73 insertions(+), 11 deletions(-)

diff --git a/scripts/qapi/commands.py b/scripts/qapi/commands.py
index 21001bbd6b..9691c11f96 100644
--- a/scripts/qapi/commands.py
+++ b/scripts/qapi/commands.py
@@ -53,7 +53,8 @@ def gen_command_decl(name: str,
  def gen_call(name: str,
   arg_type: Optional[QAPISchemaObjectType],
   boxed: bool,
- ret_type: Optional[QAPISchemaType]) -> str:
+ ret_type: Optional[QAPISchemaType],
+ add_trace_points: bool) -> str:


Please use the term "trace events" instead of "trace points". That's the
term that docs/devel/tracing.rst uses.


@@ -122,10 +167,14 @@ def gen_marshal_decl(name: str) -> str:
   proto=build_marshal_proto(name))
  
  
+def gen_trace(name: str) -> str:

+return f'qmp_{c_name(name)}(const char *tag, const char *json) "%s%s"\n'


This trace event is emitted in 3 different ways:
1. For arguments before calling a QMP command.
2. For the error message when the QMP command fails.
3. For the return value when a QMP command succeeds.

This makes parsing the trace akward because you get two events in
succession for a single call and they both have the same name.

Please generate 2 trace events:
1. qmp_enter_ 
2. qmp_exit_  

(That's similar to how the syscalls Linux kernel trace events work.)

Scripts processing the trace can easily differentiate between enter
(args) and exit (return value) events without parsing or keeping state
to count the second event.



OK, reasonable. This also makes patch 01 not needed.


--
Best regards,
Vladimir



Re: [PATCH v2 2/4] scripts/qapi/commands: gen_commands(): add add_trace_points argument

2022-01-17 Thread Vladimir Sementsov-Ogievskiy

12.01.2022 13:50, Stefan Hajnoczi wrote:

On Tue, Jan 11, 2022 at 07:32:52PM -0500, John Snow wrote:

On Tue, Jan 11, 2022 at 6:53 PM John Snow  wrote:


On Thu, Dec 23, 2021 at 6:08 AM Vladimir Sementsov-Ogievskiy
 wrote:


Add possibility to generate trace points for each qmp command.

We should generate both trace points and trace-events file, for further
trace point code generation.

Signed-off-by: Vladimir Sementsov-Ogievskiy 
---
  scripts/qapi/commands.py | 84 ++--
  1 file changed, 73 insertions(+), 11 deletions(-)

diff --git a/scripts/qapi/commands.py b/scripts/qapi/commands.py
index 21001bbd6b..9691c11f96 100644
--- a/scripts/qapi/commands.py
+++ b/scripts/qapi/commands.py
@@ -53,7 +53,8 @@ def gen_command_decl(name: str,
  def gen_call(name: str,
   arg_type: Optional[QAPISchemaObjectType],
   boxed: bool,
- ret_type: Optional[QAPISchemaType]) -> str:
+ ret_type: Optional[QAPISchemaType],
+ add_trace_points: bool) -> str:
  ret = ''

  argstr = ''
@@ -71,21 +72,65 @@ def gen_call(name: str,
  if ret_type:
  lhs = 'retval = '

-ret = mcgen('''
+qmp_name = f'qmp_{c_name(name)}'
+upper = qmp_name.upper()
+
+if add_trace_points:
+ret += mcgen('''
+
+if (trace_event_get_state_backends(TRACE_%(upper)s)) {
+g_autoptr(GString) req_json = qobject_to_json(QOBJECT(args));
+trace_%(qmp_name)s("", req_json->str);
+}
+''',
+ upper=upper, qmp_name=qmp_name)
+
+ret += mcgen('''

  %(lhs)sqmp_%(c_name)s(%(args)s&err);
-error_propagate(errp, err);
  ''',
  c_name=c_name(name), args=argstr, lhs=lhs)
-if ret_type:
-ret += mcgen('''
+
+ret += mcgen('''
  if (err) {
+''')
+
+if add_trace_points:
+ret += mcgen('''
+trace_%(qmp_name)s("FAIL: ", error_get_pretty(err));
+''',
+ qmp_name=qmp_name)
+
+ret += mcgen('''
+error_propagate(errp, err);
  goto out;
  }
+''')
+
+if ret_type:
+ret += mcgen('''

  qmp_marshal_output_%(c_name)s(retval, ret, errp);
  ''',
   c_name=ret_type.c_name())
+
+if add_trace_points:
+if ret_type:
+ret += mcgen('''
+
+if (trace_event_get_state_backends(TRACE_%(upper)s)) {
+g_autoptr(GString) ret_json = qobject_to_json(*ret);
+trace_%(qmp_name)s("RET:", ret_json->str);
+}
+''',
+ upper=upper, qmp_name=qmp_name)
+else:
+ret += mcgen('''
+
+trace_%(qmp_name)s("SUCCESS", "");
+''',
+ qmp_name=qmp_name)
+
  return ret


@@ -122,10 +167,14 @@ def gen_marshal_decl(name: str) -> str:
   proto=build_marshal_proto(name))


+def gen_trace(name: str) -> str:
+return f'qmp_{c_name(name)}(const char *tag, const char *json) "%s%s"\n'
+
  def gen_marshal(name: str,
  arg_type: Optional[QAPISchemaObjectType],
  boxed: bool,
-ret_type: Optional[QAPISchemaType]) -> str:
+ret_type: Optional[QAPISchemaType],
+add_trace_points: bool) -> str:
  have_args = boxed or (arg_type and not arg_type.is_empty())
  if have_args:
  assert arg_type is not None
@@ -180,7 +229,7 @@ def gen_marshal(name: str,
  }
  ''')

-ret += gen_call(name, arg_type, boxed, ret_type)
+ret += gen_call(name, arg_type, boxed, ret_type, add_trace_points)

  ret += mcgen('''

@@ -238,11 +287,12 @@ def gen_register_command(name: str,


  class QAPISchemaGenCommandVisitor(QAPISchemaModularCVisitor):
-def __init__(self, prefix: str):
+def __init__(self, prefix: str, add_trace_points: bool):
  super().__init__(
  prefix, 'qapi-commands',
  ' * Schema-defined QAPI/QMP commands', None, __doc__)
  self._visited_ret_types: Dict[QAPIGenC, Set[QAPISchemaType]] = {}
+self.add_trace_points = add_trace_points

  def _begin_user_module(self, name: str) -> None:
  self._visited_ret_types[self._genc] = set()
@@ -261,6 +311,15 @@ def _begin_user_module(self, name: str) -> None:

  ''',
   commands=commands, visit=visit))
+
+if self.add_trace_points and c_name(commands) != 'qapi_commands':
+self._genc.add(mcgen('''
+#include "trace/trace-qapi.h"
+#include "qapi/qmp/qjson.h"
+#include "trace/trace-%(nm)s_trace_events.h"
+''',
+ nm=c_name(commands)))
+
  self._genh.add(mcgen('''
  #include "%(types)s.h"

@@ -322,7 +381,9 @@ def visit_command(self,
  with ifcontext(ifcond, self._genh, self._genc):
  self._genh.add(gen_command_decl(name, arg_type, boxed, ret_type))
  self._genh.add(gen_marshal_decl(name))
-self._genc.add(gen_marshal(name, arg_type, boxed, ret_type))
+self._genc

Re: [PATCH v2 2/4] scripts/qapi/commands: gen_commands(): add add_trace_points argument

2022-01-12 Thread Stefan Hajnoczi
On Tue, Jan 11, 2022 at 07:32:52PM -0500, John Snow wrote:
> On Tue, Jan 11, 2022 at 6:53 PM John Snow  wrote:
> >
> > On Thu, Dec 23, 2021 at 6:08 AM Vladimir Sementsov-Ogievskiy
> >  wrote:
> > >
> > > Add possibility to generate trace points for each qmp command.
> > >
> > > We should generate both trace points and trace-events file, for further
> > > trace point code generation.
> > >
> > > Signed-off-by: Vladimir Sementsov-Ogievskiy 
> > > ---
> > >  scripts/qapi/commands.py | 84 ++--
> > >  1 file changed, 73 insertions(+), 11 deletions(-)
> > >
> > > diff --git a/scripts/qapi/commands.py b/scripts/qapi/commands.py
> > > index 21001bbd6b..9691c11f96 100644
> > > --- a/scripts/qapi/commands.py
> > > +++ b/scripts/qapi/commands.py
> > > @@ -53,7 +53,8 @@ def gen_command_decl(name: str,
> > >  def gen_call(name: str,
> > >   arg_type: Optional[QAPISchemaObjectType],
> > >   boxed: bool,
> > > - ret_type: Optional[QAPISchemaType]) -> str:
> > > + ret_type: Optional[QAPISchemaType],
> > > + add_trace_points: bool) -> str:
> > >  ret = ''
> > >
> > >  argstr = ''
> > > @@ -71,21 +72,65 @@ def gen_call(name: str,
> > >  if ret_type:
> > >  lhs = 'retval = '
> > >
> > > -ret = mcgen('''
> > > +qmp_name = f'qmp_{c_name(name)}'
> > > +upper = qmp_name.upper()
> > > +
> > > +if add_trace_points:
> > > +ret += mcgen('''
> > > +
> > > +if (trace_event_get_state_backends(TRACE_%(upper)s)) {
> > > +g_autoptr(GString) req_json = qobject_to_json(QOBJECT(args));
> > > +trace_%(qmp_name)s("", req_json->str);
> > > +}
> > > +''',
> > > + upper=upper, qmp_name=qmp_name)
> > > +
> > > +ret += mcgen('''
> > >
> > >  %(lhs)sqmp_%(c_name)s(%(args)s&err);
> > > -error_propagate(errp, err);
> > >  ''',
> > >  c_name=c_name(name), args=argstr, lhs=lhs)
> > > -if ret_type:
> > > -ret += mcgen('''
> > > +
> > > +ret += mcgen('''
> > >  if (err) {
> > > +''')
> > > +
> > > +if add_trace_points:
> > > +ret += mcgen('''
> > > +trace_%(qmp_name)s("FAIL: ", error_get_pretty(err));
> > > +''',
> > > + qmp_name=qmp_name)
> > > +
> > > +ret += mcgen('''
> > > +error_propagate(errp, err);
> > >  goto out;
> > >  }
> > > +''')
> > > +
> > > +if ret_type:
> > > +ret += mcgen('''
> > >
> > >  qmp_marshal_output_%(c_name)s(retval, ret, errp);
> > >  ''',
> > >   c_name=ret_type.c_name())
> > > +
> > > +if add_trace_points:
> > > +if ret_type:
> > > +ret += mcgen('''
> > > +
> > > +if (trace_event_get_state_backends(TRACE_%(upper)s)) {
> > > +g_autoptr(GString) ret_json = qobject_to_json(*ret);
> > > +trace_%(qmp_name)s("RET:", ret_json->str);
> > > +}
> > > +''',
> > > + upper=upper, qmp_name=qmp_name)
> > > +else:
> > > +ret += mcgen('''
> > > +
> > > +trace_%(qmp_name)s("SUCCESS", "");
> > > +''',
> > > + qmp_name=qmp_name)
> > > +
> > >  return ret
> > >
> > >
> > > @@ -122,10 +167,14 @@ def gen_marshal_decl(name: str) -> str:
> > >   proto=build_marshal_proto(name))
> > >
> > >
> > > +def gen_trace(name: str) -> str:
> > > +return f'qmp_{c_name(name)}(const char *tag, const char *json) 
> > > "%s%s"\n'
> > > +
> > >  def gen_marshal(name: str,
> > >  arg_type: Optional[QAPISchemaObjectType],
> > >  boxed: bool,
> > > -ret_type: Optional[QAPISchemaType]) -> str:
> > > +ret_type: Optional[QAPISchemaType],
> > > +add_trace_points: bool) -> str:
> > >  have_args = boxed or (arg_type and not arg_type.is_empty())
> > >  if have_args:
> > >  assert arg_type is not None
> > > @@ -180,7 +229,7 @@ def gen_marshal(name: str,
> > >  }
> > >  ''')
> > >
> > > -ret += gen_call(name, arg_type, boxed, ret_type)
> > > +ret += gen_call(name, arg_type, boxed, ret_type, add_trace_points)
> > >
> > >  ret += mcgen('''
> > >
> > > @@ -238,11 +287,12 @@ def gen_register_command(name: str,
> > >
> > >
> > >  class QAPISchemaGenCommandVisitor(QAPISchemaModularCVisitor):
> > > -def __init__(self, prefix: str):
> > > +def __init__(self, prefix: str, add_trace_points: bool):
> > >  super().__init__(
> > >  prefix, 'qapi-commands',
> > >  ' * Schema-defined QAPI/QMP commands', None, __doc__)
> > >  self._visited_ret_types: Dict[QAPIGenC, Set[QAPISchemaType]] = {}
> > > +self.add_trace_points = add_trace_points
> > >
> > >  def _begin_user_module(self, name: str) -> None:
> > >  self._visited_ret_types[self._genc] = set()
> > > @@ -261,6 +311,15 @@ def _begin_user_module(self, name: str) -> None:
> > >
> > >  ''',
> 

Re: [PATCH v2 2/4] scripts/qapi/commands: gen_commands(): add add_trace_points argument

2022-01-11 Thread John Snow
On Tue, Jan 11, 2022 at 6:53 PM John Snow  wrote:
>
> On Thu, Dec 23, 2021 at 6:08 AM Vladimir Sementsov-Ogievskiy
>  wrote:
> >
> > Add possibility to generate trace points for each qmp command.
> >
> > We should generate both trace points and trace-events file, for further
> > trace point code generation.
> >
> > Signed-off-by: Vladimir Sementsov-Ogievskiy 
> > ---
> >  scripts/qapi/commands.py | 84 ++--
> >  1 file changed, 73 insertions(+), 11 deletions(-)
> >
> > diff --git a/scripts/qapi/commands.py b/scripts/qapi/commands.py
> > index 21001bbd6b..9691c11f96 100644
> > --- a/scripts/qapi/commands.py
> > +++ b/scripts/qapi/commands.py
> > @@ -53,7 +53,8 @@ def gen_command_decl(name: str,
> >  def gen_call(name: str,
> >   arg_type: Optional[QAPISchemaObjectType],
> >   boxed: bool,
> > - ret_type: Optional[QAPISchemaType]) -> str:
> > + ret_type: Optional[QAPISchemaType],
> > + add_trace_points: bool) -> str:
> >  ret = ''
> >
> >  argstr = ''
> > @@ -71,21 +72,65 @@ def gen_call(name: str,
> >  if ret_type:
> >  lhs = 'retval = '
> >
> > -ret = mcgen('''
> > +qmp_name = f'qmp_{c_name(name)}'
> > +upper = qmp_name.upper()
> > +
> > +if add_trace_points:
> > +ret += mcgen('''
> > +
> > +if (trace_event_get_state_backends(TRACE_%(upper)s)) {
> > +g_autoptr(GString) req_json = qobject_to_json(QOBJECT(args));
> > +trace_%(qmp_name)s("", req_json->str);
> > +}
> > +''',
> > + upper=upper, qmp_name=qmp_name)
> > +
> > +ret += mcgen('''
> >
> >  %(lhs)sqmp_%(c_name)s(%(args)s&err);
> > -error_propagate(errp, err);
> >  ''',
> >  c_name=c_name(name), args=argstr, lhs=lhs)
> > -if ret_type:
> > -ret += mcgen('''
> > +
> > +ret += mcgen('''
> >  if (err) {
> > +''')
> > +
> > +if add_trace_points:
> > +ret += mcgen('''
> > +trace_%(qmp_name)s("FAIL: ", error_get_pretty(err));
> > +''',
> > + qmp_name=qmp_name)
> > +
> > +ret += mcgen('''
> > +error_propagate(errp, err);
> >  goto out;
> >  }
> > +''')
> > +
> > +if ret_type:
> > +ret += mcgen('''
> >
> >  qmp_marshal_output_%(c_name)s(retval, ret, errp);
> >  ''',
> >   c_name=ret_type.c_name())
> > +
> > +if add_trace_points:
> > +if ret_type:
> > +ret += mcgen('''
> > +
> > +if (trace_event_get_state_backends(TRACE_%(upper)s)) {
> > +g_autoptr(GString) ret_json = qobject_to_json(*ret);
> > +trace_%(qmp_name)s("RET:", ret_json->str);
> > +}
> > +''',
> > + upper=upper, qmp_name=qmp_name)
> > +else:
> > +ret += mcgen('''
> > +
> > +trace_%(qmp_name)s("SUCCESS", "");
> > +''',
> > + qmp_name=qmp_name)
> > +
> >  return ret
> >
> >
> > @@ -122,10 +167,14 @@ def gen_marshal_decl(name: str) -> str:
> >   proto=build_marshal_proto(name))
> >
> >
> > +def gen_trace(name: str) -> str:
> > +return f'qmp_{c_name(name)}(const char *tag, const char *json) 
> > "%s%s"\n'
> > +
> >  def gen_marshal(name: str,
> >  arg_type: Optional[QAPISchemaObjectType],
> >  boxed: bool,
> > -ret_type: Optional[QAPISchemaType]) -> str:
> > +ret_type: Optional[QAPISchemaType],
> > +add_trace_points: bool) -> str:
> >  have_args = boxed or (arg_type and not arg_type.is_empty())
> >  if have_args:
> >  assert arg_type is not None
> > @@ -180,7 +229,7 @@ def gen_marshal(name: str,
> >  }
> >  ''')
> >
> > -ret += gen_call(name, arg_type, boxed, ret_type)
> > +ret += gen_call(name, arg_type, boxed, ret_type, add_trace_points)
> >
> >  ret += mcgen('''
> >
> > @@ -238,11 +287,12 @@ def gen_register_command(name: str,
> >
> >
> >  class QAPISchemaGenCommandVisitor(QAPISchemaModularCVisitor):
> > -def __init__(self, prefix: str):
> > +def __init__(self, prefix: str, add_trace_points: bool):
> >  super().__init__(
> >  prefix, 'qapi-commands',
> >  ' * Schema-defined QAPI/QMP commands', None, __doc__)
> >  self._visited_ret_types: Dict[QAPIGenC, Set[QAPISchemaType]] = {}
> > +self.add_trace_points = add_trace_points
> >
> >  def _begin_user_module(self, name: str) -> None:
> >  self._visited_ret_types[self._genc] = set()
> > @@ -261,6 +311,15 @@ def _begin_user_module(self, name: str) -> None:
> >
> >  ''',
> >   commands=commands, visit=visit))
> > +
> > +if self.add_trace_points and c_name(commands) != 'qapi_commands':
> > +self._genc.add(mcgen('''
> > +#include "trace/trace-qapi.h"
> > +#include "qapi/qmp/qjson.h"
> > +#include "trace/trace-%(nm)s_trace_events.h"
> > +''',
> > +  

Re: [PATCH v2 2/4] scripts/qapi/commands: gen_commands(): add add_trace_points argument

2022-01-11 Thread John Snow
On Thu, Dec 23, 2021 at 6:08 AM Vladimir Sementsov-Ogievskiy
 wrote:
>
> Add possibility to generate trace points for each qmp command.
>
> We should generate both trace points and trace-events file, for further
> trace point code generation.
>
> Signed-off-by: Vladimir Sementsov-Ogievskiy 
> ---
>  scripts/qapi/commands.py | 84 ++--
>  1 file changed, 73 insertions(+), 11 deletions(-)
>
> diff --git a/scripts/qapi/commands.py b/scripts/qapi/commands.py
> index 21001bbd6b..9691c11f96 100644
> --- a/scripts/qapi/commands.py
> +++ b/scripts/qapi/commands.py
> @@ -53,7 +53,8 @@ def gen_command_decl(name: str,
>  def gen_call(name: str,
>   arg_type: Optional[QAPISchemaObjectType],
>   boxed: bool,
> - ret_type: Optional[QAPISchemaType]) -> str:
> + ret_type: Optional[QAPISchemaType],
> + add_trace_points: bool) -> str:
>  ret = ''
>
>  argstr = ''
> @@ -71,21 +72,65 @@ def gen_call(name: str,
>  if ret_type:
>  lhs = 'retval = '
>
> -ret = mcgen('''
> +qmp_name = f'qmp_{c_name(name)}'
> +upper = qmp_name.upper()
> +
> +if add_trace_points:
> +ret += mcgen('''
> +
> +if (trace_event_get_state_backends(TRACE_%(upper)s)) {
> +g_autoptr(GString) req_json = qobject_to_json(QOBJECT(args));
> +trace_%(qmp_name)s("", req_json->str);
> +}
> +''',
> + upper=upper, qmp_name=qmp_name)
> +
> +ret += mcgen('''
>
>  %(lhs)sqmp_%(c_name)s(%(args)s&err);
> -error_propagate(errp, err);
>  ''',
>  c_name=c_name(name), args=argstr, lhs=lhs)
> -if ret_type:
> -ret += mcgen('''
> +
> +ret += mcgen('''
>  if (err) {
> +''')
> +
> +if add_trace_points:
> +ret += mcgen('''
> +trace_%(qmp_name)s("FAIL: ", error_get_pretty(err));
> +''',
> + qmp_name=qmp_name)
> +
> +ret += mcgen('''
> +error_propagate(errp, err);
>  goto out;
>  }
> +''')
> +
> +if ret_type:
> +ret += mcgen('''
>
>  qmp_marshal_output_%(c_name)s(retval, ret, errp);
>  ''',
>   c_name=ret_type.c_name())
> +
> +if add_trace_points:
> +if ret_type:
> +ret += mcgen('''
> +
> +if (trace_event_get_state_backends(TRACE_%(upper)s)) {
> +g_autoptr(GString) ret_json = qobject_to_json(*ret);
> +trace_%(qmp_name)s("RET:", ret_json->str);
> +}
> +''',
> + upper=upper, qmp_name=qmp_name)
> +else:
> +ret += mcgen('''
> +
> +trace_%(qmp_name)s("SUCCESS", "");
> +''',
> + qmp_name=qmp_name)
> +
>  return ret
>
>
> @@ -122,10 +167,14 @@ def gen_marshal_decl(name: str) -> str:
>   proto=build_marshal_proto(name))
>
>
> +def gen_trace(name: str) -> str:
> +return f'qmp_{c_name(name)}(const char *tag, const char *json) "%s%s"\n'
> +
>  def gen_marshal(name: str,
>  arg_type: Optional[QAPISchemaObjectType],
>  boxed: bool,
> -ret_type: Optional[QAPISchemaType]) -> str:
> +ret_type: Optional[QAPISchemaType],
> +add_trace_points: bool) -> str:
>  have_args = boxed or (arg_type and not arg_type.is_empty())
>  if have_args:
>  assert arg_type is not None
> @@ -180,7 +229,7 @@ def gen_marshal(name: str,
>  }
>  ''')
>
> -ret += gen_call(name, arg_type, boxed, ret_type)
> +ret += gen_call(name, arg_type, boxed, ret_type, add_trace_points)
>
>  ret += mcgen('''
>
> @@ -238,11 +287,12 @@ def gen_register_command(name: str,
>
>
>  class QAPISchemaGenCommandVisitor(QAPISchemaModularCVisitor):
> -def __init__(self, prefix: str):
> +def __init__(self, prefix: str, add_trace_points: bool):
>  super().__init__(
>  prefix, 'qapi-commands',
>  ' * Schema-defined QAPI/QMP commands', None, __doc__)
>  self._visited_ret_types: Dict[QAPIGenC, Set[QAPISchemaType]] = {}
> +self.add_trace_points = add_trace_points
>
>  def _begin_user_module(self, name: str) -> None:
>  self._visited_ret_types[self._genc] = set()
> @@ -261,6 +311,15 @@ def _begin_user_module(self, name: str) -> None:
>
>  ''',
>   commands=commands, visit=visit))
> +
> +if self.add_trace_points and c_name(commands) != 'qapi_commands':
> +self._genc.add(mcgen('''
> +#include "trace/trace-qapi.h"
> +#include "qapi/qmp/qjson.h"
> +#include "trace/trace-%(nm)s_trace_events.h"
> +''',
> + nm=c_name(commands)))
> +
>  self._genh.add(mcgen('''
>  #include "%(types)s.h"
>
> @@ -322,7 +381,9 @@ def visit_command(self,
>  with ifcontext(ifcond, self._genh, self._genc):
>  self._genh.add(gen_command_decl(name, arg_type, boxed, ret_type))
>  self._genh.add(gen_marshal_decl(name))
> - 

Re: [PATCH v2 2/4] scripts/qapi/commands: gen_commands(): add add_trace_points argument

2022-01-10 Thread Stefan Hajnoczi
On Thu, Dec 23, 2021 at 12:07:54PM +0100, Vladimir Sementsov-Ogievskiy wrote:
> Add possibility to generate trace points for each qmp command.
> 
> We should generate both trace points and trace-events file, for further
> trace point code generation.
> 
> Signed-off-by: Vladimir Sementsov-Ogievskiy 
> ---
>  scripts/qapi/commands.py | 84 ++--
>  1 file changed, 73 insertions(+), 11 deletions(-)
> 
> diff --git a/scripts/qapi/commands.py b/scripts/qapi/commands.py
> index 21001bbd6b..9691c11f96 100644
> --- a/scripts/qapi/commands.py
> +++ b/scripts/qapi/commands.py
> @@ -53,7 +53,8 @@ def gen_command_decl(name: str,
>  def gen_call(name: str,
>   arg_type: Optional[QAPISchemaObjectType],
>   boxed: bool,
> - ret_type: Optional[QAPISchemaType]) -> str:
> + ret_type: Optional[QAPISchemaType],
> + add_trace_points: bool) -> str:

Please use the term "trace events" instead of "trace points". That's the
term that docs/devel/tracing.rst uses.

> @@ -122,10 +167,14 @@ def gen_marshal_decl(name: str) -> str:
>   proto=build_marshal_proto(name))
>  
>  
> +def gen_trace(name: str) -> str:
> +return f'qmp_{c_name(name)}(const char *tag, const char *json) "%s%s"\n'

This trace event is emitted in 3 different ways:
1. For arguments before calling a QMP command.
2. For the error message when the QMP command fails.
3. For the return value when a QMP command succeeds.

This makes parsing the trace akward because you get two events in
succession for a single call and they both have the same name.

Please generate 2 trace events:
1. qmp_enter_ 
2. qmp_exit_  

(That's similar to how the syscalls Linux kernel trace events work.)

Scripts processing the trace can easily differentiate between enter
(args) and exit (return value) events without parsing or keeping state
to count the second event.

Thanks,
Stefan


signature.asc
Description: PGP signature


[PATCH v2 2/4] scripts/qapi/commands: gen_commands(): add add_trace_points argument

2021-12-23 Thread Vladimir Sementsov-Ogievskiy
Add possibility to generate trace points for each qmp command.

We should generate both trace points and trace-events file, for further
trace point code generation.

Signed-off-by: Vladimir Sementsov-Ogievskiy 
---
 scripts/qapi/commands.py | 84 ++--
 1 file changed, 73 insertions(+), 11 deletions(-)

diff --git a/scripts/qapi/commands.py b/scripts/qapi/commands.py
index 21001bbd6b..9691c11f96 100644
--- a/scripts/qapi/commands.py
+++ b/scripts/qapi/commands.py
@@ -53,7 +53,8 @@ def gen_command_decl(name: str,
 def gen_call(name: str,
  arg_type: Optional[QAPISchemaObjectType],
  boxed: bool,
- ret_type: Optional[QAPISchemaType]) -> str:
+ ret_type: Optional[QAPISchemaType],
+ add_trace_points: bool) -> str:
 ret = ''
 
 argstr = ''
@@ -71,21 +72,65 @@ def gen_call(name: str,
 if ret_type:
 lhs = 'retval = '
 
-ret = mcgen('''
+qmp_name = f'qmp_{c_name(name)}'
+upper = qmp_name.upper()
+
+if add_trace_points:
+ret += mcgen('''
+
+if (trace_event_get_state_backends(TRACE_%(upper)s)) {
+g_autoptr(GString) req_json = qobject_to_json(QOBJECT(args));
+trace_%(qmp_name)s("", req_json->str);
+}
+''',
+ upper=upper, qmp_name=qmp_name)
+
+ret += mcgen('''
 
 %(lhs)sqmp_%(c_name)s(%(args)s&err);
-error_propagate(errp, err);
 ''',
 c_name=c_name(name), args=argstr, lhs=lhs)
-if ret_type:
-ret += mcgen('''
+
+ret += mcgen('''
 if (err) {
+''')
+
+if add_trace_points:
+ret += mcgen('''
+trace_%(qmp_name)s("FAIL: ", error_get_pretty(err));
+''',
+ qmp_name=qmp_name)
+
+ret += mcgen('''
+error_propagate(errp, err);
 goto out;
 }
+''')
+
+if ret_type:
+ret += mcgen('''
 
 qmp_marshal_output_%(c_name)s(retval, ret, errp);
 ''',
  c_name=ret_type.c_name())
+
+if add_trace_points:
+if ret_type:
+ret += mcgen('''
+
+if (trace_event_get_state_backends(TRACE_%(upper)s)) {
+g_autoptr(GString) ret_json = qobject_to_json(*ret);
+trace_%(qmp_name)s("RET:", ret_json->str);
+}
+''',
+ upper=upper, qmp_name=qmp_name)
+else:
+ret += mcgen('''
+
+trace_%(qmp_name)s("SUCCESS", "");
+''',
+ qmp_name=qmp_name)
+
 return ret
 
 
@@ -122,10 +167,14 @@ def gen_marshal_decl(name: str) -> str:
  proto=build_marshal_proto(name))
 
 
+def gen_trace(name: str) -> str:
+return f'qmp_{c_name(name)}(const char *tag, const char *json) "%s%s"\n'
+
 def gen_marshal(name: str,
 arg_type: Optional[QAPISchemaObjectType],
 boxed: bool,
-ret_type: Optional[QAPISchemaType]) -> str:
+ret_type: Optional[QAPISchemaType],
+add_trace_points: bool) -> str:
 have_args = boxed or (arg_type and not arg_type.is_empty())
 if have_args:
 assert arg_type is not None
@@ -180,7 +229,7 @@ def gen_marshal(name: str,
 }
 ''')
 
-ret += gen_call(name, arg_type, boxed, ret_type)
+ret += gen_call(name, arg_type, boxed, ret_type, add_trace_points)
 
 ret += mcgen('''
 
@@ -238,11 +287,12 @@ def gen_register_command(name: str,
 
 
 class QAPISchemaGenCommandVisitor(QAPISchemaModularCVisitor):
-def __init__(self, prefix: str):
+def __init__(self, prefix: str, add_trace_points: bool):
 super().__init__(
 prefix, 'qapi-commands',
 ' * Schema-defined QAPI/QMP commands', None, __doc__)
 self._visited_ret_types: Dict[QAPIGenC, Set[QAPISchemaType]] = {}
+self.add_trace_points = add_trace_points
 
 def _begin_user_module(self, name: str) -> None:
 self._visited_ret_types[self._genc] = set()
@@ -261,6 +311,15 @@ def _begin_user_module(self, name: str) -> None:
 
 ''',
  commands=commands, visit=visit))
+
+if self.add_trace_points and c_name(commands) != 'qapi_commands':
+self._genc.add(mcgen('''
+#include "trace/trace-qapi.h"
+#include "qapi/qmp/qjson.h"
+#include "trace/trace-%(nm)s_trace_events.h"
+''',
+ nm=c_name(commands)))
+
 self._genh.add(mcgen('''
 #include "%(types)s.h"
 
@@ -322,7 +381,9 @@ def visit_command(self,
 with ifcontext(ifcond, self._genh, self._genc):
 self._genh.add(gen_command_decl(name, arg_type, boxed, ret_type))
 self._genh.add(gen_marshal_decl(name))
-self._genc.add(gen_marshal(name, arg_type, boxed, ret_type))
+self._genc.add(gen_marshal(name, arg_type, boxed, ret_type,
+   self.add_trace_points))
+self._gent.add(gen_trace(name))
 with self._temp_module('./init'):
 with ifcontext(ifcond, self._genh, sel