Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

Macschrauber

macrumors 68030
Original poster
Dec 27, 2015
2,776
1,374
Germany
A little x-mas gift for you guys :)

As there is no real way (I have knowledge of) to monitor the actual / turbo cpu frequency of the Xeons in classic Mac Pros I made two little scripts for displaying the actual cpu and turbo cpu frequency.

(The Intel Power Gadget tool does not work on our Xeon generation.)

It's the powermetrics cli tool what gives that information, I took 15 x 100ms samples and calculated the average for the actual load. Plus maxing 1 core out with the yes cli tool for triggering full (but not infinite) load.

That was a single Mac Pro 5,1 running a X5660 on Monterey

turbo X5660.png

actual X5660.png


The scripts need the admin password for privileges of Powermetrics and Terminal access. Also they needed right-click-open for the 1st start as they are not signed. The script text is readable.

Edit: added CPU type reporting to the turbo script (don't wanted to add additional load for the actual frequency script)




Edit2:
Added a script for measuring the actual CPU Frequency working on Apple Silicon. Measuring forcing a turbo load I cannot do as I have no Silicon Mac available. Everyone is welcome to add this.
 

Attachments

  • CPU Frequency 1.1.zip
    172.2 KB · Views: 115
  • silicon.zip
    64.3 KB · Views: 77
Last edited:
  • Like
Reactions: Xde and h9826790

h9826790

macrumors P6
Apr 3, 2014
16,614
8,546
Hong Kong
A little x-mas gift for you guys :)

As there is no real way (I have knowledge of) to monitor the actual / turbo cpu frequency of the Xeons in classic Mac Pros I made two little scripts for displaying the actual cpu and turbo cpu frequency.

(The Intel Power Gadget tool does not work on our Xeon generation.)

It's the powermetrics cli tool what gives that information, I took 15 x 100ms samples and calculated the average for the actual load. Plus maxing 1 core out with the yes cli tool for triggering full (but not infinite) load.

That was a single Mac Pro 5,1 running a X5660 on Monterey

View attachment 2132662
View attachment 2132661

The scripts need the admin password for privileges of powermetrics and Terminal access. Also they needed right-click-open for the 1st start as they are not signed. The script text is readable.
Merry Christmas, both script works beautifully.
Screenshot 2022-12-26 at 0.05.11.png

Screenshot 2022-12-26 at 0.05.34.png
 

Macschrauber

macrumors 68030
Original poster
Dec 27, 2015
2,776
1,374
Germany
I expected a higher turbo frequency, maybe you need to run the turbo script more times (or the machine was not in idle).

tested it in a supported system (Mavericks) and the turbo speed was closer to the specs (3.2 Ghz for X5660)

Screenshot 2022-12-25 at 16.23.26.png
 
Last edited:

h9826790

macrumors P6
Apr 3, 2014
16,614
8,546
Hong Kong
I expected a higher turbo frequency, maybe you need to run the turbo script more times (or the machine was not in idle).

tested it in a supported system (Mavericks) and the turbo speed was closer to the specs (3.2 Ghz for X5660)

View attachment 2132682
You are right, the cMP was not in idle. And I agree with you that the clock speed should be higher for the Turbo check. Even all cores running, the speed should able to reach 3.6GHz. My cMP had no thermal restriction during the check, all cores were cool.

Will run it a few times properly later and report back.
 

h9826790

macrumors P6
Apr 3, 2014
16,614
8,546
Hong Kong
I closed all apps, and run the script when the CPU load was nearly zero. This give me a more reasonable result.
Screenshot 2022-12-26 at 10.56.41.png


Even it should be 3.73GHz, but 3.6GHz is much easier to capture. I will run it few more times and see if I can capture anything close to 3.73GHz.

Anyway, for info, there were two Yes command captured, not one.
Screenshot 2022-12-26 at 10.56.16.png


I believe run only one Yes command is better. My understanding is that another physical core will have piority before the 1st virtual core. Therefore, the method now will stress two physical cores, but not a single physical + virtual core.
 

h9826790

macrumors P6
Apr 3, 2014
16,614
8,546
Hong Kong
Another recommendation, if the user click "stop" during that 2s delay. The script will abort, but the yes command may still running at the background. By considering not all users has habbit to monitor CPU loading, and not everyone know how to kill the background yes command. I think it's better to let the script jump to the killall yes step if the user hit the stop button at anytime.
 
Last edited:

h9826790

macrumors P6
Apr 3, 2014
16,614
8,546
Hong Kong
I tried 15, 100, and 1500 samples. All worked out the same clock speed. So, I believe the sampling method and the script itself is working beautifully. Able to provide accurate and consitent results.
15 samples.png

100 samples.png

1500 samples.png


For info, in the last 10 years, the only thing (in macOS) can show me ~3.73GHz is Linpack (32bit). I believe it also use similar method to work out the CPU clock speed.
3.722 GHz.png

But I have to try quite a few times to capture that, 3.591GHz is the normal number that I can capture.
 

h9826790

macrumors P6
Apr 3, 2014
16,614
8,546
Hong Kong
Another interesting finding. If I test run the script in the Script Editor, the clock speed will be slightly higher. Also, the result will vary a bit, but not always 3591GHz.
3659GHz.png

3685GHz.png
3690GHz.png

(I reduced the sample number to two in order to save some time. For peak clock speed capturing, this should be good enough anyway).
 
  • Like
Reactions: Macschrauber

Macschrauber

