Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Getting frequncy out of /proc/cpuinfo

49 views
Skip to first unread message

Cecil Westerhof

unread,
Dec 1, 2017, 8:28:07 AM12/1/17
to
I want to fetch the frequencies out of /proc/cpuinfo.

This information is in line like:
cpu MHz : 1400.000

What is the best way to retrieve this information?

--
Cecil Westerhof
Senior Software Engineer
LinkedIn: http://www.linkedin.com/in/cecilwesterhof

Rich

unread,
Dec 1, 2017, 8:55:54 AM12/1/17
to
Cecil Westerhof <Ce...@decebal.nl> wrote:
> I want to fetch the frequencies out of /proc/cpuinfo.
>
> This information is in line like:
> cpu MHz : 1400.000
>
> What is the best way to retrieve this information?

"Best" is somewhat of an 'opinion' type item.

One way to do so would be to read the file line by line, pattern
matching each line against "cpu MHz", then when a match is found,
extract the numerical value.

Whether that is 'best' is quite subjective.

Cecil Westerhof

unread,
Dec 1, 2017, 9:44:06 AM12/1/17
to
That is what I do at the moment:
set filename "/proc/cpuinfo"
set pattern "^cpu MHz."
set count 0

set fid [open ${filename} r]
while {[gets ${fid} line] != -1} {
if {[regexp -all -- ${pattern} ${line}]} {
set frequency [lindex ${line} 3]
incr count
puts ${line}
puts [lindex ${line} 3]
if {${count} == 1} {
set max ${frequency}
set min ${frequency}
set sigma ${frequency}
} else {
if {${frequency} < ${min}} {
set min ${frequency}
} elseif {${frequency} > ${max}} {
set max ${frequency}
}
set sigma [expr ${sigma} + ${frequency}]
}
}
}
close ${fid}
puts [format "total: %f\nmin: %f\nmax: %f\navg: %f" \
${sigma} \
${min} \
${max} \
[expr ${sigma} / ${count}]]

But it seems a bit verbose. I was wondering if there was a way to have
an expression and a filename and return an array of matches.

Also: I would like to use something like:
set pattern "^cpu MHz.\S+: [0-9.]$"
instead of:
set pattern "^cpu MHz."

But that does not work. Even:
set pattern "^cpu MHz.\S+"
does not work.

What am I doing wrong?

Ashok

unread,
Dec 1, 2017, 10:46:13 AM12/1/17
to
If you are willing to use tcllib you can try fileutil::grep

Rich

unread,
Dec 1, 2017, 1:29:02 PM12/1/17
to
Cecil Westerhof <Ce...@decebal.nl> wrote:
> Rich <ri...@example.invalid> writes:
>
>> Cecil Westerhof <Ce...@decebal.nl> wrote:
>>> I want to fetch the frequencies out of /proc/cpuinfo.
>>>
>>> This information is in line like:
>>> cpu MHz : 1400.000
>>>
>>> What is the best way to retrieve this information?
>>
>> "Best" is somewhat of an 'opinion' type item.
>>
>> One way to do so would be to read the file line by line, pattern
>> matching each line against "cpu MHz", then when a match is found,
>> extract the numerical value.
>
> That is what I do at the moment:
[long code block elided - see prior post for details]
>
> But it seems a bit verbose. I was wondering if there was a way to
> have an expression and a filename and return an array of matches.

Install tcllib, then you can have a tcl level 'grep' where you pass it
a pattern and a set of filenames.

> Also: I would like to use something like:
> set pattern "^cpu MHz.\S+: [0-9.]$"
> instead of:
> set pattern "^cpu MHz."
>
> But that does not work. Even:
> set pattern "^cpu MHz.\S+"
> does not work.
>
> What am I doing wrong?

You forgot a + on your bracket expression, so it only matches a single
character.

The \S escape is "not whitespace" - you want \s

$ rlwrap tclsh
% set line "cpu MHz : 1400.000"
cpu MHz : 1400.000
% regexp {^cpu MHz.\s+: [0-9.]$} $line -> freq
0
% regexp {^cpu MHz.\s+: [0-9.]+$} $line -> freq
1
% regexp {^cpu MHz.\s+: [0-9.]+$} $line
1

