qom: aggressively optimize qom casting
This patch adds a small typename cache to ObjectClass. This allows caching positive casts within each ObjectClass. Benchmarking a PPC workload provided by Aurelien, this patch eliminates every single g_hash_table_lookup() happening during the benchmark (which was about 2 million per-second). With this patch applied, I get exactly the same performance (within the margin of error) as with --disable-qom-cast-debug. N.B. it's safe to cache typenames only from the _assert() macros because they are always called with string literals. Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
This commit is contained in:
parent
b087143b4d
commit
035873283b
@ -344,6 +344,8 @@ typedef void (ObjectUnparent)(Object *obj);
|
|||||||
*/
|
*/
|
||||||
typedef void (ObjectFree)(void *obj);
|
typedef void (ObjectFree)(void *obj);
|
||||||
|
|
||||||
|
#define OBJECT_CLASS_CAST_CACHE 4
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ObjectClass:
|
* ObjectClass:
|
||||||
*
|
*
|
||||||
@ -356,6 +358,8 @@ struct ObjectClass
|
|||||||
Type type;
|
Type type;
|
||||||
GSList *interfaces;
|
GSList *interfaces;
|
||||||
|
|
||||||
|
const char *cast_cache[OBJECT_CLASS_CAST_CACHE];
|
||||||
|
|
||||||
ObjectUnparent *unparent;
|
ObjectUnparent *unparent;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
40
qom/object.c
40
qom/object.c
@ -439,7 +439,16 @@ Object *object_dynamic_cast_assert(Object *obj, const char *typename,
|
|||||||
typename, file, line, func);
|
typename, file, line, func);
|
||||||
|
|
||||||
#ifdef CONFIG_QOM_CAST_DEBUG
|
#ifdef CONFIG_QOM_CAST_DEBUG
|
||||||
Object *inst = object_dynamic_cast(obj, typename);
|
int i;
|
||||||
|
Object *inst;
|
||||||
|
|
||||||
|
for (i = 0; i < OBJECT_CLASS_CAST_CACHE; i++) {
|
||||||
|
if (obj->class->cast_cache[i] == typename) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inst = object_dynamic_cast(obj, typename);
|
||||||
|
|
||||||
if (!inst && obj) {
|
if (!inst && obj) {
|
||||||
fprintf(stderr, "%s:%d:%s: Object %p is not an instance of type %s\n",
|
fprintf(stderr, "%s:%d:%s: Object %p is not an instance of type %s\n",
|
||||||
@ -448,6 +457,15 @@ Object *object_dynamic_cast_assert(Object *obj, const char *typename,
|
|||||||
}
|
}
|
||||||
|
|
||||||
assert(obj == inst);
|
assert(obj == inst);
|
||||||
|
|
||||||
|
if (obj == inst) {
|
||||||
|
for (i = 1; i < OBJECT_CLASS_CAST_CACHE; i++) {
|
||||||
|
obj->class->cast_cache[i - 1] = obj->class->cast_cache[i];
|
||||||
|
}
|
||||||
|
obj->class->cast_cache[i - 1] = typename;
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
#endif
|
#endif
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
@ -510,7 +528,16 @@ ObjectClass *object_class_dynamic_cast_assert(ObjectClass *class,
|
|||||||
trace_object_class_dynamic_cast_assert(class ? class->type->name : "(null)",
|
trace_object_class_dynamic_cast_assert(class ? class->type->name : "(null)",
|
||||||
typename, file, line, func);
|
typename, file, line, func);
|
||||||
|
|
||||||
#ifndef CONFIG_QOM_CAST_DEBUG
|
#ifdef CONFIG_QOM_CAST_DEBUG
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < OBJECT_CLASS_CAST_CACHE; i++) {
|
||||||
|
if (class->cast_cache[i] == typename) {
|
||||||
|
ret = class;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
if (!class->interfaces) {
|
if (!class->interfaces) {
|
||||||
return class;
|
return class;
|
||||||
}
|
}
|
||||||
@ -523,6 +550,15 @@ ObjectClass *object_class_dynamic_cast_assert(ObjectClass *class,
|
|||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_QOM_CAST_DEBUG
|
||||||
|
if (ret == class) {
|
||||||
|
for (i = 1; i < OBJECT_CLASS_CAST_CACHE; i++) {
|
||||||
|
class->cast_cache[i - 1] = class->cast_cache[i];
|
||||||
|
}
|
||||||
|
class->cast_cache[i - 1] = typename;
|
||||||
|
}
|
||||||
|
out:
|
||||||
|
#endif
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user