macrumors 68030
Original poster
Dec 27, 2015
2,776
1,374
Germany



The problem with the stop button of the progress bar is that it just hard ends the script. I found no way to treat this situation, even not by a quit-handler.

solved: a typo in properties for script_run_thru plus a misunderstanding of continue quit (assumed it continues the quit handler)

Everyone with better AppleScript or programming knowledge is welcome to help :)


(even if I solved the -not-working-stop-button- it is not super responsive, so I let the fallback in to stop the >yes< process.)

The workaround I made for quitting >yes< is: after a calculated time it stops >yes< regardless what the script is doing or if it was interrupted. Don't want to let the process eat energy.

this is the

Code:
tell app "terminal" to do script "sleep x && killall yes"

command, it sleeps a calculated time plus 4 seconds and kill >yes< processes regardless what happens.
Even if the script run thru and does >killall yes<. If so it gives an error in the Terminal window but that's just cosmetical.

Also I defined the vars samples and sample_ms in properties so it can be changed easily.

The sleep time before >killall yes< is calculated by samples*(sample_ms/1000)+x


Also >yes< runs now for 1 core, having it called twice slipped thru as I tested something.


Edit: removed the "test" password as it confuses Big Sur and later
Edit2: added a treatment for false stored password in Big Sur and later


AppleScript:
property my_password : ""
property progress_counter : 0
property big_sur : false
property script_run_thru : false
property samples : 15
property sample_ms : 100


on run
 
 
 
    -- get the sudo password, should not ask for it when running yes
    do_shell_script_sudo("echo 1")
 
 
    set script_run_thru to false
    set progress_counter to 0
 
    progress(5, "probing CPU Type")
    try
        set StrCPU to (do shell script ("sysctl -a | grep machdep.cpu.brand_string"))
        set AppleScript's text item delimiters to ": "
        set StrCPU to last text item of StrCPU
        set AppleScript's text item delimiters to ""
    on error
        set StrCPU to ""
    end try
 
 
    -- big sur (or later) ?  (has a bug in do shell script with password, need a workaround)
 
    try
        set boot_rom_version to last word of (do shell script "system_profiler SPHardwareDataType | grep -i \"Boot Rom Version\"")
        if (length of boot_rom_version is 7) and (character 1 of boot_rom_version is "1") then -- older Systems like Mavericks truncates the sn
            set boot_rom_version to boot_rom_version & ".0"
        end if
        set big_sur to false
    on error --Big Sur
        set boot_rom_version to last word of (do shell script "system_profiler SPHardwareDataType | grep -i \"System Firmware Version\"")
        set big_sur to true
    end try
 
 
 
    set yes_timeout to (samples * (sample_ms / 1000) as integer) + 4 -- extra time for proceeding the script
 
 
 
 
    --ignoring application responses
 
 
    progress(5, "running yes on 1 core")
 
    tell application "Terminal" -- if we run yes by do shell script it locks the script as it runs forever
        do script "yes > /dev/null"
        do script "sleep " & yes_timeout & " && killall yes"
    end tell
 
 
    delay 2
 
 
    progress(5, "powermetrics start")
    try
        do_shell_script_sudo("powermetrics -n " & samples & space & "-i" & space & sample_ms & space & "| grep 'System Average frequency as fraction of nominal' >/tmp/powermetrics.txt")
    end try
 
    progress(5, "powermetrics done")
 
    try
        do shell script "killall yes"
    end try
 
    progress(5, "killall yes")
 
    set readout to do shell script "cat /tmp/powermetrics.txt"
 
    set cpu_percentages to do shell script "cat /tmp/powermetrics.txt | awk '{print $(NF-2)}' | sed 's/.$//'"
 
    set readout to paragraph 1 of readout
 
    set percentage to (word -3 of readout) as real
    set frequency to (word -2 of readout) as real
    set nominal_cpu_frequency to frequency / percentage * 100 as integer
 
    -- every word of readout: {"System", "Average", "frequency", "as", "fraction", "of", "nominal", "76.93", "1077.01", "Mhz"}
 
    set samples to count every paragraph in cpu_percentages
    set average to listAvg(every paragraph of cpu_percentages)
    set sampled_frequency to (nominal_cpu_frequency * average) / 100 as integer
 
    --end ignoring
 
    activate me
 
 
 
 
    display dialog StrCPU & return & "actual CPU Frequency: " & (sampled_frequency as string) & " Mhz" & return & ¬
        "nominal CPU Frequency: " & (nominal_cpu_frequency as string) & " Mhz" & return & ¬
        "samples: " & (samples as string) with title "Macschrauber's turbo CPU frequency teller" buttons {"OK"} default button "OK"
 
    set script_run_thru to true
 
end run

on quit
    if (not script_run_thru) then
        activate me
    
        progress(5, "stop, killall yes")
        try
            do shell script "killall yes"
        end try
        delay 1
    end if
end quit


on listAvg(theList)
    set the_list to theList
    set a to 0
    repeat with this_item in the_list
        set a to a + (this_item as real)
    end repeat
    set avg to (a / (count the_list)) as real
    return avg
end listAvg


on do_shell_script_sudo(the_text)
    if my_password is not "" then
    
        if big_sur then
            try -- if the password is wrong it runs into an error
                return do shell script "echo " & my_password & " | sudo -S " & the_text
            on error number errorNumber
                --display dialog (errorNumber as text) & return & the_text
                return do shell script the_text with administrator privileges
                -- and ask for the correct password
            end try
        
        else -- does not run into an error
            try
                return do shell script the_text password my_password with administrator privileges
            on error
                return do shell script the_text with administrator privileges
            end try
        end if

    
    else -- no password given
        return do shell script the_text with administrator privileges
    end if
 
