On Fri, Jan 15, 2010 at 04:58:59PM +0100, Jiri Denemark wrote: > Current implementation of x86Decode() used for CPUID -> model+features > translation does not always select the closest CPU model. When walking > through all models from cpu_map.xml the function considers a new > candidate as a better choice than a previously selected candidate only > if the new one is a superset of the old one. In case the new candidate > is closer to host CPU but lacks some feature comparing to the old > candidate, the function does not choose well. > > This patch changes the algorithm so that the closest model is always > selected. That is, the model which requires the lowest number of > additional features to describe host CPU. > > Signed-off-by: Jiri Denemark <jdenemar@xxxxxxxxxx> > --- > src/cpu/cpu_x86.c | 122 ++++++++++++++++++++++++++++++++++------------------- > 1 files changed, 78 insertions(+), 44 deletions(-) > > diff --git a/src/cpu/cpu_x86.c b/src/cpu/cpu_x86.c > index 298b632..dae7c90 100644 > --- a/src/cpu/cpu_x86.c > +++ b/src/cpu/cpu_x86.c > @@ -238,6 +238,55 @@ x86DataFromModel(const struct x86_model *model) > } > > > +static virCPUDefPtr > +x86DataToCPU(const union cpuData *data, > + const struct x86_model *model, > + const struct x86_map *map) > +{ > + virCPUDefPtr cpu; > + union cpuData *tmp = NULL; > + struct cpuX86cpuid *cpuid; > + const struct x86_feature *feature; > + int i; > + > + if (VIR_ALLOC(cpu) < 0 || > + (cpu->model = strdup(model->name)) == NULL || > + (tmp = x86DataCopy(data)) == NULL) > + goto no_memory; > + > + for (i = 0; i < model->ncpuid; i++) { > + x86cpuidClearBits(x86DataCpuid(tmp, model->cpuid[i].function), > + model->cpuid + i); > + } > + > + feature = map->features; > + while (feature != NULL) { > + for (i = 0; i < feature->ncpuid; i++) { > + if ((cpuid = x86DataCpuid(tmp, feature->cpuid[i].function)) > + && x86cpuidMatchMasked(cpuid, feature->cpuid + i)) { > + x86cpuidClearBits(cpuid, feature->cpuid + i); > + if (virCPUDefAddFeature(NULL, cpu, feature->name, > + VIR_CPU_FEATURE_REQUIRE) < 0) > + goto error; > + } > + } > + > + feature = feature->next; > + } > + > +cleanup: > + x86DataFree(tmp); > + return cpu; > + > +no_memory: > + virReportOOMError(NULL); > +error: > + virCPUDefFree(cpu); > + cpu = NULL; > + goto cleanup; > +} > + > + > static void > x86FeatureFree(struct x86_feature *feature) > { > @@ -896,10 +945,9 @@ x86Decode(virCPUDefPtr cpu, > { > int ret = -1; > struct x86_map *map; > - const struct x86_feature *feature; > - const struct x86_model *model = NULL; > const struct x86_model *candidate; > - union cpuData *tmp = NULL; > + virCPUDefPtr cpuCandidate; > + virCPUDefPtr cpuModel = NULL; > struct cpuX86cpuid *cpuid; > int i; > > @@ -908,6 +956,8 @@ x86Decode(virCPUDefPtr cpu, > > candidate = map->models; > while (candidate != NULL) { > + bool allowed = (models == NULL); > + > for (i = 0; i < candidate->ncpuid; i++) { > cpuid = x86DataCpuid(data, candidate->cpuid[i].function); > if (cpuid == NULL > @@ -915,65 +965,49 @@ x86Decode(virCPUDefPtr cpu, > goto next; > } > > - if (model == NULL > - || x86ModelCompare(model, candidate) == SUBSET) { > - bool found = false; > - for (i = 0; i < nmodels; i++) { > - if (STREQ(models[i], candidate->name)) { > - found = true; > - break; > - } > + for (i = 0; i < nmodels; i++) { > + if (STREQ(models[i], candidate->name)) { > + allowed = true; > + break; > } > + } > > - if (nmodels > 0 && !found) { > - VIR_DEBUG("CPU model %s not allowed by hypervisor; ignoring", > - candidate->name); > - } > - else > - model = candidate; > + if (!allowed) { > + VIR_DEBUG("CPU model %s not allowed by hypervisor; ignoring", > + candidate->name); > + goto next; > } > > + if (!(cpuCandidate = x86DataToCPU(data, candidate, map))) > + goto out; > + > + if (cpuModel == NULL > + || cpuModel->nfeatures > cpuCandidate->nfeatures) { > + virCPUDefFree(cpuModel); > + cpuModel = cpuCandidate; > + } else > + virCPUDefFree(cpuCandidate); > + > next: > candidate = candidate->next; > } > > - if (model == NULL) { > + if (cpuModel == NULL) { > virCPUReportError(NULL, VIR_ERR_INTERNAL_ERROR, > "%s", _("Cannot find suitable CPU model for given data")); > goto out; > } > > - if ((cpu->model = strdup(model->name)) == NULL > - || (tmp = x86DataCopy(data)) == NULL) { > - virReportOOMError(NULL); > - goto out; > - } > - > - for (i = 0; i < model->ncpuid; i++) { > - x86cpuidClearBits(x86DataCpuid(tmp, model->cpuid[i].function), > - model->cpuid + i); > - } > - > - feature = map->features; > - while (feature != NULL) { > - for (i = 0; i < feature->ncpuid; i++) { > - if ((cpuid = x86DataCpuid(tmp, feature->cpuid[i].function)) > - && x86cpuidMatchMasked(cpuid, feature->cpuid + i)) { > - x86cpuidClearBits(cpuid, feature->cpuid + i); > - if (virCPUDefAddFeature(NULL, cpu, feature->name, > - VIR_CPU_FEATURE_REQUIRE) < 0) > - goto out; > - } > - } > - > - feature = feature->next; > - } > + cpu->model = cpuModel->model; > + cpu->nfeatures = cpuModel->nfeatures; > + cpu->features = cpuModel->features; > + VIR_FREE(cpuModel); > > ret = 0; > > out: > - x86DataFree(tmp); > x86MapFree(map); > + virCPUDefFree(cpuModel); > > return ret; > } > -- ACK Daniel -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :| -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list