This is the mail archive of the
libc-alpha@sourceware.org
mailing list for the glibc project.
Re: V5 [PATCH 2/2] x86: Add a LD_PRELOAD IFUNC resolver test for CPU_FEATURE_USABLE
- From: "H.J. Lu" <hjl dot tools at gmail dot com>
- To: Florian Weimer <fweimer at redhat dot com>
- Cc: libc-alpha at sourceware dot org
- Date: Wed, 24 Oct 2018 05:38:03 -0700
- Subject: Re: V5 [PATCH 2/2] x86: Add a LD_PRELOAD IFUNC resolver test for CPU_FEATURE_USABLE
- References: <20180927194327.7683-1-hjl.tools@gmail.com> <20180927194327.7683-3-hjl.tools@gmail.com> <878t2n908g.fsf@oldenburg.str.redhat.com> <CAMe9rOrkrRd3Ms+J3gw_6O8zqL4-=G+ixrjsygVUamhXffdh3w@mail.gmail.com> <87ftwv61uk.fsf@oldenburg.str.redhat.com>
On 10/24/18, Florian Weimer <fweimer@redhat.com> wrote:
> * H. J. Lu:
>
>> I guess you knew that this issue was independent of my new functions.
>> You will get the same error regardless of what the get_free body has.
>
> Yes, the check is certainly overly conservative. I thought we want to
> remove it. Don't we trigger it in glibc in a few places? If the check
> is gone, then I think we will see incorrect results from the new
> interface.
>
> I think we are very consistent right now when it comes to relocations in
> IFUNC handlers. I want to see this settled before adding something that
> requires a relocation which is (among other things) targeted at IFUNC
> resolvers.
>
<sys/platform/x86.h> isn't targeted for IFUNC. My first use is to add
x86_tsc_to_ns and x86_ns_to_tsc. I am enclosing 2 patches here.
--
H.J.
From 0eda869020f2c77a9d3a850b9ef1d739039a340a Mon Sep 17 00:00:00 2001
From: "H.J. Lu" <hjl.tools@gmail.com>
Date: Thu, 26 Jul 2018 12:45:18 -0700
Subject: [PATCH 1/2] x86: Add COMMON_CPUID_INDEX_[D_ECX_1|80000007|80000008]
Add COMMON_CPUID_INDEX_D_ECX_1, COMMON_CPUID_INDEX_80000007 and
COMMON_CPUID_INDEX_80000008 to check CPU feature bits in them.
* manual/platform.texi: Add entries for INVARIANT_TSC, WBNOINVD,
XGETBV_ECX_1, XSAVEC, XSAVEOPT and XSAVES.
* sysdeps/x86/cpu-features.c (get_extended_indeces): Also
populate COMMON_CPUID_INDEX_80000007 and
COMMON_CPUID_INDEX_80000008.
(get_common_indeces): Also populate COMMON_CPUID_INDEX_D_ECX_1.
Use CPU_FEATURES_CPU_P (cpu_features, XSAVEC) to check if
XSAVEC is available.
* sysdeps/x86/sys/platform/x86.h (bit_arch_XSAVEOPT_Usable): New.
(bit_arch_XGETBV_ECX_1_Usable): Likewise.
(bit_arch_XSAVES_Usable): Likewise.
(bit_arch_INVARIANT_TSC_Usable): Likewise.
(bit_arch_WBNOINVD_Usable): Likewise.
(index_arch_XSAVEOPT_Usable): Likewise.
(index_arch_XGETBV_ECX_1_Usable): Likewise.
(index_arch_XSAVES_Usable): Likewise.
(index_arch_INVARIANT_TSC_Usable): Likewise.
(index_arch_WBNOINVD_Usable): Likewise.
(need_arch_feature_XSAVEOPT): Likewise.
(need_arch_feature_XSAVEC): Likewise.
(need_arch_feature_XGETBV_ECX_1): Likewise.
(need_arch_feature_XSAVES): Likewise.
(need_arch_feature_INVARIANT_TSC): Likewise.
(need_arch_feature_WBNOINVD): Likewise.
(bit_cpu_XSAVEOPT): Likewise.
(bit_cpu_XSAVEC): Likewise.
(bit_cpu_XGETBV_ECX_1): Likewise.
(bit_cpu_XSAVES): Likewise.
(bit_cpu_INVARIANT_TSC): Likewise.
(bit_cpu_WBNOINVD): Likewise.
(index_cpu_XSAVEOPT): Likewise.
(index_cpu_XSAVEC): Likewise.
(index_cpu_XGETBV_ECX_1): Likewise.
(index_cpu_XSAVES): Likewise.
(index_cpu_INVARIANT_TSC): Likewise.
(index_cpu_WBNOINVD): Likewise.
(reg_XSAVEOPT): Likewise.
(reg_XSAVEC): Likewise.
(reg_XGETBV_ECX_1): Likewise.
(reg_XSAVES): Likewise.
(reg_INVARIANT_TSC): Likewise.
(reg_WBNOINVD): Likewise.
(COMMON_CPUID_INDEX_D_ECX_1): Likewise.
(COMMON_CPUID_INDEX_80000007): Likewise.
(COMMON_CPUID_INDEX_80000008): Likewise.
* sysdeps/x86/tst-x86-platform-1.c (do_test): Also check
XSAVEOPT, XSAVEC, XGETBV_ECX_1, XSAVES, INVARIANT_TSC and
WBNOINVD.
---
manual/platform.texi | 20 ++++++++-
sysdeps/x86/cpu-features.c | 24 +++++++++--
sysdeps/x86/sys/platform/x86.h | 73 ++++++++++++++++++++++++++++++++
sysdeps/x86/tst-x86-platform-1.c | 12 ++++++
4 files changed, 124 insertions(+), 5 deletions(-)
diff --git a/manual/platform.texi b/manual/platform.texi
index a2d9cc79fe..b0faa61a67 100644
--- a/manual/platform.texi
+++ b/manual/platform.texi
@@ -305,6 +305,9 @@ by @code{CPUID} instruction. The available features are:
@item
@code{IBT} -- Intel Indirect Branch Tracking instruction extensions.
+@item
+@code{INVARIANT_TSC} -- Invariant TSC.
+
@item
@code{INVPCID} -- INVPCID instruction.
@@ -527,9 +530,15 @@ using a TSC deadline value.
@item
@code{WAITPKG} -- WAITPKG instruction extensions.
+@item
+@code{WBNOINVD} -- WBNOINVD instruction.
+
@item
@code{X2APIC} -- x2APIC.
+@item
+@code{XGETBV_ECX_1} -- XGETBV with ECX = 1.
+
@item
@code{XOP} -- XOP instruction extensions.
@@ -537,6 +546,15 @@ using a TSC deadline value.
@code{XSAVE} -- The XSAVE/XRSTOR processor extended states feature, the
XSETBV/XGETBV instructions, and XCR0.
+@item
+@code{XSAVEC} -- XSAVEC instruction.
+
+@item
+@code{XSAVEOPT} -- XSAVEOPT instruction.
+
+@item
+@code{XSAVES} -- XSAVES/XRSTORS instructions.
+
@item
@code{XTPRUPDCTRL} -- xTPR Update Control.
@@ -588,7 +606,7 @@ The supported features are:
@item
@code{TBM} @tab @code{TSC} @tab @code{VAES} @tab @code{VPCLMULQDQ}
@item
-@code{XOP} @tab @code{XSAVE}
+@code{XOP} @tab @code{XSAVE} @tab @code{XSAVEC}
@end multitable
@end defmac
diff --git a/sysdeps/x86/cpu-features.c b/sysdeps/x86/cpu-features.c
index 5f6ac6664c..f812f406fd 100644
--- a/sysdeps/x86/cpu-features.c
+++ b/sysdeps/x86/cpu-features.c
@@ -53,7 +53,18 @@ get_extended_indices (struct cpu_features *cpu_features)
cpu_features->cpuid[COMMON_CPUID_INDEX_80000001].ebx,
cpu_features->cpuid[COMMON_CPUID_INDEX_80000001].ecx,
cpu_features->cpuid[COMMON_CPUID_INDEX_80000001].edx);
-
+ if (eax >= 0x80000007)
+ __cpuid (0x80000007,
+ cpu_features->cpuid[COMMON_CPUID_INDEX_80000007].eax,
+ cpu_features->cpuid[COMMON_CPUID_INDEX_80000007].ebx,
+ cpu_features->cpuid[COMMON_CPUID_INDEX_80000007].ecx,
+ cpu_features->cpuid[COMMON_CPUID_INDEX_80000007].edx);
+ if (eax >= 0x80000008)
+ __cpuid (0x80000008,
+ cpu_features->cpuid[COMMON_CPUID_INDEX_80000008].eax,
+ cpu_features->cpuid[COMMON_CPUID_INDEX_80000008].ebx,
+ cpu_features->cpuid[COMMON_CPUID_INDEX_80000008].ecx,
+ cpu_features->cpuid[COMMON_CPUID_INDEX_80000008].edx);
}
static void
@@ -86,6 +97,13 @@ get_common_indices (struct cpu_features *cpu_features,
cpu_features->cpuid[COMMON_CPUID_INDEX_7].ecx,
cpu_features->cpuid[COMMON_CPUID_INDEX_7].edx);
+ if (cpu_features->max_cpuid >= 0xd)
+ __cpuid_count (0xd, 1,
+ cpu_features->cpuid[COMMON_CPUID_INDEX_D_ECX_1].eax,
+ cpu_features->cpuid[COMMON_CPUID_INDEX_D_ECX_1].ebx,
+ cpu_features->cpuid[COMMON_CPUID_INDEX_D_ECX_1].ecx,
+ cpu_features->cpuid[COMMON_CPUID_INDEX_D_ECX_1].edx);
+
/* Can we call xgetbv? */
if (CPU_FEATURES_CPU_P (cpu_features, OSXSAVE))
{
@@ -219,10 +237,8 @@ get_common_indices (struct cpu_features *cpu_features,
cpu_features->xsave_state_full_size
= xsave_state_full_size;
- __cpuid_count (0xd, 1, eax, ebx, ecx, edx);
-
/* Check if XSAVEC is available. */
- if ((eax & (1 << 1)) != 0)
+ if (CPU_FEATURES_CPU_P (cpu_features, XSAVEC))
{
unsigned int xstate_comp_offsets[32];
unsigned int xstate_comp_sizes[32];
diff --git a/sysdeps/x86/sys/platform/x86.h b/sysdeps/x86/sys/platform/x86.h
index 48e42ae983..a2c5c7074d 100644
--- a/sysdeps/x86/sys/platform/x86.h
+++ b/sysdeps/x86/sys/platform/x86.h
@@ -38,6 +38,9 @@ enum
COMMON_CPUID_INDEX_1 = 0,
COMMON_CPUID_INDEX_7,
COMMON_CPUID_INDEX_80000001,
+ COMMON_CPUID_INDEX_D_ECX_1,
+ COMMON_CPUID_INDEX_80000007,
+ COMMON_CPUID_INDEX_80000008,
/* Keep the following line at the end. */
COMMON_CPUID_INDEX_MAX
};
@@ -169,6 +172,11 @@ extern unsigned int x86_get_arch_feature (unsigned int)
#define bit_arch_TBM_Usable (1u << 0)
#define bit_arch_SYSCALL_SYSRET_Usable (1u << 0)
#define bit_arch_RDTSCP_Usable (1u << 0)
+#define bit_arch_XSAVEOPT_Usable (1u << 0)
+#define bit_arch_XGETBV_ECX_1_Usable (1u << 0)
+#define bit_arch_XSAVES_Usable (1u << 0)
+#define bit_arch_INVARIANT_TSC_Usable (1u << 0)
+#define bit_arch_WBNOINVD_Usable (1u << 0)
/* Unused. Compiler will optimize them out. */
#define index_arch_SSE3_Usable FEATURE_INDEX_1
@@ -220,6 +228,11 @@ extern unsigned int x86_get_arch_feature (unsigned int)
#define index_arch_TBM_Usable FEATURE_INDEX_1
#define index_arch_SYSCALL_SYSRET_Usable FEATURE_INDEX_1
#define index_arch_RDTSCP_Usable FEATURE_INDEX_1
+#define index_arch_XSAVEOPT_Usable FEATURE_INDEX_1
+#define index_arch_XGETBV_ECX_1_Usable FEATURE_INDEX_1
+#define index_arch_XSAVES_Usable FEATURE_INDEX_1
+#define index_arch_INVARIANT_TSC_Usable FEATURE_INDEX_1
+#define index_arch_WBNOINVD_Usable FEATURE_INDEX_1
/* COMMON_CPUID_INDEX_1. */
@@ -309,6 +322,12 @@ extern unsigned int x86_get_arch_feature (unsigned int)
#define need_arch_feature_TBM 0
#define need_arch_feature_SYSCALL_SYSRET 0
#define need_arch_feature_RDTSCP 0
+#define need_arch_feature_XSAVEOPT 0
+#define need_arch_feature_XSAVEC 1
+#define need_arch_feature_XGETBV_ECX_1 0
+#define need_arch_feature_XSAVES 0
+#define need_arch_feature_INVARIANT_TSC 0
+#define need_arch_feature_WBNOINVD 0
/* CPU features. */
@@ -458,6 +477,24 @@ extern unsigned int x86_get_arch_feature (unsigned int)
#define bit_cpu_RDTSCP (1u << 27)
#define bit_cpu_LM (1u << 29)
+/* COMMON_CPUID_INDEX_D_ECX_1. */
+
+/* EAX. */
+#define bit_cpu_XSAVEOPT (1u << 0)
+#define bit_cpu_XSAVEC (1u << 1)
+#define bit_cpu_XGETBV_ECX_1 (1u << 2)
+#define bit_cpu_XSAVES (1u << 3)
+
+/* COMMON_CPUID_INDEX_80000007. */
+
+/* EDX. */
+#define bit_cpu_INVARIANT_TSC (1u << 8)
+
+/* COMMON_CPUID_INDEX_80000008. */
+
+/* EBX. */
+#define bit_cpu_WBNOINVD (1u << 9)
+
/* COMMON_CPUID_INDEX_1. */
/* ECX. */
@@ -604,6 +641,24 @@ extern unsigned int x86_get_arch_feature (unsigned int)
#define index_cpu_RDTSCP COMMON_CPUID_INDEX_80000001
#define index_cpu_LM COMMON_CPUID_INDEX_80000001
+/* COMMON_CPUID_INDEX_D_ECX_1. */
+
+/* EAX. */
+#define index_cpu_XSAVEOPT COMMON_CPUID_INDEX_D_ECX_1
+#define index_cpu_XSAVEC COMMON_CPUID_INDEX_D_ECX_1
+#define index_cpu_XGETBV_ECX_1 COMMON_CPUID_INDEX_D_ECX_1
+#define index_cpu_XSAVES COMMON_CPUID_INDEX_D_ECX_1
+
+/* COMMON_CPUID_INDEX_80000007. */
+
+/* EDX. */
+#define index_cpu_INVARIANT_TSC COMMON_CPUID_INDEX_80000007
+
+/* COMMON_CPUID_INDEX_80000008. */
+
+/* EBX. */
+#define index_cpu_WBNOINVD COMMON_CPUID_INDEX_80000008
+
/* COMMON_CPUID_INDEX_1. */
/* ECX. */
@@ -750,6 +805,24 @@ extern unsigned int x86_get_arch_feature (unsigned int)
#define reg_RDTSCP edx
#define reg_LM edx
+/* COMMON_CPUID_INDEX_D_ECX_1. */
+
+/* EAX. */
+#define reg_XSAVEOPT eax
+#define reg_XSAVEC eax
+#define reg_XGETBV_ECX_1 eax
+#define reg_XSAVES eax
+
+/* COMMON_CPUID_INDEX_80000007. */
+
+/* EDX. */
+#define reg_INVARIANT_TSC edx
+
+/* COMMON_CPUID_INDEX_80000008. */
+
+/* EBX. */
+#define reg_WBNOINVD ebx
+
__END_DECLS
#endif /* _SYS_PLATFORM_X86_H */
diff --git a/sysdeps/x86/tst-x86-platform-1.c b/sysdeps/x86/tst-x86-platform-1.c
index 7c13d65ab1..56c2c8c8c1 100644
--- a/sysdeps/x86/tst-x86-platform-1.c
+++ b/sysdeps/x86/tst-x86-platform-1.c
@@ -173,6 +173,12 @@ do_test (void)
CHECK_CPU_FEATURE (PAGE1GB);
CHECK_CPU_FEATURE (RDTSCP);
CHECK_CPU_FEATURE (LM);
+ CHECK_CPU_FEATURE (XSAVEOPT);
+ CHECK_CPU_FEATURE (XSAVEC);
+ CHECK_CPU_FEATURE (XGETBV_ECX_1);
+ CHECK_CPU_FEATURE (XSAVES);
+ CHECK_CPU_FEATURE (INVARIANT_TSC);
+ CHECK_CPU_FEATURE (WBNOINVD);
printf ("Usable CPU features:\n");
CHECK_CPU_FEATURE_USABLE (SSE3);
@@ -245,6 +251,12 @@ do_test (void)
CHECK_CPU_FEATURE_USABLE (TBM);
CHECK_CPU_FEATURE_USABLE (SYSCALL_SYSRET);
CHECK_CPU_FEATURE_USABLE (RDTSCP);
+ CHECK_CPU_FEATURE_USABLE (XSAVEOPT);
+ CHECK_CPU_FEATURE_USABLE (XSAVEC);
+ CHECK_CPU_FEATURE_USABLE (XGETBV_ECX_1);
+ CHECK_CPU_FEATURE_USABLE (XSAVES);
+ CHECK_CPU_FEATURE_USABLE (INVARIANT_TSC);
+ CHECK_CPU_FEATURE_USABLE (WBNOINVD);
return 0;
}
--
2.17.2
From d596a8620e40be7052329acdc1c4dc505f68e017 Mon Sep 17 00:00:00 2001
From: "H.J. Lu" <hjl.tools@gmail.com>
Date: Thu, 26 Jul 2018 13:46:05 -0700
Subject: [PATCH 2/2] sys/platform/x86.h: Add x86_tsc_to_ns/x86_ns_to_tsc
If "CPU_FEATURE_USABLE (TSC_To_NS)" evaluates true,
extern unsigned long long x86_tsc_to_ns (unsigned long long);
extern unsigned long long x86_ns_to_tsc (unsigned long long);
can be used to convert between time stamp counters (TSCs) and nanoseconds.
* manual/platform.texi: Document x86_tsc_to_ns, x86_ns_to_tsc
and TSC_To_NS.
* sysdeps/mach/hurd/i386/libc.abilist: Add x86_ns_to_tsc and
x86_tsc_to_ns.
* sysdeps/unix/sysv/linux/i386/libc.abilist: Likewise.
* sysdeps/unix/sysv/linux/x86_64/64/libc.abilist: Likewise.
* sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist: Likewise.
* sysdeps/x86/Makefile (sysdep_routines): Add tsc-ns.
(tests): Add tst-tsc-ns and tst-tsc-ns-static.
(tests-static): Add tst-tsc-ns-static.
* sysdeps/x86/Versions (libc::GLIBC_2.29): Add x86_tsc_to_ns
and x86_ns_to_tsc.
* sysdeps/x86/cpu-features.c (init_cpu_features): Update
tsc_nccc_data and set TSC_To_NS_Usable if supported.
* sysdeps/x86/cpu-features.h (tsc_nccc_info): New.
(cpu_features): Add tsc_nccc_data.
* sysdeps/x86/cpu-tunables.c (TUNABLE_CALLBACK (set_hwcaps)):
Support TSC_To_NS_Usable.
* sysdeps/x86/sys/platform/x86.h (x86_tsc_to_ns): New.
(x86_ns_to_tsc): Likewise.
(bit_arch_TSC_To_NS_Usable): Likewise.
(index_arch_TSC_To_NS_Usable): Likewise.
(bit_cpu_TSC_To_NS): Likewise.
(index_cpu_TSC_To_NS): Likewise.
(reg_TSC_To_NS): Likewise.
(need_arch_feature_TSC_To_NS): Likewise.
* sysdeps/x86/tsc-ns.c: New file.
* sysdeps/x86/tst-tsc-ns-static.c: Likewise.
* sysdeps/x86/tst-tsc-ns.c: Likewise.
* sysdeps/x86/tst-x86-platform-1.c (do_test): Also check
TSC_To_NS.
---
manual/platform.texi | 14 +++-
sysdeps/mach/hurd/i386/libc.abilist | 2 +
sysdeps/unix/sysv/linux/i386/libc.abilist | 2 +
.../unix/sysv/linux/x86_64/64/libc.abilist | 2 +
.../unix/sysv/linux/x86_64/x32/libc.abilist | 2 +
sysdeps/x86/Makefile | 5 ++
sysdeps/x86/Versions | 6 ++
sysdeps/x86/cpu-features.c | 41 ++++++++++++
sysdeps/x86/cpu-features.h | 13 ++++
sysdeps/x86/cpu-tunables.c | 9 ++-
sysdeps/x86/sys/platform/x86.h | 17 +++++
sysdeps/x86/tsc-ns.c | 64 +++++++++++++++++++
sysdeps/x86/tst-tsc-ns-static.c | 1 +
sysdeps/x86/tst-tsc-ns.c | 51 +++++++++++++++
sysdeps/x86/tst-x86-platform-1.c | 2 +
15 files changed, 227 insertions(+), 4 deletions(-)
create mode 100644 sysdeps/x86/tsc-ns.c
create mode 100644 sysdeps/x86/tst-tsc-ns-static.c
create mode 100644 sysdeps/x86/tst-tsc-ns.c
diff --git a/manual/platform.texi b/manual/platform.texi
index b0faa61a67..a3f43a1a1f 100644
--- a/manual/platform.texi
+++ b/manual/platform.texi
@@ -151,6 +151,18 @@ Internal function used by @code{HAS_CPU_FEATURE}.
Internal function used by @code{CPU_FEATURE_USABLE}.
@end deftypefun
+@deftypefun {unsigned long long} x86_tsc_to_ns (unsigned long long)
+
+Convert time stamp counter (TSC) to nanosecond if
+@code{CPU_FEATURE_USABLE (TSC_To_NS)} evaluates to true.
+@end deftypefun
+
+@deftypefun {unsigned long long} x86_ns_to_tsc (unsigned long long)
+
+Convert nanosecond to time stamp counter (TSC) if
+@code{CPU_FEATURE_USABLE (TSC_To_NS)} evaluates to true.
+@end deftypefun
+
@defmac HAS_CPU_FEATURE(name)
Evaluate to true if the CPU feature @code{name} is supported as indicated
@@ -606,7 +618,7 @@ The supported features are:
@item
@code{TBM} @tab @code{TSC} @tab @code{VAES} @tab @code{VPCLMULQDQ}
@item
-@code{XOP} @tab @code{XSAVE} @tab @code{XSAVEC}
+@code{XOP} @tab @code{XSAVE} @tab @code{XSAVEC} @tab @code{TSC_To_NS}
@end multitable
@end defmac
diff --git a/sysdeps/mach/hurd/i386/libc.abilist b/sysdeps/mach/hurd/i386/libc.abilist
index e3fc05137b..deadfda6a9 100644
--- a/sysdeps/mach/hurd/i386/libc.abilist
+++ b/sysdeps/mach/hurd/i386/libc.abilist
@@ -2038,6 +2038,8 @@ GLIBC_2.27 wcstof64x_l F
GLIBC_2.28 fcntl64 F
GLIBC_2.28 renameat2 F
GLIBC_2.28 statx F
+GLIBC_2.29 x86_ns_to_tsc F
+GLIBC_2.29 x86_tsc_to_ns F
GLIBC_2.3 __ctype_b_loc F
GLIBC_2.3 __ctype_tolower_loc F
GLIBC_2.3 __ctype_toupper_loc F
diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist
index 9762c81365..f499b74acc 100644
--- a/sysdeps/unix/sysv/linux/i386/libc.abilist
+++ b/sysdeps/unix/sysv/linux/i386/libc.abilist
@@ -2045,6 +2045,8 @@ GLIBC_2.28 thrd_current F
GLIBC_2.28 thrd_equal F
GLIBC_2.28 thrd_sleep F
GLIBC_2.28 thrd_yield F
+GLIBC_2.29 x86_ns_to_tsc F
+GLIBC_2.29 x86_tsc_to_ns F
GLIBC_2.3 __ctype_b_loc F
GLIBC_2.3 __ctype_tolower_loc F
GLIBC_2.3 __ctype_toupper_loc F
diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
index 816e4a7426..436c18162b 100644
--- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
@@ -1895,6 +1895,8 @@ GLIBC_2.28 thrd_current F
GLIBC_2.28 thrd_equal F
GLIBC_2.28 thrd_sleep F
GLIBC_2.28 thrd_yield F
+GLIBC_2.29 x86_ns_to_tsc F
+GLIBC_2.29 x86_tsc_to_ns F
GLIBC_2.3 __ctype_b_loc F
GLIBC_2.3 __ctype_tolower_loc F
GLIBC_2.3 __ctype_toupper_loc F
diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
index 6fee16a850..61a23fb686 100644
--- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
@@ -2146,3 +2146,5 @@ GLIBC_2.28 thrd_current F
GLIBC_2.28 thrd_equal F
GLIBC_2.28 thrd_sleep F
GLIBC_2.28 thrd_yield F
+GLIBC_2.29 x86_ns_to_tsc F
+GLIBC_2.29 x86_tsc_to_ns F
diff --git a/sysdeps/x86/Makefile b/sysdeps/x86/Makefile
index 1e759d3efc..b2433c4317 100644
--- a/sysdeps/x86/Makefile
+++ b/sysdeps/x86/Makefile
@@ -26,6 +26,11 @@ endif
ifeq ($(subdir),misc)
sysdep_headers += sys/platform/x86.h
+
+sysdep_routines += tsc-ns
+
+tests += tst-tsc-ns tst-tsc-ns-static
+tests-static += tst-tsc-ns-static
endif
ifeq ($(subdir),setjmp)
diff --git a/sysdeps/x86/Versions b/sysdeps/x86/Versions
index 92ab4d93a3..7481c6ec56 100644
--- a/sysdeps/x86/Versions
+++ b/sysdeps/x86/Versions
@@ -1,3 +1,9 @@
+libc {
+ GLIBC_2.29 {
+ x86_tsc_to_ns; x86_ns_to_tsc;
+ }
+}
+
ld {
GLIBC_2.29 {
x86_get_cpuid_registers; x86_get_arch_feature;
diff --git a/sysdeps/x86/cpu-features.c b/sysdeps/x86/cpu-features.c
index f812f406fd..31e3474e38 100644
--- a/sysdeps/x86/cpu-features.c
+++ b/sysdeps/x86/cpu-features.c
@@ -423,6 +423,47 @@ init_cpu_features (struct cpu_features *cpu_features)
else
cpu_features->feature[index_arch_Prefer_No_AVX512]
|= bit_arch_Prefer_No_AVX512;
+
+ if (cpu_features->max_cpuid >= 0x15
+ && CPU_FEATURES_CPU_P (cpu_features, INVARIANT_TSC))
+ {
+ unsigned int frequency = 0;
+ unsigned int nominator = 0;
+
+ __cpuid (0x15,
+ cpu_features->tsc_nccc_data.denominator,
+ nominator, frequency, edx);
+ if (nominator != 0 && frequency == 0 && family == 6)
+ switch (model)
+ {
+ case 0x55:
+ /* Skylake server is 25 MHz. */
+ frequency = 25 * 1000 * 1000;
+ break;
+ case 0x5c:
+ /* Goldmont is 19.2 MHz. */
+ frequency = 19.2 * 1000 * 1000;
+ break;
+ default:
+ if (CPU_FEATURES_CPU_P (cpu_features, AVX2)
+ && CPU_FEATURES_CPU_P (cpu_features, XSAVEC)
+ && CPU_FEATURES_CPU_P (cpu_features,
+ XGETBV_ECX_1))
+ {
+ /* Skylake client is 24 MHz. */
+ frequency = 24 * 1000 * 1000;
+ break;
+ }
+ }
+ if (frequency != 0)
+ {
+ /* Store frequency as kHz. */
+ cpu_features->tsc_nccc_data.frequency = frequency / 1000;
+ cpu_features->tsc_nccc_data.nominator = nominator;
+ cpu_features->feature[index_arch_TSC_To_NS_Usable]
+ |= bit_arch_TSC_To_NS_Usable;
+ }
+ }
}
/* This spells out "AuthenticAMD". */
else if (ebx == 0x68747541 && ecx == 0x444d4163 && edx == 0x69746e65)
diff --git a/sysdeps/x86/cpu-features.h b/sysdeps/x86/cpu-features.h
index 9ffa77e040..2db5249018 100644
--- a/sysdeps/x86/cpu-features.h
+++ b/sysdeps/x86/cpu-features.h
@@ -70,6 +70,17 @@ enum cpu_features_kind
arch_kind_other
};
+/* Time Stamp Counter and Nominal Core Crystal Clock Information. */
+struct tsc_nccc_info
+{
+ /* The denominator of the TSC/core crystal clock ratio. */
+ unsigned int denominator;
+ /* The numerator of the TSC/core crystal clock ratio. */
+ unsigned int nominator;
+ /* The nominal frequency of the core crystal clock in Hz. */
+ unsigned int frequency;
+};
+
struct cpu_features
{
enum cpu_features_kind kind;
@@ -98,6 +109,8 @@ struct cpu_features
unsigned long int shared_cache_size;
/* Threshold to use non temporal store. */
unsigned long int non_temporal_threshold;
+ /* Time Stamp Counter and Nominal Core Crystal Clock Information. */
+ struct tsc_nccc_info tsc_nccc_data;
};
/* Used from outside of glibc to get access to the CPU features
diff --git a/sysdeps/x86/cpu-tunables.c b/sysdeps/x86/cpu-tunables.c
index 8e92358c67..89df38c870 100644
--- a/sysdeps/x86/cpu-tunables.c
+++ b/sysdeps/x86/cpu-tunables.c
@@ -271,11 +271,14 @@ TUNABLE_CALLBACK (set_hwcaps) (tunable_val_t *valp)
disable, 15);
break;
case 16:
+ if (disable)
{
- CHECK_GLIBC_IFUNC_ARCH_NEED_ARCH_BOTH
- (n, cpu_features, Prefer_No_AVX512, AVX512F_Usable,
- disable, 16);
+ CHECK_GLIBC_IFUNC_ARCH_OFF (n, cpu_features,
+ TSC_To_NS_Usable, 16);
}
+ CHECK_GLIBC_IFUNC_ARCH_NEED_ARCH_BOTH
+ (n, cpu_features, Prefer_No_AVX512, AVX512F_Usable,
+ disable, 16);
break;
case 18:
{
diff --git a/sysdeps/x86/sys/platform/x86.h b/sysdeps/x86/sys/platform/x86.h
index a2c5c7074d..168081e08a 100644
--- a/sysdeps/x86/sys/platform/x86.h
+++ b/sysdeps/x86/sys/platform/x86.h
@@ -59,6 +59,9 @@ extern const struct cpuid_registers *x86_get_cpuid_registers
extern unsigned int x86_get_arch_feature (unsigned int)
__attribute__ ((const));
+extern unsigned long long x86_tsc_to_ns (unsigned long long);
+extern unsigned long long x86_ns_to_tsc (unsigned long long);
+
/* HAS_CPU_FEATURE evaluates to true if CPU supports the feature. */
#define HAS_CPU_FEATURE(name) \
((x86_get_cpuid_registers (index_cpu_##name)->reg_##name \
@@ -96,6 +99,7 @@ extern unsigned int x86_get_arch_feature (unsigned int)
#define bit_arch_VPCLMULQDQ_Usable (1u << 20)
#define bit_arch_XOP_Usable (1u << 21)
#define bit_arch_XSAVEC_Usable (1u << 22)
+#define bit_arch_TSC_To_NS_Usable (1u << 23)
#define index_arch_AVX_Usable FEATURE_INDEX_1
#define index_arch_AVX2_Usable FEATURE_INDEX_1
@@ -120,6 +124,7 @@ extern unsigned int x86_get_arch_feature (unsigned int)
#define index_arch_VPCLMULQDQ_Usable FEATURE_INDEX_1
#define index_arch_XOP_Usable FEATURE_INDEX_1
#define index_arch_XSAVEC_Usable FEATURE_INDEX_1
+#define index_arch_TSC_To_NS_Usable FEATURE_INDEX_1
/* Unused. Compiler will optimize them out. */
#define bit_arch_SSE3_Usable (1u << 0)
@@ -234,6 +239,18 @@ extern unsigned int x86_get_arch_feature (unsigned int)
#define index_arch_INVARIANT_TSC_Usable FEATURE_INDEX_1
#define index_arch_WBNOINVD_Usable FEATURE_INDEX_1
+/* Unused. Compiler will optimize them out. */
+#define bit_cpu_TSC_To_NS (1u << 0)
+
+/* Unused. Compiler will optimize them out. */
+#define index_cpu_TSC_To_NS COMMON_CPUID_INDEX_1
+
+/* Unused. Compiler will optimize them out. */
+#define reg_TSC_To_NS eax
+
+/* There is no CPUID bit. */
+#define need_arch_feature_TSC_To_NS 1
+
/* COMMON_CPUID_INDEX_1. */
/* ECX. */
diff --git a/sysdeps/x86/tsc-ns.c b/sysdeps/x86/tsc-ns.c
new file mode 100644
index 0000000000..ba1e677382
--- /dev/null
+++ b/sysdeps/x86/tsc-ns.c
@@ -0,0 +1,64 @@
+/* Conversion functions between TSCs and nanoseconds.
+ Copyright (C) 2018 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <ldsodefs.h>
+
+static struct tsc_nccc_info tsc_nccc_data;
+
+static void
+__attribute__((constructor))
+init_tsc_nccc_data (void)
+{
+ const struct cpu_features* cpu_features = __get_cpu_features ();
+ if (CPU_FEATURES_ARCH_P (cpu_features, TSC_To_NS_Usable))
+ tsc_nccc_data = cpu_features->tsc_nccc_data;
+}
+
+unsigned long long
+x86_tsc_to_ns (unsigned long long tsc)
+{
+ if (__glibc_unlikely (tsc_nccc_data.frequency == 0))
+ return 0;
+
+ /* Use double to avoid integer overflow. */
+ double tmp = tsc;
+ tmp *= tsc_nccc_data.denominator * 1000000;
+ tmp /= tsc_nccc_data.frequency;
+ unsigned long long ns = tmp;
+ /* Round to the closest integer. */
+ ns += tsc_nccc_data.nominator / 2;
+ return ns / tsc_nccc_data.nominator;
+
+}
+
+unsigned long long
+x86_ns_to_tsc (unsigned long long ns)
+{
+ if (__glibc_unlikely (tsc_nccc_data.frequency == 0))
+ return 0;
+
+ /* Use double to avoid integer overflow. */
+ double tmp = ns;
+ tmp *= tsc_nccc_data.frequency;
+ tmp *= tsc_nccc_data.nominator;
+ tmp /= tsc_nccc_data.denominator;
+ unsigned long long tsc = tmp;
+ /* Round to the closest integer. */
+ ns += 1000000 / 2;
+ return tsc / 1000000;
+}
diff --git a/sysdeps/x86/tst-tsc-ns-static.c b/sysdeps/x86/tst-tsc-ns-static.c
new file mode 100644
index 0000000000..ceb5ebc682
--- /dev/null
+++ b/sysdeps/x86/tst-tsc-ns-static.c
@@ -0,0 +1 @@
+#include "tst-tsc-ns.c"
diff --git a/sysdeps/x86/tst-tsc-ns.c b/sysdeps/x86/tst-tsc-ns.c
new file mode 100644
index 0000000000..b3a11f311c
--- /dev/null
+++ b/sysdeps/x86/tst-tsc-ns.c
@@ -0,0 +1,51 @@
+/* Test cases for x86 conversion functions between TSCs and nanoseconds.
+ Copyright (C) 2015-2018 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <x86intrin.h>
+#include <sys/platform/x86.h>
+
+static int do_test (void);
+
+#include <support/test-driver.c>
+
+static int
+do_test (void)
+{
+ if (!CPU_FEATURE_USABLE (TSC_To_NS))
+ return EXIT_UNSUPPORTED;
+
+ unsigned long long start_tscs, end_tscs, diff_tscs;
+ unsigned long long diff_nanoseconds;
+ start_tscs = _rdtsc ();
+ end_tscs = _rdtsc ();
+ diff_tscs = end_tscs - start_tscs;
+ diff_nanoseconds = x86_tsc_to_ns (diff_tscs);
+
+ printf ("Diff: %lld (TSCs) -> %lld (nanoseconds)\n",
+ diff_tscs, diff_nanoseconds);
+
+ diff_tscs = x86_ns_to_tsc (diff_nanoseconds);
+
+ printf ("Diff: %lld (nanoseconds) -> %lld (TSCs)\n",
+ diff_nanoseconds, diff_tscs);
+
+ return EXIT_SUCCESS;
+}
diff --git a/sysdeps/x86/tst-x86-platform-1.c b/sysdeps/x86/tst-x86-platform-1.c
index 56c2c8c8c1..6c572f25c6 100644
--- a/sysdeps/x86/tst-x86-platform-1.c
+++ b/sysdeps/x86/tst-x86-platform-1.c
@@ -258,6 +258,8 @@ do_test (void)
CHECK_CPU_FEATURE_USABLE (INVARIANT_TSC);
CHECK_CPU_FEATURE_USABLE (WBNOINVD);
+ CHECK_CPU_FEATURE_USABLE (TSC_To_NS);
+
return 0;
}
--
2.17.2