end do_shell_script_sudo



on progress(progress_total_steps, progress_description)
    try
        log progress_description
        set progress total steps to progress_total_steps
        set progress_counter to progress_counter + 1
        set progress completed steps to progress_counter
        set progress description to progress_description
        delay 1
    end try
 
end progress

Attached is the turbo and actual frequency script.
 

Attachments

  • CPU Frequency 0.6.zip
    160 KB · Views: 66
Last edited by a moderator:

h9826790

macrumors P6
Apr 3, 2014
16,614
8,546
Hong Kong
I believe you accidentally leave the word "test" here. I think it should be just ""?
Screenshot 2022-12-26 at 23.03.53.png


Otherwise, error occur (in Monterey 12.6.2)
Screenshot 2022-12-26 at 23.11.04.png
 
Last edited:

Macschrauber

macrumors 68030
Original poster
Dec 27, 2015
2,776
1,374
Germany
I believe you accidentally leave the word "test" here. I think it should be just ""?
View attachment 2133011

It don't matters, if it is wrong its asking for the admin password.

Edit: But not for Big Sur and later, that was fixed

That's btw the AppleScript do shell script bug since Big Sur, if the stored password in a variable is wrong it won't ask for the correct one.

I know noone should store a password in a script as it is readable for everyone - but for test sake it is much more comfortable to do it temporarily.

btw: I have edited the 1st post, stop button problem is solved.

Response of that button is bad, but that's a major AppleScript thing.
 
Last edited:
  • Like
Reactions: h9826790

h9826790

macrumors P6
Apr 3, 2014
16,614
8,546
Hong Kong
One more consideration, we may change the killall yes to killall -9 Terminal. So that not just the yes command will stop, but also close the terminal that opened by the script automatically.

Of course, if the user is using terminal, then that will be closed as well. Therefore, we may just consider it.
 
Last edited:

Macschrauber

macrumors 68030
Original poster
Dec 27, 2015
2,776
1,374
Germany
Ok, the password error is new for me, run my test in Mojave and High Sierra.
When running in Monterey the test box password matches :)


will edit it and do more test

added treating a wrong stored password in Big Sur and later
 
Last edited:

Macschrauber

macrumors 68030
Original poster
Dec 27, 2015
2,776
1,374
Germany
One more consideration, we may change the killall yes to killall -9 Terminal. So that not just the yes command will stop, but also close the terminal that opened by the script automatically.

Of course, if the user was using terminal, then that will be closed as well. Therefore, we may just consider it.

Oh I would freak out if someone kills my Terminal app :)
 

Macschrauber

macrumors 68030
Original poster
Dec 27, 2015
2,776
1,374
Germany
thanks for putting the posts together not bloating the cpu thread


As we have an own thread it's much easier


Added quitting the Terminal if it was not open before



AppleScript:
property my_password : ""
property progress_counter : 0
property big_sur : false
property script_run_thru : false
property samples : 15
property sample_ms : 100
property terminal_was_open : false


on run
 
    set terminal_was_open to terminal_runs()
 
    -- get the sudo password, should not ask for it when running yes
    do_shell_script_sudo("echo 1")
 
 
    set script_run_thru to false
    set progress_counter to 0
 
    progress(5, "probing CPU Type")
    try
        set StrCPU to (do shell script ("sysctl -a | grep machdep.cpu.brand_string"))
        set AppleScript's text item delimiters to ": "
        set StrCPU to last text item of StrCPU
        set AppleScript's text item delimiters to ""
    on error
        set StrCPU to ""
    end try
 
 
    -- big sur (or later) ?  (has a bug in do shell script with password, need a workaround)
 
    try
        set boot_rom_version to last word of (do shell script "system_profiler SPHardwareDataType | grep -i \"Boot Rom Version\"")
        if (length of boot_rom_version is 7) and (character 1 of boot_rom_version is "1") then -- older Systems like Mavericks truncates the sn
            set boot_rom_version to boot_rom_version & ".0"
        end if
        set big_sur to false
    on error --Big Sur
        set boot_rom_version to last word of (do shell script "system_profiler SPHardwareDataType | grep -i \"System Firmware Version\"")
        set big_sur to true
    end try
 
 
 
    set yes_timeout to (samples * (sample_ms / 1000) as integer) + 4 -- extra time for proceeding the script
 
 
 
 
    --ignoring application responses
 
 
    progress(5, "running yes on 1 core")
 
    tell application "Terminal" -- if we run yes by do shell script it locks the script as it runs forever
        do script "yes > /dev/null"
        do script "sleep " & yes_timeout & " && killall yes"
    end tell
 
 
    delay 2
 
 
    progress(5, "powermetrics start")
    try
        do_shell_script_sudo("powermetrics -n " & samples & space & "-i" & space & sample_ms & space & "| grep 'System Average frequency as fraction of nominal' >/tmp/powermetrics.txt")
    end try
 
    progress(5, "powermetrics done")
 
    try
        do shell script "killall yes"
    end try
 
    progress(5, "killall yes")
 
    set readout to do shell script "cat /tmp/powermetrics.txt"
 
    set cpu_percentages to do shell script "cat /tmp/powermetrics.txt | awk '{print $(NF-2)}' | sed 's/.$//'"
 
    set readout to paragraph 1 of readout
 
    set percentage to (word -3 of readout) as real
    set frequency to (word -2 of readout) as real
    set nominal_cpu_frequency to frequency / percentage * 100 as integer
 
    -- every word of readout: {"System", "Average", "frequency", "as", "fraction", "of", "nominal", "76.93", "1077.01", "Mhz"}
 
    set samples to count every paragraph in cpu_percentages
    set average to listAvg(every paragraph of cpu_percentages)
    set sampled_frequency to (nominal_cpu_frequency * average) / 100 as integer
 
    --end ignoring
 
    activate me
 
 
 
 
    display dialog StrCPU & return & "actual CPU Frequency: " & (sampled_frequency as string) & " Mhz" & return & ¬
        "nominal CPU Frequency: " & (nominal_cpu_frequency as string) & " Mhz" & return & ¬
        "samples: " & (samples as string) with title "Macschrauber's turbo CPU frequency teller" buttons {"OK"} default button "OK"
 
    set script_run_thru to true
 
    try
        if (not terminal_was_open) then tell application "Terminal" to quit
    end try
 
