From: Igor Mammedov <imammedo@redhat.com>
To: Eduardo Habkost <ehabkost@redhat.com>
Cc: "Blue Swirl" <blauwirbel@gmail.com>,
qemu-devel@nongnu.org, "Gleb Natapov" <gleb@redhat.com>,
"Andreas Färber" <afaerber@suse.de>
Subject: Re: [Qemu-devel] [RFC 14/15] i386: topology & APIC ID utility functions (v2)
Date: Tue, 14 Aug 2012 19:03:24 +0200 [thread overview]
Message-ID: <20120814190324.20e39cbf@thinkpad.mammed.net> (raw)
In-Reply-To: <1344369413-9053-15-git-send-email-ehabkost@redhat.com>
On Tue, 7 Aug 2012 16:56:52 -0300
Eduardo Habkost <ehabkost@redhat.com> wrote:
> Changes v1 -> v2:
> - Support 32-bit APIC IDs (in case x2APIC is going to be used)
> - Coding style changes
> - Use TARGET_I386_TOPOLOGY_H instead of __QEMU_X86_TOPOLOGY_H__
> - Rename topo_make_apic_id() to topo_apicid_for_cpu()
> - Rename __make_apicid() to topo_make_apicid()
> - Spaces around operators on test-x86-cpuid.c, as requested by
> Blue Swirl
> - Make test-x86-cpuid a target-specific test
adding to commit description ref to intel(& maybe amd) spec or/and short
description how apicid is structured/constructed would be nice
> Cc: Blue Swirl <blauwirbel@gmail.com>
> Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
> ---
> target-i386/topology.h | 144 +++++++++++++++++++++++++++++++++++++++++++++++++
> tests/.gitignore | 1 +
> tests/Makefile | 3 ++
> tests/test-x86-cpuid.c | 108 +++++++++++++++++++++++++++++++++++++
> 4 files changed, 256 insertions(+)
> create mode 100644 target-i386/topology.h
> create mode 100644 tests/test-x86-cpuid.c
>
> diff --git a/target-i386/topology.h b/target-i386/topology.h
> new file mode 100644
> index 0000000..35d9817
> --- /dev/null
> +++ b/target-i386/topology.h
> @@ -0,0 +1,144 @@
> +/*
> + * x86 CPU topology data structures and functions
> + *
> + * Copyright (c) 2012 Red Hat Inc.
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a copy
> + * of this software and associated documentation files (the "Software"), to deal
> + * in the Software without restriction, including without limitation the rights
> + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
> + * copies of the Software, and to permit persons to whom the Software is
> + * furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice shall be included in
> + * all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
> + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
> + * THE SOFTWARE.
> + */
> +#ifndef TARGET_I386_TOPOLOGY_H
> +#define TARGET_I386_TOPOLOGY_H
> +
> +#include <stdint.h>
> +#include <string.h>
> +
> +#include "bitops.h"
> +
> +/* APIC IDs can be 32-bit, but beware: APIC IDs > 255 require x2APIC support
> + */
> +typedef uint32_t apic_id_t;
> +
> +/* Return the bit width needed for 'count' IDs
> + */
> +static unsigned bits_for_count(unsigned count)
bitwidth_for_count(...) perhaps would be clearer?
and you could drop apicid_*_width/apicid_*_offset () funcs and use
it directly in topo_make_apicid() to make code more concise
> +{
> + g_assert(count >= 1);
> + if (count == 1) {
> + return 0;
> + }
> + return bitops_flsl(count - 1) + 1;
> +}
> +
> +/* Bit width of the SMT_ID (thread ID) field on the APIC ID
> + */
> +static inline unsigned apicid_smt_width(unsigned nr_cores, unsigned nr_threads)
> +{
> + return bits_for_count(nr_threads);
> +}
> +
> +/* Bit width of the Core_ID field
> + */
> +static inline unsigned apicid_core_width(unsigned nr_cores, unsigned nr_threads)
> +{
> + return bits_for_count(nr_cores);
> +}
> +
> +/* Bit offset of the Core_ID field
> + */
> +static inline unsigned apicid_core_offset(unsigned nr_cores,
> + unsigned nr_threads)
> +{
> + return apicid_smt_width(nr_cores, nr_threads);
> +}
> +
> +/* Bit offset of the Pkg_ID (socket ID) field
> + */
> +static inline unsigned apicid_pkg_offset(unsigned nr_cores, unsigned nr_threads)
> +{
> + return apicid_core_offset(nr_cores, nr_threads) + \
> + apicid_core_width(nr_cores, nr_threads);
> +}
> +
> +/* Make APIC ID for the CPU based on Pkg_ID, Core_ID, SMT_ID
> + *
> + * The caller must make sure core_id < nr_cores and smt_id < nr_threads.
> + */
> +static inline apic_id_t topo_make_apicid(unsigned nr_cores,
> + unsigned nr_threads,
> + unsigned pkg_id, unsigned core_id,
> + unsigned smt_id)
> +{
> + return (pkg_id << apicid_pkg_offset(nr_cores, nr_threads)) | \
> + (core_id << apicid_core_offset(nr_cores, nr_threads)) | \
> + smt_id;
> +}
Looks like it considers only Intel spec, would it be correct for AMD case?
see support.amd.com/us/Embedded_TechDocs/25481.pdf "3.2 Extended Method"
AMD doesn't have SMT, perhaps nr_threads should be enforced to 1 when VCPU is
AMD?
> +
> +/* Calculate thread/core/package IDs for a specific topology,
> + * based on (continguous) CPU index
> + */
> +static inline void topo_ids_from_idx(unsigned nr_cores, unsigned nr_threads,
> + unsigned cpu_index,
> + unsigned *pkg_id, unsigned *core_id,
> + unsigned *smt_id)
> +{
> + unsigned core_index = cpu_index / nr_threads;
> + *smt_id = cpu_index % nr_threads;
> + *core_id = core_index % nr_cores;
> + *pkg_id = core_index / nr_cores;
> +}
> +
> +/* Get package ID from an APIC ID
> + */
> +static inline unsigned apicid_pkg_id(unsigned nr_cores, unsigned nr_threads,
> + apic_id_t apic_id)
> +{
> + return apic_id >> apicid_pkg_offset(nr_cores, nr_threads);
> +}
> +
> +/* Get core ID from an APIC ID
> + */
> +static inline unsigned apicid_core_id(unsigned nr_cores, unsigned nr_threads,
> + apic_id_t apic_id)
> +{
> + return (apic_id >> apicid_core_offset(nr_cores, nr_threads)) & \
> + ((1 << apicid_core_width(nr_cores, nr_threads)) - 1);
> +}
> +
> +/* Get SMT (thread) ID from an APIC ID
> + */
> +static inline unsigned apicid_smt_id(unsigned nr_cores, unsigned nr_threads,
> + apic_id_t apic_id)
> +{
> + return apic_id & ((1 << apicid_smt_width(nr_cores, nr_threads)) - 1);
> +}
Are above getters necessary for fix to work or are there plans to use them?
> +
> +/* Make APIC ID for the CPU 'cpu_index'
> + *
> + * 'cpu_index' is a sequential, contiguous ID for the CPU.
> + */
> +static inline apic_id_t topo_apicid_for_cpu(unsigned nr_cores,
> + unsigned nr_threads,
> + unsigned cpu_index)
> +{
> + unsigned pkg_id, core_id, smt_id;
> + topo_ids_from_idx(nr_cores, nr_threads, cpu_index,
> + &pkg_id, &core_id, &smt_id);
> + return topo_make_apicid(nr_cores, nr_threads, pkg_id, core_id, smt_id);
> +}
> +
> +#endif /* TARGET_I386_TOPOLOGY_H */
> diff --git a/tests/.gitignore b/tests/.gitignore
> index f9041f3..38c94ef 100644
> --- a/tests/.gitignore
> +++ b/tests/.gitignore
> @@ -10,4 +10,5 @@ test-qmp-commands.h
> test-qmp-commands
> test-qmp-input-strict
> test-qmp-marshal.c
> +test-x86-cpuid
> *-test
> diff --git a/tests/Makefile b/tests/Makefile
> index 79796aa..e74efdd 100644
> --- a/tests/Makefile
> +++ b/tests/Makefile
> @@ -15,6 +15,7 @@ check-unit-y += tests/test-string-output-visitor$(EXESUF)
> check-unit-y += tests/test-coroutine$(EXESUF)
> check-unit-y += tests/test-visitor-serialization$(EXESUF)
> check-unit-y += tests/test-iov$(EXESUF)
> +check-unit-i386-y += tests/test-x86-cpuid$(EXESUF)
>
> check-block-$(CONFIG_POSIX) += tests/qemu-iotests-quick.sh
>
> @@ -35,6 +36,7 @@ test-obj-y = tests/check-qint.o tests/check-qstring.o tests/check-qdict.o \
> tests/test-string-input-visitor.o tests/test-qmp-output-visitor.o \
> tests/test-qmp-input-visitor.o tests/test-qmp-input-strict.o \
> tests/test-qmp-commands.o tests/test-visitor-serialization.o
> +test-obj-i386-y = tests/test-x86-cpuid.o
>
> test-qapi-obj-y = $(qobject-obj-y) $(qapi-obj-y) $(tools-obj-y)
> test-qapi-obj-y += tests/test-qapi-visit.o tests/test-qapi-types.o
> @@ -48,6 +50,7 @@ tests/check-qfloat$(EXESUF): tests/check-qfloat.o qfloat.o $(tools-obj-y)
> tests/check-qjson$(EXESUF): tests/check-qjson.o $(qobject-obj-y) $(tools-obj-y)
> tests/test-coroutine$(EXESUF): tests/test-coroutine.o $(coroutine-obj-y) $(tools-obj-y)
> tests/test-iov$(EXESUF): tests/test-iov.o iov.o
> +tests/test-x86-cpuid$(EXESUF): tests/test-x86-cpuid.o
>
> tests/test-qapi-types.c tests/test-qapi-types.h :\
> $(SRC_PATH)/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-types.py
> diff --git a/tests/test-x86-cpuid.c b/tests/test-x86-cpuid.c
> new file mode 100644
> index 0000000..d782c9c
> --- /dev/null
> +++ b/tests/test-x86-cpuid.c
> @@ -0,0 +1,108 @@
> +/*
> + * Test code for x86 CPUID and Topology functions
> + *
> + * Copyright (c) 2012 Red Hat Inc.
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a copy
> + * of this software and associated documentation files (the "Software"), to deal
> + * in the Software without restriction, including without limitation the rights
> + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
> + * copies of the Software, and to permit persons to whom the Software is
> + * furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice shall be included in
> + * all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
> + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
> + * THE SOFTWARE.
> + */
> +
> +#include <glib.h>
> +
> +/*FIXME: this should be built inside the i386 target directory instead */
> +#include "topology.h"
> +
> +static void test_topo_bits(void)
> +{
> + /* simple tests for 1 thread per core, 1 core per socket */
> + g_assert_cmpuint(apicid_smt_width(1, 1), ==, 0);
> + g_assert_cmpuint(apicid_core_width(1, 1), ==, 0);
> +
> + g_assert_cmpuint(topo_apicid_for_cpu(1, 1, 0), ==, 0);
> + g_assert_cmpuint(topo_apicid_for_cpu(1, 1, 1), ==, 1);
> + g_assert_cmpuint(topo_apicid_for_cpu(1, 1, 2), ==, 2);
> + g_assert_cmpuint(topo_apicid_for_cpu(1, 1, 3), ==, 3);
> +
> +
> + /* Test field width calculation for multiple values
> + */
> + g_assert_cmpuint(apicid_smt_width(1, 2), ==, 1);
> + g_assert_cmpuint(apicid_smt_width(1, 3), ==, 2);
> + g_assert_cmpuint(apicid_smt_width(1, 4), ==, 2);
> +
> + g_assert_cmpuint(apicid_smt_width(1, 14), ==, 4);
> + g_assert_cmpuint(apicid_smt_width(1, 15), ==, 4);
> + g_assert_cmpuint(apicid_smt_width(1, 16), ==, 4);
> + g_assert_cmpuint(apicid_smt_width(1, 17), ==, 5);
> +
> +
> + g_assert_cmpuint(apicid_core_width(30, 2), ==, 5);
> + g_assert_cmpuint(apicid_core_width(31, 2), ==, 5);
> + g_assert_cmpuint(apicid_core_width(32, 2), ==, 5);
> + g_assert_cmpuint(apicid_core_width(33, 2), ==, 6);
> +
> +
> + /* build a weird topology and see if IDs are calculated correctly
> + */
> +
> + /* This will use 2 bits for thread ID and 3 bits for core ID
> + */
> + g_assert_cmpuint( apicid_smt_width(6, 3), ==, 2);
> + g_assert_cmpuint(apicid_core_width(6, 3), ==, 3);
> + g_assert_cmpuint(apicid_pkg_offset(6, 3), ==, 5);
> +
> + g_assert_cmpuint(topo_apicid_for_cpu(6, 3, 0), ==, 0);
> + g_assert_cmpuint(topo_apicid_for_cpu(6, 3, 1), ==, 1);
> + g_assert_cmpuint(topo_apicid_for_cpu(6, 3, 2), ==, 2);
> +
> + g_assert_cmpuint(topo_apicid_for_cpu(6, 3, 1 * 3 + 0), ==, (1 << 2) | 0);
> + g_assert_cmpuint(topo_apicid_for_cpu(6, 3, 1 * 3 + 1), ==, (1 << 2) | 1);
> + g_assert_cmpuint(topo_apicid_for_cpu(6, 3, 1 * 3 + 2), ==, (1 << 2) | 2);
> +
> + g_assert_cmpuint(topo_apicid_for_cpu(6, 3, 2 * 3 + 0), ==, (2 << 2) | 0);
> + g_assert_cmpuint(topo_apicid_for_cpu(6, 3, 2 * 3 + 1), ==, (2 << 2) | 1);
> + g_assert_cmpuint(topo_apicid_for_cpu(6, 3, 2 * 3 + 2), ==, (2 << 2) | 2);
> +
> + g_assert_cmpuint(topo_apicid_for_cpu(6, 3, 5 * 3 + 0), ==, (5 << 2) | 0);
> + g_assert_cmpuint(topo_apicid_for_cpu(6, 3, 5 * 3 + 1), ==, (5 << 2) | 1);
> + g_assert_cmpuint(topo_apicid_for_cpu(6, 3, 5 * 3 + 2), ==, (5 << 2) | 2);
> +
> + g_assert_cmpuint(topo_apicid_for_cpu(6, 3, 1 * 6 * 3 + 0 * 3 + 0), ==,
> + (1 << 5));
> + g_assert_cmpuint(topo_apicid_for_cpu(6, 3, 1 * 6 * 3 + 1 * 3 + 1), ==,
> + (1 << 5) | (1 << 2) | 1);
> + g_assert_cmpuint(topo_apicid_for_cpu(6, 3, 3 * 6 * 3 + 5 * 3 + 2), ==,
> + (3 << 5) | (5 << 2) | 2);
> +
> +
> + /* Check the APIC ID -> {pkg,core,thread} ID functions */
> + g_assert_cmpuint( apicid_pkg_id(6, 3, (3 << 5) | (5 << 2) | 2), ==, 3);
> + g_assert_cmpuint(apicid_core_id(6, 3, (3 << 5) | (5 << 2) | 2), ==, 5);
> + g_assert_cmpuint( apicid_smt_id(6, 3, (3 << 5) | (5 << 2) | 2), ==, 2);
> +}
> +
> +int main(int argc, char **argv)
> +{
> + g_test_init(&argc, &argv, NULL);
> +
> + g_test_add_func("/cpuid/topology/basic", test_topo_bits);
> +
> + g_test_run();
> +
> + return 0;
> +}
> --
> 1.7.11.2
>
>
--
Regards,
Igor
next prev parent reply other threads:[~2012-08-14 17:03 UTC|newest]
Thread overview: 25+ messages / expand[flat|nested] mbox.gz Atom feed top
2012-08-07 19:56 [Qemu-devel] [RFC 00/15] attempt to fix CPU topology info on CPU APIC IDs Eduardo Habkost
2012-08-07 19:56 ` [Qemu-devel] [RFC 01/15] cpus.h: include cpu-common.h Eduardo Habkost
2012-08-13 19:06 ` Igor Mammedov
2012-08-07 19:56 ` [Qemu-devel] [RFC 02/15] hw/apic.c: rename bit functions to not conflict with bitops.h (v2) Eduardo Habkost
2012-08-13 19:08 ` Igor Mammedov
2012-08-07 19:56 ` [Qemu-devel] [RFC 03/15] kvm: set vcpu_id to APIC ID instead of CPU index Eduardo Habkost
2012-08-13 19:16 ` Igor Mammedov
2012-08-13 19:59 ` Eduardo Habkost
2012-08-07 19:56 ` [Qemu-devel] [RFC 04/15] i386: create apic_id_for_cpu() function (v2) Eduardo Habkost
2012-08-07 19:56 ` [Qemu-devel] [RFC 05/15] remove FW_CFG_MAX_CPUS from fw_cfg_init() Eduardo Habkost
2012-08-07 19:56 ` [Qemu-devel] [RFC 06/15] pc: set FW_CFG data based on APIC ID calculation Eduardo Habkost
2012-08-13 19:52 ` Igor Mammedov
2012-08-13 20:01 ` Eduardo Habkost
2012-08-07 19:56 ` [Qemu-devel] [RFC 07/15] qdev: allow qdev_prop_parse() to report errors Eduardo Habkost
2012-08-07 19:56 ` [Qemu-devel] [RFC 08/15] move global properties code to global-properties.c Eduardo Habkost
2012-08-07 19:56 ` [Qemu-devel] [RFC 09/15] isolate qdev-independent parts of qdev_prop_set_globals() Eduardo Habkost
2012-08-07 19:56 ` [Qemu-devel] [RFC 10/15] create object_prop_set_globals() Eduardo Habkost
2012-08-07 19:56 ` [Qemu-devel] [RFC 11/15] rename qdev_prop_register_global_list to qemu_globals_register_list Eduardo Habkost
2012-08-07 19:56 ` [Qemu-devel] [RFC 12/15] create qemu_global_get() function Eduardo Habkost
2012-08-07 19:56 ` [Qemu-devel] [RFC 13/15] tests: support target-specific unit tests Eduardo Habkost
2012-08-07 19:56 ` [Qemu-devel] [RFC 14/15] i386: topology & APIC ID utility functions (v2) Eduardo Habkost
2012-08-08 18:57 ` Blue Swirl
2012-08-08 19:06 ` Eduardo Habkost
2012-08-14 17:03 ` Igor Mammedov [this message]
2012-08-07 19:56 ` [Qemu-devel] [RFC 15/15] generate APIC IDs according to CPU topology (v2) Eduardo Habkost
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20120814190324.20e39cbf@thinkpad.mammed.net \
--to=imammedo@redhat.com \
--cc=afaerber@suse.de \
--cc=blauwirbel@gmail.com \
--cc=ehabkost@redhat.com \
--cc=gleb@redhat.com \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.