Blame SOURCES/libvirt-cpu_x86-Refactor-storage-of-CPUID-data-to-add-support-for-KVM-features.patch

43fe83
From f8da43ba082eb3b6beea90147ad0222dc4870a25 Mon Sep 17 00:00:00 2001
43fe83
Message-Id: <f8da43ba082eb3b6beea90147ad0222dc4870a25.1383922566.git.jdenemar@redhat.com>
43fe83
From: Peter Krempa <pkrempa@redhat.com>
43fe83
Date: Fri, 8 Nov 2013 12:33:30 +0100
43fe83
Subject: [PATCH] cpu_x86: Refactor storage of CPUID data to add support for
43fe83
 KVM features
43fe83
43fe83
https://bugzilla.redhat.com/show_bug.cgi?id=1008989
43fe83
43fe83
The CPUID functions were stored in multiple arrays according to a
43fe83
specified prefix of those. This made it very hard to add another prefix
43fe83
to store KVM CPUID features (0x40000000). Instead of hardcoding a third
43fe83
array this patch changes the approach used:
43fe83
43fe83
The code is refactored to use a single array where the CPUID functions
43fe83
are stored ordered by the cpuid function so that they don't depend on
43fe83
the specific prefix and don't waste memory. The code is also less
43fe83
complex using this approach. A trateoff to this is the change from O(N)
43fe83
complexity to O(N^2) in x86DataAdd and x86DataSubtract. The rest of the
43fe83
functions were already using O(N^2) algorithms.
43fe83
43fe83
(cherry picked from commit f80a11c9214fdd0e2eb489fc1481de6bba0c3a5c)
43fe83
43fe83
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
43fe83
---
43fe83
 src/cpu/cpu_x86.c      | 213 ++++++++++++++++++-------------------------------
43fe83
 src/cpu/cpu_x86_data.h |   8 +-
43fe83
 2 files changed, 80 insertions(+), 141 deletions(-)