end run

on quit
    if (not script_run_thru) then
        activate me
     
        progress(5, "stop, killall yes")
        try
            do shell script "killall yes"
        end try
        delay 1
    end if
 
    try
        if (not terminal_was_open) then tell application "Terminal" to quit
    end try
end quit


on listAvg(theList)
    set the_list to theList
    set a to 0
    repeat with this_item in the_list
        set a to a + (this_item as real)
    end repeat
    set avg to (a / (count the_list)) as real
    return avg
end listAvg


on do_shell_script_sudo(the_text)
    if my_password is not "" then
        if big_sur then
            try -- if the password is wrong it runs into an error
                return do shell script "echo " & my_password & " | sudo -S " & the_text
            on error number errorNumber
                --display dialog (errorNumber as text) & return & the_text
                return do shell script the_text with administrator privileges
                -- and ask for the correct password
            end try
         
        else -- does not run into an error
            try
                return do shell script the_text password my_password with administrator privileges
            on error
                return do shell script the_text with administrator privileges
            end try
        end if
     
    else -- no password given
        return do shell script the_text with administrator privileges
    end if
 
end do_shell_script_sudo


on progress(progress_total_steps, progress_description)
    try
        log progress_description
        set progress total steps to progress_total_steps
        set progress_counter to progress_counter + 1
        set progress completed steps to progress_counter
        set progress description to progress_description
        delay 1
    end try
 
end progress


on terminal_runs()
    try
        tell application "System Events"
            set processList to every process whose (name is "Terminal")
        end tell
        if processList is {} then
            return false
        else
            return true
        end if
    on error
        return false
    end try
end terminal_runs
 

Attachments

  • CPU Frequency 0.7.zip
    161.7 KB · Views: 66
Last edited:

h9826790

macrumors P6
Apr 3, 2014
16,614
8,546
Hong Kong
thanks for putting the posts together not bloating the cpu thread


As we have an own thread it's much easier


Added quitting the Terminal if it was not open before



AppleScript:
property my_password : ""
property progress_counter : 0
property big_sur : false
property script_run_thru : false
property samples : 15
property sample_ms : 100
property terminal_was_open : false


on run
 
    set terminal_was_open to terminal_runs()
 
    -- get the sudo password, should not ask for it when running yes
    do_shell_script_sudo("echo 1")
 
 
    set script_run_thru to false
    set progress_counter to 0
 
    progress(5, "probing CPU Type")
    try
        set StrCPU to (do shell script ("sysctl -a | grep machdep.cpu.brand_string"))
        set AppleScript's text item delimiters to ": "
        set StrCPU to last text item of StrCPU
        set AppleScript's text item delimiters to ""
    on error
        set StrCPU to ""
    end try
 
 
    -- big sur (or later) ?  (has a bug in do shell script with password, need a workaround)
 
    try
        set boot_rom_version to last word of (do shell script "system_profiler SPHardwareDataType | grep -i \"Boot Rom Version\"")
        if (length of boot_rom_version is 7) and (character 1 of boot_rom_version is "1") then -- older Systems like Mavericks truncates the sn
            set boot_rom_version to boot_rom_version & ".0"
        end if
        set big_sur to false
    on error --Big Sur
        set boot_rom_version to last word of (do shell script "system_profiler SPHardwareDataType | grep -i \"System Firmware Version\"")
        set big_sur to true
    end try
 
 
 
    set yes_timeout to (samples * (sample_ms / 1000) as integer) + 4 -- extra time for proceeding the script
 
 
 
 
    --ignoring application responses
 
 
    progress(5, "running yes on 1 core")
 
    tell application "Terminal" -- if we run yes by do shell script it locks the script as it runs forever
        do script "yes > /dev/null"
        do script "sleep " & yes_timeout & " && killall yes"
    end tell
 
 
    delay 2
 
 
    progress(5, "powermetrics start")
    try
        do_shell_script_sudo("powermetrics -n " & samples & space & "-i" & space & sample_ms & space & "| grep 'System Average frequency as fraction of nominal' >/tmp/powermetrics.txt")
    end try
 
    progress(5, "powermetrics done")
 
    try
        do shell script "killall yes"
    end try
 
    progress(5, "killall yes")
 
    set readout to do shell script "cat /tmp/powermetrics.txt"
 
    set cpu_percentages to do shell script "cat /tmp/powermetrics.txt | awk '{print $(NF-2)}' | sed 's/.$//'"
 
    set readout to paragraph 1 of readout
 
    set percentage to (word -3 of readout) as real
    set frequency to (word -2 of readout) as real
    set nominal_cpu_frequency to frequency / percentage * 100 as integer
 
    -- every word of readout: {"System", "Average", "frequency", "as", "fraction", "of", "nominal", "76.93", "1077.01", "Mhz"}
 
    set samples to count every paragraph in cpu_percentages
    set average to listAvg(every paragraph of cpu_percentages)
    set sampled_frequency to (nominal_cpu_frequency * average) / 100 as integer
 
    --end ignoring
 
    activate me
 
 
 
 
    display dialog StrCPU & return & "actual CPU Frequency: " & (sampled_frequency as string) & " Mhz" & return & ¬
        "nominal CPU Frequency: " & (nominal_cpu_frequency as string) & " Mhz" & return & ¬
        "samples: " & (samples as string) with title "Macschrauber's turbo CPU frequency teller" buttons {"OK"} default button "OK"
 
    set script_run_thru to true
 
    try
        if (not terminal_was_open) then tell application "Terminal" to quit
    end try
 
