Skip to contentSkip to conversation

qom: avoid reporting errors for NULL error object

PATCH In review Daniel P. Berrangé 3 participants 5 messages Nov 19, 2018 – Nov 21, 2018

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 qom: avoid reporting errors for NULL error object

When debugging QEMU it is often useful to put a breakpoint on the error_setg_internal method impl.

Unfortunately the object_property_add / object_class_property_add methods call object_property_find / object_class_property_find methods to check if a property exists already before adding the new property.

As a result there are a huge number of calls to error_setg_internal on startup of most QEMU commands, making it very painful to set a breakpoint on this method.

This puts a minor optimization on the code so that we avoid calling error_setg() when errp is NULL. Functionally there's no difference since error_setg() is a no-op when errp is NULL, but this lets us use breakpoints in GDB in a practical way.

---
 qom/object.c | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)
qom/object.c +10 -2
index 547dcf97c3..ddd5e7a30e 100644
@@ -1087,7 +1087,12 @@ ObjectProperty *object_property_find(Object *obj, const char *name,
         return prop;
     }
 
-    error_setg(errp, "Property '.%s' not found", name);
+    /* Optimized to avoid calling error_setg if errp == NULL
+     * otherwise every property add call hits error_setg
+     * making it impratical to set breakpoints in GDB */
+    if (errp) {
+        error_setg(errp, "Property '.%s' not found", name);
+    }
     return NULL;
 }
 
@@ -1133,7 +1138,10 @@ ObjectProperty *object_class_property_find(ObjectClass *klass, const char *name,
     }
 
     prop = g_hash_table_lookup(klass->properties, name);
-    if (!prop) {
+    /* Optimized to avoid calling error_setg if errp == NULL
+     * otherwise every property add call hits error_setg
+     * making it impratical to set breakpoints in GDB */
+    if (!prop && errp) {
         error_setg(errp, "Property '.%s' not found", name);
     }
     return prop;
Signature · 1 line
2.19.1
#1 lore raw

Hi

Quoted 12 lines · Daniel P. Berrangé

When debugging QEMU it is often useful to put a breakpoint on the error_setg_internal method impl.

Unfortunately the object_property_add / object_class_property_add methods call object_property_find / object_class_property_find methods to check if a property exists already before adding the new property.

As a result there are a huge number of calls to error_setg_internal on startup of most QEMU commands, making it very painful to set a breakpoint on this method.

Quoted 6 lines

This puts a minor optimization on the code so that we avoid calling error_setg() when errp is NULL. Functionally there's no difference since error_setg() is a no-op when errp is NULL, but this lets us use breakpoints in GDB in a practical way.

Or maybe change the error_setg* macros? After all, if errp is NULL, it's an error qemu can handle.

Quoted 38 lines
---
 qom/object.c | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)
qom/object.c +10 -3
index 547dcf97c3..ddd5e7a30e 100644
@@ -1087,7 +1087,12 @@ ObjectProperty *object_property_find(Object *obj, const char *name,
         return prop;
     }
 
-    error_setg(errp, "Property '.%s' not found", name);
+    /* Optimized to avoid calling error_setg if errp == NULL
+     * otherwise every property add call hits error_setg
+     * making it impratical to set breakpoints in GDB */
+    if (errp) {
+        error_setg(errp, "Property '.%s' not found", name);
+    }
     return NULL;
 }
 
@@ -1133,7 +1138,10 @@ ObjectProperty *object_class_property_find(ObjectClass *klass, const char *name,
     }
 
     prop = g_hash_table_lookup(klass->properties, name);
