yeahuh / rpms / qemu-kvm

Forked from rpms/qemu-kvm 2 years ago
Clone

Blame SOURCES/kvm-qjson-surprise-allocating-6-QObjects-per-token-is-ex.patch

9ae3a8
From 7bef5fab7d59aa9a6a1eb6ea747ba04811bc01e2 Mon Sep 17 00:00:00 2001
9ae3a8
From: Markus Armbruster <armbru@redhat.com>
9ae3a8
Date: Wed, 27 Jul 2016 07:35:10 +0200
9ae3a8
Subject: [PATCH 12/16] qjson: surprise, allocating 6 QObjects per token is
9ae3a8
 expensive
9ae3a8
9ae3a8
RH-Author: Markus Armbruster <armbru@redhat.com>
9ae3a8
Message-id: <1469604913-12442-14-git-send-email-armbru@redhat.com>
9ae3a8
Patchwork-id: 71475
9ae3a8
O-Subject: [RHEL-7.3 qemu-kvm PATCH v2 12/15] qjson: surprise, allocating 6 QObjects per token is expensive
9ae3a8
Bugzilla: 1276036
9ae3a8
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
9ae3a8
RH-Acked-by: John Snow <jsnow@redhat.com>
9ae3a8
RH-Acked-by: Paolo Bonzini <pbonzini@redhat.com>
9ae3a8
9ae3a8
From: Paolo Bonzini <pbonzini@redhat.com>
9ae3a8
9ae3a8
Replace the contents of the tokens GQueue with a simple struct.  This cuts
9ae3a8
the amount of memory allocated by tests/check-qjson from ~500MB to ~20MB,
9ae3a8
and the execution time from 600ms to 80ms on my laptop.  Still a lot (some
9ae3a8
could be saved by using an intrusive list, such as QSIMPLEQ, instead of
9ae3a8
the GQueue), but the savings are already massive and the right thing to
9ae3a8
do would probably be to get rid of json-streamer completely.
9ae3a8
9ae3a8
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
9ae3a8
Message-Id: <1448300659-23559-5-git-send-email-pbonzini@redhat.com>
9ae3a8
[Straightforwardly rebased on my patches]
9ae3a8
Signed-off-by: Markus Armbruster <armbru@redhat.com>
9ae3a8
Reviewed-by: Eric Blake <eblake@redhat.com>
9ae3a8
(cherry picked from commit 9bada8971173345ceb37ed1a47b00a01a4dd48cf)
9ae3a8
9ae3a8
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
9ae3a8
9ae3a8
Conflicts:
9ae3a8
	qobject/json-parser.c
9ae3a8
9ae3a8
Straighforward conflicts because lacking commit fc48ffc "qobject: Use
9ae3a8
'bool' for qbool", we still use qbool_from_int(), and we lack commit
9ae3a8
e549e71 "json-parser: Accept 'null' in QMP".
9ae3a8
9ae3a8
Signed-off-by: Markus Armbruster <armbru@redhat.com>
9ae3a8
---
9ae3a8
 include/qapi/qmp/json-streamer.h |   7 +++
9ae3a8
 qobject/json-parser.c            | 113 ++++++++++++++++-----------------------
9ae3a8
 qobject/json-streamer.c          |  19 +++----
9ae3a8
 3 files changed, 62 insertions(+), 77 deletions(-)
9ae3a8
9ae3a8
diff --git a/include/qapi/qmp/json-streamer.h b/include/qapi/qmp/json-streamer.h
9ae3a8
index e9f2937..09b3d3e 100644
9ae3a8
--- a/include/qapi/qmp/json-streamer.h
9ae3a8
+++ b/include/qapi/qmp/json-streamer.h
9ae3a8
@@ -18,6 +18,13 @@
9ae3a8
 #include "glib-compat.h"
9ae3a8
 #include "qapi/qmp/json-lexer.h"
9ae3a8
 