end run

on quit
    if (not script_run_thru) then
        activate me
    
        progress(5, "stop, killall yes")
        try
            do shell script "killall yes"
        end try
        delay 1
    end if
 
    try
        if (not terminal_was_open) then tell application "Terminal" to quit
    end try
end quit


on listAvg(theList)
    set the_list to theList
    set a to 0
    repeat with this_item in the_list
        set a to a + (this_item as real)
    end repeat
    set avg to (a / (count the_list)) as real
    return avg
end listAvg


on do_shell_script_sudo(the_text)
    if my_password is not "" then
        if big_sur then
            try -- if the password is wrong it runs into an error
                return do shell script "echo " & my_password & " | sudo -S " & the_text
            on error number errorNumber
                --display dialog (errorNumber as text) & return & the_text
                return do shell script the_text with administrator privileges
                -- and ask for the correct password
            end try
        
        else -- does not run into an error
            try
                return do shell script the_text password my_password with administrator privileges
            on error
                return do shell script the_text with administrator privileges
            end try
        end if
    
    else -- no password given
        return do shell script the_text with administrator privileges
    end if
 
end do_shell_script_sudo


on progress(progress_total_steps, progress_description)
    try
        log progress_description
        set progress total steps to progress_total_steps
        set progress_counter to progress_counter + 1
        set progress completed steps to progress_counter
        set progress description to progress_description
        delay 1
    end try
 
end progress


on terminal_runs()
    try
        tell application "System Events"
            set processList to every process whose (name is "Terminal")
        end tell
        if processList is {} then
            return false
        else
            return true
        end if
    on error
        return false
    end try
end terminal_runs
Thanks for keep polishing this little tool. It works perfectly now, cheers! 🍺
 

Macschrauber

macrumors 68030
Original poster
Dec 27, 2015
2,776
1,374
Germany
I found a way running >do shell script< in background without locking the script.

Hardest part was to kill >yes< after a given time. (what I wanted to keep in the script as a failback). Achieved it by redirecting text to >sh< in background.

alike:
Code:
echo 'sleep $timeout;killall yes' | sh > /dev/null 2>&1 &


So no more need to open those 2 Terminal windows.

AppleScript:
--v1.0
property my_password : ""
property progress_counter : 0
property big_sur : false
property script_run_thru : false
property samples : 15
property sample_ms : 100
property yes_timeout : 0


on run
    
    
    -- get the sudo password, should not ask for it when running yes
    do_shell_script_sudo("echo 1")
    
    
    set script_run_thru to false
    set progress_counter to 0
    
    progress(5, "probing CPU Type")
    try
        set StrCPU to (do shell script ("sysctl -a | grep machdep.cpu.brand_string"))
        set AppleScript's text item delimiters to ": "
        set StrCPU to last text item of StrCPU
        set AppleScript's text item delimiters to ""
    on error
        set StrCPU to ""
    end try
    
    
    -- big sur (or later) ?  (has a bug in do shell script with password, need a workaround)
    
    try
        set boot_rom_version to last word of (do shell script "system_profiler SPHardwareDataType | grep -i \"Boot Rom Version\"")
        if (length of boot_rom_version is 7) and (character 1 of boot_rom_version is "1") then -- older Systems like Mavericks truncates the sn
            set boot_rom_version to boot_rom_version & ".0"
        end if
        set big_sur to false
    on error --Big Sur
        set boot_rom_version to last word of (do shell script "system_profiler SPHardwareDataType | grep -i \"System Firmware Version\"")
        set big_sur to true
    end try
    
    
    
    set yes_timeout to (samples * (sample_ms / 1000) as integer) + 4 -- extra time for proceeding the script
    
    
        
    progress(5, "running yes on 1 core")
    
    do_shell_script_in_background("yes")
    do_shell_script_in_background("echo 'sleep " & (yes_timeout as string) & ";killall yes' | sh")
    
    delay 2
    
    
    progress(5, "powermetrics start")
    try
        do_shell_script_sudo("powermetrics -n " & samples & space & "-i" & space & sample_ms & space & "| grep 'System Average frequency as fraction of nominal' >/tmp/powermetrics.txt")
    end try
    
    
    progress(5, "powermetrics done")
    
    try
        do shell script "killall yes"
    end try
    
    progress(5, "killall yes")
    
    set readout to do shell script "cat /tmp/powermetrics.txt"
    
    set cpu_percentages to do shell script "cat /tmp/powermetrics.txt | awk '{print $(NF-2)}' | sed 's/.$//'"
    
    try
        do_shell_script_sudo("rm /tmp/powermetrics.txt")
    end try
    
    
    set readout to paragraph 1 of readout
    
    set percentage to (word -3 of readout) as real
    set frequency to (word -2 of readout) as real
    set nominal_cpu_frequency to frequency / percentage * 100 as integer
    
    -- every word of readout: {"System", "Average", "frequency", "as", "fraction", "of", "nominal", "76.93", "1077.01", "Mhz"}
    
    set samples to count every paragraph in cpu_percentages
    set average to listAvg(every paragraph of cpu_percentages)
    set sampled_frequency to (nominal_cpu_frequency * average) / 100 as integer
    
    
    activate me
    
    
    
    
    display dialog StrCPU & return & "actual CPU Frequency: " & (sampled_frequency as string) & " Mhz" & return & ¬
        "nominal CPU Frequency: " & (nominal_cpu_frequency as string) & " Mhz" & return & ¬
        "samples: " & (samples as string) with title "Macschrauber's turbo CPU frequency teller" buttons {"OK"} default button "OK"
    
    set script_run_thru to true
    
    
    