43fe83
43fe83
diff --git a/src/cpu/cpu_x86.c b/src/cpu/cpu_x86.c
43fe83
index d4d3731..3bdb3c3 100644
43fe83
--- a/src/cpu/cpu_x86.c
43fe83
+++ b/src/cpu/cpu_x86.c
43fe83
@@ -84,14 +84,13 @@ enum compare_result {
43fe83
 
43fe83
 
43fe83
 struct virCPUx86DataIterator {
43fe83
-    virCPUx86Data *data;
43fe83
+    const virCPUx86Data *data;
43fe83
     int pos;
43fe83
-    bool extended;
43fe83
 };
43fe83
 
43fe83
 
43fe83
 #define virCPUx86DataIteratorInit(data) \
43fe83
-    { data, -1, false }
43fe83
+    { data, -1 }
43fe83
 
43fe83
 
43fe83
 static bool
43fe83
@@ -120,6 +119,9 @@ static void
43fe83
 x86cpuidSetBits(virCPUx86CPUID *cpuid,
43fe83
                 const virCPUx86CPUID *mask)
43fe83
 {
43fe83
+    if (!mask)
43fe83
+        return;
43fe83
+
43fe83
     cpuid->eax |= mask->eax;
43fe83
     cpuid->ebx |= mask->ebx;
43fe83
     cpuid->ecx |= mask->ecx;
43fe83
@@ -131,6 +133,9 @@ static void
43fe83
 x86cpuidClearBits(virCPUx86CPUID *cpuid,
43fe83
                   const virCPUx86CPUID *mask)
43fe83
 {
43fe83
+    if (!mask)
43fe83
+        return;
43fe83
+
43fe83
     cpuid->eax &= ~mask->eax;
43fe83
     cpuid->ebx &= ~mask->ebx;
43fe83
     cpuid->ecx &= ~mask->ecx;
43fe83
@@ -142,42 +147,45 @@ static void
43fe83
 x86cpuidAndBits(virCPUx86CPUID *cpuid,
43fe83
                 const virCPUx86CPUID *mask)
43fe83
 {
43fe83
+    if (!mask)
43fe83
+        return;
43fe83
+
43fe83
     cpuid->eax &= mask->eax;
43fe83
     cpuid->ebx &= mask->ebx;
43fe83
     cpuid->ecx &= mask->ecx;
43fe83
     cpuid->edx &= mask->edx;
43fe83
 }
43fe83
 
43fe83
+static int
43fe83
+virCPUx86CPUIDSorter(const void *a, const void *b)
43fe83
+{
43fe83
+    virCPUx86CPUID *da = (virCPUx86CPUID *) a;
43fe83
+    virCPUx86CPUID *db = (virCPUx86CPUID *) b;
43fe83
+
43fe83
+    if (da->function > db->function)
43fe83
+        return 1;
43fe83
+    else if (da->function < db->function)
43fe83
+        return -1;
43fe83
+
43fe83
+    return 0;
43fe83
+}
43fe83
+
43fe83
 
43fe83
 /* skips all zero CPUID leafs */
43fe83
 static virCPUx86CPUID *
43fe83
 x86DataCpuidNext(struct virCPUx86DataIterator *iterator)
43fe83
 {
43fe83
-    virCPUx86CPUID *ret;
43fe83
-    virCPUx86Data *data = iterator->data;
43fe83
+    const virCPUx86Data *data = iterator->data;
43fe83
 
43fe83
     if (!data)
43fe83
         return NULL;
43fe83
 
43fe83
-    do {
43fe83
-        ret = NULL;
43fe83
-        iterator->pos++;
43fe83
-
43fe83
-        if (!iterator->extended) {
43fe83
-            if (iterator->pos < data->basic_len)
43fe83
-                ret = data->basic + iterator->pos;
43fe83
-            else {
43fe83
-                iterator->extended = true;
43fe83
-                iterator->pos = 0;
43fe83
-            }
43fe83
-        }
43fe83
-
43fe83
-        if (iterator->extended && iterator->pos < data->extended_len) {
43fe83
-            ret = data->extended + iterator->pos;
43fe83
-        }
43fe83
-    } while (ret && x86cpuidMatch(ret, &cpuidNull));
43fe83
+    while (++iterator->pos < data->len) {
43fe83
+        if (!x86cpuidMatch(data->data + iterator->pos, &cpuidNull))
43fe83
+            return data->data + iterator->pos;
43fe83
+    }
43fe83
 
43fe83
-    return ret;
43fe83
+    return NULL;
43fe83
 }
43fe83
 
43fe83
 
43fe83
@@ -185,36 +193,23 @@ static virCPUx86CPUID *
43fe83
 x86DataCpuid(const virCPUx86Data *data,
43fe83
              uint32_t function)
43fe83
 {
43fe83
-    virCPUx86CPUID *cpuids;
43fe83
-    int len;
43fe83
     size_t i;
43fe83
 
43fe83
-    if (function < CPUX86_EXTENDED) {
43fe83
-        cpuids = data->basic;
43fe83
-        len = data->basic_len;
43fe83
-        i = function;
43fe83
-    }
43fe83
-    else {
43fe83
-        cpuids = data->extended;
43fe83
-        len = data->extended_len;
43fe83
-        i = function - CPUX86_EXTENDED;
43fe83
+    for (i = 0; i < data->len; i++) {
43fe83
+        if (data->data[i].function == function)
43fe83
+            return data->data + i;
43fe83
     }
43fe83
 
43fe83
-    if (i < len && !x86cpuidMatch(cpuids + i, &cpuidNull))
43fe83
-        return cpuids + i;
43fe83
-    else
43fe83
-        return NULL;
43fe83
+    return NULL;
43fe83
 }
43fe83
 
43fe83
-
43fe83
 void
43fe83
 virCPUx86DataFree(virCPUx86Data *data)
43fe83
 {
43fe83
     if (data == NULL)
43fe83
         return;
43fe83
 
43fe83
-    VIR_FREE(data->basic);
43fe83
-    VIR_FREE(data->extended);
43fe83
+    VIR_FREE(data->data);
43fe83
     VIR_FREE(data);
43fe83
 }
43fe83
 
43fe83
@@ -251,77 +246,36 @@ x86DataCopy(const virCPUx86Data *data)
43fe83
     virCPUx86Data *copy = NULL;
43fe83
     size_t i;
43fe83
 
43fe83
-    if (VIR_ALLOC(copy) < 0
43fe83
-        || VIR_ALLOC_N(copy->basic, data->basic_len) < 0
43fe83
-        || VIR_ALLOC_N(copy->extended, data->extended_len) < 0) {
43fe83
+    if (VIR_ALLOC(copy) < 0 ||
43fe83
+        VIR_ALLOC_N(copy->data, data->len) < 0) {
43fe83
         virCPUx86DataFree(copy);
43fe83
         return NULL;
43fe83
     }
43fe83
 
43fe83
-    copy->basic_len = data->basic_len;
43fe83
-    for (i = 0; i < data->basic_len; i++)
43fe83
-        copy->basic[i] = data->basic[i];
43fe83
-
43fe83
-    copy->extended_len = data->extended_len;
43fe83
-    for (i = 0; i < data->extended_len; i++)
43fe83
-        copy->extended[i] = data->extended[i];
43fe83
+    copy->len = data->len;
43fe83
+    for (i = 0; i < data->len; i++)
43fe83
+        copy->data[i] = data->data[i];
43fe83
 
43fe83
     return copy;
43fe83
 }
43fe83
 
43fe83
 
43fe83
-static int
43fe83
-x86DataExpand(virCPUx86Data *data,
43fe83
-              int basic_by,
43fe83
-              int extended_by)
43fe83
-{
43fe83
-    size_t i;
43fe83
-
43fe83
-    if (basic_by > 0) {
43fe83
-        size_t len = data->basic_len;
43fe83
-        if (VIR_EXPAND_N(data->basic, data->basic_len, basic_by) < 0)
43fe83
-            return -1;
43fe83
-
43fe83
-        for (i = 0; i < basic_by; i++)
43fe83
-            data->basic[len + i].function = len + i;
43fe83
-    }
43fe83
-
43fe83
-    if (extended_by > 0) {
43fe83
-        size_t len = data->extended_len;
43fe83
-        if (VIR_EXPAND_N(data->extended, data->extended_len, extended_by) < 0)
43fe83
-            return -1;
43fe83
-
43fe83
-        for (i = 0; i < extended_by; i++)
43fe83
-            data->extended[len + i].function = len + i + CPUX86_EXTENDED;
43fe83
-    }
43fe83
-
43fe83
-    return 0;
43fe83
-}
43fe83
-
43fe83
-
43fe83
 int
43fe83
 virCPUx86DataAddCPUID(virCPUx86Data *data,
43fe83
                       const virCPUx86CPUID *cpuid)
43fe83
 {
43fe83
-    unsigned int basic_by = 0;
43fe83
-    unsigned int extended_by = 0;
43fe83
-    virCPUx86CPUID **cpuids;
43fe83
-    unsigned int pos;
43fe83
-
43fe83
-    if (cpuid->function < CPUX86_EXTENDED) {
43fe83
-        pos = cpuid->function;
43fe83
-        basic_by = pos + 1 - data->basic_len;
43fe83
-        cpuids = &data->basic;
43fe83
-    } else {
43fe83
-        pos = cpuid->function - CPUX86_EXTENDED;
43fe83
-        extended_by = pos + 1 - data->extended_len;
43fe83
-        cpuids = &data->extended;
43fe83
-    }
43fe83
+    virCPUx86CPUID *existing;
43fe83
 
43fe83
-    if (x86DataExpand(data, basic_by, extended_by) < 0)
43fe83
-        return -1;
43fe83
+    if ((existing = x86DataCpuid(data, cpuid->function))) {
43fe83
+        x86cpuidSetBits(existing, cpuid);
43fe83
+    } else {
43fe83
+        if (VIR_APPEND_ELEMENT_COPY(data->data, data->len,
43fe83
+                                    *((virCPUx86CPUID *)cpuid)) < 0)
43fe83
+            return -1;
43fe83
 
43fe83
-    x86cpuidSetBits((*cpuids) + pos, cpuid);
43fe83
+        qsort(data->data, data->len,
43fe83
+              sizeof(virCPUx86CPUID), virCPUx86CPUIDSorter);
43fe83
+    }
43fe83
 
43fe83
     return 0;
43fe83
 }
43fe83
@@ -331,21 +285,19 @@ static int
43fe83
 x86DataAdd(virCPUx86Data *data1,
43fe83
            const virCPUx86Data *data2)
43fe83
 {
43fe83
-    size_t i;
43fe83
-
43fe83
-    if (x86DataExpand(data1,
43fe83
-                      data2->basic_len - data1->basic_len,
43fe83
-                      data2->extended_len - data1->extended_len) < 0)
43fe83
-        return -1;
43fe83
+    struct virCPUx86DataIterator iter = virCPUx86DataIteratorInit(data2);
43fe83
+    virCPUx86CPUID *cpuid1;
43fe83
+    virCPUx86CPUID *cpuid2;
43fe83
 
43fe83
-    for (i = 0; i < data2->basic_len; i++) {
43fe83
-        x86cpuidSetBits(data1->basic + i,
43fe83
-                        data2->basic + i);
43fe83
-    }
43fe83
+    while ((cpuid2 = x86DataCpuidNext(&iter))) {
43fe83
+        cpuid1 = x86DataCpuid(data1, cpuid2->function);
43fe83
 
43fe83
-    for (i = 0; i < data2->extended_len; i++) {
43fe83
-        x86cpuidSetBits(data1->extended + i,
43fe83
-                        data2->extended + i);
43fe83
+        if (cpuid1) {
43fe83
+            x86cpuidSetBits(cpuid1, cpuid2);
43fe83
+        } else {
43fe83
+            if (virCPUx86DataAddCPUID(data1, cpuid2) < 0)
43fe83
+                return -1;
43fe83
+        }
43fe83
     }
43fe83
 
43fe83
     return 0;
43fe83
@@ -356,19 +308,13 @@ static void
43fe83
 x86DataSubtract(virCPUx86Data *data1,
43fe83
                 const virCPUx86Data *data2)
43fe83
 {
43fe83
-    size_t i;
43fe83
-    unsigned int len;
43fe83
-
43fe83
-    len = MIN(data1->basic_len, data2->basic_len);
43fe83
-    for (i = 0; i < len; i++) {
43fe83
-        x86cpuidClearBits(data1->basic + i,
43fe83
-                          data2->basic + i);
43fe83
-    }
43fe83
+    struct virCPUx86DataIterator iter = virCPUx86DataIteratorInit(data1);
43fe83
+    virCPUx86CPUID *cpuid1;
43fe83
+    virCPUx86CPUID *cpuid2;
43fe83
 
43fe83
-    len = MIN(data1->extended_len, data2->extended_len);
43fe83
-    for (i = 0; i < len; i++) {
43fe83
-        x86cpuidClearBits(data1->extended + i,
43fe83
-                          data2->extended + i);
43fe83
+    while ((cpuid1 = x86DataCpuidNext(&iter))) {
43fe83
+        cpuid2 = x86DataCpuid(data2, cpuid1->function);
43fe83
+        x86cpuidClearBits(cpuid1, cpuid2);
43fe83
     }
43fe83
 }
43fe83
 
43fe83
@@ -1726,25 +1672,23 @@ cpuidCall(virCPUx86CPUID *cpuid)
43fe83
 
43fe83
 
43fe83
 static int
43fe83
-cpuidSet(uint32_t base, virCPUx86CPUID **set)
43fe83
+cpuidSet(uint32_t base, virCPUx86Data *data)
43fe83
 {
43fe83
     uint32_t max;
43fe83
     uint32_t i;
43fe83
     virCPUx86CPUID cpuid = { base, 0, 0, 0, 0 };
43fe83
 
43fe83
     cpuidCall(&cpuid);
43fe83
-    max = cpuid.eax - base;
43fe83
+    max = cpuid.eax;
43fe83
 
43fe83
-    if (VIR_ALLOC_N(*set, max + 1) < 0)
43fe83
-        return -1;
43fe83
-
43fe83
-    for (i = 0; i <= max; i++) {
43fe83
-        cpuid.function = base | i;
43fe83
+    for (i = base; i <= max; i++) {
43fe83
+        cpuid.function = i;
43fe83
         cpuidCall(&cpuid);
43fe83
-        (*set)[i] = cpuid;
43fe83
+        if (virCPUx86DataAddCPUID(data, &cpuid) < 0)
43fe83
+            return -1;
43fe83
     }
43fe83
 
43fe83
-    return max + 1;
43fe83
+    return 0;
43fe83
 }
43fe83
 
43fe83
 
43fe83
@@ -1753,18 +1697,15 @@ x86NodeData(virArch arch)
43fe83
 {
43fe83
     virCPUDataPtr cpuData = NULL;
43fe83
     virCPUx86Data *data;
43fe83
-    int ret;
43fe83
 
43fe83
     if (VIR_ALLOC(data) < 0)
43fe83
         return NULL;
43fe83
 
43fe83
-    if ((ret = cpuidSet(CPUX86_BASIC, &data->basic)) < 0)
43fe83
+    if (cpuidSet(CPUX86_BASIC, data) < 0)
43fe83
         goto error;
43fe83
-    data->basic_len = ret;
43fe83
 
43fe83
-    if ((ret = cpuidSet(CPUX86_EXTENDED, &data->extended)) < 0)
43fe83
+    if (cpuidSet(CPUX86_EXTENDED, data) < 0)
43fe83
         goto error;
43fe83
-    data->extended_len = ret;
43fe83
 
43fe83
     if (!(cpuData = virCPUx86MakeData(arch, &data)))
43fe83
         goto error;
43fe83
diff --git a/src/cpu/cpu_x86_data.h b/src/cpu/cpu_x86_data.h
43fe83
index 5910ea9..69066f1 100644
43fe83
--- a/src/cpu/cpu_x86_data.h
43fe83
+++ b/src/cpu/cpu_x86_data.h
43fe83
@@ -1,7 +1,7 @@
43fe83
 /*
43fe83
  * cpu_x86_data.h: x86 specific CPU data
43fe83
  *
43fe83
- * Copyright (C) 2009-2010 Red Hat, Inc.
43fe83
+ * Copyright (C) 2009-2010, 2013 Red Hat, Inc.
43fe83
  *
43fe83
  * This library is free software; you can redistribute it and/or
43fe83
  * modify it under the terms of the GNU Lesser General Public
43fe83
@@ -40,10 +40,8 @@ struct _virCPUx86CPUID {
43fe83
 
43fe83
 typedef struct _virCPUx86Data virCPUx86Data;
43fe83
 struct _virCPUx86Data {
43fe83
-    size_t basic_len;
43fe83
-    virCPUx86CPUID *basic;
43fe83
-    size_t extended_len;
43fe83
-    virCPUx86CPUID *extended;
43fe83
+    size_t len;
43fe83
+    virCPUx86CPUID *data;
43fe83
 };
43fe83
 
43fe83
 #endif /* __VIR_CPU_X86_DATA_H__ */
43fe83
-- 
43fe83
1.8.4.2
43fe83