9ae3a8
+typedef struct JSONToken {
9ae3a8
+    int type;
9ae3a8
+    int x;
9ae3a8
+    int y;
9ae3a8
+    char str[];
9ae3a8
+} JSONToken;
9ae3a8
+
9ae3a8
 typedef struct JSONMessageParser
9ae3a8
 {
9ae3a8
     void (*emit)(struct JSONMessageParser *parser, GQueue *tokens);
9ae3a8
diff --git a/qobject/json-parser.c b/qobject/json-parser.c
9ae3a8
index 6e5e257..944e1a1 100644
9ae3a8
--- a/qobject/json-parser.c
9ae3a8
+++ b/qobject/json-parser.c
9ae3a8
@@ -23,11 +23,12 @@
9ae3a8
 #include "qapi/qmp/json-parser.h"
9ae3a8
 #include "qapi/qmp/json-lexer.h"
9ae3a8
 #include "qapi/qmp/qerror.h"
9ae3a8
+#include "qapi/qmp/json-streamer.h"
9ae3a8
 
9ae3a8
 typedef struct JSONParserContext
9ae3a8
 {
9ae3a8
     Error *err;
9ae3a8
-    QObject *current;
9ae3a8
+    JSONToken *current;
9ae3a8
     GQueue *buf;
9ae3a8
 } JSONParserContext;
9ae3a8
 
9ae3a8
@@ -45,27 +46,10 @@ typedef struct JSONParserContext
9ae3a8
 static QObject *parse_value(JSONParserContext *ctxt, va_list *ap);
9ae3a8
 
9ae3a8
 /**
9ae3a8
- * Token manipulators
9ae3a8
- *
9ae3a8
- * tokens are dictionaries that contain a type, a string value, and geometry information
9ae3a8
- * about a token identified by the lexer.  These are routines that make working with
9ae3a8
- * these objects a bit easier.
9ae3a8
- */
9ae3a8
-static const char *token_get_value(QObject *obj)
9ae3a8
-{
9ae3a8
-    return qdict_get_str(qobject_to_qdict(obj), "token");
9ae3a8
-}
9ae3a8
-
9ae3a8
-static JSONTokenType token_get_type(QObject *obj)
9ae3a8
-{
9ae3a8
-    return qdict_get_int(qobject_to_qdict(obj), "type");
9ae3a8
-}
9ae3a8
-
9ae3a8
-/**
9ae3a8
  * Error handler
9ae3a8
  */
9ae3a8
 static void GCC_FMT_ATTR(3, 4) parse_error(JSONParserContext *ctxt,
9ae3a8
-                                           QObject *token, const char *msg, ...)
9ae3a8
+                                           JSONToken *token, const char *msg, ...)
9ae3a8
 {
9ae3a8
     va_list ap;
9ae3a8
     char message[1024];
9ae3a8
@@ -143,9 +127,10 @@ static int hex2decimal(char ch)
9ae3a8
  *      \t
9ae3a8
  *      \u four-hex-digits 
9ae3a8
  */
9ae3a8
-static QString *qstring_from_escaped_str(JSONParserContext *ctxt, QObject *token)
9ae3a8
+static QString *qstring_from_escaped_str(JSONParserContext *ctxt,
9ae3a8
+                                         JSONToken *token)
9ae3a8
 {
9ae3a8
-    const char *ptr = token_get_value(token);
9ae3a8
+    const char *ptr = token->str;
9ae3a8
     QString *str;
9ae3a8
     int double_quote = 1;
9ae3a8
 
9ae3a8
@@ -241,19 +226,19 @@ out:
9ae3a8
     return NULL;
9ae3a8
 }
9ae3a8
 
9ae3a8
-/* Note: unless the token object returned by parser_context_peek_token
9ae3a8
- * or parser_context_pop_token is explicitly incref'd, it will be
9ae3a8
- * deleted as soon as parser_context_pop_token is called again.
9ae3a8
+/* Note: the token object returned by parser_context_peek_token or
9ae3a8
+ * parser_context_pop_token is deleted as soon as parser_context_pop_token
9ae3a8
+ * is called again.
9ae3a8
  */
9ae3a8
-static QObject *parser_context_pop_token(JSONParserContext *ctxt)
9ae3a8
+static JSONToken *parser_context_pop_token(JSONParserContext *ctxt)
9ae3a8
 {
9ae3a8
-    qobject_decref(ctxt->current);
9ae3a8
+    g_free(ctxt->current);
9ae3a8
     assert(!g_queue_is_empty(ctxt->buf));
9ae3a8
     ctxt->current = g_queue_pop_head(ctxt->buf);
9ae3a8
     return ctxt->current;
9ae3a8
 }
9ae3a8
 
9ae3a8
-static QObject *parser_context_peek_token(JSONParserContext *ctxt)
9ae3a8
+static JSONToken *parser_context_peek_token(JSONParserContext *ctxt)
9ae3a8
 {
9ae3a8
     assert(!g_queue_is_empty(ctxt->buf));
9ae3a8
     return g_queue_peek_head(ctxt->buf);
9ae3a8
@@ -280,7 +265,7 @@ static void parser_context_free(JSONParserContext *ctxt)
9ae3a8
         while (!g_queue_is_empty(ctxt->buf)) {
9ae3a8
             parser_context_pop_token(ctxt);
9ae3a8
         }
9ae3a8
-        qobject_decref(ctxt->current);
9ae3a8
+        g_free(ctxt->current);
9ae3a8
         g_queue_free(ctxt->buf);
9ae3a8
         g_free(ctxt);
9ae3a8
     }
9ae3a8
@@ -291,7 +276,8 @@ static void parser_context_free(JSONParserContext *ctxt)
9ae3a8
  */
9ae3a8
 static int parse_pair(JSONParserContext *ctxt, QDict *dict, va_list *ap)
9ae3a8
 {
9ae3a8
-    QObject *key = NULL, *token = NULL, *value, *peek;
9ae3a8
+    QObject *key = NULL, *value;
9ae3a8
+    JSONToken *peek, *token;
9ae3a8
 
9ae3a8
     peek = parser_context_peek_token(ctxt);
9ae3a8
     if (peek == NULL) {
9ae3a8
@@ -311,7 +297,7 @@ static int parse_pair(JSONParserContext *ctxt, QDict *dict, va_list *ap)
9ae3a8
         goto out;
9ae3a8
     }
9ae3a8
 
9ae3a8
-    if (token_get_type(token) != JSON_COLON) {
9ae3a8
+    if (token->type != JSON_COLON) {
9ae3a8
         parse_error(ctxt, token, "missing : in object pair");
9ae3a8
         goto out;
9ae3a8
     }
9ae3a8
@@ -337,10 +323,10 @@ out:
9ae3a8
 static QObject *parse_object(JSONParserContext *ctxt, va_list *ap)
9ae3a8
 {
9ae3a8
     QDict *dict = NULL;
9ae3a8
-    QObject *token, *peek;
9ae3a8
+    JSONToken *token, *peek;
9ae3a8
 
9ae3a8
     token = parser_context_pop_token(ctxt);
9ae3a8
-    assert(token && token_get_type(token) == JSON_LCURLY);
9ae3a8
+    assert(token && token->type == JSON_LCURLY);
9ae3a8
 
9ae3a8
     dict = qdict_new();
9ae3a8
 
9ae3a8
@@ -350,7 +336,7 @@ static QObject *parse_object(JSONParserContext *ctxt, va_list *ap)
9ae3a8
         goto out;
9ae3a8
     }
9ae3a8
 
9ae3a8
-    if (token_get_type(peek) != JSON_RCURLY) {
9ae3a8
+    if (peek->type != JSON_RCURLY) {
9ae3a8
         if (parse_pair(ctxt, dict, ap) == -1) {
9ae3a8
             goto out;
9ae3a8
         }
9ae3a8
@@ -361,8 +347,8 @@ static QObject *parse_object(JSONParserContext *ctxt, va_list *ap)
9ae3a8
             goto out;
9ae3a8
         }
9ae3a8
 
9ae3a8
-        while (token_get_type(token) != JSON_RCURLY) {
9ae3a8
-            if (token_get_type(token) != JSON_COMMA) {
9ae3a8
+        while (token->type != JSON_RCURLY) {
9ae3a8
+            if (token->type != JSON_COMMA) {
9ae3a8
                 parse_error(ctxt, token, "expected separator in dict");
9ae3a8
                 goto out;
9ae3a8
             }
9ae3a8
@@ -391,10 +377,10 @@ out:
9ae3a8
 static QObject *parse_array(JSONParserContext *ctxt, va_list *ap)
9ae3a8
 {
9ae3a8
     QList *list = NULL;
9ae3a8
-    QObject *token, *peek;
9ae3a8
+    JSONToken *token, *peek;
9ae3a8
 
9ae3a8
     token = parser_context_pop_token(ctxt);
9ae3a8
-    assert(token && token_get_type(token) == JSON_LSQUARE);
9ae3a8
+    assert(token && token->type == JSON_LSQUARE);
9ae3a8
 
9ae3a8
     list = qlist_new();
9ae3a8
 
9ae3a8
@@ -404,7 +390,7 @@ static QObject *parse_array(JSONParserContext *ctxt, va_list *ap)
9ae3a8
         goto out;
9ae3a8
     }
9ae3a8
 
9ae3a8
-    if (token_get_type(peek) != JSON_RSQUARE) {
9ae3a8
+    if (peek->type != JSON_RSQUARE) {
9ae3a8
         QObject *obj;
9ae3a8
 
9ae3a8
         obj = parse_value(ctxt, ap);
9ae3a8
@@ -421,8 +407,8 @@ static QObject *parse_array(JSONParserContext *ctxt, va_list *ap)
9ae3a8
             goto out;
9ae3a8
         }
9ae3a8
 
9ae3a8
-        while (token_get_type(token) != JSON_RSQUARE) {
9ae3a8
-            if (token_get_type(token) != JSON_COMMA) {
9ae3a8
+        while (token->type != JSON_RSQUARE) {
9ae3a8
+            if (token->type != JSON_COMMA) {
9ae3a8
                 parse_error(ctxt, token, "expected separator in list");
9ae3a8
                 goto out;
9ae3a8
             }
9ae3a8
@@ -454,49 +440,45 @@ out:
9ae3a8
 
9ae3a8
 static QObject *parse_keyword(JSONParserContext *ctxt)
9ae3a8
 {
9ae3a8
-    QObject *token;
9ae3a8
-    const char *val;
9ae3a8
+    JSONToken *token;
9ae3a8
 
9ae3a8
     token = parser_context_pop_token(ctxt);
9ae3a8
-    assert(token && token_get_type(token) == JSON_KEYWORD);
9ae3a8
-    val = token_get_value(token);
9ae3a8
+    assert(token && token->type == JSON_KEYWORD);
9ae3a8
 
9ae3a8
-    if (!strcmp(val, "true")) {
9ae3a8
+    if (!strcmp(token->str, "true")) {
9ae3a8
         return QOBJECT(qbool_from_int(true));
9ae3a8
-    } else if (!strcmp(val, "false")) {
9ae3a8
+    } else if (!strcmp(token->str, "false")) {
9ae3a8
         return QOBJECT(qbool_from_int(false));
9ae3a8
     }
9ae3a8
-    parse_error(ctxt, token, "invalid keyword '%s'", val);
9ae3a8
+    parse_error(ctxt, token, "invalid keyword '%s'", token->str);
9ae3a8
     return NULL;
9ae3a8
 }
9ae3a8
 
9ae3a8
 static QObject *parse_escape(JSONParserContext *ctxt, va_list *ap)
9ae3a8
 {
9ae3a8
-    QObject *token;
9ae3a8
-    const char *val;
9ae3a8
+    JSONToken *token;
9ae3a8
 
9ae3a8
     if (ap == NULL) {
9ae3a8
         return NULL;
9ae3a8
     }
9ae3a8
 
9ae3a8
     token = parser_context_pop_token(ctxt);
9ae3a8
-    assert(token && token_get_type(token) == JSON_ESCAPE);
9ae3a8
-    val = token_get_value(token);
9ae3a8
+    assert(token && token->type == JSON_ESCAPE);
9ae3a8
 
9ae3a8
-    if (!strcmp(val, "%p")) {
9ae3a8
+    if (!strcmp(token->str, "%p")) {
9ae3a8
         return va_arg(*ap, QObject *);
9ae3a8
-    } else if (!strcmp(val, "%i")) {
9ae3a8
+    } else if (!strcmp(token->str, "%i")) {
9ae3a8
         return QOBJECT(qbool_from_int(va_arg(*ap, int)));
9ae3a8
-    } else if (!strcmp(val, "%d")) {
9ae3a8
+    } else if (!strcmp(token->str, "%d")) {
9ae3a8
         return QOBJECT(qint_from_int(va_arg(*ap, int)));
9ae3a8
-    } else if (!strcmp(val, "%ld")) {
9ae3a8
+    } else if (!strcmp(token->str, "%ld")) {
9ae3a8
         return QOBJECT(qint_from_int(va_arg(*ap, long)));
9ae3a8
-    } else if (!strcmp(val, "%lld") ||
9ae3a8
-               !strcmp(val, "%I64d")) {
9ae3a8
+    } else if (!strcmp(token->str, "%lld") ||
9ae3a8
+               !strcmp(token->str, "%I64d")) {
9ae3a8
         return QOBJECT(qint_from_int(va_arg(*ap, long long)));
9ae3a8
-    } else if (!strcmp(val, "%s")) {
9ae3a8
+    } else if (!strcmp(token->str, "%s")) {
9ae3a8
         return QOBJECT(qstring_from_str(va_arg(*ap, const char *)));
9ae3a8
-    } else if (!strcmp(val, "%f")) {
9ae3a8
+    } else if (!strcmp(token->str, "%f")) {
9ae3a8
         return QOBJECT(qfloat_from_double(va_arg(*ap, double)));
9ae3a8
     }
9ae3a8
     return NULL;
9ae3a8
@@ -504,12 +486,12 @@ static QObject *parse_escape(JSONParserContext *ctxt, va_list *ap)
9ae3a8
 
9ae3a8
 static QObject *parse_literal(JSONParserContext *ctxt)
9ae3a8
 {
9ae3a8
-    QObject *token;
9ae3a8
+    JSONToken *token;
9ae3a8
 
9ae3a8
     token = parser_context_pop_token(ctxt);
9ae3a8
     assert(token);
9ae3a8
 
9ae3a8
-    switch (token_get_type(token)) {
9ae3a8
+    switch (token->type) {
9ae3a8
     case JSON_STRING:
9ae3a8
         return QOBJECT(qstring_from_escaped_str(ctxt, token));
9ae3a8
     case JSON_INTEGER: {
9ae3a8
@@ -528,7 +510,7 @@ static QObject *parse_literal(JSONParserContext *ctxt)
9ae3a8
         int64_t value;
9ae3a8
 
9ae3a8
         errno = 0; /* strtoll doesn't set errno on success */
9ae3a8
-        value = strtoll(token_get_value(token), NULL, 10);
9ae3a8
+        value = strtoll(token->str, NULL, 10);
9ae3a8
         if (errno != ERANGE) {
9ae3a8
             return QOBJECT(qint_from_int(value));
9ae3a8
         }
9ae3a8
@@ -536,8 +518,7 @@ static QObject *parse_literal(JSONParserContext *ctxt)
9ae3a8
     }
9ae3a8
     case JSON_FLOAT:
9ae3a8
         /* FIXME dependent on locale */
9ae3a8
-        return QOBJECT(qfloat_from_double(strtod(token_get_value(token),
9ae3a8
-                                                 NULL)));
9ae3a8
+        return QOBJECT(qfloat_from_double(strtod(token->str, NULL)));
9ae3a8
     default:
9ae3a8
         abort();
9ae3a8
     }
9ae3a8
@@ -545,7 +526,7 @@ static QObject *parse_literal(JSONParserContext *ctxt)
9ae3a8
 
9ae3a8
 static QObject *parse_value(JSONParserContext *ctxt, va_list *ap)
9ae3a8
 {
9ae3a8
-    QObject *token;
9ae3a8
+    JSONToken *token;
9ae3a8
 
9ae3a8
     token = parser_context_peek_token(ctxt);
9ae3a8
     if (token == NULL) {
9ae3a8
@@ -553,7 +534,7 @@ static QObject *parse_value(JSONParserContext *ctxt, va_list *ap)
9ae3a8
         return NULL;
9ae3a8
     }
9ae3a8
 
9ae3a8
-    switch (token_get_type(token)) {
9ae3a8
+    switch (token->type) {
9ae3a8
     case JSON_LCURLY:
9ae3a8
         return parse_object(ctxt, ap);
9ae3a8
     case JSON_LSQUARE:
9ae3a8
diff --git a/qobject/json-streamer.c b/qobject/json-streamer.c
9ae3a8
index f7a3e78..e87230d 100644
9ae3a8
--- a/qobject/json-streamer.c
9ae3a8
+++ b/qobject/json-streamer.c
9ae3a8
@@ -11,10 +11,6 @@
9ae3a8
  *
9ae3a8
  */
9ae3a8
 
9ae3a8
-#include "qapi/qmp/qlist.h"
9ae3a8
-#include "qapi/qmp/qstring.h"
9ae3a8
-#include "qapi/qmp/qint.h"
9ae3a8
-#include "qapi/qmp/qdict.h"
9ae3a8
 #include "qemu-common.h"
9ae3a8
 #include "qapi/qmp/json-lexer.h"
9ae3a8
 #include "qapi/qmp/json-streamer.h"
9ae3a8
@@ -34,7 +30,7 @@ static void json_message_process_token(JSONLexer *lexer, GString *input,
9ae3a8
                                        JSONTokenType type, int x, int y)
9ae3a8
 {
9ae3a8
     JSONMessageParser *parser = container_of(lexer, JSONMessageParser, lexer);
9ae3a8
-    QDict *dict;
9ae3a8
+    JSONToken *token;
9ae3a8
 
9ae3a8
     switch (type) {
9ae3a8
     case JSON_LCURLY:
9ae3a8
@@ -53,15 +49,16 @@ static void json_message_process_token(JSONLexer *lexer, GString *input,
9ae3a8
         break;
9ae3a8
     }
9ae3a8
 
9ae3a8
-    dict = qdict_new();
9ae3a8
-    qdict_put(dict, "type", qint_from_int(type));
9ae3a8
-    qdict_put(dict, "token", qstring_from_str(input->str));
9ae3a8
-    qdict_put(dict, "x", qint_from_int(x));
9ae3a8
-    qdict_put(dict, "y", qint_from_int(y));
9ae3a8
+    token = g_malloc(sizeof(JSONToken) + input->len + 1);
9ae3a8
+    token->type = type;
9ae3a8
+    memcpy(token->str, input->str, input->len);
9ae3a8
+    token->str[input->len] = 0;
9ae3a8
+    token->x = x;
9ae3a8
+    token->y = y;
9ae3a8
 
9ae3a8
     parser->token_size += input->len;
9ae3a8
 
9ae3a8
-    g_queue_push_tail(parser->tokens, dict);
9ae3a8
+    g_queue_push_tail(parser->tokens, token);
9ae3a8
 
9ae3a8
     if (type == JSON_ERROR) {
9ae3a8
         goto out_emit_bad;
9ae3a8
-- 
9ae3a8
1.8.3.1
9ae3a8