end run

on quit
    if (not script_run_thru) then
        activate me
        progress(5, "stop, killall yes, just in case")
        try
            do shell script "killall yes"
        end try
    end if
    
    continue quit
end quit


on listAvg(theList)
    set the_list to theList
    set a to 0
    repeat with this_item in the_list
        set a to a + (this_item as real)
    end repeat
    set avg to (a / (count the_list)) as real
    return avg
end listAvg


on do_shell_script_sudo(the_text)
    if my_password is not "" then
        if big_sur then
            try -- if the password is wrong it runs into an error
                return do shell script "echo " & my_password & " | sudo -S " & the_text
            on error number errorNumber
                --display dialog (errorNumber as text) & return & the_text
                return do shell script the_text with administrator privileges
                -- and ask for the correct password
            end try
            
        else -- does not run into an error
            try
                return do shell script the_text password my_password with administrator privileges
            on error
                return do shell script the_text with administrator privileges
            end try
        end if
        
    else -- no password given
        return do shell script the_text with administrator privileges
    end if
    
end do_shell_script_sudo



on do_shell_script_in_background(the_command)
    do shell script (the_command & " > /dev/null 2>&1 &")
end do_shell_script_in_background



on progress(progress_total_steps, progress_description)
    try
        log progress_description
        set progress total steps to progress_total_steps
        set progress_counter to progress_counter + 1
        set progress completed steps to progress_counter
        set progress description to progress_description
        delay 1
    end try
end progress
 

Attachments

  • CPU Frequency 1.0.zip
    165.7 KB · Views: 80
  • Like
Reactions: h9826790

Macschrauber

macrumors 68030
Original poster
Dec 27, 2015
2,776
1,374
Germany
I come across a weird behaviour (readings are from Xeon X5660)

When running in Monterey Powermetrics gave inconsistent output, when running in Script Editor the output was correct.

After fighting a whole afternoon I sorted a timing problem. My theory is that Powermetrics gave no decent quit/ready signal.

Anyway, the solution is as weird as the problem: running >Powermetrics< in Background and waiting a calculated time -instead of running it thru >do shell script< (what locks the script until the shell script is done).


AppleScript:
--v1.1
property my_password : ""
property progress_counter : 0
property big_sur : false
property script_run_thru : false
property samples : 15
property sample_ms : 100
property yes_timeout : 0


