Автор: Эрик Палмер (Eric Palmer)
При разработке для платформ x64 в Visual Studio .NET* 2005 программисты уже не могут использовать встроенный ассемблерный код, как в случае 32-разрядного кода. Это вынуждает программистов либо полагаться на код C/C++, используя встроенные средства, либо использовать трудоемкое создание 64-разрядной MASM (.asm) версии функции. К сожалению, реализация встроенного средства VS .Net 2005 для CPUID (__cpuid) распознает только входные параметры в регистре eax, и не распознает определенные позже входные параметры в ecx, которые требуются для запросов, связанных с параметрами кэша и определенными многоядерными характеристиками. Таким образом, для использования функции CPUID в полном объеме требуется 64-разрядный .asm листинг.
Следующие примеры кодов демонстрируют, как использовать команды CUPID и RDSTC с VS.NET 2005 для 64-разрядных (x64) платформ. Команда CPUID обычно применяется для получения подробной информации о ЦП системы, а RDTSC используется для считывания внутреннего счетчика системного времени ЦП для целей синхронизации и измерения производительности. Встроенное средство RDTSC (__rdtsc) должно работать, как и предполагается, и может использоваться вместо встроенного ассемблера.
Для компоновки 64-разрядного файла .asm создайте пользовательский шаг компоновки, который вызывает 64-разрядный MASM, "ml64.exe", как показано на приведенном ниже моментальном снимке экрана. Для 32-разрядной конфигурации файл cpuid64.asm компоновать не следует, поэтому для платформы Win32 установите значение Да для опции Общие -> Исключить из компоновки.

(Для увеличения нажмите на изображение)
Показанный ниже файл заголовка (cpuid_32_64.h) создает единое определение функций _CPUID и _RDTSC, которое можно использовать и в 32-разрядных, и в 64-разрядных компоновках. Для 64-разрядных компоновок _CPUID использует .asm-функцию cpuid64, а _RDTSC использует встроенное средство __rdtsc. Для 32-разрядных компоновок _CPUID использует функцию встроенного ассемблера cpuid32, а _RDTSC - функцию _inl_rdtsc32.
В представленном ниже файле C (cpuid_32_64.c) показано два примера. В первом из них - GetCoresPerPackage() - вызывается _CPUID с eax=4 и ecx=0 для считывания детерминированных параметров кэша первого набора, представленных ЦП, и извлечения поля, указывающего число ядер процессора в процессорном пакете. (Например, эта функция будет возвращать значение 1 в случае одноядерного процессора Intel® Pentium® 4 и значение 2 в случае двухъядерного процессора Intel® Pentium® D.) Если в этой функции на платформе x64 использовалось бы встроенное средство __cpuid вместо функции cpuid64, входящее значение ecx было бы недетерминированным, и значение вывода было бы недостоверным. Во втором примере функция timeSomethingExample() дважды вызывает _RDTSC и вычисляет число тактов счетчика в цикле. Пример _CPUID показывает, как можно использовать одно и то же определение для вызова либо 64-разрядного кода .asm, либо 32-разрядного встроенного ассемблера, а в примере _RDTSC показано, как с помощью одного определения можно вызывать либо 64--разрядное встроенное средство, либо 32-разрядный встроенный ассемблер.
И в примере _CPUID, и в примере _RDTSC показано создание служебных функций, явно портируемых с платформ Win32 на платформы x64 в тех случаях, когда для каждой платформы требуется свой базовый код. Кроме того, функция cpuid64 позволяет обойти недостаток встроенного средства __cpuid, обеспечивая возможность и 32-разрядным, и 64-разрядным приложениям полностью использовать возможности команды CPUID.
Файл заголовка (cpuid_32_64.h):
32/64-разрядный файл .c (cpuid_32_64.c):
64-разрядный файл .asm (cpuid64.asm):
При разработке для платформ x64 в Visual Studio .NET* 2005 программисты уже не могут использовать встроенный ассемблерный код, как в случае 32-разрядного кода. Это вынуждает программистов либо полагаться на код C/C++, используя встроенные средства, либо использовать трудоемкое создание 64-разрядной MASM (.asm) версии функции. К сожалению, реализация встроенного средства VS .Net 2005 для CPUID (__cpuid) распознает только входные параметры в регистре eax, и не распознает определенные позже входные параметры в ecx, которые требуются для запросов, связанных с параметрами кэша и определенными многоядерными характеристиками. Таким образом, для использования функции CPUID в полном объеме требуется 64-разрядный .asm листинг.
Следующие примеры кодов демонстрируют, как использовать команды CUPID и RDSTC с VS.NET 2005 для 64-разрядных (x64) платформ. Команда CPUID обычно применяется для получения подробной информации о ЦП системы, а RDTSC используется для считывания внутреннего счетчика системного времени ЦП для целей синхронизации и измерения производительности. Встроенное средство RDTSC (__rdtsc) должно работать, как и предполагается, и может использоваться вместо встроенного ассемблера.
Для компоновки 64-разрядного файла .asm создайте пользовательский шаг компоновки, который вызывает 64-разрядный MASM, "ml64.exe", как показано на приведенном ниже моментальном снимке экрана. Для 32-разрядной конфигурации файл cpuid64.asm компоновать не следует, поэтому для платформы Win32 установите значение Да для опции Общие -> Исключить из компоновки.