-    if (!prop) {
+    /* Optimized to avoid calling error_setg if errp == NULL
+     * otherwise every property add call hits error_setg
+     * making it impratical to set breakpoints in GDB */
+    if (!prop && errp) {
         error_setg(errp, "Property '.%s' not found", name);
     }
     return prop;
--

2.19.1

Signature · 1 line
Marc-André Lureau
#2 lore raw
Quoted 20 lines · Marc-André Lureau

Hi

Quoted 17 lines · Daniel P. Berrangé

When debugging QEMU it is often useful to put a breakpoint on the error_setg_internal method impl.

Unfortunately the object_property_add / object_class_property_add methods call object_property_find / object_class_property_find methods to check if a property exists already before adding the new property.

As a result there are a huge number of calls to error_setg_internal on startup of most QEMU commands, making it very painful to set a breakpoint on this method.

This puts a minor optimization on the code so that we avoid calling error_setg() when errp is NULL. Functionally there's no difference since error_setg() is a no-op when errp is NULL, but this lets us use breakpoints in GDB in a practical way.

Quoted 4 lines
Quoted 1 line

Or maybe change the error_setg* macros? After all, if errp is NULL, it's an error qemu can handle.

That would mean that all callers would get short circuited which I don't think it is desirable in general.

This QOM usage is special in that the calling code is using the error scenario as a means to trigger different code flow. IOW it doesn't consider it an error scenario at all.

Quoted 25 lines
Quoted 25 lines
---
 qom/object.c | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)
qom/object.c +6 -1
index 547dcf97c3..ddd5e7a30e 100644
@@ -1087,7 +1087,12 @@ ObjectProperty *object_property_find(Object *obj, const char *name,
         return prop;
     }
 
-    error_setg(errp, "Property '.%s' not found", name);
+    /* Optimized to avoid calling error_setg if errp == NULL
+     * otherwise every property add call hits error_setg
+     * making it impratical to set breakpoints in GDB */
+    if (errp) {
+        error_setg(errp, "Property '.%s' not found", name);
+    }
     return NULL;
 }
 
@@ -1133,7 +1138,10 @@ ObjectProperty *object_class_property_find(ObjectClass *klass, const char *name,
     }
 
Quoted 17 lines
Quoted 13 lines
qom/object.c +4 -2
     prop = g_hash_table_lookup(klass->properties, name);
-    if (!prop) {
+    /* Optimized to avoid calling error_setg if errp == NULL
+     * otherwise every property add call hits error_setg
+     * making it impratical to set breakpoints in GDB */
+    if (!prop && errp) {
         error_setg(errp, "Property '.%s' not found", name);
     }
     return prop;
--

2.19.1

Signature · 1 line
Marc-André Lureau

Regards,
Daniel

Signature · 3 lines
|: https://berrange.com      -o-    https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org         -o-            https://fstop138.berrange.com :|
|: https://entangle-photo.org    -o-    https://www.instagram.com/dberrange :|
#3 lore raw
In reply to Daniel P. Berrangé
Quoted 29 lines · Daniel P. Berrangé

When debugging QEMU it is often useful to put a breakpoint on the error_setg_internal method impl.

Unfortunately the object_property_add / object_class_property_add methods call object_property_find / object_class_property_find methods to check if a property exists already before adding the new property.

As a result there are a huge number of calls to error_setg_internal on startup of most QEMU commands, making it very painful to set a breakpoint on this method.

This puts a minor optimization on the code so that we avoid calling error_setg() when errp is NULL. Functionally there's no difference since error_setg() is a no-op when errp is NULL, but this lets us use breakpoints in GDB in a practical way.

---
 qom/object.c | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)
qom/object.c +0 -0
index 547dcf97c3..ddd5e7a30e 100644
@@ -1087,7 +1087,12 @@ ObjectProperty *object_property_find(Object *obj, const char *name,
         return prop;
     }
 

qom/object.c ObjectProperty *object_property_find(Object *obj, const char *name, · line 1098

Quoted 10 lines
qom/object.c +6 -1
-    error_setg(errp, "Property '.%s' not found", name);
+    /* Optimized to avoid calling error_setg if errp == NULL
+     * otherwise every property add call hits error_setg
+     * making it impratical to set breakpoints in GDB */
+    if (errp) {
+        error_setg(errp, "Property '.%s' not found", name);
+    }
     return NULL;
 }
 

In my opinion, this function's design is awkward. Stress on *opinion*.

On success, it returns a (non-null) pointer.

On failure, it sets an error and returns null. Note that it has just one failure mode: "Property '.%s' not found". Setting an error is just a convenience for those callers that want to propagate exactly this error to their callers.

I count 30 callers. Only six pass a non-NULL argument to @errp.