on run
   
   
    -- get the sudo password, should not ask for it when running yes
    do_shell_script_sudo("echo 1")
   
   
    set script_run_thru to false
    set progress_counter to 0
   
    progress(5, "probing CPU Type")
    try
        set StrCPU to (do shell script ("sysctl -a | grep machdep.cpu.brand_string"))
        set AppleScript's text item delimiters to ": "
        set StrCPU to last text item of StrCPU
        set AppleScript's text item delimiters to ""
    on error
        set StrCPU to ""
    end try
   
   
    -- big sur (or later) ?  (has a bug in do shell script with password, need a workaround)
   
    try
        set boot_rom_version to last word of (do shell script "system_profiler SPHardwareDataType | grep -i \"Boot Rom Version\"")
        if (length of boot_rom_version is 7) and (character 1 of boot_rom_version is "1") then -- older Systems like Mavericks truncates the sn
            set boot_rom_version to boot_rom_version & ".0"
        end if
        set big_sur to false
    on error --Big Sur
        set boot_rom_version to last word of (do shell script "system_profiler SPHardwareDataType | grep -i \"System Firmware Version\"")
        set big_sur to true
    end try
   
   
   
    set yes_timeout to (samples * (sample_ms / 1000) as integer) + 10 -- extra time for proceeding the script, thats just a failback of the script is shut down
   
   
   
   
   
    progress(5, "running yes on 1 core")
   
    do_shell_script_in_background("yes")
    do_shell_script_in_background("echo 'sleep " & (yes_timeout as string) & ";killall yes' | sh")
   
   
   
    progress(5, "powermetrics start")
   
    -- powermetrics needs to start in background if not the readings are not consistent, differ from running in Script Editor
   
    do_shell_script_sudo_in_background("powermetrics -n" & samples & space & "-i" & sample_ms & " --output-file /tmp/powermetrics.txt")
   
   
    set the_timeout to (samples * (sample_ms / 1000) as integer) + 2 -- extra time for proceeding the script
   
   
    delay the_timeout -- powermetrics needs some time to finish the output file !
   
    do_shell_script_sudo("cat /tmp/powermetrics.txt | grep 'System Average frequency as fraction of nominal' >/tmp/powermetrics2.txt")
    do_shell_script_sudo("rm /tmp/powermetrics.txt")
    do_shell_script_sudo("mv /tmp/powermetrics2.txt /tmp/powermetrics.txt")
   
   
    progress(5, "powermetrics done")
   
    try
        do shell script "killall yes"
    end try
   
    progress(5, "killall yes")
   
    set readout to do shell script "cat /tmp/powermetrics.txt"
   
    set cpu_percentages to do shell script "cat /tmp/powermetrics.txt | awk '{print $(NF-2)}' | sed 's/.$//'"
   
   
    set readout to paragraph 1 of readout
   
    set percentage to (word -3 of readout) as real
    set frequency to (word -2 of readout) as real
    set nominal_cpu_frequency to frequency / percentage * 100 as integer
   
    -- every word of readout: {"System", "Average", "frequency", "as", "fraction", "of", "nominal", "76.93", "1077.01", "Mhz"}
   
    set samples to count every paragraph in cpu_percentages
    set average to listAvg(every paragraph of cpu_percentages)
    set sampled_frequency to (nominal_cpu_frequency * average) / 100 as integer
   
   
    activate me
   
   
   
   
    display dialog StrCPU & return & "actual CPU Frequency: " & (sampled_frequency as string) & " Mhz" & return & ¬
        "nominal CPU Frequency: " & (nominal_cpu_frequency as string) & " Mhz" & return & ¬
        "samples: " & (samples as string) with title "Macschrauber's turbo CPU frequency teller" buttons {"OK"} default button "OK"
   
   
    try
        do_shell_script_sudo("rm /tmp/powermetrics.txt")
    end try
   
   
    set script_run_thru to true
   
   
   
end run

on quit
    if (not script_run_thru) then
        activate me
        progress(5, "stop, killall yes just in case")
        try
            do shell script "killall yes"
        end try
    end if
   
    contine quit
end quit


on listAvg(theList)
    set the_list to theList
    set a to 0
    repeat with this_item in the_list
        set a to a + (this_item as real)
    end repeat
    set avg to (a / (count the_list)) as real
    return avg
end listAvg


on do_shell_script_sudo(the_text)
    if my_password is not "" then
        if big_sur then
            try -- if the password is wrong it runs into an error
                return do shell script "echo " & my_password & " | sudo -S " & the_text
            on error number errorNumber
                --display dialog (errorNumber as text) & return & the_text
                return do shell script the_text with administrator privileges
                -- and ask for the correct password
            end try
           
        else -- does not run into an error
            try
                return do shell script the_text password my_password with administrator privileges
            on error
                return do shell script the_text with administrator privileges
            end try
        end if
       
    else -- no password given
        return do shell script the_text with administrator privileges
    end if
   
end do_shell_script_sudo



on do_shell_script_in_background(the_command)
    do shell script (the_command & " > /dev/null 2>&1 &")
end do_shell_script_in_background



on do_shell_script_sudo_in_background(the_command)
    do shell script (the_command & " > /dev/null 2>&1 &") password my_password with administrator privileges
end do_shell_script_sudo_in_background




on progress(progress_total_steps, progress_description)
    try
        log progress_description
        set progress total steps to progress_total_steps
        set progress_counter to progress_counter + 1
        set progress completed steps to progress_counter
        set progress description to progress_description
        delay 1
    end try
end progress
 

Attachments

  • CPU Frequency 1.1.zip
    172.2 KB · Views: 91
Last edited:

h9826790

macrumors P6
Apr 3, 2014
16,614
8,546
Hong Kong
I come across a weird behaviour (readings are from Xeon X5660)

When running in Monterey Powermetrics gave inconsistent output, when running in Script Editor the output was correct.

After fighting a whole afternoon I sorted a timing problem. My theory is that Powermetrics gave no decent quit/ready signal.

Anyway, the solution is as weird as the problem: running >Powermetrics< in Background and waiting a calculated time -instead of running it thru >do shell script< (what locks the script until the shell script is done).


AppleScript:
--v1.1
property my_password : ""
property progress_counter : 0
property big_sur : false
property script_run_thru : false
property samples : 15
property sample_ms : 100
property yes_timeout : 0


