From patchwork Tue Jun 16 07:50:05 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Pavel Fedin X-Patchwork-Id: 484818 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 02EC31401F6 for ; Tue, 16 Jun 2015 17:50:42 +1000 (AEST) Received: from localhost ([::1]:38404 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Z4ldo-0000Uz-9P for incoming@patchwork.ozlabs.org; Tue, 16 Jun 2015 03:50:40 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:45182) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Z4ldQ-0008Uy-7V for qemu-devel@nongnu.org; Tue, 16 Jun 2015 03:50:17 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1Z4ldL-0002Rf-7E for qemu-devel@nongnu.org; Tue, 16 Jun 2015 03:50:16 -0400 Received: from mailout4.w1.samsung.com ([210.118.77.14]:51400) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Z4ldK-0002PP-UJ for qemu-devel@nongnu.org; Tue, 16 Jun 2015 03:50:11 -0400 Received: from eucpsbgm2.samsung.com (unknown [203.254.199.245]) by mailout4.w1.samsung.com (Oracle Communications Messaging Server 7.0.5.31.0 64bit (built May 5 2014)) with ESMTP id <0NQ1008LX1RIBY00@mailout4.w1.samsung.com> for qemu-devel@nongnu.org; Tue, 16 Jun 2015 08:50:06 +0100 (BST) X-AuditID: cbfec7f5-f794b6d000001495-92-557fd52e189d Received: from eusync1.samsung.com ( [203.254.199.211]) by eucpsbgm2.samsung.com (EUCPMTA) with SMTP id B8.B8.05269.E25DF755; Tue, 16 Jun 2015 08:50:06 +0100 (BST) Received: from fedinw7x64 ([106.109.131.169]) by eusync1.samsung.com (Oracle Communications Messaging Server 7.0.5.31.0 64bit (built May 5 2014)) with ESMTPA id <0NQ1001QB1RHVF40@eusync1.samsung.com>; Tue, 16 Jun 2015 08:50:06 +0100 (BST) From: Pavel Fedin To: 'QEMU Developers' Date: Tue, 16 Jun 2015 10:50:05 +0300 Message-id: <017b01d0a809$0f682580$2e387080$@samsung.com> MIME-version: 1.0 Content-type: text/plain; charset=iso-8859-1 Content-transfer-encoding: 7bit X-Mailer: Microsoft Outlook 14.0 Thread-index: AdCoCF9qhQ4hTGUgRdexjxy+jY2+EQ== Content-language: ru X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFjrJLMWRmVeSWpSXmKPExsVy+t/xy7p6V+tDDWZu4rFo3lRscfPqUSaL 4707WByYPZ5c28zksfl0tcfez79ZApijuGxSUnMyy1KL9O0SuDI2z2xiKXirXbFnwlOWBsal cl2MnBwSAiYSGx/+Y4GwxSQu3FvP1sXIxSEksJRRYtWN24wQzndGiUcNHxlBqtgE1CVOf/0A 1iEioCux/+VEMJtZoEDi583VzCC2sICbxI6vJ9lBbBYBVYkf/3aD1fAKWEqsnLGSFcIWlPgx +R5Ur45E7/dvzBC2vMTmNW+ZIS5SkNhx9jUjxC49iUu9G6DqRSSm/bvHPIFRYBaSUbOQjJqF ZNQsJC0LGFlWMYqmliYXFCel5xrpFSfmFpfmpesl5+duYoQE8NcdjEuPWR1iFOBgVOLhjfhU GyrEmlhWXJl7iFGCg1lJhPf1ufpQId6UxMqq1KL8+KLSnNTiQ4zSHCxK4rwzd70PERJITyxJ zU5NLUgtgskycXBKNTA2bOeyTEhUq2SUKZ/M+txzbt6Vc2qlVlfkkjcztzi93jC5U2JNwIOa VmUh/po32RsNjs65qtVRpuMh+v3U3g3Lt+QrHfWQFuI41bv5UZhk6o7PCvE7X/Derf0t47VH 4C7XeWO3kkTPr4x7rnFuYYrpaX+velZP9vCy5oD7sl4nTf33CCvML1BiKc5INNRiLipOBACi fvxbXAIAAA== X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 210.118.77.14 Cc: 'Peter Crosthwaite' , =?iso-8859-1?Q?'Andreas_F=E4rber'?= Subject: [Qemu-devel] [PATCH v3] QOM: object_property_add() performance improvement X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org The function originally behaves very badly when adding properties with "[*]" suffix. Normally these are used for numbering IRQ pins. In order to find the correct starting number the function started from zero and checked for duplicates. This takes incredibly long time with large number of CPUs because number of IRQ pins on some architectures (like ARM GICv3) gets multiplied by number of CPUs. The solution is to add one more property which caches last used index so that duplication check is not repeated thousands of times. Every time an array is expanded the index is picked up from this cache. The property is a uint32_t and has the original name of the array ('name[*]') for simplicity. It has getter function in order to allow to inspect it from within monitor. The modification decreases qemu startup time with 32 CPUs by a factor of 2 (~10 sec vs ~20 sec). Signed-off-by: Pavel Fedin Reviewed-by: Peter Crosthwaite --- Changes since v2: - Fixed line spacing - 'i' is now uintptr_t, got rid of double-casting from void *. String space is enlarged to 20 characters in order to accommodate maximum possible 64-bit value. --- qom/object.c | 93 ++++++++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 66 insertions(+), 27 deletions(-) diff --git a/qom/object.c b/qom/object.c index 96abd34..e8b94fb 100644 --- a/qom/object.c +++ b/qom/object.c @@ -10,6 +10,8 @@ * See the COPYING file in the top-level directory. */ +#include + #include "qom/object.h" #include "qemu-common.h" #include "qapi/visitor.h" @@ -721,35 +723,14 @@ void object_unref(Object *obj) } } -ObjectProperty * -object_property_add(Object *obj, const char *name, const char *type, - ObjectPropertyAccessor *get, - ObjectPropertyAccessor *set, - ObjectPropertyRelease *release, - void *opaque, Error **errp) +static ObjectProperty * +object_property_add_single(Object *obj, const char *name, const char *type, + ObjectPropertyAccessor *get, + ObjectPropertyAccessor *set, + ObjectPropertyRelease *release, + void *opaque, Error **errp) { ObjectProperty *prop; - size_t name_len = strlen(name); - - if (name_len >= 3 && !memcmp(name + name_len - 3, "[*]", 4)) { - int i; - ObjectProperty *ret; - char *name_no_array = g_strdup(name); - - name_no_array[name_len - 3] = '\0'; - for (i = 0; ; ++i) { - char *full_name = g_strdup_printf("%s[%d]", name_no_array, i); - - ret = object_property_add(obj, full_name, type, get, set, - release, opaque, NULL); - g_free(full_name); - if (ret) { - break; - } - } - g_free(name_no_array); - return ret; - } QTAILQ_FOREACH(prop, &obj->properties, node) { if (strcmp(prop->name, name) == 0) { @@ -774,6 +755,64 @@ object_property_add(Object *obj, const char *name, const char *type, return prop; } +static void property_get_uint32_opaque(Object *obj, Visitor *v, + void *opaque, const char *name, + Error **errp) +{ + uint32_t value = (uintptr_t)opaque; + visit_type_uint32(v, &value, name, errp); +} + +ObjectProperty * +object_property_add(Object *obj, const char *name, const char *type, + ObjectPropertyAccessor *get, + ObjectPropertyAccessor *set, + ObjectPropertyRelease *release, + void *opaque, Error **errp) +{ + size_t name_len = strlen(name); + char *name_no_array; + ObjectProperty *ret, *count; + uintptr_t i; + + if (name_len < 3 || memcmp(&name[name_len - 3], "[*]", 4)) { + return object_property_add_single(obj, name, type, + get, set, release, opaque, errp); + } + + /* 20 characters for maximum possible uintptr_t (64-bit) */ + name_no_array = g_malloc(name_len + 20); + + count = object_property_find(obj, name, NULL); + if (count == NULL) { + /* This is very similar to object_property_add_uint32_ptr(), but: + * - Returns pointer + * - Will not recurse here so that we can use raw name with [*] + * - Allows us to use 'opaque' pointer itself as a storage, because + * we want to store only a single integer which should not be + * modified from outside. + */ + count = object_property_add_single(obj, name, "uint32", + property_get_uint32_opaque, NULL, + NULL, NULL, &error_abort); + } + + name_len -= 3; + memcpy(name_no_array, name, name_len); + i = (uintptr_t)count->opaque; + + do { + g_sprintf(&name_no_array[name_len], "[%zu]", i++); + + ret = object_property_add_single(obj, name_no_array, type, get, set, + release, opaque, NULL); + } while (!ret); + + count->opaque = (void *)i; + g_free(name_no_array); + return ret; +} + ObjectProperty *object_property_find(Object *obj, const char *name, Error **errp) {