Open Neikon opened 3 years ago
Did you execute the enable_performance_counter.bat
in the /troubleshooting folder?
If yes, can you paste the output when you execute this code in a Powershell terminal?
function Get-PerformanceCounterIDs {
param (
[Parameter(Mandatory=$true)]
[Array]
$englishCounterNames
)
$key = 'Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Perflib\009'
$allCounters = (Get-ItemProperty -Path $key -Name Counter).Counter
$numCounters = $allCounters.Count
$countersHash = @{}
# The string contains two-line pairs
# The first line is the ID
# The second line is the name
for ($i = 0; $i -lt $numCounters; $i += 2) {
$counterId = [Int]$allCounters[$i]
$counterName = [String]$allCounters[$i+1]
if ($englishCounterNames.Contains($counterName)) {
$countersHash[$counterName] = $counterId
}
}
return $countersHash
}
function Get-PerformanceCounterLocalName {
param (
[UInt32]
$ID,
$ComputerName = $env:COMPUTERNAME
)
try {
$code = '[DllImport("pdh.dll", SetLastError=true, CharSet=CharSet.Unicode)] public static extern UInt32 PdhLookupPerfNameByIndex(string szMachineName, uint dwNameIndex, System.Text.StringBuilder szNameBuffer, ref uint pcchNameBufferSize);'
$Buffer = New-Object System.Text.StringBuilder(1024)
[UInt32]$BufferSize = $Buffer.Capacity
$t = Add-Type -MemberDefinition $code -PassThru -Name PerfCounter -Namespace Utility
$rv = $t::PdhLookupPerfNameByIndex($ComputerName, $ID, $Buffer, [Ref]$BufferSize)
'ID: ' + $ID
'Found String: ' + $Buffer
if ($rv -eq 0) {
'Final Result:'
$Buffer.ToString().Substring(0, $BufferSize-1)
}
else {
Throw 'Get-PerformanceCounterLocalName : Unable to retrieve localized name. Check computer name and performance counter ID.'
}
}
catch {
'ERROR!'
$Error
$Error.Clear()
}
}
$englishCounterNames = @(
'Process',
'ID Process',
'% Processor Time'
)
$counterNames = @{}
$counterNameIds = Get-PerformanceCounterIDs $englishCounterNames
''
''
'-----------------'
'Counter Name IDs:'
'-----------------'
$counterNameIds
''
''
'------------------------'
'Localized Counter Names:'
'------------------------'
Get-PerformanceCounterLocalName $counterNameIds['Process']
Get-PerformanceCounterLocalName $counterNameIds['ID Process']
Get-PerformanceCounterLocalName $counterNameIds['% Processor Time']
Did you execute the
enable_performance_counter.bat
in the /troubleshooting folder?
yes.
this is the output
Hm. It doesn't find the localized string for % Processor Time
with the performance counter ID 6268. The other two are identified fine.
It does find the English string within the the registry key HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Perflib\009
Counter
entry, from where it extracts the ID.
But apparently it can't find the localized value for this ID within the Computer\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Perflib\CurrentLanguage
Counter
entry.
I've never dealt with a Spanish(?) version before, only with English and German. Is there any chance you could post the content of these two registry keys here? You can use this script to dump the content into two files which you then can upload here:
$directory = $env:TEMP
$fileEnglish = $directory + '\_performanceCounters.English.txt'
$fileLocalized = $directory + '\_performanceCounters.Localized.txt'
$keyEnglish = 'Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Perflib\009'
$keyLocalized = 'Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Perflib\CurrentLanguage'
$countersEnglish = (Get-ItemProperty -Path $keyEnglish -Name Counter).Counter
$countersLocalized = (Get-ItemProperty -Path $keyLocalized -Name Counter).Counter
cd $directory
Set-Content -Path $fileEnglish -Value $countersEnglish
Set-Content -Path $fileLocalized -Value $countersLocalized
The script dumps the content into two files, _performanceCounters.English.txt
and _performanceCounters.Localized.txt
and puts them into the TEMP directory, which you can access in Windows Explorer by entering %TEMP%
into the address bar.
I may have a possible fix for this issue. Can you run this script:
function Get-PerformanceCounterIDs {
param (
[Parameter(Mandatory=$true)]
[Array]
$englishCounterNames
)
$key = 'Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Perflib\009'
$allCounters = (Get-ItemProperty -Path $key -Name Counter).Counter
$numCounters = $allCounters.Count
$countersHash = @{}
# The string contains two-line pairs
# The first line is the ID
# The second line is the name
for ($i = 0; $i -lt $numCounters; $i += 2) {
$counterId = [Int]$allCounters[$i]
$counterName = [String]$allCounters[$i+1]
if ($englishCounterNames.Contains($counterName) -and !$countersHash.ContainsKey($counterName)) {
$countersHash[$counterName] = $counterId
}
}
return $countersHash
}
function Get-PerformanceCounterLocalName {
param (
[UInt32]
$ID,
$ComputerName = $env:COMPUTERNAME
)
try {
$code = '[DllImport("pdh.dll", SetLastError=true, CharSet=CharSet.Unicode)] public static extern UInt32 PdhLookupPerfNameByIndex(string szMachineName, uint dwNameIndex, System.Text.StringBuilder szNameBuffer, ref uint pcchNameBufferSize);'
$Buffer = New-Object System.Text.StringBuilder(1024)
[UInt32]$BufferSize = $Buffer.Capacity
$t = Add-Type -MemberDefinition $code -PassThru -Name PerfCounter -Namespace Utility
$rv = $t::PdhLookupPerfNameByIndex($ComputerName, $ID, $Buffer, [Ref]$BufferSize)
'ID: ' + $ID
'Found String: ' + $Buffer
if ($rv -eq 0) {
'Final Result:'
$Buffer.ToString().Substring(0, $BufferSize-1)
}
else {
Throw 'Get-PerformanceCounterLocalName : Unable to retrieve localized name. Check computer name and performance counter ID.'
}
}
catch {
'ERROR!'
$Error
$Error.Clear()
}
}
$englishCounterNames = @(
'Process',
'ID Process',
'% Processor Time'
)
$counterNames = @{}
$counterNameIds = Get-PerformanceCounterIDs $englishCounterNames
''
''
'-----------------'
'Counter Name IDs:'
'-----------------'
$counterNameIds
''
''
'------------------------'
'Localized Counter Names:'
'------------------------'
Get-PerformanceCounterLocalName $counterNameIds['Process']
Get-PerformanceCounterLocalName $counterNameIds['ID Process']
Get-PerformanceCounterLocalName $counterNameIds['% Processor Time']
If this works without showing an error, you could change line 238 in script-corecycler.ps1 from
if ($englishCounterNames.Contains($counterName)) {
to
if ($englishCounterNames.Contains($counterName) -and !$countersHash.ContainsKey($counterName)) {
and hopefully it will work.
I installed the Spanish language pack to do some tests and initially received the same error, but with that change it worked.
Yes, new version works
Sorry to reopen this issue. But it seems like I have a very similar problem.
I tried the manual approach to enable the counter and your batch file. But I still have this result.
And your suggested fix seems to be already included in the newer version.
However, when I use Version 0.7.8.5 it does not throw an error. But 0.7.8.9 does throw the above error from user Neikon.
I have German/English Windows 10.
Sorry to reopen this issue. But it seems like I have a very similar problem.
I tried the manual approach to enable the counter and your batch file. But I still have this result. And your suggested fix seems to be already included in the newer version. However, when I use Version 0.7.8.5 it does not throw an error. But 0.7.8.9 does throw the above error from user Neikon. I have German/English Windows 10.
Can you try to run the script I posted above and post the results?
I tried, but gives me an error. Here you go:
Hello, I have the same error as @claudjaris but my computer is in french. and running
$directory = $env:TEMP $fileEnglish = $directory + '\_performanceCounters.English.txt' $fileLocalized = $directory + '\_performanceCounters.Localized.txt' $keyEnglish = 'Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Perflib\009' $keyLocalized = 'Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Perflib\CurrentLanguage' $countersEnglish = (Get-ItemProperty -Path $keyEnglish -Name Counter).Counter $countersLocalized = (Get-ItemProperty -Path $keyLocalized -Name Counter).Counter cd $directory Set-Content -Path $fileEnglish -Value $countersEnglish Set-Content -Path $fileLocalized -Value $countersLocalized
works but the two files contain french counter names even _performanceCounters.english.txt I did a quick search in the registry but didn't find english counter names. any hint or need tu correct this issue?
@boucz
The English registry key contains French strings? That sounds really weird, Perflib\009
should always contain the English strings.
I can only test this by installing language packs, so it's not the native & default Windows language, but for me this always was the case in this way.
Here's another howto on resetting the Performance Counters, which seems to be a bit more extended than my instructions, but I've never tried this approach, so can't comment on the effort or success of this one: https://docs.microsoft.com/en-us/troubleshoot/windows-server/performance/rebuild-performance-counter-library-values
any idea how to fix this?
Did you try to execute the enable_performance_counter.bat
in the /tools directory?
If that doesn't work, from the error message it seems that the service is not started at all, did you maybe disable them at some point (I know I do disable services I deem unnecessary from time to time).
Maybe this can help, too, although it's for Windows Server: https://learn.microsoft.com/de-de/troubleshoot/windows-server/performance/manually-rebuild-performance-counters
yes i tried enable_performance_counter.bat already and also the other fix in the link, still doesnt work.
i also ran the script from above if that any help for you here is the screenshot
Does the Windows tool perfmon.exe
work?
It accesses the same performance counters.
i get this when i open it
Yeah, something is wrong with the Performance Counters (Leistungsindikatoren) on your system. I can only point to batch file and the links in the readme.txt, as without working Performance Counters the script can't check the CPU usage for the stress test program.
Also as an additional note, I wouldn't run the script from C:\Program Files
. It requires administrator privileges if you do so, because it wants to write config files to its directory.
As Spoon said you should try to rue-register perf counters following learn.Microsoft.com as he suggested. Even if the link talk about server version of os it should work ok for a workstation
I had exactly the same issue and was able to fix it using the microsoft https://learn.microsoft.com/en-us/troubleshoot/windows-server/performance/manually-rebuild-performance-counters link provided by boucz.
I have opened a cmd command in administrator and type: cd c:\windows\system32 lodctr /R cd c:\windows\sysWOW64 lodctr /R WINMGMT.EXE /RESYNCPERF
then the Run CoreCycler.bat was working fine.
If someone has not working with this error, i don't know how, but this script executes normally if you don't use .bat file, use ps1 and executes it in Visual Studio Code. Don't ask why, i don't know...
I mean the script that sp00n sent once helped me with this. When i run this again now, it doesnt work anymore and im stuck with the same as @playpun1
enable_performance_counter.bat Does not help
@iDarkEmpire I guess you'll have to try to manually restore the performance counters. Some possibly helpful links are provided in the readme.txt.
Also, sometimes the batch file cannot stop/restart all necessary services if additional ones are installed that depend on one of those that need to be stopped.
https://leansentry.zendesk.com/hc/en-us/articles/360038645792-How-to-Fix-performance-counter-issues https://learn.microsoft.com/en-us/troubleshoot/windows-server/performance/manually-rebuild-performance-counters I tried to do as indicated here, but still the error is there
I by the way only version 0.7.8.5 works for me
I had to change the Russian language in windows to English, only after that the error disappeared
The Performance Counters, PowerShell and indeed Windows itself is a bit weird, because it does localize a couple of things that IMO really shouldn't be localized internally, like the names of the Performance Counters. And additionally they have no fixed id, so they can change at any time, which is why I have to do a more or less reliable matching process to find the correct localized performance counter entry.
This worked fine for a couple other languages, but I have not yet had any experience with non-latin character sets like Russian.
There's even a chance that it might miraculously work now if you switch back to Russian. It's just that weird.
The English names for the Performance Counter names are in the HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Perflib\009\Counter
registry key, while the one for the currently selected language are in HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Perflib\CurrentLanguage\Counter
.
Maybe you could export both entries (English and Russian) and upload them here, so that I could take a look at what's failing there.
Counter https://pastebin.com/k2e23jUk
the value is the same that in 009 that in CurrentLanguage
Counter eng https://pastebin.com/AfLXLSXy
So it should find
230
Процесс
which represents
230
Process
But apparently it doesn't?
I suspect it didn't suddenly start working when you switched back to Russian?
No, when the interface is in Russian, CoreCycler gives an error, most likely there may be a problem in the Cyrillic alphabet in the values of the registry
@iDarkEmpire could you please open PowerShell with Russian interface language, copy/paste the following code and share the results here? Feel free to try it on both Russian and English interface language but Russian would be the one that interests me more. 😊
(Get-Counter -ListSet Process | Select-Object -ExpandProperty Paths)[0]
(Get-Counter -ListSet Process | Select-Object -ExpandProperty PathsWithInstances | Where-Object {$_ -match '(?=.*explorer)(?=.*%)'})[0]
Get-Counter -Counter $((Get-Counter -ListSet Process | Select-Object -ExpandProperty Paths)[0])
Thanks in advance.
That would be neat if index 14 would always represent the same entry. But counter names are localized, so the order may be different. Let's see.
And actually I'm using % Processor Time
, which would be [0]
when set to English for me.
Yeah I just realized that in the end it goes for % Processor Time
. Just walked through the script and first stumbled upon it retrieving \Process(*)\ID Process
as a counter string and then replacing \ID Process
with \% Processor Time
.
I have a good feeling about this to be honest. Even though they badly mess up with things like unnecessarily localizing system relevant strings they tend to have such lists and items in general in the same order or place throughout different locales.
My second idea to solve this:
Ultimately Get-Counter
should be retrieving the % Processor Time
by simply calculating TotalProcessorTime\SampleInterval
. According to the MS doc Get-Counter does this for one sample over a time span of one second if the according parameters aren't specified. Therefore we also could simply use (Get-Process <Process ID>).TotalProcessorTime
to calculate it ourselves. Question is if there is a big difference in precision and if that would even matter that much. Going this route we could probably avoid the whole Get-Counter cmdlet. In theory this should do the same as the Get-Counter cmdlet:
$process = 'BoostTesterMannix'
$interval = 1000
$time = Get-Date
$tpt = ( Get-Process $process ).TotalProcessorTime.Ticks
Start-Sleep -Milliseconds $interval
$dtpt = ( Get-Process $process ).TotalProcessorTime.Ticks- $tpt
$ppt = ( $dtpt / ( New-TimeSpan $time ).Ticks ) * 100
Write-Host "% Processor Time: $ppt"
Ahh stupid me... The last command didn't do what I wanted it to do and overwrote the content of the console. 😅 But still it seems to be working. Thank you very much @iDarkEmpire - this was with Russian interface language, right? Could you please again run only this code and share the result again?
(Get-Counter -ListSet Process | Select-Object -ExpandProperty Paths)[0]
(Get-Counter -ListSet Process | Select-Object -ExpandProperty PathsWithInstances | Where-Object {$_ -match '(?=.*explorer)(?=.*%)'})[0]
Thanks again.
yes, russian interface language
Thanks a lot @iDarkEmpire! 👌 It seems like either your system is installed with an English Windows image and has the Russian language package added afterwards OR some languages use the English counter names. Either way using the ListSet parameter to retrieve the names seems like a good idea. I will set up a few VMs with different language images and try the behavior in these environments. If it works I'll include it with my own version of CoreCycler and provide it for testing. It then could be integrated into the main version to hopefully resolve this issue for all languages.
Ok so I set up a Russian VM and tried this.
(Get-Counter -ListSet **Process** | Select-Object -ExpandProperty Paths)[0]
... isn't working for the simple reason, that the ListSet parameter also wants the localized name... 🤦♂️
But indeed the first parameter of the process list set in Russian is the translated version of \Process(*)\% Processor Time
. I will try it for two additional languages but this looks promising.
And the correct list set can be found by regex matching the paths.
This is what so far worked for me for both Russian and English Windows:
$processSet = (Get-Counter -ListSet * | Where-Object {$_.PathsWithInstances -match '(?=.*\(explorer\))(?=.*%)' -and -not ($_.PathsWithInstances -match '\/0\)' ) } )[0].CounterSetName
(Get-Counter -ListSet $processSet | Select-Object -ExpandProperty Paths)[0]
I have to say though that the original attempt from the current CoreCycler version (retrieving the names from the Perflib registry keys) works perfectly fine on my Russian Windows 10 VM and returns the correct Russian counter names. So I guess @iDarkEmpire's issue lies in the display language differing from OS installation language - Russian installation gives Russian reg keys but English interface language sets English counter names in the shell.
yes, windows english image with russian localization package installed
I was able to reproduce the issue. It is indeed the case that on an English Windows image with Russian language pack installed the HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Perflib\009 key gets replaced with the Russian counter names, too. There is not a single key present anymore that contains the English counter names. Running the enable_performance_counter.bat on this system also doesn't change anything about this. All keys are still in Russian after running it. Meanwhile on a Russian image this is not the case and 009 contains the English counter names. That means MS is messing it up even more when installing language packs and we can't depend on it at all. Even though I must say this really is an edge case.
I tried to simply replace how the strings are retrieved using my ListSet approach from above. But that didn't work out. We not only need the localized \Process(*)\% Processor Time
for which it worked perfectly fine in EN, FR, RU, ES images. But we also need the localized ID Process
string to retrieve the correct counter process ID/string of the stress test. This one turned out to be on position [14] in EN, RU and ES and looked promising to this point but is on position [12] of the ListSet array in FR. Dead end.
I then thought why don't we just use the IDs and use only the Get-PerformanceCounterLocalNames function as we know the IDs. I then stumbled upon this link which tells that you can use the IDs directly instead of the names.
Get-Counter -Counter "\238(*)\6"
works perfectly fine and is the equivalent of the counter path \Processor(*)\% Processor Time
.
But sadly Get-Counter "\230(*)\784"
which should be \Process(*)\ID Process
doesn't work. Right when I thought I understand how this counter construct works in Windows it again is not what I expected it to be. 😅 Get-Counter "\230(*)\ID Process"
on the other hand works... It's just really weird.
Next I'll check if the IDs are the same for the relevant counter names in my 4 test languages. If they are this would be the way to go in my mind.
O Allah...just change the language to English do your CPU stress test, then switch back to your language. Simple solution - sometimes not a wrost solution)) Yeah, It's cool when everything works out of the box But, code developer gave us a super solution that allows us to do such a stress test on a single core, which (For a second) no program on the market gives. Thank you so much for your tinder (This is for you, the developer of this code) But don't make a problem for yourself ))
Okay, OCCT can do that too.Stupid user wrote a comment without thinking My bad...
but I have always "FATAL ERROR: Could not get the localized Performance Process Counter name!"
tested with v0.7.9.0