on run
  
  
    -- get the sudo password, should not ask for it when running yes
    do_shell_script_sudo("echo 1")
  
  
    set script_run_thru to false
    set progress_counter to 0
  
    progress(5, "probing CPU Type")
    try
        set StrCPU to (do shell script ("sysctl -a | grep machdep.cpu.brand_string"))
        set AppleScript's text item delimiters to ": "
        set StrCPU to last text item of StrCPU
        set AppleScript's text item delimiters to ""
    on error
        set StrCPU to ""
    end try
  
  
    -- big sur (or later) ?  (has a bug in do shell script with password, need a workaround)
  
    try
        set boot_rom_version to last word of (do shell script "system_profiler SPHardwareDataType | grep -i \"Boot Rom Version\"")
        if (length of boot_rom_version is 7) and (character 1 of boot_rom_version is "1") then -- older Systems like Mavericks truncates the sn
            set boot_rom_version to boot_rom_version & ".0"
        end if
        set big_sur to false
    on error --Big Sur
        set boot_rom_version to last word of (do shell script "system_profiler SPHardwareDataType | grep -i \"System Firmware Version\"")
        set big_sur to true
    end try
  
  
  
    set yes_timeout to (samples * (sample_ms / 1000) as integer) + 10 -- extra time for proceeding the script, thats just a failback of the script is shut down
  
  
  
  
  
    progress(5, "running yes on 1 core")
  
    do_shell_script_in_background("yes")
    do_shell_script_in_background("echo 'sleep " & (yes_timeout as string) & ";killall yes' | sh")
  
  
  
    progress(5, "powermetrics start")
  
    -- powermetrics needs to start in background if not the readings are not consistent, differ from running in Script Editor
  
    do_shell_script_sudo_in_background("powermetrics -n" & samples & space & "-i" & sample_ms & " --output-file /tmp/powermetrics.txt")
  
  
    set the_timeout to (samples * (sample_ms / 1000) as integer) + 2 -- extra time for proceeding the script
  
  
    delay the_timeout -- powermetrics needs some time to finish the output file !
  
    do_shell_script_sudo("cat /tmp/powermetrics.txt | grep 'System Average frequency as fraction of nominal' >/tmp/powermetrics2.txt")
    do_shell_script_sudo("rm /tmp/powermetrics.txt")
    do_shell_script_sudo("mv /tmp/powermetrics2.txt /tmp/powermetrics.txt")
  
  
    progress(5, "powermetrics done")
  
    try
        do shell script "killall yes"
    end try
  
    progress(5, "killall yes")
  
    set readout to do shell script "cat /tmp/powermetrics.txt"
  
    set cpu_percentages to do shell script "cat /tmp/powermetrics.txt | awk '{print $(NF-2)}' | sed 's/.$//'"
  
  
    set readout to paragraph 1 of readout
  
    set percentage to (word -3 of readout) as real
    set frequency to (word -2 of readout) as real
    set nominal_cpu_frequency to frequency / percentage * 100 as integer
  
    -- every word of readout: {"System", "Average", "frequency", "as", "fraction", "of", "nominal", "76.93", "1077.01", "Mhz"}
  
    set samples to count every paragraph in cpu_percentages
    set average to listAvg(every paragraph of cpu_percentages)
    set sampled_frequency to (nominal_cpu_frequency * average) / 100 as integer
  
  
    activate me
  
  
  
  
    display dialog StrCPU & return & "actual CPU Frequency: " & (sampled_frequency as string) & " Mhz" & return & ¬
        "nominal CPU Frequency: " & (nominal_cpu_frequency as string) & " Mhz" & return & ¬
        "samples: " & (samples as string) with title "Macschrauber's turbo CPU frequency teller" buttons {"OK"} default button "OK"
  
  
    try
        do_shell_script_sudo("rm /tmp/powermetrics.txt")
    end try
  
  
    set script_run_thru to true
  
  
  
end run

on quit
    if (not script_run_thru) then
        activate me
        progress(5, "stop, killall yes just in case")
        try
            do shell script "killall yes"
        end try
    end if
  
    contine quit
end quit


on listAvg(theList)
    set the_list to theList
    set a to 0
    repeat with this_item in the_list
        set a to a + (this_item as real)
    end repeat
    set avg to (a / (count the_list)) as real
    return avg
end listAvg


on do_shell_script_sudo(the_text)
    if my_password is not "" then
        if big_sur then
            try -- if the password is wrong it runs into an error
                return do shell script "echo " & my_password & " | sudo -S " & the_text
            on error number errorNumber
                --display dialog (errorNumber as text) & return & the_text
                return do shell script the_text with administrator privileges
                -- and ask for the correct password
            end try
          
        else -- does not run into an error
            try
                return do shell script the_text password my_password with administrator privileges
            on error
                return do shell script the_text with administrator privileges
            end try
        end if
      
    else -- no password given
        return do shell script the_text with administrator privileges
    end if
  
end do_shell_script_sudo



on do_shell_script_in_background(the_command)
    do shell script (the_command & " > /dev/null 2>&1 &")
end do_shell_script_in_background



on do_shell_script_sudo_in_background(the_command)
    do shell script (the_command & " > /dev/null 2>&1 &") password my_password with administrator privileges
end do_shell_script_sudo_in_background




on progress(progress_total_steps, progress_description)
    try
        log progress_description
        set progress total steps to progress_total_steps
        set progress_counter to progress_counter + 1
        set progress completed steps to progress_counter
        set progress description to progress_description
        delay 1
    end try
end progress

Yeah, Ver 1.1 seems works better. In the previous version. I always get 3.591 if using the apps (in Monterey). And must run the script in the script editor in order to get this kind of real time calculated number. But now, the apps can show me this number.
Screenshot 2022-12-28 at 10.07.06.png
 

Macschrauber

macrumors 68030
Original poster
Dec 27, 2015
2,776
1,374
Germany
Yes, that was that nasty behaviour of Powermetrics.

But just in new systems, older like Mojave or El Capitan read correct, self running and in Script Editor. At least for my test boxes.
 
  • Like
Reactions: h9826790
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.