source: Plugins/rdtscTimeSource/Cpu.cpp @ 1

Revision 1, 6.1 KB checked in by art, 13 years ago (diff)
Line 
1/***************************************************************************
2 *                                                                         *
3 *   (c) Art Tevs, MPI Informatik Saarbruecken                             *
4 *       mailto: <tevs@mpi-sb.mpg.de>                                      *
5 *                                                                         *
6 *   This program is free software; you can redistribute it and/or modify  *
7 *   it under the terms of the GNU General Public License as published by  *
8 *   the Free Software Foundation; either version 2 of the License, or     *
9 *   (at your option) any later version.                                   *
10 *                                                                         *
11 ***************************************************************************/
12
13
14//----------------------------------------------------------------------------------
15// Includes
16//----------------------------------------------------------------------------------
17#include "Cpu.h"
18
19//----------------------------------------------------------------------------------
20// Defines
21// bit flags set by cpuid when called with register eax set to 1
22//----------------------------------------------------------------------------------
23#define MMX_SUPPORTED                   (1 << 23)
24#define SSE_SUPPORTED                   (1 << 25)
25#define SSE2_SUPPORTED          (1 << 26)
26#define RDTSC_SUPPORTED         (1 << 4)
27
28#define GET_EXTENDED_VALUES                             0x80000000
29#define EXTENDED_VALUES_SUPPORTED       0x80000001
30
31// AMD specific
32#define AMD_3DNOW_EXT_SUPPORTED (1 << 30)
33#define AMD_3DNOW_SUPPORTED                     (1 << 31)
34#define AMD_MMX_EX_SUPPORTED            (1 << 24)
35
36//--------------------------------------------------------------------
37ScriptFunctionDec(getCpuString, Cpu){
38
39        Cpu* cpu = ScriptEngine::parameter_cast<Cpu*>(param[0]);
40
41        return ScriptResult(cpu->m_strDescr);
42}
43
44
45//--------------------------------------------------------------------
46Cpu::Cpu() : m_strVendor("Unkown"),m_strName("Unkown")
47{
48        m_nSpeed        = 0;
49        m_fSpeedMhz  = 0.0f;
50        m_bMMX          = false;
51        m_bSSE          = false;
52        m_bSSE2         = false;
53        m_b3DNowEx= false;
54        m_b3DNow        = false;
55        m_bRDTSC  = false;
56}
57
58//--------------------------------------------------------------------
59void Cpu::detect()
60{
61        // detection can only be done, if cpuid is supported
62        if (!_cpuidSupported())
63        {
64                m_strDescr = "Can not retrieve CPU Information, because cpuid instruction is not supported";
65                return;
66        }
67
68        // local variables;
69        char szVendor[13];
70        uint32 eax = 0;
71        uint32 ebx = 0;
72        uint32 edx = 0;
73        uint32 unused = 0;
74
75        // Get the CPU - Vendor name
76        _cpuid(0, eax, ebx, unused, edx);
77        *(uint32 *)(szVendor) = ebx;
78        *(uint32 *)(szVendor + 4) = edx;
79        *(uint32 *)(szVendor + 8) = unused;
80        szVendor[12] = '\0';
81        m_strVendor = szVendor;
82
83        // now check for intel's extensions
84        _cpuid(1, eax, ebx, unused, edx);
85        m_bMMX      = ((edx & MMX_SUPPORTED) != 0);
86        m_bSSE      = ((edx & SSE_SUPPORTED) != 0);
87        m_bSSE2     = ((edx & SSE2_SUPPORTED) != 0);
88        m_bRDTSC                = ((edx & RDTSC_SUPPORTED) != 0);
89
90        // check for AMD Specific extensions
91        _cpuid(GET_EXTENDED_VALUES, eax, ebx, unused, edx);
92        if(eax >= EXTENDED_VALUES_SUPPORTED)
93        {
94                _cpuid(EXTENDED_VALUES_SUPPORTED, eax, ebx, unused, edx);
95                m_b3DNow = ((edx & AMD_3DNOW_SUPPORTED) != 0);
96                m_b3DNowEx = ((edx & AMD_3DNOW_EXT_SUPPORTED) != 0);
97                m_bMMXEx = ((edx & AMD_MMX_EX_SUPPORTED) != 0);
98        }
99
100        // calculate the speed
101        calculateSpeed();
102
103        // Now generate a formatted description of the CPU
104        char buffer[2056];
105        sprintf(buffer, "CPU %s running at %f MHz, ", getVendor().c_str(), getSpeedMhz());
106        m_strDescr = buffer;
107
108        m_strDescr += "Features: ";
109        if (isRDTSC()) m_strDescr += "rdtsc ";
110        if (isMMX()) m_strDescr += "MMX ";
111        if (isMMXEx()) m_strDescr += "MMXext ";
112        if (isSSE()) m_strDescr += "SSE ";
113        if (isSSE2()) m_strDescr += "SSE2 ";
114        if (is3dNow()) m_strDescr += "3DNow! ";
115        if (is3dNowEx()) m_strDescr += "3DNowExt! ";
116
117}
118
119//--------------------------------------------------------------------
120void Cpu::calculateSpeed(uint32 calcTimeInMilliseconds)
121{
122        // Code is borrowed from SDL-Library - Thanks for That!
123        uint64  nStart, nEnd;
124        struct timeval tv_start, tv_end;
125        int64 usec_delay;
126
127        // get time through the rdtsc
128        rdtsc(nStart);
129        gettimeofday(&tv_start, NULL);
130        nrEngine::sleep(calcTimeInMilliseconds);
131        rdtsc(nEnd);
132        gettimeofday(&tv_end, NULL);
133        usec_delay = 1000000L * (tv_end.tv_sec - tv_start.tv_sec) +
134                                                                                                        (tv_end.tv_usec - tv_start.tv_usec);
135
136        // calculate the speed of the processor
137        m_fSpeedMhz = static_cast<float32>((nEnd - nStart)) / static_cast<float32>(usec_delay);
138        m_nSpeed = static_cast<uint64>(m_fSpeedMhz * 1000.0f);
139
140}
141
142
143//--------------------------------------------------------------------
144void Cpu::_cpuid(uint32 function, uint32 &out_eax, uint32 &out_ebx, uint32 &out_ecx, uint32 &out_edx)
145{
146#if NR_PLATFORM == NR_PLATFORM_WIN32 && NR_COMPILER == NR_COMPILER_MSVC
147        _asm
148        {
149                cpuid
150                mov [out_eax], eax
151                mov [out_ebx], ebx
152                mov [out_ecx], ecx
153                mov [out_edx], edx
154        }
155#else
156        asm volatile(
157        "                                               \
158                push %%ebx;                     \
159                cpuid;                          \
160                mov %%ebx, %%esi;       \
161                pop %%ebx                       \
162        "
163                :       "=a"(out_eax),
164                        "=r"(out_ebx),
165                        "=c"(out_ecx),
166                        "=d"(out_edx)
167                :       "a"(function));
168#endif
169}
170
171//--------------------------------------------------------------------
172bool Cpu::_cpuidSupported()
173{
174        try {
175        #if NR_PLATFORM == NR_PLATFORM_WIN32 && NR_COMPILER == NR_COMPILER_MSVC
176                _asm {
177                                xor eax, eax
178                                cpuid
179                }
180        #else
181                asm volatile("xor %eax, %eax; cpuid;");
182        #endif
183        }catch (...) {
184                return false;
185        }
186
187        return true;
188}
189
190//--------------------------------------------------------------------
191void Cpu::rdtsc(uint64& ticks)
192{
193        // check whenever we got a rdtsc support
194        if (!isRDTSC()){
195                ticks = 0;
196                return;
197        }
198
199        // 2x32 bit variables to hold the ticks
200        uint32 tickLow, tickHigh;
201
202        // get the ticks
203        try{
204        #if NR_PLATFORM == NR_PLATFORM_WIN32 && NR_COMPILER == NR_COMPILER_MSVC
205
206                _asm {
207                                rdtsc
208                                mov [tickLow], eax
209                                mov [tickHigh], edx
210                }
211        #else
212                asm volatile("rdtsc" : "=a"(tickLow), "=d"(tickHigh));
213        #endif
214        }catch(...){
215                ticks = 0;
216                m_bRDTSC = false;
217        }
218
219        // now combine the two values to produce a single 64 bit value
220        ticks = 0;
221        ticks |= tickHigh;
222        ticks <<= 32;
223        ticks |= tickLow;
224
225}
226
Note: See TracBrowser for help on using the repository browser.