But you can also do more in the regexp. Change it to this one:

^cpu MHz\s+:\s([0-9.]+)$

And call the regexp command this way:

% regexp {^cpu MHz\s+:\s([0-9.]+)$} $line -> freq
1
% set freq
1400.000
%

And the regex engine also returns the frequency already extracted for
you. The parenthesis do the extraction.

Cecil Westerhof

unread,
Dec 1, 2017, 6:59:06 PM12/1/17
to
Rich <ri...@example.invalid> writes:

> Cecil Westerhof <Ce...@decebal.nl> wrote:
>> Rich <ri...@example.invalid> writes:
>>
>>> Cecil Westerhof <Ce...@decebal.nl> wrote:
>>>> I want to fetch the frequencies out of /proc/cpuinfo.
>>>>
>>>> This information is in line like:
>>>> cpu MHz : 1400.000
>>>>
>>>> What is the best way to retrieve this information?
>>>
>>> "Best" is somewhat of an 'opinion' type item.
>>>
>>> One way to do so would be to read the file line by line, pattern
>>> matching each line against "cpu MHz", then when a match is found,
>>> extract the numerical value.
>>
>> That is what I do at the moment:
> [long code block elided - see prior post for details]
>>
>> But it seems a bit verbose. I was wondering if there was a way to
>> have an expression and a filename and return an array of matches.
>
> Install tcllib, then you can have a tcl level 'grep' where you pass it
> a pattern and a set of filenames.

I will look into that. But that would make my code depending on an
extra library?


>> Also: I would like to use something like:
>> set pattern "^cpu MHz.\S+: [0-9.]$"
>> instead of:
>> set pattern "^cpu MHz."
>>
>> But that does not work. Even:
>> set pattern "^cpu MHz.\S+"
>> does not work.
>>
>> What am I doing wrong?
>
> You forgot a + on your bracket expression, so it only matches a single
> character.

That was not very smart. :'-(


> The \S escape is "not whitespace" - you want \s
>
> $ rlwrap tclsh
> % set line "cpu MHz : 1400.000"
> cpu MHz : 1400.000
> % regexp {^cpu MHz.\s+: [0-9.]$} $line -> freq
> 0
> % regexp {^cpu MHz.\s+: [0-9.]+$} $line -> freq
> 1
> % regexp {^cpu MHz.\s+: [0-9.]+$} $line
> 1
>
> But you can also do more in the regexp. Change it to this one:
>
> ^cpu MHz\s+:\s([0-9.]+)$

I did it a bit different:
set pattern {^cpu MHz\s+: ([0-9]+)\.0+$}

There should be exactly one space after the ':'.
I only want the integral part.
After the point there are only zeros.


> And call the regexp command this way:
>
> % regexp {^cpu MHz\s+:\s([0-9.]+)$} $line -> freq
> 1
> % set freq
> 1400.000
> %
>
> And the regex engine also returns the frequency already extracted for
> you. The parenthesis do the extraction.

I thought something like this should be possible. ;-)

