Oxygen Basic
Programming => Problems & Solutions => Topic started by: Karen Zibowski on March 08, 2018, 08:45:07 AM
-
I was able to compile the following program without errors, however it just exited when run.
It is a program to get CPU speed, it was working well in PowerBasic
could be something to do with QUAD?
$ filename "GetCpuSpeed_64.exe"
use rtl64
use minwin
' This program will obtain the CPU's speed
Declare Function QueryPerformanceCounter Lib "kernel32" (lpPerformanceCount As QUAD) As Long
Declare Function QueryPerformanceFrequency Lib "kernel32" (lpFrequency As QUAD) As Long
'=====================================
FUNCTION CpuSpeed() AS STRING
LOCAL Count0 AS QUAD
LOCAL Count1 AS QUAD
LOCAL Count2 AS QUAD
LOCAL Freq AS QUAD
LOCAL NewCount AS QUAD
LOCAL CpuFreq AS DWORD
QueryPerformanceFrequency(Freq)
Freq = Freq \ 10
pushad
db &h0f, &h31
mov Count1[04], edx
mov Count1[00], eax
popad
QueryPerformanceCounter(Count0)
NewCount = Count0 + Freq
WHILE (Count0 < NewCount)
QueryPerformanceCounter(Count0)
WEND
pushad
db &h0f, &h31
mov Count2[04], edx
mov Count2[00], eax
popad
CpuFreq = (Count2 - Count1) \ 100000
IF CpuFreq > 1000 THEN
FUNCTION = str(CpuFreq / 1000 ) + " giga hertz"
ELSE
FUNCTION = str(CpuFreq ) + " mega hertz"
END IF
END FUNCTION
'====================
print CpuSpeed
The Powerbasic equivalent is here
#COMPILE EXE
#DIM ALL
#INCLUDE "Win32API.inc"
'===============================
FUNCTION PBMAIN () AS LONG
LOCAL cpuspd AS STRING
cpuspd = CpuSpeed()
? cpuspd
END FUNCTION
'=============================
FUNCTION CpuSpeed() AS STRING
LOCAL Count0 AS QUAD
LOCAL Count1 AS QUAD
LOCAL Count2 AS QUAD
LOCAL Freq AS QUAD
LOCAL NewCount AS QUAD
LOCAL CpuFreq AS DWORD
QueryPerformanceFrequency(Freq)
Freq = Freq \ 10
ASM pushad
ASM db &h0f, &h31
ASM mov Count1[04], edx
ASM mov Count1[00], eax
ASM popad
QueryPerformanceCounter(Count0)
NewCount = Count0 + Freq
WHILE (Count0 < NewCount)
QueryPerformanceCounter(Count0)
WEND
ASM pushad
ASM db &h0f, &h31
ASM mov Count2[04], edx
ASM mov Count2[00], eax
ASM popad
CpuFreq = (Count2 - Count1) \ 100000
IF CpuFreq > 1000 THEN
FUNCTION = FORMAT$(CpuFreq / 1000, "0.000") & " giga hertz"
ELSE
FUNCTION = FORMAT$(CpuFreq, "0,0") & " mega hertz"
END IF
END FUNCTION
-
Karen,
The 64bit binary is now okay but my PC thinks the 32bit binary contains a virus :)
'2018-03-08 T 17:34:33
'64bit debug:
'convert to 64bit regs
'remove pushad and popad (invalid in 64bit mode)
'use rdi as pointer
'inhibit use of rdx register in 64bit mode
$ filename "GetCpuSpeed_64.exe"
use rtl64
use minwin
' This program will obtain the CPU's speed
Declare Function QueryPerformanceCounter Lib "kernel32" (lpPerformanceCount As QUAD) As Long
Declare Function QueryPerformanceFrequency Lib "kernel32" (lpFrequency As QUAD) As Long
'=====================================
FUNCTION CpuSpeed() AS STRING
LOCAL Count0 AS QUAD
LOCAL Count1 AS QUAD
LOCAL Count2 AS QUAD
LOCAL Freq AS QUAD
LOCAL NewCount AS QUAD
LOCAL CpuFreq AS DWORD
QueryPerformanceFrequency(Freq)
Freq = Freq \ 10
db &h0f, &h31
lea rdi,Count1
#ifndef mode64bit
mov [rdi+4], rdx
#endif
mov [rdi], rax
QueryPerformanceCounter(Count0)
NewCount = Count0 + Freq
WHILE (Count0 < NewCount)
QueryPerformanceCounter(Count0)
WEND
db &h0f, &h31
lea rdi,Count2
#ifndef mode64bit
mov [rdi+4], rdx
#endif
mov [rdi], rax
CpuFreq = (Count2 - Count1) \ 100000
IF CpuFreq > 1000 THEN
FUNCTION = str(CpuFreq / 1000 ) + " giga hertz"
ELSE
FUNCTION = str(CpuFreq ) + " mega hertz"
END IF
END FUNCTION
'====================
print CpuSpeed
-
WHILE (Count0 < NewCount)
QueryPerformanceCounter(Count0)
WEND
Is this how you're fighting SpeedStep, or what? :)
-
It's a mystery to me. But it works on my PC.
incidentally, o2 assembler understands rdtsc
rdtsc 'db &h0f, &h31
ref:
https://en.wikipedia.org/wiki/Time_Stamp_Counter
My corrected update:
'2018-03-08 T 17:34:33
'https://en.wikipedia.org/wiki/Time_Stamp_Counter
'https://msdn.microsoft.com/en-us/library/windows/desktop/dn553408(v=vs.85).aspx
'
'64bit debug:
'remove pushad and popad (invalid in 64bit mode)
'use rdi as pointer
$ filename "GetCpuSpeed_64.exe"
use rtl64
use minwin
' This program will obtain the CPU's speed
Declare Function QueryPerformanceCounter Lib "kernel32" (lpPerformanceCount As QUAD) As Long
Declare Function QueryPerformanceFrequency Lib "kernel32" (lpFrequency As QUAD) As Long
'=====================================
FUNCTION CpuSpeed() AS STRING
LOCAL Count0 AS QUAD
LOCAL Count1 AS QUAD
LOCAL Count2 AS QUAD
LOCAL Freq AS QUAD
LOCAL NewCount AS QUAD
LOCAL CpuFreq AS DWORD
QueryPerformanceFrequency(Freq)
Freq = Freq \ 10
rdtsc 'db &h0f, &h31
lea rdi,Count1
mov [rdi+4], edx
mov [rdi], eax
QueryPerformanceCounter(Count0)
NewCount = Count0 + Freq
WHILE (Count0 < NewCount)
QueryPerformanceCounter(Count0)
WEND
rdtsc 'db &h0f, &h31
lea rdi,Count2
mov [rdi+4], edx
mov [rdi], eax
CpuFreq = (Count2 - Count1) \ 100000
IF CpuFreq > 1000 THEN
FUNCTION = str(CpuFreq / 1000 ) + " giga hertz"
ELSE
FUNCTION = str(CpuFreq ) + " mega hertz"
END IF
END FUNCTION
'====================
print CpuSpeed
-
Many Thanks Charles
Both posts' programs give the same figure when executed, however in the wikipedia in regards to rdtsc
https://en.wikipedia.org/wiki/Time_Stamp_Counter
(https://en.wikipedia.org/wiki/Time_Stamp_Counter)
On Windows platforms, Microsoft strongly discourages using the TSC for high-resolution timing for exactly these reasons, providing instead the Windows APIs QueryPerformanceCounter and QueryPerformanceFrequency.[2] On POSIX systems, a program can get similar function by reading the value of CLOCK_MONOTONIC clock using the clock_gettime function.[3
TSC is discourage so it is best that we stick to the program in post #2 ? What do you think?
Also did an antivirus scan on these programs and found no virus.
-
Hi Karen,
It will certainly simplify your code. All you need is QueryPerformanceFrequency:
Declare Function QueryPerformanceFrequency Lib "kernel32" (lpFrequency As QUAD) As Long
quad q
QueryPerformanceFrequency q
print "CPU Clock Speed " str(q/1e6) " GHz"
PS:
Fortunately, we get far less virus false-positives with 64bit binaries.
-
Both programs are equally questionable under MS Windows. What PowerBASIC encodes as literal DB &H0f, &H31 because its parser can't recognize it as a valid CPU instruction, is in fact the RDTSC instruction supported by the O2 assembler officially.
Pure QueryPerformanceFrequency/QueryPerformanceCounter do not however guarantee that your measurements would not fall into a trap of SpeedStep (https://en.wikipedia.org/wiki/SpeedStep) -- Intel's technology to minimize CPU power consumption by lowering its speed when more or less idle, or of its AMD analog, Cool'n'Quiet.
SpeedStep can be very deceptive. See the upper picture attached below for three successive measurements taken on my former, slower CPU while writing a forum message. Now I'm working with Patrice Terrier on his 3D OBJ file viewer again and I need every bit of my new CPU's throughput for my OpenGL experimentation, so I have my CPU SpeedStep option disabled in my BIOS settings. (see lower picture below)