(Для увеличения нажмите на изображение)
Показанный ниже файл заголовка (cpuid_32_64.h) создает единое определение функций _CPUID и _RDTSC, которое можно использовать и в 32-разрядных, и в 64-разрядных компоновках. Для 64-разрядных компоновок _CPUID использует .asm-функцию cpuid64, а _RDTSC использует встроенное средство __rdtsc. Для 32-разрядных компоновок _CPUID использует функцию встроенного ассемблера cpuid32, а _RDTSC - функцию _inl_rdtsc32.
В представленном ниже файле C (cpuid_32_64.c) показано два примера. В первом из них - GetCoresPerPackage() - вызывается _CPUID с eax=4 и ecx=0 для считывания детерминированных параметров кэша первого набора, представленных ЦП, и извлечения поля, указывающего число ядер процессора в процессорном пакете. (Например, эта функция будет возвращать значение 1 в случае одноядерного процессора Intel® Pentium® 4 и значение 2 в случае двухъядерного процессора Intel® Pentium® D.) Если в этой функции на платформе x64 использовалось бы встроенное средство __cpuid вместо функции cpuid64, входящее значение ecx было бы недетерминированным, и значение вывода было бы недостоверным. Во втором примере функция timeSomethingExample() дважды вызывает _RDTSC и вычисляет число тактов счетчика в цикле. Пример _CPUID показывает, как можно использовать одно и то же определение для вызова либо 64-разрядного кода .asm, либо 32-разрядного встроенного ассемблера, а в примере _RDTSC показано, как с помощью одного определения можно вызывать либо 64--разрядное встроенное средство, либо 32-разрядный встроенный ассемблер.
И в примере _CPUID, и в примере _RDTSC показано создание служебных функций, явно портируемых с платформ Win32 на платформы x64 в тех случаях, когда для каждой платформы требуется свой базовый код. Кроме того, функция cpuid64 позволяет обойти недостаток встроенного средства __cpuid, обеспечивая возможность и 32-разрядным, и 64-разрядным приложениям полностью использовать возможности команды CPUID.
Файл заголовка (cpuid_32_64.h):
#pragma once
typedef struct cpuid_args_s {
DWORD eax;
DWORD ebx;
DWORD ecx;
DWORD edx;
} CPUID_ARGS;
#ifdef __cplusplus
extern "C" {
#endif
#ifdef _M_X64 // For 64-bit apps
unsigned __int64 __rdtsc(void);
#pragma intrinsic(__rdtsc)
#define _RDTSC __rdtsc
void cpuid64(CPUID_ARGS* p);
#define _CPUID cpuid64
#else // For 32-bit apps
#define _RDTSC_STACK(ts) \
__asm rdtsc \
__asm mov DWORD PTR [ts], eax \
__asm mov DWORD PTR [ts+4], edx
__inline unsigned __int64 _inl_rdtsc32() {
unsigned __int64 t;
_RDTSC_STACK(t);
return t;
}
#define _RDTSC _inl_rdtsc32
void cpuid32(CPUID_ARGS* p);
#define _CPUID cpuid32
#endif
// Our 32/64-bit example function
int GetCoresPerPackage();
#ifdef __cplusplus
}
#endif
|
32/64-разрядный файл .c (cpuid_32_64.c):
|
64-разрядный файл .asm (cpuid64.asm):
|