I now have:
while {[gets ${fid} line] != -1} {
if {[regexp ${pattern} ${line} -> frequency] == 1} {
incr count
if {${count} == 1} {
set max ${frequency}
.
.
.

And my format string is of-course now:
"total: %d\nmin: %d\nmax: %d\navg: %d\n"

Rich

unread,
Dec 1, 2017, 8:30:49 PM12/1/17
to
Cecil Westerhof <Ce...@decebal.nl> wrote:
> Rich <ri...@example.invalid> writes:
>
>> Cecil Westerhof <Ce...@decebal.nl> wrote:
>>> Rich <ri...@example.invalid> writes:
>>>
>>>> Cecil Westerhof <Ce...@decebal.nl> wrote:
>>>>> I want to fetch the frequencies out of /proc/cpuinfo.
>>>>>
>>>>> This information is in line like:
>>>>> cpu MHz : 1400.000
>>>>>
>>>>> What is the best way to retrieve this information?
>>>>
>>>> "Best" is somewhat of an 'opinion' type item.
>>>>
>>>> One way to do so would be to read the file line by line, pattern
>>>> matching each line against "cpu MHz", then when a match is found,
>>>> extract the numerical value.
>>>
>>> That is what I do at the moment:
>> [long code block elided - see prior post for details]
>>>
>>> But it seems a bit verbose. I was wondering if there was a way to
>>> have an expression and a filename and return an array of matches.
>>
>> Install tcllib, then you can have a tcl level 'grep' where you pass it
>> a pattern and a set of filenames.
>
> I will look into that. But that would make my code depending on an
> extra library?

Yes. But it is a pure Tcl library so 'distributing' both parts
together is not hard. But the 'grep' library routine would simply give
you the lines of interest, you'd still need to pull out the number of
interest anyway. So your snippet below may be the better variant in
this case.

>> The \S escape is "not whitespace" - you want \s
>>
>> $ rlwrap tclsh
>> % set line "cpu MHz : 1400.000"
>> cpu MHz : 1400.000
>> % regexp {^cpu MHz.\s+: [0-9.]+$} $line
>> 1
>>
>> But you can also do more in the regexp. Change it to this one:
>>
>> ^cpu MHz\s+:\s([0-9.]+)$
>
> I did it a bit different:
> set pattern {^cpu MHz\s+: ([0-9]+)\.0+$}
>
> There should be exactly one space after the ':'.
> I only want the integral part.
> After the point there are only zeros.

That works. I did not know if you wanted the full string or the
integral part when I wrote mine.

>> And call the regexp command this way:
>>
>> % regexp {^cpu MHz\s+:\s([0-9.]+)$} $line -> freq
>> 1
>> % set freq
>> 1400.000
>> %
>>
>> And the regex engine also returns the frequency already extracted for
>> you. The parenthesis do the extraction.
>
> I thought something like this should be possible. ;-)
>
> I now have:
> while {[gets ${fid} line] != -1} {
> if {[regexp ${pattern} ${line} -> frequency] == 1} {
> incr count
> if {${count} == 1} {
> set max ${frequency}
> .
> .
> .
>
> And my format string is of-course now:
> "total: %d\nmin: %d\nmax: %d\navg: %d\n"

One little extra tip. That -> is actually a variable assignment. The
third parameter returns the full match, so it would contain the whole
line. You could access it using the ${} notation (${->}) if you really
wanted its contents. The "->" variable name just makes for a nice look
when one only wants the sub-matches instead of the full match.

Schelte Bron

unread,
Dec 2, 2017, 7:23:39 AM12/2/17
to
Cecil Westerhof wrote:
> Rich <ri...@example.invalid> writes:
>> Install tcllib, then you can have a tcl level 'grep' where you
>> pass it a pattern and a set of filenames.
>
> I will look into that. But that would make my code depending on an
> extra library?
>
I would use [scan] rather than [regexp]:

namespace path {tcl::mathfunc tcl::mathop}

set fd [open /proc/cpuinfo]
set list {}
while {[gets $fd line] != -1} {
if {[scan $line {cpu MHz : %f} speed] == 1} {
lappend list $speed
}
}
close $fd

puts [format "total: %.3f\nmin: %.3f\nmax: %.3f\navg: %.3f" \
[set sigma [+ {*}$list]] \
[min {*}$list] \
[max {*}$list] \
[/ $sigma [llength $list]]]


Schelte.

Cecil Westerhof

unread,
Dec 2, 2017, 4:44:06 PM12/2/17
to
Rich <ri...@example.invalid> writes:

>>> But you can also do more in the regexp. Change it to this one:
>>>
>>> ^cpu MHz\s+:\s([0-9.]+)$
>>
>> I did it a bit different:
>> set pattern {^cpu MHz\s+: ([0-9]+)\.0+$}
>>
>> There should be exactly one space after the ':'.
>> I only want the integral part.
>> After the point there are only zeros.
>
> That works. I did not know if you wanted the full string or the
> integral part when I wrote mine.

I did not tell. ;-) But it are always big numbers without anything
after the comma, so it is not really useful to use floats I think.

But you set me on the right track.


> One little extra tip. That -> is actually a variable assignment. The
> third parameter returns the full match, so it would contain the whole
> line. You could access it using the ${} notation (${->}) if you really
> wanted its contents. The "->" variable name just makes for a nice look
> when one only wants the sub-matches instead of the full match.

Yep, that was very useful.
0 new messages