I'd rather have a pair of functions similar to how Python has both .get() and .__getitem__(): the former doesn't fail, but returns None instead, and the latter does fail, throwing KeyError. In QEMU, we can't throw, so we set an error. Here's the obvious code:

    ObjectProperty *object_property_find(Object *obj, const char *name)
    {
        ObjectProperty *prop;
        ObjectClass *klass = object_get_class(obj);

        prop = object_class_property_find(klass, name, NULL);
        if (prop) {
            return prop;
        }

        prop = g_hash_table_lookup(obj->properties, name);
        if (prop) {
            return prop;
        }

        return NULL;
    }

    ObjectProperty *object_property_find_err(Object *obj, const char *name,
                                             Error **errp)
    {
        ObjectProperty *prop = object_property_find(obj, name);

        if (!prop) {
            error_setg(errp, "Property '.%s' not found", name);
        }
        return prop;
    }

qom/object.c ObjectProperty *object_class_property_find(ObjectClass *klass, const char *name, · line 1147

Quoted 12 lines
qom/object.c +4 -1
@@ -1133,7 +1138,10 @@ ObjectProperty *object_class_property_find(ObjectClass *klass, const char *name,
     }
 
     prop = g_hash_table_lookup(klass->properties, name);
-    if (!prop) {
+    /* Optimized to avoid calling error_setg if errp == NULL
+     * otherwise every property add call hits error_setg
+     * making it impratical to set breakpoints in GDB */
+    if (!prop && errp) {
         error_setg(errp, "Property '.%s' not found", name);
     }
     return prop;

Likewise, just more so: callers passing non-NULL do not exist.

#4 lore raw
Quoted 78 lines · Markus Armbruster
Quoted 29 lines · Daniel P. Berrangé

When debugging QEMU it is often useful to put a breakpoint on the error_setg_internal method impl.

Unfortunately the object_property_add / object_class_property_add methods call object_property_find / object_class_property_find methods to check if a property exists already before adding the new property.

As a result there are a huge number of calls to error_setg_internal on startup of most QEMU commands, making it very painful to set a breakpoint on this method.

This puts a minor optimization on the code so that we avoid calling error_setg() when errp is NULL. Functionally there's no difference since error_setg() is a no-op when errp is NULL, but this lets us use breakpoints in GDB in a practical way.

---
 qom/object.c | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)
qom/object.c +0 -0
index 547dcf97c3..ddd5e7a30e 100644
@@ -1087,7 +1087,12 @@ ObjectProperty *object_property_find(Object *obj, const char *name,
         return prop;
     }
 

qom/object.c ObjectProperty *object_property_find(Object *obj, const char *name, · line 1098

Quoted 10 lines
qom/object.c +6 -1
-    error_setg(errp, "Property '.%s' not found", name);
+    /* Optimized to avoid calling error_setg if errp == NULL
+     * otherwise every property add call hits error_setg
+     * making it impratical to set breakpoints in GDB */
+    if (errp) {
+        error_setg(errp, "Property '.%s' not found", name);
+    }
     return NULL;
 }
 

In my opinion, this function's design is awkward. Stress on *opinion*.

On success, it returns a (non-null) pointer.

On failure, it sets an error and returns null. Note that it has just one failure mode: "Property '.%s' not found". Setting an error is just a convenience for those callers that want to propagate exactly this error to their callers.

I count 30 callers. Only six pass a non-NULL argument to @errp.

I'd rather have a pair of functions similar to how Python has both .get() and .__getitem__(): the former doesn't fail, but returns None instead, and the latter does fail, throwing KeyError. In QEMU, we can't throw, so we set an error. Here's the obvious code:

    ObjectProperty *object_property_find(Object *obj, const char *name)
    {
        ObjectProperty *prop;
        ObjectClass *klass = object_get_class(obj);

        prop = object_class_property_find(klass, name, NULL);
        if (prop) {
            return prop;
        }

        prop = g_hash_table_lookup(obj->properties, name);
        if (prop) {
            return prop;
        }

        return NULL;
    }

    ObjectProperty *object_property_find_err(Object *obj, const char *name,
                                             Error **errp)
Quoted 8 lines
    {
        ObjectProperty *prop = object_property_find(obj, name);

        if (!prop) {
            error_setg(errp, "Property '.%s' not found", name);
        }
        return prop;
    }

Yes, I'd be happy with this approach as I think it is more useful in general

Regards,
Daniel

Signature · 3 lines
|: https://berrange.com      -o-    https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org         -o-            https://fstop138.berrange.com :|
|: https://entangle-photo.org    -o-    https://www.instagram.com/dberrange :|