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);
|
||||
|
||||
#define OBJECT_CLASS_CAST_CACHE 4
|
||||
|
||||
/**
|
||||
* ObjectClass:
|
||||
*
|
||||
@ -356,6 +358,8 @@ struct ObjectClass
|
||||
Type type;
|
||||
GSList *interfaces;
|
||||
|
||||
const char *cast_cache[OBJECT_CLASS_CAST_CACHE];
|
||||
|
||||
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);
|
||||
|
||||
#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) {
|
||||
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);
|
||||
|
||||
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
|
||||
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)",
|
||||
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) {
|
||||
return class;
|
||||
}
|
||||
@ -523,6 +550,15 @@ ObjectClass *object_class_dynamic_cast_assert(ObjectClass *class,
|
||||
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;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user