Tizen 2.1 base
authorJinkun Jang <jinkun.jang@samsung.com>
Tue, 12 Mar 2013 16:44:37 +0000 (01:44 +0900)
committerJinkun Jang <jinkun.jang@samsung.com>
Tue, 12 Mar 2013 16:44:37 +0000 (01:44 +0900)
155 files changed:
Android.mk [new file with mode: 0644]
COPYING [new file with mode: 0644]
INSTALL [new file with mode: 0644]
Makefile.am [new file with mode: 0644]
README [new file with mode: 0644]
README.traceevent [new file with mode: 0644]
TODO [new file with mode: 0644]
autogen.sh [new file with mode: 0755]
configure.ac [new file with mode: 0644]
doc/Makefile.am [new file with mode: 0644]
doc/powertop.8 [new file with mode: 0644]
packaging/powertop.changes [new file with mode: 0644]
packaging/powertop.manifest [new file with mode: 0644]
packaging/powertop.spec [new file with mode: 0644]
patches/linux-2.6.37-ahci-alpm-accounting.patch [new file with mode: 0644]
patches/linux-2.6.37-vfs-dirty-inode.patch [new file with mode: 0644]
patches/linux-3.3.0-ahci-alpm-accounting.patch [new file with mode: 0644]
patches/linux-3.3.0-vfs-dirty-inode.patch [new file with mode: 0644]
po/.tx/config [new file with mode: 0644]
po/LINGUAS [new file with mode: 0644]
po/Makefile.in.in [new file with mode: 0644]
po/Makevars [new file with mode: 0644]
po/POTFILES.in [new file with mode: 0644]
po/bn_IN.po [new file with mode: 0644]
po/ca.po [new file with mode: 0644]
po/cs_CZ.po [new file with mode: 0644]
po/de_DE.po [new file with mode: 0644]
po/en_GB.po [new file with mode: 0644]
po/en_US.po [new file with mode: 0644]
po/es_ES.po [new file with mode: 0644]
po/hi.po [new file with mode: 0644]
po/hu_HU.po [new file with mode: 0644]
po/id_ID.po [new file with mode: 0644]
po/lt.po [new file with mode: 0644]
po/nl_NL.po [new file with mode: 0644]
po/pl_PL.po [new file with mode: 0644]
po/powertop.pot [new file with mode: 0644]
po/zh_CN.po [new file with mode: 0644]
po/zh_TW.po [new file with mode: 0644]
src/Makefile.am [new file with mode: 0644]
src/calibrate/calibrate.cpp [new file with mode: 0644]
src/calibrate/calibrate.h [new file with mode: 0644]
src/cpu/abstract_cpu.cpp [new file with mode: 0644]
src/cpu/cpu.cpp [new file with mode: 0644]
src/cpu/cpu.h [new file with mode: 0644]
src/cpu/cpu_core.cpp [new file with mode: 0644]
src/cpu/cpu_linux.cpp [new file with mode: 0644]
src/cpu/cpu_package.cpp [new file with mode: 0644]
src/cpu/cpudevice.cpp [new file with mode: 0644]
src/cpu/cpudevice.h [new file with mode: 0644]
src/cpu/intel_cpus.cpp [new file with mode: 0644]
src/cpu/intel_cpus.h [new file with mode: 0644]
src/cpu/intel_gpu.cpp [new file with mode: 0644]
src/csstoh.c [new file with mode: 0644]
src/devices/ahci.cpp [new file with mode: 0644]
src/devices/ahci.h [new file with mode: 0644]
src/devices/alsa.cpp [new file with mode: 0644]
src/devices/alsa.h [new file with mode: 0644]
src/devices/backlight.cpp [new file with mode: 0644]
src/devices/backlight.h [new file with mode: 0644]
src/devices/device.cpp [new file with mode: 0644]
src/devices/device.h [new file with mode: 0644]
src/devices/i915-gpu.cpp [new file with mode: 0644]
src/devices/i915-gpu.h [new file with mode: 0644]
src/devices/network.cpp [new file with mode: 0644]
src/devices/network.h [new file with mode: 0644]
src/devices/rfkill.cpp [new file with mode: 0644]
src/devices/rfkill.h [new file with mode: 0644]
src/devices/runtime_pm.cpp [new file with mode: 0644]
src/devices/runtime_pm.h [new file with mode: 0644]
src/devices/thinkpad-fan.cpp [new file with mode: 0644]
src/devices/thinkpad-fan.h [new file with mode: 0644]
src/devices/thinkpad-light.cpp [new file with mode: 0644]
src/devices/thinkpad-light.h [new file with mode: 0644]
src/devices/usb.cpp [new file with mode: 0644]
src/devices/usb.h [new file with mode: 0644]
src/devlist.cpp [new file with mode: 0644]
src/devlist.h [new file with mode: 0644]
src/display.cpp [new file with mode: 0644]
src/display.h [new file with mode: 0644]
src/lib.cpp [new file with mode: 0644]
src/lib.h [new file with mode: 0644]
src/main.cpp [new file with mode: 0644]
src/measurement/acpi.cpp [new file with mode: 0644]
src/measurement/acpi.h [new file with mode: 0644]
src/measurement/extech.cpp [new file with mode: 0644]
src/measurement/extech.h [new file with mode: 0644]
src/measurement/measurement.cpp [new file with mode: 0644]
src/measurement/measurement.h [new file with mode: 0644]
src/measurement/power_supply.cpp [new file with mode: 0644]
src/measurement/power_supply.h [new file with mode: 0644]
src/measurement/sysfs.cpp [new file with mode: 0644]
src/measurement/sysfs.h [new file with mode: 0644]
src/parameters/learn.cpp [new file with mode: 0644]
src/parameters/parameters.cpp [new file with mode: 0644]
src/parameters/parameters.h [new file with mode: 0644]
src/parameters/persistent.cpp [new file with mode: 0644]
src/perf/perf.cpp [new file with mode: 0644]
src/perf/perf.h [new file with mode: 0644]
src/perf/perf_bundle.cpp [new file with mode: 0644]
src/perf/perf_bundle.h [new file with mode: 0644]
src/perf/perf_event.h [new file with mode: 0644]
src/powertop.css [new file with mode: 0644]
src/process/do_process.cpp [new file with mode: 0644]
src/process/interrupt.cpp [new file with mode: 0644]
src/process/interrupt.h [new file with mode: 0644]
src/process/powerconsumer.cpp [new file with mode: 0644]
src/process/powerconsumer.h [new file with mode: 0644]
src/process/process.cpp [new file with mode: 0644]
src/process/process.h [new file with mode: 0644]
src/process/processdevice.cpp [new file with mode: 0644]
src/process/processdevice.h [new file with mode: 0644]
src/process/timer.cpp [new file with mode: 0644]
src/process/timer.h [new file with mode: 0644]
src/process/work.cpp [new file with mode: 0644]
src/process/work.h [new file with mode: 0644]
src/report/report-formatter-base.cpp [new file with mode: 0644]
src/report/report-formatter-base.h [new file with mode: 0644]
src/report/report-formatter-csv.cpp [new file with mode: 0644]
src/report/report-formatter-csv.h [new file with mode: 0644]
src/report/report-formatter-html.cpp [new file with mode: 0644]
src/report/report-formatter-html.h [new file with mode: 0644]
src/report/report-formatter.h [new file with mode: 0644]
src/report/report-maker.cpp [new file with mode: 0644]
src/report/report-maker.h [new file with mode: 0644]
src/report/report.cpp [new file with mode: 0644]
src/report/report.h [new file with mode: 0644]
src/tuning/bluetooth.cpp [new file with mode: 0644]
src/tuning/bluetooth.h [new file with mode: 0644]
src/tuning/cpufreq.cpp [new file with mode: 0644]
src/tuning/cpufreq.h [new file with mode: 0644]
src/tuning/ethernet.cpp [new file with mode: 0644]
src/tuning/ethernet.h [new file with mode: 0644]
src/tuning/iw.c [new file with mode: 0644]
src/tuning/iw.h [new file with mode: 0644]
src/tuning/nl80211.h [new file with mode: 0644]
src/tuning/runtime.cpp [new file with mode: 0644]
src/tuning/runtime.h [new file with mode: 0644]
src/tuning/tunable.cpp [new file with mode: 0644]
src/tuning/tunable.h [new file with mode: 0644]
src/tuning/tuning.cpp [new file with mode: 0644]
src/tuning/tuning.h [new file with mode: 0644]
src/tuning/tuningsysfs.cpp [new file with mode: 0644]
src/tuning/tuningsysfs.h [new file with mode: 0644]
src/tuning/tuningusb.cpp [new file with mode: 0644]
src/tuning/tuningusb.h [new file with mode: 0644]
src/tuning/wifi.cpp [new file with mode: 0644]
src/tuning/wifi.h [new file with mode: 0644]
traceevent/Makefile.am [new file with mode: 0644]
traceevent/event-parse.c [new file with mode: 0644]
traceevent/event-parse.h [new file with mode: 0644]
traceevent/event-utils.h [new file with mode: 0644]
traceevent/parse-filter.c [new file with mode: 0644]
traceevent/parse-utils.c [new file with mode: 0644]
traceevent/trace-seq.c [new file with mode: 0644]

diff --git a/Android.mk b/Android.mk
new file mode 100644 (file)
index 0000000..a52ecfd
--- /dev/null
@@ -0,0 +1,75 @@
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := debug
+LOCAL_SHARED_LIBRARIES := libstlport \
+                         libnl \
+                         libpci \
+                         libtraceevnet \
+LOCAL_MODULE := powertop  
+
+#LOCAL_CFLAGS += -Wall -O2 -g -fno-omit-frame-pointer -fstack-protector -Wshadow -Wformat -D_FORTIFY_SOURCE=2
+#LOCAL_CPPFLAGS += -Wall -O2 -g -fno-omit-frame-pointer
+
+LOCAL_C_INCLUDES += external/stlport/stlport/ external/stlport/stlport/stl external/stlport/stlport/using/h/  bionic external/libnl/include/
+
+LOCAL_SRC_FILES += \
+       src/parameters/parameters.cpp \
+       src/parameters/persistent.cpp \
+       src/parameters/learn.cpp \
+       src/process/powerconsumer.cpp \
+       src/process/work.cpp \
+       src/process/process.cpp \
+       src/process/timer.cpp \
+       src/process/device.cpp \
+       src/process/interrupt.cpp \
+       src/process/do_process.cpp \
+       src/cpu/intel_cpus.cpp \
+       src/cpu/cpu.cpp \
+       src/cpu/cpu_linux.cpp \
+       src/cpu/cpudevice.cpp \
+       src/cpu/cpu_core.cpp \
+       src/cpu/cpu_package.cpp \
+       src/cpu/abstract_cpu.cpp \
+       src/measurement/measurement.cpp \
+       src/measurement/acpi.cpp \
+       src/measurement/extech.cpp \
+       src/measurement/power_supply.cpp \
+       src/display.cpp \
+       src/report.cpp \
+       src/main.cpp \
+       src/tuning/tuning.cpp \
+       src/tuning/usb.cpp \
+       src/tuning/bluetooth.cpp \
+       src/tuning/ethernet.cpp \
+       src/tuning/runtime.cpp \
+       src/tuning/iw.c \
+       src/tuning/iw.h \
+       src/tuning/tunable.cpp \
+       src/tuning/sysfs.cpp \
+       src/tuning/cpufreq.cpp \
+       src/tuning/wifi.cpp \
+       src/perf/perf_bundle.cpp \
+       src/perf/perf.cpp \
+       src/devices/thinkpad-fan.cpp \
+       src/devices/alsa.cpp \
+       src/devices/runtime_pm.cpp \
+       src/devices/usb.cpp \
+       src/devices/ahci.cpp \
+       src/devices/rfkill.cpp \
+       src/devices/thinkpad-light.cpp \
+       src/devices/i915-gpu.cpp \
+       src/devices/backlight.cpp \
+       src/devices/network.cpp \
+       src/devices/device.cpp \
+       src/devlist.cpp \
+       src/calibrate/calibrate.cpp \
+       src/lib.cpp \
+       traceevent/event-parse.c \
+       traceevent/event-parse.h \
+       traceevent/event-utils.h \
+       traceevent/parse-filter.c \
+       traceevent/parse-utils.c \
+       traceevent/trace-seq.c
+
+include $(BUILD_EXECUTABLE)
diff --git a/COPYING b/COPYING
new file mode 100644 (file)
index 0000000..6d45519
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,340 @@
+                   GNU GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                       51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                   GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                           NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+
+           How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/INSTALL b/INSTALL
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/Makefile.am b/Makefile.am
new file mode 100644 (file)
index 0000000..f5e466b
--- /dev/null
@@ -0,0 +1,6 @@
+AUTOMAKE_OPTIONS = subdir-objects
+ACLOCAL_AMFLAGS = -I m4
+
+SUBDIRS = traceevent src po doc
+
+EXTRA_DIST = README TODO Android.mk COPYING autogen.sh 
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..7e789e0
--- /dev/null
+++ b/README
@@ -0,0 +1,116 @@
+Building & Installing PowerTOP
+------------------------------
+
+To build and install PowerTOP type the following commands, 
+       ./configure 
+       ./make
+       ./make install
+
+Note: For Android (running Intel Architecture ) there is a Android.mk 
+that was provided by community members, and at this time is supported
+ mostly by community members. 
+
+Build dependencies
+------------------
+
+PowerTOP uses C++, and expects g++ and libstdc++ to be functional 
+along with a glibc/pthreadsi, autoconf, automake, and libtool in the 
+development environment.
+
+in addition to that, PowerTOP requires the following components:
+
+pciutils-devel (is only required if you have PCI) 
+ncurses-devel  (required) 
+libnl-devel    (required)
+kernel version => 2.6.38
+
+Kernel Parameters:
+------------------
+
+PowerTOP needs some kernel config options enabled in order function properly.
+As of linux-3.3.0 these are (list probably incomplete):
+
+CONFIG_NO_HZ
+CONFIG_HIGH_RES_TIMERS
+CONFIG_HPET_TIMER
+CONFIG_CPU_FREQ_GOV_ONDEMAND
+CONFIG_USB_SUSPEND
+CONFIG_SND_AC97_POWER_SAVE
+CONFIG_TIMER_STATS
+CONFIG_PERF_EVENTS
+CONFIG_PERF_COUNTERS
+CONFIG_TRACEPOINTS
+CONFIG_TRACING
+CONFIG_EVENT_POWER_TRACING_DEPRECATED
+ACPI_PROCFS_POWER
+
+The patches in the patches/ sub-directory are required for PowerTOP to function
+fully.
+
+
+
+Outputting a report
+-------------------
+When invoking PowerTOP without arguments, PowerTOP starts in interactive mode.
+However, for reporting bugs etc there is a special reporting modes:
+
+For an HTML formatted report simply execute PowerTOP with the following,  
+
+powertop --html
+
+which will create a "powertop.html" file which is static and can be sent to
+others to help diagnose power issues. Additionally has the feature of showing 
+the tunables executions withing the report as a reference. 
+
+Note for the developers: If you make changes on the report format please
+make sure that the output can be cleanly validated by the W3C Markup
+Validation Service and W3C CSS Validation Service:
+ * http://validator.w3.org/#validate_by_upload
+ * http://jigsaw.w3.org/css-validator/#validate_by_upload
+
+For a CSV formatted report, simply execute PowerTOP with the following, 
+
+Powertop --csv 
+
+which will create a “powertop.csv” file which is static and can be used in 
+reporting, diagnoses, and analytical data analysis. 
+
+Also you can set the number of iterations, and duration of test, in which case 
+all reports will time stamp for you. 
+
+Calibrating & Power Numbers
+---------------------------
+PowerTOP will, when running on battery, track your power consumption as well
+as your activity on the system. Once there are sufficient such measurements,
+PowerTOP can start to report power estimates for various activities.
+You can help get this estimation more accurate by running a calibration
+cycle:
+
+powertop --calibrate
+
+at least once; this will cycle through various display brightness levels
+(including "off") as well as USB device activities and some other workloads.
+
+
+Code from other open source projects
+------------------------------------
+PowerTOP contains some code from other open source projects; we'd like to
+thank the authors of those projects for their work. 
+Specifically PowerTOP contains code from
+
+Parse Event Library - Copyright 2009, 2010 Red Hat Inc  Steven Rosted <srostedt@redhat.com>
+nl80211 userspace tool - Copyright 2007, 2008  Johannes Berg <johannes@sipsolutions.net>
+
+
+Extech Power Analyzer / Datalogger support
+------------------------------------------
+I use, and our analysis teams use, the Extech Power Analyzer/Datalogger
+(model number 380803) quite a lot, and PowerTOP supports using this
+device over the serial cable. Just pass the device node on the command line
+like this
+
+powertop --extech=/dev/ttyUSB0
+
+(where ttyUSB0 is the devicenode of the serial-to-usb adapter on my system)
+
diff --git a/README.traceevent b/README.traceevent
new file mode 100644 (file)
index 0000000..38563ab
--- /dev/null
@@ -0,0 +1,15 @@
+traceevent: 
+
+The traceevent library being built in PowerTOP is really a effort by Steven Rostedt. 
+The long term intent is for Steven to push the trace event library to distributions, and consume it externally. Right now the PowerTOP project is keeping in sync with his code posted in the Linux kernel git under tools/lib/traceevent. 
+We will not take patches into the traceevent code directly, rather we will be re-basing 
+against that code base. 
+
+If you find a bug in the trace event code, you should to one of two things. 
+
+1. Send a patch to the PowerTOP mailing list, which will get forwared to Steven if appropriate. 
+2. Send a patch to the PowerTOP mailing list, cc <Steven Rostedt> rostedt@goodmis.org
+
+
+Please do use the PowerTOP mailing list to discuss topics about traceevent as its used with PowerTOP.
+
diff --git a/TODO b/TODO
new file mode 100644 (file)
index 0000000..6735b82
--- /dev/null
+++ b/TODO
@@ -0,0 +1,21 @@
+Needed for 2.2
+----------------------------------
+
+* more translations / strings
+* more end user documentation
+* audio calibration? Need appropriate sample
+* reporting for workload mode 
+* Add GPU stats to reports [csv,html]
+
+
+Nice to Have
+----------------------------------
+NCURSES STUB (anyone who may care to do this)
+        PowerTOP is intended to be run with ncurses. As such if there is any
+       distribution that can't or won't support ncurses, they need to supply 
+       a separate stub to handle there issues.  
+
+DONE for 2.2
+----------------------------------
+* interactive mode scrolling 
+* In tunables suggest writing min_power to all SATA ports 
diff --git a/autogen.sh b/autogen.sh
new file mode 100755 (executable)
index 0000000..e210037
--- /dev/null
@@ -0,0 +1,3 @@
+#!/bin/sh      
+
+autoreconf --install --verbose
diff --git a/configure.ac b/configure.ac
new file mode 100644 (file)
index 0000000..3a7a83c
--- /dev/null
@@ -0,0 +1,83 @@
+#                                               -*- Autoconf -*-
+# Process this file with autoconf to produce a configure script.
+
+AC_PREREQ([2.68])
+AC_INIT([powertop], [2.2], [powertop@lists.01.org])
+AM_INIT_AUTOMAKE([-Wall foreign ])
+AC_LANG([C++])
+AC_CONFIG_FILES([Makefile src/Makefile traceevent/Makefile po/Makefile.in doc/Makefile])
+AC_CONFIG_SRCDIR([src/main.cpp])
+AC_CONFIG_MACRO_DIR([m4])
+AC_CONFIG_HEADERS([config.h])
+GETTEXT_PACKAGE=powertop
+AC_SUBST(GETTEXT_PACKAGE)
+AM_SILENT_RULES([yes])
+AM_GNU_GETTEXT([external])
+AM_GNU_GETTEXT_VERSION([0.18])
+
+m4_ifdef([AM_PROG_AR], [AM_PROG_AR])
+# Checks for programs.
+AC_PROG_CPP
+AC_PROG_CXX
+AC_PROG_LIBTOOL
+AC_PROG_CC
+AC_PROG_INSTALL
+AM_PROG_CC_C_O
+
+# Checks for libraries.
+# Checks for header files.
+AC_CHECK_HEADERS([fcntl.h libintl.h limits.h locale.h malloc.h stdint.h stdlib.h string.h sys/ioctl.h sys/socket.h sys/statfs.h sys/time.h termios.h unistd.h ncurses.h])
+
+# Checks for typedefs, structures, and compiler characteristics.
+AC_HEADER_STDBOOL
+AC_C_INLINE
+AC_TYPE_INT64_T
+AC_TYPE_PID_T
+AC_TYPE_SIZE_T
+AC_TYPE_SSIZE_T
+AC_TYPE_UINT16_T
+AC_TYPE_UINT32_T
+AC_TYPE_UINT64_T
+
+# Checks for library functions.
+AC_FUNC_MALLOC
+AC_FUNC_MMAP
+AC_FUNC_REALLOC
+AC_FUNC_STRTOD
+AC_CHECK_FUNCS([fdatasync getpagesize gettimeofday memmove memset mkdir munmap pow realpath regcomp select setlocale socket sqrt strcasecmp strchr strdup strerror strncasecmp strstr strtoul strtoull])
+
+AC_SEARCH_LIBS([delwin], [ncursesw ncurses], [], AC_MSG_ERROR([ncurses is required but was not found]), [])
+
+has_libpci=0
+PKG_CHECK_MODULES([PCIUTILS], [libpci],[has_libpci=1],[
+       AC_SEARCH_LIBS([pci_get_dev], [pci],[has_libpci=1], [has_libpci=0] )])
+
+has_libnl_ver=0
+# libnl-2 provides only libnl-2.0.pc file, so we check for separate libnl-genl-3.0.pc
+# pkg-config file just for libnl-3.0 case.
+#
+PKG_CHECK_MODULES([LIBNL], [libnl-3.0 >= 3.0 libnl-genl-3.0 >= 3.0], [has_libnl_ver=3], [
+       PKG_CHECK_MODULES([LIBNL], [libnl-2.0 >= 2.0], [has_libnl_ver=2], [
+               PKG_CHECK_MODULES([LIBNL], [libnl-1], [has_libnl_ver=1], [has_libnl_ver=0])])])
+if (test "$has_libnl_ver" -eq 0); then
+       AC_MSG_ERROR(libnl and libnl-genl are required but were not found)
+fi
+if (test "$has_libnl_ver" -gt 1); then
+       AC_DEFINE([HAVE_LIBNL20], [1], [Define if you have libnl-2.0 or higher])
+fi
+
+if (test "$has_libpci" -eq 0); then 
+       AC_DEFINE([HAVE_NO_PCI],[1],[Define if pci is not supported])
+        AC_MSG_WARN([
+                       ************* LIBPCI SUPPORT NOT CONFIGURED**************
+                       If you need or want pci support, please install libpci 
+                       and re-configure PowerTOP. 
+                       *********************************************************
+       ])
+fi
+
+AC_SEARCH_LIBS([pthread_create], [pthread], [], AC_MSG_ERROR([libpthread is required but was not found]), [])
+AC_SEARCH_LIBS([inet_aton], [resolv], [], AC_MSG_ERROR([libresolv is required but was not found]), [])
+
+AC_OUTPUT
diff --git a/doc/Makefile.am b/doc/Makefile.am
new file mode 100644 (file)
index 0000000..3fa3770
--- /dev/null
@@ -0,0 +1,2 @@
+man_MANS = powertop.8
+EXTRA_DIST = powertop.8
diff --git a/doc/powertop.8 b/doc/powertop.8
new file mode 100644 (file)
index 0000000..8a70076
--- /dev/null
@@ -0,0 +1,62 @@
+.TH POWERTOP 8 "June 1, 2012" "Linux" "powertop manual"
+.SH NAME
+powertop \- a power consumption and power management diagnosis tool.
+.SH SYNOPSIS
+.B powertop
+.RB [
+.IR options
+.RB ]
+.SH DESCRIPTION
+.P
+\fBpowertop\fP is a program that helps to diagnose various issues with power consumption
+and power management. It also has an interactive mode allowing one to
+experiment with various power management settings. When invoking powertop
+without arguments powertop starts in interactive mode.
+.SH OPTIONS
+.TP
+\fB\-\-calibrate
+runs powertop in calibration mode. When running on battery, powertop
+can track power consumption as well as system activity. When there
+are enough measurements, powertop can start to report power estimates. One
+can get more accurate estimates by using this option to enable a
+calibration cycle. This will cycle through various display levels and USB
+device activities and workloads.
+.TP
+\fB\-\-csv[\fR=\fIFILENAME\fR]
+generate a CSV report. If a filename is not specified then the
+default name "powertop.csv" is used. The CSV report can be
+used for reporting and data analysis.
+.TP
+\fB\-\-debug
+ run in "debug" mode.
+.TP
+\fB\-\-extech\fR=\fIdevnode\fR
+use the Extech Power Analyzer for measurements. This allows one to
+specify the serial device node of the serial to USB adaptor connecting to
+the Extech Power Analyzer, for example /dev/ttyUSB0.
+.TP
+\fB\-\-help
+ show the help message.
+.TP
+\fB\-\-html[\fR=\fIFILENAME\fR]
+generate an HTML report. If a filename is not specified then the
+default name "powertop.html" is used. The HTML report can be
+sent to others to help diagnose power issues.
+.TP
+\fB\-\-iteration[\fR=\fIiterations\fR]
+number of times to run each test.
+.TP
+\fB\-\-quiet
+ supress stderr output.
+.TP
+\fB\-\-time[\fR=\fIseconds\fR]
+generate a report for a specified number of seconds.
+.TP
+\fB\-\-version
+print version information and exit.
+.SH BUGS
+Send bug reports to <powertop@lists.01.org>
+.SH SEE ALSO
+The program is more fully described at https://01.org/powertop
+.SH AUTHOR
+powertop was written by Arjan van de Ven <arjan@linux.intel.com>, and is currently maintained by Chris E Ferron <chris.e.ferron@linux.intel.com>.
diff --git a/packaging/powertop.changes b/packaging/powertop.changes
new file mode 100644 (file)
index 0000000..fbd0321
--- /dev/null
@@ -0,0 +1,12 @@
+* Mon Jan 14 2013 Austin Zhang <zhang.austin@gmail.com>
+- Rebase to upsteam version
+- Reimplement atom support
+
+* Mon Nov 26 2012 Austin Zhang <zhang.austin@gmail.com> b655ae6
+- Merge branch 'local-up'
+- Initial import powertop2.2 into RSA 
+  1 import powertop-2.2 codes
+  2 add default Smack file
+  3 add spec file
+  4 changelog file
+
diff --git a/packaging/powertop.manifest b/packaging/powertop.manifest
new file mode 100644 (file)
index 0000000..017d22d
--- /dev/null
@@ -0,0 +1,5 @@
+<manifest>
+ <request>
+    <domain name="_"/>
+ </request>
+</manifest>
diff --git a/packaging/powertop.spec b/packaging/powertop.spec
new file mode 100644 (file)
index 0000000..bd175b2
--- /dev/null
@@ -0,0 +1,58 @@
+Name:       powertop
+Summary:    PowerTop is tool that is used for power diagnostics
+Url    :    http://www.linuxpowertop.org
+Version:    2.2
+Release:    1
+Group:      Applications/System
+License:    GPLv2
+Source0:    http://www.kernel.org/pub/linux/status/powertop/powertop-%{version}.tar.bz2
+Source1001: packaging/powertop.manifest
+
+BuildRequires:  pkgconfig(libpci)
+BuildRequires:  pkgconfig(ncurses)
+BuildRequires:  gettext
+BuildRequires:  ncurses-devel
+BuildRequires:  libnl2
+BuildRequires:  libnl2-devel
+
+%description
+PowerTop is tool that detects which Linux programs
+and kernel tunables are resulting in the largest
+power consumption and use of battery time. By
+fixing (or closing) these applications or
+processes, you can immediately see the power
+savings in the tool. You'll also see the estimated
+time left for battery power if you are running a
+laptop.
+
+%prep
+%setup -q -n %{name}-%{version}
+
+%build
+./autogen.sh
+%configure --disable-static
+cp %{SOURCE1001} .
+make %{?jobs:-j%jobs}
+
+%install
+%make_install
+
+%post -p /sbin/ldconfig
+
+%files
+%manifest powertop.manifest
+%defattr(-,root,root,-)
+%doc COPYING
+/usr/sbin/powertop
+/usr/share/locale/ca/LC_MESSAGES/powertop.mo
+/usr/share/locale/cs_CZ/LC_MESSAGES/powertop.mo
+/usr/share/locale/de_DE/LC_MESSAGES/powertop.mo
+/usr/share/locale/en_GB/LC_MESSAGES/powertop.mo
+/usr/share/locale/en_US/LC_MESSAGES/powertop.mo
+/usr/share/locale/es_ES/LC_MESSAGES/powertop.mo
+/usr/share/locale/hu_HU/LC_MESSAGES/powertop.mo
+/usr/share/locale/id_ID/LC_MESSAGES/powertop.mo
+/usr/share/locale/nl_NL/LC_MESSAGES/powertop.mo
+/usr/share/locale/zh_TW/LC_MESSAGES/powertop.mo
+/usr/share/man/man8/powertop.8.gz
+
diff --git a/patches/linux-2.6.37-ahci-alpm-accounting.patch b/patches/linux-2.6.37-ahci-alpm-accounting.patch
new file mode 100644 (file)
index 0000000..dbe897d
--- /dev/null
@@ -0,0 +1,302 @@
+From: Arjan van de Ven <arjan@linux.intel.com>
+Subject: [PATCH] libata: Add ALPM power state accounting to the AHCI driver
+
+PowerTOP wants to be able to show the user how effective the ALPM link
+power management is for the user. ALPM is worth around 0.5W on a quiet
+link; PowerTOP wants to be able to find cases where the "quiet link" isn't
+actually quiet.
+
+This patch adds state accounting functionality to the AHCI driver for
+PowerTOP to use.
+The parts of the patch are
+1) the sysfs logic of exposing the stats for each state in sysfs
+2) the basic accounting logic that gets update on link change interrupts
+   (or when the user accesses the info from sysfs)
+3) a "accounting enable" flag; in order to get the accounting to work,
+   the driver needs to get phyrdy interrupts on link status changes.
+   Normally and currently this is disabled by the driver when ALPM is
+   on (to reduce overhead); when PowerTOP is running this will need
+   to be on to get usable statistics... hence the sysfs tunable.
+
+The PowerTOP output currently looks like this:
+
+Recent SATA AHCI link activity statistics
+Active Partial Slumber Device name
+  0.5%  99.5%    0.0%  host0
+
+(work to resolve "host0" to a more human readable name is in progress)
+
+Signed-off-by: Arjan van de Ven <arjan@linux.intel.com>
+
+---
+ drivers/ata/ahci.h    |   15 ++++
+ drivers/ata/libahci.c |  187 +++++++++++++++++++++++++++++++++++++++++++++++++-
+ 2 files changed, 200 insertions(+), 2 deletions(-)
+
+Index: linux-2.6.37/drivers/ata/ahci.h
+===================================================================
+--- linux-2.6.37.orig/drivers/ata/ahci.h
++++ linux-2.6.37/drivers/ata/ahci.h
+@@ -262,6 +262,13 @@ struct ahci_em_priv {
+       unsigned long led_state;
+ };
++enum ahci_port_states {
++      AHCI_PORT_NOLINK = 0,
++      AHCI_PORT_ACTIVE = 1,
++      AHCI_PORT_PARTIAL = 2,
++      AHCI_PORT_SLUMBER = 3
++};
++
+ struct ahci_port_priv {
+       struct ata_link         *active_link;
+       struct ahci_cmd_hdr     *cmd_slot;
+@@ -280,6 +287,14 @@ struct ahci_port_priv {
+       int                     fbs_last_dev;   /* save FBS.DEV of last FIS */
+       /* enclosure management info per PM slot */
+       struct ahci_em_priv     em_priv[EM_MAX_SLOTS];
++
++      /* ALPM accounting state and stats */
++      unsigned int            accounting_active:1;
++      u64                     active_jiffies;
++      u64                     partial_jiffies;
++      u64                     slumber_jiffies;
++      int                     previous_state;
++      int                     previous_jiffies;
+ };
+ struct ahci_host_priv {
+Index: linux-2.6.37/drivers/ata/libahci.c
+===================================================================
+--- linux-2.6.37.orig/drivers/ata/libahci.c
++++ linux-2.6.37/drivers/ata/libahci.c
+@@ -58,6 +58,17 @@ MODULE_PARM_DESC(ignore_sss, "Ignore sta
+ static int ahci_set_lpm(struct ata_link *link, enum ata_lpm_policy policy,
+                       unsigned hints);
++static ssize_t ahci_alpm_show_active(struct device *dev,
++                                struct device_attribute *attr, char *buf);
++static ssize_t ahci_alpm_show_slumber(struct device *dev,
++                                struct device_attribute *attr, char *buf);
++static ssize_t ahci_alpm_show_partial(struct device *dev,
++                                struct device_attribute *attr, char *buf);
++static ssize_t ahci_alpm_show_accounting(struct device *dev,
++                                struct device_attribute *attr, char *buf);
++static ssize_t ahci_alpm_set_accounting(struct device *dev,
++                                struct device_attribute *attr,
++                                const char *buf, size_t count);
+ static ssize_t ahci_led_show(struct ata_port *ap, char *buf);
+ static ssize_t ahci_led_store(struct ata_port *ap, const char *buf,
+                             size_t size);
+@@ -117,6 +128,12 @@ static DEVICE_ATTR(ahci_host_caps, S_IRU
+ static DEVICE_ATTR(ahci_host_cap2, S_IRUGO, ahci_show_host_cap2, NULL);
+ static DEVICE_ATTR(ahci_host_version, S_IRUGO, ahci_show_host_version, NULL);
+ static DEVICE_ATTR(ahci_port_cmd, S_IRUGO, ahci_show_port_cmd, NULL);
++static DEVICE_ATTR(ahci_alpm_active, S_IRUGO, ahci_alpm_show_active, NULL);
++static DEVICE_ATTR(ahci_alpm_partial, S_IRUGO, ahci_alpm_show_partial, NULL);
++static DEVICE_ATTR(ahci_alpm_slumber, S_IRUGO, ahci_alpm_show_slumber, NULL);
++static DEVICE_ATTR(ahci_alpm_accounting, S_IRUGO | S_IWUSR,
++              ahci_alpm_show_accounting, ahci_alpm_set_accounting);
++
+ static DEVICE_ATTR(em_buffer, S_IWUSR | S_IRUGO,
+                  ahci_read_em_buffer, ahci_store_em_buffer);
+@@ -128,6 +145,10 @@ struct device_attribute *ahci_shost_attr
+       &dev_attr_ahci_host_cap2,
+       &dev_attr_ahci_host_version,
+       &dev_attr_ahci_port_cmd,
++      &dev_attr_ahci_alpm_active,
++      &dev_attr_ahci_alpm_partial,
++      &dev_attr_ahci_alpm_slumber,
++      &dev_attr_ahci_alpm_accounting,
+       &dev_attr_em_buffer,
+       NULL
+ };
+@@ -653,9 +674,14 @@ static int ahci_set_lpm(struct ata_link 
+                * Disable interrupts on Phy Ready. This keeps us from
+                * getting woken up due to spurious phy ready
+                * interrupts.
++               *
++               * However, when accounting_active is set, we do want
++               * the interrupts for accounting purposes.
+                */
+-              pp->intr_mask &= ~PORT_IRQ_PHYRDY;
+-              writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
++              if (!pp->accounting_active) {
++                      pp->intr_mask &= ~PORT_IRQ_PHYRDY;
++                      writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
++              }
+               sata_link_scr_lpm(link, policy, false);
+       }
+@@ -1570,6 +1596,162 @@ static void ahci_error_intr(struct ata_p
+               ata_port_abort(ap);
+ }
++static int get_current_alpm_state(struct ata_port *ap)
++{
++      u32 status = 0;
++
++      ahci_scr_read(&ap->link, SCR_STATUS, &status);
++
++      /* link status is in bits 11-8 */
++      status = status >> 8;
++      status = status & 0x7;
++
++      if (status == 6)
++              return AHCI_PORT_SLUMBER;
++      if (status == 2)
++              return AHCI_PORT_PARTIAL;
++      if (status == 1)
++              return AHCI_PORT_ACTIVE;
++      return AHCI_PORT_NOLINK;
++}
++
++static void account_alpm_stats(struct ata_port *ap)
++{
++      struct ahci_port_priv *pp;
++
++      int new_state;
++      u64 new_jiffies, jiffies_delta;
++
++      if (ap == NULL)
++              return;
++      pp = ap->private_data;
++
++      if (!pp) return;
++
++      new_state = get_current_alpm_state(ap);
++      new_jiffies = jiffies;
++
++      jiffies_delta = new_jiffies - pp->previous_jiffies;
++
++      switch (pp->previous_state) {
++      case AHCI_PORT_NOLINK:
++              pp->active_jiffies = 0;
++              pp->partial_jiffies = 0;
++              pp->slumber_jiffies = 0;
++              break;
++      case AHCI_PORT_ACTIVE:
++              pp->active_jiffies += jiffies_delta;
++              break;
++      case AHCI_PORT_PARTIAL:
++              pp->partial_jiffies += jiffies_delta;
++              break;
++      case AHCI_PORT_SLUMBER:
++              pp->slumber_jiffies += jiffies_delta;
++              break;
++      default:
++              break;
++      }
++      pp->previous_state = new_state;
++      pp->previous_jiffies = new_jiffies;
++}
++
++static ssize_t ahci_alpm_show_active(struct device *dev,
++                                 struct device_attribute *attr, char *buf)
++{
++      struct Scsi_Host *shost = class_to_shost(dev);
++      struct ata_port *ap = ata_shost_to_port(shost);
++      struct ahci_port_priv *pp;
++
++      if (!ap || ata_port_is_dummy(ap))
++              return -EINVAL;
++      pp = ap->private_data;
++      account_alpm_stats(ap);
++
++      return sprintf(buf, "%u\n", jiffies_to_msecs(pp->active_jiffies));
++}
++
++static ssize_t ahci_alpm_show_partial(struct device *dev,
++                                 struct device_attribute *attr, char *buf)
++{
++      struct Scsi_Host *shost = class_to_shost(dev);
++      struct ata_port *ap = ata_shost_to_port(shost);
++      struct ahci_port_priv *pp;
++
++      if (!ap || ata_port_is_dummy(ap))
++              return -EINVAL;
++
++      pp = ap->private_data;
++      account_alpm_stats(ap);
++
++      return sprintf(buf, "%u\n", jiffies_to_msecs(pp->partial_jiffies));
++}
++
++static ssize_t ahci_alpm_show_slumber(struct device *dev,
++                                 struct device_attribute *attr, char *buf)
++{
++      struct Scsi_Host *shost = class_to_shost(dev);
++      struct ata_port *ap = ata_shost_to_port(shost);
++      struct ahci_port_priv *pp;
++
++      if (!ap || ata_port_is_dummy(ap))
++              return -EINVAL;
++
++      pp = ap->private_data;
++
++      account_alpm_stats(ap);
++
++      return sprintf(buf, "%u\n", jiffies_to_msecs(pp->slumber_jiffies));
++}
++
++static ssize_t ahci_alpm_show_accounting(struct device *dev,
++                                struct device_attribute *attr, char *buf)
++{
++      struct Scsi_Host *shost = class_to_shost(dev);
++      struct ata_port *ap = ata_shost_to_port(shost);
++      struct ahci_port_priv *pp;
++
++      if (!ap || ata_port_is_dummy(ap))
++              return -EINVAL;
++
++      pp = ap->private_data;
++
++      return sprintf(buf, "%u\n", pp->accounting_active);
++}
++
++static ssize_t ahci_alpm_set_accounting(struct device *dev,
++                                struct device_attribute *attr,
++                                const char *buf, size_t count)
++{
++      unsigned long flags;
++      struct Scsi_Host *shost = class_to_shost(dev);
++      struct ata_port *ap = ata_shost_to_port(shost);
++      struct ahci_port_priv *pp;
++      void __iomem *port_mmio;
++
++      if (!ap || ata_port_is_dummy(ap))
++              return 1;
++
++      pp = ap->private_data;
++      port_mmio = ahci_port_base(ap);
++
++      if (!pp)
++              return 1;
++      if (buf[0] == '0')
++              pp->accounting_active = 0;
++      if (buf[0] == '1')
++              pp->accounting_active = 1;
++
++      /* we need to enable the PHYRDY interrupt when we want accounting */
++      if (pp->accounting_active) {
++              spin_lock_irqsave(ap->lock, flags);
++              pp->intr_mask |= PORT_IRQ_PHYRDY;
++              writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
++              spin_unlock_irqrestore(ap->lock, flags);
++      }
++      return count;
++}
++
++
+ static void ahci_port_intr(struct ata_port *ap)
+ {
+       void __iomem *port_mmio = ahci_port_base(ap);
+@@ -1590,6 +1772,7 @@ static void ahci_port_intr(struct ata_po
+       /* if LPM is enabled, PHYRDY doesn't mean anything */
+       if (ap->link.lpm_policy > ATA_LPM_MAX_POWER) {
+               status &= ~PORT_IRQ_PHYRDY;
++              account_alpm_stats(ap);
+               ahci_scr_write(&ap->link, SCR_ERROR, SERR_PHYRDY_CHG);
+       }
diff --git a/patches/linux-2.6.37-vfs-dirty-inode.patch b/patches/linux-2.6.37-vfs-dirty-inode.patch
new file mode 100644 (file)
index 0000000..c218291
--- /dev/null
@@ -0,0 +1,102 @@
+From 3950d3c04a6bf8ccf9ff912a49bdd242a2fe9e47 Mon Sep 17 00:00:00 2001
+From: Arjan van de Ven <arjan@linux.intel.com>
+Date: Fri, 26 Nov 2010 12:18:03 -0800
+Subject: [PATCH] vfs: Add a trace point in the mark_inode_dirty function
+
+PowerTOP would like to be able to show who is keeping the disk
+busy by dirtying data. The most logical spot for this is in the vfs
+in the mark_inode_dirty() function, doing this on the block level
+is not possible because by the time the IO hits the block layer the
+guilty party can no longer be found ("kjournald" and "pdflush" are not
+useful answers to "who caused this file to be dirty).
+
+The trace point follows the same logic/style as the block_dump code
+and pretty much dumps the same data, just not to dmesg (and thus to
+/var/log/messages) but via the trace events streams.
+
+Eventually we should be able to phase out the block dump code, but that's
+for later on after a transition time.
+
+Signed-of-by: Arjan van de Ven <arjan@linux.intel.com>
+---
+ fs/fs-writeback.c                |    3 +++
+ include/linux/fs.h               |   12 ++++++++++++
+ include/trace/events/writeback.h |   28 ++++++++++++++++++++++++++++
+ 3 files changed, 43 insertions(+)
+
+Index: linux-2.6.37/fs/fs-writeback.c
+===================================================================
+--- linux-2.6.37.orig/fs/fs-writeback.c
++++ linux-2.6.37/fs/fs-writeback.c
+@@ -952,6 +952,9 @@ void __mark_inode_dirty(struct inode *in
+       if ((inode->i_state & flags) == flags)
+               return;
++      if (flags & (I_DIRTY_SYNC | I_DIRTY_DATASYNC | I_DIRTY_PAGES))
++              trace_writeback_inode_dirty(inode, flags);
++
+       if (unlikely(block_dump))
+               block_dump___mark_inode_dirty(inode);
+Index: linux-2.6.37/include/linux/fs.h
+===================================================================
+--- linux-2.6.37.orig/include/linux/fs.h
++++ linux-2.6.37/include/linux/fs.h
+@@ -1677,6 +1677,18 @@ struct super_operations {
+ #define I_DIRTY (I_DIRTY_SYNC | I_DIRTY_DATASYNC | I_DIRTY_PAGES)
++#define INODE_DIRTY_FLAGS \
++      { I_DIRTY_SYNC,         "DIRTY-SYNC" }, \
++      { I_DIRTY_DATASYNC,     "DIRTY-DATASYNC" }, \
++      { I_DIRTY_PAGES,        "DIRTY-PAGES" }, \
++      { I_NEW,                "NEW" }, \
++      { I_WILL_FREE,          "WILL-FREE" }, \
++      { I_FREEING,            "FREEING" }, \
++      { I_CLEAR,              "CLEAR" }, \
++      { I_SYNC,               "SYNC" }, \
++      { I_REFERENCED,         "REFERENCED" }
++
++
+ extern void __mark_inode_dirty(struct inode *, int);
+ static inline void mark_inode_dirty(struct inode *inode)
+ {
+Index: linux-2.6.37/include/trace/events/writeback.h
+===================================================================
+--- linux-2.6.37.orig/include/trace/events/writeback.h
++++ linux-2.6.37/include/trace/events/writeback.h
+@@ -186,6 +186,34 @@ DEFINE_EVENT(writeback_congest_waited_te
+       TP_ARGS(usec_timeout, usec_delayed)
+ );
++/*
++ * Tracepoint for dirtying an inode; used by PowerTOP
++ */
++TRACE_EVENT(writeback_inode_dirty,
++
++      TP_PROTO(struct inode *inode, int flags),
++
++      TP_ARGS(inode, flags),
++
++      TP_STRUCT__entry(
++              __field(        __kernel_dev_t, dev             )
++              __field(        ino_t,          ino             )
++              __field(        u32,            flags           )
++      ),
++
++      TP_fast_assign(
++              __entry->dev    = inode->i_sb->s_dev;
++              __entry->ino    = inode->i_ino;
++              __entry->flags  = flags;
++      ),
++
++      TP_printk("dev %d:%d ino %lu flags %d %s", MAJOR(__entry->dev), MINOR(__entry->dev),
++                (unsigned long) __entry->ino,
++                __entry->flags,
++                __print_flags(__entry->flags, "|", INODE_DIRTY_FLAGS)
++      )
++);
++
+ #endif /* _TRACE_WRITEBACK_H */
+ /* This part must be outside protection */
diff --git a/patches/linux-3.3.0-ahci-alpm-accounting.patch b/patches/linux-3.3.0-ahci-alpm-accounting.patch
new file mode 100644 (file)
index 0000000..8b2f892
--- /dev/null
@@ -0,0 +1,307 @@
+From 3d1f00627a8db9d71091db32cd8109962f69ec43 Mon Sep 17 00:00:00 2001
+From: Arjan van de Ven <arjan at linux.intel.com>
+Date: Sat, 31 Mar 2012 20:35:12 +0200
+Subject: [PATCH 2/2] libata: Add ALPM power state accounting to the AHCI
+ driver
+
+PowerTOP wants to be able to show the user how effective the ALPM link
+power management is for the user. ALPM is worth around 0.5W on a quiet
+link; PowerTOP wants to be able to find cases where the "quiet link" isn't
+actually quiet.
+
+This patch adds state accounting functionality to the AHCI driver for
+PowerTOP to use.
+The parts of the patch are
+1) the sysfs logic of exposing the stats for each state in sysfs
+2) the basic accounting logic that gets update on link change interrupts
+   (or when the user accesses the info from sysfs)
+3) a "accounting enable" flag; in order to get the accounting to work,
+   the driver needs to get phyrdy interrupts on link status changes.
+   Normally and currently this is disabled by the driver when ALPM is
+   on (to reduce overhead); when PowerTOP is running this will need
+   to be on to get usable statistics... hence the sysfs tunable.
+
+The PowerTOP output currently looks like this:
+
+Recent SATA AHCI link activity statistics
+Active Partial Slumber Device name
+  0.5%  99.5%    0.0%  host0
+
+(work to resolve "host0" to a more human readable name is in progress)
+
+Signed-off-by: Arjan van de Ven <arjan at linux.intel.com>
+---
+ drivers/ata/ahci.h    |   15 ++++
+ drivers/ata/libahci.c |  187 ++++++++++++++++++++++++++++++++++++++++++++++++-
+ 2 files changed, 200 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h
+index b175000..38297f9 100644
+--- a/drivers/ata/ahci.h
++++ b/drivers/ata/ahci.h
+@@ -264,6 +264,13 @@ struct ahci_em_priv {
+       unsigned long led_state;
+ };
++enum ahci_port_states {
++      AHCI_PORT_NOLINK = 0,
++      AHCI_PORT_ACTIVE = 1,
++      AHCI_PORT_PARTIAL = 2,
++      AHCI_PORT_SLUMBER = 3
++};
++
+ struct ahci_port_priv {
+       struct ata_link         *active_link;
+       struct ahci_cmd_hdr     *cmd_slot;
+@@ -282,6 +289,14 @@ struct ahci_port_priv {
+       int                     fbs_last_dev;   /* save FBS.DEV of last FIS */
+       /* enclosure management info per PM slot */
+       struct ahci_em_priv     em_priv[EM_MAX_SLOTS];
++
++      /* ALPM accounting state and stats */
++      unsigned int            accounting_active:1;
++      u64                     active_jiffies;
++      u64                     partial_jiffies;
++      u64                     slumber_jiffies;
++      int                     previous_state;
++      int                     previous_jiffies;
+ };
+ struct ahci_host_priv {
+diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c
+index a72bfd0..5859215 100644
+--- a/drivers/ata/libahci.c
++++ b/drivers/ata/libahci.c
+@@ -58,6 +58,17 @@ MODULE_PARM_DESC(ignore_sss, "Ignore staggered spinup flag (0=don't ignore, 1=ig
+ static int ahci_set_lpm(struct ata_link *link, enum ata_lpm_policy policy,
+                       unsigned hints);
++static ssize_t ahci_alpm_show_active(struct device *dev,
++                                struct device_attribute *attr, char *buf);
++static ssize_t ahci_alpm_show_slumber(struct device *dev,
++                                struct device_attribute *attr, char *buf);
++static ssize_t ahci_alpm_show_partial(struct device *dev,
++                                struct device_attribute *attr, char *buf);
++static ssize_t ahci_alpm_show_accounting(struct device *dev,
++                                struct device_attribute *attr, char *buf);
++static ssize_t ahci_alpm_set_accounting(struct device *dev,
++                                struct device_attribute *attr,
++                                const char *buf, size_t count);
+ static ssize_t ahci_led_show(struct ata_port *ap, char *buf);
+ static ssize_t ahci_led_store(struct ata_port *ap, const char *buf,
+                             size_t size);
+@@ -118,6 +129,12 @@ static DEVICE_ATTR(ahci_host_caps, S_IRUGO, ahci_show_host_caps, NULL);
+ static DEVICE_ATTR(ahci_host_cap2, S_IRUGO, ahci_show_host_cap2, NULL);
+ static DEVICE_ATTR(ahci_host_version, S_IRUGO, ahci_show_host_version, NULL);
+ static DEVICE_ATTR(ahci_port_cmd, S_IRUGO, ahci_show_port_cmd, NULL);
++static DEVICE_ATTR(ahci_alpm_active, S_IRUGO, ahci_alpm_show_active, NULL);
++static DEVICE_ATTR(ahci_alpm_partial, S_IRUGO, ahci_alpm_show_partial, NULL);
++static DEVICE_ATTR(ahci_alpm_slumber, S_IRUGO, ahci_alpm_show_slumber, NULL);
++static DEVICE_ATTR(ahci_alpm_accounting, S_IRUGO | S_IWUSR,
++              ahci_alpm_show_accounting, ahci_alpm_set_accounting);
++
+ static DEVICE_ATTR(em_buffer, S_IWUSR | S_IRUGO,
+                  ahci_read_em_buffer, ahci_store_em_buffer);
+ static DEVICE_ATTR(em_message_supported, S_IRUGO, ahci_show_em_supported, NULL);
+@@ -130,6 +147,10 @@ struct device_attribute *ahci_shost_attrs[] = {
+       &dev_attr_ahci_host_cap2,
+       &dev_attr_ahci_host_version,
+       &dev_attr_ahci_port_cmd,
++      &dev_attr_ahci_alpm_active,
++      &dev_attr_ahci_alpm_partial,
++      &dev_attr_ahci_alpm_slumber,
++      &dev_attr_ahci_alpm_accounting,
+       &dev_attr_em_buffer,
+       &dev_attr_em_message_supported,
+       NULL
+@@ -673,9 +694,14 @@ static int ahci_set_lpm(struct ata_link *link, enum ata_lpm_policy policy,
+                * Disable interrupts on Phy Ready. This keeps us from
+                * getting woken up due to spurious phy ready
+                * interrupts.
++               *
++               * However, when accounting_active is set, we do want
++               * the interrupts for accounting purposes.
+                */
+-              pp->intr_mask &= ~PORT_IRQ_PHYRDY;
+-              writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
++              if (!pp->accounting_active) {
++                      pp->intr_mask &= ~PORT_IRQ_PHYRDY;
++                      writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
++              }
+               sata_link_scr_lpm(link, policy, false);
+       }
+@@ -1633,6 +1659,162 @@ static void ahci_error_intr(struct ata_port *ap, u32 irq_stat)
+               ata_port_abort(ap);
+ }
++static int get_current_alpm_state(struct ata_port *ap)
++{
++      u32 status = 0;
++
++      ahci_scr_read(&ap->link, SCR_STATUS, &status);
++
++      /* link status is in bits 11-8 */
++      status = status >> 8;
++      status = status & 0x7;
++
++      if (status == 6)
++              return AHCI_PORT_SLUMBER;
++      if (status == 2)
++              return AHCI_PORT_PARTIAL;
++      if (status == 1)
++              return AHCI_PORT_ACTIVE;
++      return AHCI_PORT_NOLINK;
++}
++
++static void account_alpm_stats(struct ata_port *ap)
++{
++      struct ahci_port_priv *pp;
++
++      int new_state;
++      u64 new_jiffies, jiffies_delta;
++
++      if (ap == NULL)
++              return;
++      pp = ap->private_data;
++
++      if (!pp) return;
++
++      new_state = get_current_alpm_state(ap);
++      new_jiffies = jiffies;
++
++      jiffies_delta = new_jiffies - pp->previous_jiffies;
++
++      switch (pp->previous_state) {
++      case AHCI_PORT_NOLINK:
++              pp->active_jiffies = 0;
++              pp->partial_jiffies = 0;
++              pp->slumber_jiffies = 0;
++              break;
++      case AHCI_PORT_ACTIVE:
++              pp->active_jiffies += jiffies_delta;
++              break;
++      case AHCI_PORT_PARTIAL:
++              pp->partial_jiffies += jiffies_delta;
++              break;
++      case AHCI_PORT_SLUMBER:
++              pp->slumber_jiffies += jiffies_delta;
++              break;
++      default:
++              break;
++      }
++      pp->previous_state = new_state;
++      pp->previous_jiffies = new_jiffies;
++}
++
++static ssize_t ahci_alpm_show_active(struct device *dev,
++                                 struct device_attribute *attr, char *buf)
++{
++      struct Scsi_Host *shost = class_to_shost(dev);
++      struct ata_port *ap = ata_shost_to_port(shost);
++      struct ahci_port_priv *pp;
++
++      if (!ap || ata_port_is_dummy(ap))
++              return -EINVAL;
++      pp = ap->private_data;
++      account_alpm_stats(ap);
++
++      return sprintf(buf, "%u\n", jiffies_to_msecs(pp->active_jiffies));
++}
++
++static ssize_t ahci_alpm_show_partial(struct device *dev,
++                                 struct device_attribute *attr, char *buf)
++{
++      struct Scsi_Host *shost = class_to_shost(dev);
++      struct ata_port *ap = ata_shost_to_port(shost);
++      struct ahci_port_priv *pp;
++
++      if (!ap || ata_port_is_dummy(ap))
++              return -EINVAL;
++
++      pp = ap->private_data;
++      account_alpm_stats(ap);
++
++      return sprintf(buf, "%u\n", jiffies_to_msecs(pp->partial_jiffies));
++}
++
++static ssize_t ahci_alpm_show_slumber(struct device *dev,
++                                 struct device_attribute *attr, char *buf)
++{
++      struct Scsi_Host *shost = class_to_shost(dev);
++      struct ata_port *ap = ata_shost_to_port(shost);
++      struct ahci_port_priv *pp;
++
++      if (!ap || ata_port_is_dummy(ap))
++              return -EINVAL;
++
++      pp = ap->private_data;
++
++      account_alpm_stats(ap);
++
++      return sprintf(buf, "%u\n", jiffies_to_msecs(pp->slumber_jiffies));
++}
++
++static ssize_t ahci_alpm_show_accounting(struct device *dev,
++                                struct device_attribute *attr, char *buf)
++{
++      struct Scsi_Host *shost = class_to_shost(dev);
++      struct ata_port *ap = ata_shost_to_port(shost);
++      struct ahci_port_priv *pp;
++
++      if (!ap || ata_port_is_dummy(ap))
++              return -EINVAL;
++
++      pp = ap->private_data;
++
++      return sprintf(buf, "%u\n", pp->accounting_active);
++}
++
++static ssize_t ahci_alpm_set_accounting(struct device *dev,
++                                struct device_attribute *attr,
++                                const char *buf, size_t count)
++{
++      unsigned long flags;
++      struct Scsi_Host *shost = class_to_shost(dev);
++      struct ata_port *ap = ata_shost_to_port(shost);
++      struct ahci_port_priv *pp;
++      void __iomem *port_mmio;
++
++      if (!ap || ata_port_is_dummy(ap))
++              return 1;
++
++      pp = ap->private_data;
++      port_mmio = ahci_port_base(ap);
++
++      if (!pp)
++              return 1;
++      if (buf[0] == '0')
++              pp->accounting_active = 0;
++      if (buf[0] == '1')
++              pp->accounting_active = 1;
++
++      /* we need to enable the PHYRDY interrupt when we want accounting */
++      if (pp->accounting_active) {
++              spin_lock_irqsave(ap->lock, flags);
++              pp->intr_mask |= PORT_IRQ_PHYRDY;
++              writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
++              spin_unlock_irqrestore(ap->lock, flags);
++      }
++      return count;
++}
++
++
+ static void ahci_port_intr(struct ata_port *ap)
+ {
+       void __iomem *port_mmio = ahci_port_base(ap);
+@@ -1653,6 +1835,7 @@ static void ahci_port_intr(struct ata_port *ap)
+       /* if LPM is enabled, PHYRDY doesn't mean anything */
+       if (ap->link.lpm_policy > ATA_LPM_MAX_POWER) {
+               status &= ~PORT_IRQ_PHYRDY;
++              account_alpm_stats(ap);
+               ahci_scr_write(&ap->link, SCR_ERROR, SERR_PHYRDY_CHG);
+       }
+-- 
+1.7.8.5
+
diff --git a/patches/linux-3.3.0-vfs-dirty-inode.patch b/patches/linux-3.3.0-vfs-dirty-inode.patch
new file mode 100644 (file)
index 0000000..4177093
--- /dev/null
@@ -0,0 +1,103 @@
+From 9f7c5d04fdee46dbe715f2758152bb1664d4259c Mon Sep 17 00:00:00 2001
+From: Arjan van de Ven <arjan at linux.intel.com>
+Date: Fri, 26 Nov 2010 12:18:03 -0800
+Subject: [PATCH 1/2] vfs: Add a trace point in the mark_inode_dirty function
+
+PowerTOP would like to be able to show who is keeping the disk
+busy by dirtying data. The most logical spot for this is in the vfs
+in the mark_inode_dirty() function, doing this on the block level
+is not possible because by the time the IO hits the block layer the
+guilty party can no longer be found ("kjournald" and "pdflush" are not
+useful answers to "who caused this file to be dirty).
+
+The trace point follows the same logic/style as the block_dump code
+and pretty much dumps the same data, just not to dmesg (and thus to
+/var/log/messages) but via the trace events streams.
+
+Eventually we should be able to phase out the block dump code, but that's
+for later on after a transition time.
+---
+ fs/fs-writeback.c                |    3 +++
+ include/linux/fs.h               |   11 +++++++++++
+ include/trace/events/writeback.h |   28 ++++++++++++++++++++++++++++
+ 3 files changed, 42 insertions(+), 0 deletions(-)
+
+diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c
+index 5b4a936..5ef5bb0 100644
+--- a/fs/fs-writeback.c
++++ b/fs/fs-writeback.c
+@@ -1081,6 +1081,9 @@ void __mark_inode_dirty(struct inode *inode, int flags)
+       if ((inode->i_state & flags) == flags)
+               return;
++      if (flags & (I_DIRTY_SYNC | I_DIRTY_DATASYNC | I_DIRTY_PAGES))
++              trace_writeback_inode_dirty(inode, flags);
++
+       if (unlikely(block_dump))
+               block_dump___mark_inode_dirty(inode);
+diff --git a/include/linux/fs.h b/include/linux/fs.h
+index 69cd5bb..e0ac37c 100644
+--- a/include/linux/fs.h
++++ b/include/linux/fs.h
+@@ -1768,6 +1768,18 @@ struct super_operations {
+ #define I_DIRTY (I_DIRTY_SYNC | I_DIRTY_DATASYNC | I_DIRTY_PAGES)
++#define INODE_DIRTY_FLAGS \
++      { I_DIRTY_SYNC,         "DIRTY-SYNC" }, \
++      { I_DIRTY_DATASYNC,     "DIRTY-DATASYNC" }, \
++      { I_DIRTY_PAGES,        "DIRTY-PAGES" }, \
++      { I_NEW,                "NEW" }, \
++      { I_WILL_FREE,          "WILL-FREE" }, \
++      { I_FREEING,            "FREEING" }, \
++      { I_CLEAR,              "CLEAR" }, \
++      { I_SYNC,               "SYNC" }, \
++      { I_REFERENCED,         "REFERENCED" }
++
++
+ extern void __mark_inode_dirty(struct inode *, int);
+ static inline void mark_inode_dirty(struct inode *inode)
+ {
+diff --git a/include/trace/events/writeback.h b/include/trace/events/writeback.h
+index 5973410..5f1e2a3 100644
+--- a/include/trace/events/writeback.h
++++ b/include/trace/events/writeback.h
+@@ -408,6 +408,34 @@ DEFINE_EVENT(writeback_congest_waited_template, writeback_wait_iff_congested,
+       TP_ARGS(usec_timeout, usec_delayed)
+ );
++/*
++ * Tracepoint for dirtying an inode; used by PowerTOP
++ */
++TRACE_EVENT(writeback_inode_dirty,
++
++      TP_PROTO(struct inode *inode, int flags),
++
++      TP_ARGS(inode, flags),
++
++      TP_STRUCT__entry(
++              __field(        __kernel_dev_t, dev             )
++              __field(        ino_t,          ino             )
++              __field(        u32,            flags           )
++      ),
++
++      TP_fast_assign(
++              __entry->dev    = inode->i_sb->s_dev;
++              __entry->ino    = inode->i_ino;
++              __entry->flags  = flags;
++      ),
++
++      TP_printk("dev %d:%d ino %lu flags %d %s", MAJOR(__entry->dev), MINOR(__entry->dev),
++                (unsigned long) __entry->ino,
++                __entry->flags,
++                __print_flags(__entry->flags, "|", INODE_DIRTY_FLAGS)
++      )
++);
++
+ DECLARE_EVENT_CLASS(writeback_single_inode_template,
+       TP_PROTO(struct inode *inode,
+-- 
+1.7.8.5
+
diff --git a/po/.tx/config b/po/.tx/config
new file mode 100644 (file)
index 0000000..479780a
--- /dev/null
@@ -0,0 +1,6 @@
+[main]
+host = https://www.transifex.net
+[PowerTOP.powertop-devel]
+file_filter=<lang>.po
+source_lang=en
+
diff --git a/po/LINGUAS b/po/LINGUAS
new file mode 100644 (file)
index 0000000..5939602
--- /dev/null
@@ -0,0 +1,11 @@
+# set of available languages
+ca
+cs_CZ
+de_DE
+en_GB
+en_US
+es_ES
+hu_HU
+id_ID
+nl_NL
+zh_TW
diff --git a/po/Makefile.in.in b/po/Makefile.in.in
new file mode 100644 (file)
index 0000000..83d8838
--- /dev/null
@@ -0,0 +1,444 @@
+# Makefile for PO directory in any package using GNU gettext.
+# Copyright (C) 1995-1997, 2000-2007, 2009-2010 by Ulrich Drepper <drepper@gnu.ai.mit.edu>
+#
+# This file can be copied and used freely without restrictions.  It can
+# be used in projects which are not available under the GNU General Public
+# License but which still want to provide support for the GNU gettext
+# functionality.
+# Please note that the actual code of GNU gettext is covered by the GNU
+# General Public License and is *not* in the public domain.
+#
+# Origin: gettext-0.18
+GETTEXT_MACRO_VERSION = 0.18
+
+PACKAGE = @PACKAGE@
+VERSION = @VERSION@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+
+SHELL = /bin/sh
+@SET_MAKE@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+datarootdir = @datarootdir@
+datadir = @datadir@
+localedir = @localedir@
+gettextsrcdir = $(datadir)/gettext/po
+
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+
+# We use $(mkdir_p).
+# In automake <= 1.9.x, $(mkdir_p) is defined either as "mkdir -p --" or as
+# "$(mkinstalldirs)" or as "$(install_sh) -d". For these automake versions,
+# @install_sh@ does not start with $(SHELL), so we add it.
+# In automake >= 1.10, @mkdir_p@ is derived from ${MKDIR_P}, which is defined
+# either as "/path/to/mkdir -p" or ".../install-sh -c -d". For these automake
+# versions, $(mkinstalldirs) and $(install_sh) are unused.
+mkinstalldirs = $(SHELL) @install_sh@ -d
+install_sh = $(SHELL) @install_sh@
+MKDIR_P = @MKDIR_P@
+mkdir_p = @mkdir_p@
+
+GMSGFMT_ = @GMSGFMT@
+GMSGFMT_no = @GMSGFMT@
+GMSGFMT_yes = @GMSGFMT_015@
+GMSGFMT = $(GMSGFMT_$(USE_MSGCTXT))
+MSGFMT_ = @MSGFMT@
+MSGFMT_no = @MSGFMT@
+MSGFMT_yes = @MSGFMT_015@
+MSGFMT = $(MSGFMT_$(USE_MSGCTXT))
+XGETTEXT_ = @XGETTEXT@
+XGETTEXT_no = @XGETTEXT@
+XGETTEXT_yes = @XGETTEXT_015@
+XGETTEXT = $(XGETTEXT_$(USE_MSGCTXT))
+MSGMERGE = msgmerge
+MSGMERGE_UPDATE = @MSGMERGE@ --update
+MSGINIT = msginit
+MSGCONV = msgconv
+MSGFILTER = msgfilter
+
+POFILES = @POFILES@
+GMOFILES = @GMOFILES@
+UPDATEPOFILES = @UPDATEPOFILES@
+DUMMYPOFILES = @DUMMYPOFILES@
+DISTFILES.common = Makefile.in.in remove-potcdate.sin \
+$(DISTFILES.common.extra1) $(DISTFILES.common.extra2) $(DISTFILES.common.extra3)
+DISTFILES = $(DISTFILES.common) Makevars POTFILES.in \
+$(POFILES) $(GMOFILES) \
+$(DISTFILES.extra1) $(DISTFILES.extra2) $(DISTFILES.extra3)
+
+POTFILES = \
+
+CATALOGS = @CATALOGS@
+
+# Makevars gets inserted here. (Don't remove this line!)
+
+.SUFFIXES:
+.SUFFIXES: .po .gmo .mo .sed .sin .nop .po-create .po-update
+
+.po.mo:
+       @echo "$(MSGFMT) -c -o $@ $<"; \
+       $(MSGFMT) -c -o t-$@ $< && mv t-$@ $@
+
+.po.gmo:
+       @lang=`echo $* | sed -e 's,.*/,,'`; \
+       test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \
+       echo "$${cdcmd}rm -f $${lang}.gmo && $(GMSGFMT) -c --statistics --verbose -o $${lang}.gmo $${lang}.po"; \
+       cd $(srcdir) && rm -f $${lang}.gmo && $(GMSGFMT) -c --statistics --verbose -o t-$${lang}.gmo $${lang}.po && mv t-$${lang}.gmo $${lang}.gmo
+
+.sin.sed:
+       sed -e '/^#/d' $< > t-$@
+       mv t-$@ $@
+
+
+all: check-macro-version all-@USE_NLS@
+
+all-yes: stamp-po
+all-no:
+
+# Ensure that the gettext macros and this Makefile.in.in are in sync.
+check-macro-version:
+       @test "$(GETTEXT_MACRO_VERSION)" = "@GETTEXT_MACRO_VERSION@" \
+         || { echo "*** error: gettext infrastructure mismatch: using a Makefile.in.in from gettext version $(GETTEXT_MACRO_VERSION) but the autoconf macros are from gettext version @GETTEXT_MACRO_VERSION@" 1>&2; \
+              exit 1; \
+            }
+
+# $(srcdir)/$(DOMAIN).pot is only created when needed. When xgettext finds no
+# internationalized messages, no $(srcdir)/$(DOMAIN).pot is created (because
+# we don't want to bother translators with empty POT files). We assume that
+# LINGUAS is empty in this case, i.e. $(POFILES) and $(GMOFILES) are empty.
+# In this case, stamp-po is a nop (i.e. a phony target).
+
+# stamp-po is a timestamp denoting the last time at which the CATALOGS have
+# been loosely updated. Its purpose is that when a developer or translator
+# checks out the package via CVS, and the $(DOMAIN).pot file is not in CVS,
+# "make" will update the $(DOMAIN).pot and the $(CATALOGS), but subsequent
+# invocations of "make" will do nothing. This timestamp would not be necessary
+# if updating the $(CATALOGS) would always touch them; however, the rule for
+# $(POFILES) has been designed to not touch files that don't need to be
+# changed.
+stamp-po: $(srcdir)/$(DOMAIN).pot
+       test ! -f $(srcdir)/$(DOMAIN).pot || \
+         test -z "$(GMOFILES)" || $(MAKE) $(GMOFILES)
+       @test ! -f $(srcdir)/$(DOMAIN).pot || { \
+         echo "touch stamp-po" && \
+         echo timestamp > stamp-poT && \
+         mv stamp-poT stamp-po; \
+       }
+
+# Note: Target 'all' must not depend on target '$(DOMAIN).pot-update',
+# otherwise packages like GCC can not be built if only parts of the source
+# have been downloaded.
+
+# This target rebuilds $(DOMAIN).pot; it is an expensive operation.
+# Note that $(DOMAIN).pot is not touched if it doesn't need to be changed.
+$(DOMAIN).pot-update: $(POTFILES) $(srcdir)/POTFILES.in remove-potcdate.sed
+       if LC_ALL=C grep 'GNU @PACKAGE@' $(top_srcdir)/* 2>/dev/null | grep -v 'libtool:' >/dev/null; then \
+         package_gnu='GNU '; \
+       else \
+         package_gnu=''; \
+       fi; \
+       if test -n '$(MSGID_BUGS_ADDRESS)' || test '$(PACKAGE_BUGREPORT)' = '@'PACKAGE_BUGREPORT'@'; then \
+         msgid_bugs_address='$(MSGID_BUGS_ADDRESS)'; \
+       else \
+         msgid_bugs_address='$(PACKAGE_BUGREPORT)'; \
+       fi; \
+       case `$(XGETTEXT) --version | sed 1q | sed -e 's,^[^0-9]*,,'` in \
+         '' | 0.[0-9] | 0.[0-9].* | 0.1[0-5] | 0.1[0-5].* | 0.16 | 0.16.[0-1]*) \
+           $(XGETTEXT) --default-domain=$(DOMAIN) --directory=$(top_srcdir) \
+             --add-comments=TRANSLATORS: $(XGETTEXT_OPTIONS) @XGETTEXT_EXTRA_OPTIONS@ \
+             --files-from=$(srcdir)/POTFILES.in \
+             --copyright-holder='$(COPYRIGHT_HOLDER)' \
+             --msgid-bugs-address="$$msgid_bugs_address" \
+           ;; \
+         *) \
+           $(XGETTEXT) --default-domain=$(DOMAIN) --directory=$(top_srcdir) \
+             --add-comments=TRANSLATORS: $(XGETTEXT_OPTIONS) @XGETTEXT_EXTRA_OPTIONS@ \
+             --files-from=$(srcdir)/POTFILES.in \
+             --copyright-holder='$(COPYRIGHT_HOLDER)' \
+             --package-name="$${package_gnu}@PACKAGE@" \
+             --package-version='@VERSION@' \
+             --msgid-bugs-address="$$msgid_bugs_address" \
+           ;; \
+       esac
+       test ! -f $(DOMAIN).po || { \
+         if test -f $(srcdir)/$(DOMAIN).pot; then \
+           sed -f remove-potcdate.sed < $(srcdir)/$(DOMAIN).pot > $(DOMAIN).1po && \
+           sed -f remove-potcdate.sed < $(DOMAIN).po > $(DOMAIN).2po && \
+           if cmp $(DOMAIN).1po $(DOMAIN).2po >/dev/null 2>&1; then \
+             rm -f $(DOMAIN).1po $(DOMAIN).2po $(DOMAIN).po; \
+           else \
+             rm -f $(DOMAIN).1po $(DOMAIN).2po $(srcdir)/$(DOMAIN).pot && \
+             mv $(DOMAIN).po $(srcdir)/$(DOMAIN).pot; \
+           fi; \
+         else \
+           mv $(DOMAIN).po $(srcdir)/$(DOMAIN).pot; \
+         fi; \
+       }
+
+# This rule has no dependencies: we don't need to update $(DOMAIN).pot at
+# every "make" invocation, only create it when it is missing.
+# Only "make $(DOMAIN).pot-update" or "make dist" will force an update.
+$(srcdir)/$(DOMAIN).pot:
+       $(MAKE) $(DOMAIN).pot-update
+
+# This target rebuilds a PO file if $(DOMAIN).pot has changed.
+# Note that a PO file is not touched if it doesn't need to be changed.
+$(POFILES): $(srcdir)/$(DOMAIN).pot
+       @lang=`echo $@ | sed -e 's,.*/,,' -e 's/\.po$$//'`; \
+       if test -f "$(srcdir)/$${lang}.po"; then \
+         test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \
+         echo "$${cdcmd}$(MSGMERGE_UPDATE) $(MSGMERGE_OPTIONS) --lang=$${lang} $${lang}.po $(DOMAIN).pot"; \
+         cd $(srcdir) \
+           && { case `$(MSGMERGE_UPDATE) --version | sed 1q | sed -e 's,^[^0-9]*,,'` in \
+                  '' | 0.[0-9] | 0.[0-9].* | 0.1[0-7] | 0.1[0-7].*) \
+                    $(MSGMERGE_UPDATE) $(MSGMERGE_OPTIONS) $${lang}.po $(DOMAIN).pot;; \
+                  *) \
+                    $(MSGMERGE_UPDATE) $(MSGMERGE_OPTIONS) --lang=$${lang} $${lang}.po $(DOMAIN).pot;; \
+                esac; \
+              }; \
+       else \
+         $(MAKE) $${lang}.po-create; \
+       fi
+
+
+install: install-exec install-data
+install-exec:
+install-data: install-data-@USE_NLS@
+       if test "$(PACKAGE)" = "gettext-tools"; then \
+         $(mkdir_p) $(DESTDIR)$(gettextsrcdir); \
+         for file in $(DISTFILES.common) Makevars.template; do \
+           $(INSTALL_DATA) $(srcdir)/$$file \
+                           $(DESTDIR)$(gettextsrcdir)/$$file; \
+         done; \
+         for file in Makevars; do \
+           rm -f $(DESTDIR)$(gettextsrcdir)/$$file; \
+         done; \
+       else \
+         : ; \
+       fi
+install-data-no: all
+install-data-yes: all
+       @catalogs='$(CATALOGS)'; \
+       for cat in $$catalogs; do \
+         cat=`basename $$cat`; \
+         lang=`echo $$cat | sed -e 's/\.gmo$$//'`; \
+         dir=$(localedir)/$$lang/LC_MESSAGES; \
+         $(mkdir_p) $(DESTDIR)$$dir; \
+         if test -r $$cat; then realcat=$$cat; else realcat=$(srcdir)/$$cat; fi; \
+         $(INSTALL_DATA) $$realcat $(DESTDIR)$$dir/$(DOMAIN).mo; \
+         echo "installing $$realcat as $(DESTDIR)$$dir/$(DOMAIN).mo"; \
+         for lc in '' $(EXTRA_LOCALE_CATEGORIES); do \
+           if test -n "$$lc"; then \
+             if (cd $(DESTDIR)$(localedir)/$$lang && LC_ALL=C ls -l -d $$lc 2>/dev/null) | grep ' -> ' >/dev/null; then \
+               link=`cd $(DESTDIR)$(localedir)/$$lang && LC_ALL=C ls -l -d $$lc | sed -e 's/^.* -> //'`; \
+               mv $(DESTDIR)$(localedir)/$$lang/$$lc $(DESTDIR)$(localedir)/$$lang/$$lc.old; \
+               mkdir $(DESTDIR)$(localedir)/$$lang/$$lc; \
+               (cd $(DESTDIR)$(localedir)/$$lang/$$lc.old && \
+                for file in *; do \
+                  if test -f $$file; then \
+                    ln -s ../$$link/$$file $(DESTDIR)$(localedir)/$$lang/$$lc/$$file; \
+                  fi; \
+                done); \
+               rm -f $(DESTDIR)$(localedir)/$$lang/$$lc.old; \
+             else \
+               if test -d $(DESTDIR)$(localedir)/$$lang/$$lc; then \
+                 :; \
+               else \
+                 rm -f $(DESTDIR)$(localedir)/$$lang/$$lc; \
+                 mkdir $(DESTDIR)$(localedir)/$$lang/$$lc; \
+               fi; \
+             fi; \
+             rm -f $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo; \
+             ln -s ../LC_MESSAGES/$(DOMAIN).mo $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo 2>/dev/null || \
+             ln $(DESTDIR)$(localedir)/$$lang/LC_MESSAGES/$(DOMAIN).mo $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo 2>/dev/null || \
+             cp -p $(DESTDIR)$(localedir)/$$lang/LC_MESSAGES/$(DOMAIN).mo $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo; \
+             echo "installing $$realcat link as $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo"; \
+           fi; \
+         done; \
+       done
+
+install-strip: install
+
+installdirs: installdirs-exec installdirs-data
+installdirs-exec:
+installdirs-data: installdirs-data-@USE_NLS@
+       if test "$(PACKAGE)" = "gettext-tools"; then \
+         $(mkdir_p) $(DESTDIR)$(gettextsrcdir); \
+       else \
+         : ; \
+       fi
+installdirs-data-no:
+installdirs-data-yes:
+       @catalogs='$(CATALOGS)'; \
+       for cat in $$catalogs; do \
+         cat=`basename $$cat`; \
+         lang=`echo $$cat | sed -e 's/\.gmo$$//'`; \
+         dir=$(localedir)/$$lang/LC_MESSAGES; \
+         $(mkdir_p) $(DESTDIR)$$dir; \
+         for lc in '' $(EXTRA_LOCALE_CATEGORIES); do \
+           if test -n "$$lc"; then \
+             if (cd $(DESTDIR)$(localedir)/$$lang && LC_ALL=C ls -l -d $$lc 2>/dev/null) | grep ' -> ' >/dev/null; then \
+               link=`cd $(DESTDIR)$(localedir)/$$lang && LC_ALL=C ls -l -d $$lc | sed -e 's/^.* -> //'`; \
+               mv $(DESTDIR)$(localedir)/$$lang/$$lc $(DESTDIR)$(localedir)/$$lang/$$lc.old; \
+               mkdir $(DESTDIR)$(localedir)/$$lang/$$lc; \
+               (cd $(DESTDIR)$(localedir)/$$lang/$$lc.old && \
+                for file in *; do \
+                  if test -f $$file; then \
+                    ln -s ../$$link/$$file $(DESTDIR)$(localedir)/$$lang/$$lc/$$file; \
+                  fi; \
+                done); \
+               rm -f $(DESTDIR)$(localedir)/$$lang/$$lc.old; \
+             else \
+               if test -d $(DESTDIR)$(localedir)/$$lang/$$lc; then \
+                 :; \
+               else \
+                 rm -f $(DESTDIR)$(localedir)/$$lang/$$lc; \
+                 mkdir $(DESTDIR)$(localedir)/$$lang/$$lc; \
+               fi; \
+             fi; \
+           fi; \
+         done; \
+       done
+
+# Define this as empty until I found a useful application.
+installcheck:
+
+uninstall: uninstall-exec uninstall-data
+uninstall-exec:
+uninstall-data: uninstall-data-@USE_NLS@
+       if test "$(PACKAGE)" = "gettext-tools"; then \
+         for file in $(DISTFILES.common) Makevars.template; do \
+           rm -f $(DESTDIR)$(gettextsrcdir)/$$file; \
+         done; \
+       else \
+         : ; \
+       fi
+uninstall-data-no:
+uninstall-data-yes:
+       catalogs='$(CATALOGS)'; \
+       for cat in $$catalogs; do \
+         cat=`basename $$cat`; \
+         lang=`echo $$cat | sed -e 's/\.gmo$$//'`; \
+         for lc in LC_MESSAGES $(EXTRA_LOCALE_CATEGORIES); do \
+           rm -f $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo; \
+         done; \
+       done
+
+check: all
+
+info dvi ps pdf html tags TAGS ctags CTAGS ID:
+
+mostlyclean:
+       rm -f remove-potcdate.sed
+       rm -f stamp-poT
+       rm -f core core.* $(DOMAIN).po $(DOMAIN).1po $(DOMAIN).2po *.new.po
+       rm -fr *.o
+
+clean: mostlyclean
+
+distclean: clean
+       rm -f Makefile Makefile.in POTFILES *.mo
+
+maintainer-clean: distclean
+       @echo "This command is intended for maintainers to use;"
+       @echo "it deletes files that may require special tools to rebuild."
+       rm -f stamp-po $(GMOFILES)
+
+distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
+dist distdir:
+       $(MAKE) update-po
+       @$(MAKE) dist2
+# This is a separate target because 'update-po' must be executed before.
+dist2: stamp-po $(DISTFILES)
+       dists="$(DISTFILES)"; \
+       if test "$(PACKAGE)" = "gettext-tools"; then \
+         dists="$$dists Makevars.template"; \
+       fi; \
+       if test -f $(srcdir)/$(DOMAIN).pot; then \
+         dists="$$dists $(DOMAIN).pot stamp-po"; \
+       fi; \
+       if test -f $(srcdir)/ChangeLog; then \
+         dists="$$dists ChangeLog"; \
+       fi; \
+       for i in 0 1 2 3 4 5 6 7 8 9; do \
+         if test -f $(srcdir)/ChangeLog.$$i; then \
+           dists="$$dists ChangeLog.$$i"; \
+         fi; \
+       done; \
+       if test -f $(srcdir)/LINGUAS; then dists="$$dists LINGUAS"; fi; \
+       for file in $$dists; do \
+         if test -f $$file; then \
+           cp -p $$file $(distdir) || exit 1; \
+         else \
+           cp -p $(srcdir)/$$file $(distdir) || exit 1; \
+         fi; \
+       done
+
+update-po: Makefile
+       $(MAKE) $(DOMAIN).pot-update
+       test -z "$(UPDATEPOFILES)" || $(MAKE) $(UPDATEPOFILES)
+       $(MAKE) update-gmo
+
+# General rule for creating PO files.
+
+.nop.po-create:
+       @lang=`echo $@ | sed -e 's/\.po-create$$//'`; \
+       echo "File $$lang.po does not exist. If you are a translator, you can create it through 'msginit'." 1>&2; \
+       exit 1
+
+# General rule for updating PO files.
+
+.nop.po-update:
+       @lang=`echo $@ | sed -e 's/\.po-update$$//'`; \
+       if test "$(PACKAGE)" = "gettext-tools"; then PATH=`pwd`/../src:$$PATH; fi; \
+       tmpdir=`pwd`; \
+       echo "$$lang:"; \
+       test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \
+       echo "$${cdcmd}$(MSGMERGE) $(MSGMERGE_OPTIONS) --lang=$$lang $$lang.po $(DOMAIN).pot -o $$lang.new.po"; \
+       cd $(srcdir); \
+       if { case `$(MSGMERGE) --version | sed 1q | sed -e 's,^[^0-9]*,,'` in \
+              '' | 0.[0-9] | 0.[0-9].* | 0.1[0-7] | 0.1[0-7].*) \
+                $(MSGMERGE) $(MSGMERGE_OPTIONS) -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \
+              *) \
+                $(MSGMERGE) $(MSGMERGE_OPTIONS) --lang=$$lang -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \
+            esac; \
+          }; then \
+         if cmp $$lang.po $$tmpdir/$$lang.new.po >/dev/null 2>&1; then \
+           rm -f $$tmpdir/$$lang.new.po; \
+         else \
+           if mv -f $$tmpdir/$$lang.new.po $$lang.po; then \
+             :; \
+           else \
+             echo "msgmerge for $$lang.po failed: cannot move $$tmpdir/$$lang.new.po to $$lang.po" 1>&2; \
+             exit 1; \
+           fi; \
+         fi; \
+       else \
+         echo "msgmerge for $$lang.po failed!" 1>&2; \
+         rm -f $$tmpdir/$$lang.new.po; \
+       fi
+
+$(DUMMYPOFILES):
+
+update-gmo: Makefile $(GMOFILES)
+       @:
+
+# Recreate Makefile by invoking config.status. Explicitly invoke the shell,
+# because execution permission bits may not work on the current file system.
+# Use @SHELL@, which is the shell determined by autoconf for the use by its
+# scripts, not $(SHELL) which is hardwired to /bin/sh and may be deficient.
+Makefile: Makefile.in.in Makevars $(top_builddir)/config.status @POMAKEFILEDEPS@
+       cd $(top_builddir) \
+         && @SHELL@ ./config.status $(subdir)/$@.in po-directories
+
+force:
+
+# Tell versions [3.59,3.63) of GNU make not to export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/po/Makevars b/po/Makevars
new file mode 100644 (file)
index 0000000..bbb9ebe
--- /dev/null
@@ -0,0 +1,41 @@
+# Makefile variables for PO directory in any package using GNU gettext.
+
+# Usually the message domain is the same as the package name.
+DOMAIN = $(PACKAGE)
+
+# These two variables depend on the location of this directory.
+subdir = po
+top_builddir = ..
+
+# These options get passed to xgettext.
+XGETTEXT_OPTIONS = --keyword=_ --keyword=N_ --keyword=__
+
+# This is the copyright holder that gets inserted into the header of the
+# $(DOMAIN).pot file.  Set this to the copyright holder of the surrounding
+# package.  (Note that the msgstr strings, extracted from the package's
+# sources, belong to the copyright holder of the package.)  Translators are
+# expected to transfer the copyright for their translations to this person
+# or entity, or to disclaim their copyright.  The empty string stands for
+# the public domain; in this case the translators are expected to disclaim
+# their copyright.
+COPYRIGHT_HOLDER = Intel Corporation 
+
+# This is the email address or URL to which the translators shall report
+# bugs in the untranslated strings:
+# - Strings which are not entire sentences, see the maintainer guidelines
+#   in the GNU gettext documentation, section 'Preparing Strings'.
+# - Strings which use unclear terms or require additional context to be
+#   understood.
+# - Strings which make invalid assumptions about notation of date, time or
+#   money.
+# - Pluralisation problems.
+# - Incorrect English spelling.
+# - Incorrect formatting.
+# It can be your email address, or a mailing list address where translators
+# can write to without being subscribed, or the URL of a web page through
+# which the translators can contact you.
+MSGID_BUGS_ADDRESS = "powertop@lists.01.org"
+
+# This is the list of locale categories, beyond LC_MESSAGES, for which the
+# message catalogs shall be used.  It is usually empty.
+EXTRA_LOCALE_CATEGORIES =
diff --git a/po/POTFILES.in b/po/POTFILES.in
new file mode 100644 (file)
index 0000000..4f4d061
--- /dev/null
@@ -0,0 +1,35 @@
+# List of source files which contain translatable strings.
+
+traceevent/parse-utils.c
+src/parameters/persistent.cpp
+src/display.cpp
+src/cpu/cpu_core.cpp
+src/cpu/cpu.cpp
+src/cpu/cpu_linux.cpp
+src/cpu/cpu_package.cpp
+src/cpu/intel_cpus.cpp
+src/devlist.cpp
+src/lib.cpp
+src/process/do_process.cpp
+src/perf/perf.cpp
+src/perf/perf_bundle.cpp
+src/devices/device.cpp
+src/devices/alsa.cpp
+src/devices/runtime_pm.cpp
+src/devices/usb.cpp
+src/devices/ahci.cpp
+src/devices/rfkill.cpp
+src/devices/network.cpp
+src/lib.h
+src/tuning/bluetooth.cpp
+src/tuning/cpufreq.cpp
+src/tuning/tuning.cpp
+src/tuning/ethernet.cpp
+src/tuning/tunable.cpp
+src/tuning/nl80211.h
+src/tuning/wifi.cpp
+src/tuning/runtime.cpp
+src/tuning/tuningusb.cpp
+src/tuning/tuningsysfs.cpp
+src/calibrate/calibrate.cpp
+src/main.cpp
diff --git a/po/bn_IN.po b/po/bn_IN.po
new file mode 100644 (file)
index 0000000..6bd0b34
--- /dev/null
@@ -0,0 +1,587 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR Intel Corporation
+# This file is distributed under the same license as the PACKAGE package.
+# 
+# Translators:
+#   <rajeshdey606@gmail.com>, 2012.
+msgid ""
+msgstr ""
+"Project-Id-Version: PowerTOP\n"
+"Report-Msgid-Bugs-To: \"powertop@lists.01.org\"\n"
+"POT-Creation-Date: 2012-10-26 09:24-0700\n"
+"PO-Revision-Date: 2012-10-26 22:23+0000\n"
+"Last-Translator: ceferron <chris.e.ferron@linux.intel.com>\n"
+"Language-Team: Bengali (India) (http://www.transifex.com/projects/p/PowerTOP/language/bn_IN/)\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Language: bn_IN\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+
+#: src/parameters/persistent.cpp:46 src/parameters/persistent.cpp:140
+msgid "Cannot save to file"
+msgstr ""
+
+#: src/parameters/persistent.cpp:78 src/parameters/persistent.cpp:165
+msgid "Cannot load from file"
+msgstr ""
+
+#: src/parameters/persistent.cpp:123
+#, c-format
+msgid "Loaded %i prior measurements\n"
+msgstr "লোডকৃত %i আগের পরিমাপ\n\n"
+
+#: src/display.cpp:70
+msgid "Overview"
+msgstr "পরিদর্শন"
+
+#: src/display.cpp:71
+msgid "Idle stats"
+msgstr "অলস পরিসংখ্যান"
+
+#: src/display.cpp:72
+msgid "Frequency stats"
+msgstr "কম্পাংক পরিসংখ্যান"
+
+#: src/display.cpp:73
+msgid "Device stats"
+msgstr "ডিভাইস পরিসংখ্যান"
+
+#: src/display.cpp:130
+msgid "Exit"
+msgstr "প্রস্থান"
+
+#: src/cpu/cpu_core.cpp:111 src/cpu/cpu_linux.cpp:360
+#: src/cpu/cpu_package.cpp:133 src/cpu/intel_cpus.cpp:222
+#: src/cpu/intel_cpus.cpp:444 src/cpu/intel_cpus.cpp:639
+msgid "Idle"
+msgstr "নিষ্ক্রিয়"
+
+#: src/cpu/cpu_core.cpp:113 src/cpu/cpu_linux.cpp:362
+#: src/cpu/cpu_package.cpp:135 src/cpu/intel_cpus.cpp:224
+#: src/cpu/intel_cpus.cpp:446
+#, c-format
+msgid "Turbo Mode"
+msgstr "Turbo Mode"
+
+#: src/cpu/cpu.cpp:93
+#, c-format
+msgid "cpu package %i"
+msgstr "সিপিইউ প্যাকেজ %i"
+
+#: src/cpu/cpu.cpp:94
+msgid "cpu package"
+msgstr "cpu 'র প্যাকেজ"
+
+#: src/cpu/cpu.cpp:437 src/cpu/cpu.cpp:563
+#, c-format
+msgid "Package %i"
+msgstr ""
+
+#: src/cpu/cpu.cpp:469 src/cpu/cpu.cpp:583
+#, c-format
+msgid "Core %i"
+msgstr ""
+
+#: src/cpu/cpu.cpp:471
+#, c-format
+msgid "GPU %i"
+msgstr ""
+
+#: src/cpu/cpu.cpp:493 src/cpu/cpu.cpp:604
+#, c-format
+msgid "CPU %i"
+msgstr ""
+
+#: src/cpu/cpu.cpp:772
+#, c-format
+msgid "cpu_idle event returned no state?\n"
+msgstr "cpu_idle ইভেন্ট  কোনও অবস্থাষ় ফিরে আসেনি?\n\n"
+
+#: src/cpu/cpu.cpp:787
+#, c-format
+msgid "power or cpu_frequecny event returned no state?\n"
+msgstr "ক্ষমতা বা cpu_frequecny ইভেন্ট কোনও অবস্থাষ় ফিরে আসেনি?\n"
+
+#: src/cpu/cpu_linux.cpp:92
+msgid "C0 polling"
+msgstr "C0 polling"
+
+#: src/cpu/intel_cpus.cpp:69
+#, c-format
+msgid "msr reg not found"
+msgstr "msr reg খুঁজে পাষ় নি"
+
+#: src/cpu/intel_cpus.cpp:79
+#, c-format
+msgid "pread cpu%d 0x%llx : "
+msgstr "pread cpu 'র%d 0x%llx :"
+
+#: src/cpu/intel_cpus.cpp:516
+msgid "C0 active"
+msgstr "C0 সক্রিয়"
+
+#: src/cpu/intel_cpus.cpp:575
+#, c-format
+msgid "Actual"
+msgstr "প্রকৃত"
+
+#: src/lib.cpp:257
+#, c-format
+msgid "%7sW"
+msgstr "%7sW"
+
+#: src/lib.cpp:260
+#, c-format
+msgid "    0 mW"
+msgstr "      0 mW"
+
+#: src/lib.cpp:381
+msgid "PS/2 Touchpad / Keyboard / Mouse"
+msgstr "PS / 2, টাচপ্যাড / কীবোর্ড / মাউস"
+
+#: src/lib.cpp:382
+msgid "SATA controller"
+msgstr "SATA নিয়ন্ত্রণ"
+
+#: src/lib.cpp:383
+msgid "Intel built in USB hub"
+msgstr "ইন্টেল নির্মিত USB হাব"
+
+#: src/process/do_process.cpp:830
+#, c-format
+msgid ""
+"Estimated power: %5.1f    Measured power: %5.1f    Sum: %5.1f\n"
+"\n"
+msgstr "Estimated power: %5.1f    Measured power: %5.1f    Sum: %5.1f\n\n"
+
+#: src/process/do_process.cpp:841 src/devices/device.cpp:171
+#, c-format
+msgid "The battery reports a discharge rate of %sW\n"
+msgstr "The battery reports a discharge rate of %sW\n"
+
+#: src/process/do_process.cpp:846
+#, c-format
+msgid "The estimated remaining time is %i hours, %i minutes\n"
+msgstr "আনুমানিক অবশিষ্ট সময় হল %i ঘন্টা, %i মিনিট\n\n\n"
+
+#: src/process/do_process.cpp:854
+msgid "Summary"
+msgstr "সারাংশ"
+
+#: src/process/do_process.cpp:854 src/process/do_process.cpp:1024
+msgid "wakeups/second"
+msgstr "ওষ়েকআপস/সেকেন্ড"
+
+#: src/process/do_process.cpp:854
+msgid "GPU ops/seconds"
+msgstr "জিপিইউ ops/সেকেন্ড"
+
+#: src/process/do_process.cpp:854
+msgid "VFS ops/sec and"
+msgstr "ভিএফএস OPS / সেকেন্ড এবং"
+
+#: src/process/do_process.cpp:854 src/process/do_process.cpp:1028
+msgid "CPU use"
+msgstr "সিপিইউ-র ব্যবহার"
+
+#: src/process/do_process.cpp:858 src/process/do_process.cpp:915
+#: src/process/do_process.cpp:1034
+msgid "Power est."
+msgstr "শক্তি অনুমান"
+
+#: src/process/do_process.cpp:858 src/process/do_process.cpp:860
+#: src/process/do_process.cpp:919 src/process/do_process.cpp:1038
+msgid "Usage"
+msgstr "ব্যবহার"
+
+#: src/process/do_process.cpp:858 src/process/do_process.cpp:860
+#: src/process/do_process.cpp:1040
+msgid "Events/s"
+msgstr "ইভেন্টস / গুলি"
+
+#: src/process/do_process.cpp:858 src/process/do_process.cpp:860
+#: src/process/do_process.cpp:929 src/process/do_process.cpp:1042
+msgid "Category"
+msgstr "বিভাগ"
+
+#: src/process/do_process.cpp:858 src/process/do_process.cpp:860
+#: src/process/do_process.cpp:931 src/process/do_process.cpp:1044
+msgid "Description"
+msgstr "বিবরণ"
+
+#: src/process/do_process.cpp:910
+msgid "Overview of Software Power Consumers"
+msgstr "সফ্টওয়্যার পাওয়ার কনজিউমার্স রূপরেখা"
+
+#: src/process/do_process.cpp:921
+msgid "Wakeups/s"
+msgstr "ওষ়েকআপস/ গুলি"
+
+#: src/process/do_process.cpp:923
+msgid "GPU ops/s"
+msgstr "জিপিইউ ops/ গুলি"
+
+#: src/process/do_process.cpp:925
+msgid "Disk IO/s"
+msgstr "ডিস্ক IO / গুলি"
+
+#: src/process/do_process.cpp:927
+msgid "GFX Wakeups/s"
+msgstr "GFX ওষ়েকআপস/ গুলি"
+
+#: src/process/do_process.cpp:1021
+msgid "Power Consumption Summary"
+msgstr "বিদ্যুত ব্যবহার সারাংশ"
+
+#: src/process/do_process.cpp:1025
+msgid "GPU ops/second"
+msgstr "জিপিইউ ops/সেকেন্ড"
+
+#: src/process/do_process.cpp:1026
+msgid "VFS ops/sec"
+msgstr "VFS ops/sec"
+
+#: src/process/do_process.cpp:1027
+msgid "GFX wakes/sec and"
+msgstr "ভিএফএস OPS / সেকেন্ড "
+
+#: src/perf/perf.cpp:111
+#, c-format
+msgid "PowerTOP %s needs the kernel to support the 'perf' subsystem\n"
+msgstr "PowerTOP %s 'perf' সাবসিস্টেম সমর্থন করতে কার্নেল প্রয়োজন বোধ করে\n\n"
+
+#: src/perf/perf.cpp:112
+#, c-format
+msgid "as well as support for trace points in the kernel:\n"
+msgstr "কার্নেলে ছাপ বিন্দুর জন্য সমর্থন হিসেবে যত ভাল:\n\n"
+
+#: src/devices/device.cpp:177
+#, c-format
+msgid "System baseline power is estimated at %sW\n"
+msgstr "System baseline power is estimated at %sW\n"
+
+#: src/devices/device.cpp:184
+msgid "Power est.    Usage     Device name\n"
+msgstr "বিদ্যুৎ est.   ব্যবহার    ডিভাইস নাম\n\n"
+
+#: src/devices/device.cpp:186
+msgid "              Usage     Device name\n"
+msgstr "             ব্যবহারের ডিভাইস নাম\n\n"
+
+#: src/devices/alsa.cpp:79
+#, c-format
+msgid "Audio codec %s: %s (%s)"
+msgstr "Audio codec %s: %s (%s)"
+
+#: src/devices/alsa.cpp:81 src/devices/alsa.cpp:83
+#, c-format
+msgid "Audio codec %s: %s"
+msgstr "অডিও কোডেক %s: %s"
+
+#: src/devices/runtime_pm.cpp:225
+#, c-format
+msgid "PCI Device: %s"
+msgstr "পিসিআই ডিভাইস: %s"
+
+#: src/devices/usb.cpp:51 src/devices/usb.cpp:94 src/devices/usb.cpp:96
+#, c-format
+msgid "USB device: %s"
+msgstr "ইউএসবি ডিভাইস: %s"
+
+#: src/devices/usb.cpp:92
+#, c-format
+msgid "USB device: %s (%s)"
+msgstr "ইউএসবি ডিভাইস: %s (%s)"
+
+#: src/devices/ahci.cpp:140
+#, c-format
+msgid "SATA link: %s"
+msgstr "SATA সংযোগ: %s"
+
+#: src/devices/ahci.cpp:142
+#, c-format
+msgid "SATA disk: %s"
+msgstr "SATA ডিস্ক: %s"
+
+#: src/devices/rfkill.cpp:65 src/devices/rfkill.cpp:69
+#, c-format
+msgid "Radio device: %s"
+msgstr "রেডিও ডিভাইস: %s"
+
+#: src/devices/network.cpp:177
+#, c-format
+msgid "Network interface: %s (%s)"
+msgstr "নেটওয়ার্ক ইন্টারফেস: %s (%s)"
+
+#: src/tuning/bluetooth.cpp:48
+#, c-format
+msgid "Bluetooth device interface status"
+msgstr "ব্লুটুথ ডিভাইসের ইন্টারফেস অবস্থা"
+
+#: src/tuning/cpufreq.cpp:43 src/tuning/ethernet.cpp:53
+#: src/tuning/tunable.cpp:48 src/tuning/wifi.cpp:45 src/tuning/runtime.cpp:41
+#: src/tuning/tuningusb.cpp:40 src/tuning/tuningsysfs.cpp:44
+msgid "Good"
+msgstr "ভাল"
+
+#: src/tuning/cpufreq.cpp:43 src/tuning/ethernet.cpp:53
+#: src/tuning/tunable.cpp:49 src/tuning/wifi.cpp:45 src/tuning/runtime.cpp:41
+#: src/tuning/tuningusb.cpp:40 src/tuning/tuningsysfs.cpp:44
+msgid "Bad"
+msgstr "খারাপ"
+
+#: src/tuning/cpufreq.cpp:43 src/tuning/ethernet.cpp:53
+#: src/tuning/tunable.cpp:50 src/tuning/wifi.cpp:45 src/tuning/runtime.cpp:41
+#: src/tuning/tuningusb.cpp:40 src/tuning/tuningsysfs.cpp:44
+msgid "Unknown"
+msgstr "অজানা"
+
+#: src/tuning/cpufreq.cpp:46
+#, c-format
+msgid "Using 'ondemand' cpufreq governor"
+msgstr "'ondemand' cpufreq গভর্নর ব্যবহার করছে"
+
+#: src/tuning/tuning.cpp:59
+msgid "Enable Audio codec power management"
+msgstr "অডিও কোডেকর অধিকার ব্যবস্থাপনা সক্রিয় করুন"
+
+#: src/tuning/tuning.cpp:60
+msgid "NMI watchdog should be turned off"
+msgstr "NMI পাহরাদার বন্ধ করা উচিত"
+
+#: src/tuning/tuning.cpp:61
+msgid "Power Aware CPU scheduler"
+msgstr "সিপিইউ সময়-তালিকা নির্ধারণ ব্যবস্থার বিদ্যুৎ সচেতন"
+
+#: src/tuning/tuning.cpp:62
+msgid "VM writeback timeout"
+msgstr "VM writeback  সময়সীমা"
+
+#: src/tuning/tuning.cpp:79
+msgid "Tunables"
+msgstr "সুরেলা "
+
+#: src/tuning/tuning.cpp:79
+msgid " <ESC> Exit | <Enter> Toggle tunable | <r> Window refresh"
+msgstr " <ESC> থেকে প্রস্থান করুন | <Enter> টগল করুন সুরেলা | <r> উইন্ডো রিফ্রেশ করুন"
+
+#: src/tuning/ethernet.cpp:57
+#, c-format
+msgid "Wake-on-lan status for device %s"
+msgstr "ডিভাইস %sএর জন্য  LAN অবস্থা  অন কর"
+
+#: src/tuning/wifi.cpp:48
+#, c-format
+msgid "Wireless Power Saving for interface %s"
+msgstr "Wireless Power Saving for interface %s"
+
+#: src/tuning/runtime.cpp:47
+#, c-format
+msgid "Runtime PM for %s device %s"
+msgstr "Runtime PM for %s device %s"
+
+#: src/tuning/runtime.cpp:49
+#, c-format
+msgid "%s device %s has no runtime power management"
+msgstr "%s device %s has no runtime power management"
+
+#: src/tuning/runtime.cpp:73
+#, c-format
+msgid "PCI Device %s has no runtime power management"
+msgstr "PCI Device %s has no runtime power management"
+
+#: src/tuning/runtime.cpp:75
+#, c-format
+msgid "Runtime PM for PCI Device %s"
+msgstr "পিসিআই ডিভাইস %sএর জন্য  রানটাইম  PM"
+
+#: src/tuning/tuningusb.cpp:55
+#, c-format
+msgid "Autosuspend for unknown USB device %s (%s:%s)"
+msgstr "অজানা ইউএসবি ডিভাইস %s.(%s: %s) এর জন্য Autosuspend"
+
+#: src/tuning/tuningusb.cpp:72 src/tuning/tuningusb.cpp:74
+#: src/tuning/tuningusb.cpp:76
+#, c-format
+msgid "Autosuspend for USB device %s [%s]"
+msgstr "ইউএসবি ডিভাইস %s[%s] এর জন্য Autosuspend "
+
+#: src/tuning/tuningsysfs.cpp:142
+#, c-format
+msgid "Enable SATA link power Managmenet for %s"
+msgstr ""
+
+#: src/calibrate/calibrate.cpp:291
+#, c-format
+msgid "Cannot create temp file\n"
+msgstr "সাময়িক ফাইল তৈরি করতে পারবেন না\n"
+
+#: src/calibrate/calibrate.cpp:310
+#, c-format
+msgid "Calibrating: CPU usage on %i threads\n"
+msgstr "Calibrating: CPU usage on %i threads\n"
+
+#: src/calibrate/calibrate.cpp:325
+#, c-format
+msgid "Calibrating: CPU wakeup power consumption\n"
+msgstr "Calibrating: সিপিইউ -র ওয়েকআপ ক্ষমতা গ্রহণ\n\n"
+
+#: src/calibrate/calibrate.cpp:342
+#, c-format
+msgid "Calibrating USB devices\n"
+msgstr "কেলিবেটি ইউএসবি ডিভাইস\n\n\n"
+
+#: src/calibrate/calibrate.cpp:344 src/calibrate/calibrate.cpp:361
+#: src/calibrate/calibrate.cpp:369 src/calibrate/calibrate.cpp:386
+#, c-format
+msgid ".... device %s \n"
+msgstr "  ... ডিভাইস %s\n\n\n"
+
+#: src/calibrate/calibrate.cpp:359
+#, c-format
+msgid "Calibrating radio devices\n"
+msgstr "Calibrating রেডিও ডিভাইস\n\n"
+
+#: src/calibrate/calibrate.cpp:383
+#, c-format
+msgid "Calibrating backlight\n"
+msgstr "Calibrating বেকলাইট\n\n"
+
+#: src/calibrate/calibrate.cpp:407 src/calibrate/calibrate.cpp:415
+#, c-format
+msgid "Calibrating idle\n"
+msgstr "Calibrating অলস\n\n"
+
+#: src/calibrate/calibrate.cpp:426
+#, c-format
+msgid "Calibrating: disk usage \n"
+msgstr "Calibrating: ডিস্ক ব্যবহার\n\n"
+
+#: src/calibrate/calibrate.cpp:451
+msgid "Starting PowerTOP power estimate calibration \n"
+msgstr "পাওষ়ারটপ শক্তি অনুমান ক্রমাঙ্কন শুরু\n\n"
+
+#: src/calibrate/calibrate.cpp:474
+msgid "Finishing PowerTOP power estimate calibration \n"
+msgstr "পাওষ়ারটপ শক্তি অনুমান ক্রমাঙ্কন সমাপ্তি\n\n"
+
+#: src/calibrate/calibrate.cpp:478
+#, c-format
+msgid "Parameters after calibration:\n"
+msgstr "ক্রমাঙ্কন-র পরে প্যারামিটারগুলি:\n\n"
+
+#: src/main.cpp:86
+#, c-format
+msgid "PowerTOP version"
+msgstr "পাওষ়ারটপ অনুবাদ"
+
+#: src/main.cpp:92
+msgid "Set refresh time out"
+msgstr "রিফ্রেশ সময় আউট সেট করুন"
+
+#: src/main.cpp:105
+msgid "Usage: powertop [OPTIONS]"
+msgstr "ব্যবহার: পাওষ়ারটপ  [বিকল্প]"
+
+#: src/main.cpp:106
+msgid "run in \"debug\" mode"
+msgstr "\"ডিবাগ\" মোডে চালানো"
+
+#: src/main.cpp:107
+msgid "print version information"
+msgstr "প্রিন্ট সংস্করণ সংক্রান্ত তথ্য"
+
+#: src/main.cpp:108
+msgid "runs powertop in calibration mode"
+msgstr "মোডে সঞ্চালিত "
+
+#: src/main.cpp:109
+msgid "[=devnode]"
+msgstr "[=ডেভনোড]"
+
+#: src/main.cpp:109
+msgid "uses an Extech Power Analyzer for measurements"
+msgstr "পরিমাপের জন্য একটি Extech পাওয়ার বিশ্লেষক ব্যবহার"
+
+#: src/main.cpp:110 src/main.cpp:111
+msgid "[=FILENAME]"
+msgstr "[=ফাইলনেইম]"
+
+#: src/main.cpp:110
+msgid "generate a html report"
+msgstr "একটি এইচটিএমএল রিপোর্ট তৈরি কর "
+
+#: src/main.cpp:111
+msgid "generate a csv report"
+msgstr "একটি csv রিপোর্ট তৈরি কর "
+
+#: src/main.cpp:112
+msgid "[=seconds]"
+msgstr "[=সেকেন্ডস]"
+
+#: src/main.cpp:112
+msgid "generate a report for 'x' seconds"
+msgstr "'x' সেকেন্ডের জন্য একটি প্রতিবেদন তৈরি করুন"
+
+#: src/main.cpp:113
+msgid "[=iterations] number of times to run each test"
+msgstr "[= পুনরাবৃত্তিও] প্রত্যেক পরীক্ষা চালাতে সময়ের সংখ্যা"
+
+#: src/main.cpp:114
+msgid "[=workload]"
+msgstr ""
+
+#: src/main.cpp:114
+msgid "file to execute for workload"
+msgstr ""
+
+#: src/main.cpp:115
+msgid "suppress stderr output"
+msgstr ""
+
+#: src/main.cpp:116
+msgid "print this help menu"
+msgstr "এই সাহায্য মেনু মুদ্রণ কর"
+
+#: src/main.cpp:118
+msgid "For more help please refer to the README"
+msgstr "আরও সাহায্যের জন্য README পড়ুন দয়া করে"
+
+#: src/main.cpp:235
+msgid "PowerTOP is out of memory. PowerTOP is Aborting"
+msgstr "পাওষ়ারটপ মেমরি হয়ে গেছে । পাওষ়ারটপ বাতিল করছে"
+
+#: src/main.cpp:243
+#, c-format
+msgid "Preparing to take measurements\n"
+msgstr "পরিমাপ গ্রহণ করতে প্রস্তুত \n\n"
+
+#: src/main.cpp:248
+#, c-format
+msgid "Taking %d measurement(s) for a duration of %d second(s) each.\n"
+msgstr "প্রতিটি %d সেকেন্ড(গুলি) এর একটি সময়কালের জন্য %d পরিমাপ(গুলি) গ্রহণ করছে\n"
+
+#: src/main.cpp:250
+#, c-format
+msgid "Measuring workload %s.\n"
+msgstr ""
+
+#: src/main.cpp:273
+#, c-format
+msgid "PowerTOP "
+msgstr "পাওষ়ারটপ "
+
+#: src/main.cpp:274 src/main.cpp:302
+#, c-format
+msgid "exiting...\n"
+msgstr "প্রস্থান করছে...\n\n"
+
+#: src/main.cpp:301
+#, c-format
+msgid "Failed to mount debugfs!\n"
+msgstr "debugfs মাউন্ট করতে ব্যর্থ!\n\n"
+
+#: src/main.cpp:438
+msgid "Leaving PowerTOP"
+msgstr "পাওষ়ারটপ বন্ধ হচেছ"
diff --git a/po/ca.po b/po/ca.po
new file mode 100644 (file)
index 0000000..b9088e1
--- /dev/null
+++ b/po/ca.po
@@ -0,0 +1,580 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR Intel Corporation
+# This file is distributed under the same license as the PACKAGE package.
+#
+# Translators:
+# capimans, 2012.
+# Il_Tifossi <lluita_i_no_dorm@hotmail.com>, 2011.
+# Juanma Hernández <juanmah@gmail.com>, 2012.
+msgid ""
+msgstr ""
+"Project-Id-Version: PowerTOP\n"
+"Report-Msgid-Bugs-To: \"powertop@lists.01.org\"\n"
+"POT-Creation-Date: 2012-05-31 14:03-0700\n"
+"PO-Revision-Date: 2012-06-04 19:23+0000\n"
+"Last-Translator: Juanma Hernández <juanmah@gmail.com>\n"
+"Language-Team: Catalan (http://www.transifex.com/projects/p/PowerTOP/"
+"language/ca/)\n"
+"Language: ca\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1)\n"
+
+#: src/parameters/persistent.cpp:46 src/parameters/persistent.cpp:140
+msgid "Cannot save to file "
+msgstr "No s'ha pogut desar al fitxer "
+
+#: src/parameters/persistent.cpp:78 src/parameters/persistent.cpp:165
+msgid "Cannot load from file "
+msgstr "No s'ha pogut carregar des del fitxer "
+
+#: src/parameters/persistent.cpp:123
+#, c-format
+msgid "Loaded %i prior measurements\n"
+msgstr "Últimes mesuracions de %i carregades\n"
+
+#: src/display.cpp:71
+msgid "Overview"
+msgstr "Informació general"
+
+#: src/display.cpp:72
+msgid "Idle stats"
+msgstr "Estadístiques de repòs"
+
+#: src/display.cpp:73
+msgid "Frequency stats"
+msgstr "Estadístiques de freqüència"
+
+#: src/display.cpp:74
+msgid "Device stats"
+msgstr "Estadístiques del dispositiu"
+
+#: src/display.cpp:131
+msgid "Exit"
+msgstr "Surt"
+
+#: src/cpu/cpu_core.cpp:46 src/cpu/cpu_core.cpp:190 src/cpu/intel_cpus.cpp:296
+#, c-format
+msgid "  Core"
+msgstr "  Nucli"
+
+#: src/cpu/cpu_core.cpp:116 src/cpu/cpu_linux.cpp:329
+#: src/cpu/cpu_package.cpp:145 src/cpu/intel_cpus.cpp:222
+#: src/cpu/intel_cpus.cpp:457 src/cpu/intel_cpus.cpp:658
+msgid "Idle"
+msgstr "Desocupat"
+
+#: src/cpu/cpu_core.cpp:118 src/cpu/cpu_linux.cpp:331
+#: src/cpu/cpu_package.cpp:147 src/cpu/intel_cpus.cpp:224
+#: src/cpu/intel_cpus.cpp:459
+#, c-format
+msgid "Turbo Mode"
+msgstr "Mode turbo"
+
+#: src/cpu/cpu.cpp:90
+#, c-format
+msgid "cpu package %i"
+msgstr "Paquet CPU %i"
+
+#: src/cpu/cpu.cpp:91
+msgid "cpu package"
+msgstr "paquet cpu"
+
+#: src/cpu/cpu.cpp:925
+#, c-format
+msgid "cpu_idle event returned no state?\n"
+msgstr "l'event cpu_idle no ha retornat cap estat?\n"
+
+#: src/cpu/cpu.cpp:940
+#, c-format
+msgid "power or cpu_frequecny event returned no state?\n"
+msgstr "els events power o cpu_frequecny no han retornat cap estat?\n"
+
+#: src/cpu/cpu_linux.cpp:92
+msgid "C0 polling"
+msgstr "C0 sondejant"
+
+#: src/cpu/cpu_linux.cpp:231 src/cpu/cpu_linux.cpp:289
+#: src/cpu/intel_cpus.cpp:605
+#, c-format
+msgid " CPU %i"
+msgstr " CPU %i"
+
+#: src/cpu/cpu_package.cpp:46
+#, c-format
+msgid "Package"
+msgstr "Paquet"
+
+#: src/cpu/cpu_package.cpp:104 src/cpu/intel_cpus.cpp:322
+#, c-format
+msgid "  Package"
+msgstr "  Paquet"
+
+#: src/cpu/intel_cpus.cpp:69
+#, c-format
+msgid "msr reg not found"
+msgstr "No s'ha trobat msr reg"
+
+#: src/cpu/intel_cpus.cpp:79
+#, c-format
+msgid "pread cpu%d 0x%llx : "
+msgstr ""
+
+#: src/cpu/intel_cpus.cpp:529
+msgid "C0 active"
+msgstr "C0 actiu"
+
+#: src/cpu/intel_cpus.cpp:588
+#, c-format
+msgid "Actual"
+msgstr "Autèntic"
+
+#: src/lib.cpp:257
+#, c-format
+msgid "%7sW"
+msgstr "%7sW"
+
+#: src/lib.cpp:260
+#, c-format
+msgid "    0 mW"
+msgstr "    0 mW"
+
+#: src/lib.cpp:369
+msgid "PS/2 Touchpad / Keyboard / Mouse"
+msgstr "PS/2 Touchpad / Teclat / Ratolí"
+
+#: src/lib.cpp:370
+msgid "SATA controller"
+msgstr "Controlador SATA"
+
+#: src/lib.cpp:371
+msgid "Intel built in USB hub"
+msgstr "Intel connectat a port USB"
+
+#: src/process/do_process.cpp:818
+#, c-format
+msgid ""
+"Estimated power: %5.1f    Measured power: %5.1f    Sum: %5.1f\n"
+"\n"
+msgstr ""
+"Potència estimada: %5.1f    Potència mesurada: %5.1f    Suma: %5.1f\n"
+"\n"
+
+#: src/process/do_process.cpp:829 src/devices/device.cpp:171
+#, c-format
+msgid "The battery reports a discharge rate of %sW\n"
+msgstr "La bateria reporta un nivell de descàrrega de %sW\n"
+
+#: src/process/do_process.cpp:834
+#, c-format
+msgid "The estimated remaining time is %i hours, %i minutes\n"
+msgstr ""
+
+#: src/process/do_process.cpp:842
+msgid "Summary"
+msgstr ""
+
+#: src/process/do_process.cpp:842 src/process/do_process.cpp:1029
+msgid "wakeups/second"
+msgstr ""
+
+#: src/process/do_process.cpp:842
+msgid "GPU ops/seconds"
+msgstr ""
+
+#: src/process/do_process.cpp:842
+msgid "VFS ops/sec and"
+msgstr ""
+
+#: src/process/do_process.cpp:842 src/process/do_process.cpp:1030
+msgid "CPU use"
+msgstr ""
+
+#: src/process/do_process.cpp:846 src/process/do_process.cpp:914
+#: src/process/do_process.cpp:1034
+msgid "Power est."
+msgstr ""
+
+#: src/process/do_process.cpp:846 src/process/do_process.cpp:848
+#: src/process/do_process.cpp:914 src/process/do_process.cpp:917
+#: src/process/do_process.cpp:1034 src/process/do_process.cpp:1038
+msgid "Usage"
+msgstr ""
+
+#: src/process/do_process.cpp:846 src/process/do_process.cpp:848
+#: src/process/do_process.cpp:1034 src/process/do_process.cpp:1038
+msgid "Events/s"
+msgstr ""
+
+#: src/process/do_process.cpp:846 src/process/do_process.cpp:848
+#: src/process/do_process.cpp:914 src/process/do_process.cpp:917
+#: src/process/do_process.cpp:1034 src/process/do_process.cpp:1038
+msgid "Category"
+msgstr ""
+
+#: src/process/do_process.cpp:846 src/process/do_process.cpp:848
+#: src/process/do_process.cpp:914 src/process/do_process.cpp:917
+#: src/process/do_process.cpp:1034 src/process/do_process.cpp:1038
+msgid "Description"
+msgstr ""
+
+#: src/process/do_process.cpp:911
+msgid "Overview of Software Power Consumers"
+msgstr ""
+
+#: src/process/do_process.cpp:914 src/process/do_process.cpp:917
+msgid "Wakeups/s"
+msgstr ""
+
+#: src/process/do_process.cpp:914 src/process/do_process.cpp:917
+msgid "GPU ops/s"
+msgstr ""
+
+#: src/process/do_process.cpp:914 src/process/do_process.cpp:917
+msgid "Disk IO/s"
+msgstr ""
+
+#: src/process/do_process.cpp:914 src/process/do_process.cpp:917
+msgid "GFX Wakeups/s"
+msgstr ""
+
+#: src/process/do_process.cpp:1026
+msgid "Power Consumption Summary"
+msgstr ""
+
+#: src/process/do_process.cpp:1029
+msgid "GPU ops/second"
+msgstr ""
+
+#: src/process/do_process.cpp:1030
+msgid "VFS ops/sec"
+msgstr ""
+
+#: src/process/do_process.cpp:1030
+msgid "GFX wakes/sec and"
+msgstr ""
+
+#: src/perf/perf.cpp:121
+#, c-format
+msgid "PowerTOP %s needs the kernel to support the 'perf' subsystem\n"
+msgstr "PowerTOP %s necessita que el kernel suporti el subsistema 'perf'\n"
+
+#: src/perf/perf.cpp:122
+#, c-format
+msgid "as well as support for trace points in the kernel:\n"
+msgstr "així com suport per a punts de seguiment en el kernel:\n"
+
+#: src/devices/device.cpp:177
+#, c-format
+msgid "System baseline power is estimated at %sW\n"
+msgstr "La línia base d'energia del sistema està estimada en %sW\n"
+
+#: src/devices/device.cpp:184
+msgid "Power est.    Usage     Device name\n"
+msgstr "Energia est.    Ús     Nom del dispositiu\n"
+
+#: src/devices/device.cpp:186
+msgid "              Usage     Device name\n"
+msgstr "              Ús     Nom del dispositiu\n"
+
+#: src/devices/alsa.cpp:79
+#, c-format
+msgid "Audio codec %s: %s (%s)"
+msgstr "Còdec d'àudio %s: %s (%s)"
+
+#: src/devices/alsa.cpp:81 src/devices/alsa.cpp:83
+#, c-format
+msgid "Audio codec %s: %s"
+msgstr "Còdec d'àudio %s: %s"
+
+#: src/devices/runtime_pm.cpp:225
+#, c-format
+msgid "PCI Device: %s"
+msgstr "Dispositiu PCI: %s"
+
+#: src/devices/usb.cpp:51 src/devices/usb.cpp:94 src/devices/usb.cpp:96
+#, c-format
+msgid "USB device: %s"
+msgstr "Dispositiu USB: %s"
+
+#: src/devices/usb.cpp:92
+#, c-format
+msgid "USB device: %s (%s)"
+msgstr "Dispositiu USB: %s (%s)"
+
+#: src/devices/ahci.cpp:140
+#, c-format
+msgid "SATA link: %s"
+msgstr "Connexió SATA: %s"
+
+#: src/devices/ahci.cpp:142
+#, c-format
+msgid "SATA disk: %s"
+msgstr "Disc SATA: %s"
+
+#: src/devices/rfkill.cpp:65 src/devices/rfkill.cpp:69
+#, c-format
+msgid "Radio device: %s"
+msgstr "Dispositiu de ràdio: %s"
+
+#: src/devices/network.cpp:177
+#, c-format
+msgid "Network interface: %s (%s)"
+msgstr "Interfície de xarxa: %s(%s)"
+
+#: src/tuning/bluetooth.cpp:48
+#, c-format
+msgid "Bluetooth device interface status"
+msgstr "Estat de la interfície del dispositiu Bluetooth"
+
+#: src/tuning/cpufreq.cpp:43 src/tuning/ethernet.cpp:53
+#: src/tuning/tunable.cpp:48 src/tuning/wifi.cpp:45 src/tuning/runtime.cpp:41
+#: src/tuning/tuningusb.cpp:40 src/tuning/tuningsysfs.cpp:37
+msgid "Good"
+msgstr "Bo"
+
+#: src/tuning/cpufreq.cpp:43 src/tuning/ethernet.cpp:53
+#: src/tuning/tunable.cpp:49 src/tuning/wifi.cpp:45 src/tuning/runtime.cpp:41
+#: src/tuning/tuningusb.cpp:40 src/tuning/tuningsysfs.cpp:37
+msgid "Bad"
+msgstr "Malament"
+
+#: src/tuning/cpufreq.cpp:43 src/tuning/ethernet.cpp:53
+#: src/tuning/tunable.cpp:50 src/tuning/wifi.cpp:45 src/tuning/runtime.cpp:41
+#: src/tuning/tuningusb.cpp:40 src/tuning/tuningsysfs.cpp:37
+msgid "Unknown"
+msgstr "Desconegut"
+
+#: src/tuning/cpufreq.cpp:46
+#, c-format
+msgid "Using 'ondemand' cpufreq governor"
+msgstr "Utilitzant governador de la freqüència CPU 'ondemand'"
+
+#: src/tuning/tuning.cpp:60
+msgid "Enable Audio codec power management"
+msgstr "Habilita administració d'energia del còdec d'àudio"
+
+#: src/tuning/tuning.cpp:61
+msgid "Enable SATA link power management for /dev/sda"
+msgstr "Habilita control d'energia de la connexió SATA /dev/sda"
+
+#: src/tuning/tuning.cpp:62
+msgid "NMI watchdog should be turned off"
+msgstr "S'hauria d'apagar la vigilància NMI"
+
+#: src/tuning/tuning.cpp:63
+msgid "Power Aware CPU scheduler"
+msgstr "Planificador de CPU conscient d'energia"
+
+#: src/tuning/tuning.cpp:64
+msgid "VM writeback timeout"
+msgstr "Temps límint de reescriptura VM"
+
+#: src/tuning/tuning.cpp:82
+msgid "Tunables"
+msgstr "Optimitzables"
+
+#: src/tuning/tuning.cpp:82
+msgid " <ESC> Exit | <Enter> Toggle tunable | <r> Window refresh"
+msgstr "<ESC> Sortir | <ENTRAR> canvia optimitzable | <r> Actualitza finestra"
+
+#: src/tuning/ethernet.cpp:57
+#, c-format
+msgid "Wake-on-lan status for device %s"
+msgstr "Estat Wake-on-lan per a dispositiu %s"
+
+#: src/tuning/wifi.cpp:48
+#, c-format
+msgid "Wireless Power Saving for interface %s"
+msgstr "Estalvi d'energia sense cable per a interfície %s"
+
+#: src/tuning/runtime.cpp:47
+#, c-format
+msgid "Runtime PM for %s device %s"
+msgstr "Temps d'execució PM per %s dispositiu %s"
+
+#: src/tuning/runtime.cpp:49
+#, c-format
+msgid "%s device %s has no runtime power management"
+msgstr "%s dispositiu %s no té administració d'energia en el funcionament"
+
+#: src/tuning/runtime.cpp:73
+#, c-format
+msgid "PCI Device %s has no runtime power management"
+msgstr "El dispositiu PCI %s no té administració d'energia en temps d'execució"
+
+#: src/tuning/runtime.cpp:75
+#, c-format
+msgid "Runtime PM for PCI Device %s"
+msgstr "Temps d'execució PM per dispositiu PCI %s"
+
+#: src/tuning/tuningusb.cpp:55
+#, c-format
+msgid "Autosuspend for unknown USB device %s (%s:%s)"
+msgstr "Autosuspès per a dispositiu USB desconegut %s (%s:%s)"
+
+#: src/tuning/tuningusb.cpp:72 src/tuning/tuningusb.cpp:74
+#: src/tuning/tuningusb.cpp:76
+#, c-format
+msgid "Autosuspend for USB device %s [%s]"
+msgstr "Autosuspès per a dipositiu USB %s [%s]"
+
+#: src/calibrate/calibrate.cpp:291
+#, c-format
+msgid "Cannot create temp file\n"
+msgstr "No es pot crear el fitxer temporal\n"
+
+#: src/calibrate/calibrate.cpp:310
+#, c-format
+msgid "Calibrating: CPU usage on %i threads\n"
+msgstr "Calibrant: ús de CPU en %i discussions\n"
+
+#: src/calibrate/calibrate.cpp:325
+#, c-format
+msgid "Calibrating: CPU wakeup power consumption\n"
+msgstr "Calibrant: consum d'energia de l'encesa de CPU\n"
+
+#: src/calibrate/calibrate.cpp:342
+#, c-format
+msgid "Calibrating USB devices\n"
+msgstr "Calibrant dispositius USB\n"
+
+#: src/calibrate/calibrate.cpp:344 src/calibrate/calibrate.cpp:361
+#: src/calibrate/calibrate.cpp:369 src/calibrate/calibrate.cpp:386
+#, c-format
+msgid ".... device %s \n"
+msgstr ".... dispositiu %s\n"
+
+#: src/calibrate/calibrate.cpp:359
+#, c-format
+msgid "Calibrating radio devices\n"
+msgstr "Calibrant dispositius de ràdio\n"
+
+#: src/calibrate/calibrate.cpp:383
+#, c-format
+msgid "Calibrating backlight\n"
+msgstr "Calibrant llum de fons\n"
+
+#: src/calibrate/calibrate.cpp:407 src/calibrate/calibrate.cpp:415
+#, c-format
+msgid "Calibrating idle\n"
+msgstr "Calibrant repòs\n"
+
+#: src/calibrate/calibrate.cpp:426
+#, c-format
+msgid "Calibrating: disk usage \n"
+msgstr "Calibrant: ús de disc\n"
+
+#: src/calibrate/calibrate.cpp:451
+msgid "Starting PowerTOP power estimate calibration \n"
+msgstr "Iniciant calibrat d'estimació d'energia PowerTOP\n"
+
+#: src/calibrate/calibrate.cpp:474
+msgid "Finishing PowerTOP power estimate calibration \n"
+msgstr "Finalitzant calibració d'estimació d'energia de PowerTOP\n"
+
+#: src/calibrate/calibrate.cpp:478
+#, c-format
+msgid "Parameters after calibration:\n"
+msgstr "Paràmetres després del calibrat:\n"
+
+#: src/main.cpp:84
+#, c-format
+msgid "PowerTOP version"
+msgstr ""
+
+#: src/main.cpp:90
+msgid "Set refresh time out"
+msgstr ""
+
+#: src/main.cpp:103
+msgid "Usage: powertop [OPTIONS]"
+msgstr ""
+
+#: src/main.cpp:104
+msgid "run in \"debug\" mode"
+msgstr ""
+
+#: src/main.cpp:105
+msgid "print version information"
+msgstr ""
+
+#: src/main.cpp:106
+msgid "runs powertop in calibration mode"
+msgstr ""
+
+#: src/main.cpp:107
+msgid "[=devnode]"
+msgstr ""
+
+#: src/main.cpp:107
+msgid "uses an Extech Power Analyzer for measurements"
+msgstr ""
+
+#: src/main.cpp:108 src/main.cpp:109
+msgid "[=FILENAME]"
+msgstr ""
+
+#: src/main.cpp:108
+msgid "generate a html report"
+msgstr ""
+
+#: src/main.cpp:109
+msgid "generate a csv report"
+msgstr ""
+
+#: src/main.cpp:110
+msgid "[=seconds]"
+msgstr ""
+
+#: src/main.cpp:110
+msgid "generate a report for 'x' seconds"
+msgstr ""
+
+#: src/main.cpp:111
+msgid "[=iterations] number of times to run each test"
+msgstr ""
+
+#: src/main.cpp:112
+msgid "print this help menu"
+msgstr ""
+
+#: src/main.cpp:114
+msgid "For more help please refer to the README"
+msgstr ""
+
+#: src/main.cpp:224
+#, c-format
+msgid "PowerTOP is out of memory. PowerTOP is Aborting"
+msgstr ""
+
+#: src/main.cpp:252
+#, c-format
+msgid "Preparing to take measurements\n"
+msgstr ""
+
+#: src/main.cpp:255
+#, c-format
+msgid "Taking %d measurement(s) for a duration of %d second(s) each.\n"
+msgstr ""
+
+#: src/main.cpp:278
+#, c-format
+msgid "PowerTOP "
+msgstr "PowerTOP "
+
+#: src/main.cpp:279 src/main.cpp:307
+#, c-format
+msgid "exiting...\n"
+msgstr "sortint...\n"
+
+#: src/main.cpp:306
+#, c-format
+msgid "Failed to mount debugfs!\n"
+msgstr ""
+
+#: src/main.cpp:443
+#, c-format
+msgid "Leaving PowerTOP"
+msgstr ""
diff --git a/po/cs_CZ.po b/po/cs_CZ.po
new file mode 100644 (file)
index 0000000..f27b538
--- /dev/null
@@ -0,0 +1,580 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR Intel Corporation
+# This file is distributed under the same license as the PACKAGE package.
+#
+# Translators:
+# Otto Bříza <otto.briza@gmail.com>, 2012.
+msgid ""
+msgstr ""
+"Project-Id-Version: PowerTOP\n"
+"Report-Msgid-Bugs-To: \"powertop@lists.01.org\"\n"
+"POT-Creation-Date: 2012-05-31 14:03-0700\n"
+"PO-Revision-Date: 2012-07-12 15:01+0000\n"
+"Last-Translator: Otto Bříza <otto.briza@gmail.com>\n"
+"Language-Team: Czech (Czech Republic) (http://www.transifex.com/projects/p/"
+"PowerTOP/language/cs_CZ/)\n"
+"Language: cs_CZ\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2\n"
+
+#: src/parameters/persistent.cpp:46 src/parameters/persistent.cpp:140
+msgid "Cannot save to file "
+msgstr "Nelze uložit do souboru"
+
+#: src/parameters/persistent.cpp:78 src/parameters/persistent.cpp:165
+msgid "Cannot load from file "
+msgstr "Nelze nahrát ze souboru"
+
+#: src/parameters/persistent.cpp:123
+#, c-format
+msgid "Loaded %i prior measurements\n"
+msgstr "Nahráno %i měření\n"
+
+#: src/display.cpp:71
+msgid "Overview"
+msgstr "Přehled"
+
+#: src/display.cpp:72
+msgid "Idle stats"
+msgstr "Nečinné"
+
+#: src/display.cpp:73
+msgid "Frequency stats"
+msgstr "Frekvence"
+
+#: src/display.cpp:74
+msgid "Device stats"
+msgstr "Zařízení"
+
+#: src/display.cpp:131
+msgid "Exit"
+msgstr "Konec"
+
+#: src/cpu/cpu_core.cpp:46 src/cpu/cpu_core.cpp:190 src/cpu/intel_cpus.cpp:296
+#, c-format
+msgid "  Core"
+msgstr "  Jádro"
+
+#: src/cpu/cpu_core.cpp:116 src/cpu/cpu_linux.cpp:329
+#: src/cpu/cpu_package.cpp:145 src/cpu/intel_cpus.cpp:222
+#: src/cpu/intel_cpus.cpp:457 src/cpu/intel_cpus.cpp:658
+msgid "Idle"
+msgstr "Nečinné"
+
+#: src/cpu/cpu_core.cpp:118 src/cpu/cpu_linux.cpp:331
+#: src/cpu/cpu_package.cpp:147 src/cpu/intel_cpus.cpp:224
+#: src/cpu/intel_cpus.cpp:459
+#, c-format
+msgid "Turbo Mode"
+msgstr "Turbo režim"
+
+#: src/cpu/cpu.cpp:90
+#, c-format
+msgid "cpu package %i"
+msgstr "cpu svazek %i"
+
+#: src/cpu/cpu.cpp:91
+msgid "cpu package"
+msgstr "cpu svazek"
+
+#: src/cpu/cpu.cpp:925
+#, c-format
+msgid "cpu_idle event returned no state?\n"
+msgstr "cpu_idle událost nevrátila stav?\n"
+
+#: src/cpu/cpu.cpp:940
+#, c-format
+msgid "power or cpu_frequecny event returned no state?\n"
+msgstr ""
+"power nebo cpu_frequecny událost nevrátila stav?\n"
+"\n"
+
+#: src/cpu/cpu_linux.cpp:92
+msgid "C0 polling"
+msgstr "C0 sdílení"
+
+#: src/cpu/cpu_linux.cpp:231 src/cpu/cpu_linux.cpp:289
+#: src/cpu/intel_cpus.cpp:605
+#, c-format
+msgid " CPU %i"
+msgstr " CPU %i"
+
+#: src/cpu/cpu_package.cpp:46
+#, c-format
+msgid "Package"
+msgstr "Balíček"
+
+#: src/cpu/cpu_package.cpp:104 src/cpu/intel_cpus.cpp:322
+#, c-format
+msgid "  Package"
+msgstr "  Balíček"
+
+#: src/cpu/intel_cpus.cpp:69
+#, c-format
+msgid "msr reg not found"
+msgstr "msr reg nenalezen"
+
+#: src/cpu/intel_cpus.cpp:79
+#, c-format
+msgid "pread cpu%d 0x%llx : "
+msgstr "pread cpu%d 0x%llx : "
+
+#: src/cpu/intel_cpus.cpp:529
+msgid "C0 active"
+msgstr "C0 aktivní"
+
+#: src/cpu/intel_cpus.cpp:588
+#, c-format
+msgid "Actual"
+msgstr "Aktuální"
+
+#: src/lib.cpp:257
+#, c-format
+msgid "%7sW"
+msgstr "%7sW"
+
+#: src/lib.cpp:260
+#, c-format
+msgid "    0 mW"
+msgstr "    0 mW"
+
+#: src/lib.cpp:369
+msgid "PS/2 Touchpad / Keyboard / Mouse"
+msgstr "PS/2 Touchpad / Klávesnice / Myš"
+
+#: src/lib.cpp:370
+msgid "SATA controller"
+msgstr "SATA ovladač"
+
+#: src/lib.cpp:371
+msgid "Intel built in USB hub"
+msgstr "Intel vestavěn v USB hubu"
+
+#: src/process/do_process.cpp:818
+#, c-format
+msgid ""
+"Estimated power: %5.1f    Measured power: %5.1f    Sum: %5.1f\n"
+"\n"
+msgstr ""
+"Odhad energie: %5.1f    Změřená energie: %5.1f    Součet: %5.1f\n"
+"\n"
+
+#: src/process/do_process.cpp:829 src/devices/device.cpp:171
+#, c-format
+msgid "The battery reports a discharge rate of %sW\n"
+msgstr "Hlášení stavu baterie %sW\n"
+
+#: src/process/do_process.cpp:834
+#, c-format
+msgid "The estimated remaining time is %i hours, %i minutes\n"
+msgstr "Odhadovaný zbývající čas je %i hodin, %i minut\n"
+
+#: src/process/do_process.cpp:842
+msgid "Summary"
+msgstr "Souhrn"
+
+#: src/process/do_process.cpp:842 src/process/do_process.cpp:1029
+msgid "wakeups/second"
+msgstr "probuzení/sekund"
+
+#: src/process/do_process.cpp:842
+msgid "GPU ops/seconds"
+msgstr "GPU ops/sekund"
+
+#: src/process/do_process.cpp:842
+msgid "VFS ops/sec and"
+msgstr "VFS ops/sec a"
+
+#: src/process/do_process.cpp:842 src/process/do_process.cpp:1030
+msgid "CPU use"
+msgstr "využití CPU"
+
+#: src/process/do_process.cpp:846 src/process/do_process.cpp:914
+#: src/process/do_process.cpp:1034
+msgid "Power est."
+msgstr "Energie zbývá"
+
+#: src/process/do_process.cpp:846 src/process/do_process.cpp:848
+#: src/process/do_process.cpp:914 src/process/do_process.cpp:917
+#: src/process/do_process.cpp:1034 src/process/do_process.cpp:1038
+msgid "Usage"
+msgstr "Využití"
+
+#: src/process/do_process.cpp:846 src/process/do_process.cpp:848
+#: src/process/do_process.cpp:1034 src/process/do_process.cpp:1038
+msgid "Events/s"
+msgstr "Událost/i"
+
+#: src/process/do_process.cpp:846 src/process/do_process.cpp:848
+#: src/process/do_process.cpp:914 src/process/do_process.cpp:917
+#: src/process/do_process.cpp:1034 src/process/do_process.cpp:1038
+msgid "Category"
+msgstr "Kategorie"
+
+#: src/process/do_process.cpp:846 src/process/do_process.cpp:848
+#: src/process/do_process.cpp:914 src/process/do_process.cpp:917
+#: src/process/do_process.cpp:1034 src/process/do_process.cpp:1038
+msgid "Description"
+msgstr "Popis"
+
+#: src/process/do_process.cpp:911
+msgid "Overview of Software Power Consumers"
+msgstr "Přehled uživatelů Software Power"
+
+#: src/process/do_process.cpp:914 src/process/do_process.cpp:917
+msgid "Wakeups/s"
+msgstr "Probuzení/s"
+
+#: src/process/do_process.cpp:914 src/process/do_process.cpp:917
+msgid "GPU ops/s"
+msgstr "GPU ops/s"
+
+#: src/process/do_process.cpp:914 src/process/do_process.cpp:917
+msgid "Disk IO/s"
+msgstr "Disk IO/s"
+
+#: src/process/do_process.cpp:914 src/process/do_process.cpp:917
+msgid "GFX Wakeups/s"
+msgstr "GFX Probuzení/s"
+
+#: src/process/do_process.cpp:1026
+msgid "Power Consumption Summary"
+msgstr "Souhrn spotřeby energie"
+
+#: src/process/do_process.cpp:1029
+msgid "GPU ops/second"
+msgstr "GPU ops/sekund"
+
+#: src/process/do_process.cpp:1030
+msgid "VFS ops/sec"
+msgstr "VFS ops/sekund"
+
+#: src/process/do_process.cpp:1030
+msgid "GFX wakes/sec and"
+msgstr "GFX probuzení/sek a"
+
+#: src/perf/perf.cpp:121
+#, c-format
+msgid "PowerTOP %s needs the kernel to support the 'perf' subsystem\n"
+msgstr "PowerTOP %s potřebuje kernel k podpoře 'perf' subsystému\n"
+
+#: src/perf/perf.cpp:122
+#, c-format
+msgid "as well as support for trace points in the kernel:\n"
+msgstr "stejně jako podpora pro sledované body v kernelu:\n"
+
+#: src/devices/device.cpp:177
+#, c-format
+msgid "System baseline power is estimated at %sW\n"
+msgstr "Systém základního napájení je odhadován na %sW\n"
+
+#: src/devices/device.cpp:184
+msgid "Power est.    Usage     Device name\n"
+msgstr "Odhadovaná energie.    Použití     Jméno zařízení\n"
+
+#: src/devices/device.cpp:186
+msgid "              Usage     Device name\n"
+msgstr "              Použití     Jméno zařízení\n"
+
+#: src/devices/alsa.cpp:79
+#, c-format
+msgid "Audio codec %s: %s (%s)"
+msgstr "Audio kodek %s: %s (%s)"
+
+#: src/devices/alsa.cpp:81 src/devices/alsa.cpp:83
+#, c-format
+msgid "Audio codec %s: %s"
+msgstr "Audio kodek %s: %s"
+
+#: src/devices/runtime_pm.cpp:225
+#, c-format
+msgid "PCI Device: %s"
+msgstr "PCI Zařízení: %s"
+
+#: src/devices/usb.cpp:51 src/devices/usb.cpp:94 src/devices/usb.cpp:96
+#, c-format
+msgid "USB device: %s"
+msgstr "USB zařízení: %s"
+
+#: src/devices/usb.cpp:92
+#, c-format
+msgid "USB device: %s (%s)"
+msgstr "USB zařízení: %s (%s)"
+
+#: src/devices/ahci.cpp:140
+#, c-format
+msgid "SATA link: %s"
+msgstr "SATA link: %s"
+
+#: src/devices/ahci.cpp:142
+#, c-format
+msgid "SATA disk: %s"
+msgstr "SATA disk: %s"
+
+#: src/devices/rfkill.cpp:65 src/devices/rfkill.cpp:69
+#, c-format
+msgid "Radio device: %s"
+msgstr "Radio zařízení: %s"
+
+#: src/devices/network.cpp:177
+#, c-format
+msgid "Network interface: %s (%s)"
+msgstr "Síťové rozhraní: %s (%s)"
+
+#: src/tuning/bluetooth.cpp:48
+#, c-format
+msgid "Bluetooth device interface status"
+msgstr "Status rozhraní bluetooth zařízení"
+
+#: src/tuning/cpufreq.cpp:43 src/tuning/ethernet.cpp:53
+#: src/tuning/tunable.cpp:48 src/tuning/wifi.cpp:45 src/tuning/runtime.cpp:41
+#: src/tuning/tuningusb.cpp:40 src/tuning/tuningsysfs.cpp:37
+msgid "Good"
+msgstr "Dobré"
+
+#: src/tuning/cpufreq.cpp:43 src/tuning/ethernet.cpp:53
+#: src/tuning/tunable.cpp:49 src/tuning/wifi.cpp:45 src/tuning/runtime.cpp:41
+#: src/tuning/tuningusb.cpp:40 src/tuning/tuningsysfs.cpp:37
+msgid "Bad"
+msgstr "Špatné"
+
+#: src/tuning/cpufreq.cpp:43 src/tuning/ethernet.cpp:53
+#: src/tuning/tunable.cpp:50 src/tuning/wifi.cpp:45 src/tuning/runtime.cpp:41
+#: src/tuning/tuningusb.cpp:40 src/tuning/tuningsysfs.cpp:37
+msgid "Unknown"
+msgstr "Neznámé"
+
+#: src/tuning/cpufreq.cpp:46
+#, c-format
+msgid "Using 'ondemand' cpufreq governor"
+msgstr "Užití 'ondemand' cpufreq regulátoru"
+
+#: src/tuning/tuning.cpp:60
+msgid "Enable Audio codec power management"
+msgstr "Zapnutí správy napájení audio kodeku"
+
+#: src/tuning/tuning.cpp:61
+msgid "Enable SATA link power management for /dev/sda"
+msgstr "Zapnutí správy napájení SATA linku pro /dev/sda"
+
+#: src/tuning/tuning.cpp:62
+msgid "NMI watchdog should be turned off"
+msgstr "Hlídací pes NMI by měl být vypnutý"
+
+#: src/tuning/tuning.cpp:63
+msgid "Power Aware CPU scheduler"
+msgstr "Power Aware CPU plánovač"
+
+#: src/tuning/tuning.cpp:64
+msgid "VM writeback timeout"
+msgstr "Vypršel čas VM writeback"
+
+#: src/tuning/tuning.cpp:82
+msgid "Tunables"
+msgstr "Měnitelné"
+
+#: src/tuning/tuning.cpp:82
+msgid " <ESC> Exit | <Enter> Toggle tunable | <r> Window refresh"
+msgstr " <ESC> Konec | <Enter> Přepnout změnitelné | <r> Obnovit okno"
+
+#: src/tuning/ethernet.cpp:57
+#, c-format
+msgid "Wake-on-lan status for device %s"
+msgstr "Wake-on-lan status zařízení %s"
+
+#: src/tuning/wifi.cpp:48
+#, c-format
+msgid "Wireless Power Saving for interface %s"
+msgstr "Úspora energie bezdrátových zařízení %s"
+
+#: src/tuning/runtime.cpp:47
+#, c-format
+msgid "Runtime PM for %s device %s"
+msgstr "Trvání PM pro %s zařízení %s"
+
+#: src/tuning/runtime.cpp:49
+#, c-format
+msgid "%s device %s has no runtime power management"
+msgstr "%s zařízení %s nemá spustitelnou správu napájení"
+
+#: src/tuning/runtime.cpp:73
+#, c-format
+msgid "PCI Device %s has no runtime power management"
+msgstr "PCI Zařízení %s nemá spustitelnou správu napájení"
+
+#: src/tuning/runtime.cpp:75
+#, c-format
+msgid "Runtime PM for PCI Device %s"
+msgstr "Trvání PM pro PCI zařízení %s"
+
+#: src/tuning/tuningusb.cpp:55
+#, c-format
+msgid "Autosuspend for unknown USB device %s (%s:%s)"
+msgstr "Automatické uspání pro neznámé USB zařízení %s (%s:%s)"
+
+#: src/tuning/tuningusb.cpp:72 src/tuning/tuningusb.cpp:74
+#: src/tuning/tuningusb.cpp:76
+#, c-format
+msgid "Autosuspend for USB device %s [%s]"
+msgstr "Automatické uspání pro USB zařízení %s [%s]"
+
+#: src/calibrate/calibrate.cpp:291
+#, c-format
+msgid "Cannot create temp file\n"
+msgstr "Nelze vytvořit dočasný soubor\n"
+
+#: src/calibrate/calibrate.cpp:310
+#, c-format
+msgid "Calibrating: CPU usage on %i threads\n"
+msgstr "Kalibrace: CPU použito na %i vláken\n"
+
+#: src/calibrate/calibrate.cpp:325
+#, c-format
+msgid "Calibrating: CPU wakeup power consumption\n"
+msgstr "Kalibrace: spotřeba energie na probuzení CPU\n"
+
+#: src/calibrate/calibrate.cpp:342
+#, c-format
+msgid "Calibrating USB devices\n"
+msgstr "Kalibrace USB zařízení\n"
+
+#: src/calibrate/calibrate.cpp:344 src/calibrate/calibrate.cpp:361
+#: src/calibrate/calibrate.cpp:369 src/calibrate/calibrate.cpp:386
+#, c-format
+msgid ".... device %s \n"
+msgstr ".... zařízení %s \n"
+
+#: src/calibrate/calibrate.cpp:359
+#, c-format
+msgid "Calibrating radio devices\n"
+msgstr "Kalibrace radio zařízení\n"
+
+#: src/calibrate/calibrate.cpp:383
+#, c-format
+msgid "Calibrating backlight\n"
+msgstr "Kalibrace podsvícení\n"
+
+#: src/calibrate/calibrate.cpp:407 src/calibrate/calibrate.cpp:415
+#, c-format
+msgid "Calibrating idle\n"
+msgstr "Kalibrace nečinnosti\n"
+
+#: src/calibrate/calibrate.cpp:426
+#, c-format
+msgid "Calibrating: disk usage \n"
+msgstr "Kalibrace: užití disku \n"
+
+#: src/calibrate/calibrate.cpp:451
+msgid "Starting PowerTOP power estimate calibration \n"
+msgstr "Začínání kalibrace odhadování energie PowerTOP\n"
+
+#: src/calibrate/calibrate.cpp:474
+msgid "Finishing PowerTOP power estimate calibration \n"
+msgstr "Ukončování kalibrace odhadování energie PowerTOP\n"
+
+#: src/calibrate/calibrate.cpp:478
+#, c-format
+msgid "Parameters after calibration:\n"
+msgstr "Parametry po kalibraci:\n"
+
+#: src/main.cpp:84
+#, c-format
+msgid "PowerTOP version"
+msgstr "PowerTOP verze"
+
+#: src/main.cpp:90
+msgid "Set refresh time out"
+msgstr "Nastavit čas obnovení"
+
+#: src/main.cpp:103
+msgid "Usage: powertop [OPTIONS]"
+msgstr "Použití: powertop [VOLBY]"
+
+#: src/main.cpp:104
+msgid "run in \"debug\" mode"
+msgstr "běh v \"debug\" módu"
+
+#: src/main.cpp:105
+msgid "print version information"
+msgstr "vypíše informace o verzi"
+
+#: src/main.cpp:106
+msgid "runs powertop in calibration mode"
+msgstr "běh powertopu v kalibračním režimu"
+
+#: src/main.cpp:107
+msgid "[=devnode]"
+msgstr "[=devnode]"
+
+#: src/main.cpp:107
+msgid "uses an Extech Power Analyzer for measurements"
+msgstr "využití Extech Power Analyzéru pro měření"
+
+#: src/main.cpp:108 src/main.cpp:109
+msgid "[=FILENAME]"
+msgstr "[=JMENOSOUBORU]"
+
+#: src/main.cpp:108
+msgid "generate a html report"
+msgstr "vytvoření html hlášení"
+
+#: src/main.cpp:109
+msgid "generate a csv report"
+msgstr "vytvoření csv hlášení"
+
+#: src/main.cpp:110
+msgid "[=seconds]"
+msgstr "[=sekundy]"
+
+#: src/main.cpp:110
+msgid "generate a report for 'x' seconds"
+msgstr "vytvoření hlášení pro \"x\" sekund"
+
+#: src/main.cpp:111
+msgid "[=iterations] number of times to run each test"
+msgstr "[=iterace] počet spuštění každého testu"
+
+#: src/main.cpp:112
+msgid "print this help menu"
+msgstr "vypiš tuto nápovědu"
+
+#: src/main.cpp:114
+msgid "For more help please refer to the README"
+msgstr "Pro více nápovědy přejděte prosím do README"
+
+#: src/main.cpp:224
+#, c-format
+msgid "PowerTOP is out of memory. PowerTOP is Aborting"
+msgstr "PowerTOPu došla paměť. Power TOP je přerušen."
+
+#: src/main.cpp:252
+#, c-format
+msgid "Preparing to take measurements\n"
+msgstr "Příprava k měření\n"
+
+#: src/main.cpp:255
+#, c-format
+msgid "Taking %d measurement(s) for a duration of %d second(s) each.\n"
+msgstr "Změřeno %d výsledků za dobu trvání %d vteřin každý.\n"
+
+#: src/main.cpp:278
+#, c-format
+msgid "PowerTOP "
+msgstr "PowerTOP "
+
+#: src/main.cpp:279 src/main.cpp:307
+#, c-format
+msgid "exiting...\n"
+msgstr "ukončuji...\n"
+
+#: src/main.cpp:306
+#, c-format
+msgid "Failed to mount debugfs!\n"
+msgstr "Selhalo připojení debugfs!\n"
+
+#: src/main.cpp:443
+#, c-format
+msgid "Leaving PowerTOP"
+msgstr "Ukončuji PowerTOP. Přeji hezký den"
diff --git a/po/de_DE.po b/po/de_DE.po
new file mode 100644 (file)
index 0000000..1b95e96
--- /dev/null
@@ -0,0 +1,579 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR Intel Corporation
+# This file is distributed under the same license as the PACKAGE package.
+#
+# Translators:
+# Fabian Affolter <fab@fedoraproject.org>, 2011.
+#   <ulf.hofemeier@intel.com>, 2012.
+msgid ""
+msgstr ""
+"Project-Id-Version: PowerTOP\n"
+"Report-Msgid-Bugs-To: \"powertop@lists.01.org\"\n"
+"POT-Creation-Date: 2012-05-31 14:03-0700\n"
+"PO-Revision-Date: 2012-05-31 22:35+0000\n"
+"Last-Translator: Patrick McCarty <patrick.mccarty@linux.intel.com>\n"
+"Language-Team: German (Germany) (http://www.transifex.com/projects/p/"
+"PowerTOP/language/de_DE/)\n"
+"Language: de_DE\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1)\n"
+
+#: src/parameters/persistent.cpp:46 src/parameters/persistent.cpp:140
+msgid "Cannot save to file "
+msgstr "Kann Datei nicht abspeichern"
+
+#: src/parameters/persistent.cpp:78 src/parameters/persistent.cpp:165
+msgid "Cannot load from file "
+msgstr "Kann nicht von Datei laden"
+
+#: src/parameters/persistent.cpp:123
+#, c-format
+msgid "Loaded %i prior measurements\n"
+msgstr ""
+
+#: src/display.cpp:71
+msgid "Overview"
+msgstr "Übersicht"
+
+#: src/display.cpp:72
+msgid "Idle stats"
+msgstr "Leerlauf-Statistiken"
+
+#: src/display.cpp:73
+msgid "Frequency stats"
+msgstr "Frequenz-Statistiken"
+
+#: src/display.cpp:74
+msgid "Device stats"
+msgstr "Gerät-Statistiken"
+
+#: src/display.cpp:131
+msgid "Exit"
+msgstr ""
+
+#: src/cpu/cpu_core.cpp:46 src/cpu/cpu_core.cpp:190 src/cpu/intel_cpus.cpp:296
+#, c-format
+msgid "  Core"
+msgstr "Prozessorkern"
+
+#: src/cpu/cpu_core.cpp:116 src/cpu/cpu_linux.cpp:329
+#: src/cpu/cpu_package.cpp:145 src/cpu/intel_cpus.cpp:222
+#: src/cpu/intel_cpus.cpp:457 src/cpu/intel_cpus.cpp:658
+msgid "Idle"
+msgstr "Leerlauf"
+
+#: src/cpu/cpu_core.cpp:118 src/cpu/cpu_linux.cpp:331
+#: src/cpu/cpu_package.cpp:147 src/cpu/intel_cpus.cpp:224
+#: src/cpu/intel_cpus.cpp:459
+#, c-format
+msgid "Turbo Mode"
+msgstr "Turbo-Modus"
+
+#: src/cpu/cpu.cpp:90
+#, c-format
+msgid "cpu package %i"
+msgstr "CPU-Paket %i"
+
+#: src/cpu/cpu.cpp:91
+msgid "cpu package"
+msgstr "CPU-Paket"
+
+#: src/cpu/cpu.cpp:925
+#, c-format
+msgid "cpu_idle event returned no state?\n"
+msgstr ""
+
+#: src/cpu/cpu.cpp:940
+#, c-format
+msgid "power or cpu_frequecny event returned no state?\n"
+msgstr ""
+
+#: src/cpu/cpu_linux.cpp:92
+msgid "C0 polling"
+msgstr "C0 sammeln"
+
+#: src/cpu/cpu_linux.cpp:231 src/cpu/cpu_linux.cpp:289
+#: src/cpu/intel_cpus.cpp:605
+#, c-format
+msgid " CPU %i"
+msgstr " CPU %i"
+
+#: src/cpu/cpu_package.cpp:46
+#, c-format
+msgid "Package"
+msgstr "Paket"
+
+#: src/cpu/cpu_package.cpp:104 src/cpu/intel_cpus.cpp:322
+#, c-format
+msgid "  Package"
+msgstr "Paket"
+
+#: src/cpu/intel_cpus.cpp:69
+#, c-format
+msgid "msr reg not found"
+msgstr ""
+
+#: src/cpu/intel_cpus.cpp:79
+#, c-format
+msgid "pread cpu%d 0x%llx : "
+msgstr ""
+
+#: src/cpu/intel_cpus.cpp:529
+msgid "C0 active"
+msgstr "C0 aktiv"
+
+#: src/cpu/intel_cpus.cpp:588
+#, c-format
+msgid "Actual"
+msgstr "Aktuell"
+
+#: src/lib.cpp:257
+#, c-format
+msgid "%7sW"
+msgstr "%7sW"
+
+#: src/lib.cpp:260
+#, c-format
+msgid "    0 mW"
+msgstr "    0 mW"
+
+#: src/lib.cpp:369
+msgid "PS/2 Touchpad / Keyboard / Mouse"
+msgstr ""
+
+#: src/lib.cpp:370
+msgid "SATA controller"
+msgstr "SATA-Controller"
+
+#: src/lib.cpp:371
+msgid "Intel built in USB hub"
+msgstr "Intel integrierter USB Hub"
+
+#: src/process/do_process.cpp:818
+#, c-format
+msgid ""
+"Estimated power: %5.1f    Measured power: %5.1f    Sum: %5.1f\n"
+"\n"
+msgstr ""
+"Geschätzter Stromverbrauch: %5.1f    Gemessener Stromverbrauch: %5.1f    "
+"Summe: %5.1f\\n\n"
+
+#: src/process/do_process.cpp:829 src/devices/device.cpp:171
+#, c-format
+msgid "The battery reports a discharge rate of %sW\n"
+msgstr ""
+
+#: src/process/do_process.cpp:834
+#, c-format
+msgid "The estimated remaining time is %i hours, %i minutes\n"
+msgstr ""
+
+#: src/process/do_process.cpp:842
+msgid "Summary"
+msgstr ""
+
+#: src/process/do_process.cpp:842 src/process/do_process.cpp:1029
+msgid "wakeups/second"
+msgstr ""
+
+#: src/process/do_process.cpp:842
+msgid "GPU ops/seconds"
+msgstr ""
+
+#: src/process/do_process.cpp:842
+msgid "VFS ops/sec and"
+msgstr ""
+
+#: src/process/do_process.cpp:842 src/process/do_process.cpp:1030
+msgid "CPU use"
+msgstr ""
+
+#: src/process/do_process.cpp:846 src/process/do_process.cpp:914
+#: src/process/do_process.cpp:1034
+msgid "Power est."
+msgstr ""
+
+#: src/process/do_process.cpp:846 src/process/do_process.cpp:848
+#: src/process/do_process.cpp:914 src/process/do_process.cpp:917
+#: src/process/do_process.cpp:1034 src/process/do_process.cpp:1038
+msgid "Usage"
+msgstr ""
+
+#: src/process/do_process.cpp:846 src/process/do_process.cpp:848
+#: src/process/do_process.cpp:1034 src/process/do_process.cpp:1038
+msgid "Events/s"
+msgstr ""
+
+#: src/process/do_process.cpp:846 src/process/do_process.cpp:848
+#: src/process/do_process.cpp:914 src/process/do_process.cpp:917
+#: src/process/do_process.cpp:1034 src/process/do_process.cpp:1038
+msgid "Category"
+msgstr ""
+
+#: src/process/do_process.cpp:846 src/process/do_process.cpp:848
+#: src/process/do_process.cpp:914 src/process/do_process.cpp:917
+#: src/process/do_process.cpp:1034 src/process/do_process.cpp:1038
+msgid "Description"
+msgstr ""
+
+#: src/process/do_process.cpp:911
+msgid "Overview of Software Power Consumers"
+msgstr ""
+
+#: src/process/do_process.cpp:914 src/process/do_process.cpp:917
+msgid "Wakeups/s"
+msgstr ""
+
+#: src/process/do_process.cpp:914 src/process/do_process.cpp:917
+msgid "GPU ops/s"
+msgstr ""
+
+#: src/process/do_process.cpp:914 src/process/do_process.cpp:917
+msgid "Disk IO/s"
+msgstr ""
+
+#: src/process/do_process.cpp:914 src/process/do_process.cpp:917
+msgid "GFX Wakeups/s"
+msgstr ""
+
+#: src/process/do_process.cpp:1026
+msgid "Power Consumption Summary"
+msgstr ""
+
+#: src/process/do_process.cpp:1029
+msgid "GPU ops/second"
+msgstr ""
+
+#: src/process/do_process.cpp:1030
+msgid "VFS ops/sec"
+msgstr ""
+
+#: src/process/do_process.cpp:1030
+msgid "GFX wakes/sec and"
+msgstr ""
+
+#: src/perf/perf.cpp:121
+#, c-format
+msgid "PowerTOP %s needs the kernel to support the 'perf' subsystem\n"
+msgstr ""
+
+#: src/perf/perf.cpp:122
+#, c-format
+msgid "as well as support for trace points in the kernel:\n"
+msgstr ""
+
+#: src/devices/device.cpp:177
+#, c-format
+msgid "System baseline power is estimated at %sW\n"
+msgstr ""
+
+#: src/devices/device.cpp:184
+msgid "Power est.    Usage     Device name\n"
+msgstr ""
+
+#: src/devices/device.cpp:186
+msgid "              Usage     Device name\n"
+msgstr ""
+
+#: src/devices/alsa.cpp:79
+#, c-format
+msgid "Audio codec %s: %s (%s)"
+msgstr ""
+
+#: src/devices/alsa.cpp:81 src/devices/alsa.cpp:83
+#, c-format
+msgid "Audio codec %s: %s"
+msgstr ""
+
+#: src/devices/runtime_pm.cpp:225
+#, c-format
+msgid "PCI Device: %s"
+msgstr ""
+
+#: src/devices/usb.cpp:51 src/devices/usb.cpp:94 src/devices/usb.cpp:96
+#, c-format
+msgid "USB device: %s"
+msgstr "USB-Gerät: %s"
+
+#: src/devices/usb.cpp:92
+#, c-format
+msgid "USB device: %s (%s)"
+msgstr "USB-Gerät: %s (%s)"
+
+#: src/devices/ahci.cpp:140
+#, c-format
+msgid "SATA link: %s"
+msgstr "SATA-Verbindung: %s"
+
+#: src/devices/ahci.cpp:142
+#, c-format
+msgid "SATA disk: %s"
+msgstr "SATA-Festplatte: %s"
+
+#: src/devices/rfkill.cpp:65 src/devices/rfkill.cpp:69
+#, c-format
+msgid "Radio device: %s"
+msgstr "Funk-Gerät:%s"
+
+#: src/devices/network.cpp:177
+#, c-format
+msgid "Network interface: %s (%s)"
+msgstr "Netzwerkschnittstelle: %s (%s)"
+
+#: src/tuning/bluetooth.cpp:48
+#, c-format
+msgid "Bluetooth device interface status"
+msgstr ""
+
+#: src/tuning/cpufreq.cpp:43 src/tuning/ethernet.cpp:53
+#: src/tuning/tunable.cpp:48 src/tuning/wifi.cpp:45 src/tuning/runtime.cpp:41
+#: src/tuning/tuningusb.cpp:40 src/tuning/tuningsysfs.cpp:37
+msgid "Good"
+msgstr "Gut"
+
+#: src/tuning/cpufreq.cpp:43 src/tuning/ethernet.cpp:53
+#: src/tuning/tunable.cpp:49 src/tuning/wifi.cpp:45 src/tuning/runtime.cpp:41
+#: src/tuning/tuningusb.cpp:40 src/tuning/tuningsysfs.cpp:37
+msgid "Bad"
+msgstr "Schlecht"
+
+#: src/tuning/cpufreq.cpp:43 src/tuning/ethernet.cpp:53
+#: src/tuning/tunable.cpp:50 src/tuning/wifi.cpp:45 src/tuning/runtime.cpp:41
+#: src/tuning/tuningusb.cpp:40 src/tuning/tuningsysfs.cpp:37
+msgid "Unknown"
+msgstr "Unbekannt"
+
+#: src/tuning/cpufreq.cpp:46
+#, c-format
+msgid "Using 'ondemand' cpufreq governor"
+msgstr ""
+
+#: src/tuning/tuning.cpp:60
+msgid "Enable Audio codec power management"
+msgstr ""
+
+#: src/tuning/tuning.cpp:61
+msgid "Enable SATA link power management for /dev/sda"
+msgstr ""
+
+#: src/tuning/tuning.cpp:62
+msgid "NMI watchdog should be turned off"
+msgstr ""
+
+#: src/tuning/tuning.cpp:63
+msgid "Power Aware CPU scheduler"
+msgstr ""
+
+#: src/tuning/tuning.cpp:64
+msgid "VM writeback timeout"
+msgstr ""
+
+#: src/tuning/tuning.cpp:82
+msgid "Tunables"
+msgstr ""
+
+#: src/tuning/tuning.cpp:82
+msgid " <ESC> Exit | <Enter> Toggle tunable | <r> Window refresh"
+msgstr ""
+
+#: src/tuning/ethernet.cpp:57
+#, c-format
+msgid "Wake-on-lan status for device %s"
+msgstr ""
+
+#: src/tuning/wifi.cpp:48
+#, c-format
+msgid "Wireless Power Saving for interface %s"
+msgstr ""
+
+#: src/tuning/runtime.cpp:47
+#, c-format
+msgid "Runtime PM for %s device %s"
+msgstr ""
+
+#: src/tuning/runtime.cpp:49
+#, c-format
+msgid "%s device %s has no runtime power management"
+msgstr ""
+
+#: src/tuning/runtime.cpp:73
+#, c-format
+msgid "PCI Device %s has no runtime power management"
+msgstr ""
+
+#: src/tuning/runtime.cpp:75
+#, c-format
+msgid "Runtime PM for PCI Device %s"
+msgstr ""
+
+#: src/tuning/tuningusb.cpp:55
+#, c-format
+msgid "Autosuspend for unknown USB device %s (%s:%s)"
+msgstr ""
+
+#: src/tuning/tuningusb.cpp:72 src/tuning/tuningusb.cpp:74
+#: src/tuning/tuningusb.cpp:76
+#, c-format
+msgid "Autosuspend for USB device %s [%s]"
+msgstr ""
+
+#: src/calibrate/calibrate.cpp:291
+#, c-format
+msgid "Cannot create temp file\n"
+msgstr ""
+
+#: src/calibrate/calibrate.cpp:310
+#, c-format
+msgid "Calibrating: CPU usage on %i threads\n"
+msgstr ""
+
+#: src/calibrate/calibrate.cpp:325
+#, c-format
+msgid "Calibrating: CPU wakeup power consumption\n"
+msgstr ""
+
+#: src/calibrate/calibrate.cpp:342
+#, c-format
+msgid "Calibrating USB devices\n"
+msgstr ""
+
+#: src/calibrate/calibrate.cpp:344 src/calibrate/calibrate.cpp:361
+#: src/calibrate/calibrate.cpp:369 src/calibrate/calibrate.cpp:386
+#, c-format
+msgid ".... device %s \n"
+msgstr ""
+
+#: src/calibrate/calibrate.cpp:359
+#, c-format
+msgid "Calibrating radio devices\n"
+msgstr ""
+
+#: src/calibrate/calibrate.cpp:383
+#, c-format
+msgid "Calibrating backlight\n"
+msgstr ""
+
+#: src/calibrate/calibrate.cpp:407 src/calibrate/calibrate.cpp:415
+#, c-format
+msgid "Calibrating idle\n"
+msgstr ""
+
+#: src/calibrate/calibrate.cpp:426
+#, c-format
+msgid "Calibrating: disk usage \n"
+msgstr ""
+
+#: src/calibrate/calibrate.cpp:451
+msgid "Starting PowerTOP power estimate calibration \n"
+msgstr ""
+
+#: src/calibrate/calibrate.cpp:474
+msgid "Finishing PowerTOP power estimate calibration \n"
+msgstr ""
+
+#: src/calibrate/calibrate.cpp:478
+#, c-format
+msgid "Parameters after calibration:\n"
+msgstr ""
+
+#: src/main.cpp:84
+#, c-format
+msgid "PowerTOP version"
+msgstr ""
+
+#: src/main.cpp:90
+msgid "Set refresh time out"
+msgstr ""
+
+#: src/main.cpp:103
+msgid "Usage: powertop [OPTIONS]"
+msgstr ""
+
+#: src/main.cpp:104
+msgid "run in \"debug\" mode"
+msgstr ""
+
+#: src/main.cpp:105
+msgid "print version information"
+msgstr ""
+
+#: src/main.cpp:106
+msgid "runs powertop in calibration mode"
+msgstr ""
+
+#: src/main.cpp:107
+msgid "[=devnode]"
+msgstr ""
+
+#: src/main.cpp:107
+msgid "uses an Extech Power Analyzer for measurements"
+msgstr ""
+
+#: src/main.cpp:108 src/main.cpp:109
+msgid "[=FILENAME]"
+msgstr ""
+
+#: src/main.cpp:108
+msgid "generate a html report"
+msgstr ""
+
+#: src/main.cpp:109
+msgid "generate a csv report"
+msgstr ""
+
+#: src/main.cpp:110
+msgid "[=seconds]"
+msgstr ""
+
+#: src/main.cpp:110
+msgid "generate a report for 'x' seconds"
+msgstr ""
+
+#: src/main.cpp:111
+msgid "[=iterations] number of times to run each test"
+msgstr ""
+
+#: src/main.cpp:112
+msgid "print this help menu"
+msgstr ""
+
+#: src/main.cpp:114
+msgid "For more help please refer to the README"
+msgstr ""
+
+#: src/main.cpp:224
+#, c-format
+msgid "PowerTOP is out of memory. PowerTOP is Aborting"
+msgstr ""
+
+#: src/main.cpp:252
+#, c-format
+msgid "Preparing to take measurements\n"
+msgstr ""
+
+#: src/main.cpp:255
+#, c-format
+msgid "Taking %d measurement(s) for a duration of %d second(s) each.\n"
+msgstr ""
+
+#: src/main.cpp:278
+#, c-format
+msgid "PowerTOP "
+msgstr "PowerTOP "
+
+#: src/main.cpp:279 src/main.cpp:307
+#, c-format
+msgid "exiting...\n"
+msgstr "Verlassen ...\n"
+
+#: src/main.cpp:306
+#, c-format
+msgid "Failed to mount debugfs!\n"
+msgstr ""
+
+#: src/main.cpp:443
+#, c-format
+msgid "Leaving PowerTOP"
+msgstr ""
diff --git a/po/en_GB.po b/po/en_GB.po
new file mode 100644 (file)
index 0000000..37659a2
--- /dev/null
@@ -0,0 +1,578 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR Intel Corporation
+# This file is distributed under the same license as the PACKAGE package.
+#
+# Translators:
+# Margie Foster <margie@linux.intel.com>, 2012.
+msgid ""
+msgstr ""
+"Project-Id-Version: PowerTOP\n"
+"Report-Msgid-Bugs-To: \"powertop@lists.01.org\"\n"
+"POT-Creation-Date: 2012-05-31 14:03-0700\n"
+"PO-Revision-Date: 2012-05-31 22:35+0000\n"
+"Last-Translator: Patrick McCarty <patrick.mccarty@linux.intel.com>\n"
+"Language-Team: English (United Kingdom) (http://www.transifex.com/projects/p/"
+"PowerTOP/language/en_GB/)\n"
+"Language: en_GB\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1)\n"
+
+#: src/parameters/persistent.cpp:46 src/parameters/persistent.cpp:140
+msgid "Cannot save to file "
+msgstr "Cannot save to file "
+
+#: src/parameters/persistent.cpp:78 src/parameters/persistent.cpp:165
+msgid "Cannot load from file "
+msgstr "Cannot load from file "
+
+#: src/parameters/persistent.cpp:123
+#, c-format
+msgid "Loaded %i prior measurements\n"
+msgstr "Loaded %i prior measurements\n"
+
+#: src/display.cpp:71
+msgid "Overview"
+msgstr "Overview"
+
+#: src/display.cpp:72
+msgid "Idle stats"
+msgstr "Idle stats"
+
+#: src/display.cpp:73
+msgid "Frequency stats"
+msgstr "Frequency stats"
+
+#: src/display.cpp:74
+msgid "Device stats"
+msgstr "Device stats"
+
+#: src/display.cpp:131
+msgid "Exit"
+msgstr ""
+
+#: src/cpu/cpu_core.cpp:46 src/cpu/cpu_core.cpp:190 src/cpu/intel_cpus.cpp:296
+#, c-format
+msgid "  Core"
+msgstr "  Core"
+
+#: src/cpu/cpu_core.cpp:116 src/cpu/cpu_linux.cpp:329
+#: src/cpu/cpu_package.cpp:145 src/cpu/intel_cpus.cpp:222
+#: src/cpu/intel_cpus.cpp:457 src/cpu/intel_cpus.cpp:658
+msgid "Idle"
+msgstr "Idle"
+
+#: src/cpu/cpu_core.cpp:118 src/cpu/cpu_linux.cpp:331
+#: src/cpu/cpu_package.cpp:147 src/cpu/intel_cpus.cpp:224
+#: src/cpu/intel_cpus.cpp:459
+#, c-format
+msgid "Turbo Mode"
+msgstr "Turbo Mode"
+
+#: src/cpu/cpu.cpp:90
+#, c-format
+msgid "cpu package %i"
+msgstr "CPU package %i"
+
+#: src/cpu/cpu.cpp:91
+msgid "cpu package"
+msgstr "CPU package"
+
+#: src/cpu/cpu.cpp:925
+#, c-format
+msgid "cpu_idle event returned no state?\n"
+msgstr ""
+
+#: src/cpu/cpu.cpp:940
+#, c-format
+msgid "power or cpu_frequecny event returned no state?\n"
+msgstr ""
+
+#: src/cpu/cpu_linux.cpp:92
+msgid "C0 polling"
+msgstr "C0 polling"
+
+#: src/cpu/cpu_linux.cpp:231 src/cpu/cpu_linux.cpp:289
+#: src/cpu/intel_cpus.cpp:605
+#, c-format
+msgid " CPU %i"
+msgstr " CPU %i"
+
+#: src/cpu/cpu_package.cpp:46
+#, c-format
+msgid "Package"
+msgstr "Package"
+
+#: src/cpu/cpu_package.cpp:104 src/cpu/intel_cpus.cpp:322
+#, c-format
+msgid "  Package"
+msgstr "  Package"
+
+#: src/cpu/intel_cpus.cpp:69
+#, c-format
+msgid "msr reg not found"
+msgstr ""
+
+#: src/cpu/intel_cpus.cpp:79
+#, c-format
+msgid "pread cpu%d 0x%llx : "
+msgstr ""
+
+#: src/cpu/intel_cpus.cpp:529
+msgid "C0 active"
+msgstr "C0 active"
+
+#: src/cpu/intel_cpus.cpp:588
+#, c-format
+msgid "Actual"
+msgstr "Actual"
+
+#: src/lib.cpp:257
+#, c-format
+msgid "%7sW"
+msgstr "%7sW"
+
+#: src/lib.cpp:260
+#, c-format
+msgid "    0 mW"
+msgstr "    0 mW"
+
+#: src/lib.cpp:369
+msgid "PS/2 Touchpad / Keyboard / Mouse"
+msgstr "PS/2 Touchpad / Keyboard / Mouse"
+
+#: src/lib.cpp:370
+msgid "SATA controller"
+msgstr "SATA controller"
+
+#: src/lib.cpp:371
+msgid "Intel built in USB hub"
+msgstr "Intel built in USB hub"
+
+#: src/process/do_process.cpp:818
+#, c-format
+msgid ""
+"Estimated power: %5.1f    Measured power: %5.1f    Sum: %5.1f\n"
+"\n"
+msgstr ""
+"Estimated power: %5.1f    Measured power: %5.1f    Sum: %5.1f\n"
+"\n"
+
+#: src/process/do_process.cpp:829 src/devices/device.cpp:171
+#, c-format
+msgid "The battery reports a discharge rate of %sW\n"
+msgstr "The battery reports a discharge rate of %sW\n"
+
+#: src/process/do_process.cpp:834
+#, c-format
+msgid "The estimated remaining time is %i hours, %i minutes\n"
+msgstr ""
+
+#: src/process/do_process.cpp:842
+msgid "Summary"
+msgstr ""
+
+#: src/process/do_process.cpp:842 src/process/do_process.cpp:1029
+msgid "wakeups/second"
+msgstr ""
+
+#: src/process/do_process.cpp:842
+msgid "GPU ops/seconds"
+msgstr ""
+
+#: src/process/do_process.cpp:842
+msgid "VFS ops/sec and"
+msgstr ""
+
+#: src/process/do_process.cpp:842 src/process/do_process.cpp:1030
+msgid "CPU use"
+msgstr ""
+
+#: src/process/do_process.cpp:846 src/process/do_process.cpp:914
+#: src/process/do_process.cpp:1034
+msgid "Power est."
+msgstr ""
+
+#: src/process/do_process.cpp:846 src/process/do_process.cpp:848
+#: src/process/do_process.cpp:914 src/process/do_process.cpp:917
+#: src/process/do_process.cpp:1034 src/process/do_process.cpp:1038
+msgid "Usage"
+msgstr ""
+
+#: src/process/do_process.cpp:846 src/process/do_process.cpp:848
+#: src/process/do_process.cpp:1034 src/process/do_process.cpp:1038
+msgid "Events/s"
+msgstr ""
+
+#: src/process/do_process.cpp:846 src/process/do_process.cpp:848
+#: src/process/do_process.cpp:914 src/process/do_process.cpp:917
+#: src/process/do_process.cpp:1034 src/process/do_process.cpp:1038
+msgid "Category"
+msgstr ""
+
+#: src/process/do_process.cpp:846 src/process/do_process.cpp:848
+#: src/process/do_process.cpp:914 src/process/do_process.cpp:917
+#: src/process/do_process.cpp:1034 src/process/do_process.cpp:1038
+msgid "Description"
+msgstr ""
+
+#: src/process/do_process.cpp:911
+msgid "Overview of Software Power Consumers"
+msgstr ""
+
+#: src/process/do_process.cpp:914 src/process/do_process.cpp:917
+msgid "Wakeups/s"
+msgstr ""
+
+#: src/process/do_process.cpp:914 src/process/do_process.cpp:917
+msgid "GPU ops/s"
+msgstr ""
+
+#: src/process/do_process.cpp:914 src/process/do_process.cpp:917
+msgid "Disk IO/s"
+msgstr ""
+
+#: src/process/do_process.cpp:914 src/process/do_process.cpp:917
+msgid "GFX Wakeups/s"
+msgstr ""
+
+#: src/process/do_process.cpp:1026
+msgid "Power Consumption Summary"
+msgstr ""
+
+#: src/process/do_process.cpp:1029
+msgid "GPU ops/second"
+msgstr ""
+
+#: src/process/do_process.cpp:1030
+msgid "VFS ops/sec"
+msgstr ""
+
+#: src/process/do_process.cpp:1030
+msgid "GFX wakes/sec and"
+msgstr ""
+
+#: src/perf/perf.cpp:121
+#, c-format
+msgid "PowerTOP %s needs the kernel to support the 'perf' subsystem\n"
+msgstr "PowerTOP %s needs the kernel to support the 'perf' subsystem\n"
+
+#: src/perf/perf.cpp:122
+#, c-format
+msgid "as well as support for trace points in the kernel:\n"
+msgstr "as well as support for trace points in the kernel:\n"
+
+#: src/devices/device.cpp:177
+#, c-format
+msgid "System baseline power is estimated at %sW\n"
+msgstr "System baseline power is estimated at %sW\n"
+
+#: src/devices/device.cpp:184
+msgid "Power est.    Usage     Device name\n"
+msgstr "Power est.    Usage     Device name\n"
+
+#: src/devices/device.cpp:186
+msgid "              Usage     Device name\n"
+msgstr ""
+
+#: src/devices/alsa.cpp:79
+#, c-format
+msgid "Audio codec %s: %s (%s)"
+msgstr ""
+
+#: src/devices/alsa.cpp:81 src/devices/alsa.cpp:83
+#, c-format
+msgid "Audio codec %s: %s"
+msgstr ""
+
+#: src/devices/runtime_pm.cpp:225
+#, c-format
+msgid "PCI Device: %s"
+msgstr ""
+
+#: src/devices/usb.cpp:51 src/devices/usb.cpp:94 src/devices/usb.cpp:96
+#, c-format
+msgid "USB device: %s"
+msgstr ""
+
+#: src/devices/usb.cpp:92
+#, c-format
+msgid "USB device: %s (%s)"
+msgstr ""
+
+#: src/devices/ahci.cpp:140
+#, c-format
+msgid "SATA link: %s"
+msgstr ""
+
+#: src/devices/ahci.cpp:142
+#, c-format
+msgid "SATA disk: %s"
+msgstr ""
+
+#: src/devices/rfkill.cpp:65 src/devices/rfkill.cpp:69
+#, c-format
+msgid "Radio device: %s"
+msgstr ""
+
+#: src/devices/network.cpp:177
+#, c-format
+msgid "Network interface: %s (%s)"
+msgstr ""
+
+#: src/tuning/bluetooth.cpp:48
+#, c-format
+msgid "Bluetooth device interface status"
+msgstr ""
+
+#: src/tuning/cpufreq.cpp:43 src/tuning/ethernet.cpp:53
+#: src/tuning/tunable.cpp:48 src/tuning/wifi.cpp:45 src/tuning/runtime.cpp:41
+#: src/tuning/tuningusb.cpp:40 src/tuning/tuningsysfs.cpp:37
+msgid "Good"
+msgstr ""
+
+#: src/tuning/cpufreq.cpp:43 src/tuning/ethernet.cpp:53
+#: src/tuning/tunable.cpp:49 src/tuning/wifi.cpp:45 src/tuning/runtime.cpp:41
+#: src/tuning/tuningusb.cpp:40 src/tuning/tuningsysfs.cpp:37
+msgid "Bad"
+msgstr ""
+
+#: src/tuning/cpufreq.cpp:43 src/tuning/ethernet.cpp:53
+#: src/tuning/tunable.cpp:50 src/tuning/wifi.cpp:45 src/tuning/runtime.cpp:41
+#: src/tuning/tuningusb.cpp:40 src/tuning/tuningsysfs.cpp:37
+msgid "Unknown"
+msgstr ""
+
+#: src/tuning/cpufreq.cpp:46
+#, c-format
+msgid "Using 'ondemand' cpufreq governor"
+msgstr ""
+
+#: src/tuning/tuning.cpp:60
+msgid "Enable Audio codec power management"
+msgstr ""
+
+#: src/tuning/tuning.cpp:61
+msgid "Enable SATA link power management for /dev/sda"
+msgstr ""
+
+#: src/tuning/tuning.cpp:62
+msgid "NMI watchdog should be turned off"
+msgstr ""
+
+#: src/tuning/tuning.cpp:63
+msgid "Power Aware CPU scheduler"
+msgstr ""
+
+#: src/tuning/tuning.cpp:64
+msgid "VM writeback timeout"
+msgstr ""
+
+#: src/tuning/tuning.cpp:82
+msgid "Tunables"
+msgstr ""
+
+#: src/tuning/tuning.cpp:82
+msgid " <ESC> Exit | <Enter> Toggle tunable | <r> Window refresh"
+msgstr ""
+
+#: src/tuning/ethernet.cpp:57
+#, c-format
+msgid "Wake-on-lan status for device %s"
+msgstr ""
+
+#: src/tuning/wifi.cpp:48
+#, c-format
+msgid "Wireless Power Saving for interface %s"
+msgstr ""
+
+#: src/tuning/runtime.cpp:47
+#, c-format
+msgid "Runtime PM for %s device %s"
+msgstr ""
+
+#: src/tuning/runtime.cpp:49
+#, c-format
+msgid "%s device %s has no runtime power management"
+msgstr ""
+
+#: src/tuning/runtime.cpp:73
+#, c-format
+msgid "PCI Device %s has no runtime power management"
+msgstr ""
+
+#: src/tuning/runtime.cpp:75
+#, c-format
+msgid "Runtime PM for PCI Device %s"
+msgstr ""
+
+#: src/tuning/tuningusb.cpp:55
+#, c-format
+msgid "Autosuspend for unknown USB device %s (%s:%s)"
+msgstr ""
+
+#: src/tuning/tuningusb.cpp:72 src/tuning/tuningusb.cpp:74
+#: src/tuning/tuningusb.cpp:76
+#, c-format
+msgid "Autosuspend for USB device %s [%s]"
+msgstr ""
+
+#: src/calibrate/calibrate.cpp:291
+#, c-format
+msgid "Cannot create temp file\n"
+msgstr ""
+
+#: src/calibrate/calibrate.cpp:310
+#, c-format
+msgid "Calibrating: CPU usage on %i threads\n"
+msgstr ""
+
+#: src/calibrate/calibrate.cpp:325
+#, c-format
+msgid "Calibrating: CPU wakeup power consumption\n"
+msgstr ""
+
+#: src/calibrate/calibrate.cpp:342
+#, c-format
+msgid "Calibrating USB devices\n"
+msgstr ""
+
+#: src/calibrate/calibrate.cpp:344 src/calibrate/calibrate.cpp:361
+#: src/calibrate/calibrate.cpp:369 src/calibrate/calibrate.cpp:386
+#, c-format
+msgid ".... device %s \n"
+msgstr ""
+
+#: src/calibrate/calibrate.cpp:359
+#, c-format
+msgid "Calibrating radio devices\n"
+msgstr ""
+
+#: src/calibrate/calibrate.cpp:383
+#, c-format
+msgid "Calibrating backlight\n"
+msgstr ""
+
+#: src/calibrate/calibrate.cpp:407 src/calibrate/calibrate.cpp:415
+#, c-format
+msgid "Calibrating idle\n"
+msgstr ""
+
+#: src/calibrate/calibrate.cpp:426
+#, c-format
+msgid "Calibrating: disk usage \n"
+msgstr ""
+
+#: src/calibrate/calibrate.cpp:451
+msgid "Starting PowerTOP power estimate calibration \n"
+msgstr ""
+
+#: src/calibrate/calibrate.cpp:474
+msgid "Finishing PowerTOP power estimate calibration \n"
+msgstr ""
+
+#: src/calibrate/calibrate.cpp:478
+#, c-format
+msgid "Parameters after calibration:\n"
+msgstr ""
+
+#: src/main.cpp:84
+#, c-format
+msgid "PowerTOP version"
+msgstr ""
+
+#: src/main.cpp:90
+msgid "Set refresh time out"
+msgstr ""
+
+#: src/main.cpp:103
+msgid "Usage: powertop [OPTIONS]"
+msgstr ""
+
+#: src/main.cpp:104
+msgid "run in \"debug\" mode"
+msgstr ""
+
+#: src/main.cpp:105
+msgid "print version information"
+msgstr ""
+
+#: src/main.cpp:106
+msgid "runs powertop in calibration mode"
+msgstr ""
+
+#: src/main.cpp:107
+msgid "[=devnode]"
+msgstr ""
+
+#: src/main.cpp:107
+msgid "uses an Extech Power Analyzer for measurements"
+msgstr ""
+
+#: src/main.cpp:108 src/main.cpp:109
+msgid "[=FILENAME]"
+msgstr ""
+
+#: src/main.cpp:108
+msgid "generate a html report"
+msgstr ""
+
+#: src/main.cpp:109
+msgid "generate a csv report"
+msgstr ""
+
+#: src/main.cpp:110
+msgid "[=seconds]"
+msgstr ""
+
+#: src/main.cpp:110
+msgid "generate a report for 'x' seconds"
+msgstr ""
+
+#: src/main.cpp:111
+msgid "[=iterations] number of times to run each test"
+msgstr ""
+
+#: src/main.cpp:112
+msgid "print this help menu"
+msgstr ""
+
+#: src/main.cpp:114
+msgid "For more help please refer to the README"
+msgstr ""
+
+#: src/main.cpp:224
+#, c-format
+msgid "PowerTOP is out of memory. PowerTOP is Aborting"
+msgstr ""
+
+#: src/main.cpp:252
+#, c-format
+msgid "Preparing to take measurements\n"
+msgstr ""
+
+#: src/main.cpp:255
+#, c-format
+msgid "Taking %d measurement(s) for a duration of %d second(s) each.\n"
+msgstr ""
+
+#: src/main.cpp:278
+#, c-format
+msgid "PowerTOP "
+msgstr ""
+
+#: src/main.cpp:279 src/main.cpp:307
+#, c-format
+msgid "exiting...\n"
+msgstr ""
+
+#: src/main.cpp:306
+#, c-format
+msgid "Failed to mount debugfs!\n"
+msgstr ""
+
+#: src/main.cpp:443
+#, c-format
+msgid "Leaving PowerTOP"
+msgstr ""
diff --git a/po/en_US.po b/po/en_US.po
new file mode 100644 (file)
index 0000000..812a78f
--- /dev/null
@@ -0,0 +1,578 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR Intel Corporation
+# This file is distributed under the same license as the PACKAGE package.
+#
+# Translators:
+# Dimitris Glezos <glezos@indifex.com>, 2011.
+msgid ""
+msgstr ""
+"Project-Id-Version: PowerTOP\n"
+"Report-Msgid-Bugs-To: \"powertop@lists.01.org\"\n"
+"POT-Creation-Date: 2012-05-31 14:03-0700\n"
+"PO-Revision-Date: 2012-05-31 22:35+0000\n"
+"Last-Translator: Patrick McCarty <patrick.mccarty@linux.intel.com>\n"
+"Language-Team: English (United States) (http://www.transifex.com/projects/p/"
+"PowerTOP/language/en_US/)\n"
+"Language: en_US\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1)\n"
+
+#: src/parameters/persistent.cpp:46 src/parameters/persistent.cpp:140
+msgid "Cannot save to file "
+msgstr "Cannot save to file "
+
+#: src/parameters/persistent.cpp:78 src/parameters/persistent.cpp:165
+msgid "Cannot load from file "
+msgstr "Cannot load from file "
+
+#: src/parameters/persistent.cpp:123
+#, c-format
+msgid "Loaded %i prior measurements\n"
+msgstr "Loaded %i prior measurements\n"
+
+#: src/display.cpp:71
+msgid "Overview"
+msgstr "Overview"
+
+#: src/display.cpp:72
+msgid "Idle stats"
+msgstr "Idle stats"
+
+#: src/display.cpp:73
+msgid "Frequency stats"
+msgstr "Frequency stats"
+
+#: src/display.cpp:74
+msgid "Device stats"
+msgstr "Device stats"
+
+#: src/display.cpp:131
+msgid "Exit"
+msgstr ""
+
+#: src/cpu/cpu_core.cpp:46 src/cpu/cpu_core.cpp:190 src/cpu/intel_cpus.cpp:296
+#, c-format
+msgid "  Core"
+msgstr "  Core"
+
+#: src/cpu/cpu_core.cpp:116 src/cpu/cpu_linux.cpp:329
+#: src/cpu/cpu_package.cpp:145 src/cpu/intel_cpus.cpp:222
+#: src/cpu/intel_cpus.cpp:457 src/cpu/intel_cpus.cpp:658
+msgid "Idle"
+msgstr "Idle"
+
+#: src/cpu/cpu_core.cpp:118 src/cpu/cpu_linux.cpp:331
+#: src/cpu/cpu_package.cpp:147 src/cpu/intel_cpus.cpp:224
+#: src/cpu/intel_cpus.cpp:459
+#, c-format
+msgid "Turbo Mode"
+msgstr "Turbo Mode"
+
+#: src/cpu/cpu.cpp:90
+#, c-format
+msgid "cpu package %i"
+msgstr "cpu package %i"
+
+#: src/cpu/cpu.cpp:91
+msgid "cpu package"
+msgstr "cpu package"
+
+#: src/cpu/cpu.cpp:925
+#, c-format
+msgid "cpu_idle event returned no state?\n"
+msgstr ""
+
+#: src/cpu/cpu.cpp:940
+#, c-format
+msgid "power or cpu_frequecny event returned no state?\n"
+msgstr ""
+
+#: src/cpu/cpu_linux.cpp:92
+msgid "C0 polling"
+msgstr "C0 polling"
+
+#: src/cpu/cpu_linux.cpp:231 src/cpu/cpu_linux.cpp:289
+#: src/cpu/intel_cpus.cpp:605
+#, c-format
+msgid " CPU %i"
+msgstr " CPU %i"
+
+#: src/cpu/cpu_package.cpp:46
+#, c-format
+msgid "Package"
+msgstr "Package"
+
+#: src/cpu/cpu_package.cpp:104 src/cpu/intel_cpus.cpp:322
+#, c-format
+msgid "  Package"
+msgstr "  Package"
+
+#: src/cpu/intel_cpus.cpp:69
+#, c-format
+msgid "msr reg not found"
+msgstr ""
+
+#: src/cpu/intel_cpus.cpp:79
+#, c-format
+msgid "pread cpu%d 0x%llx : "
+msgstr ""
+
+#: src/cpu/intel_cpus.cpp:529
+msgid "C0 active"
+msgstr "C0 active"
+
+#: src/cpu/intel_cpus.cpp:588
+#, c-format
+msgid "Actual"
+msgstr "Actual"
+
+#: src/lib.cpp:257
+#, c-format
+msgid "%7sW"
+msgstr "%7sW"
+
+#: src/lib.cpp:260
+#, c-format
+msgid "    0 mW"
+msgstr "    0 mW"
+
+#: src/lib.cpp:369
+msgid "PS/2 Touchpad / Keyboard / Mouse"
+msgstr "PS/2 Touchpad / Keyboard / Mouse"
+
+#: src/lib.cpp:370
+msgid "SATA controller"
+msgstr "SATA controller"
+
+#: src/lib.cpp:371
+msgid "Intel built in USB hub"
+msgstr "Intel built in USB hub"
+
+#: src/process/do_process.cpp:818
+#, c-format
+msgid ""
+"Estimated power: %5.1f    Measured power: %5.1f    Sum: %5.1f\n"
+"\n"
+msgstr ""
+"Estimated power: %5.1f    Measured power: %5.1f    Sum: %5.1f\n"
+"\n"
+
+#: src/process/do_process.cpp:829 src/devices/device.cpp:171
+#, c-format
+msgid "The battery reports a discharge rate of %sW\n"
+msgstr "The battery reports a discharge rate of %sW\n"
+
+#: src/process/do_process.cpp:834
+#, c-format
+msgid "The estimated remaining time is %i hours, %i minutes\n"
+msgstr ""
+
+#: src/process/do_process.cpp:842
+msgid "Summary"
+msgstr ""
+
+#: src/process/do_process.cpp:842 src/process/do_process.cpp:1029
+msgid "wakeups/second"
+msgstr ""
+
+#: src/process/do_process.cpp:842
+msgid "GPU ops/seconds"
+msgstr ""
+
+#: src/process/do_process.cpp:842
+msgid "VFS ops/sec and"
+msgstr ""
+
+#: src/process/do_process.cpp:842 src/process/do_process.cpp:1030
+msgid "CPU use"
+msgstr ""
+
+#: src/process/do_process.cpp:846 src/process/do_process.cpp:914
+#: src/process/do_process.cpp:1034
+msgid "Power est."
+msgstr ""
+
+#: src/process/do_process.cpp:846 src/process/do_process.cpp:848
+#: src/process/do_process.cpp:914 src/process/do_process.cpp:917
+#: src/process/do_process.cpp:1034 src/process/do_process.cpp:1038
+msgid "Usage"
+msgstr ""
+
+#: src/process/do_process.cpp:846 src/process/do_process.cpp:848
+#: src/process/do_process.cpp:1034 src/process/do_process.cpp:1038
+msgid "Events/s"
+msgstr ""
+
+#: src/process/do_process.cpp:846 src/process/do_process.cpp:848
+#: src/process/do_process.cpp:914 src/process/do_process.cpp:917
+#: src/process/do_process.cpp:1034 src/process/do_process.cpp:1038
+msgid "Category"
+msgstr ""
+
+#: src/process/do_process.cpp:846 src/process/do_process.cpp:848
+#: src/process/do_process.cpp:914 src/process/do_process.cpp:917
+#: src/process/do_process.cpp:1034 src/process/do_process.cpp:1038
+msgid "Description"
+msgstr ""
+
+#: src/process/do_process.cpp:911
+msgid "Overview of Software Power Consumers"
+msgstr ""
+
+#: src/process/do_process.cpp:914 src/process/do_process.cpp:917
+msgid "Wakeups/s"
+msgstr ""
+
+#: src/process/do_process.cpp:914 src/process/do_process.cpp:917
+msgid "GPU ops/s"
+msgstr ""
+
+#: src/process/do_process.cpp:914 src/process/do_process.cpp:917
+msgid "Disk IO/s"
+msgstr ""
+
+#: src/process/do_process.cpp:914 src/process/do_process.cpp:917
+msgid "GFX Wakeups/s"
+msgstr ""
+
+#: src/process/do_process.cpp:1026
+msgid "Power Consumption Summary"
+msgstr ""
+
+#: src/process/do_process.cpp:1029
+msgid "GPU ops/second"
+msgstr ""
+
+#: src/process/do_process.cpp:1030
+msgid "VFS ops/sec"
+msgstr ""
+
+#: src/process/do_process.cpp:1030
+msgid "GFX wakes/sec and"
+msgstr ""
+
+#: src/perf/perf.cpp:121
+#, c-format
+msgid "PowerTOP %s needs the kernel to support the 'perf' subsystem\n"
+msgstr "PowerTOP %s needs the kernel to support the 'perf' subsystem\n"
+
+#: src/perf/perf.cpp:122
+#, c-format
+msgid "as well as support for trace points in the kernel:\n"
+msgstr "as well as support for trace points in the kernel:\n"
+
+#: src/devices/device.cpp:177
+#, c-format
+msgid "System baseline power is estimated at %sW\n"
+msgstr "System baseline power is estimated at %sW\n"
+
+#: src/devices/device.cpp:184
+msgid "Power est.    Usage     Device name\n"
+msgstr "Power est.    Usage     Device name\n"
+
+#: src/devices/device.cpp:186
+msgid "              Usage     Device name\n"
+msgstr "              Usage     Device name\n"
+
+#: src/devices/alsa.cpp:79
+#, c-format
+msgid "Audio codec %s: %s (%s)"
+msgstr "Audio codec %s: %s (%s)"
+
+#: src/devices/alsa.cpp:81 src/devices/alsa.cpp:83
+#, c-format
+msgid "Audio codec %s: %s"
+msgstr "Audio codec %s: %s"
+
+#: src/devices/runtime_pm.cpp:225
+#, c-format
+msgid "PCI Device: %s"
+msgstr "PCI Device: %s"
+
+#: src/devices/usb.cpp:51 src/devices/usb.cpp:94 src/devices/usb.cpp:96
+#, c-format
+msgid "USB device: %s"
+msgstr "USB device: %s"
+
+#: src/devices/usb.cpp:92
+#, c-format
+msgid "USB device: %s (%s)"
+msgstr "USB device: %s (%s)"
+
+#: src/devices/ahci.cpp:140
+#, c-format
+msgid "SATA link: %s"
+msgstr "SATA link: %s"
+
+#: src/devices/ahci.cpp:142
+#, c-format
+msgid "SATA disk: %s"
+msgstr "SATA disk: %s"
+
+#: src/devices/rfkill.cpp:65 src/devices/rfkill.cpp:69
+#, c-format
+msgid "Radio device: %s"
+msgstr "Radio device: %s"
+
+#: src/devices/network.cpp:177
+#, c-format
+msgid "Network interface: %s (%s)"
+msgstr "Network interface: %s (%s)"
+
+#: src/tuning/bluetooth.cpp:48
+#, c-format
+msgid "Bluetooth device interface status"
+msgstr "Bluetooth device interface status"
+
+#: src/tuning/cpufreq.cpp:43 src/tuning/ethernet.cpp:53
+#: src/tuning/tunable.cpp:48 src/tuning/wifi.cpp:45 src/tuning/runtime.cpp:41
+#: src/tuning/tuningusb.cpp:40 src/tuning/tuningsysfs.cpp:37
+msgid "Good"
+msgstr "Good"
+
+#: src/tuning/cpufreq.cpp:43 src/tuning/ethernet.cpp:53
+#: src/tuning/tunable.cpp:49 src/tuning/wifi.cpp:45 src/tuning/runtime.cpp:41
+#: src/tuning/tuningusb.cpp:40 src/tuning/tuningsysfs.cpp:37
+msgid "Bad"
+msgstr "Bad"
+
+#: src/tuning/cpufreq.cpp:43 src/tuning/ethernet.cpp:53
+#: src/tuning/tunable.cpp:50 src/tuning/wifi.cpp:45 src/tuning/runtime.cpp:41
+#: src/tuning/tuningusb.cpp:40 src/tuning/tuningsysfs.cpp:37
+msgid "Unknown"
+msgstr "Unknown"
+
+#: src/tuning/cpufreq.cpp:46
+#, c-format
+msgid "Using 'ondemand' cpufreq governor"
+msgstr "Using 'ondemand' cpufreq governor"
+
+#: src/tuning/tuning.cpp:60
+msgid "Enable Audio codec power management"
+msgstr "Enable Audio codec power management"
+
+#: src/tuning/tuning.cpp:61
+msgid "Enable SATA link power management for /dev/sda"
+msgstr "Enable SATA link power management for /dev/sda"
+
+#: src/tuning/tuning.cpp:62
+msgid "NMI watchdog should be turned off"
+msgstr "NMI watchdog should be turned off"
+
+#: src/tuning/tuning.cpp:63
+msgid "Power Aware CPU scheduler"
+msgstr "Power Aware CPU scheduler"
+
+#: src/tuning/tuning.cpp:64
+msgid "VM writeback timeout"
+msgstr "VM writeback timeout"
+
+#: src/tuning/tuning.cpp:82
+msgid "Tunables"
+msgstr "Tunables"
+
+#: src/tuning/tuning.cpp:82
+msgid " <ESC> Exit | <Enter> Toggle tunable | <r> Window refresh"
+msgstr ""
+
+#: src/tuning/ethernet.cpp:57
+#, c-format
+msgid "Wake-on-lan status for device %s"
+msgstr "Wake-on-lan status for device %s"
+
+#: src/tuning/wifi.cpp:48
+#, c-format
+msgid "Wireless Power Saving for interface %s"
+msgstr "Wireless Power Saving for interface %s"
+
+#: src/tuning/runtime.cpp:47
+#, c-format
+msgid "Runtime PM for %s device %s"
+msgstr "Runtime PM for %s device %s"
+
+#: src/tuning/runtime.cpp:49
+#, c-format
+msgid "%s device %s has no runtime power management"
+msgstr "%s device %s has no runtime power management"
+
+#: src/tuning/runtime.cpp:73
+#, c-format
+msgid "PCI Device %s has no runtime power management"
+msgstr "PCI Device %s has no runtime power management"
+
+#: src/tuning/runtime.cpp:75
+#, c-format
+msgid "Runtime PM for PCI Device %s"
+msgstr "Runtime PM for PCI Device %s"
+
+#: src/tuning/tuningusb.cpp:55
+#, c-format
+msgid "Autosuspend for unknown USB device %s (%s:%s)"
+msgstr "Autosuspend for unknown USB device %s (%s:%s)"
+
+#: src/tuning/tuningusb.cpp:72 src/tuning/tuningusb.cpp:74
+#: src/tuning/tuningusb.cpp:76
+#, c-format
+msgid "Autosuspend for USB device %s [%s]"
+msgstr "Autosuspend for USB device %s [%s]"
+
+#: src/calibrate/calibrate.cpp:291
+#, c-format
+msgid "Cannot create temp file\n"
+msgstr "Cannot create temp file\n"
+
+#: src/calibrate/calibrate.cpp:310
+#, c-format
+msgid "Calibrating: CPU usage on %i threads\n"
+msgstr "Calibrating: CPU usage on %i threads\n"
+
+#: src/calibrate/calibrate.cpp:325
+#, c-format
+msgid "Calibrating: CPU wakeup power consumption\n"
+msgstr "Calibrating: CPU wakeup power consumption\n"
+
+#: src/calibrate/calibrate.cpp:342
+#, c-format
+msgid "Calibrating USB devices\n"
+msgstr "Calibrating USB devices\n"
+
+#: src/calibrate/calibrate.cpp:344 src/calibrate/calibrate.cpp:361
+#: src/calibrate/calibrate.cpp:369 src/calibrate/calibrate.cpp:386
+#, c-format
+msgid ".... device %s \n"
+msgstr ".... device %s \n"
+
+#: src/calibrate/calibrate.cpp:359
+#, c-format
+msgid "Calibrating radio devices\n"
+msgstr "Calibrating radio devices\n"
+
+#: src/calibrate/calibrate.cpp:383
+#, c-format
+msgid "Calibrating backlight\n"
+msgstr "Calibrating backlight\n"
+
+#: src/calibrate/calibrate.cpp:407 src/calibrate/calibrate.cpp:415
+#, c-format
+msgid "Calibrating idle\n"
+msgstr "Calibrating idle\n"
+
+#: src/calibrate/calibrate.cpp:426
+#, c-format
+msgid "Calibrating: disk usage \n"
+msgstr "Calibrating: disk usage \n"
+
+#: src/calibrate/calibrate.cpp:451
+msgid "Starting PowerTOP power estimate calibration \n"
+msgstr "Starting PowerTOP power estimate calibration \n"
+
+#: src/calibrate/calibrate.cpp:474
+msgid "Finishing PowerTOP power estimate calibration \n"
+msgstr "Finishing PowerTOP power estimate calibration \n"
+
+#: src/calibrate/calibrate.cpp:478
+#, c-format
+msgid "Parameters after calibration:\n"
+msgstr "Parameters after calibration:\n"
+
+#: src/main.cpp:84
+#, c-format
+msgid "PowerTOP version"
+msgstr ""
+
+#: src/main.cpp:90
+msgid "Set refresh time out"
+msgstr ""
+
+#: src/main.cpp:103
+msgid "Usage: powertop [OPTIONS]"
+msgstr ""
+
+#: src/main.cpp:104
+msgid "run in \"debug\" mode"
+msgstr ""
+
+#: src/main.cpp:105
+msgid "print version information"
+msgstr ""
+
+#: src/main.cpp:106
+msgid "runs powertop in calibration mode"
+msgstr ""
+
+#: src/main.cpp:107
+msgid "[=devnode]"
+msgstr ""
+
+#: src/main.cpp:107
+msgid "uses an Extech Power Analyzer for measurements"
+msgstr ""
+
+#: src/main.cpp:108 src/main.cpp:109
+msgid "[=FILENAME]"
+msgstr ""
+
+#: src/main.cpp:108
+msgid "generate a html report"
+msgstr ""
+
+#: src/main.cpp:109
+msgid "generate a csv report"
+msgstr ""
+
+#: src/main.cpp:110
+msgid "[=seconds]"
+msgstr ""
+
+#: src/main.cpp:110
+msgid "generate a report for 'x' seconds"
+msgstr ""
+
+#: src/main.cpp:111
+msgid "[=iterations] number of times to run each test"
+msgstr ""
+
+#: src/main.cpp:112
+msgid "print this help menu"
+msgstr ""
+
+#: src/main.cpp:114
+msgid "For more help please refer to the README"
+msgstr ""
+
+#: src/main.cpp:224
+#, c-format
+msgid "PowerTOP is out of memory. PowerTOP is Aborting"
+msgstr ""
+
+#: src/main.cpp:252
+#, c-format
+msgid "Preparing to take measurements\n"
+msgstr ""
+
+#: src/main.cpp:255
+#, c-format
+msgid "Taking %d measurement(s) for a duration of %d second(s) each.\n"
+msgstr ""
+
+#: src/main.cpp:278
+#, c-format
+msgid "PowerTOP "
+msgstr "PowerTOP "
+
+#: src/main.cpp:279 src/main.cpp:307
+#, c-format
+msgid "exiting...\n"
+msgstr "exiting...\n"
+
+#: src/main.cpp:306
+#, c-format
+msgid "Failed to mount debugfs!\n"
+msgstr ""
+
+#: src/main.cpp:443
+#, c-format
+msgid "Leaving PowerTOP"
+msgstr ""
diff --git a/po/es_ES.po b/po/es_ES.po
new file mode 100644 (file)
index 0000000..49edcb1
--- /dev/null
@@ -0,0 +1,579 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR Intel Corporation
+# This file is distributed under the same license as the PACKAGE package.
+#
+# Translators:
+# Andres  <andreshko9@hotmail.com>, 2011.
+msgid ""
+msgstr ""
+"Project-Id-Version: PowerTOP\n"
+"Report-Msgid-Bugs-To: \"powertop@lists.01.org\"\n"
+"POT-Creation-Date: 2012-05-31 14:03-0700\n"
+"PO-Revision-Date: 2012-05-31 22:35+0000\n"
+"Last-Translator: Patrick McCarty <patrick.mccarty@linux.intel.com>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"Language: es_ES\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1)\n"
+
+#: src/parameters/persistent.cpp:46 src/parameters/persistent.cpp:140
+msgid "Cannot save to file "
+msgstr "No puede guardar a archivo"
+
+#: src/parameters/persistent.cpp:78 src/parameters/persistent.cpp:165
+msgid "Cannot load from file "
+msgstr "No puede cargar desde archivo "
+
+#: src/parameters/persistent.cpp:123
+#, c-format
+msgid "Loaded %i prior measurements\n"
+msgstr "Cargado %i medidas previas\n"
+
+#: src/display.cpp:71
+msgid "Overview"
+msgstr "Información general"
+
+#: src/display.cpp:72
+msgid "Idle stats"
+msgstr "Estadísticas de parado"
+
+#: src/display.cpp:73
+msgid "Frequency stats"
+msgstr "Estadísticas de frecuencia"
+
+#: src/display.cpp:74
+msgid "Device stats"
+msgstr "Estadísticas del dispositivo"
+
+#: src/display.cpp:131
+msgid "Exit"
+msgstr ""
+
+#: src/cpu/cpu_core.cpp:46 src/cpu/cpu_core.cpp:190 src/cpu/intel_cpus.cpp:296
+#, c-format
+msgid "  Core"
+msgstr "  Núcleo"
+
+#: src/cpu/cpu_core.cpp:116 src/cpu/cpu_linux.cpp:329
+#: src/cpu/cpu_package.cpp:145 src/cpu/intel_cpus.cpp:222
+#: src/cpu/intel_cpus.cpp:457 src/cpu/intel_cpus.cpp:658
+msgid "Idle"
+msgstr "Desocupado"
+
+#: src/cpu/cpu_core.cpp:118 src/cpu/cpu_linux.cpp:331
+#: src/cpu/cpu_package.cpp:147 src/cpu/intel_cpus.cpp:224
+#: src/cpu/intel_cpus.cpp:459
+#, c-format
+msgid "Turbo Mode"
+msgstr "Modo Turbo"
+
+#: src/cpu/cpu.cpp:90
+#, c-format
+msgid "cpu package %i"
+msgstr "package cpu %i"
+
+#: src/cpu/cpu.cpp:91
+msgid "cpu package"
+msgstr "paquete cpu"
+
+#: src/cpu/cpu.cpp:925
+#, c-format
+msgid "cpu_idle event returned no state?\n"
+msgstr ""
+
+#: src/cpu/cpu.cpp:940
+#, c-format
+msgid "power or cpu_frequecny event returned no state?\n"
+msgstr ""
+
+#: src/cpu/cpu_linux.cpp:92
+msgid "C0 polling"
+msgstr "C0 sondeando"
+
+#: src/cpu/cpu_linux.cpp:231 src/cpu/cpu_linux.cpp:289
+#: src/cpu/intel_cpus.cpp:605
+#, c-format
+msgid " CPU %i"
+msgstr " CPU %i"
+
+#: src/cpu/cpu_package.cpp:46
+#, c-format
+msgid "Package"
+msgstr "Paquete"
+
+#: src/cpu/cpu_package.cpp:104 src/cpu/intel_cpus.cpp:322
+#, c-format
+msgid "  Package"
+msgstr "  Paquete"
+
+#: src/cpu/intel_cpus.cpp:69
+#, c-format
+msgid "msr reg not found"
+msgstr ""
+
+#: src/cpu/intel_cpus.cpp:79
+#, c-format
+msgid "pread cpu%d 0x%llx : "
+msgstr ""
+
+#: src/cpu/intel_cpus.cpp:529
+msgid "C0 active"
+msgstr "C0 activo"
+
+#: src/cpu/intel_cpus.cpp:588
+#, c-format
+msgid "Actual"
+msgstr "Actual"
+
+#: src/lib.cpp:257
+#, c-format
+msgid "%7sW"
+msgstr "%7sW"
+
+#: src/lib.cpp:260
+#, c-format
+msgid "    0 mW"
+msgstr "    0 mW"
+
+#: src/lib.cpp:369
+msgid "PS/2 Touchpad / Keyboard / Mouse"
+msgstr "PS/2 Touchpad / Teclado / Ratón"
+
+#: src/lib.cpp:370
+msgid "SATA controller"
+msgstr "Controlador SATA"
+
+#: src/lib.cpp:371
+msgid "Intel built in USB hub"
+msgstr "Intel construido en concentrador USB"
+
+#: src/process/do_process.cpp:818
+#, c-format
+msgid ""
+"Estimated power: %5.1f    Measured power: %5.1f    Sum: %5.1f\n"
+"\n"
+msgstr ""
+"Energía estimada: %5.1f    Energía medida: %5.1f    Sum: %5.1f\n"
+"\n"
+
+#: src/process/do_process.cpp:829 src/devices/device.cpp:171
+#, c-format
+msgid "The battery reports a discharge rate of %sW\n"
+msgstr "La batería reporta una tasa de descarga de %sW\n"
+
+#: src/process/do_process.cpp:834
+#, c-format
+msgid "The estimated remaining time is %i hours, %i minutes\n"
+msgstr ""
+
+#: src/process/do_process.cpp:842
+msgid "Summary"
+msgstr ""
+
+#: src/process/do_process.cpp:842 src/process/do_process.cpp:1029
+msgid "wakeups/second"
+msgstr ""
+
+#: src/process/do_process.cpp:842
+msgid "GPU ops/seconds"
+msgstr ""
+
+#: src/process/do_process.cpp:842
+msgid "VFS ops/sec and"
+msgstr ""
+
+#: src/process/do_process.cpp:842 src/process/do_process.cpp:1030
+msgid "CPU use"
+msgstr ""
+
+#: src/process/do_process.cpp:846 src/process/do_process.cpp:914
+#: src/process/do_process.cpp:1034
+msgid "Power est."
+msgstr ""
+
+#: src/process/do_process.cpp:846 src/process/do_process.cpp:848
+#: src/process/do_process.cpp:914 src/process/do_process.cpp:917
+#: src/process/do_process.cpp:1034 src/process/do_process.cpp:1038
+msgid "Usage"
+msgstr ""
+
+#: src/process/do_process.cpp:846 src/process/do_process.cpp:848
+#: src/process/do_process.cpp:1034 src/process/do_process.cpp:1038
+msgid "Events/s"
+msgstr ""
+
+#: src/process/do_process.cpp:846 src/process/do_process.cpp:848
+#: src/process/do_process.cpp:914 src/process/do_process.cpp:917
+#: src/process/do_process.cpp:1034 src/process/do_process.cpp:1038
+msgid "Category"
+msgstr ""
+
+#: src/process/do_process.cpp:846 src/process/do_process.cpp:848
+#: src/process/do_process.cpp:914 src/process/do_process.cpp:917
+#: src/process/do_process.cpp:1034 src/process/do_process.cpp:1038
+msgid "Description"
+msgstr ""
+
+#: src/process/do_process.cpp:911
+msgid "Overview of Software Power Consumers"
+msgstr ""
+
+#: src/process/do_process.cpp:914 src/process/do_process.cpp:917
+msgid "Wakeups/s"
+msgstr ""
+
+#: src/process/do_process.cpp:914 src/process/do_process.cpp:917
+msgid "GPU ops/s"
+msgstr ""
+
+#: src/process/do_process.cpp:914 src/process/do_process.cpp:917
+msgid "Disk IO/s"
+msgstr ""
+
+#: src/process/do_process.cpp:914 src/process/do_process.cpp:917
+msgid "GFX Wakeups/s"
+msgstr ""
+
+#: src/process/do_process.cpp:1026
+msgid "Power Consumption Summary"
+msgstr ""
+
+#: src/process/do_process.cpp:1029
+msgid "GPU ops/second"
+msgstr ""
+
+#: src/process/do_process.cpp:1030
+msgid "VFS ops/sec"
+msgstr ""
+
+#: src/process/do_process.cpp:1030
+msgid "GFX wakes/sec and"
+msgstr ""
+
+#: src/perf/perf.cpp:121
+#, c-format
+msgid "PowerTOP %s needs the kernel to support the 'perf' subsystem\n"
+msgstr "PowerTOP %s necesita que el kernel soporte el subsistema 'perf'\n"
+
+#: src/perf/perf.cpp:122
+#, c-format
+msgid "as well as support for trace points in the kernel:\n"
+msgstr "así como soporte para puntos de seguimiento en el kernel:\n"
+
+#: src/devices/device.cpp:177
+#, c-format
+msgid "System baseline power is estimated at %sW\n"
+msgstr "Linea base de energía del sistema es estimada en %sW\n"
+
+#: src/devices/device.cpp:184
+msgid "Power est.    Usage     Device name\n"
+msgstr "Power est.    Usage     Device name\n"
+
+#: src/devices/device.cpp:186
+msgid "              Usage     Device name\n"
+msgstr "              Uso     Nombre del dispositivo\n"
+
+#: src/devices/alsa.cpp:79
+#, c-format
+msgid "Audio codec %s: %s (%s)"
+msgstr "Codec de audio %s: %s (%s)"
+
+#: src/devices/alsa.cpp:81 src/devices/alsa.cpp:83
+#, c-format
+msgid "Audio codec %s: %s"
+msgstr "Codec de audio %s: %s"
+
+#: src/devices/runtime_pm.cpp:225
+#, c-format
+msgid "PCI Device: %s"
+msgstr "Dispositivo PCI: %s"
+
+#: src/devices/usb.cpp:51 src/devices/usb.cpp:94 src/devices/usb.cpp:96
+#, c-format
+msgid "USB device: %s"
+msgstr "Dispositivo USB: %s"
+
+#: src/devices/usb.cpp:92
+#, c-format
+msgid "USB device: %s (%s)"
+msgstr "Dispositivo USB: %s (%s)"
+
+#: src/devices/ahci.cpp:140
+#, c-format
+msgid "SATA link: %s"
+msgstr "Enlace SATA: %s"
+
+#: src/devices/ahci.cpp:142
+#, c-format
+msgid "SATA disk: %s"
+msgstr "Disco SATA: %s"
+
+#: src/devices/rfkill.cpp:65 src/devices/rfkill.cpp:69
+#, c-format
+msgid "Radio device: %s"
+msgstr "Dispositivo de radio: %s"
+
+#: src/devices/network.cpp:177
+#, c-format
+msgid "Network interface: %s (%s)"
+msgstr "Interfaz de red: %s (%s)"
+
+#: src/tuning/bluetooth.cpp:48
+#, c-format
+msgid "Bluetooth device interface status"
+msgstr "Estado de la interfaz de dispositivo Bluetooth"
+
+#: src/tuning/cpufreq.cpp:43 src/tuning/ethernet.cpp:53
+#: src/tuning/tunable.cpp:48 src/tuning/wifi.cpp:45 src/tuning/runtime.cpp:41
+#: src/tuning/tuningusb.cpp:40 src/tuning/tuningsysfs.cpp:37
+msgid "Good"
+msgstr "Bueno"
+
+#: src/tuning/cpufreq.cpp:43 src/tuning/ethernet.cpp:53
+#: src/tuning/tunable.cpp:49 src/tuning/wifi.cpp:45 src/tuning/runtime.cpp:41
+#: src/tuning/tuningusb.cpp:40 src/tuning/tuningsysfs.cpp:37
+msgid "Bad"
+msgstr "Malo"
+
+#: src/tuning/cpufreq.cpp:43 src/tuning/ethernet.cpp:53
+#: src/tuning/tunable.cpp:50 src/tuning/wifi.cpp:45 src/tuning/runtime.cpp:41
+#: src/tuning/tuningusb.cpp:40 src/tuning/tuningsysfs.cpp:37
+msgid "Unknown"
+msgstr "Desconocido"
+
+#: src/tuning/cpufreq.cpp:46
+#, c-format
+msgid "Using 'ondemand' cpufreq governor"
+msgstr "Usando 'ondemand' cpufreq governor"
+
+#: src/tuning/tuning.cpp:60
+msgid "Enable Audio codec power management"
+msgstr "Habilitar administración de energía del codec de Audio "
+
+#: src/tuning/tuning.cpp:61
+msgid "Enable SATA link power management for /dev/sda"
+msgstr "Habilitar control de energía del enlace SATA /dev/sda"
+
+#: src/tuning/tuning.cpp:62
+msgid "NMI watchdog should be turned off"
+msgstr "Vigilancia NMI se debe apagar"
+
+#: src/tuning/tuning.cpp:63
+msgid "Power Aware CPU scheduler"
+msgstr "Planificador de CPU Consciente de Energía "
+
+#: src/tuning/tuning.cpp:64
+msgid "VM writeback timeout"
+msgstr "Tiempo límite de reescritura VM"
+
+#: src/tuning/tuning.cpp:82
+msgid "Tunables"
+msgstr "Optimizables"
+
+#: src/tuning/tuning.cpp:82
+msgid " <ESC> Exit | <Enter> Toggle tunable | <r> Window refresh"
+msgstr ""
+
+#: src/tuning/ethernet.cpp:57
+#, c-format
+msgid "Wake-on-lan status for device %s"
+msgstr "Estado Wake-on-lan para dispositivo %s"
+
+#: src/tuning/wifi.cpp:48
+#, c-format
+msgid "Wireless Power Saving for interface %s"
+msgstr "Ahorro de Energía Wireless para interfaz %s"
+
+#: src/tuning/runtime.cpp:47
+#, c-format
+msgid "Runtime PM for %s device %s"
+msgstr "Tiempo de ejecución PM para %s dispositivo %s"
+
+#: src/tuning/runtime.cpp:49
+#, c-format
+msgid "%s device %s has no runtime power management"
+msgstr ""
+"%s dispositivo %s no tiene administración de energía en tiempo de ejecución"
+
+#: src/tuning/runtime.cpp:73
+#, c-format
+msgid "PCI Device %s has no runtime power management"
+msgstr ""
+"Dispositivo PCI %s no tiene administración de energía en tiempo de ejecución"
+
+#: src/tuning/runtime.cpp:75
+#, c-format
+msgid "Runtime PM for PCI Device %s"
+msgstr "Tiempo de ejecución PM para dispositivo PCI %s"
+
+#: src/tuning/tuningusb.cpp:55
+#, c-format
+msgid "Autosuspend for unknown USB device %s (%s:%s)"
+msgstr "Autosuspender para dispositivo USB desconocido %s (%s:%s)"
+
+#: src/tuning/tuningusb.cpp:72 src/tuning/tuningusb.cpp:74
+#: src/tuning/tuningusb.cpp:76
+#, c-format
+msgid "Autosuspend for USB device %s [%s]"
+msgstr "Autosuspender para dispositivo USB %s [%s]"
+
+#: src/calibrate/calibrate.cpp:291
+#, c-format
+msgid "Cannot create temp file\n"
+msgstr "No puede crear archivo temp\n"
+
+#: src/calibrate/calibrate.cpp:310
+#, c-format
+msgid "Calibrating: CPU usage on %i threads\n"
+msgstr "Calibrando: uso de CPU en %i discusiones\n"
+
+#: src/calibrate/calibrate.cpp:325
+#, c-format
+msgid "Calibrating: CPU wakeup power consumption\n"
+msgstr "Calibrando: consumo de energía del despertado de la CPU\n"
+
+#: src/calibrate/calibrate.cpp:342
+#, c-format
+msgid "Calibrating USB devices\n"
+msgstr "Calibrando dispositivos USB\n"
+
+#: src/calibrate/calibrate.cpp:344 src/calibrate/calibrate.cpp:361
+#: src/calibrate/calibrate.cpp:369 src/calibrate/calibrate.cpp:386
+#, c-format
+msgid ".... device %s \n"
+msgstr ".... dispositivo %s \n"
+
+#: src/calibrate/calibrate.cpp:359
+#, c-format
+msgid "Calibrating radio devices\n"
+msgstr "Calibrando dispositivos de radio\n"
+
+#: src/calibrate/calibrate.cpp:383
+#, c-format
+msgid "Calibrating backlight\n"
+msgstr "Calibrando luz trasera\n"
+
+#: src/calibrate/calibrate.cpp:407 src/calibrate/calibrate.cpp:415
+#, c-format
+msgid "Calibrating idle\n"
+msgstr "Calibrando parado\n"
+
+#: src/calibrate/calibrate.cpp:426
+#, c-format
+msgid "Calibrating: disk usage \n"
+msgstr "Calibrando: uso de disco \n"
+
+#: src/calibrate/calibrate.cpp:451
+msgid "Starting PowerTOP power estimate calibration \n"
+msgstr "Iniciando calibración de estimado de energía PowerTOP \n"
+
+#: src/calibrate/calibrate.cpp:474
+msgid "Finishing PowerTOP power estimate calibration \n"
+msgstr "Finalizando calibración de estimación de energía de PowerTOP  \n"
+
+#: src/calibrate/calibrate.cpp:478
+#, c-format
+msgid "Parameters after calibration:\n"
+msgstr "Parámetros tras calibración:\n"
+
+#: src/main.cpp:84
+#, c-format
+msgid "PowerTOP version"
+msgstr ""
+
+#: src/main.cpp:90
+msgid "Set refresh time out"
+msgstr ""
+
+#: src/main.cpp:103
+msgid "Usage: powertop [OPTIONS]"
+msgstr ""
+
+#: src/main.cpp:104
+msgid "run in \"debug\" mode"
+msgstr ""
+
+#: src/main.cpp:105
+msgid "print version information"
+msgstr ""
+
+#: src/main.cpp:106
+msgid "runs powertop in calibration mode"
+msgstr ""
+
+#: src/main.cpp:107
+msgid "[=devnode]"
+msgstr ""
+
+#: src/main.cpp:107
+msgid "uses an Extech Power Analyzer for measurements"
+msgstr ""
+
+#: src/main.cpp:108 src/main.cpp:109
+msgid "[=FILENAME]"
+msgstr ""
+
+#: src/main.cpp:108
+msgid "generate a html report"
+msgstr ""
+
+#: src/main.cpp:109
+msgid "generate a csv report"
+msgstr ""
+
+#: src/main.cpp:110
+msgid "[=seconds]"
+msgstr ""
+
+#: src/main.cpp:110
+msgid "generate a report for 'x' seconds"
+msgstr ""
+
+#: src/main.cpp:111
+msgid "[=iterations] number of times to run each test"
+msgstr ""
+
+#: src/main.cpp:112
+msgid "print this help menu"
+msgstr ""
+
+#: src/main.cpp:114
+msgid "For more help please refer to the README"
+msgstr ""
+
+#: src/main.cpp:224
+#, c-format
+msgid "PowerTOP is out of memory. PowerTOP is Aborting"
+msgstr ""
+
+#: src/main.cpp:252
+#, c-format
+msgid "Preparing to take measurements\n"
+msgstr ""
+
+#: src/main.cpp:255
+#, c-format
+msgid "Taking %d measurement(s) for a duration of %d second(s) each.\n"
+msgstr ""
+
+#: src/main.cpp:278
+#, c-format
+msgid "PowerTOP "
+msgstr "PowerTOP "
+
+#: src/main.cpp:279 src/main.cpp:307
+#, c-format
+msgid "exiting...\n"
+msgstr "saliendo...\n"
+
+#: src/main.cpp:306
+#, c-format
+msgid "Failed to mount debugfs!\n"
+msgstr ""
+
+#: src/main.cpp:443
+#, c-format
+msgid "Leaving PowerTOP"
+msgstr ""
diff --git a/po/hi.po b/po/hi.po
new file mode 100644 (file)
index 0000000..9fa4b4a
--- /dev/null
+++ b/po/hi.po
@@ -0,0 +1,587 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR Intel Corporation
+# This file is distributed under the same license as the PACKAGE package.
+# 
+# Translators:
+#   <piyushkumarchauhan@live.in>, 2012.
+msgid ""
+msgstr ""
+"Project-Id-Version: PowerTOP\n"
+"Report-Msgid-Bugs-To: \"powertop@lists.01.org\"\n"
+"POT-Creation-Date: 2012-10-26 09:24-0700\n"
+"PO-Revision-Date: 2012-10-26 22:23+0000\n"
+"Last-Translator: ceferron <chris.e.ferron@linux.intel.com>\n"
+"Language-Team: Hindi (http://www.transifex.com/projects/p/PowerTOP/language/hi/)\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Language: hi\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+
+#: src/parameters/persistent.cpp:46 src/parameters/persistent.cpp:140
+msgid "Cannot save to file"
+msgstr ""
+
+#: src/parameters/persistent.cpp:78 src/parameters/persistent.cpp:165
+msgid "Cannot load from file"
+msgstr ""
+
+#: src/parameters/persistent.cpp:123
+#, c-format
+msgid "Loaded %i prior measurements\n"
+msgstr "%i पूर्व माप लोड किया जा चूका हैं \n"
+
+#: src/display.cpp:70
+msgid "Overview"
+msgstr " विवरण"
+
+#: src/display.cpp:71
+msgid "Idle stats"
+msgstr "निष्क्रिय आँकड़े"
+
+#: src/display.cpp:72
+msgid "Frequency stats"
+msgstr " आवृति आँकड़े"
+
+#: src/display.cpp:73
+msgid "Device stats"
+msgstr " उपकरण आँकड़े"
+
+#: src/display.cpp:130
+msgid "Exit"
+msgstr "बाहर निकलें"
+
+#: src/cpu/cpu_core.cpp:111 src/cpu/cpu_linux.cpp:360
+#: src/cpu/cpu_package.cpp:133 src/cpu/intel_cpus.cpp:222
+#: src/cpu/intel_cpus.cpp:444 src/cpu/intel_cpus.cpp:639
+msgid "Idle"
+msgstr "निष्क्रिय"
+
+#: src/cpu/cpu_core.cpp:113 src/cpu/cpu_linux.cpp:362
+#: src/cpu/cpu_package.cpp:135 src/cpu/intel_cpus.cpp:224
+#: src/cpu/intel_cpus.cpp:446
+#, c-format
+msgid "Turbo Mode"
+msgstr "टर्बो प्रणाली"
+
+#: src/cpu/cpu.cpp:93
+#, c-format
+msgid "cpu package %i"
+msgstr "सीपीयू पैकेज %i"
+
+#: src/cpu/cpu.cpp:94
+msgid "cpu package"
+msgstr "सीपीयू पैकेज"
+
+#: src/cpu/cpu.cpp:437 src/cpu/cpu.cpp:563
+#, c-format
+msgid "Package %i"
+msgstr ""
+
+#: src/cpu/cpu.cpp:469 src/cpu/cpu.cpp:583
+#, c-format
+msgid "Core %i"
+msgstr ""
+
+#: src/cpu/cpu.cpp:471
+#, c-format
+msgid "GPU %i"
+msgstr ""
+
+#: src/cpu/cpu.cpp:493 src/cpu/cpu.cpp:604
+#, c-format
+msgid "CPU %i"
+msgstr ""
+
+#: src/cpu/cpu.cpp:772
+#, c-format
+msgid "cpu_idle event returned no state?\n"
+msgstr "cpu_idle की घटना ने किसी भी तरीके की स्थिति नहीं लोटायी है?\n"
+
+#: src/cpu/cpu.cpp:787
+#, c-format
+msgid "power or cpu_frequecny event returned no state?\n"
+msgstr "शक्ति या सीपीयू_आवृति की घटना ने किसी भी तरीके की स्थिति नहीं लोटायी है?\n"
+
+#: src/cpu/cpu_linux.cpp:92
+msgid "C0 polling"
+msgstr "C0 मतदान"
+
+#: src/cpu/intel_cpus.cpp:69
+#, c-format
+msgid "msr reg not found"
+msgstr "msr reg नहीं पाया गया"
+
+#: src/cpu/intel_cpus.cpp:79
+#, c-format
+msgid "pread cpu%d 0x%llx : "
+msgstr "pread cpu%d 0x%llx : "
+
+#: src/cpu/intel_cpus.cpp:516
+msgid "C0 active"
+msgstr "C0 सक्रिय"
+
+#: src/cpu/intel_cpus.cpp:575
+#, c-format
+msgid "Actual"
+msgstr "वास्तविक"
+
+#: src/lib.cpp:257
+#, c-format
+msgid "%7sW"
+msgstr "%7sW"
+
+#: src/lib.cpp:260
+#, c-format
+msgid "    0 mW"
+msgstr "0 मेगावाट"
+
+#: src/lib.cpp:381
+msgid "PS/2 Touchpad / Keyboard / Mouse"
+msgstr "पीएस/2 टचपैड / कुंजीपटल / माउस "
+
+#: src/lib.cpp:382
+msgid "SATA controller"
+msgstr "SATA नियंत्रक"
+
+#: src/lib.cpp:383
+msgid "Intel built in USB hub"
+msgstr "इंटेल में निर्मित यूएसबी हब "
+
+#: src/process/do_process.cpp:830
+#, c-format
+msgid ""
+"Estimated power: %5.1f    Measured power: %5.1f    Sum: %5.1f\n"
+"\n"
+msgstr "अनुमानित शक्ति: %5.1f    मापित शक्ति: %5.1f    जोड़: %5.1f\n"
+
+#: src/process/do_process.cpp:841 src/devices/device.cpp:171
+#, c-format
+msgid "The battery reports a discharge rate of %sW\n"
+msgstr "बैटरी रिपोर्ट कर रही हैं %sW की चुकौती दर\n\n"
+
+#: src/process/do_process.cpp:846
+#, c-format
+msgid "The estimated remaining time is %i hours, %i minutes\n"
+msgstr "अनुमानित शेष समय %i घंटे, %i मिनट हैं \n"
+
+#: src/process/do_process.cpp:854
+msgid "Summary"
+msgstr "संक्षेप"
+
+#: src/process/do_process.cpp:854 src/process/do_process.cpp:1024
+msgid "wakeups/second"
+msgstr "वेकअप/सेकेंड"
+
+#: src/process/do_process.cpp:854
+msgid "GPU ops/seconds"
+msgstr "GPU ऑप्स/सेकण्ड्स"
+
+#: src/process/do_process.cpp:854
+msgid "VFS ops/sec and"
+msgstr "VFS ऑप्स/सेकंड और"
+
+#: src/process/do_process.cpp:854 src/process/do_process.cpp:1028
+msgid "CPU use"
+msgstr "सीपीयू उपयोग"
+
+#: src/process/do_process.cpp:858 src/process/do_process.cpp:915
+#: src/process/do_process.cpp:1034
+msgid "Power est."
+msgstr "शक्ति अनुमानित."
+
+#: src/process/do_process.cpp:858 src/process/do_process.cpp:860
+#: src/process/do_process.cpp:919 src/process/do_process.cpp:1038
+msgid "Usage"
+msgstr "खपत"
+
+#: src/process/do_process.cpp:858 src/process/do_process.cpp:860
+#: src/process/do_process.cpp:1040
+msgid "Events/s"
+msgstr "घटना/सेकेंड"
+
+#: src/process/do_process.cpp:858 src/process/do_process.cpp:860
+#: src/process/do_process.cpp:929 src/process/do_process.cpp:1042
+msgid "Category"
+msgstr "श्रेणी"
+
+#: src/process/do_process.cpp:858 src/process/do_process.cpp:860
+#: src/process/do_process.cpp:931 src/process/do_process.cpp:1044
+msgid "Description"
+msgstr "विवरण"
+
+#: src/process/do_process.cpp:910
+msgid "Overview of Software Power Consumers"
+msgstr "सॉफ्टवेयर बिजली उपभोक्ताओं का विवरण"
+
+#: src/process/do_process.cpp:921
+msgid "Wakeups/s"
+msgstr "वेकअप/सेकेंड"
+
+#: src/process/do_process.cpp:923
+msgid "GPU ops/s"
+msgstr "GPU ऑप्स/सेकेंड"
+
+#: src/process/do_process.cpp:925
+msgid "Disk IO/s"
+msgstr "डिस्क IO/सेकेंड"
+
+#: src/process/do_process.cpp:927
+msgid "GFX Wakeups/s"
+msgstr "GFX वेकअप/सेकेंड"
+
+#: src/process/do_process.cpp:1021
+msgid "Power Consumption Summary"
+msgstr "विद्युत उपभोग सारांश"
+
+#: src/process/do_process.cpp:1025
+msgid "GPU ops/second"
+msgstr "GPU ऑप्स/सेकेंड"
+
+#: src/process/do_process.cpp:1026
+msgid "VFS ops/sec"
+msgstr "VFS ऑप्स/सेकेंड"
+
+#: src/process/do_process.cpp:1027
+msgid "GFX wakes/sec and"
+msgstr "GFX वेक/सेकेंड और"
+
+#: src/perf/perf.cpp:111
+#, c-format
+msgid "PowerTOP %s needs the kernel to support the 'perf' subsystem\n"
+msgstr "PowerTOP %s को 'perf' उपतंत्र को समर्थन देने के लिए kernel की जरुरत होती है \n"
+
+#: src/perf/perf.cpp:112
+#, c-format
+msgid "as well as support for trace points in the kernel:\n"
+msgstr "तथा kernel के ट्रेस अंक को समर्थन:\n"
+
+#: src/devices/device.cpp:177
+#, c-format
+msgid "System baseline power is estimated at %sW\n"
+msgstr "प्रणाली आधारभूत शक्ति का अनुमान %sW से लगाया जा चूका हैं\n"
+
+#: src/devices/device.cpp:184
+msgid "Power est.    Usage     Device name\n"
+msgstr "शक्ति अनुमानित  उपयोग  उपकरण का नाम \n"
+
+#: src/devices/device.cpp:186
+msgid "              Usage     Device name\n"
+msgstr "खपत  उपकरण नाम\n"
+
+#: src/devices/alsa.cpp:79
+#, c-format
+msgid "Audio codec %s: %s (%s)"
+msgstr "श्रव्य कोडेक %s: %s (%s)"
+
+#: src/devices/alsa.cpp:81 src/devices/alsa.cpp:83
+#, c-format
+msgid "Audio codec %s: %s"
+msgstr "श्रव्य कोडेक %s: %s"
+
+#: src/devices/runtime_pm.cpp:225
+#, c-format
+msgid "PCI Device: %s"
+msgstr "पीसीआई उपकरण: %s"
+
+#: src/devices/usb.cpp:51 src/devices/usb.cpp:94 src/devices/usb.cpp:96
+#, c-format
+msgid "USB device: %s"
+msgstr "यूएसबी उपकरण: %s "
+
+#: src/devices/usb.cpp:92
+#, c-format
+msgid "USB device: %s (%s)"
+msgstr "यूएसबी उपकरण: %s (%s)"
+
+#: src/devices/ahci.cpp:140
+#, c-format
+msgid "SATA link: %s"
+msgstr "SATA कड़ी: %s"
+
+#: src/devices/ahci.cpp:142
+#, c-format
+msgid "SATA disk: %s"
+msgstr "SATA डिस्क: %s"
+
+#: src/devices/rfkill.cpp:65 src/devices/rfkill.cpp:69
+#, c-format
+msgid "Radio device: %s"
+msgstr "रेडियो उपकरण: %s"
+
+#: src/devices/network.cpp:177
+#, c-format
+msgid "Network interface: %s (%s)"
+msgstr "संजाल अंतराफलक: %s (%s)"
+
+#: src/tuning/bluetooth.cpp:48
+#, c-format
+msgid "Bluetooth device interface status"
+msgstr "ब्लूटूथ उपकरण अंतराफलक की स्थिति"
+
+#: src/tuning/cpufreq.cpp:43 src/tuning/ethernet.cpp:53
+#: src/tuning/tunable.cpp:48 src/tuning/wifi.cpp:45 src/tuning/runtime.cpp:41
+#: src/tuning/tuningusb.cpp:40 src/tuning/tuningsysfs.cpp:44
+msgid "Good"
+msgstr "अच्छा"
+
+#: src/tuning/cpufreq.cpp:43 src/tuning/ethernet.cpp:53
+#: src/tuning/tunable.cpp:49 src/tuning/wifi.cpp:45 src/tuning/runtime.cpp:41
+#: src/tuning/tuningusb.cpp:40 src/tuning/tuningsysfs.cpp:44
+msgid "Bad"
+msgstr "बुरा"
+
+#: src/tuning/cpufreq.cpp:43 src/tuning/ethernet.cpp:53
+#: src/tuning/tunable.cpp:50 src/tuning/wifi.cpp:45 src/tuning/runtime.cpp:41
+#: src/tuning/tuningusb.cpp:40 src/tuning/tuningsysfs.cpp:44
+msgid "Unknown"
+msgstr "अनजान"
+
+#: src/tuning/cpufreq.cpp:46
+#, c-format
+msgid "Using 'ondemand' cpufreq governor"
+msgstr "'ondemand' सीपीयू आवृति नियन्त्रक का उपयोग"
+
+#: src/tuning/tuning.cpp:59
+msgid "Enable Audio codec power management"
+msgstr "श्रव्य कोडेक ऊर्जा प्रबंधन को सक्षम बनाए"
+
+#: src/tuning/tuning.cpp:60
+msgid "NMI watchdog should be turned off"
+msgstr "एनएमआई पर निगरानी को बंद कर दिया जाएँ"
+
+#: src/tuning/tuning.cpp:61
+msgid "Power Aware CPU scheduler"
+msgstr "पावर अवगत सीपीयू अनुसूचक "
+
+#: src/tuning/tuning.cpp:62
+msgid "VM writeback timeout"
+msgstr "VM को प्रतिलेखन करने का समय समाप्त "
+
+#: src/tuning/tuning.cpp:79
+msgid "Tunables"
+msgstr "ट्यून करने योग्य"
+
+#: src/tuning/tuning.cpp:79
+msgid " <ESC> Exit | <Enter> Toggle tunable | <r> Window refresh"
+msgstr "<ESC> बाहर निकलें | <Enter> टॉगल tunable | <r> विंडो ताजा करे "
+
+#: src/tuning/ethernet.cpp:57
+#, c-format
+msgid "Wake-on-lan status for device %s"
+msgstr "स्थानीय क्षेत्र तंत्र की स्थिति को उपकरण %s के लिए जागृत करना "
+
+#: src/tuning/wifi.cpp:48
+#, c-format
+msgid "Wireless Power Saving for interface %s"
+msgstr "बेतार संप्रेषण शक्ति बचत के लिए अंतराफलक %s"
+
+#: src/tuning/runtime.cpp:47
+#, c-format
+msgid "Runtime PM for %s device %s"
+msgstr "%s उपकरण %s के लिए PM कार्यावधि करे "
+
+#: src/tuning/runtime.cpp:49
+#, c-format
+msgid "%s device %s has no runtime power management"
+msgstr "%s उपकरण %s के पास कार्यावधि शक्ति प्रबंधन नहीं हैं "
+
+#: src/tuning/runtime.cpp:73
+#, c-format
+msgid "PCI Device %s has no runtime power management"
+msgstr "पीसीआई उपकरण %s के पास कार्यावधि शक्ति प्रबंधन नहीं हैं  "
+
+#: src/tuning/runtime.cpp:75
+#, c-format
+msgid "Runtime PM for PCI Device %s"
+msgstr "पीसीआई उपकरण %s के लिए PM कार्यावधि करे"
+
+#: src/tuning/tuningusb.cpp:55
+#, c-format
+msgid "Autosuspend for unknown USB device %s (%s:%s)"
+msgstr "अज्ञात यूएसबी उपकरण के लिए स्वतःस्थगित होना %s (%s:%s) "
+
+#: src/tuning/tuningusb.cpp:72 src/tuning/tuningusb.cpp:74
+#: src/tuning/tuningusb.cpp:76
+#, c-format
+msgid "Autosuspend for USB device %s [%s]"
+msgstr "यूएसबी उपकरण के लिए स्वतःस्थगित होना %s [%s]"
+
+#: src/tuning/tuningsysfs.cpp:142
+#, c-format
+msgid "Enable SATA link power Managmenet for %s"
+msgstr ""
+
+#: src/calibrate/calibrate.cpp:291
+#, c-format
+msgid "Cannot create temp file\n"
+msgstr "अस्थायी फ़ाइल नहीं बना सकते\n"
+
+#: src/calibrate/calibrate.cpp:310
+#, c-format
+msgid "Calibrating: CPU usage on %i threads\n"
+msgstr "केलिब्रतिंग: सीपीयू की खपत %i है लड़ियाँ  पे\n"
+
+#: src/calibrate/calibrate.cpp:325
+#, c-format
+msgid "Calibrating: CPU wakeup power consumption\n"
+msgstr "केलिब्रतिंग: सीपीयू के सतर्क होने के समय की शक्ति की खपत\n"
+
+#: src/calibrate/calibrate.cpp:342
+#, c-format
+msgid "Calibrating USB devices\n"
+msgstr "यूएसबी उपकरण केलिब्रेट हो रहे हैं\n"
+
+#: src/calibrate/calibrate.cpp:344 src/calibrate/calibrate.cpp:361
+#: src/calibrate/calibrate.cpp:369 src/calibrate/calibrate.cpp:386
+#, c-format
+msgid ".... device %s \n"
+msgstr "...उपकरण %s\n"
+
+#: src/calibrate/calibrate.cpp:359
+#, c-format
+msgid "Calibrating radio devices\n"
+msgstr "रेडियो उपकरण केलिब्रेट हो रहे हैं\n"
+
+#: src/calibrate/calibrate.cpp:383
+#, c-format
+msgid "Calibrating backlight\n"
+msgstr "बेकलाईट केलिब्रेट हो रहा है \n"
+
+#: src/calibrate/calibrate.cpp:407 src/calibrate/calibrate.cpp:415
+#, c-format
+msgid "Calibrating idle\n"
+msgstr "निष्क्रिय केलिब्रेट हो रहा है\n"
+
+#: src/calibrate/calibrate.cpp:426
+#, c-format
+msgid "Calibrating: disk usage \n"
+msgstr "कलिब्रटिंग: डिस्क की खपत \n"
+
+#: src/calibrate/calibrate.cpp:451
+msgid "Starting PowerTOP power estimate calibration \n"
+msgstr "PowerTOP की शक्ति का अनुमान का केलिब्रेसन सुरु हो रहा हैं\n"
+
+#: src/calibrate/calibrate.cpp:474
+msgid "Finishing PowerTOP power estimate calibration \n"
+msgstr "PowerTOP की शक्ति का अनुमान का केलिब्रेसन समाप्त हो रहा हैं\n"
+
+#: src/calibrate/calibrate.cpp:478
+#, c-format
+msgid "Parameters after calibration:\n"
+msgstr "केलिब्रेसन के बाद पैरामीटर्स:\n"
+
+#: src/main.cpp:86
+#, c-format
+msgid "PowerTOP version"
+msgstr "PowerTOP संस्करण"
+
+#: src/main.cpp:92
+msgid "Set refresh time out"
+msgstr "ताज़ा करने के टाइम-आउट को नियत करें"
+
+#: src/main.cpp:105
+msgid "Usage: powertop [OPTIONS]"
+msgstr "खपत: पॉवरटॉप [विकल्प]"
+
+#: src/main.cpp:106
+msgid "run in \"debug\" mode"
+msgstr "\"डिबग\" मोड में चलाये"
+
+#: src/main.cpp:107
+msgid "print version information"
+msgstr "संस्करण जानकारी को छापें"
+
+#: src/main.cpp:108
+msgid "runs powertop in calibration mode"
+msgstr "पॉवरटॉप को केलिब्रेसन मोड में चलाता हैं"
+
+#: src/main.cpp:109
+msgid "[=devnode]"
+msgstr "[=devnode]"
+
+#: src/main.cpp:109
+msgid "uses an Extech Power Analyzer for measurements"
+msgstr "माप के लिए एक Extech पावर विश्लेषक का उपयोग करता है"
+
+#: src/main.cpp:110 src/main.cpp:111
+msgid "[=FILENAME]"
+msgstr "[=फ़ाइलनाम]"
+
+#: src/main.cpp:110
+msgid "generate a html report"
+msgstr "एक एचटीएमएल रिपोर्ट उत्पन्न करना"
+
+#: src/main.cpp:111
+msgid "generate a csv report"
+msgstr "एक सीएसवी रिपोर्ट उत्पन्न करना"
+
+#: src/main.cpp:112
+msgid "[=seconds]"
+msgstr "[=सेकण्ड्स]"
+
+#: src/main.cpp:112
+msgid "generate a report for 'x' seconds"
+msgstr "'x' सेकंड के लिए एक रिपोर्ट उत्पन्न करना"
+
+#: src/main.cpp:113
+msgid "[=iterations] number of times to run each test"
+msgstr "[=संतृप्ति] प्रत्येक परीक्षा को चलाने की संख्या"
+
+#: src/main.cpp:114
+msgid "[=workload]"
+msgstr ""
+
+#: src/main.cpp:114
+msgid "file to execute for workload"
+msgstr ""
+
+#: src/main.cpp:115
+msgid "suppress stderr output"
+msgstr ""
+
+#: src/main.cpp:116
+msgid "print this help menu"
+msgstr "इस सहायक मेन्यू को छापें"
+
+#: src/main.cpp:118
+msgid "For more help please refer to the README"
+msgstr "अधिक सहायता के लिए कृपया रीडमी देखें"
+
+#: src/main.cpp:235
+msgid "PowerTOP is out of memory. PowerTOP is Aborting"
+msgstr "PowerTOP स्मृति से बाहर है. PowerTOP रद्द कर रहा है"
+
+#: src/main.cpp:243
+#, c-format
+msgid "Preparing to take measurements\n"
+msgstr "माप लेने के लिए तैयार होना \n"
+
+#: src/main.cpp:248
+#, c-format
+msgid "Taking %d measurement(s) for a duration of %d second(s) each.\n"
+msgstr "%d का माप लिया जा रहा है प्रत्येक %d सेकण्ड की अवधि के लिए.\n"
+
+#: src/main.cpp:250
+#, c-format
+msgid "Measuring workload %s.\n"
+msgstr ""
+
+#: src/main.cpp:273
+#, c-format
+msgid "PowerTOP "
+msgstr "PowerTOP"
+
+#: src/main.cpp:274 src/main.cpp:302
+#, c-format
+msgid "exiting...\n"
+msgstr "बाहर हो रहे है ...\n"
+
+#: src/main.cpp:301
+#, c-format
+msgid "Failed to mount debugfs!\n"
+msgstr "Debugfs को आरोहित करने में असफल रहे!\n"
+
+#: src/main.cpp:438
+msgid "Leaving PowerTOP"
+msgstr "PowerTOP को छोड़ना"
diff --git a/po/hu_HU.po b/po/hu_HU.po
new file mode 100644 (file)
index 0000000..031cdf6
--- /dev/null
@@ -0,0 +1,582 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR Intel Corporation
+# This file is distributed under the same license as the PACKAGE package.
+#
+# Translators:
+# Márton Németh <nemeth.marton@gmail.com>, 2012.
+# Márton Németh <nm127@freemail.hu>, 2012.
+msgid ""
+msgstr ""
+"Project-Id-Version: PowerTOP\n"
+"Report-Msgid-Bugs-To: \"powertop@lists.01.org\"\n"
+"POT-Creation-Date: 2012-05-31 14:03-0700\n"
+"PO-Revision-Date: 2012-06-06 05:25+0000\n"
+"Last-Translator: Márton Németh <nemeth.marton@gmail.com>\n"
+"Language-Team: Hungarian (Hungary) (http://www.transifex.com/projects/p/"
+"PowerTOP/language/hu_HU/)\n"
+"Language: hu_HU\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1)\n"
+
+#: src/parameters/persistent.cpp:46 src/parameters/persistent.cpp:140
+msgid "Cannot save to file "
+msgstr "Nem lehet menteni a következő fájlba: "
+
+#: src/parameters/persistent.cpp:78 src/parameters/persistent.cpp:165
+msgid "Cannot load from file "
+msgstr "Nem lehet betölteni a következő fájlból: "
+
+#: src/parameters/persistent.cpp:123
+#, c-format
+msgid "Loaded %i prior measurements\n"
+msgstr "%i korábbi mérés betöltve\n"
+
+#: src/display.cpp:71
+msgid "Overview"
+msgstr "Áttekintés"
+
+#: src/display.cpp:72
+msgid "Idle stats"
+msgstr "Üresjárat-statisztika"
+
+#: src/display.cpp:73
+msgid "Frequency stats"
+msgstr "Frekvenciastatisztika"
+
+#: src/display.cpp:74
+msgid "Device stats"
+msgstr "Eszközstatisztika"
+
+#: src/display.cpp:131
+msgid "Exit"
+msgstr "Kilépés"
+
+#: src/cpu/cpu_core.cpp:46 src/cpu/cpu_core.cpp:190 src/cpu/intel_cpus.cpp:296
+#, c-format
+msgid "  Core"
+msgstr "  Mag"
+
+#: src/cpu/cpu_core.cpp:116 src/cpu/cpu_linux.cpp:329
+#: src/cpu/cpu_package.cpp:145 src/cpu/intel_cpus.cpp:222
+#: src/cpu/intel_cpus.cpp:457 src/cpu/intel_cpus.cpp:658
+msgid "Idle"
+msgstr "Üresjárat"
+
+#: src/cpu/cpu_core.cpp:118 src/cpu/cpu_linux.cpp:331
+#: src/cpu/cpu_package.cpp:147 src/cpu/intel_cpus.cpp:224
+#: src/cpu/intel_cpus.cpp:459
+#, c-format
+msgid "Turbo Mode"
+msgstr "Turbó mód"
+
+#: src/cpu/cpu.cpp:90
+#, c-format
+msgid "cpu package %i"
+msgstr "CPU tok %i"
+
+#: src/cpu/cpu.cpp:91
+msgid "cpu package"
+msgstr "CPU tok"
+
+#: src/cpu/cpu.cpp:925
+#, c-format
+msgid "cpu_idle event returned no state?\n"
+msgstr "a CPU üresjáratesemény nem adott vissza állapotot?\n"
+
+#: src/cpu/cpu.cpp:940
+#, c-format
+msgid "power or cpu_frequecny event returned no state?\n"
+msgstr ""
+"a teljesítmény vagy CPU frekvencia esemény nem adott vissza állapotot?\n"
+
+#: src/cpu/cpu_linux.cpp:92
+msgid "C0 polling"
+msgstr "C0 ciklikus lekérdezés"
+
+#: src/cpu/cpu_linux.cpp:231 src/cpu/cpu_linux.cpp:289
+#: src/cpu/intel_cpus.cpp:605
+#, c-format
+msgid " CPU %i"
+msgstr " CPU %i"
+
+#: src/cpu/cpu_package.cpp:46
+#, c-format
+msgid "Package"
+msgstr "tok"
+
+#: src/cpu/cpu_package.cpp:104 src/cpu/intel_cpus.cpp:322
+#, c-format
+msgid "  Package"
+msgstr "  tok"
+
+#: src/cpu/intel_cpus.cpp:69
+#, c-format
+msgid "msr reg not found"
+msgstr "Az msr regiszterek nem találhatók"
+
+#: src/cpu/intel_cpus.cpp:79
+#, c-format
+msgid "pread cpu%d 0x%llx : "
+msgstr "pread cpu%d 0x%llx: "
+
+#: src/cpu/intel_cpus.cpp:529
+msgid "C0 active"
+msgstr "C0 aktív"
+
+#: src/cpu/intel_cpus.cpp:588
+#, c-format
+msgid "Actual"
+msgstr "Aktuális"
+
+#: src/lib.cpp:257
+#, c-format
+msgid "%7sW"
+msgstr "%7sW"
+
+#: src/lib.cpp:260
+#, c-format
+msgid "    0 mW"
+msgstr "    0 mW"
+
+#: src/lib.cpp:369
+msgid "PS/2 Touchpad / Keyboard / Mouse"
+msgstr "PS/2 tapipad / billentyűzet / egér"
+
+#: src/lib.cpp:370
+msgid "SATA controller"
+msgstr "SATA vezérlő"
+
+#: src/lib.cpp:371
+msgid "Intel built in USB hub"
+msgstr "Beépített Intel USB hub"
+
+#: src/process/do_process.cpp:818
+#, c-format
+msgid ""
+"Estimated power: %5.1f    Measured power: %5.1f    Sum: %5.1f\n"
+"\n"
+msgstr ""
+"Becsült teljesítmény: %5.1f    Mért teljesítmény: %5.1f    Összeg: %5.1f\n"
+"\n"
+
+#: src/process/do_process.cpp:829 src/devices/device.cpp:171
+#, c-format
+msgid "The battery reports a discharge rate of %sW\n"
+msgstr "Az akkumulátor %sW kisülési sebességet jelent\n"
+
+#: src/process/do_process.cpp:834
+#, c-format
+msgid "The estimated remaining time is %i hours, %i minutes\n"
+msgstr "Becsült hátralévő idő %i óra %i perc\n"
+
+#: src/process/do_process.cpp:842
+msgid "Summary"
+msgstr "Összefoglalás"
+
+#: src/process/do_process.cpp:842 src/process/do_process.cpp:1029
+msgid "wakeups/second"
+msgstr "felébredés/másodperc"
+
+#: src/process/do_process.cpp:842
+msgid "GPU ops/seconds"
+msgstr "GPU művelet/másodperc"
+
+#: src/process/do_process.cpp:842
+msgid "VFS ops/sec and"
+msgstr "VFS művelet/másodperc"
+
+#: src/process/do_process.cpp:842 src/process/do_process.cpp:1030
+msgid "CPU use"
+msgstr "CPU használtság"
+
+#: src/process/do_process.cpp:846 src/process/do_process.cpp:914
+#: src/process/do_process.cpp:1034
+msgid "Power est."
+msgstr "Becsült telj."
+
+#: src/process/do_process.cpp:846 src/process/do_process.cpp:848
+#: src/process/do_process.cpp:914 src/process/do_process.cpp:917
+#: src/process/do_process.cpp:1034 src/process/do_process.cpp:1038
+msgid "Usage"
+msgstr "Használat"
+
+#: src/process/do_process.cpp:846 src/process/do_process.cpp:848
+#: src/process/do_process.cpp:1034 src/process/do_process.cpp:1038
+msgid "Events/s"
+msgstr "Esemény/s"
+
+#: src/process/do_process.cpp:846 src/process/do_process.cpp:848
+#: src/process/do_process.cpp:914 src/process/do_process.cpp:917
+#: src/process/do_process.cpp:1034 src/process/do_process.cpp:1038
+msgid "Category"
+msgstr "Kategória"
+
+#: src/process/do_process.cpp:846 src/process/do_process.cpp:848
+#: src/process/do_process.cpp:914 src/process/do_process.cpp:917
+#: src/process/do_process.cpp:1034 src/process/do_process.cpp:1038
+msgid "Description"
+msgstr "Leírás"
+
+#: src/process/do_process.cpp:911
+msgid "Overview of Software Power Consumers"
+msgstr "Szofver teljesítményfogyasztók áttekintése"
+
+#: src/process/do_process.cpp:914 src/process/do_process.cpp:917
+msgid "Wakeups/s"
+msgstr "Felébredés/s"
+
+#: src/process/do_process.cpp:914 src/process/do_process.cpp:917
+msgid "GPU ops/s"
+msgstr "GPU művelet/s"
+
+#: src/process/do_process.cpp:914 src/process/do_process.cpp:917
+msgid "Disk IO/s"
+msgstr "Lemez BK/s"
+
+#: src/process/do_process.cpp:914 src/process/do_process.cpp:917
+msgid "GFX Wakeups/s"
+msgstr "GFX felébredés/s"
+
+#: src/process/do_process.cpp:1026
+msgid "Power Consumption Summary"
+msgstr "Teljesítményfelvétel összefoglaló"
+
+#: src/process/do_process.cpp:1029
+msgid "GPU ops/second"
+msgstr "GPU művelet/másodperc"
+
+#: src/process/do_process.cpp:1030
+msgid "VFS ops/sec"
+msgstr "VFS művelet/mp"
+
+#: src/process/do_process.cpp:1030
+msgid "GFX wakes/sec and"
+msgstr "GFX felébredés/mp és"
+
+#: src/perf/perf.cpp:121
+#, c-format
+msgid "PowerTOP %s needs the kernel to support the 'perf' subsystem\n"
+msgstr ""
+"A PowerTOP %s verziójának szüksége van arra, hogy a rendszermag támogassa a "
+"„perf” alrendszert\n"
+
+#: src/perf/perf.cpp:122
+#, c-format
+msgid "as well as support for trace points in the kernel:\n"
+msgstr "valamint a nyomkövetési pontokra is a rendszermagban:\n"
+
+#: src/devices/device.cpp:177
+#, c-format
+msgid "System baseline power is estimated at %sW\n"
+msgstr "%sW a rendszer becsült alapteljesítménye\n"
+
+#: src/devices/device.cpp:184
+msgid "Power est.    Usage     Device name\n"
+msgstr "Becsült telj.   Használat   Eszköz név\n"
+
+#: src/devices/device.cpp:186
+msgid "              Usage     Device name\n"
+msgstr "                Használat   Eszköz név\n"
+
+#: src/devices/alsa.cpp:79
+#, c-format
+msgid "Audio codec %s: %s (%s)"
+msgstr "Hangkodek %s: %s (%s)"
+
+#: src/devices/alsa.cpp:81 src/devices/alsa.cpp:83
+#, c-format
+msgid "Audio codec %s: %s"
+msgstr "Hangkodek %s: %s"
+
+#: src/devices/runtime_pm.cpp:225
+#, c-format
+msgid "PCI Device: %s"
+msgstr "PCI eszköz: %s"
+
+#: src/devices/usb.cpp:51 src/devices/usb.cpp:94 src/devices/usb.cpp:96
+#, c-format
+msgid "USB device: %s"
+msgstr "USB eszköz: %s"
+
+#: src/devices/usb.cpp:92
+#, c-format
+msgid "USB device: %s (%s)"
+msgstr "USB eszköz: %s (%s)"
+
+#: src/devices/ahci.cpp:140
+#, c-format
+msgid "SATA link: %s"
+msgstr "SATA kapcsolat: %s"
+
+#: src/devices/ahci.cpp:142
+#, c-format
+msgid "SATA disk: %s"
+msgstr "SATA lemez: %s"
+
+#: src/devices/rfkill.cpp:65 src/devices/rfkill.cpp:69
+#, c-format
+msgid "Radio device: %s"
+msgstr "Rádiós eszköz: %s"
+
+#: src/devices/network.cpp:177
+#, c-format
+msgid "Network interface: %s (%s)"
+msgstr "Hálózati csatoló: %s (%s)"
+
+#: src/tuning/bluetooth.cpp:48
+#, c-format
+msgid "Bluetooth device interface status"
+msgstr "Bluetooth eszközcsatoló állapota"
+
+#: src/tuning/cpufreq.cpp:43 src/tuning/ethernet.cpp:53
+#: src/tuning/tunable.cpp:48 src/tuning/wifi.cpp:45 src/tuning/runtime.cpp:41
+#: src/tuning/tuningusb.cpp:40 src/tuning/tuningsysfs.cpp:37
+msgid "Good"
+msgstr "Jó"
+
+#: src/tuning/cpufreq.cpp:43 src/tuning/ethernet.cpp:53
+#: src/tuning/tunable.cpp:49 src/tuning/wifi.cpp:45 src/tuning/runtime.cpp:41
+#: src/tuning/tuningusb.cpp:40 src/tuning/tuningsysfs.cpp:37
+msgid "Bad"
+msgstr "Rossz"
+
+#: src/tuning/cpufreq.cpp:43 src/tuning/ethernet.cpp:53
+#: src/tuning/tunable.cpp:50 src/tuning/wifi.cpp:45 src/tuning/runtime.cpp:41
+#: src/tuning/tuningusb.cpp:40 src/tuning/tuningsysfs.cpp:37
+msgid "Unknown"
+msgstr "Ismeretlen"
+
+#: src/tuning/cpufreq.cpp:46
+#, c-format
+msgid "Using 'ondemand' cpufreq governor"
+msgstr "Igény szerinti (ondemand) cpufreq vezérlő használata"
+
+#: src/tuning/tuning.cpp:60
+msgid "Enable Audio codec power management"
+msgstr "A hang kodek energiagazdálkodásának engedélyezése"
+
+#: src/tuning/tuning.cpp:61
+msgid "Enable SATA link power management for /dev/sda"
+msgstr "A /dev/sda SATA kapcsolat energiagazdálkodásának engedélyezése"
+
+#: src/tuning/tuning.cpp:62
+msgid "NMI watchdog should be turned off"
+msgstr "NMI felügyeletnek (watchdog) kikapcsolva kellene lennie"
+
+#: src/tuning/tuning.cpp:63
+msgid "Power Aware CPU scheduler"
+msgstr "Teljesítményt figyelembevevő CPU ütemező"
+
+#: src/tuning/tuning.cpp:64
+msgid "VM writeback timeout"
+msgstr "VM visszaírás időtúllépése"
+
+#: src/tuning/tuning.cpp:82
+msgid "Tunables"
+msgstr "Hangolások"
+
+#: src/tuning/tuning.cpp:82
+msgid " <ESC> Exit | <Enter> Toggle tunable | <r> Window refresh"
+msgstr " <ESC> Kilépés | <Enter> Hangolás átkapcsolása | <r> Ablak frissítése"
+
+#: src/tuning/ethernet.cpp:57
+#, c-format
+msgid "Wake-on-lan status for device %s"
+msgstr "Felébredés hálózati eseményre (wake-on-lan) állapot a(z) %s eszközön"
+
+#: src/tuning/wifi.cpp:48
+#, c-format
+msgid "Wireless Power Saving for interface %s"
+msgstr "Vezeték nélküli teljesítménymegtakarítás a(z) %s illesztőegységen"
+
+#: src/tuning/runtime.cpp:47
+#, c-format
+msgid "Runtime PM for %s device %s"
+msgstr "Futásidejű energiagazdálkodás a(z) %s buszon és %s eszközön"
+
+#: src/tuning/runtime.cpp:49
+#, c-format
+msgid "%s device %s has no runtime power management"
+msgstr "A(z) %s busz %s eszközének nincs futásidejű energiagazdálkodása"
+
+#: src/tuning/runtime.cpp:73
+#, c-format
+msgid "PCI Device %s has no runtime power management"
+msgstr "A(z) %s PCI eszköznek nincs futásidejű energiagazdálkodása"
+
+#: src/tuning/runtime.cpp:75
+#, c-format
+msgid "Runtime PM for PCI Device %s"
+msgstr "Futásidejű energiagazdálkodás a(z) %s PCI eszközön"
+
+#: src/tuning/tuningusb.cpp:55
+#, c-format
+msgid "Autosuspend for unknown USB device %s (%s:%s)"
+msgstr "Automatikus felfüggesztés a(z) %s (%s:%s) ismeretlen USB eszközön"
+
+#: src/tuning/tuningusb.cpp:72 src/tuning/tuningusb.cpp:74
+#: src/tuning/tuningusb.cpp:76
+#, c-format
+msgid "Autosuspend for USB device %s [%s]"
+msgstr "Automatikus felfüggesztés a(z) %s [%s] USB eszközön"
+
+#: src/calibrate/calibrate.cpp:291
+#, c-format
+msgid "Cannot create temp file\n"
+msgstr "Nem tudok létrehozni ideiglenes fájlt\n"
+
+#: src/calibrate/calibrate.cpp:310
+#, c-format
+msgid "Calibrating: CPU usage on %i threads\n"
+msgstr "Kalibrálás: CPU használtság %i szálon\n"
+
+#: src/calibrate/calibrate.cpp:325
+#, c-format
+msgid "Calibrating: CPU wakeup power consumption\n"
+msgstr "Kalibrálás: CPU felébredési teljesítményfelvétel\n"
+
+#: src/calibrate/calibrate.cpp:342
+#, c-format
+msgid "Calibrating USB devices\n"
+msgstr "USB eszközök kalibrálása\n"
+
+#: src/calibrate/calibrate.cpp:344 src/calibrate/calibrate.cpp:361
+#: src/calibrate/calibrate.cpp:369 src/calibrate/calibrate.cpp:386
+#, c-format
+msgid ".... device %s \n"
+msgstr ".... %s eszköz \n"
+
+#: src/calibrate/calibrate.cpp:359
+#, c-format
+msgid "Calibrating radio devices\n"
+msgstr "Rádiós eszközök kalibrálása\n"
+
+#: src/calibrate/calibrate.cpp:383
+#, c-format
+msgid "Calibrating backlight\n"
+msgstr "Háttérvilágítás kalibrálása\n"
+
+#: src/calibrate/calibrate.cpp:407 src/calibrate/calibrate.cpp:415
+#, c-format
+msgid "Calibrating idle\n"
+msgstr "Üresjárat kalibrálása\n"
+
+#: src/calibrate/calibrate.cpp:426
+#, c-format
+msgid "Calibrating: disk usage \n"
+msgstr "Kalibrálás: lemezhasználat \n"
+
+#: src/calibrate/calibrate.cpp:451
+msgid "Starting PowerTOP power estimate calibration \n"
+msgstr "PowerTop teljesítménybecslés kalibrálás indítása \n"
+
+#: src/calibrate/calibrate.cpp:474
+msgid "Finishing PowerTOP power estimate calibration \n"
+msgstr "PowerTop teljesítménybecslés-kalibrálás befejezése \n"
+
+#: src/calibrate/calibrate.cpp:478
+#, c-format
+msgid "Parameters after calibration:\n"
+msgstr "Paraméterek a kalibrálás után:\n"
+
+#: src/main.cpp:84
+#, c-format
+msgid "PowerTOP version"
+msgstr "PowerTOP verzió"
+
+#: src/main.cpp:90
+msgid "Set refresh time out"
+msgstr "Frissítés időkorlát leteltének beállítása"
+
+#: src/main.cpp:103
+msgid "Usage: powertop [OPTIONS]"
+msgstr "Használat: powertop [OPCIÓK]"
+
+#: src/main.cpp:104
+msgid "run in \"debug\" mode"
+msgstr "futtatás hibakeresési módban"
+
+#: src/main.cpp:105
+msgid "print version information"
+msgstr "verzió-információ kiíratása"
+
+#: src/main.cpp:106
+msgid "runs powertop in calibration mode"
+msgstr "a powertop futtatása kalibrációs módban"
+
+#: src/main.cpp:107
+msgid "[=devnode]"
+msgstr "[=eszköznév]"
+
+#: src/main.cpp:107
+msgid "uses an Extech Power Analyzer for measurements"
+msgstr "Extech Power Analyzer eszköz használata a mérésekhez"
+
+#: src/main.cpp:108 src/main.cpp:109
+msgid "[=FILENAME]"
+msgstr "[=FÁJLNÉV]"
+
+#: src/main.cpp:108
+msgid "generate a html report"
+msgstr "HTML jelentés készítése"
+
+#: src/main.cpp:109
+msgid "generate a csv report"
+msgstr "CSV jelentés készítése"
+
+#: src/main.cpp:110
+msgid "[=seconds]"
+msgstr "[=másodperc]"
+
+#: src/main.cpp:110
+msgid "generate a report for 'x' seconds"
+msgstr "ennyi másodpercig készüljön a jelentés"
+
+#: src/main.cpp:111
+msgid "[=iterations] number of times to run each test"
+msgstr "[=iterációk] ennyiszer fusson le minden egyes teszt"
+
+#: src/main.cpp:112
+msgid "print this help menu"
+msgstr "e súgó kiíratása"
+
+#: src/main.cpp:114
+msgid "For more help please refer to the README"
+msgstr "További információk a README fájlban találhatók"
+
+#: src/main.cpp:224
+#, c-format
+msgid "PowerTOP is out of memory. PowerTOP is Aborting"
+msgstr "Nincs elég memória a PowerTOP-nak. A PowerTOP futása megszakad"
+
+#: src/main.cpp:252
+#, c-format
+msgid "Preparing to take measurements\n"
+msgstr "Előkészülés a mérések elvégzéséhez\n"
+
+#: src/main.cpp:255
+#, c-format
+msgid "Taking %d measurement(s) for a duration of %d second(s) each.\n"
+msgstr "%d darab, egyenként %d másodperces mérés készítése.\n"
+
+#: src/main.cpp:278
+#, c-format
+msgid "PowerTOP "
+msgstr "PowerTOP "
+
+#: src/main.cpp:279 src/main.cpp:307
+#, c-format
+msgid "exiting...\n"
+msgstr "kilépés...\n"
+
+#: src/main.cpp:306
+#, c-format
+msgid "Failed to mount debugfs!\n"
+msgstr "Nem tudtam csatolni a debugfs-t!\n"
+
+#: src/main.cpp:443
+#, c-format
+msgid "Leaving PowerTOP"
+msgstr "A PowerTOP elhagyása"
diff --git a/po/id_ID.po b/po/id_ID.po
new file mode 100644 (file)
index 0000000..13b1c63
--- /dev/null
@@ -0,0 +1,575 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR Intel Corporation
+# This file is distributed under the same license as the PACKAGE package.
+# 
+# Translators:
+# Andika Triwidada <andika@gmail.com>, 2012.
+msgid ""
+msgstr ""
+"Project-Id-Version: PowerTOP\n"
+"Report-Msgid-Bugs-To: \"powertop@lists.01.org\"\n"
+"POT-Creation-Date: 2012-05-31 14:03-0700\n"
+"PO-Revision-Date: 2012-10-10 01:35+0000\n"
+"Last-Translator: Andika Triwidada <andika@gmail.com>\n"
+"Language-Team: Indonesian (Indonesia) (http://www.transifex.com/projects/p/PowerTOP/language/id_ID/)\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Language: id_ID\n"
+"Plural-Forms: nplurals=1; plural=0;\n"
+
+#: src/parameters/persistent.cpp:46 src/parameters/persistent.cpp:140
+msgid "Cannot save to file "
+msgstr "Tak bisa menyimpan ke berkas "
+
+#: src/parameters/persistent.cpp:78 src/parameters/persistent.cpp:165
+msgid "Cannot load from file "
+msgstr "Tak bisa memuat dari berkas "
+
+#: src/parameters/persistent.cpp:123
+#, c-format
+msgid "Loaded %i prior measurements\n"
+msgstr "Dimuat %i pengukuran sebelumnya\n"
+
+#: src/display.cpp:71
+msgid "Overview"
+msgstr "Ringkasan"
+
+#: src/display.cpp:72
+msgid "Idle stats"
+msgstr "Stat menganggur"
+
+#: src/display.cpp:73
+msgid "Frequency stats"
+msgstr "Stat frekuensi"
+
+#: src/display.cpp:74
+msgid "Device stats"
+msgstr "Stat perangkat"
+
+#: src/display.cpp:131
+msgid "Exit"
+msgstr "Keluar"
+
+#: src/cpu/cpu_core.cpp:46 src/cpu/cpu_core.cpp:190 src/cpu/intel_cpus.cpp:296
+#, c-format
+msgid "  Core"
+msgstr "  Core"
+
+#: src/cpu/cpu_core.cpp:116 src/cpu/cpu_linux.cpp:329
+#: src/cpu/cpu_package.cpp:145 src/cpu/intel_cpus.cpp:222
+#: src/cpu/intel_cpus.cpp:457 src/cpu/intel_cpus.cpp:658
+msgid "Idle"
+msgstr "Menganggur"
+
+#: src/cpu/cpu_core.cpp:118 src/cpu/cpu_linux.cpp:331
+#: src/cpu/cpu_package.cpp:147 src/cpu/intel_cpus.cpp:224
+#: src/cpu/intel_cpus.cpp:459
+#, c-format
+msgid "Turbo Mode"
+msgstr "Mode Turbo"
+
+#: src/cpu/cpu.cpp:90
+#, c-format
+msgid "cpu package %i"
+msgstr "paket %i cpu"
+
+#: src/cpu/cpu.cpp:91
+msgid "cpu package"
+msgstr "paket cpu"
+
+#: src/cpu/cpu.cpp:925
+#, c-format
+msgid "cpu_idle event returned no state?\n"
+msgstr "kejadian cpu_idle tak mengembalikan keadaan?\n"
+
+#: src/cpu/cpu.cpp:940
+#, c-format
+msgid "power or cpu_frequecny event returned no state?\n"
+msgstr "kejadian power atau cpu_frequency tak mengembalikan keadaan?\n"
+
+#: src/cpu/cpu_linux.cpp:92
+msgid "C0 polling"
+msgstr "C0 polling"
+
+#: src/cpu/cpu_linux.cpp:231 src/cpu/cpu_linux.cpp:289
+#: src/cpu/intel_cpus.cpp:605
+#, c-format
+msgid " CPU %i"
+msgstr " CPU %i"
+
+#: src/cpu/cpu_package.cpp:46
+#, c-format
+msgid "Package"
+msgstr "Paket"
+
+#: src/cpu/cpu_package.cpp:104 src/cpu/intel_cpus.cpp:322
+#, c-format
+msgid "  Package"
+msgstr "  Package"
+
+#: src/cpu/intel_cpus.cpp:69
+#, c-format
+msgid "msr reg not found"
+msgstr "msg reg tak ditemukan"
+
+#: src/cpu/intel_cpus.cpp:79
+#, c-format
+msgid "pread cpu%d 0x%llx : "
+msgstr "pread cpu%d 0x%llx : "
+
+#: src/cpu/intel_cpus.cpp:529
+msgid "C0 active"
+msgstr "C0 aktif"
+
+#: src/cpu/intel_cpus.cpp:588
+#, c-format
+msgid "Actual"
+msgstr "Aktual"
+
+#: src/lib.cpp:257
+#, c-format
+msgid "%7sW"
+msgstr "%7sW"
+
+#: src/lib.cpp:260
+#, c-format
+msgid "    0 mW"
+msgstr "    0 mW"
+
+#: src/lib.cpp:369
+msgid "PS/2 Touchpad / Keyboard / Mouse"
+msgstr "PS/2 Touchpad / Keyboard / Mouse"
+
+#: src/lib.cpp:370
+msgid "SATA controller"
+msgstr "Pengendali SATA"
+
+#: src/lib.cpp:371
+msgid "Intel built in USB hub"
+msgstr "Hub USB built in Intel"
+
+#: src/process/do_process.cpp:818
+#, c-format
+msgid ""
+"Estimated power: %5.1f    Measured power: %5.1f    Sum: %5.1f\n"
+"\n"
+msgstr "Perkiraan daya: %5.1f    Daya terukur: %5.1f    Jumlah: %5.1f\n\n"
+
+#: src/process/do_process.cpp:829 src/devices/device.cpp:171
+#, c-format
+msgid "The battery reports a discharge rate of %sW\n"
+msgstr "Baterai melaporkan laju pengosongan %sW\n"
+
+#: src/process/do_process.cpp:834
+#, c-format
+msgid "The estimated remaining time is %i hours, %i minutes\n"
+msgstr "Perkiraan sisa waktu adalah %i jam, %i menit\n"
+
+#: src/process/do_process.cpp:842
+msgid "Summary"
+msgstr "Ringkasan"
+
+#: src/process/do_process.cpp:842 src/process/do_process.cpp:1029
+msgid "wakeups/second"
+msgstr "bangun/detik"
+
+#: src/process/do_process.cpp:842
+msgid "GPU ops/seconds"
+msgstr "op GPU/detik"
+
+#: src/process/do_process.cpp:842
+msgid "VFS ops/sec and"
+msgstr "op VFS/detik"
+
+#: src/process/do_process.cpp:842 src/process/do_process.cpp:1030
+msgid "CPU use"
+msgstr "pakai CPU"
+
+#: src/process/do_process.cpp:846 src/process/do_process.cpp:914
+#: src/process/do_process.cpp:1034
+msgid "Power est."
+msgstr "Est. daya"
+
+#: src/process/do_process.cpp:846 src/process/do_process.cpp:848
+#: src/process/do_process.cpp:914 src/process/do_process.cpp:917
+#: src/process/do_process.cpp:1034 src/process/do_process.cpp:1038
+msgid "Usage"
+msgstr "Pakai"
+
+#: src/process/do_process.cpp:846 src/process/do_process.cpp:848
+#: src/process/do_process.cpp:1034 src/process/do_process.cpp:1038
+msgid "Events/s"
+msgstr "Kejadian/d"
+
+#: src/process/do_process.cpp:846 src/process/do_process.cpp:848
+#: src/process/do_process.cpp:914 src/process/do_process.cpp:917
+#: src/process/do_process.cpp:1034 src/process/do_process.cpp:1038
+msgid "Category"
+msgstr "Kategori"
+
+#: src/process/do_process.cpp:846 src/process/do_process.cpp:848
+#: src/process/do_process.cpp:914 src/process/do_process.cpp:917
+#: src/process/do_process.cpp:1034 src/process/do_process.cpp:1038
+msgid "Description"
+msgstr "Deskripsi"
+
+#: src/process/do_process.cpp:911
+msgid "Overview of Software Power Consumers"
+msgstr "Ringkasan Pemakai Daya Perangkat Lunak"
+
+#: src/process/do_process.cpp:914 src/process/do_process.cpp:917
+msgid "Wakeups/s"
+msgstr "Bangun/d"
+
+#: src/process/do_process.cpp:914 src/process/do_process.cpp:917
+msgid "GPU ops/s"
+msgstr "Op GPU/d"
+
+#: src/process/do_process.cpp:914 src/process/do_process.cpp:917
+msgid "Disk IO/s"
+msgstr "IO Disk/d"
+
+#: src/process/do_process.cpp:914 src/process/do_process.cpp:917
+msgid "GFX Wakeups/s"
+msgstr "GFX Bangun/d"
+
+#: src/process/do_process.cpp:1026
+msgid "Power Consumption Summary"
+msgstr "Ringkasan Konsumsi Daya"
+
+#: src/process/do_process.cpp:1029
+msgid "GPU ops/second"
+msgstr "Op GPU/detik"
+
+#: src/process/do_process.cpp:1030
+msgid "VFS ops/sec"
+msgstr "Op VFS/det"
+
+#: src/process/do_process.cpp:1030
+msgid "GFX wakes/sec and"
+msgstr "GFX bangu/det dan"
+
+#: src/perf/perf.cpp:121
+#, c-format
+msgid "PowerTOP %s needs the kernel to support the 'perf' subsystem\n"
+msgstr "PowerTop %s memerlukan kernel yang mendukung subsistem 'perf'\n"
+
+#: src/perf/perf.cpp:122
+#, c-format
+msgid "as well as support for trace points in the kernel:\n"
+msgstr "dan juga dukungan trace point dalam kernel:\n"
+
+#: src/devices/device.cpp:177
+#, c-format
+msgid "System baseline power is estimated at %sW\n"
+msgstr "Daya baseline sistem diperkirakan %sW\n"
+
+#: src/devices/device.cpp:184
+msgid "Power est.    Usage     Device name\n"
+msgstr "Est. daya     Pakai     Nama perangkat\n"
+
+#: src/devices/device.cpp:186
+msgid "              Usage     Device name\n"
+msgstr "              Pakai     Nama perangkat\n"
+
+#: src/devices/alsa.cpp:79
+#, c-format
+msgid "Audio codec %s: %s (%s)"
+msgstr "Codec audio %s: %s (%s)"
+
+#: src/devices/alsa.cpp:81 src/devices/alsa.cpp:83
+#, c-format
+msgid "Audio codec %s: %s"
+msgstr "Codec audio %s: %s"
+
+#: src/devices/runtime_pm.cpp:225
+#, c-format
+msgid "PCI Device: %s"
+msgstr "Perangkat PCI: %s"
+
+#: src/devices/usb.cpp:51 src/devices/usb.cpp:94 src/devices/usb.cpp:96
+#, c-format
+msgid "USB device: %s"
+msgstr "Perangkat USB: %s"
+
+#: src/devices/usb.cpp:92
+#, c-format
+msgid "USB device: %s (%s)"
+msgstr "Perangkat USB: %s (%s)"
+
+#: src/devices/ahci.cpp:140
+#, c-format
+msgid "SATA link: %s"
+msgstr "Link SATA: %s"
+
+#: src/devices/ahci.cpp:142
+#, c-format
+msgid "SATA disk: %s"
+msgstr "Disk SATA: %s"
+
+#: src/devices/rfkill.cpp:65 src/devices/rfkill.cpp:69
+#, c-format
+msgid "Radio device: %s"
+msgstr "Perangkat radio: %s"
+
+#: src/devices/network.cpp:177
+#, c-format
+msgid "Network interface: %s (%s)"
+msgstr "Antarmuka jaringa: %s (%s)"
+
+#: src/tuning/bluetooth.cpp:48
+#, c-format
+msgid "Bluetooth device interface status"
+msgstr "Status antarmuka perangkat Bluetooth"
+
+#: src/tuning/cpufreq.cpp:43 src/tuning/ethernet.cpp:53
+#: src/tuning/tunable.cpp:48 src/tuning/wifi.cpp:45 src/tuning/runtime.cpp:41
+#: src/tuning/tuningusb.cpp:40 src/tuning/tuningsysfs.cpp:37
+msgid "Good"
+msgstr "Baik"
+
+#: src/tuning/cpufreq.cpp:43 src/tuning/ethernet.cpp:53
+#: src/tuning/tunable.cpp:49 src/tuning/wifi.cpp:45 src/tuning/runtime.cpp:41
+#: src/tuning/tuningusb.cpp:40 src/tuning/tuningsysfs.cpp:37
+msgid "Bad"
+msgstr "Buruk"
+
+#: src/tuning/cpufreq.cpp:43 src/tuning/ethernet.cpp:53
+#: src/tuning/tunable.cpp:50 src/tuning/wifi.cpp:45 src/tuning/runtime.cpp:41
+#: src/tuning/tuningusb.cpp:40 src/tuning/tuningsysfs.cpp:37
+msgid "Unknown"
+msgstr "Tak diketahui"
+
+#: src/tuning/cpufreq.cpp:46
+#, c-format
+msgid "Using 'ondemand' cpufreq governor"
+msgstr "Memakai governor cpufreq 'ondemand'"
+
+#: src/tuning/tuning.cpp:60
+msgid "Enable Audio codec power management"
+msgstr "Aktifkan manajemen daya codec audio"
+
+#: src/tuning/tuning.cpp:61
+msgid "Enable SATA link power management for /dev/sda"
+msgstr "Aktifkan manajemen daya link SATA bagi /dev/sda"
+
+#: src/tuning/tuning.cpp:62
+msgid "NMI watchdog should be turned off"
+msgstr "Watchdog NMI mesti dimatikan"
+
+#: src/tuning/tuning.cpp:63
+msgid "Power Aware CPU scheduler"
+msgstr "Scheduler CPU Sadar Daya"
+
+#: src/tuning/tuning.cpp:64
+msgid "VM writeback timeout"
+msgstr "Tenggang waktu writeback VM"
+
+#: src/tuning/tuning.cpp:82
+msgid "Tunables"
+msgstr "Tunables"
+
+#: src/tuning/tuning.cpp:82
+msgid " <ESC> Exit | <Enter> Toggle tunable | <r> Window refresh"
+msgstr " <ESC> Keluar | <Enter> Jungkit tunable | <r> Segarkan jendela"
+
+#: src/tuning/ethernet.cpp:57
+#, c-format
+msgid "Wake-on-lan status for device %s"
+msgstr "Status wake-on-lan bagi perangkat %s"
+
+#: src/tuning/wifi.cpp:48
+#, c-format
+msgid "Wireless Power Saving for interface %s"
+msgstr "Penghematan Daya Nirkabel bagi antarmuka %s"
+
+#: src/tuning/runtime.cpp:47
+#, c-format
+msgid "Runtime PM for %s device %s"
+msgstr "PM runtime bagi %s perangkat %s"
+
+#: src/tuning/runtime.cpp:49
+#, c-format
+msgid "%s device %s has no runtime power management"
+msgstr "%s perangkat %s tak memiliki manajemen daya runtime"
+
+#: src/tuning/runtime.cpp:73
+#, c-format
+msgid "PCI Device %s has no runtime power management"
+msgstr "Perangkat PCI %s tak memiliki manajemen daya runtime"
+
+#: src/tuning/runtime.cpp:75
+#, c-format
+msgid "Runtime PM for PCI Device %s"
+msgstr "PM runtime bagi Perangkat PCI %s"
+
+#: src/tuning/tuningusb.cpp:55
+#, c-format
+msgid "Autosuspend for unknown USB device %s (%s:%s)"
+msgstr "Suspensi otomatis bagi perangkat USB tak dikenal %s (%s:%s)"
+
+#: src/tuning/tuningusb.cpp:72 src/tuning/tuningusb.cpp:74
+#: src/tuning/tuningusb.cpp:76
+#, c-format
+msgid "Autosuspend for USB device %s [%s]"
+msgstr "Suspensi otomatis bagi perangkat USB %s [%s]"
+
+#: src/calibrate/calibrate.cpp:291
+#, c-format
+msgid "Cannot create temp file\n"
+msgstr "Tak bisa membuat berkas temp\n"
+
+#: src/calibrate/calibrate.cpp:310
+#, c-format
+msgid "Calibrating: CPU usage on %i threads\n"
+msgstr "Kalibrasi: Pemakaian CPU pada %i thread \n"
+
+#: src/calibrate/calibrate.cpp:325
+#, c-format
+msgid "Calibrating: CPU wakeup power consumption\n"
+msgstr "Kalibrasi: Konsumsi daya CPU bangun \n"
+
+#: src/calibrate/calibrate.cpp:342
+#, c-format
+msgid "Calibrating USB devices\n"
+msgstr "Kalibrasi perangkat USB \n"
+
+#: src/calibrate/calibrate.cpp:344 src/calibrate/calibrate.cpp:361
+#: src/calibrate/calibrate.cpp:369 src/calibrate/calibrate.cpp:386
+#, c-format
+msgid ".... device %s \n"
+msgstr ".... perangkat %s \n"
+
+#: src/calibrate/calibrate.cpp:359
+#, c-format
+msgid "Calibrating radio devices\n"
+msgstr "Kalibrasi perangkat radio \n"
+
+#: src/calibrate/calibrate.cpp:383
+#, c-format
+msgid "Calibrating backlight\n"
+msgstr "Kalibrasi cahaya latar \n"
+
+#: src/calibrate/calibrate.cpp:407 src/calibrate/calibrate.cpp:415
+#, c-format
+msgid "Calibrating idle\n"
+msgstr "Kalibrasi menganggur \n"
+
+#: src/calibrate/calibrate.cpp:426
+#, c-format
+msgid "Calibrating: disk usage \n"
+msgstr "Kalibrasi: pemakaian disk \n"
+
+#: src/calibrate/calibrate.cpp:451
+msgid "Starting PowerTOP power estimate calibration \n"
+msgstr "Memulai kalibrasi estimasi daya PowerTop \n"
+
+#: src/calibrate/calibrate.cpp:474
+msgid "Finishing PowerTOP power estimate calibration \n"
+msgstr "Mengakhiri kalibrasi estimasi daya PowerTop \n"
+
+#: src/calibrate/calibrate.cpp:478
+#, c-format
+msgid "Parameters after calibration:\n"
+msgstr "Parameter setelah kalibrasi:\n"
+
+#: src/main.cpp:84
+#, c-format
+msgid "PowerTOP version"
+msgstr "PowerTop versi"
+
+#: src/main.cpp:90
+msgid "Set refresh time out"
+msgstr "Tata tenggang waktu penyegaran"
+
+#: src/main.cpp:103
+msgid "Usage: powertop [OPTIONS]"
+msgstr "Cara pakai: powertop [OPSI]"
+
+#: src/main.cpp:104
+msgid "run in \"debug\" mode"
+msgstr "jalankan dalam mode \"debug\""
+
+#: src/main.cpp:105
+msgid "print version information"
+msgstr "cetak informasi versi"
+
+#: src/main.cpp:106
+msgid "runs powertop in calibration mode"
+msgstr "jalankan powertop dalam mode kalibrasi"
+
+#: src/main.cpp:107
+msgid "[=devnode]"
+msgstr "[=devnode]"
+
+#: src/main.cpp:107
+msgid "uses an Extech Power Analyzer for measurements"
+msgstr "pakai Extech Power Analyzer untuk pengukuran"
+
+#: src/main.cpp:108 src/main.cpp:109
+msgid "[=FILENAME]"
+msgstr "[=NAMAFILE]"
+
+#: src/main.cpp:108
+msgid "generate a html report"
+msgstr "buat laporan html"
+
+#: src/main.cpp:109
+msgid "generate a csv report"
+msgstr "buat laporan csv"
+
+#: src/main.cpp:110
+msgid "[=seconds]"
+msgstr "[=detik]"
+
+#: src/main.cpp:110
+msgid "generate a report for 'x' seconds"
+msgstr "buat laporan untuk 'x' detik"
+
+#: src/main.cpp:111
+msgid "[=iterations] number of times to run each test"
+msgstr "[=iterasi] berapa kali menjalankan tiap tes"
+
+#: src/main.cpp:112
+msgid "print this help menu"
+msgstr "cetik menu bantuan ini"
+
+#: src/main.cpp:114
+msgid "For more help please refer to the README"
+msgstr "Untuk bantuan lebih lanjut lihatlah README"
+
+#: src/main.cpp:224
+#, c-format
+msgid "PowerTOP is out of memory. PowerTOP is Aborting"
+msgstr "PowerTop kehabisan memori. PowerTop digugurkan."
+
+#: src/main.cpp:252
+#, c-format
+msgid "Preparing to take measurements\n"
+msgstr "Bersiap melakukan pengkukuran\n"
+
+#: src/main.cpp:255
+#, c-format
+msgid "Taking %d measurement(s) for a duration of %d second(s) each.\n"
+msgstr "Melakukan %d pengukuran selama masing-masing %d detik.\n"
+
+#: src/main.cpp:278
+#, c-format
+msgid "PowerTOP "
+msgstr "PowerTOP "
+
+#: src/main.cpp:279 src/main.cpp:307
+#, c-format
+msgid "exiting...\n"
+msgstr "keluar...\n"
+
+#: src/main.cpp:306
+#, c-format
+msgid "Failed to mount debugfs!\n"
+msgstr "Gagal mengait debugfs!\n"
+
+#: src/main.cpp:443
+#, c-format
+msgid "Leaving PowerTOP"
+msgstr "Meninggalkan PowerTop"
diff --git a/po/lt.po b/po/lt.po
new file mode 100644 (file)
index 0000000..e4f37be
--- /dev/null
+++ b/po/lt.po
@@ -0,0 +1,587 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR Intel Corporation
+# This file is distributed under the same license as the PACKAGE package.
+# 
+# Translators:
+# Simonas Kazlauskas <simonas@kazlauskas.me>, 2012.
+msgid ""
+msgstr ""
+"Project-Id-Version: PowerTOP\n"
+"Report-Msgid-Bugs-To: \"powertop@lists.01.org\"\n"
+"POT-Creation-Date: 2012-10-26 09:24-0700\n"
+"PO-Revision-Date: 2012-10-26 22:23+0000\n"
+"Last-Translator: ceferron <chris.e.ferron@linux.intel.com>\n"
+"Language-Team: Lithuanian (http://www.transifex.com/projects/p/PowerTOP/language/lt/)\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Language: lt\n"
+"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
+
+#: src/parameters/persistent.cpp:46 src/parameters/persistent.cpp:140
+msgid "Cannot save to file"
+msgstr ""
+
+#: src/parameters/persistent.cpp:78 src/parameters/persistent.cpp:165
+msgid "Cannot load from file"
+msgstr ""
+
+#: src/parameters/persistent.cpp:123
+#, c-format
+msgid "Loaded %i prior measurements\n"
+msgstr "Įkelti %i ankstesni matavimai\\n"
+
+#: src/display.cpp:70
+msgid "Overview"
+msgstr "Apžvalga"
+
+#: src/display.cpp:71
+msgid "Idle stats"
+msgstr "Neveikos statistika"
+
+#: src/display.cpp:72
+msgid "Frequency stats"
+msgstr "Dažnių statistika"
+
+#: src/display.cpp:73
+msgid "Device stats"
+msgstr "Įrenginių statistika"
+
+#: src/display.cpp:130
+msgid "Exit"
+msgstr "Išeiti"
+
+#: src/cpu/cpu_core.cpp:111 src/cpu/cpu_linux.cpp:360
+#: src/cpu/cpu_package.cpp:133 src/cpu/intel_cpus.cpp:222
+#: src/cpu/intel_cpus.cpp:444 src/cpu/intel_cpus.cpp:639
+msgid "Idle"
+msgstr "Neveika"
+
+#: src/cpu/cpu_core.cpp:113 src/cpu/cpu_linux.cpp:362
+#: src/cpu/cpu_package.cpp:135 src/cpu/intel_cpus.cpp:224
+#: src/cpu/intel_cpus.cpp:446
+#, c-format
+msgid "Turbo Mode"
+msgstr "Turbo režimas"
+
+#: src/cpu/cpu.cpp:93
+#, c-format
+msgid "cpu package %i"
+msgstr "%i procesorių paketas"
+
+#: src/cpu/cpu.cpp:94
+msgid "cpu package"
+msgstr "procesorių paketas"
+
+#: src/cpu/cpu.cpp:437 src/cpu/cpu.cpp:563
+#, c-format
+msgid "Package %i"
+msgstr ""
+
+#: src/cpu/cpu.cpp:469 src/cpu/cpu.cpp:583
+#, c-format
+msgid "Core %i"
+msgstr ""
+
+#: src/cpu/cpu.cpp:471
+#, c-format
+msgid "GPU %i"
+msgstr ""
+
+#: src/cpu/cpu.cpp:493 src/cpu/cpu.cpp:604
+#, c-format
+msgid "CPU %i"
+msgstr ""
+
+#: src/cpu/cpu.cpp:772
+#, c-format
+msgid "cpu_idle event returned no state?\n"
+msgstr "cpu_idle įvykis negrąžino būsenos?\\n"
+
+#: src/cpu/cpu.cpp:787
+#, c-format
+msgid "power or cpu_frequecny event returned no state?\n"
+msgstr "power arba cpu_frequency įvykis negrąžino būsenos?\\n"
+
+#: src/cpu/cpu_linux.cpp:92
+msgid "C0 polling"
+msgstr "C0 laukia"
+
+#: src/cpu/intel_cpus.cpp:69
+#, c-format
+msgid "msr reg not found"
+msgstr "msr reg nerastas"
+
+#: src/cpu/intel_cpus.cpp:79
+#, c-format
+msgid "pread cpu%d 0x%llx : "
+msgstr "pread cpu%d 0x%llx:"
+
+#: src/cpu/intel_cpus.cpp:516
+msgid "C0 active"
+msgstr "C0 aktyvus"
+
+#: src/cpu/intel_cpus.cpp:575
+#, c-format
+msgid "Actual"
+msgstr "Tikrasis"
+
+#: src/lib.cpp:257
+#, c-format
+msgid "%7sW"
+msgstr "%7sW"
+
+#: src/lib.cpp:260
+#, c-format
+msgid "    0 mW"
+msgstr "0 mW"
+
+#: src/lib.cpp:381
+msgid "PS/2 Touchpad / Keyboard / Mouse"
+msgstr "PS/2 Jutiklinis kilimėlis / Klaviatūra / Pėlė"
+
+#: src/lib.cpp:382
+msgid "SATA controller"
+msgstr "SATA kontroleris"
+
+#: src/lib.cpp:383
+msgid "Intel built in USB hub"
+msgstr "Integruotas Intel USB centras"
+
+#: src/process/do_process.cpp:830
+#, c-format
+msgid ""
+"Estimated power: %5.1f    Measured power: %5.1f    Sum: %5.1f\n"
+"\n"
+msgstr "Apytikrė energija: %5.1f Pamatuota energija: %5.1f  Suma: %5.1f\\n\\n"
+
+#: src/process/do_process.cpp:841 src/devices/device.cpp:171
+#, c-format
+msgid "The battery reports a discharge rate of %sW\n"
+msgstr "Akumuliatorius praneša %sW išsikrovimo greitį\\n"
+
+#: src/process/do_process.cpp:846
+#, c-format
+msgid "The estimated remaining time is %i hours, %i minutes\n"
+msgstr "Apskaičiuotas likęs laikas – %i valandos ir %i minutės\\n"
+
+#: src/process/do_process.cpp:854
+msgid "Summary"
+msgstr "Santrauka"
+
+#: src/process/do_process.cpp:854 src/process/do_process.cpp:1024
+msgid "wakeups/second"
+msgstr "pabudimai/sekundę"
+
+#: src/process/do_process.cpp:854
+msgid "GPU ops/seconds"
+msgstr "Grafikos posistemės operacijos/sekundes"
+
+#: src/process/do_process.cpp:854
+msgid "VFS ops/sec and"
+msgstr "Virtualios failų sistemos operacijos/sek ir"
+
+#: src/process/do_process.cpp:854 src/process/do_process.cpp:1028
+msgid "CPU use"
+msgstr "Procesoriaus naudojimas"
+
+#: src/process/do_process.cpp:858 src/process/do_process.cpp:915
+#: src/process/do_process.cpp:1034
+msgid "Power est."
+msgstr "Energijos įvertis"
+
+#: src/process/do_process.cpp:858 src/process/do_process.cpp:860
+#: src/process/do_process.cpp:919 src/process/do_process.cpp:1038
+msgid "Usage"
+msgstr "Naudojimas"
+
+#: src/process/do_process.cpp:858 src/process/do_process.cpp:860
+#: src/process/do_process.cpp:1040
+msgid "Events/s"
+msgstr "Įvykiai/s"
+
+#: src/process/do_process.cpp:858 src/process/do_process.cpp:860
+#: src/process/do_process.cpp:929 src/process/do_process.cpp:1042
+msgid "Category"
+msgstr "Kategorija"
+
+#: src/process/do_process.cpp:858 src/process/do_process.cpp:860
+#: src/process/do_process.cpp:931 src/process/do_process.cpp:1044
+msgid "Description"
+msgstr "Aprašymas"
+
+#: src/process/do_process.cpp:910
+msgid "Overview of Software Power Consumers"
+msgstr "Programinės įrangos energijos naudojimo apžvalga"
+
+#: src/process/do_process.cpp:921
+msgid "Wakeups/s"
+msgstr "Pabudimai/s"
+
+#: src/process/do_process.cpp:923
+msgid "GPU ops/s"
+msgstr "Grafikos posistemės operacijos/s"
+
+#: src/process/do_process.cpp:925
+msgid "Disk IO/s"
+msgstr "Disko operacijos/s"
+
+#: src/process/do_process.cpp:927
+msgid "GFX Wakeups/s"
+msgstr "GFX pabudimai/s"
+
+#: src/process/do_process.cpp:1021
+msgid "Power Consumption Summary"
+msgstr "Energijos sąnaudų aprašymas"
+
+#: src/process/do_process.cpp:1025
+msgid "GPU ops/second"
+msgstr "Grafikos posistemės operacijos/sekundę"
+
+#: src/process/do_process.cpp:1026
+msgid "VFS ops/sec"
+msgstr "Virtualios failų sistemos operacijos/sek"
+
+#: src/process/do_process.cpp:1027
+msgid "GFX wakes/sec and"
+msgstr "GFX pabudimai/sek ir"
+
+#: src/perf/perf.cpp:111
+#, c-format
+msgid "PowerTOP %s needs the kernel to support the 'perf' subsystem\n"
+msgstr "PowerTOP %s reikalingas 'perf' posistemės\\n"
+
+#: src/perf/perf.cpp:112
+#, c-format
+msgid "as well as support for trace points in the kernel:\n"
+msgstr "ir sekimo taškų palaikymas branduolyje:\\n"
+
+#: src/devices/device.cpp:177
+#, c-format
+msgid "System baseline power is estimated at %sW\n"
+msgstr "Apytikrė Sistemos bazinė energija yra %sW\\n"
+
+#: src/devices/device.cpp:184
+msgid "Power est.    Usage     Device name\n"
+msgstr "Apytikrė energija Naudojimas Įrenginio vardas\\n"
+
+#: src/devices/device.cpp:186
+msgid "              Usage     Device name\n"
+msgstr "Sąnaudos Įrenginio pavadinimas\\n"
+
+#: src/devices/alsa.cpp:79
+#, c-format
+msgid "Audio codec %s: %s (%s)"
+msgstr "Garso kodekas %s: %s (%s)"
+
+#: src/devices/alsa.cpp:81 src/devices/alsa.cpp:83
+#, c-format
+msgid "Audio codec %s: %s"
+msgstr "Garso kodekas %s: %s"
+
+#: src/devices/runtime_pm.cpp:225
+#, c-format
+msgid "PCI Device: %s"
+msgstr "PCI įrenginys: %s"
+
+#: src/devices/usb.cpp:51 src/devices/usb.cpp:94 src/devices/usb.cpp:96
+#, c-format
+msgid "USB device: %s"
+msgstr "USB įrenginys: %s"
+
+#: src/devices/usb.cpp:92
+#, c-format
+msgid "USB device: %s (%s)"
+msgstr "USB įrenginys: %s (%s)"
+
+#: src/devices/ahci.cpp:140
+#, c-format
+msgid "SATA link: %s"
+msgstr "SATA sąsaja: %s"
+
+#: src/devices/ahci.cpp:142
+#, c-format
+msgid "SATA disk: %s"
+msgstr "SATA diskas: %s"
+
+#: src/devices/rfkill.cpp:65 src/devices/rfkill.cpp:69
+#, c-format
+msgid "Radio device: %s"
+msgstr "Radijo imtuvas: %s"
+
+#: src/devices/network.cpp:177
+#, c-format
+msgid "Network interface: %s (%s)"
+msgstr "Tinklo sąsaja: %s (%s)"
+
+#: src/tuning/bluetooth.cpp:48
+#, c-format
+msgid "Bluetooth device interface status"
+msgstr "Bluetooth įrenginio sąsajos būsena"
+
+#: src/tuning/cpufreq.cpp:43 src/tuning/ethernet.cpp:53
+#: src/tuning/tunable.cpp:48 src/tuning/wifi.cpp:45 src/tuning/runtime.cpp:41
+#: src/tuning/tuningusb.cpp:40 src/tuning/tuningsysfs.cpp:44
+msgid "Good"
+msgstr "Gerai"
+
+#: src/tuning/cpufreq.cpp:43 src/tuning/ethernet.cpp:53
+#: src/tuning/tunable.cpp:49 src/tuning/wifi.cpp:45 src/tuning/runtime.cpp:41
+#: src/tuning/tuningusb.cpp:40 src/tuning/tuningsysfs.cpp:44
+msgid "Bad"
+msgstr "Blogai"
+
+#: src/tuning/cpufreq.cpp:43 src/tuning/ethernet.cpp:53
+#: src/tuning/tunable.cpp:50 src/tuning/wifi.cpp:45 src/tuning/runtime.cpp:41
+#: src/tuning/tuningusb.cpp:40 src/tuning/tuningsysfs.cpp:44
+msgid "Unknown"
+msgstr "Nežinoma"
+
+#: src/tuning/cpufreq.cpp:46
+#, c-format
+msgid "Using 'ondemand' cpufreq governor"
+msgstr "Naudojamas 'ondemand' cpufreq valdytojas"
+
+#: src/tuning/tuning.cpp:59
+msgid "Enable Audio codec power management"
+msgstr "Įjungti garso kodekų energijos valdymą"
+
+#: src/tuning/tuning.cpp:60
+msgid "NMI watchdog should be turned off"
+msgstr "NMI kontrolierius turėtų būti išjungtas"
+
+#: src/tuning/tuning.cpp:61
+msgid "Power Aware CPU scheduler"
+msgstr "Energijos sąnaudas suprantantis procesoriaus valdytojas"
+
+#: src/tuning/tuning.cpp:62
+msgid "VM writeback timeout"
+msgstr "Laikas iki virtualiosios mašinos kešo išrašymo"
+
+#: src/tuning/tuning.cpp:79
+msgid "Tunables"
+msgstr "Deriniai"
+
+#: src/tuning/tuning.cpp:79
+msgid " <ESC> Exit | <Enter> Toggle tunable | <r> Window refresh"
+msgstr "<ESC> Išeiti | <Enter> Perjungti derinį | <r> Perkrauti langą"
+
+#: src/tuning/ethernet.cpp:57
+#, c-format
+msgid "Wake-on-lan status for device %s"
+msgstr "Wake-on-lan būsena įrenginiui %s"
+
+#: src/tuning/wifi.cpp:48
+#, c-format
+msgid "Wireless Power Saving for interface %s"
+msgstr "Energijos saugojimas bevielio ryšio įrenginiui %s"
+
+#: src/tuning/runtime.cpp:47
+#, c-format
+msgid "Runtime PM for %s device %s"
+msgstr "%s įrengnio %s energijos valdymas jo veikimo metu"
+
+#: src/tuning/runtime.cpp:49
+#, c-format
+msgid "%s device %s has no runtime power management"
+msgstr "%s įrenginys %s neturi energijos valdymo veikimo metu"
+
+#: src/tuning/runtime.cpp:73
+#, c-format
+msgid "PCI Device %s has no runtime power management"
+msgstr "PCI įrenginys %s neturi energijos valdymo veikimo metu"
+
+#: src/tuning/runtime.cpp:75
+#, c-format
+msgid "Runtime PM for PCI Device %s"
+msgstr "PCI įrenginio %s energijos valdymas jo veikimo metu"
+
+#: src/tuning/tuningusb.cpp:55
+#, c-format
+msgid "Autosuspend for unknown USB device %s (%s:%s)"
+msgstr "Automatinis nežinomo USB įrenginio %s (%s:%s) užmigdymas"
+
+#: src/tuning/tuningusb.cpp:72 src/tuning/tuningusb.cpp:74
+#: src/tuning/tuningusb.cpp:76
+#, c-format
+msgid "Autosuspend for USB device %s [%s]"
+msgstr "Automatinis USB įrenginio %s [%s] užmigdymas"
+
+#: src/tuning/tuningsysfs.cpp:142
+#, c-format
+msgid "Enable SATA link power Managmenet for %s"
+msgstr ""
+
+#: src/calibrate/calibrate.cpp:291
+#, c-format
+msgid "Cannot create temp file\n"
+msgstr "Negalima sukurti laikino failo\\n"
+
+#: src/calibrate/calibrate.cpp:310
+#, c-format
+msgid "Calibrating: CPU usage on %i threads\n"
+msgstr "Kalibruojama: procesoriaus sąnaudos veikiant %i gijoms\\n"
+
+#: src/calibrate/calibrate.cpp:325
+#, c-format
+msgid "Calibrating: CPU wakeup power consumption\n"
+msgstr "Kalibruojama: procesoriaus pabudimų energijos sąnaudos\\n"
+
+#: src/calibrate/calibrate.cpp:342
+#, c-format
+msgid "Calibrating USB devices\n"
+msgstr "Kalibruojami USB įrenginiai\\n"
+
+#: src/calibrate/calibrate.cpp:344 src/calibrate/calibrate.cpp:361
+#: src/calibrate/calibrate.cpp:369 src/calibrate/calibrate.cpp:386
+#, c-format
+msgid ".... device %s \n"
+msgstr "… įrenginys %s\\n"
+
+#: src/calibrate/calibrate.cpp:359
+#, c-format
+msgid "Calibrating radio devices\n"
+msgstr "Kalibruojami radijo imtuvai\\n"
+
+#: src/calibrate/calibrate.cpp:383
+#, c-format
+msgid "Calibrating backlight\n"
+msgstr "Kalibruojamas apšvietimas\\n"
+
+#: src/calibrate/calibrate.cpp:407 src/calibrate/calibrate.cpp:415
+#, c-format
+msgid "Calibrating idle\n"
+msgstr "Kalibruojama neveika\\n"
+
+#: src/calibrate/calibrate.cpp:426
+#, c-format
+msgid "Calibrating: disk usage \n"
+msgstr "Kalibruojama: disko naudojimas\\n"
+
+#: src/calibrate/calibrate.cpp:451
+msgid "Starting PowerTOP power estimate calibration \n"
+msgstr "Pradedama PowerTop energijos vertinimo kalibracija\\n"
+
+#: src/calibrate/calibrate.cpp:474
+msgid "Finishing PowerTOP power estimate calibration \n"
+msgstr "Užbaigiama PowerTOP energijos vertinimo kalibracija\\n"
+
+#: src/calibrate/calibrate.cpp:478
+#, c-format
+msgid "Parameters after calibration:\n"
+msgstr "Parametrai po kalibracijos:\\n"
+
+#: src/main.cpp:86
+#, c-format
+msgid "PowerTOP version"
+msgstr "PowerTOP versija"
+
+#: src/main.cpp:92
+msgid "Set refresh time out"
+msgstr "Nustatyti atnaujimui skirtą laiką"
+
+#: src/main.cpp:105
+msgid "Usage: powertop [OPTIONS]"
+msgstr "Naudojimas: powertop [NUOSTATOS]"
+
+#: src/main.cpp:106
+msgid "run in \"debug\" mode"
+msgstr "paleisti derinimo režimu"
+
+#: src/main.cpp:107
+msgid "print version information"
+msgstr "spausdinti informaciją apie versiją"
+
+#: src/main.cpp:108
+msgid "runs powertop in calibration mode"
+msgstr "leidžia powertop kalibravimo režimu"
+
+#: src/main.cpp:109
+msgid "[=devnode]"
+msgstr "[=įrenginio mazgas]"
+
+#: src/main.cpp:109
+msgid "uses an Extech Power Analyzer for measurements"
+msgstr "Matavimams naudojamas Extech energijos analizatorius"
+
+#: src/main.cpp:110 src/main.cpp:111
+msgid "[=FILENAME]"
+msgstr "[=FAILO VARDAS]"
+
+#: src/main.cpp:110
+msgid "generate a html report"
+msgstr "generuoti raportą html formatu"
+
+#: src/main.cpp:111
+msgid "generate a csv report"
+msgstr "generuoti raportą csv formatu"
+
+#: src/main.cpp:112
+msgid "[=seconds]"
+msgstr "[=sekundės]"
+
+#: src/main.cpp:112
+msgid "generate a report for 'x' seconds"
+msgstr "generuoti x sekundžių raportą"
+
+#: src/main.cpp:113
+msgid "[=iterations] number of times to run each test"
+msgstr "[=iteracijos] kiekvieno testo atlikimų skaičius"
+
+#: src/main.cpp:114
+msgid "[=workload]"
+msgstr ""
+
+#: src/main.cpp:114
+msgid "file to execute for workload"
+msgstr ""
+
+#: src/main.cpp:115
+msgid "suppress stderr output"
+msgstr ""
+
+#: src/main.cpp:116
+msgid "print this help menu"
+msgstr "spausdina šį pagalbos pranešimą"
+
+#: src/main.cpp:118
+msgid "For more help please refer to the README"
+msgstr "Daugiau pagalbos ieškokite README faile"
+
+#: src/main.cpp:235
+msgid "PowerTOP is out of memory. PowerTOP is Aborting"
+msgstr "PowerTOP neužtenka atminties. PowerTOP išjungiamas"
+
+#: src/main.cpp:243
+#, c-format
+msgid "Preparing to take measurements\n"
+msgstr "Ruošiamasi matavimams\\n"
+
+#: src/main.cpp:248
+#, c-format
+msgid "Taking %d measurement(s) for a duration of %d second(s) each.\n"
+msgstr "Imami %d matavimas(–ai) kas %d sekundę(–es).\\n"
+
+#: src/main.cpp:250
+#, c-format
+msgid "Measuring workload %s.\n"
+msgstr ""
+
+#: src/main.cpp:273
+#, c-format
+msgid "PowerTOP "
+msgstr "PowerTOP"
+
+#: src/main.cpp:274 src/main.cpp:302
+#, c-format
+msgid "exiting...\n"
+msgstr "išjungiama...\\n"
+
+#: src/main.cpp:301
+#, c-format
+msgid "Failed to mount debugfs!\n"
+msgstr "Nepavyko prijungti debugfs!\\n"
+
+#: src/main.cpp:438
+msgid "Leaving PowerTOP"
+msgstr "PowerTOP išjungiamas"
diff --git a/po/nl_NL.po b/po/nl_NL.po
new file mode 100644 (file)
index 0000000..59cbab8
--- /dev/null
@@ -0,0 +1,576 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR Intel Corporation
+# This file is distributed under the same license as the PACKAGE package.
+# 
+# Translators:
+#   <auke-jan.h.kok@intel.com>, 2012.
+#   <jan.ceuleers@computer.org>, 2012.
+msgid ""
+msgstr ""
+"Project-Id-Version: PowerTOP\n"
+"Report-Msgid-Bugs-To: \"powertop@lists.01.org\"\n"
+"POT-Creation-Date: 2012-05-31 14:03-0700\n"
+"PO-Revision-Date: 2012-05-31 22:35+0000\n"
+"Last-Translator: Patrick McCarty <patrick.mccarty@linux.intel.com>\n"
+"Language-Team: Dutch (Netherlands) (http://www.transifex.com/projects/p/PowerTOP/language/nl_NL/)\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Language: nl_NL\n"
+"Plural-Forms: nplurals=2; plural=(n != 1)\n"
+
+#: src/parameters/persistent.cpp:46 src/parameters/persistent.cpp:140
+msgid "Cannot save to file "
+msgstr "Kan niet opslaan in bestand  "
+
+#: src/parameters/persistent.cpp:78 src/parameters/persistent.cpp:165
+msgid "Cannot load from file "
+msgstr "Kan bestand niet inladen  "
+
+#: src/parameters/persistent.cpp:123
+#, c-format
+msgid "Loaded %i prior measurements\n"
+msgstr "%i eerdere metingen ingeladen\n"
+
+#: src/display.cpp:71
+msgid "Overview"
+msgstr "Overzicht"
+
+#: src/display.cpp:72
+msgid "Idle stats"
+msgstr "Rust stats"
+
+#: src/display.cpp:73
+msgid "Frequency stats"
+msgstr "Frekwentie stats"
+
+#: src/display.cpp:74
+msgid "Device stats"
+msgstr "Apparaat stats"
+
+#: src/display.cpp:131
+msgid "Exit"
+msgstr ""
+
+#: src/cpu/cpu_core.cpp:46 src/cpu/cpu_core.cpp:190 src/cpu/intel_cpus.cpp:296
+#, c-format
+msgid "  Core"
+msgstr "  Core"
+
+#: src/cpu/cpu_core.cpp:116 src/cpu/cpu_linux.cpp:329
+#: src/cpu/cpu_package.cpp:145 src/cpu/intel_cpus.cpp:222
+#: src/cpu/intel_cpus.cpp:457 src/cpu/intel_cpus.cpp:658
+msgid "Idle"
+msgstr "Idle"
+
+#: src/cpu/cpu_core.cpp:118 src/cpu/cpu_linux.cpp:331
+#: src/cpu/cpu_package.cpp:147 src/cpu/intel_cpus.cpp:224
+#: src/cpu/intel_cpus.cpp:459
+#, c-format
+msgid "Turbo Mode"
+msgstr "Turbo Mode"
+
+#: src/cpu/cpu.cpp:90
+#, c-format
+msgid "cpu package %i"
+msgstr "cpu package %i"
+
+#: src/cpu/cpu.cpp:91
+msgid "cpu package"
+msgstr "cpu package"
+
+#: src/cpu/cpu.cpp:925
+#, c-format
+msgid "cpu_idle event returned no state?\n"
+msgstr ""
+
+#: src/cpu/cpu.cpp:940
+#, c-format
+msgid "power or cpu_frequecny event returned no state?\n"
+msgstr ""
+
+#: src/cpu/cpu_linux.cpp:92
+msgid "C0 polling"
+msgstr "C0 polling"
+
+#: src/cpu/cpu_linux.cpp:231 src/cpu/cpu_linux.cpp:289
+#: src/cpu/intel_cpus.cpp:605
+#, c-format
+msgid " CPU %i"
+msgstr " CPU %i"
+
+#: src/cpu/cpu_package.cpp:46
+#, c-format
+msgid "Package"
+msgstr "Package"
+
+#: src/cpu/cpu_package.cpp:104 src/cpu/intel_cpus.cpp:322
+#, c-format
+msgid "  Package"
+msgstr "  Package"
+
+#: src/cpu/intel_cpus.cpp:69
+#, c-format
+msgid "msr reg not found"
+msgstr ""
+
+#: src/cpu/intel_cpus.cpp:79
+#, c-format
+msgid "pread cpu%d 0x%llx : "
+msgstr ""
+
+#: src/cpu/intel_cpus.cpp:529
+msgid "C0 active"
+msgstr "C0 active"
+
+#: src/cpu/intel_cpus.cpp:588
+#, c-format
+msgid "Actual"
+msgstr "Huidig"
+
+#: src/lib.cpp:257
+#, c-format
+msgid "%7sW"
+msgstr "%7sW"
+
+#: src/lib.cpp:260
+#, c-format
+msgid "    0 mW"
+msgstr "    0 mW"
+
+#: src/lib.cpp:369
+msgid "PS/2 Touchpad / Keyboard / Mouse"
+msgstr ""
+
+#: src/lib.cpp:370
+msgid "SATA controller"
+msgstr ""
+
+#: src/lib.cpp:371
+msgid "Intel built in USB hub"
+msgstr ""
+
+#: src/process/do_process.cpp:818
+#, c-format
+msgid ""
+"Estimated power: %5.1f    Measured power: %5.1f    Sum: %5.1f\n"
+"\n"
+msgstr ""
+
+#: src/process/do_process.cpp:829 src/devices/device.cpp:171
+#, c-format
+msgid "The battery reports a discharge rate of %sW\n"
+msgstr ""
+
+#: src/process/do_process.cpp:834
+#, c-format
+msgid "The estimated remaining time is %i hours, %i minutes\n"
+msgstr ""
+
+#: src/process/do_process.cpp:842
+msgid "Summary"
+msgstr ""
+
+#: src/process/do_process.cpp:842 src/process/do_process.cpp:1029
+msgid "wakeups/second"
+msgstr ""
+
+#: src/process/do_process.cpp:842
+msgid "GPU ops/seconds"
+msgstr ""
+
+#: src/process/do_process.cpp:842
+msgid "VFS ops/sec and"
+msgstr ""
+
+#: src/process/do_process.cpp:842 src/process/do_process.cpp:1030
+msgid "CPU use"
+msgstr ""
+
+#: src/process/do_process.cpp:846 src/process/do_process.cpp:914
+#: src/process/do_process.cpp:1034
+msgid "Power est."
+msgstr ""
+
+#: src/process/do_process.cpp:846 src/process/do_process.cpp:848
+#: src/process/do_process.cpp:914 src/process/do_process.cpp:917
+#: src/process/do_process.cpp:1034 src/process/do_process.cpp:1038
+msgid "Usage"
+msgstr ""
+
+#: src/process/do_process.cpp:846 src/process/do_process.cpp:848
+#: src/process/do_process.cpp:1034 src/process/do_process.cpp:1038
+msgid "Events/s"
+msgstr ""
+
+#: src/process/do_process.cpp:846 src/process/do_process.cpp:848
+#: src/process/do_process.cpp:914 src/process/do_process.cpp:917
+#: src/process/do_process.cpp:1034 src/process/do_process.cpp:1038
+msgid "Category"
+msgstr ""
+
+#: src/process/do_process.cpp:846 src/process/do_process.cpp:848
+#: src/process/do_process.cpp:914 src/process/do_process.cpp:917
+#: src/process/do_process.cpp:1034 src/process/do_process.cpp:1038
+msgid "Description"
+msgstr ""
+
+#: src/process/do_process.cpp:911
+msgid "Overview of Software Power Consumers"
+msgstr ""
+
+#: src/process/do_process.cpp:914 src/process/do_process.cpp:917
+msgid "Wakeups/s"
+msgstr ""
+
+#: src/process/do_process.cpp:914 src/process/do_process.cpp:917
+msgid "GPU ops/s"
+msgstr ""
+
+#: src/process/do_process.cpp:914 src/process/do_process.cpp:917
+msgid "Disk IO/s"
+msgstr ""
+
+#: src/process/do_process.cpp:914 src/process/do_process.cpp:917
+msgid "GFX Wakeups/s"
+msgstr ""
+
+#: src/process/do_process.cpp:1026
+msgid "Power Consumption Summary"
+msgstr ""
+
+#: src/process/do_process.cpp:1029
+msgid "GPU ops/second"
+msgstr ""
+
+#: src/process/do_process.cpp:1030
+msgid "VFS ops/sec"
+msgstr ""
+
+#: src/process/do_process.cpp:1030
+msgid "GFX wakes/sec and"
+msgstr ""
+
+#: src/perf/perf.cpp:121
+#, c-format
+msgid "PowerTOP %s needs the kernel to support the 'perf' subsystem\n"
+msgstr ""
+
+#: src/perf/perf.cpp:122
+#, c-format
+msgid "as well as support for trace points in the kernel:\n"
+msgstr ""
+
+#: src/devices/device.cpp:177
+#, c-format
+msgid "System baseline power is estimated at %sW\n"
+msgstr ""
+
+#: src/devices/device.cpp:184
+msgid "Power est.    Usage     Device name\n"
+msgstr ""
+
+#: src/devices/device.cpp:186
+msgid "              Usage     Device name\n"
+msgstr ""
+
+#: src/devices/alsa.cpp:79
+#, c-format
+msgid "Audio codec %s: %s (%s)"
+msgstr ""
+
+#: src/devices/alsa.cpp:81 src/devices/alsa.cpp:83
+#, c-format
+msgid "Audio codec %s: %s"
+msgstr ""
+
+#: src/devices/runtime_pm.cpp:225
+#, c-format
+msgid "PCI Device: %s"
+msgstr ""
+
+#: src/devices/usb.cpp:51 src/devices/usb.cpp:94 src/devices/usb.cpp:96
+#, c-format
+msgid "USB device: %s"
+msgstr ""
+
+#: src/devices/usb.cpp:92
+#, c-format
+msgid "USB device: %s (%s)"
+msgstr ""
+
+#: src/devices/ahci.cpp:140
+#, c-format
+msgid "SATA link: %s"
+msgstr ""
+
+#: src/devices/ahci.cpp:142
+#, c-format
+msgid "SATA disk: %s"
+msgstr ""
+
+#: src/devices/rfkill.cpp:65 src/devices/rfkill.cpp:69
+#, c-format
+msgid "Radio device: %s"
+msgstr ""
+
+#: src/devices/network.cpp:177
+#, c-format
+msgid "Network interface: %s (%s)"
+msgstr ""
+
+#: src/tuning/bluetooth.cpp:48
+#, c-format
+msgid "Bluetooth device interface status"
+msgstr ""
+
+#: src/tuning/cpufreq.cpp:43 src/tuning/ethernet.cpp:53
+#: src/tuning/tunable.cpp:48 src/tuning/wifi.cpp:45 src/tuning/runtime.cpp:41
+#: src/tuning/tuningusb.cpp:40 src/tuning/tuningsysfs.cpp:37
+msgid "Good"
+msgstr "Goed"
+
+#: src/tuning/cpufreq.cpp:43 src/tuning/ethernet.cpp:53
+#: src/tuning/tunable.cpp:49 src/tuning/wifi.cpp:45 src/tuning/runtime.cpp:41
+#: src/tuning/tuningusb.cpp:40 src/tuning/tuningsysfs.cpp:37
+msgid "Bad"
+msgstr "Slecht"
+
+#: src/tuning/cpufreq.cpp:43 src/tuning/ethernet.cpp:53
+#: src/tuning/tunable.cpp:50 src/tuning/wifi.cpp:45 src/tuning/runtime.cpp:41
+#: src/tuning/tuningusb.cpp:40 src/tuning/tuningsysfs.cpp:37
+msgid "Unknown"
+msgstr "Onbekend"
+
+#: src/tuning/cpufreq.cpp:46
+#, c-format
+msgid "Using 'ondemand' cpufreq governor"
+msgstr "'ondemand' cpufreq governor in gebruik"
+
+#: src/tuning/tuning.cpp:60
+msgid "Enable Audio codec power management"
+msgstr "Audio codec energiebeheer inschakelen"
+
+#: src/tuning/tuning.cpp:61
+msgid "Enable SATA link power management for /dev/sda"
+msgstr "SATA link energiebeheer voor /dev/sda inschakelen"
+
+#: src/tuning/tuning.cpp:62
+msgid "NMI watchdog should be turned off"
+msgstr "NMI watchdog is beter uitgeschakeld"
+
+#: src/tuning/tuning.cpp:63
+msgid "Power Aware CPU scheduler"
+msgstr ""
+
+#: src/tuning/tuning.cpp:64
+msgid "VM writeback timeout"
+msgstr ""
+
+#: src/tuning/tuning.cpp:82
+msgid "Tunables"
+msgstr ""
+
+#: src/tuning/tuning.cpp:82
+msgid " <ESC> Exit | <Enter> Toggle tunable | <r> Window refresh"
+msgstr ""
+
+#: src/tuning/ethernet.cpp:57
+#, c-format
+msgid "Wake-on-lan status for device %s"
+msgstr ""
+
+#: src/tuning/wifi.cpp:48
+#, c-format
+msgid "Wireless Power Saving for interface %s"
+msgstr ""
+
+#: src/tuning/runtime.cpp:47
+#, c-format
+msgid "Runtime PM for %s device %s"
+msgstr ""
+
+#: src/tuning/runtime.cpp:49
+#, c-format
+msgid "%s device %s has no runtime power management"
+msgstr ""
+
+#: src/tuning/runtime.cpp:73
+#, c-format
+msgid "PCI Device %s has no runtime power management"
+msgstr ""
+
+#: src/tuning/runtime.cpp:75
+#, c-format
+msgid "Runtime PM for PCI Device %s"
+msgstr ""
+
+#: src/tuning/tuningusb.cpp:55
+#, c-format
+msgid "Autosuspend for unknown USB device %s (%s:%s)"
+msgstr ""
+
+#: src/tuning/tuningusb.cpp:72 src/tuning/tuningusb.cpp:74
+#: src/tuning/tuningusb.cpp:76
+#, c-format
+msgid "Autosuspend for USB device %s [%s]"
+msgstr ""
+
+#: src/calibrate/calibrate.cpp:291
+#, c-format
+msgid "Cannot create temp file\n"
+msgstr ""
+
+#: src/calibrate/calibrate.cpp:310
+#, c-format
+msgid "Calibrating: CPU usage on %i threads\n"
+msgstr ""
+
+#: src/calibrate/calibrate.cpp:325
+#, c-format
+msgid "Calibrating: CPU wakeup power consumption\n"
+msgstr ""
+
+#: src/calibrate/calibrate.cpp:342
+#, c-format
+msgid "Calibrating USB devices\n"
+msgstr ""
+
+#: src/calibrate/calibrate.cpp:344 src/calibrate/calibrate.cpp:361
+#: src/calibrate/calibrate.cpp:369 src/calibrate/calibrate.cpp:386
+#, c-format
+msgid ".... device %s \n"
+msgstr ""
+
+#: src/calibrate/calibrate.cpp:359
+#, c-format
+msgid "Calibrating radio devices\n"
+msgstr ""
+
+#: src/calibrate/calibrate.cpp:383
+#, c-format
+msgid "Calibrating backlight\n"
+msgstr ""
+
+#: src/calibrate/calibrate.cpp:407 src/calibrate/calibrate.cpp:415
+#, c-format
+msgid "Calibrating idle\n"
+msgstr ""
+
+#: src/calibrate/calibrate.cpp:426
+#, c-format
+msgid "Calibrating: disk usage \n"
+msgstr ""
+
+#: src/calibrate/calibrate.cpp:451
+msgid "Starting PowerTOP power estimate calibration \n"
+msgstr ""
+
+#: src/calibrate/calibrate.cpp:474
+msgid "Finishing PowerTOP power estimate calibration \n"
+msgstr ""
+
+#: src/calibrate/calibrate.cpp:478
+#, c-format
+msgid "Parameters after calibration:\n"
+msgstr "Parameters na calibratie:\n"
+
+#: src/main.cpp:84
+#, c-format
+msgid "PowerTOP version"
+msgstr ""
+
+#: src/main.cpp:90
+msgid "Set refresh time out"
+msgstr "Stel verversingstijd in"
+
+#: src/main.cpp:103
+msgid "Usage: powertop [OPTIONS]"
+msgstr ""
+
+#: src/main.cpp:104
+msgid "run in \"debug\" mode"
+msgstr ""
+
+#: src/main.cpp:105
+msgid "print version information"
+msgstr ""
+
+#: src/main.cpp:106
+msgid "runs powertop in calibration mode"
+msgstr ""
+
+#: src/main.cpp:107
+msgid "[=devnode]"
+msgstr ""
+
+#: src/main.cpp:107
+msgid "uses an Extech Power Analyzer for measurements"
+msgstr ""
+
+#: src/main.cpp:108 src/main.cpp:109
+msgid "[=FILENAME]"
+msgstr ""
+
+#: src/main.cpp:108
+msgid "generate a html report"
+msgstr ""
+
+#: src/main.cpp:109
+msgid "generate a csv report"
+msgstr ""
+
+#: src/main.cpp:110
+msgid "[=seconds]"
+msgstr ""
+
+#: src/main.cpp:110
+msgid "generate a report for 'x' seconds"
+msgstr ""
+
+#: src/main.cpp:111
+msgid "[=iterations] number of times to run each test"
+msgstr ""
+
+#: src/main.cpp:112
+msgid "print this help menu"
+msgstr ""
+
+#: src/main.cpp:114
+msgid "For more help please refer to the README"
+msgstr ""
+
+#: src/main.cpp:224
+#, c-format
+msgid "PowerTOP is out of memory. PowerTOP is Aborting"
+msgstr ""
+
+#: src/main.cpp:252
+#, c-format
+msgid "Preparing to take measurements\n"
+msgstr "Voorbereiding om metingen te nemen\n"
+
+#: src/main.cpp:255
+#, c-format
+msgid "Taking %d measurement(s) for a duration of %d second(s) each.\n"
+msgstr ""
+
+#: src/main.cpp:278
+#, c-format
+msgid "PowerTOP "
+msgstr "PowerTOP"
+
+#: src/main.cpp:279 src/main.cpp:307
+#, c-format
+msgid "exiting...\n"
+msgstr "afsluiten...\n"
+
+#: src/main.cpp:306
+#, c-format
+msgid "Failed to mount debugfs!\n"
+msgstr "Kan debugfs niet aankoppelen!\n"
+
+#: src/main.cpp:443
+#, c-format
+msgid "Leaving PowerTOP"
+msgstr ""
diff --git a/po/pl_PL.po b/po/pl_PL.po
new file mode 100644 (file)
index 0000000..8667a63
--- /dev/null
@@ -0,0 +1,588 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR Intel Corporation
+# This file is distributed under the same license as the PACKAGE package.
+# 
+# Translators:
+#   <m.kosturek@gmail.com>, 2012.
+#   <mplichta@gmail.com>, 2012.
+msgid ""
+msgstr ""
+"Project-Id-Version: PowerTOP\n"
+"Report-Msgid-Bugs-To: \"powertop@lists.01.org\"\n"
+"POT-Creation-Date: 2012-10-26 09:24-0700\n"
+"PO-Revision-Date: 2012-10-26 22:23+0000\n"
+"Last-Translator: ceferron <chris.e.ferron@linux.intel.com>\n"
+"Language-Team: Polish (Poland) (http://www.transifex.com/projects/p/PowerTOP/language/pl_PL/)\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Language: pl_PL\n"
+"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
+
+#: src/parameters/persistent.cpp:46 src/parameters/persistent.cpp:140
+msgid "Cannot save to file"
+msgstr ""
+
+#: src/parameters/persistent.cpp:78 src/parameters/persistent.cpp:165
+msgid "Cannot load from file"
+msgstr ""
+
+#: src/parameters/persistent.cpp:123
+#, c-format
+msgid "Loaded %i prior measurements\n"
+msgstr "Wczytano %i poprzednich pomiarów \\n"
+
+#: src/display.cpp:70
+msgid "Overview"
+msgstr "Przegląd"
+
+#: src/display.cpp:71
+msgid "Idle stats"
+msgstr "Stan jałowy"
+
+#: src/display.cpp:72
+msgid "Frequency stats"
+msgstr "Statystyki częstotliwości"
+
+#: src/display.cpp:73
+msgid "Device stats"
+msgstr "Statystyki urządzeń"
+
+#: src/display.cpp:130
+msgid "Exit"
+msgstr "Wyjście"
+
+#: src/cpu/cpu_core.cpp:111 src/cpu/cpu_linux.cpp:360
+#: src/cpu/cpu_package.cpp:133 src/cpu/intel_cpus.cpp:222
+#: src/cpu/intel_cpus.cpp:444 src/cpu/intel_cpus.cpp:639
+msgid "Idle"
+msgstr "Stan jałowy"
+
+#: src/cpu/cpu_core.cpp:113 src/cpu/cpu_linux.cpp:362
+#: src/cpu/cpu_package.cpp:135 src/cpu/intel_cpus.cpp:224
+#: src/cpu/intel_cpus.cpp:446
+#, c-format
+msgid "Turbo Mode"
+msgstr "Turbo Mode"
+
+#: src/cpu/cpu.cpp:93
+#, c-format
+msgid "cpu package %i"
+msgstr "paczka cpu %i"
+
+#: src/cpu/cpu.cpp:94
+msgid "cpu package"
+msgstr "paczka cpu"
+
+#: src/cpu/cpu.cpp:437 src/cpu/cpu.cpp:563
+#, c-format
+msgid "Package %i"
+msgstr ""
+
+#: src/cpu/cpu.cpp:469 src/cpu/cpu.cpp:583
+#, c-format
+msgid "Core %i"
+msgstr ""
+
+#: src/cpu/cpu.cpp:471
+#, c-format
+msgid "GPU %i"
+msgstr ""
+
+#: src/cpu/cpu.cpp:493 src/cpu/cpu.cpp:604
+#, c-format
+msgid "CPU %i"
+msgstr ""
+
+#: src/cpu/cpu.cpp:772
+#, c-format
+msgid "cpu_idle event returned no state?\n"
+msgstr ""
+
+#: src/cpu/cpu.cpp:787
+#, c-format
+msgid "power or cpu_frequecny event returned no state?\n"
+msgstr "zdarzenie power lub cpu_frequency zwróciło no state?\\n"
+
+#: src/cpu/cpu_linux.cpp:92
+msgid "C0 polling"
+msgstr "C0 polling"
+
+#: src/cpu/intel_cpus.cpp:69
+#, c-format
+msgid "msr reg not found"
+msgstr "nie znaleziono msr reg"
+
+#: src/cpu/intel_cpus.cpp:79
+#, c-format
+msgid "pread cpu%d 0x%llx : "
+msgstr ""
+
+#: src/cpu/intel_cpus.cpp:516
+msgid "C0 active"
+msgstr "C0 aktywny"
+
+#: src/cpu/intel_cpus.cpp:575
+#, c-format
+msgid "Actual"
+msgstr "rzeczywisty"
+
+#: src/lib.cpp:257
+#, c-format
+msgid "%7sW"
+msgstr "%7sW"
+
+#: src/lib.cpp:260
+#, c-format
+msgid "    0 mW"
+msgstr "0 mW"
+
+#: src/lib.cpp:381
+msgid "PS/2 Touchpad / Keyboard / Mouse"
+msgstr "PS/2 Touchpad / Klawiatura / Mysz"
+
+#: src/lib.cpp:382
+msgid "SATA controller"
+msgstr "kontroler SATA"
+
+#: src/lib.cpp:383
+msgid "Intel built in USB hub"
+msgstr "Intel wbudowany w hub USB"
+
+#: src/process/do_process.cpp:830
+#, c-format
+msgid ""
+"Estimated power: %5.1f    Measured power: %5.1f    Sum: %5.1f\n"
+"\n"
+msgstr "Moc szacunkowa: %5.1f   Moc zmierzona: %5.1f   Suma: %5.1f\\n\\n"
+
+#: src/process/do_process.cpp:841 src/devices/device.cpp:171
+#, c-format
+msgid "The battery reports a discharge rate of %sW\n"
+msgstr "Tempo rozładowywania baterii: %sW \\n"
+
+#: src/process/do_process.cpp:846
+#, c-format
+msgid "The estimated remaining time is %i hours, %i minutes\n"
+msgstr ""
+
+#: src/process/do_process.cpp:854
+msgid "Summary"
+msgstr "Podsumowanie"
+
+#: src/process/do_process.cpp:854 src/process/do_process.cpp:1024
+msgid "wakeups/second"
+msgstr "Pobudki/sekunda"
+
+#: src/process/do_process.cpp:854
+msgid "GPU ops/seconds"
+msgstr "GPU operacji/sekunde"
+
+#: src/process/do_process.cpp:854
+msgid "VFS ops/sec and"
+msgstr "VFS operacji/sek i"
+
+#: src/process/do_process.cpp:854 src/process/do_process.cpp:1028
+msgid "CPU use"
+msgstr "Zużywanie CPU"
+
+#: src/process/do_process.cpp:858 src/process/do_process.cpp:915
+#: src/process/do_process.cpp:1034
+msgid "Power est."
+msgstr "Estymacja mocy"
+
+#: src/process/do_process.cpp:858 src/process/do_process.cpp:860
+#: src/process/do_process.cpp:919 src/process/do_process.cpp:1038
+msgid "Usage"
+msgstr "Użycie"
+
+#: src/process/do_process.cpp:858 src/process/do_process.cpp:860
+#: src/process/do_process.cpp:1040
+msgid "Events/s"
+msgstr "Zdarzenie/nia"
+
+#: src/process/do_process.cpp:858 src/process/do_process.cpp:860
+#: src/process/do_process.cpp:929 src/process/do_process.cpp:1042
+msgid "Category"
+msgstr "Kategoria"
+
+#: src/process/do_process.cpp:858 src/process/do_process.cpp:860
+#: src/process/do_process.cpp:931 src/process/do_process.cpp:1044
+msgid "Description"
+msgstr "Opis"
+
+#: src/process/do_process.cpp:910
+msgid "Overview of Software Power Consumers"
+msgstr "Przedląd programowych odbiorników energii"
+
+#: src/process/do_process.cpp:921
+msgid "Wakeups/s"
+msgstr "Pobutka/i"
+
+#: src/process/do_process.cpp:923
+msgid "GPU ops/s"
+msgstr "GUP opercji/s"
+
+#: src/process/do_process.cpp:925
+msgid "Disk IO/s"
+msgstr "Wejścia/Wyjścia dysku"
+
+#: src/process/do_process.cpp:927
+msgid "GFX Wakeups/s"
+msgstr "GFX Wakeups/s"
+
+#: src/process/do_process.cpp:1021
+msgid "Power Consumption Summary"
+msgstr "Podsumowanie poboru mocy"
+
+#: src/process/do_process.cpp:1025
+msgid "GPU ops/second"
+msgstr "GPU ops/sekundę"
+
+#: src/process/do_process.cpp:1026
+msgid "VFS ops/sec"
+msgstr "VFS ops/sec"
+
+#: src/process/do_process.cpp:1027
+msgid "GFX wakes/sec and"
+msgstr "GFX wakes/sec i"
+
+#: src/perf/perf.cpp:111
+#, c-format
+msgid "PowerTOP %s needs the kernel to support the 'perf' subsystem\n"
+msgstr "PowerTOP %s wymaga aby kernel wspierał narzędzie 'perf' \\n"
+
+#: src/perf/perf.cpp:112
+#, c-format
+msgid "as well as support for trace points in the kernel:\n"
+msgstr "tak jak wsparcie kernela dla tracepoit-ów: \\n"
+
+#: src/devices/device.cpp:177
+#, c-format
+msgid "System baseline power is estimated at %sW\n"
+msgstr "Bazową moc systemu oszacowano na %sW \\n"
+
+#: src/devices/device.cpp:184
+msgid "Power est.    Usage     Device name\n"
+msgstr "Szac. moc        Użycie       Nazwa urządzenia \\n"
+
+#: src/devices/device.cpp:186
+msgid "              Usage     Device name\n"
+msgstr "                      Użycie       Nazwa urządzenia \\n"
+
+#: src/devices/alsa.cpp:79
+#, c-format
+msgid "Audio codec %s: %s (%s)"
+msgstr "Kodek audio %s: %s (%s)"
+
+#: src/devices/alsa.cpp:81 src/devices/alsa.cpp:83
+#, c-format
+msgid "Audio codec %s: %s"
+msgstr "Kodek audio %s: %s"
+
+#: src/devices/runtime_pm.cpp:225
+#, c-format
+msgid "PCI Device: %s"
+msgstr "Urządzenie PCI: %s"
+
+#: src/devices/usb.cpp:51 src/devices/usb.cpp:94 src/devices/usb.cpp:96
+#, c-format
+msgid "USB device: %s"
+msgstr "Urządzenie USB: %s"
+
+#: src/devices/usb.cpp:92
+#, c-format
+msgid "USB device: %s (%s)"
+msgstr "Urządzenie USB: %s (%s)"
+
+#: src/devices/ahci.cpp:140
+#, c-format
+msgid "SATA link: %s"
+msgstr "Łącze SATA: %s"
+
+#: src/devices/ahci.cpp:142
+#, c-format
+msgid "SATA disk: %s"
+msgstr "Dysk SATA: %s"
+
+#: src/devices/rfkill.cpp:65 src/devices/rfkill.cpp:69
+#, c-format
+msgid "Radio device: %s"
+msgstr "Urządzenie radiowe: %s"
+
+#: src/devices/network.cpp:177
+#, c-format
+msgid "Network interface: %s (%s)"
+msgstr "Interfejs sieciowy: %s (%s)"
+
+#: src/tuning/bluetooth.cpp:48
+#, c-format
+msgid "Bluetooth device interface status"
+msgstr "Status interfejsu urządzenia Bluetooth"
+
+#: src/tuning/cpufreq.cpp:43 src/tuning/ethernet.cpp:53
+#: src/tuning/tunable.cpp:48 src/tuning/wifi.cpp:45 src/tuning/runtime.cpp:41
+#: src/tuning/tuningusb.cpp:40 src/tuning/tuningsysfs.cpp:44
+msgid "Good"
+msgstr "Dobrze"
+
+#: src/tuning/cpufreq.cpp:43 src/tuning/ethernet.cpp:53
+#: src/tuning/tunable.cpp:49 src/tuning/wifi.cpp:45 src/tuning/runtime.cpp:41
+#: src/tuning/tuningusb.cpp:40 src/tuning/tuningsysfs.cpp:44
+msgid "Bad"
+msgstr "Źle"
+
+#: src/tuning/cpufreq.cpp:43 src/tuning/ethernet.cpp:53
+#: src/tuning/tunable.cpp:50 src/tuning/wifi.cpp:45 src/tuning/runtime.cpp:41
+#: src/tuning/tuningusb.cpp:40 src/tuning/tuningsysfs.cpp:44
+msgid "Unknown"
+msgstr "Nieznany"
+
+#: src/tuning/cpufreq.cpp:46
+#, c-format
+msgid "Using 'ondemand' cpufreq governor"
+msgstr ""
+
+#: src/tuning/tuning.cpp:59
+msgid "Enable Audio codec power management"
+msgstr "Zarządzanie zasilaniem kodeka audio włączone"
+
+#: src/tuning/tuning.cpp:60
+msgid "NMI watchdog should be turned off"
+msgstr "Watchdog NMI powinien być wyłączony"
+
+#: src/tuning/tuning.cpp:61
+msgid "Power Aware CPU scheduler"
+msgstr ""
+
+#: src/tuning/tuning.cpp:62
+msgid "VM writeback timeout"
+msgstr ""
+
+#: src/tuning/tuning.cpp:79
+msgid "Tunables"
+msgstr ""
+
+#: src/tuning/tuning.cpp:79
+msgid " <ESC> Exit | <Enter> Toggle tunable | <r> Window refresh"
+msgstr ""
+
+#: src/tuning/ethernet.cpp:57
+#, c-format
+msgid "Wake-on-lan status for device %s"
+msgstr "Status Wake-on-lan dla urządzenia %s"
+
+#: src/tuning/wifi.cpp:48
+#, c-format
+msgid "Wireless Power Saving for interface %s"
+msgstr ""
+
+#: src/tuning/runtime.cpp:47
+#, c-format
+msgid "Runtime PM for %s device %s"
+msgstr ""
+
+#: src/tuning/runtime.cpp:49
+#, c-format
+msgid "%s device %s has no runtime power management"
+msgstr ""
+
+#: src/tuning/runtime.cpp:73
+#, c-format
+msgid "PCI Device %s has no runtime power management"
+msgstr ""
+
+#: src/tuning/runtime.cpp:75
+#, c-format
+msgid "Runtime PM for PCI Device %s"
+msgstr ""
+
+#: src/tuning/tuningusb.cpp:55
+#, c-format
+msgid "Autosuspend for unknown USB device %s (%s:%s)"
+msgstr ""
+
+#: src/tuning/tuningusb.cpp:72 src/tuning/tuningusb.cpp:74
+#: src/tuning/tuningusb.cpp:76
+#, c-format
+msgid "Autosuspend for USB device %s [%s]"
+msgstr ""
+
+#: src/tuning/tuningsysfs.cpp:142
+#, c-format
+msgid "Enable SATA link power Managmenet for %s"
+msgstr ""
+
+#: src/calibrate/calibrate.cpp:291
+#, c-format
+msgid "Cannot create temp file\n"
+msgstr "Nie można utworzyć pliku tymczasowego\\n"
+
+#: src/calibrate/calibrate.cpp:310
+#, c-format
+msgid "Calibrating: CPU usage on %i threads\n"
+msgstr ""
+
+#: src/calibrate/calibrate.cpp:325
+#, c-format
+msgid "Calibrating: CPU wakeup power consumption\n"
+msgstr ""
+
+#: src/calibrate/calibrate.cpp:342
+#, c-format
+msgid "Calibrating USB devices\n"
+msgstr "Kalibracja urządzeń USB\\n"
+
+#: src/calibrate/calibrate.cpp:344 src/calibrate/calibrate.cpp:361
+#: src/calibrate/calibrate.cpp:369 src/calibrate/calibrate.cpp:386
+#, c-format
+msgid ".... device %s \n"
+msgstr "... urządzenie %s \\n"
+
+#: src/calibrate/calibrate.cpp:359
+#, c-format
+msgid "Calibrating radio devices\n"
+msgstr "Kalibracja urządzeń radiowych\\n"
+
+#: src/calibrate/calibrate.cpp:383
+#, c-format
+msgid "Calibrating backlight\n"
+msgstr ""
+
+#: src/calibrate/calibrate.cpp:407 src/calibrate/calibrate.cpp:415
+#, c-format
+msgid "Calibrating idle\n"
+msgstr ""
+
+#: src/calibrate/calibrate.cpp:426
+#, c-format
+msgid "Calibrating: disk usage \n"
+msgstr ""
+
+#: src/calibrate/calibrate.cpp:451
+msgid "Starting PowerTOP power estimate calibration \n"
+msgstr ""
+
+#: src/calibrate/calibrate.cpp:474
+msgid "Finishing PowerTOP power estimate calibration \n"
+msgstr "Zakończenie PowerTOP po zebraniu estymaty mocy\\n"
+
+#: src/calibrate/calibrate.cpp:478
+#, c-format
+msgid "Parameters after calibration:\n"
+msgstr "Parametry po kalibracji:\\n"
+
+#: src/main.cpp:86
+#, c-format
+msgid "PowerTOP version"
+msgstr "Wersja PowerTOP"
+
+#: src/main.cpp:92
+msgid "Set refresh time out"
+msgstr "Ustaw czas odświerzania"
+
+#: src/main.cpp:105
+msgid "Usage: powertop [OPTIONS]"
+msgstr "Użycie: powertop [OPTIONS]"
+
+#: src/main.cpp:106
+msgid "run in \"debug\" mode"
+msgstr "uruchom w trybie \"debug\""
+
+#: src/main.cpp:107
+msgid "print version information"
+msgstr "wypisz informacje o wersji"
+
+#: src/main.cpp:108
+msgid "runs powertop in calibration mode"
+msgstr "uruchom powertop w trybie kalibracji"
+
+#: src/main.cpp:109
+msgid "[=devnode]"
+msgstr "[=devnode]"
+
+#: src/main.cpp:109
+msgid "uses an Extech Power Analyzer for measurements"
+msgstr "do pomiarów użyj Extech Power Analyzer"
+
+#: src/main.cpp:110 src/main.cpp:111
+msgid "[=FILENAME]"
+msgstr "[=NAZWAPLIKU]"
+
+#: src/main.cpp:110
+msgid "generate a html report"
+msgstr "generuje raport html"
+
+#: src/main.cpp:111
+msgid "generate a csv report"
+msgstr "generuje raport csv"
+
+#: src/main.cpp:112
+msgid "[=seconds]"
+msgstr "[=sekund]"
+
+#: src/main.cpp:112
+msgid "generate a report for 'x' seconds"
+msgstr "generuje raport dla 'x' sekund"
+
+#: src/main.cpp:113
+msgid "[=iterations] number of times to run each test"
+msgstr " [=iteracji] liczba powtórzeń każdego testu"
+
+#: src/main.cpp:114
+msgid "[=workload]"
+msgstr ""
+
+#: src/main.cpp:114
+msgid "file to execute for workload"
+msgstr ""
+
+#: src/main.cpp:115
+msgid "suppress stderr output"
+msgstr ""
+
+#: src/main.cpp:116
+msgid "print this help menu"
+msgstr "wypisuje tę informację "
+
+#: src/main.cpp:118
+msgid "For more help please refer to the README"
+msgstr "Więcej pomocy znajduje się w pliku README"
+
+#: src/main.cpp:235
+msgid "PowerTOP is out of memory. PowerTOP is Aborting"
+msgstr "Brak pamięci. PowerTop kończy działanie"
+
+#: src/main.cpp:243
+#, c-format
+msgid "Preparing to take measurements\n"
+msgstr "Przygotowywanie to pomiarów\\n"
+
+#: src/main.cpp:248
+#, c-format
+msgid "Taking %d measurement(s) for a duration of %d second(s) each.\n"
+msgstr "Wykonywanie %d pomiaru(ów) o długości %d sekund(y) każdy \\n"
+
+#: src/main.cpp:250
+#, c-format
+msgid "Measuring workload %s.\n"
+msgstr ""
+
+#: src/main.cpp:273
+#, c-format
+msgid "PowerTOP "
+msgstr "PowerTOP"
+
+#: src/main.cpp:274 src/main.cpp:302
+#, c-format
+msgid "exiting...\n"
+msgstr "wychodzenie...\\n"
+
+#: src/main.cpp:301
+#, c-format
+msgid "Failed to mount debugfs!\n"
+msgstr "Błąd montowania debugfs!\\n"
+
+#: src/main.cpp:438
+msgid "Leaving PowerTOP"
+msgstr "Zamykanie PowerTop"
diff --git a/po/powertop.pot b/po/powertop.pot
new file mode 100644 (file)
index 0000000..d541baa
--- /dev/null
@@ -0,0 +1,586 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR Intel Corporation 
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: powertop 2.1\n"
+"Report-Msgid-Bugs-To: \"powertop@lists.01.org\"\n"
+"POT-Creation-Date: 2012-10-26 09:24-0700\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: src/parameters/persistent.cpp:46 src/parameters/persistent.cpp:140
+msgid "Cannot save to file"
+msgstr ""
+
+#: src/parameters/persistent.cpp:78 src/parameters/persistent.cpp:165
+msgid "Cannot load from file"
+msgstr ""
+
+#: src/parameters/persistent.cpp:123
+#, c-format
+msgid "Loaded %i prior measurements\n"
+msgstr ""
+
+#: src/display.cpp:70
+msgid "Overview"
+msgstr ""
+
+#: src/display.cpp:71
+msgid "Idle stats"
+msgstr ""
+
+#: src/display.cpp:72
+msgid "Frequency stats"
+msgstr ""
+
+#: src/display.cpp:73
+msgid "Device stats"
+msgstr ""
+
+#: src/display.cpp:130
+msgid "Exit"
+msgstr ""
+
+#: src/cpu/cpu_core.cpp:111 src/cpu/cpu_linux.cpp:360
+#: src/cpu/cpu_package.cpp:133 src/cpu/intel_cpus.cpp:222
+#: src/cpu/intel_cpus.cpp:444 src/cpu/intel_cpus.cpp:639
+msgid "Idle"
+msgstr ""
+
+#: src/cpu/cpu_core.cpp:113 src/cpu/cpu_linux.cpp:362
+#: src/cpu/cpu_package.cpp:135 src/cpu/intel_cpus.cpp:224
+#: src/cpu/intel_cpus.cpp:446
+#, c-format
+msgid "Turbo Mode"
+msgstr ""
+
+#: src/cpu/cpu.cpp:93
+#, c-format
+msgid "cpu package %i"
+msgstr ""
+
+#: src/cpu/cpu.cpp:94
+msgid "cpu package"
+msgstr ""
+
+#: src/cpu/cpu.cpp:437 src/cpu/cpu.cpp:563
+#, c-format
+msgid "Package %i"
+msgstr ""
+
+#: src/cpu/cpu.cpp:469 src/cpu/cpu.cpp:583
+#, c-format
+msgid "Core %i"
+msgstr ""
+
+#: src/cpu/cpu.cpp:471
+#, c-format
+msgid "GPU %i"
+msgstr ""
+
+#: src/cpu/cpu.cpp:493 src/cpu/cpu.cpp:604
+#, c-format
+msgid "CPU %i"
+msgstr ""
+
+#: src/cpu/cpu.cpp:772
+#, c-format
+msgid "cpu_idle event returned no state?\n"
+msgstr ""
+
+#: src/cpu/cpu.cpp:787
+#, c-format
+msgid "power or cpu_frequecny event returned no state?\n"
+msgstr ""
+
+#: src/cpu/cpu_linux.cpp:92
+msgid "C0 polling"
+msgstr ""
+
+#: src/cpu/intel_cpus.cpp:69
+#, c-format
+msgid "msr reg not found"
+msgstr ""
+
+#: src/cpu/intel_cpus.cpp:79
+#, c-format
+msgid "pread cpu%d 0x%llx : "
+msgstr ""
+
+#: src/cpu/intel_cpus.cpp:516
+msgid "C0 active"
+msgstr ""
+
+#: src/cpu/intel_cpus.cpp:575
+#, c-format
+msgid "Actual"
+msgstr ""
+
+#: src/lib.cpp:257
+#, c-format
+msgid "%7sW"
+msgstr ""
+
+#: src/lib.cpp:260
+#, c-format
+msgid "    0 mW"
+msgstr ""
+
+#: src/lib.cpp:381
+msgid "PS/2 Touchpad / Keyboard / Mouse"
+msgstr ""
+
+#: src/lib.cpp:382
+msgid "SATA controller"
+msgstr ""
+
+#: src/lib.cpp:383
+msgid "Intel built in USB hub"
+msgstr ""
+
+#: src/process/do_process.cpp:830
+#, c-format
+msgid ""
+"Estimated power: %5.1f    Measured power: %5.1f    Sum: %5.1f\n"
+"\n"
+msgstr ""
+
+#: src/process/do_process.cpp:841 src/devices/device.cpp:171
+#, c-format
+msgid "The battery reports a discharge rate of %sW\n"
+msgstr ""
+
+#: src/process/do_process.cpp:846
+#, c-format
+msgid "The estimated remaining time is %i hours, %i minutes\n"
+msgstr ""
+
+#: src/process/do_process.cpp:854
+msgid "Summary"
+msgstr ""
+
+#: src/process/do_process.cpp:854 src/process/do_process.cpp:1024
+msgid "wakeups/second"
+msgstr ""
+
+#: src/process/do_process.cpp:854
+msgid "GPU ops/seconds"
+msgstr ""
+
+#: src/process/do_process.cpp:854
+msgid "VFS ops/sec and"
+msgstr ""
+
+#: src/process/do_process.cpp:854 src/process/do_process.cpp:1028
+msgid "CPU use"
+msgstr ""
+
+#: src/process/do_process.cpp:858 src/process/do_process.cpp:915
+#: src/process/do_process.cpp:1034
+msgid "Power est."
+msgstr ""
+
+#: src/process/do_process.cpp:858 src/process/do_process.cpp:860
+#: src/process/do_process.cpp:919 src/process/do_process.cpp:1038
+msgid "Usage"
+msgstr ""
+
+#: src/process/do_process.cpp:858 src/process/do_process.cpp:860
+#: src/process/do_process.cpp:1040
+msgid "Events/s"
+msgstr ""
+
+#: src/process/do_process.cpp:858 src/process/do_process.cpp:860
+#: src/process/do_process.cpp:929 src/process/do_process.cpp:1042
+msgid "Category"
+msgstr ""
+
+#: src/process/do_process.cpp:858 src/process/do_process.cpp:860
+#: src/process/do_process.cpp:931 src/process/do_process.cpp:1044
+msgid "Description"
+msgstr ""
+
+#: src/process/do_process.cpp:910
+msgid "Overview of Software Power Consumers"
+msgstr ""
+
+#: src/process/do_process.cpp:921
+msgid "Wakeups/s"
+msgstr ""
+
+#: src/process/do_process.cpp:923
+msgid "GPU ops/s"
+msgstr ""
+
+#: src/process/do_process.cpp:925
+msgid "Disk IO/s"
+msgstr ""
+
+#: src/process/do_process.cpp:927
+msgid "GFX Wakeups/s"
+msgstr ""
+
+#: src/process/do_process.cpp:1021
+msgid "Power Consumption Summary"
+msgstr ""
+
+#: src/process/do_process.cpp:1025
+msgid "GPU ops/second"
+msgstr ""
+
+#: src/process/do_process.cpp:1026
+msgid "VFS ops/sec"
+msgstr ""
+
+#: src/process/do_process.cpp:1027
+msgid "GFX wakes/sec and"
+msgstr ""
+
+#: src/perf/perf.cpp:111
+#, c-format
+msgid "PowerTOP %s needs the kernel to support the 'perf' subsystem\n"
+msgstr ""
+
+#: src/perf/perf.cpp:112
+#, c-format
+msgid "as well as support for trace points in the kernel:\n"
+msgstr ""
+
+#: src/devices/device.cpp:177
+#, c-format
+msgid "System baseline power is estimated at %sW\n"
+msgstr ""
+
+#: src/devices/device.cpp:184
+msgid "Power est.    Usage     Device name\n"
+msgstr ""
+
+#: src/devices/device.cpp:186
+msgid "              Usage     Device name\n"
+msgstr ""
+
+#: src/devices/alsa.cpp:79
+#, c-format
+msgid "Audio codec %s: %s (%s)"
+msgstr ""
+
+#: src/devices/alsa.cpp:81 src/devices/alsa.cpp:83
+#, c-format
+msgid "Audio codec %s: %s"
+msgstr ""
+
+#: src/devices/runtime_pm.cpp:225
+#, c-format
+msgid "PCI Device: %s"
+msgstr ""
+
+#: src/devices/usb.cpp:51 src/devices/usb.cpp:94 src/devices/usb.cpp:96
+#, c-format
+msgid "USB device: %s"
+msgstr ""
+
+#: src/devices/usb.cpp:92
+#, c-format
+msgid "USB device: %s (%s)"
+msgstr ""
+
+#: src/devices/ahci.cpp:140
+#, c-format
+msgid "SATA link: %s"
+msgstr ""
+
+#: src/devices/ahci.cpp:142
+#, c-format
+msgid "SATA disk: %s"
+msgstr ""
+
+#: src/devices/rfkill.cpp:65 src/devices/rfkill.cpp:69
+#, c-format
+msgid "Radio device: %s"
+msgstr ""
+
+#: src/devices/network.cpp:177
+#, c-format
+msgid "Network interface: %s (%s)"
+msgstr ""
+
+#: src/tuning/bluetooth.cpp:48
+#, c-format
+msgid "Bluetooth device interface status"
+msgstr ""
+
+#: src/tuning/cpufreq.cpp:43 src/tuning/ethernet.cpp:53
+#: src/tuning/tunable.cpp:48 src/tuning/wifi.cpp:45 src/tuning/runtime.cpp:41
+#: src/tuning/tuningusb.cpp:40 src/tuning/tuningsysfs.cpp:44
+msgid "Good"
+msgstr ""
+
+#: src/tuning/cpufreq.cpp:43 src/tuning/ethernet.cpp:53
+#: src/tuning/tunable.cpp:49 src/tuning/wifi.cpp:45 src/tuning/runtime.cpp:41
+#: src/tuning/tuningusb.cpp:40 src/tuning/tuningsysfs.cpp:44
+msgid "Bad"
+msgstr ""
+
+#: src/tuning/cpufreq.cpp:43 src/tuning/ethernet.cpp:53
+#: src/tuning/tunable.cpp:50 src/tuning/wifi.cpp:45 src/tuning/runtime.cpp:41
+#: src/tuning/tuningusb.cpp:40 src/tuning/tuningsysfs.cpp:44
+msgid "Unknown"
+msgstr ""
+
+#: src/tuning/cpufreq.cpp:46
+#, c-format
+msgid "Using 'ondemand' cpufreq governor"
+msgstr ""
+
+#: src/tuning/tuning.cpp:59
+msgid "Enable Audio codec power management"
+msgstr ""
+
+#: src/tuning/tuning.cpp:60
+msgid "NMI watchdog should be turned off"
+msgstr ""
+
+#: src/tuning/tuning.cpp:61
+msgid "Power Aware CPU scheduler"
+msgstr ""
+
+#: src/tuning/tuning.cpp:62
+msgid "VM writeback timeout"
+msgstr ""
+
+#: src/tuning/tuning.cpp:79
+msgid "Tunables"
+msgstr ""
+
+#: src/tuning/tuning.cpp:79
+msgid " <ESC> Exit | <Enter> Toggle tunable | <r> Window refresh"
+msgstr ""
+
+#: src/tuning/ethernet.cpp:57
+#, c-format
+msgid "Wake-on-lan status for device %s"
+msgstr ""
+
+#: src/tuning/wifi.cpp:48
+#, c-format
+msgid "Wireless Power Saving for interface %s"
+msgstr ""
+
+#: src/tuning/runtime.cpp:47
+#, c-format
+msgid "Runtime PM for %s device %s"
+msgstr ""
+
+#: src/tuning/runtime.cpp:49
+#, c-format
+msgid "%s device %s has no runtime power management"
+msgstr ""
+
+#: src/tuning/runtime.cpp:73
+#, c-format
+msgid "PCI Device %s has no runtime power management"
+msgstr ""
+
+#: src/tuning/runtime.cpp:75
+#, c-format
+msgid "Runtime PM for PCI Device %s"
+msgstr ""
+
+#: src/tuning/tuningusb.cpp:55
+#, c-format
+msgid "Autosuspend for unknown USB device %s (%s:%s)"
+msgstr ""
+
+#: src/tuning/tuningusb.cpp:72 src/tuning/tuningusb.cpp:74
+#: src/tuning/tuningusb.cpp:76
+#, c-format
+msgid "Autosuspend for USB device %s [%s]"
+msgstr ""
+
+#: src/tuning/tuningsysfs.cpp:142
+#, c-format
+msgid "Enable SATA link power Managmenet for %s"
+msgstr ""
+
+#: src/calibrate/calibrate.cpp:291
+#, c-format
+msgid "Cannot create temp file\n"
+msgstr ""
+
+#: src/calibrate/calibrate.cpp:310
+#, c-format
+msgid "Calibrating: CPU usage on %i threads\n"
+msgstr ""
+
+#: src/calibrate/calibrate.cpp:325
+#, c-format
+msgid "Calibrating: CPU wakeup power consumption\n"
+msgstr ""
+
+#: src/calibrate/calibrate.cpp:342
+#, c-format
+msgid "Calibrating USB devices\n"
+msgstr ""
+
+#: src/calibrate/calibrate.cpp:344 src/calibrate/calibrate.cpp:361
+#: src/calibrate/calibrate.cpp:369 src/calibrate/calibrate.cpp:386
+#, c-format
+msgid ".... device %s \n"
+msgstr ""
+
+#: src/calibrate/calibrate.cpp:359
+#, c-format
+msgid "Calibrating radio devices\n"
+msgstr ""
+
+#: src/calibrate/calibrate.cpp:383
+#, c-format
+msgid "Calibrating backlight\n"
+msgstr ""
+
+#: src/calibrate/calibrate.cpp:407 src/calibrate/calibrate.cpp:415
+#, c-format
+msgid "Calibrating idle\n"
+msgstr ""
+
+#: src/calibrate/calibrate.cpp:426
+#, c-format
+msgid "Calibrating: disk usage \n"
+msgstr ""
+
+#: src/calibrate/calibrate.cpp:451
+msgid "Starting PowerTOP power estimate calibration \n"
+msgstr ""
+
+#: src/calibrate/calibrate.cpp:474
+msgid "Finishing PowerTOP power estimate calibration \n"
+msgstr ""
+
+#: src/calibrate/calibrate.cpp:478
+#, c-format
+msgid "Parameters after calibration:\n"
+msgstr ""
+
+#: src/main.cpp:86
+#, c-format
+msgid "PowerTOP version"
+msgstr ""
+
+#: src/main.cpp:92
+msgid "Set refresh time out"
+msgstr ""
+
+#: src/main.cpp:105
+msgid "Usage: powertop [OPTIONS]"
+msgstr ""
+
+#: src/main.cpp:106
+msgid "run in \"debug\" mode"
+msgstr ""
+
+#: src/main.cpp:107
+msgid "print version information"
+msgstr ""
+
+#: src/main.cpp:108
+msgid "runs powertop in calibration mode"
+msgstr ""
+
+#: src/main.cpp:109
+msgid "[=devnode]"
+msgstr ""
+
+#: src/main.cpp:109
+msgid "uses an Extech Power Analyzer for measurements"
+msgstr ""
+
+#: src/main.cpp:110 src/main.cpp:111
+msgid "[=FILENAME]"
+msgstr ""
+
+#: src/main.cpp:110
+msgid "generate a html report"
+msgstr ""
+
+#: src/main.cpp:111
+msgid "generate a csv report"
+msgstr ""
+
+#: src/main.cpp:112
+msgid "[=seconds]"
+msgstr ""
+
+#: src/main.cpp:112
+msgid "generate a report for 'x' seconds"
+msgstr ""
+
+#: src/main.cpp:113
+msgid "[=iterations] number of times to run each test"
+msgstr ""
+
+#: src/main.cpp:114
+msgid "[=workload]"
+msgstr ""
+
+#: src/main.cpp:114
+msgid "file to execute for workload"
+msgstr ""
+
+#: src/main.cpp:115
+msgid "suppress stderr output"
+msgstr ""
+
+#: src/main.cpp:116
+msgid "print this help menu"
+msgstr ""
+
+#: src/main.cpp:118
+msgid "For more help please refer to the README"
+msgstr ""
+
+#: src/main.cpp:235
+msgid "PowerTOP is out of memory. PowerTOP is Aborting"
+msgstr ""
+
+#: src/main.cpp:243
+#, c-format
+msgid "Preparing to take measurements\n"
+msgstr ""
+
+#: src/main.cpp:248
+#, c-format
+msgid "Taking %d measurement(s) for a duration of %d second(s) each.\n"
+msgstr ""
+
+#: src/main.cpp:250
+#, c-format
+msgid "Measuring workload %s.\n"
+msgstr ""
+
+#: src/main.cpp:273
+#, c-format
+msgid "PowerTOP "
+msgstr ""
+
+#: src/main.cpp:274 src/main.cpp:302
+#, c-format
+msgid "exiting...\n"
+msgstr ""
+
+#: src/main.cpp:301
+#, c-format
+msgid "Failed to mount debugfs!\n"
+msgstr ""
+
+#: src/main.cpp:438
+msgid "Leaving PowerTOP"
+msgstr ""
diff --git a/po/zh_CN.po b/po/zh_CN.po
new file mode 100644 (file)
index 0000000..1deae42
--- /dev/null
@@ -0,0 +1,587 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR Intel Corporation
+# This file is distributed under the same license as the PACKAGE package.
+# 
+# Translators:
+# Tommy He <lovenemesis@gmail.com>, 2012.
+msgid ""
+msgstr ""
+"Project-Id-Version: PowerTOP\n"
+"Report-Msgid-Bugs-To: \"powertop@lists.01.org\"\n"
+"POT-Creation-Date: 2012-10-26 09:24-0700\n"
+"PO-Revision-Date: 2012-10-26 22:23+0000\n"
+"Last-Translator: ceferron <chris.e.ferron@linux.intel.com>\n"
+"Language-Team: Chinese (China) (http://www.transifex.com/projects/p/PowerTOP/language/zh_CN/)\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Language: zh_CN\n"
+"Plural-Forms: nplurals=1; plural=0;\n"
+
+#: src/parameters/persistent.cpp:46 src/parameters/persistent.cpp:140
+msgid "Cannot save to file"
+msgstr ""
+
+#: src/parameters/persistent.cpp:78 src/parameters/persistent.cpp:165
+msgid "Cannot load from file"
+msgstr ""
+
+#: src/parameters/persistent.cpp:123
+#, c-format
+msgid "Loaded %i prior measurements\n"
+msgstr "载入之前 %i 的测量。\n"
+
+#: src/display.cpp:70
+msgid "Overview"
+msgstr "概况"
+
+#: src/display.cpp:71
+msgid "Idle stats"
+msgstr "空闲统计"
+
+#: src/display.cpp:72
+msgid "Frequency stats"
+msgstr "频率统计"
+
+#: src/display.cpp:73
+msgid "Device stats"
+msgstr "设备统计"
+
+#: src/display.cpp:130
+msgid "Exit"
+msgstr "退出"
+
+#: src/cpu/cpu_core.cpp:111 src/cpu/cpu_linux.cpp:360
+#: src/cpu/cpu_package.cpp:133 src/cpu/intel_cpus.cpp:222
+#: src/cpu/intel_cpus.cpp:444 src/cpu/intel_cpus.cpp:639
+msgid "Idle"
+msgstr "空闲"
+
+#: src/cpu/cpu_core.cpp:113 src/cpu/cpu_linux.cpp:362
+#: src/cpu/cpu_package.cpp:135 src/cpu/intel_cpus.cpp:224
+#: src/cpu/intel_cpus.cpp:446
+#, c-format
+msgid "Turbo Mode"
+msgstr "超频模式"
+
+#: src/cpu/cpu.cpp:93
+#, c-format
+msgid "cpu package %i"
+msgstr "CPU 代号 %i"
+
+#: src/cpu/cpu.cpp:94
+msgid "cpu package"
+msgstr "CPU 代号"
+
+#: src/cpu/cpu.cpp:437 src/cpu/cpu.cpp:563
+#, c-format
+msgid "Package %i"
+msgstr ""
+
+#: src/cpu/cpu.cpp:469 src/cpu/cpu.cpp:583
+#, c-format
+msgid "Core %i"
+msgstr ""
+
+#: src/cpu/cpu.cpp:471
+#, c-format
+msgid "GPU %i"
+msgstr ""
+
+#: src/cpu/cpu.cpp:493 src/cpu/cpu.cpp:604
+#, c-format
+msgid "CPU %i"
+msgstr ""
+
+#: src/cpu/cpu.cpp:772
+#, c-format
+msgid "cpu_idle event returned no state?\n"
+msgstr "CPU 空闲事件没有返回状态?\n"
+
+#: src/cpu/cpu.cpp:787
+#, c-format
+msgid "power or cpu_frequecny event returned no state?\n"
+msgstr "电量或者 CPU 频率事件没有返回状态?\n"
+
+#: src/cpu/cpu_linux.cpp:92
+msgid "C0 polling"
+msgstr "C0 轮巡"
+
+#: src/cpu/intel_cpus.cpp:69
+#, c-format
+msgid "msr reg not found"
+msgstr "找不到 msr 寄存器"
+
+#: src/cpu/intel_cpus.cpp:79
+#, c-format
+msgid "pread cpu%d 0x%llx : "
+msgstr "pread cpu%d 0x%llx : "
+
+#: src/cpu/intel_cpus.cpp:516
+msgid "C0 active"
+msgstr "C0 运行"
+
+#: src/cpu/intel_cpus.cpp:575
+#, c-format
+msgid "Actual"
+msgstr "实际"
+
+#: src/lib.cpp:257
+#, c-format
+msgid "%7sW"
+msgstr "%7sW"
+
+#: src/lib.cpp:260
+#, c-format
+msgid "    0 mW"
+msgstr "    0 mW"
+
+#: src/lib.cpp:381
+msgid "PS/2 Touchpad / Keyboard / Mouse"
+msgstr "PS/2 触摸板 / 键盘 / 鼠标"
+
+#: src/lib.cpp:382
+msgid "SATA controller"
+msgstr "SATA 控制器"
+
+#: src/lib.cpp:383
+msgid "Intel built in USB hub"
+msgstr "Intel 内建 USB 集线器"
+
+#: src/process/do_process.cpp:830
+#, c-format
+msgid ""
+"Estimated power: %5.1f    Measured power: %5.1f    Sum: %5.1f\n"
+"\n"
+msgstr "预计耗电量: %5.1f    测量耗电量: %5.1f    总计: %5.1f\n\n"
+
+#: src/process/do_process.cpp:841 src/devices/device.cpp:171
+#, c-format
+msgid "The battery reports a discharge rate of %sW\n"
+msgstr "电池报告放电速率为 %sW\n"
+
+#: src/process/do_process.cpp:846
+#, c-format
+msgid "The estimated remaining time is %i hours, %i minutes\n"
+msgstr "估计剩余时间 %i 小时, %i 分钟\n"
+
+#: src/process/do_process.cpp:854
+msgid "Summary"
+msgstr "摘要"
+
+#: src/process/do_process.cpp:854 src/process/do_process.cpp:1024
+msgid "wakeups/second"
+msgstr "每秒唤醒数"
+
+#: src/process/do_process.cpp:854
+msgid "GPU ops/seconds"
+msgstr "每秒 GPU 操作数"
+
+#: src/process/do_process.cpp:854
+msgid "VFS ops/sec and"
+msgstr "每秒 VFS 操作数和"
+
+#: src/process/do_process.cpp:854 src/process/do_process.cpp:1028
+msgid "CPU use"
+msgstr "CPU 占用"
+
+#: src/process/do_process.cpp:858 src/process/do_process.cpp:915
+#: src/process/do_process.cpp:1034
+msgid "Power est."
+msgstr "估计电量"
+
+#: src/process/do_process.cpp:858 src/process/do_process.cpp:860
+#: src/process/do_process.cpp:919 src/process/do_process.cpp:1038
+msgid "Usage"
+msgstr "用量"
+
+#: src/process/do_process.cpp:858 src/process/do_process.cpp:860
+#: src/process/do_process.cpp:1040
+msgid "Events/s"
+msgstr "每秒事件数"
+
+#: src/process/do_process.cpp:858 src/process/do_process.cpp:860
+#: src/process/do_process.cpp:929 src/process/do_process.cpp:1042
+msgid "Category"
+msgstr "分类"
+
+#: src/process/do_process.cpp:858 src/process/do_process.cpp:860
+#: src/process/do_process.cpp:931 src/process/do_process.cpp:1044
+msgid "Description"
+msgstr "描述"
+
+#: src/process/do_process.cpp:910
+msgid "Overview of Software Power Consumers"
+msgstr "软件电量消耗概览"
+
+#: src/process/do_process.cpp:921
+msgid "Wakeups/s"
+msgstr "每秒唤醒数"
+
+#: src/process/do_process.cpp:923
+msgid "GPU ops/s"
+msgstr "每秒 GPU 操作数"
+
+#: src/process/do_process.cpp:925
+msgid "Disk IO/s"
+msgstr "每秒磁盘 IO 数"
+
+#: src/process/do_process.cpp:927
+msgid "GFX Wakeups/s"
+msgstr "每秒 GFX 唤醒数"
+
+#: src/process/do_process.cpp:1021
+msgid "Power Consumption Summary"
+msgstr "电量消耗摘要"
+
+#: src/process/do_process.cpp:1025
+msgid "GPU ops/second"
+msgstr "每秒 GPU 操作数"
+
+#: src/process/do_process.cpp:1026
+msgid "VFS ops/sec"
+msgstr "每秒 VFS 操作数"
+
+#: src/process/do_process.cpp:1027
+msgid "GFX wakes/sec and"
+msgstr "每秒 GFX 唤醒数和"
+
+#: src/perf/perf.cpp:111
+#, c-format
+msgid "PowerTOP %s needs the kernel to support the 'perf' subsystem\n"
+msgstr "PowerTOP %s 需要内核支持 'perf' 子系统\n\n"
+
+#: src/perf/perf.cpp:112
+#, c-format
+msgid "as well as support for trace points in the kernel:\n"
+msgstr "以及支持内核中追溯点:\n"
+
+#: src/devices/device.cpp:177
+#, c-format
+msgid "System baseline power is estimated at %sW\n"
+msgstr "系统基线耗电量为 %sW\n"
+
+#: src/devices/device.cpp:184
+msgid "Power est.    Usage     Device name\n"
+msgstr "预计电量    使用量     设备名\n"
+
+#: src/devices/device.cpp:186
+msgid "              Usage     Device name\n"
+msgstr "              使用量     设备名\n"
+
+#: src/devices/alsa.cpp:79
+#, c-format
+msgid "Audio codec %s: %s (%s)"
+msgstr "音频设备 %s: %s (%s)"
+
+#: src/devices/alsa.cpp:81 src/devices/alsa.cpp:83
+#, c-format
+msgid "Audio codec %s: %s"
+msgstr "音频设备 %s: %s"
+
+#: src/devices/runtime_pm.cpp:225
+#, c-format
+msgid "PCI Device: %s"
+msgstr "PCI 设备: %s"
+
+#: src/devices/usb.cpp:51 src/devices/usb.cpp:94 src/devices/usb.cpp:96
+#, c-format
+msgid "USB device: %s"
+msgstr "USB 设备: %s"
+
+#: src/devices/usb.cpp:92
+#, c-format
+msgid "USB device: %s (%s)"
+msgstr "USB 设备: %s (%s)"
+
+#: src/devices/ahci.cpp:140
+#, c-format
+msgid "SATA link: %s"
+msgstr "SATA 连线: %s"
+
+#: src/devices/ahci.cpp:142
+#, c-format
+msgid "SATA disk: %s"
+msgstr "SATA 磁盘: %s"
+
+#: src/devices/rfkill.cpp:65 src/devices/rfkill.cpp:69
+#, c-format
+msgid "Radio device: %s"
+msgstr "无线电设备: %s"
+
+#: src/devices/network.cpp:177
+#, c-format
+msgid "Network interface: %s (%s)"
+msgstr "网络接口: %s (%s)"
+
+#: src/tuning/bluetooth.cpp:48
+#, c-format
+msgid "Bluetooth device interface status"
+msgstr "蓝牙设备接口状态"
+
+#: src/tuning/cpufreq.cpp:43 src/tuning/ethernet.cpp:53
+#: src/tuning/tunable.cpp:48 src/tuning/wifi.cpp:45 src/tuning/runtime.cpp:41
+#: src/tuning/tuningusb.cpp:40 src/tuning/tuningsysfs.cpp:44
+msgid "Good"
+msgstr "良好"
+
+#: src/tuning/cpufreq.cpp:43 src/tuning/ethernet.cpp:53
+#: src/tuning/tunable.cpp:49 src/tuning/wifi.cpp:45 src/tuning/runtime.cpp:41
+#: src/tuning/tuningusb.cpp:40 src/tuning/tuningsysfs.cpp:44
+msgid "Bad"
+msgstr "糟糕"
+
+#: src/tuning/cpufreq.cpp:43 src/tuning/ethernet.cpp:53
+#: src/tuning/tunable.cpp:50 src/tuning/wifi.cpp:45 src/tuning/runtime.cpp:41
+#: src/tuning/tuningusb.cpp:40 src/tuning/tuningsysfs.cpp:44
+msgid "Unknown"
+msgstr "未知"
+
+#: src/tuning/cpufreq.cpp:46
+#, c-format
+msgid "Using 'ondemand' cpufreq governor"
+msgstr "使用 '按需调整' CPU 频率控制器"
+
+#: src/tuning/tuning.cpp:59
+msgid "Enable Audio codec power management"
+msgstr "启用音频设备电源管理"
+
+#: src/tuning/tuning.cpp:60
+msgid "NMI watchdog should be turned off"
+msgstr "需要关闭 NMI 监控"
+
+#: src/tuning/tuning.cpp:61
+msgid "Power Aware CPU scheduler"
+msgstr "支持节电的 CPU 调度器"
+
+#: src/tuning/tuning.cpp:62
+msgid "VM writeback timeout"
+msgstr "虚拟内存回写延时"
+
+#: src/tuning/tuning.cpp:79
+msgid "Tunables"
+msgstr "可调项"
+
+#: src/tuning/tuning.cpp:79
+msgid " <ESC> Exit | <Enter> Toggle tunable | <r> Window refresh"
+msgstr " <ESC> 退出 | <Enter> 切换可调整项 | <r> 窗口刷新"
+
+#: src/tuning/ethernet.cpp:57
+#, c-format
+msgid "Wake-on-lan status for device %s"
+msgstr "设备 %s 的网络唤醒状态"
+
+#: src/tuning/wifi.cpp:48
+#, c-format
+msgid "Wireless Power Saving for interface %s"
+msgstr "接口 %s 的无线节电设置"
+
+#: src/tuning/runtime.cpp:47
+#, c-format
+msgid "Runtime PM for %s device %s"
+msgstr "%s 设备 %s 的运行时电源管理"
+
+#: src/tuning/runtime.cpp:49
+#, c-format
+msgid "%s device %s has no runtime power management"
+msgstr "%s 设备 %s 没有运行时电源管理"
+
+#: src/tuning/runtime.cpp:73
+#, c-format
+msgid "PCI Device %s has no runtime power management"
+msgstr "PCI 设备 %s 没有运行时电源管理"
+
+#: src/tuning/runtime.cpp:75
+#, c-format
+msgid "Runtime PM for PCI Device %s"
+msgstr "PCI 设备 %s 的运行时电源管理"
+
+#: src/tuning/tuningusb.cpp:55
+#, c-format
+msgid "Autosuspend for unknown USB device %s (%s:%s)"
+msgstr "自动挂起未知 USB 设备 %s (%s:%s)"
+
+#: src/tuning/tuningusb.cpp:72 src/tuning/tuningusb.cpp:74
+#: src/tuning/tuningusb.cpp:76
+#, c-format
+msgid "Autosuspend for USB device %s [%s]"
+msgstr "自动挂起 USB 设备 %s [%s]"
+
+#: src/tuning/tuningsysfs.cpp:142
+#, c-format
+msgid "Enable SATA link power Managmenet for %s"
+msgstr ""
+
+#: src/calibrate/calibrate.cpp:291
+#, c-format
+msgid "Cannot create temp file\n"
+msgstr "无法创建临时文件\n"
+
+#: src/calibrate/calibrate.cpp:310
+#, c-format
+msgid "Calibrating: CPU usage on %i threads\n"
+msgstr "校准:%i 线程中的 CPU 使用\n"
+
+#: src/calibrate/calibrate.cpp:325
+#, c-format
+msgid "Calibrating: CPU wakeup power consumption\n"
+msgstr "校准:CPU 唤醒电源消耗\n"
+
+#: src/calibrate/calibrate.cpp:342
+#, c-format
+msgid "Calibrating USB devices\n"
+msgstr "校准 USB 设备\n"
+
+#: src/calibrate/calibrate.cpp:344 src/calibrate/calibrate.cpp:361
+#: src/calibrate/calibrate.cpp:369 src/calibrate/calibrate.cpp:386
+#, c-format
+msgid ".... device %s \n"
+msgstr ".... 设别 %s \n"
+
+#: src/calibrate/calibrate.cpp:359
+#, c-format
+msgid "Calibrating radio devices\n"
+msgstr "校准无线电设备\n"
+
+#: src/calibrate/calibrate.cpp:383
+#, c-format
+msgid "Calibrating backlight\n"
+msgstr "校准背光\n"
+
+#: src/calibrate/calibrate.cpp:407 src/calibrate/calibrate.cpp:415
+#, c-format
+msgid "Calibrating idle\n"
+msgstr "校准空闲耗电\n"
+
+#: src/calibrate/calibrate.cpp:426
+#, c-format
+msgid "Calibrating: disk usage \n"
+msgstr "校准:磁盘使用\n"
+
+#: src/calibrate/calibrate.cpp:451
+msgid "Starting PowerTOP power estimate calibration \n"
+msgstr "开始 PowerTOP 电量预计校准\n"
+
+#: src/calibrate/calibrate.cpp:474
+msgid "Finishing PowerTOP power estimate calibration \n"
+msgstr "结束 PowerTOP 电量预计校准\n"
+
+#: src/calibrate/calibrate.cpp:478
+#, c-format
+msgid "Parameters after calibration:\n"
+msgstr "校准后参数:\n"
+
+#: src/main.cpp:86
+#, c-format
+msgid "PowerTOP version"
+msgstr "PowerTOP 版本"
+
+#: src/main.cpp:92
+msgid "Set refresh time out"
+msgstr "设定刷新延迟"
+
+#: src/main.cpp:105
+msgid "Usage: powertop [OPTIONS]"
+msgstr "用法:powertop [选项]"
+
+#: src/main.cpp:106
+msgid "run in \"debug\" mode"
+msgstr "以“除错”模式运行"
+
+#: src/main.cpp:107
+msgid "print version information"
+msgstr "打印版本信息"
+
+#: src/main.cpp:108
+msgid "runs powertop in calibration mode"
+msgstr "以校准模式运行 PowerTOP"
+
+#: src/main.cpp:109
+msgid "[=devnode]"
+msgstr "[=devnode]"
+
+#: src/main.cpp:109
+msgid "uses an Extech Power Analyzer for measurements"
+msgstr "使用 Extech 电源分析仪进行测量"
+
+#: src/main.cpp:110 src/main.cpp:111
+msgid "[=FILENAME]"
+msgstr "[=文件名]"
+
+#: src/main.cpp:110
+msgid "generate a html report"
+msgstr "生成 HTML 报告"
+
+#: src/main.cpp:111
+msgid "generate a csv report"
+msgstr "生成 CSV 报告"
+
+#: src/main.cpp:112
+msgid "[=seconds]"
+msgstr "[=秒]"
+
+#: src/main.cpp:112
+msgid "generate a report for 'x' seconds"
+msgstr "生成指定 'x' 秒数的报告"
+
+#: src/main.cpp:113
+msgid "[=iterations] number of times to run each test"
+msgstr "[=重复数] 运行每项测试的次数"
+
+#: src/main.cpp:114
+msgid "[=workload]"
+msgstr ""
+
+#: src/main.cpp:114
+msgid "file to execute for workload"
+msgstr ""
+
+#: src/main.cpp:115
+msgid "suppress stderr output"
+msgstr ""
+
+#: src/main.cpp:116
+msgid "print this help menu"
+msgstr "打印此帮助菜单"
+
+#: src/main.cpp:118
+msgid "For more help please refer to the README"
+msgstr "更多帮助请查阅 README"
+
+#: src/main.cpp:235
+msgid "PowerTOP is out of memory. PowerTOP is Aborting"
+msgstr "PowerTOP 内存溢出。 PowerTOP 正在退出。"
+
+#: src/main.cpp:243
+#, c-format
+msgid "Preparing to take measurements\n"
+msgstr "准备开始测量\n"
+
+#: src/main.cpp:248
+#, c-format
+msgid "Taking %d measurement(s) for a duration of %d second(s) each.\n"
+msgstr "执行 %d 次测量,每个持续 %d 秒。\n"
+
+#: src/main.cpp:250
+#, c-format
+msgid "Measuring workload %s.\n"
+msgstr ""
+
+#: src/main.cpp:273
+#, c-format
+msgid "PowerTOP "
+msgstr "PowerTOP "
+
+#: src/main.cpp:274 src/main.cpp:302
+#, c-format
+msgid "exiting...\n"
+msgstr "退出……\n"
+
+#: src/main.cpp:301
+#, c-format
+msgid "Failed to mount debugfs!\n"
+msgstr "挂载 debugfs 失败!\n"
+
+#: src/main.cpp:438
+msgid "Leaving PowerTOP"
+msgstr "离开 PowerTOP"
diff --git a/po/zh_TW.po b/po/zh_TW.po
new file mode 100644 (file)
index 0000000..c93ff67
--- /dev/null
@@ -0,0 +1,575 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR Intel Corporation
+# This file is distributed under the same license as the PACKAGE package.
+# 
+# Translators:
+# Yuan CHAO <yuanchao@gmail.com>, 2012.
+msgid ""
+msgstr ""
+"Project-Id-Version: PowerTOP\n"
+"Report-Msgid-Bugs-To: \"powertop@lists.01.org\"\n"
+"POT-Creation-Date: 2012-05-31 14:03-0700\n"
+"PO-Revision-Date: 2012-06-05 19:51+0000\n"
+"Last-Translator: Yuan CHAO <yuanchao@gmail.com>\n"
+"Language-Team: Chinese (Taiwan) (http://www.transifex.com/projects/p/PowerTOP/language/zh_TW/)\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Language: zh_TW\n"
+"Plural-Forms: nplurals=1; plural=0\n"
+
+#: src/parameters/persistent.cpp:46 src/parameters/persistent.cpp:140
+msgid "Cannot save to file "
+msgstr "無法保存到檔案 "
+
+#: src/parameters/persistent.cpp:78 src/parameters/persistent.cpp:165
+msgid "Cannot load from file "
+msgstr "無法由檔案載入  "
+
+#: src/parameters/persistent.cpp:123
+#, c-format
+msgid "Loaded %i prior measurements\n"
+msgstr "載入 %i 先前量測數據\n"
+
+#: src/display.cpp:71
+msgid "Overview"
+msgstr "總覽"
+
+#: src/display.cpp:72
+msgid "Idle stats"
+msgstr "閒置統計"
+
+#: src/display.cpp:73
+msgid "Frequency stats"
+msgstr "頻率統計"
+
+#: src/display.cpp:74
+msgid "Device stats"
+msgstr "設備統計"
+
+#: src/display.cpp:131
+msgid "Exit"
+msgstr "離開"
+
+#: src/cpu/cpu_core.cpp:46 src/cpu/cpu_core.cpp:190 src/cpu/intel_cpus.cpp:296
+#, c-format
+msgid "  Core"
+msgstr "  核心"
+
+#: src/cpu/cpu_core.cpp:116 src/cpu/cpu_linux.cpp:329
+#: src/cpu/cpu_package.cpp:145 src/cpu/intel_cpus.cpp:222
+#: src/cpu/intel_cpus.cpp:457 src/cpu/intel_cpus.cpp:658
+msgid "Idle"
+msgstr "閒置"
+
+#: src/cpu/cpu_core.cpp:118 src/cpu/cpu_linux.cpp:331
+#: src/cpu/cpu_package.cpp:147 src/cpu/intel_cpus.cpp:224
+#: src/cpu/intel_cpus.cpp:459
+#, c-format
+msgid "Turbo Mode"
+msgstr "超頻模式"
+
+#: src/cpu/cpu.cpp:90
+#, c-format
+msgid "cpu package %i"
+msgstr "cpu 代號 %i"
+
+#: src/cpu/cpu.cpp:91
+msgid "cpu package"
+msgstr "cpu 代號"
+
+#: src/cpu/cpu.cpp:925
+#, c-format
+msgid "cpu_idle event returned no state?\n"
+msgstr "cpu_idle 事件沒有傳回狀態?\n"
+
+#: src/cpu/cpu.cpp:940
+#, c-format
+msgid "power or cpu_frequecny event returned no state?\n"
+msgstr "power 或 cpu_frequecny 事件沒有傳回狀態?\n"
+
+#: src/cpu/cpu_linux.cpp:92
+msgid "C0 polling"
+msgstr "C0 輪巡"
+
+#: src/cpu/cpu_linux.cpp:231 src/cpu/cpu_linux.cpp:289
+#: src/cpu/intel_cpus.cpp:605
+#, c-format
+msgid " CPU %i"
+msgstr " CPU %i"
+
+#: src/cpu/cpu_package.cpp:46
+#, c-format
+msgid "Package"
+msgstr "代號"
+
+#: src/cpu/cpu_package.cpp:104 src/cpu/intel_cpus.cpp:322
+#, c-format
+msgid "  Package"
+msgstr "  代號"
+
+#: src/cpu/intel_cpus.cpp:69
+#, c-format
+msgid "msr reg not found"
+msgstr "找不到 msr 暫存器"
+
+#: src/cpu/intel_cpus.cpp:79
+#, c-format
+msgid "pread cpu%d 0x%llx : "
+msgstr "pread cpu%d 0x%llx : "
+
+#: src/cpu/intel_cpus.cpp:529
+msgid "C0 active"
+msgstr "C0 運作中"
+
+#: src/cpu/intel_cpus.cpp:588
+#, c-format
+msgid "Actual"
+msgstr "實際"
+
+#: src/lib.cpp:257
+#, c-format
+msgid "%7sW"
+msgstr "%7sW"
+
+#: src/lib.cpp:260
+#, c-format
+msgid "    0 mW"
+msgstr "    0 mW"
+
+#: src/lib.cpp:369
+msgid "PS/2 Touchpad / Keyboard / Mouse"
+msgstr "PS/2  觸控板 / 鍵盤 / 滑鼠"
+
+#: src/lib.cpp:370
+msgid "SATA controller"
+msgstr "SATA 控制器"
+
+#: src/lib.cpp:371
+msgid "Intel built in USB hub"
+msgstr "Intel 內建 USB 集線器"
+
+#: src/process/do_process.cpp:818
+#, c-format
+msgid ""
+"Estimated power: %5.1f    Measured power: %5.1f    Sum: %5.1f\n"
+"\n"
+msgstr "預估用電量: %5.1f         實測用電量: %5.1f        總計: %5.1f\n\n"
+
+#: src/process/do_process.cpp:829 src/devices/device.cpp:171
+#, c-format
+msgid "The battery reports a discharge rate of %sW\n"
+msgstr "電池回報放電速率為 %sW\n"
+
+#: src/process/do_process.cpp:834
+#, c-format
+msgid "The estimated remaining time is %i hours, %i minutes\n"
+msgstr "預期剩餘時間為 %i 小時 %i 分鐘\n"
+
+#: src/process/do_process.cpp:842
+msgid "Summary"
+msgstr "總覽"
+
+#: src/process/do_process.cpp:842 src/process/do_process.cpp:1029
+msgid "wakeups/second"
+msgstr "喚醒 / 秒"
+
+#: src/process/do_process.cpp:842
+msgid "GPU ops/seconds"
+msgstr "GPU 指令 / 秒"
+
+#: src/process/do_process.cpp:842
+msgid "VFS ops/sec and"
+msgstr "VFS 指令 / 秒 以及"
+
+#: src/process/do_process.cpp:842 src/process/do_process.cpp:1030
+msgid "CPU use"
+msgstr "CPU 用量"
+
+#: src/process/do_process.cpp:846 src/process/do_process.cpp:914
+#: src/process/do_process.cpp:1034
+msgid "Power est."
+msgstr "電源預計"
+
+#: src/process/do_process.cpp:846 src/process/do_process.cpp:848
+#: src/process/do_process.cpp:914 src/process/do_process.cpp:917
+#: src/process/do_process.cpp:1034 src/process/do_process.cpp:1038
+msgid "Usage"
+msgstr "用法"
+
+#: src/process/do_process.cpp:846 src/process/do_process.cpp:848
+#: src/process/do_process.cpp:1034 src/process/do_process.cpp:1038
+msgid "Events/s"
+msgstr "事件 / 秒"
+
+#: src/process/do_process.cpp:846 src/process/do_process.cpp:848
+#: src/process/do_process.cpp:914 src/process/do_process.cpp:917
+#: src/process/do_process.cpp:1034 src/process/do_process.cpp:1038
+msgid "Category"
+msgstr "分類"
+
+#: src/process/do_process.cpp:846 src/process/do_process.cpp:848
+#: src/process/do_process.cpp:914 src/process/do_process.cpp:917
+#: src/process/do_process.cpp:1034 src/process/do_process.cpp:1038
+msgid "Description"
+msgstr "描述"
+
+#: src/process/do_process.cpp:911
+msgid "Overview of Software Power Consumers"
+msgstr "軟體耗電量大戶總覽"
+
+#: src/process/do_process.cpp:914 src/process/do_process.cpp:917
+msgid "Wakeups/s"
+msgstr "喚醒 / 秒"
+
+#: src/process/do_process.cpp:914 src/process/do_process.cpp:917
+msgid "GPU ops/s"
+msgstr "GPU 指令 / 秒"
+
+#: src/process/do_process.cpp:914 src/process/do_process.cpp:917
+msgid "Disk IO/s"
+msgstr "磁碟 IO / 秒"
+
+#: src/process/do_process.cpp:914 src/process/do_process.cpp:917
+msgid "GFX Wakeups/s"
+msgstr "GFX 喚醒 / 秒"
+
+#: src/process/do_process.cpp:1026
+msgid "Power Consumption Summary"
+msgstr "電源使用量總覽"
+
+#: src/process/do_process.cpp:1029
+msgid "GPU ops/second"
+msgstr "GPU 指令 / 秒"
+
+#: src/process/do_process.cpp:1030
+msgid "VFS ops/sec"
+msgstr "VFS 指令 / 秒"
+
+#: src/process/do_process.cpp:1030
+msgid "GFX wakes/sec and"
+msgstr "GFX 喚醒 / 秒 以及"
+
+#: src/perf/perf.cpp:121
+#, c-format
+msgid "PowerTOP %s needs the kernel to support the 'perf' subsystem\n"
+msgstr "PowerTOP %s 需要 Linux 核心 'perf' 子系統支援\n"
+
+#: src/perf/perf.cpp:122
+#, c-format
+msgid "as well as support for trace points in the kernel:\n"
+msgstr "以及 Linux 核心中斷點 (trace point) 支援:\n"
+
+#: src/devices/device.cpp:177
+#, c-format
+msgid "System baseline power is estimated at %sW\n"
+msgstr "預期系統基礎用電量為 %sW\n"
+
+#: src/devices/device.cpp:184
+msgid "Power est.    Usage     Device name\n"
+msgstr "電源預估      使用量    設備名稱\n"
+
+#: src/devices/device.cpp:186
+msgid "              Usage     Device name\n"
+msgstr "              使用量    設備名稱\n"
+
+#: src/devices/alsa.cpp:79
+#, c-format
+msgid "Audio codec %s: %s (%s)"
+msgstr "音效設備 %s: %s (%s)"
+
+#: src/devices/alsa.cpp:81 src/devices/alsa.cpp:83
+#, c-format
+msgid "Audio codec %s: %s"
+msgstr "音效設備 %s: %s"
+
+#: src/devices/runtime_pm.cpp:225
+#, c-format
+msgid "PCI Device: %s"
+msgstr "PCI 設備: %s"
+
+#: src/devices/usb.cpp:51 src/devices/usb.cpp:94 src/devices/usb.cpp:96
+#, c-format
+msgid "USB device: %s"
+msgstr "USB 設備: %s"
+
+#: src/devices/usb.cpp:92
+#, c-format
+msgid "USB device: %s (%s)"
+msgstr "USB 設備: %s (%s)"
+
+#: src/devices/ahci.cpp:140
+#, c-format
+msgid "SATA link: %s"
+msgstr "SATA 連線: %s"
+
+#: src/devices/ahci.cpp:142
+#, c-format
+msgid "SATA disk: %s"
+msgstr "SATA 磁碟: %s"
+
+#: src/devices/rfkill.cpp:65 src/devices/rfkill.cpp:69
+#, c-format
+msgid "Radio device: %s"
+msgstr "無線電設備: %s"
+
+#: src/devices/network.cpp:177
+#, c-format
+msgid "Network interface: %s (%s)"
+msgstr "網路介面卡: %s (%s)"
+
+#: src/tuning/bluetooth.cpp:48
+#, c-format
+msgid "Bluetooth device interface status"
+msgstr "藍牙設備介面狀態"
+
+#: src/tuning/cpufreq.cpp:43 src/tuning/ethernet.cpp:53
+#: src/tuning/tunable.cpp:48 src/tuning/wifi.cpp:45 src/tuning/runtime.cpp:41
+#: src/tuning/tuningusb.cpp:40 src/tuning/tuningsysfs.cpp:37
+msgid "Good"
+msgstr "好"
+
+#: src/tuning/cpufreq.cpp:43 src/tuning/ethernet.cpp:53
+#: src/tuning/tunable.cpp:49 src/tuning/wifi.cpp:45 src/tuning/runtime.cpp:41
+#: src/tuning/tuningusb.cpp:40 src/tuning/tuningsysfs.cpp:37
+msgid "Bad"
+msgstr "壞"
+
+#: src/tuning/cpufreq.cpp:43 src/tuning/ethernet.cpp:53
+#: src/tuning/tunable.cpp:50 src/tuning/wifi.cpp:45 src/tuning/runtime.cpp:41
+#: src/tuning/tuningusb.cpp:40 src/tuning/tuningsysfs.cpp:37
+msgid "Unknown"
+msgstr "未知"
+
+#: src/tuning/cpufreq.cpp:46
+#, c-format
+msgid "Using 'ondemand' cpufreq governor"
+msgstr "使用 'ondemand' cpu 排程器"
+
+#: src/tuning/tuning.cpp:60
+msgid "Enable Audio codec power management"
+msgstr "啟用音效設備電源管理功能"
+
+#: src/tuning/tuning.cpp:61
+msgid "Enable SATA link power management for /dev/sda"
+msgstr "啟動 SATA 連線電源管理功能於 /dev/sda"
+
+#: src/tuning/tuning.cpp:62
+msgid "NMI watchdog should be turned off"
+msgstr "NMI watchdog 監控應該關閉"
+
+#: src/tuning/tuning.cpp:63
+msgid "Power Aware CPU scheduler"
+msgstr "省電型 CPU 排程器 "
+
+#: src/tuning/tuning.cpp:64
+msgid "VM writeback timeout"
+msgstr "VM 回寫延時"
+
+#: src/tuning/tuning.cpp:82
+msgid "Tunables"
+msgstr "可調選項"
+
+#: src/tuning/tuning.cpp:82
+msgid " <ESC> Exit | <Enter> Toggle tunable | <r> Window refresh"
+msgstr " <ESC> 離開 | <Enter> 切換選項開關   | <r> 更新視窗內容"
+
+#: src/tuning/ethernet.cpp:57
+#, c-format
+msgid "Wake-on-lan status for device %s"
+msgstr "網路喚醒啟用狀態於設備 %s"
+
+#: src/tuning/wifi.cpp:48
+#, c-format
+msgid "Wireless Power Saving for interface %s"
+msgstr "無線網路省電狀態於設備 %s"
+
+#: src/tuning/runtime.cpp:47
+#, c-format
+msgid "Runtime PM for %s device %s"
+msgstr "執行時期省電 %s 設備 %s"
+
+#: src/tuning/runtime.cpp:49
+#, c-format
+msgid "%s device %s has no runtime power management"
+msgstr "%s 設備 %s 沒有執行時期電源管理功能"
+
+#: src/tuning/runtime.cpp:73
+#, c-format
+msgid "PCI Device %s has no runtime power management"
+msgstr "PCI 設備 %s 沒有執行時期電源管理功能"
+
+#: src/tuning/runtime.cpp:75
+#, c-format
+msgid "Runtime PM for PCI Device %s"
+msgstr "PCI 設備 %s 電源管理"
+
+#: src/tuning/tuningusb.cpp:55
+#, c-format
+msgid "Autosuspend for unknown USB device %s (%s:%s)"
+msgstr "自動閒置於未知的 USB 設備 %s (%s:%s)"
+
+#: src/tuning/tuningusb.cpp:72 src/tuning/tuningusb.cpp:74
+#: src/tuning/tuningusb.cpp:76
+#, c-format
+msgid "Autosuspend for USB device %s [%s]"
+msgstr "自動閒置於 USB 設備 %s [%s]"
+
+#: src/calibrate/calibrate.cpp:291
+#, c-format
+msgid "Cannot create temp file\n"
+msgstr "無法建立暫存檔案\n"
+
+#: src/calibrate/calibrate.cpp:310
+#, c-format
+msgid "Calibrating: CPU usage on %i threads\n"
+msgstr "校正: CPU 使用量於 %i 執行緒\n"
+
+#: src/calibrate/calibrate.cpp:325
+#, c-format
+msgid "Calibrating: CPU wakeup power consumption\n"
+msgstr "校正: CPU 喚醒電源使用量\n"
+
+#: src/calibrate/calibrate.cpp:342
+#, c-format
+msgid "Calibrating USB devices\n"
+msgstr "校正 USB 設備\n"
+
+#: src/calibrate/calibrate.cpp:344 src/calibrate/calibrate.cpp:361
+#: src/calibrate/calibrate.cpp:369 src/calibrate/calibrate.cpp:386
+#, c-format
+msgid ".... device %s \n"
+msgstr ".... 裝置 %s \n"
+
+#: src/calibrate/calibrate.cpp:359
+#, c-format
+msgid "Calibrating radio devices\n"
+msgstr "校正無線電設備\n"
+
+#: src/calibrate/calibrate.cpp:383
+#, c-format
+msgid "Calibrating backlight\n"
+msgstr "校正螢幕背光\n"
+
+#: src/calibrate/calibrate.cpp:407 src/calibrate/calibrate.cpp:415
+#, c-format
+msgid "Calibrating idle\n"
+msgstr "校正閒置\n"
+
+#: src/calibrate/calibrate.cpp:426
+#, c-format
+msgid "Calibrating: disk usage \n"
+msgstr "校正: 磁碟使用\n"
+
+#: src/calibrate/calibrate.cpp:451
+msgid "Starting PowerTOP power estimate calibration \n"
+msgstr "開始 PowerTOP 電源預期校正 \n"
+
+#: src/calibrate/calibrate.cpp:474
+msgid "Finishing PowerTOP power estimate calibration \n"
+msgstr "完成 PowerTOP 電源預期校正 \n"
+
+#: src/calibrate/calibrate.cpp:478
+#, c-format
+msgid "Parameters after calibration:\n"
+msgstr "校正取得參數:\n"
+
+#: src/main.cpp:84
+#, c-format
+msgid "PowerTOP version"
+msgstr "PowerTop 版本"
+
+#: src/main.cpp:90
+msgid "Set refresh time out"
+msgstr "設定更新週期"
+
+#: src/main.cpp:103
+msgid "Usage: powertop [OPTIONS]"
+msgstr "用法: powertop [選項]"
+
+#: src/main.cpp:104
+msgid "run in \"debug\" mode"
+msgstr "以 \"debug\" 模式執行"
+
+#: src/main.cpp:105
+msgid "print version information"
+msgstr "顯示版本資訊"
+
+#: src/main.cpp:106
+msgid "runs powertop in calibration mode"
+msgstr "以校正模式執行 powertop"
+
+#: src/main.cpp:107
+msgid "[=devnode]"
+msgstr "[= 設備節點]"
+
+#: src/main.cpp:107
+msgid "uses an Extech Power Analyzer for measurements"
+msgstr "使用 Extech 電源分析儀進行量測"
+
+#: src/main.cpp:108 src/main.cpp:109
+msgid "[=FILENAME]"
+msgstr "[= 檔案名稱]"
+
+#: src/main.cpp:108
+msgid "generate a html report"
+msgstr "產生 html 報告"
+
+#: src/main.cpp:109
+msgid "generate a csv report"
+msgstr "產生 csv 報告"
+
+#: src/main.cpp:110
+msgid "[=seconds]"
+msgstr "[= 秒]"
+
+#: src/main.cpp:110
+msgid "generate a report for 'x' seconds"
+msgstr "產生蒐集資料 'x' 秒鐘的報告"
+
+#: src/main.cpp:111
+msgid "[=iterations] number of times to run each test"
+msgstr "[=iterations] 每次檢驗進行量測次數"
+
+#: src/main.cpp:112
+msgid "print this help menu"
+msgstr "顯示此輔助說明選單"
+
+#: src/main.cpp:114
+msgid "For more help please refer to the README"
+msgstr "更多的輔助說明請參閱 README"
+
+#: src/main.cpp:224
+#, c-format
+msgid "PowerTOP is out of memory. PowerTOP is Aborting"
+msgstr "PowerTOP 已耗盡記憶體,退出中。"
+
+#: src/main.cpp:252
+#, c-format
+msgid "Preparing to take measurements\n"
+msgstr "量測準備中\n"
+
+#: src/main.cpp:255
+#, c-format
+msgid "Taking %d measurement(s) for a duration of %d second(s) each.\n"
+msgstr "測量 %d 次於每 %d 秒。\n"
+
+#: src/main.cpp:278
+#, c-format
+msgid "PowerTOP "
+msgstr "PowerTOP "
+
+#: src/main.cpp:279 src/main.cpp:307
+#, c-format
+msgid "exiting...\n"
+msgstr "離開中...\n"
+
+#: src/main.cpp:306
+#, c-format
+msgid "Failed to mount debugfs!\n"
+msgstr "debugfs 掛載失敗!\n"
+
+#: src/main.cpp:443
+#, c-format
+msgid "Leaving PowerTOP"
+msgstr "離開 PowerTOP"
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644 (file)
index 0000000..f60426a
--- /dev/null
@@ -0,0 +1,53 @@
+AUTOMAKE_OPTIONS = subdir-objects
+ACLOCAL_AMFLAGS = -I ../m4 
+
+noinst_PROGRAMS = csstoh
+csstoh_SOURCES = csstoh.c 
+
+sbin_PROGRAMS = powertop
+nodist_powertop_SOURCES = css.h
+
+powertop_SOURCES = parameters/persistent.cpp parameters/learn.cpp parameters/parameters.cpp \
+               parameters/parameters.h display.cpp cpu/cpu_core.cpp cpu/cpudevice.cpp  \
+               cpu/cpu.cpp cpu/cpu.h cpu/cpu_linux.cpp cpu/abstract_cpu.cpp cpu/intel_cpus.h \
+               cpu/cpu_package.cpp cpu/cpudevice.h cpu/intel_cpus.cpp devlist.h devlist.cpp \
+               lib.cpp report/report.cpp process/process.cpp process/interrupt.h process/timer.h  \
+               process/processdevice.cpp process/powerconsumer.cpp process/work.h \
+               process/timer.cpp process/process.h process/work.cpp process/do_process.cpp \
+               process/processdevice.h process/interrupt.cpp process/powerconsumer.h report/report.h \
+               perf/perf.cpp perf/perf_event.h perf/perf.h perf/perf_bundle.h perf/perf_bundle.cpp \
+               display.h devices/rfkill.h devices/i915-gpu.cpp devices/device.cpp devices/alsa.cpp \
+               devices/runtime_pm.cpp devices/thinkpad-fan.cpp devices/usb.cpp devices/ahci.cpp \
+               devices/thinkpad-light.cpp devices/ahci.h devices/i915-gpu.h devices/network.h \
+               devices/rfkill.cpp devices/alsa.h devices/thinkpad-fan.h devices/device.h \
+               devices/usb.h devices/backlight.h devices/backlight.cpp devices/runtime_pm.h \
+               devices/thinkpad-light.h devices/network.cpp lib.h tuning tuning/cpufreq.h \
+               tuning/bluetooth.cpp tuning/cpufreq.cpp tuning/tuning.cpp tuning/tuningusb.cpp \
+               tuning/ethernet.cpp tuning/bluetooth.h tuning/tuning.h tuning/ethernet.h \
+               tuning/tunable.cpp tuning/nl80211.h tuning/iw.c tuning/wifi.cpp tuning/tuningsysfs.h \
+               tuning/tuningsysfs.cpp tuning/wifi.h tuning/runtime.cpp tuning/tunable.h \
+               tuning/runtime.h tuning/tuningusb.h tuning/iw.h calibrate/calibrate.cpp \
+               calibrate/calibrate.h measurement/measurement.cpp measurement/power_supply.cpp \
+               measurement/measurement.h measurement/acpi.cpp measurement/sysfs.h measurement/sysfs.cpp \
+               measurement/acpi.h measurement/extech.cpp measurement/power_supply.h measurement/extech.h \
+               report/report-maker.cpp report/report-maker.h report/report-formatter.h \
+               report/report-formatter-base.cpp report/report-formatter-base.h \
+               report/report-formatter-csv.cpp report/report-formatter-csv.h \
+               report/report-formatter-html.cpp report/report-formatter-html.h \
+               main.cpp css.h powertop.css cpu/intel_gpu.cpp
+
+
+powertop_CXXFLAGS = -fno-omit-frame-pointer -fstack-protector -Wall -Wshadow -Wformat $(NCURSES_CFLAGS) $(PCIUTILS_CFLAGS) $(LIBNL_CFLAGS) $(GLIB2_CFLAGS)
+
+
+powertop_CPPFLAGS = -D_FORTIFY_SOURCE=2 $(NCURSES_CFLAGS) $(PCIUTILS_CFLAGS) $(LIBNL_CFLAGS) $(GLIB2_CFLAGS) $(LIBZ_CFLAGS) -DLOCALEDIR=\"$(localedir)\"
+
+powertop_LDADD = ../traceevent/libtraceevnet.la
+
+AM_LDFLAGS = $(LIBS) $(NCURSES_LIBS) $(PCIUTILS_LIBS) $(LIBNL_LIBS) $(LIBZ_LIBS) $(PTHREAD_LIBS)  $(RESOLV_LIBS)
+
+BUILT_SOURCES = css.h
+CLEANFILES = css.h
+css.h: csstoh powertop.css
+       ./csstoh "$(srcdir)"/powertop.css css.h
+
diff --git a/src/calibrate/calibrate.cpp b/src/calibrate/calibrate.cpp
new file mode 100644 (file)
index 0000000..5457cf8
--- /dev/null
@@ -0,0 +1,483 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ *     Arjan van de Ven <arjan@linux.intel.com>
+ */
+#include <iostream>
+#include <fstream>
+#include <algorithm>
+
+#include "calibrate.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <math.h>
+#include <sys/types.h>
+#include <dirent.h>
+
+#include "../parameters/parameters.h"
+extern "C" {
+#include "../tuning/iw.h"
+}
+
+#include <map>
+#include <vector>
+#include <string>
+
+using namespace std;
+
+
+static vector<string> usb_devices;
+static vector<string> rfkill_devices;
+static vector<string> backlight_devices;
+static vector<string> scsi_link_devices;
+static int blmax;
+
+static map<string, string> saved_sysfs;
+
+
+static volatile int stop_measurement;
+
+static int wireless_PS;
+
+
+static void save_sysfs(const char *filename)
+{
+       char line[4096];
+       ifstream file;
+
+       file.open(filename, ios::in);
+       if (!file)
+               return;
+       file.getline(line, 4096);
+       file.close();
+
+       saved_sysfs[filename] = line;
+}
+
+static void restore_all_sysfs(void)
+{
+       map<string, string>::iterator it;
+
+       for (it = saved_sysfs.begin(); it != saved_sysfs.end(); it++)
+               write_sysfs(it->first, it->second);
+
+       set_wifi_power_saving("wlan0", wireless_PS);
+}
+
+static void find_all_usb(void)
+{
+       struct dirent *entry;
+       DIR *dir;
+       char filename[4096];
+
+       dir = opendir("/sys/bus/usb/devices/");
+       if (!dir)
+               return;
+       while (1) {
+               ifstream file;
+
+               entry = readdir(dir);
+
+               if (!entry)
+                       break;
+               if (entry->d_name[0] == '.')
+                       continue;
+
+               sprintf(filename, "/sys/bus/usb/devices/%s/power/active_duration", entry->d_name);
+               if (access(filename, R_OK)!=0)
+                       continue;
+
+               sprintf(filename, "/sys/bus/usb/devices/%s/power/idVendor", entry->d_name);
+               file.open(filename, ios::in);
+               if (file) {
+                       file.getline(filename, 4096);
+                       file.close();
+                       if (strcmp(filename, "1d6b")==0)
+                               continue;
+               }
+
+               sprintf(filename, "/sys/bus/usb/devices/%s/power/control", entry->d_name);
+
+               save_sysfs(filename);
+
+               usb_devices.push_back(filename);
+       }
+       closedir(dir);
+}
+
+static void suspend_all_usb_devices(void)
+{
+       unsigned int i;
+
+       for (i = 0; i < usb_devices.size(); i++)
+               write_sysfs(usb_devices[i], "auto\n");
+}
+
+
+static void find_all_rfkill(void)
+{
+       struct dirent *entry;
+       DIR *dir;
+       char filename[4096];
+
+       dir = opendir("/sys/class/rfkill/");
+       if (!dir)
+               return;
+       while (1) {
+               entry = readdir(dir);
+
+               if (!entry)
+                       break;
+               if (entry->d_name[0] == '.')
+                       continue;
+
+               sprintf(filename, "/sys/class/rfkill/%s/soft", entry->d_name);
+               if (access(filename, R_OK)!=0)
+                       continue;
+
+               save_sysfs(filename);
+
+               rfkill_devices.push_back(filename);
+       }
+       closedir(dir);
+}
+
+static void rfkill_all_radios(void)
+{
+       unsigned int i;
+
+       for (i = 0; i < rfkill_devices.size(); i++)
+               write_sysfs(rfkill_devices[i], "1\n");
+}
+static void unrfkill_all_radios(void)
+{
+       unsigned int i;
+
+       for (i = 0; i < rfkill_devices.size(); i++)
+               write_sysfs(rfkill_devices[i], "0\n");
+}
+
+static void find_backlight(void)
+{
+       struct dirent *entry;
+       DIR *dir;
+       char filename[4096];
+
+       dir = opendir("/sys/class/backlight/");
+       if (!dir)
+               return;
+       while (1) {
+               entry = readdir(dir);
+
+               if (!entry)
+                       break;
+               if (entry->d_name[0] == '.')
+                       continue;
+
+               sprintf(filename, "/sys/class/backlight/%s/brightness", entry->d_name);
+               if (access(filename, R_OK)!=0)
+                       continue;
+
+               save_sysfs(filename);
+
+               backlight_devices.push_back(filename);
+
+               sprintf(filename, "/sys/class/backlight/%s/max_brightness", entry->d_name);
+               blmax = read_sysfs(filename);
+       }
+       closedir(dir);
+}
+
+static void lower_backlight(void)
+{
+       unsigned int i;
+
+       for (i = 0; i < backlight_devices.size(); i++)
+               write_sysfs(backlight_devices[i], "0\n");
+}
+
+
+static void find_scsi_link(void)
+{
+       struct dirent *entry;
+       DIR *dir;
+       char filename[4096];
+
+       dir = opendir("/sys/class/scsi_host/");
+       if (!dir)
+               return;
+       while (1) {
+               entry = readdir(dir);
+
+               if (!entry)
+                       break;
+               if (entry->d_name[0] == '.')
+                       continue;
+
+               sprintf(filename, "/sys/class/scsi_host/%s/link_power_management_policy", entry->d_name);
+               if (access(filename, R_OK)!=0)
+                       continue;
+
+               save_sysfs(filename);
+
+               scsi_link_devices.push_back(filename);
+
+       }
+       closedir(dir);
+}
+
+static void set_scsi_link(const char *state)
+{
+       unsigned int i;
+
+       for (i = 0; i < scsi_link_devices.size(); i++)
+               write_sysfs(scsi_link_devices[i], state);
+}
+
+
+static void *burn_cpu(void *dummy)
+{
+       volatile double d = 1.1;
+
+       while (!stop_measurement) {
+               d = pow(d, 1.0001);
+       }
+       return NULL;
+}
+
+static void *burn_cpu_wakeups(void *dummy)
+{
+       struct timespec tm;
+
+       while (!stop_measurement) {
+               tm.tv_sec = 0;
+               tm.tv_nsec = (unsigned long)dummy;
+               nanosleep(&tm, NULL);
+       }
+       return NULL;
+}
+
+static void *burn_disk(void *dummy)
+{
+       int fd;
+       char buffer[64*1024];
+       char filename[256];
+
+       strcpy(filename ,"/tmp/powertop.XXXXXX");
+       fd = mkstemp(filename);
+
+       if (fd < 0) {
+               printf(_("Cannot create temp file\n"));
+               return NULL;
+       }
+
+       while (!stop_measurement) {
+               lseek(fd, 0, SEEK_SET);
+               write(fd, buffer, 64*1024);
+               fdatasync(fd);
+       }
+       close(fd);
+       return NULL;
+}
+
+
+static void cpu_calibration(int threads)
+{
+       int i;
+       pthread_t thr;
+
+       printf(_("Calibrating: CPU usage on %i threads\n"), threads);
+
+       stop_measurement = 0;
+       for (i = 0; i < threads; i++)
+               pthread_create(&thr, NULL, burn_cpu, NULL);
+
+       one_measurement(15, NULL);
+       stop_measurement = 1;
+       sleep(1);
+}
+
+static void wakeup_calibration(unsigned long interval)
+{
+       pthread_t thr;
+
+       printf(_("Calibrating: CPU wakeup power consumption\n"));
+
+       stop_measurement = 0;
+
+       pthread_create(&thr, NULL, burn_cpu_wakeups, (void *)interval);
+
+       one_measurement(15, NULL);
+       stop_measurement = 1;
+       sleep(1);
+}
+
+static void usb_calibration(void)
+{
+       unsigned int i;
+
+       /* chances are one of the USB devices is bluetooth; unrfkill first */
+       unrfkill_all_radios();
+       printf(_("Calibrating USB devices\n"));
+       for (i = 0; i < usb_devices.size(); i++) {
+               printf(_(".... device %s \n"), usb_devices[i].c_str());
+               suspend_all_usb_devices();
+               write_sysfs(usb_devices[i], "on\n");
+               one_measurement(15, NULL);
+               suspend_all_usb_devices();
+               sleep(3);
+       }
+       rfkill_all_radios();
+       sleep(4);
+}
+
+static void rfkill_calibration(void)
+{
+       unsigned int i;
+
+       printf(_("Calibrating radio devices\n"));
+       for (i = 0; i < rfkill_devices.size(); i++) {
+               printf(_(".... device %s \n"), rfkill_devices[i].c_str());
+               rfkill_all_radios();
+               write_sysfs(rfkill_devices[i], "0\n");
+               one_measurement(15, NULL);
+               rfkill_all_radios();
+               sleep(3);
+       }
+       for (i = 0; i < rfkill_devices.size(); i++) {
+               printf(_(".... device %s \n"), rfkill_devices[i].c_str());
+               unrfkill_all_radios();
+               write_sysfs(rfkill_devices[i], "1\n");
+               one_measurement(15, NULL);
+               unrfkill_all_radios();
+               sleep(3);
+       }
+       rfkill_all_radios();
+}
+
+static void backlight_calibration(void)
+{
+       unsigned int i;
+
+       printf(_("Calibrating backlight\n"));
+       for (i = 0; i < backlight_devices.size(); i++) {
+               char str[4096];
+               printf(_(".... device %s \n"), backlight_devices[i].c_str());
+               lower_backlight();
+               one_measurement(15, NULL);
+               sprintf(str, "%i\n", blmax / 4);
+               write_sysfs(backlight_devices[i], str);
+               one_measurement(15, NULL);
+
+               sprintf(str, "%i\n", blmax / 2);
+               write_sysfs(backlight_devices[i], str);
+               one_measurement(15, NULL);
+
+               sprintf(str, "%i\n", 3 * blmax / 4 );
+               write_sysfs(backlight_devices[i], str);
+               one_measurement(15, NULL);
+
+               sprintf(str, "%i\n", blmax);
+               write_sysfs(backlight_devices[i], str);
+               one_measurement(15, NULL);
+               lower_backlight();
+               sleep(1);
+       }
+       printf(_("Calibrating idle\n"));
+       system("DISPLAY=:0 /usr/bin/xset dpms force off");
+       one_measurement(15, NULL);
+       system("DISPLAY=:0 /usr/bin/xset dpms force on");
+}
+
+static void idle_calibration(void)
+{
+       printf(_("Calibrating idle\n"));
+       system("DISPLAY=:0 /usr/bin/xset dpms force off");
+       one_measurement(15, NULL);
+       system("DISPLAY=:0 /usr/bin/xset dpms force on");
+}
+
+
+static void disk_calibration(void)
+{
+       pthread_t thr;
+
+       printf(_("Calibrating: disk usage \n"));
+
+       set_scsi_link("min_power");
+
+       stop_measurement = 0;
+       pthread_create(&thr, NULL, burn_disk, NULL);
+
+       one_measurement(15, NULL);
+       stop_measurement = 1;
+       sleep(1);
+
+
+}
+
+
+void calibrate(void)
+{
+       find_all_usb();
+       find_all_rfkill();
+       find_backlight();
+       find_scsi_link();
+       wireless_PS = get_wifi_power_saving("wlan0");
+
+        save_sysfs("/sys/module/snd_hda_intel/parameters/power_save");
+
+       cout << _("Starting PowerTOP power estimate calibration \n");
+       suspend_all_usb_devices();
+       rfkill_all_radios();
+       lower_backlight();
+       set_wifi_power_saving("wlan0", 1);
+
+       sleep(4);
+
+
+       idle_calibration();
+       disk_calibration();
+       backlight_calibration();
+
+       write_sysfs("/sys/module/snd_hda_intel/parameters/power_save", "1\n");
+       cpu_calibration(1);
+       cpu_calibration(4);
+       wakeup_calibration(10000);
+       wakeup_calibration(100000);
+       wakeup_calibration(1000000);
+       set_wifi_power_saving("wlan0", 0);
+       usb_calibration();
+       rfkill_calibration();
+
+       cout << _("Finishing PowerTOP power estimate calibration \n");
+
+       restore_all_sysfs();
+        learn_parameters(300, 1);
+       printf(_("Parameters after calibration:\n"));
+       dump_parameter_bundle();
+       save_parameters("saved_parameters.powertop");
+        save_all_results("saved_results.powertop");
+
+}
diff --git a/src/calibrate/calibrate.h b/src/calibrate/calibrate.h
new file mode 100644 (file)
index 0000000..c279ae2
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ *     Arjan van de Ven <arjan@linux.intel.com>
+ */
+#ifndef __INCLUDE_GUARD_CALIBRATE_H
+#define __INCLUDE_GUARD_CALIBRATE_H
+
+extern void one_measurement(int seconds, char *workload);
+extern void calibrate(void);
+
+
+#endif
diff --git a/src/cpu/abstract_cpu.cpp b/src/cpu/abstract_cpu.cpp
new file mode 100644 (file)
index 0000000..537f3cb
--- /dev/null
@@ -0,0 +1,442 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ *     Arjan van de Ven <arjan@linux.intel.com>
+ */
+#include <iostream>
+#include <fstream>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "cpu.h"
+
+
+void abstract_cpu::measurement_start(void)
+{
+       unsigned int i;
+       ifstream file;
+       char filename[4096];
+
+       last_stamp = 0;
+
+       for (i = 0; i < cstates.size(); i++)
+               delete cstates[i];
+       cstates.resize(0);
+
+       for (i = 0; i < pstates.size(); i++)
+               delete pstates[i];
+       pstates.resize(0);
+
+       current_frequency = 0;
+       idle = false;
+       old_idle = true;
+
+
+       sprintf(filename, "/sys/devices/system/cpu/cpu%i/cpufreq/scaling_available_frequencies", number);
+       file.open(filename, ios::in);
+       if (file) {
+               file >> max_frequency;
+               file >> max_minus_one_frequency;
+               file.close();
+       }
+
+       for (i = 0; i < children.size(); i++)
+               if (children[i])
+                       children[i]->measurement_start();
+
+       gettimeofday(&stamp_before, NULL);
+
+       last_stamp = 0;
+
+       for (i = 0; i < children.size(); i++)
+               if (children[i])
+                       children[i]->wiggle();
+
+}
+
+void abstract_cpu::measurement_end(void)
+{
+       unsigned int i, j;
+
+       total_stamp = 0;
+       gettimeofday(&stamp_after, NULL);
+       for (i = 0; i < children.size(); i++)
+               if (children[i])
+                       children[i]->wiggle();
+
+       time_factor = 1000000.0 * (stamp_after.tv_sec - stamp_before.tv_sec) + stamp_after.tv_usec - stamp_before.tv_usec;
+
+
+       for (i = 0; i < children.size(); i++)
+               if (children[i])
+                       children[i]->measurement_end();
+
+       for (i = 0; i < children.size(); i++)
+               if (children[i]) {
+                       for (j = 0; j < children[i]->cstates.size(); j++) {
+                               struct idle_state *state;
+                               state = children[i]->cstates[j];
+                               if (!state)
+                                       continue;
+
+                               update_cstate( state->linux_name, state->human_name, state->usage_before, state->duration_before, state->before_count);
+                               finalize_cstate(state->linux_name,                   state->usage_after,  state->duration_after,  state->after_count);
+                       }
+                       for (j = 0; j < children[i]->pstates.size(); j++) {
+                               struct frequency *state;
+                               state = children[i]->pstates[j];
+                               if (!state)
+                                       continue;
+
+                               update_pstate(  state->freq, state->human_name, state->time_before, state->before_count);
+                               finalize_pstate(state->freq,                    state->time_after,  state->after_count);
+                       }
+               }
+
+       for (i = 0; i < cstates.size(); i++) {
+               struct idle_state *state = cstates[i];
+
+               if (state->after_count == 0) {
+                       cout << "after count is 0 " << state->linux_name << "\n";
+                       continue;
+               }
+
+               if (state->after_count != state->before_count) {
+                       cout << "count mismatch " << state->after_count << " " << state->before_count << " on cpu " << number << "\n";
+                       continue;
+               }
+
+               state->usage_delta =    (state->usage_after    - state->usage_before)    / state->after_count;
+               state->duration_delta = (state->duration_after - state->duration_before) / state->after_count;
+       }
+}
+
+void abstract_cpu::insert_cstate(const char *linux_name, const char *human_name, uint64_t usage, uint64_t duration, int count, int level)
+{
+       struct idle_state *state;
+       const char *c;
+
+       state = new(std::nothrow) struct idle_state;
+
+       if (!state)
+               return;
+
+       memset(state, 0, sizeof(*state));
+
+       cstates.push_back(state);
+
+       strcpy(state->linux_name, linux_name);
+       strcpy(state->human_name, human_name);
+
+       state->line_level = -1;
+       
+       c = human_name;
+       while (*c) {
+               if (strcmp(linux_name, "active")==0) {
+                       state->line_level = LEVEL_C0;
+                       break;
+               }
+               if (*c >= '0' && *c <='9') {
+                       state->line_level = strtoull(c, NULL, 10);
+                       break;
+               }
+               c++;
+       }
+
+       /* some architectures (ARM) don't have good numbers in their human name.. fall back to the linux name for those */
+       c = linux_name;
+       while (*c && state->line_level < 0) {
+               if (*c >= '0' && *c <='9') {
+                       state->line_level = strtoull(c, NULL, 10);
+                       break;
+               }
+               c++;
+       }
+       
+       if (level >= 0)
+               state->line_level = level;
+
+       state->usage_before = usage;
+       state->duration_before = duration;
+       state->before_count = count;
+}
+
+void abstract_cpu::finalize_cstate(const char *linux_name, uint64_t usage, uint64_t duration, int count)
+{
+       unsigned int i;
+       struct idle_state *state = NULL;
+
+       for (i = 0; i < cstates.size(); i++) {
+               if (strcmp(linux_name, cstates[i]->linux_name) == 0) {
+                       state = cstates[i];
+                       break;
+               }
+       }
+
+       if (!state) {
+               cout << "Invalid C state finalize " << linux_name << " \n";
+               return;
+       }
+
+       state->usage_after += usage;
+       state->duration_after += duration;
+       state->after_count += count;
+}
+
+void abstract_cpu::update_cstate(const char *linux_name, const char *human_name, uint64_t usage, uint64_t duration, int count, int level)
+{
+       unsigned int i;
+       struct idle_state *state = NULL;
+
+       for (i = 0; i < cstates.size(); i++) {
+               if (strcmp(linux_name, cstates[i]->linux_name) == 0) {
+                       state = cstates[i];
+                       break;
+               }
+       }
+
+       if (!state) {
+               insert_cstate(linux_name, human_name, usage, duration, count, level);
+               return;
+       }
+
+       state->usage_before += usage;
+       state->duration_before += duration;
+       state->before_count += count;
+
+}
+
+int abstract_cpu::has_cstate_level(int level)
+{
+       unsigned int i;
+
+       if (level == LEVEL_HEADER)
+               return 1;
+
+       for (i = 0; i < cstates.size(); i++)
+               if (cstates[i]->line_level == level)
+                       return 1;
+
+       for (i = 0; i < children.size(); i++)
+               if (children[i])
+                       if (children[i]->has_cstate_level(level))
+                               return 1;
+       return  0;
+}
+
+int abstract_cpu::has_pstate_level(int level)
+{
+       unsigned int i;
+
+       if (level == LEVEL_HEADER)
+               return 1;
+
+       if (level >= 0 && level < (int)pstates.size())
+               return 1;
+
+       for (i = 0; i < children.size(); i++)
+               if (children[i])
+                       if (children[i]->has_pstate_level(level))
+                               return 1;
+       return  0;
+}
+
+
+
+void abstract_cpu::insert_pstate(uint64_t freq, const char *human_name, uint64_t duration, int count)
+{
+       struct frequency *state;
+
+       state = new(std::nothrow) struct frequency;
+
+       if (!state)
+               return;
+
+       memset(state, 0, sizeof(*state));
+
+       pstates.push_back(state);
+
+       state->freq = freq;
+       strcpy(state->human_name, human_name);
+
+
+       state->time_before = duration;
+       state->before_count = count;
+}
+
+void abstract_cpu::finalize_pstate(uint64_t freq, uint64_t duration, int count)
+{
+       unsigned int i;
+       struct frequency *state = NULL;
+
+       for (i = 0; i < pstates.size(); i++) {
+               if (freq == pstates[i]->freq) {
+                       state = pstates[i];
+                       break;
+               }
+       }
+
+       if (!state) {
+               cout << "Invalid P state finalize " << freq << " \n";
+               return;
+       }
+       state->time_after += duration;
+       state->after_count += count;
+
+}
+
+void abstract_cpu::update_pstate(uint64_t freq, const char *human_name, uint64_t duration, int count)
+{
+       unsigned int i;
+       struct frequency *state = NULL;
+
+       for (i = 0; i < pstates.size(); i++) {
+               if (freq == pstates[i]->freq) {
+                       state = pstates[i];
+                       break;
+               }
+       }
+
+       if (!state) {
+               insert_pstate(freq, human_name, duration, count);
+               return;
+       }
+
+       state->time_before += duration;
+       state->before_count += count;
+}
+
+
+void abstract_cpu::calculate_freq(uint64_t time)
+{
+       uint64_t freq = 0;
+       bool is_idle = true;
+       unsigned int i;
+
+       /* calculate the maximum frequency of all children */
+       for (i = 0; i < children.size(); i++)
+               if (children[i] && children[i]->has_pstates()) {
+                       uint64_t f = 0;
+                       if (!children[i]->idle) {
+                               f = children[i]->current_frequency;
+                               is_idle = false;
+                       }
+                       if (f > freq)
+                               freq = f;
+               }
+
+       current_frequency = freq;
+       idle = is_idle;
+       if (parent)
+               parent->calculate_freq(time);
+       old_idle = idle;
+}
+
+void abstract_cpu::change_effective_frequency(uint64_t time, uint64_t frequency)
+{
+       unsigned int i;
+
+       /* propagate to all children */
+       for (i = 0; i < children.size(); i++)
+               if (children[i]) {
+                       children[i]->change_effective_frequency(time, frequency);
+               }
+
+       effective_frequency = frequency;
+}
+
+
+void abstract_cpu::wiggle(void)
+{
+       char filename[4096];
+       ifstream ifile;
+       ofstream ofile;
+       uint64_t minf,maxf;
+
+       /* wiggle a CPU so that we have a record of it at the start and end of the perf trace */
+
+       sprintf(filename, "/sys/devices/system/cpu/cpu%i/cpufreq/scaling_max_freq", first_cpu);
+       ifile.open(filename, ios::in);
+       ifile >> maxf;
+       ifile.close();
+
+       sprintf(filename, "/sys/devices/system/cpu/cpu%i/cpufreq/scaling_min_freq", first_cpu);
+       ifile.open(filename, ios::in);
+       ifile >> minf;
+       ifile.close();
+
+       ofile.open(filename, ios::out);
+       ofile << maxf;
+       ofile.close();
+       ofile.open(filename, ios::out);
+       ofile << minf;
+       ofile.close();
+       sprintf(filename, "/sys/devices/system/cpu/cpu%i/cpufreq/scaling_max_freq", first_cpu);
+       ofile.open(filename, ios::out);
+       ofile << minf;
+       ofile.close();
+       ofile.open(filename, ios::out);
+       ofile << maxf;
+       ofile.close();
+
+}
+uint64_t abstract_cpu::total_pstate_time(void)
+{
+       unsigned int i;
+       uint64_t stamp = 0;
+
+       for (i = 0; i < pstates.size(); i++)
+               stamp += pstates[i]->time_after;
+
+       return stamp;
+}
+
+
+void abstract_cpu::validate(void)
+{
+       unsigned int i;
+
+       for (i = 0; i < children.size(); i++) {
+               if (children[i])
+                       children[i]->validate();
+       }
+}
+
+void abstract_cpu::reset_pstate_data(void)
+{
+       unsigned int i;
+
+       for (i = 0; i < pstates.size(); i++) {
+               pstates[i]->time_before = 0;
+               pstates[i]->time_after = 0;
+       }
+       for (i = 0; i < cstates.size(); i++) {
+               cstates[i]->duration_before = 0;
+               cstates[i]->duration_after = 0;
+               cstates[i]->before_count = 0;
+               cstates[i]->after_count = 0;
+       }
+
+       for (i = 0; i < children.size(); i++)
+               if (children[i])
+                       children[i]->reset_pstate_data();
+}
diff --git a/src/cpu/cpu.cpp b/src/cpu/cpu.cpp
new file mode 100644 (file)
index 0000000..c692a6c
--- /dev/null
@@ -0,0 +1,852 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ *     Arjan van de Ven <arjan@linux.intel.com>
+ */
+#include <iostream>
+#include <fstream>
+#include <vector>
+#include <string.h>
+#include <stdlib.h>
+#include <ncurses.h>
+#include <unistd.h>
+#include "cpu.h"
+#include "cpudevice.h"
+#include "../parameters/parameters.h"
+
+#include "../perf/perf_bundle.h"
+#include "../lib.h"
+#include "../display.h"
+#include "../report/report.h"
+#include "../report/report-maker.h"
+
+static class abstract_cpu system_level;
+
+vector<class abstract_cpu *> all_cpus;
+
+static class perf_bundle * perf_events;
+
+
+
+class perf_power_bundle: public perf_bundle
+{
+       virtual void handle_trace_point(void *trace, int cpu, uint64_t time);
+
+};
+
+
+static class abstract_cpu * new_package(int package, int cpu, char * vendor, int family, int model)
+{
+       class abstract_cpu *ret = NULL;
+       class cpudevice *cpudev;
+       char packagename[128];
+       if (strcmp(vendor, "GenuineIntel") == 0) {
+               if (family == 6)
+                       switch (model) {
+                       case 0x1A:      /* Core i7, Xeon 5500 series */
+                       case 0x1E:      /* Core i7 and i5 Processor - Lynnfield Jasper Forest */
+                       case 0x1F:      /* Core i7 and i5 Processor - Nehalem */
+                       case 0x2E:      /* Nehalem-EX Xeon */
+                       case 0x2F:      /* Westmere-EX Xeon */
+                       case 0x25:      /* Westmere */
+                       case 0x2C:      /* Westmere */
+                               ret = new class nhm_package;
+                               break;
+                       case 0x2A:      /* SNB */
+                       case 0x2D:      /* SNB Xeon */
+                       case 0x3A:      /* IVB */
+                       case 0x3C:
+                       case 0x3D:      /* IVB Xeon */
+                               has_c2c7_res = 1;
+                               ret = new class nhm_package;
+                               break;
+                       case 0x27:      /* Atom single core */
+                               ret = new class atom_package;
+                               break;
+                       }
+       }
+
+       if (!ret)
+               ret = new class cpu_package;
+
+       ret->set_number(package, cpu);
+       ret->set_type("Package");
+       ret->childcount = 0;
+
+       sprintf(packagename, _("cpu package %i"), cpu);
+       cpudev = new class cpudevice(_("cpu package"), packagename, ret);
+       all_devices.push_back(cpudev);
+       return ret;
+}
+
+static class abstract_cpu * new_core(int core, int cpu, char * vendor, int family, int model)
+{
+       class abstract_cpu *ret = NULL;
+
+       if (strcmp(vendor, "GenuineIntel") == 0) {
+               if (family == 6)
+                       switch (model) {
+                       case 0x1A:      /* Core i7, Xeon 5500 series */
+                       case 0x1E:      /* Core i7 and i5 Processor - Lynnfield Jasper Forest */
+                       case 0x1F:      /* Core i7 and i5 Processor - Nehalem */
+                       case 0x2E:      /* Nehalem-EX Xeon */
+                       case 0x2F:      /* Westmere-EX Xeon */
+                       case 0x25:      /* Westmere */
+                       case 0x2C:      /* Westmere */
+                       case 0x2A:      /* SNB */
+                       case 0x2D:      /* SNB Xeon */
+                       case 0x3A:      /* IVB */
+                       case 0x3C:
+                       case 0x3D:      /* IVB Xeon */
+                               ret = new class nhm_core;
+                               break;
+                       case 0x27:      /* Atom single core */
+                               ret = new class atom_core;
+                               break;
+                       }
+       }
+
+       if (!ret)
+               ret = new class cpu_core;
+       ret->set_number(core, cpu);
+       ret->childcount = 0;
+       ret->set_type("Core");
+
+       return ret;
+}
+
+static class abstract_cpu * new_i965_gpu(void)
+{
+       class abstract_cpu *ret = NULL;
+
+       ret = new class i965_core;
+       ret->childcount = 0;
+       ret->set_type("GPU");
+
+       return ret;
+}
+
+static class abstract_cpu * new_cpu(int number, char * vendor, int family, int model)
+{
+       class abstract_cpu * ret = NULL;
+
+       if (strcmp(vendor, "GenuineIntel") == 0) {
+               if (family == 6)
+                       switch (model) {
+                       case 0x1A:      /* Core i7, Xeon 5500 series */
+                       case 0x1E:      /* Core i7 and i5 Processor - Lynnfield Jasper Forest */
+                       case 0x1F:      /* Core i7 and i5 Processor - Nehalem */
+                       case 0x2E:      /* Nehalem-EX Xeon */
+                       case 0x2F:      /* Westmere-EX Xeon */
+                       case 0x25:      /* Westmere */
+                       case 0x2C:      /* Westmere */
+                       case 0x2A:      /* SNB */
+                       case 0x2D:      /* SNB Xeon */
+                       case 0x3A:      /* IVB */
+                       case 0x3C:
+                       case 0x3D:      /* IVB Xeon */
+                               ret = new class nhm_cpu;
+                               break;
+                       case 0x27:      /* Atom single core */
+                               ret = new class atom_cpu;
+                               break;
+                       }
+       }
+
+       if (!ret)
+               ret = new class cpu_linux;
+       ret->set_number(number, number);
+       ret->set_type("CPU");
+       ret->childcount = 0;
+
+       return ret;
+}
+
+
+
+
+static void handle_one_cpu(unsigned int number, char *vendor, int family, int model)
+{
+       char filename[1024];
+       ifstream file;
+       unsigned int package_number = 0;
+       unsigned int core_number = 0;
+       class abstract_cpu *package, *core, *cpu;
+
+       sprintf(filename, "/sys/devices/system/cpu/cpu%i/topology/core_id", number);
+       file.open(filename, ios::in);
+       if (file) {
+               file >> core_number;
+               file.close();
+       }
+
+       sprintf(filename, "/sys/devices/system/cpu/cpu%i/topology/physical_package_id", number);
+       file.open(filename, ios::in);
+       if (file) {
+               file >> package_number;
+               if (package_number == (unsigned int) -1)
+                       package_number = 0;
+               file.close();
+       }
+
+
+       if (system_level.children.size() <= package_number)
+               system_level.children.resize(package_number + 1, NULL);
+
+       if (!system_level.children[package_number]) {
+               system_level.children[package_number] = new_package(package_number, number, vendor, family, model);
+               system_level.childcount++;
+       }
+
+       package = system_level.children[package_number];
+       package->parent = &system_level;
+
+       if (package->children.size() <= core_number)
+               package->children.resize(core_number + 1, NULL);
+
+       if (!package->children[core_number]) {
+               package->children[core_number] = new_core(core_number, number, vendor, family, model);
+               package->childcount++;
+       }
+
+       core = package->children[core_number];
+       core->parent = package;
+
+       if (core->children.size() <= number)
+               core->children.resize(number + 1, NULL);
+       if (!core->children[number]) {
+               core->children[number] = new_cpu(number, vendor, family, model);
+               core->childcount++;
+       }
+
+       cpu = core->children[number];
+       cpu->parent = core;
+
+       if (number >= all_cpus.size())
+               all_cpus.resize(number + 1, NULL);
+       all_cpus[number] = cpu;
+}
+
+static void handle_i965_gpu(void)
+{
+       unsigned int core_number = 0;
+       class abstract_cpu *package;
+
+
+       package = system_level.children[0];
+
+       core_number = package->children.size();
+
+       if (package->children.size() <= core_number)
+               package->children.resize(core_number + 1, NULL);
+
+       if (!package->children[core_number]) {
+               package->children[core_number] = new_i965_gpu();
+               package->childcount++;
+       }
+}
+
+
+void enumerate_cpus(void)
+{
+       ifstream file;
+       char line[1024];
+
+       int number = -1;
+       char vendor[128];
+       int family = 0;
+       int model = 0;
+
+       file.open("/proc/cpuinfo",  ios::in);
+
+       if (!file)
+               return;
+       /* Not all /proc/cpuinfo include "vendor_id\t". */
+       vendor[0] = '\0';
+
+       while (file) {
+
+               file.getline(line, sizeof(line));
+               if (strncmp(line, "vendor_id\t",10) == 0) {
+                       char *c;
+                       c = strchr(line, ':');
+                       if (c) {
+                               c++;
+                               if (*c == ' ')
+                                       c++;
+                               strncpy(vendor,c, 127);
+                       }
+               }
+               if (strncmp(line, "processor\t",10) == 0) {
+                       char *c;
+                       c = strchr(line, ':');
+                       if (c) {
+                               c++;
+                               number = strtoull(c, NULL, 10);
+                       }
+               }
+               if (strncmp(line, "cpu family\t",11) == 0) {
+                       char *c;
+                       c = strchr(line, ':');
+                       if (c) {
+                               c++;
+                               family = strtoull(c, NULL, 10);
+                       }
+               }
+               if (strncmp(line, "model\t",6) == 0) {
+                       char *c;
+                       c = strchr(line, ':');
+                       if (c) {
+                               c++;
+                               model = strtoull(c, NULL, 10);
+                       }
+               }
+               if (strncasecmp(line, "bogomips\t", 9) == 0) {
+                       if (number == -1) {
+                               /* Not all /proc/cpuinfo include "processor\t". */
+                               number = 0;
+                       }
+                       if (number >= 0) {
+                               handle_one_cpu(number, vendor, family, model);
+                               set_max_cpu(number);
+                               number = -2;
+                       }
+               }
+       }
+
+
+       file.close();
+
+       if (access("/sys/class/drm/card0/power/rc6_residency_ms", R_OK) == 0)
+               handle_i965_gpu();
+
+       perf_events = new perf_power_bundle();
+
+       if (!perf_events->add_event("power:cpu_idle")){
+               perf_events->add_event("power:power_start");
+               perf_events->add_event("power:power_end");
+       }
+       if (!perf_events->add_event("power:cpu_frequency"))
+               perf_events->add_event("power:power_frequency");
+
+}
+
+void start_cpu_measurement(void)
+{
+       perf_events->start();
+       system_level.measurement_start();
+}
+
+void end_cpu_measurement(void)
+{
+       system_level.measurement_end();
+       perf_events->stop();
+}
+
+static void expand_string(char *string, unsigned int newlen)
+{
+       while (strlen(string) < newlen)
+               strcat(string, " ");
+}
+
+static int has_state_level(class abstract_cpu *acpu, int state, int line)
+{
+       switch (state) {
+               case PSTATE:
+                       return acpu->has_pstate_level(line);
+                       break;
+               case CSTATE:
+                       return acpu->has_cstate_level(line);
+                       break;
+       }
+       return 0;
+}
+
+static const char * fill_state_name(class abstract_cpu *acpu, int state, int line, char *buf)
+{
+       switch (state) {
+               case PSTATE:
+                       return acpu->fill_pstate_name(line, buf);
+                       break;
+               case CSTATE:
+                       return acpu->fill_cstate_name(line, buf);
+                       break;
+       }
+       return "-EINVAL";
+}
+
+static const char * fill_state_line(class abstract_cpu *acpu, int state, int line,
+                                       char *buf, const char *sep = "")
+{
+       switch (state) {
+               case PSTATE:
+                       return acpu->fill_pstate_line(line, buf);
+                       break;
+               case CSTATE:
+                       return acpu->fill_cstate_line(line, buf, sep);
+                       break;
+       }
+       return "-EINVAL";
+}
+
+void report_display_cpu_cstates(void)
+{
+       char buffer[512], buffer2[512];
+       unsigned int package, core, cpu;
+       int line;
+       class abstract_cpu *_package, * _core, * _cpu;
+
+       report.begin_section(SECTION_CPUIDLE);
+       report.add_header("Processor Idle state report");
+
+       for (package = 0; package < system_level.children.size(); package++) {
+               bool first_core = true;
+
+               _package = system_level.children[package];
+               if (!_package)
+                       continue;
+
+               report.begin_table(TABLE_WIDE);
+               for (core = 0; core < _package->children.size(); core++) {
+                       _core = _package->children[core];
+                       if (!_core)
+                               continue;
+
+                       for (line = LEVEL_HEADER; line < STATES_LIMIT; line++) {
+                               bool first_cpu = true;
+
+                               if (!_package->has_cstate_level(line))
+                                       continue;
+
+                               report.begin_row();
+                               buffer[0] = 0;
+                               buffer2[0] = 0;
+
+                               if (line == LEVEL_HEADER) {
+                                       if (first_core) {
+                                               report.begin_cell(CELL_FIRST_PACKAGE_HEADER);
+                                               report.addf(__("Package %i"), _package->get_number());
+                                       } else {
+                                               report.begin_cell(CELL_EMPTY_PACKAGE_HEADER);
+                                               report.add_empty_cell();
+                                       }
+                               } else if (first_core) {
+                                       report.begin_cell(CELL_STATE_NAME);
+                                       report.add(_package->fill_cstate_name(line, buffer));
+                                       report.begin_cell(CELL_PACKAGE_STATE_VALUE);
+                                       report.add(_package->fill_cstate_line(line, buffer2));
+                               } else {
+                                       report.begin_cell(CELL_EMPTY_PACKAGE_STATE);
+                                       report.add_empty_cell();
+                               }
+
+                               report.begin_cell(CELL_SEPARATOR);
+                               report.add_empty_cell();
+
+                               if (!_core->can_collapse()) {
+                                       buffer[0] = 0;
+                                       buffer2[0] = 0;
+
+                                       if (line == LEVEL_HEADER) {
+                                               report.begin_cell(CELL_CORE_HEADER);
+                                               /* Here we need to check for which core type we
+                                                * are using. Do not use the core type for the 
+                                                * report.addf as it breaks an important macro use 
+                                                * for translation decision making for the reports. 
+                                                  */
+                                               const char* core_type = _core->get_type(); 
+                                               if (core_type != NULL) {        
+                                                       if (strcmp(core_type, "Core") == 0 ) {
+                                                               report.addf(__("Core %i"), _core->get_number());
+                                                       } else {
+                                                               report.addf(__("GPU %i"), _core->get_number());
+                                                       } 
+                                               }
+                                       } else {
+                                                report.begin_cell(CELL_STATE_NAME);
+                                                report.add(_core->fill_cstate_name(line, buffer));
+                                               report.begin_cell(CELL_CORE_STATE_VALUE);
+                                               report.add(_core->fill_cstate_line(line, buffer2));
+                                       }
+                               }
+
+                               report.begin_cell(CELL_SEPARATOR);
+                               report.add_empty_cell();
+
+                               for (cpu = 0; cpu < _core->children.size(); cpu++) {
+                                       _cpu = _core->children[cpu];
+                                       if (!_cpu)
+                                               continue;
+
+                                       report.set_cpu_number(cpu);
+                                       if (line == LEVEL_HEADER) {
+                                               report.begin_cell(CELL_CPU_CSTATE_HEADER);
+                                               report.addf(__("CPU %i"), _cpu->get_number());
+                                               continue;
+                                       }
+
+                                       if (first_cpu) {
+                                               report.begin_cell(CELL_STATE_NAME);
+                                               report.add(_cpu->fill_cstate_name(line, buffer));
+                                               first_cpu = false;
+                                       }
+
+                                       buffer[0] = 0;
+                                       report.begin_cell(CELL_CPU_STATE_VALUE);
+                                       report.add(_cpu->fill_cstate_percentage(line, buffer));
+                                       report.begin_cell(CELL_CPU_STATE_VALUE);
+                                       if (line != LEVEL_C0)
+                                               report.add(_cpu->fill_cstate_time(line, buffer));
+                                       else
+                                               report.add_empty_cell();
+                               }
+                       }
+
+                       first_core = false;
+               }
+       }
+}
+
+void report_display_cpu_pstates(void)
+{
+       char buffer[512], buffer2[512];
+       unsigned int package, core, cpu;
+       int line;
+       class abstract_cpu *_package, * _core, * _cpu;
+       unsigned int i, pstates_num;
+
+       for (i = 0, pstates_num = 0; i < all_cpus.size(); i++)
+               if (all_cpus[i] && all_cpus[i]->pstates.size() > pstates_num)
+                       pstates_num = all_cpus[i]->pstates.size();
+
+       report.begin_section(SECTION_CPUFREQ);
+       report.add_header("Processor Frequency Report");
+
+       for (package = 0; package < system_level.children.size(); package++) {
+               bool first_core = true;
+
+               _package = system_level.children[package];
+               if (!_package)
+                       continue;
+
+               report.begin_table(TABLE_WIDE);
+               for (core = 0; core < _package->children.size(); core++) {
+                       _core = _package->children[core];
+                       if (!_core)
+                               continue;
+
+                       if (!_core->has_pstates())
+                               continue;
+
+                       for (line = LEVEL_HEADER; line < (int)pstates_num; line++) {
+                               bool first_cpu = true;
+
+                               if (!_package->has_pstate_level(line))
+                                       continue;
+
+                               report.begin_row();
+
+                               buffer[0] = 0;
+                               buffer2[0] = 0;
+                               if (first_core) {
+                                       if (line == LEVEL_HEADER) {
+                                               report.begin_cell(CELL_FIRST_PACKAGE_HEADER);
+                                               report.addf(__("Package %i"), _package->get_number());
+                                       } else {
+                                               report.begin_cell(CELL_STATE_NAME);
+                                               report.add(_package->fill_pstate_name(line, buffer));
+                                               report.begin_cell(CELL_PACKAGE_STATE_VALUE);
+                                               report.add(_package->fill_pstate_line(line, buffer2));
+                                       }
+                               } else {
+                                       report.begin_cell(CELL_EMPTY_PACKAGE_STATE);
+                                       report.add_empty_cell();
+                               }
+
+                               report.begin_cell(CELL_SEPARATOR);
+                               report.add_empty_cell();
+
+                               if (!_core->can_collapse()) {
+                                       buffer[0] = 0;
+                                       buffer2[0] = 0;
+                                       if (line == LEVEL_HEADER) {
+                                               report.begin_cell(CELL_CORE_HEADER);
+                                               report.addf(__("Core %i"), _core->get_number());
+                                       } else {
+                                               report.begin_cell(CELL_STATE_NAME);
+                                               report.add(_core->fill_pstate_name(line, buffer));
+                                               report.begin_cell(CELL_PACKAGE_STATE_VALUE);
+                                               report.add(_core->fill_pstate_line(line, buffer2));
+                                       }
+                               }
+
+                               report.begin_cell(CELL_SEPARATOR);
+                               report.add_empty_cell();
+
+                               for (cpu = 0; cpu < _core->children.size(); cpu++) {
+                                       buffer[0] = 0;
+                                       _cpu = _core->children[cpu];
+                                       if (!_cpu)
+                                               continue;
+
+                                       report.set_cpu_number(cpu);
+                                       if (line == LEVEL_HEADER) {
+                                               report.begin_cell(CELL_CPU_PSTATE_HEADER);
+                                               report.addf(__("CPU %i"), _cpu->get_number());
+                                               continue;
+                                       }
+
+                                       if (first_cpu) {
+                                               report.begin_cell(CELL_STATE_NAME);
+                                               report.add(_cpu->fill_pstate_name(line, buffer));
+                                               first_cpu = false;
+                                       }
+
+                                       buffer[0] = 0;
+                                       report.begin_cell(CELL_CPU_STATE_VALUE);
+                                       report.add(_cpu->fill_pstate_line(line, buffer));
+                               }
+                       }
+
+                       first_core = false;
+               }
+       }
+}
+
+void impl_w_display_cpu_states(int state)
+{
+       WINDOW *win;
+       char buffer[128];
+       char linebuf[1024];
+       unsigned int package, core, cpu;
+       int line;
+       class abstract_cpu *_package, * _core, * _cpu;
+       int ctr = 0;
+
+       if (state == PSTATE)
+               win = get_ncurses_win("Frequency stats");
+       else
+               win = get_ncurses_win("Idle stats");
+
+       if (!win)
+               return;
+
+       wclear(win);
+        wmove(win, 2,0);
+
+       for (package = 0; package < system_level.children.size(); package++) {
+               int first_pkg = 0;
+               _package = system_level.children[package];
+               if (!_package)
+                       continue;
+
+               for (core = 0; core < _package->children.size(); core++) {
+                       _core = _package->children[core];
+                       if (!_core)
+                               continue;
+                       if (!_core->has_pstates() && state == PSTATE)
+                               continue;
+
+
+                       for (line = LEVEL_HEADER; line < STATES_LIMIT; line++) {
+                               int first = 1;
+                               ctr = 0;
+                               linebuf[0] = 0;
+
+                               if (!has_state_level(_package, state, line))
+                                       continue;
+
+                               buffer[0] = 0;
+                               if (first_pkg == 0) {
+                                       strcat(linebuf, fill_state_name(_package, state, line, buffer));
+                                       expand_string(linebuf, ctr + 10);
+                                       strcat(linebuf, fill_state_line(_package, state, line, buffer));
+                               }
+                               ctr += 20;
+                               expand_string(linebuf, ctr);
+
+                               strcat(linebuf, "| ");
+                               ctr += strlen("| ");
+
+                               if (!_core->can_collapse()) {
+                                       buffer[0] = 0;
+                                       strcat(linebuf, fill_state_name(_core, state, line, buffer));
+                                       expand_string(linebuf, ctr + 10);
+                                       strcat(linebuf, fill_state_line(_core, state, line, buffer));
+                                       ctr += 20;
+                                       expand_string(linebuf, ctr);
+
+                                       strcat(linebuf, "| ");
+                                       ctr += strlen("| ");
+                               }
+
+                               for (cpu = 0; cpu < _core->children.size(); cpu++) {
+                                       _cpu = _core->children[cpu];
+                                       if (!_cpu)
+                                               continue;
+
+                                       if (first == 1) {
+                                               strcat(linebuf, fill_state_name(_cpu, state, line, buffer));
+                                               expand_string(linebuf, ctr + 10);
+                                               first = 0;
+                                               ctr += 12;
+                                       }
+                                       buffer[0] = 0;
+                                       strcat(linebuf, fill_state_line(_cpu, state, line, buffer));
+                                       ctr += 10;
+                                       expand_string(linebuf, ctr);
+
+                               }
+                               strcat(linebuf, "\n");
+                               wprintw(win, "%s", linebuf);
+                       }
+                       wprintw(win, "\n");
+                       first_pkg++;
+               }
+       }
+}
+
+void w_display_cpu_pstates(void)
+{
+       impl_w_display_cpu_states(PSTATE);
+}
+
+void w_display_cpu_cstates(void)
+{
+       impl_w_display_cpu_states(CSTATE);
+}
+
+struct power_entry {
+#ifndef __i386__
+       int dummy;
+#endif
+       int64_t type;
+       int64_t value;
+} __attribute__((packed));
+
+
+void perf_power_bundle::handle_trace_point(void *trace, int cpunr, uint64_t time)
+{
+       struct event_format *event;
+        struct pevent_record rec; /* holder */
+       class abstract_cpu *cpu;
+       int type;
+
+       rec.data = trace;
+
+       type = pevent_data_type(perf_event::pevent, &rec);
+       event = pevent_find_event(perf_event::pevent, type);
+
+       if (!event)
+               return;
+
+       if (cpunr >= (int)all_cpus.size()) {
+               cout << "INVALID cpu nr in handle_trace_point\n";
+               return;
+       }
+
+       cpu = all_cpus[cpunr];
+
+#if 0
+       unsigned int i;
+       printf("Time is %llu \n", time);
+       for (i = 0; i < system_level.children.size(); i++)
+               if (system_level.children[i])
+                       system_level.children[i]->validate();
+#endif
+       unsigned long long val;
+       int ret;
+       if (strcmp(event->name, "cpu_idle")==0) {
+
+               ret = pevent_get_field_val(NULL, event, "state", &rec, &val, 0);
+                if (ret < 0) {
+                        fprintf(stderr, _("cpu_idle event returned no state?\n"));
+                        exit(-1);
+                }
+
+               if (val == 4294967295)
+                       cpu->go_unidle(time);
+               else
+                       cpu->go_idle(time);
+       }
+
+       if (strcmp(event->name, "power_frequency") == 0
+       || strcmp(event->name, "cpu_frequency") == 0){
+
+               ret = pevent_get_field_val(NULL, event, "state", &rec, &val, 0);
+               if (ret < 0) {
+                       fprintf(stderr, _("power or cpu_frequecny event returned no state?\n"));
+                       exit(-1);
+               }
+
+               cpu->change_freq(time, val);
+       }
+
+       if (strcmp(event->name, "power_start")==0)
+               cpu->go_idle(time);
+       if (strcmp(event->name, "power_end")==0)
+               cpu->go_unidle(time);
+
+#if 0
+       unsigned int i;
+       for (i = 0; i < system_level.children.size(); i++)
+               if (system_level.children[i])
+                       system_level.children[i]->validate();
+#endif
+}
+
+void process_cpu_data(void)
+{
+       unsigned int i;
+       system_level.reset_pstate_data();
+
+       perf_events->process();
+
+       for (i = 0; i < system_level.children.size(); i++)
+               if (system_level.children[i])
+                       system_level.children[i]->validate();
+
+}
+
+void end_cpu_data(void)
+{
+       system_level.reset_pstate_data();
+
+       perf_events->clear();
+}
+
+void clear_cpu_data(void)
+{
+       if (perf_events)
+               perf_events->release();
+       delete perf_events;
+}
+
+
+void clear_all_cpus(void)
+{
+       unsigned int i;
+       for (i = 0; i < all_cpus.size(); i++) {
+               delete all_cpus[i];
+       }
+       all_cpus.clear();
+}
diff --git a/src/cpu/cpu.h b/src/cpu/cpu.h
new file mode 100644 (file)
index 0000000..6dd84f4
--- /dev/null
@@ -0,0 +1,245 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ *     Arjan van de Ven <arjan@linux.intel.com>
+ */
+
+#ifndef __INCLUDE_GUARD_CPUDEV_H
+#define __INCLUDE_GUARD_CPUDEV_H
+
+#include <iostream>
+#include <vector>
+#include <string>
+#include <stdint.h>
+#include <sys/time.h>
+
+using namespace std;
+
+class abstract_cpu;
+
+#define LEVEL_C0 -1
+#define LEVEL_HEADER -2
+
+#define PSTATE 1
+#define CSTATE 2
+#define STATES_LIMIT   20
+
+struct idle_state {
+       char linux_name[16]; /* state0 etc.. cpuidle name */
+       char human_name[32];
+
+       uint64_t usage_before;
+       uint64_t usage_after;
+       uint64_t usage_delta;
+
+       uint64_t duration_before;
+       uint64_t duration_after;
+       uint64_t duration_delta;
+
+       int before_count;
+       int after_count;
+
+       int line_level;
+};
+
+struct frequency {
+       char human_name[32];
+       int line_level;
+
+       uint64_t freq;
+
+       uint64_t time_after;
+       uint64_t time_before;
+
+       int before_count;
+       int after_count;
+
+       double   display_value;
+};
+
+class abstract_cpu
+{
+protected:
+       int     first_cpu;
+       struct timeval  stamp_before, stamp_after;
+       double  time_factor;
+       uint64_t max_frequency;
+       uint64_t max_minus_one_frequency;
+public:
+       uint64_t        last_stamp;
+       uint64_t        total_stamp;
+       int     number;
+       int     childcount;
+       const char*    name;
+       bool    idle, old_idle;
+       uint64_t        current_frequency;
+       uint64_t        effective_frequency;
+
+       vector<class abstract_cpu *> children;
+       vector<struct idle_state *> cstates;
+       vector<struct frequency *> pstates;
+
+       virtual ~abstract_cpu() {};
+
+       class abstract_cpu *parent;
+
+
+       void    set_number(int _number, int cpu) {this->number = _number; this->first_cpu = cpu;};
+       void    set_type(const char* _name) {this->name = _name;};
+       int     get_number(void) { return number; };
+       const char* get_type(void) { return name; };
+
+       virtual void    measurement_start(void);
+       virtual void    measurement_end(void);
+
+       virtual int     can_collapse(void) { return 0;};
+
+
+       /* C state related methods */
+
+       void            insert_cstate(const char *linux_name, const char *human_name, uint64_t usage, uint64_t duration, int count, int level = -1);
+       void            update_cstate(const char *linux_name, const char *human_name, uint64_t usage, uint64_t duration, int count, int level = -1);
+       void            finalize_cstate(const char *linux_name, uint64_t usage, uint64_t duration, int count);
+
+       virtual int     has_cstate_level(int level);
+
+       virtual char *  fill_cstate_line(int line_nr, char *buffer, const char *separator="") { return buffer;};
+       virtual char *  fill_cstate_percentage(int line_nr, char *buffer) { return buffer; };
+       virtual char *  fill_cstate_time(int line_nr, char *buffer) { return buffer; };
+       virtual char *  fill_cstate_name(int line_nr, char *buffer) { return buffer;};
+
+
+       /* P state related methods */
+       void            insert_pstate(uint64_t freq, const char *human_name, uint64_t duration, int count);
+       void            update_pstate(uint64_t freq, const char *human_name, uint64_t duration, int count);
+       void            finalize_pstate(uint64_t freq, uint64_t duration, int count);
+
+
+       virtual char *  fill_pstate_line(int line_nr, char *buffer) { return buffer;};
+       virtual char *  fill_pstate_name(int line_nr, char *buffer) { return buffer;};
+       virtual int     has_pstate_level(int level);
+       virtual int     has_pstates(void) { return 1; };
+
+       /* Frequency micro accounting methods */
+       virtual void    calculate_freq(uint64_t time);
+       virtual void    go_idle(uint64_t time) { idle = true; if (parent) parent->calculate_freq(time);};
+       virtual void    go_unidle(uint64_t time) { idle = false; if (parent) parent->calculate_freq(time);};;
+       virtual void    change_freq(uint64_t time, int freq) { current_frequency = freq; if (parent) parent->calculate_freq(time);};
+
+       virtual void    change_effective_frequency(uint64_t time, uint64_t freq);
+
+       virtual void    wiggle(void);
+
+       virtual uint64_t total_pstate_time(void);
+
+       virtual void validate(void);
+       virtual void reset_pstate_data(void);
+};
+
+extern vector<class abstract_cpu *> all_cpus;
+
+class cpu_linux: public abstract_cpu
+{
+
+       void    account_freq(uint64_t frequency, uint64_t duration);
+       void    parse_pstates_start(void);
+       void    parse_cstates_start(void);
+       void    parse_pstates_end(void);
+       void    parse_cstates_end(void);
+
+public:
+       virtual void    measurement_start(void);
+       virtual void    measurement_end(void);
+
+       virtual char *  fill_cstate_line(int line_nr, char *buffer, const char *separator="");
+       virtual char *  fill_cstate_name(int line_nr, char *buffer);
+       virtual char *  fill_cstate_percentage(int line_nr, char *buffer);
+       virtual char *  fill_cstate_time(int line_nr, char *buffer);
+
+       virtual char *  fill_pstate_line(int line_nr, char *buffer);
+       virtual char *  fill_pstate_name(int line_nr, char *buffer);
+
+       virtual void    change_freq(uint64_t time, int freq);
+       virtual void    change_effective_frequency(uint64_t time, uint64_t freq);
+       virtual void    go_idle(uint64_t time);
+       virtual void    go_unidle(uint64_t time);
+
+};
+
+class cpu_core: public abstract_cpu
+{
+       void            account_freq(uint64_t frequency, uint64_t duration);
+public:
+       virtual char *  fill_cstate_line(int line_nr, char *buffer, const char *separator="");
+       virtual char *  fill_cstate_name(int line_nr, char *buffer);
+
+       virtual char *  fill_pstate_line(int line_nr, char *buffer);
+       virtual char *  fill_pstate_name(int line_nr, char *buffer);
+
+       virtual int     can_collapse(void) { return childcount == 1;};
+       virtual void    calculate_freq(uint64_t time);
+       virtual void    change_effective_frequency(uint64_t time, uint64_t freq);
+};
+
+class cpu_package: public abstract_cpu
+{
+       void            account_freq(uint64_t frequency, uint64_t duration);
+public:
+       virtual char *  fill_cstate_line(int line_nr, char *buffer, const char *separator="");
+       virtual char *  fill_cstate_name(int line_nr, char *buffer);
+
+       virtual char *  fill_pstate_line(int line_nr, char *buffer);
+       virtual char *  fill_pstate_name(int line_nr, char *buffer);
+       virtual int     can_collapse(void) { return childcount == 1;};
+
+       virtual void    calculate_freq(uint64_t time);
+       virtual void    change_effective_frequency(uint64_t time, uint64_t freq);
+
+};
+
+#include "intel_cpus.h"
+
+extern void enumerate_cpus(void);
+
+extern void report_display_cpu_pstates(void);
+extern void report_display_cpu_cstates(void);
+
+
+
+extern void display_cpu_cstates(const char *start= "",
+                               const char *end = "",
+                               const char *linestart = "",
+                               const char *separator = "| ",
+                               const char *lineend = "\n");
+
+extern void w_display_cpu_cstates(void);
+extern void w_display_cpu_pstates(void);
+
+
+extern void start_cpu_measurement(void);
+extern void end_cpu_measurement(void);
+extern void process_cpu_data(void);
+extern void end_cpu_data(void);
+extern void clear_cpu_data(void);
+extern void clear_all_cpus(void);
+
+#endif
diff --git a/src/cpu/cpu_core.cpp b/src/cpu/cpu_core.cpp
new file mode 100644 (file)
index 0000000..2caa58d
--- /dev/null
@@ -0,0 +1,198 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ *     Arjan van de Ven <arjan@linux.intel.com>
+ */
+#include <stdio.h>
+#include "cpu.h"
+#include "../lib.h"
+
+#include "../parameters/parameters.h"
+
+static int is_turbo(uint64_t freq, uint64_t max, uint64_t maxmo)
+{
+       if (freq != max)
+               return 0;
+       if (maxmo + 1000 != max)
+               return 0;
+       return 1;
+}
+
+char * cpu_core::fill_cstate_line(int line_nr, char *buffer, const char *separator)
+{
+       unsigned int i;
+       buffer[0] = 0;
+
+       if (line_nr == LEVEL_HEADER) {
+               sprintf(buffer,_("  Core"));
+               return buffer;
+       }
+
+       for (i = 0; i < cstates.size(); i++) {
+               if (cstates[i]->line_level != line_nr)
+                       continue;
+               sprintf(buffer,"%5.1f%%", percentage(cstates[i]->duration_delta / time_factor));
+       }
+
+       return buffer;
+}
+
+
+char * cpu_core::fill_cstate_name(int line_nr, char *buffer)
+{
+       unsigned int i;
+       buffer[0] = 0;
+
+       for (i = 0; i < cstates.size(); i++) {
+               if (cstates[i]->line_level != line_nr)
+                       continue;
+
+               sprintf(buffer,"%s", cstates[i]->human_name);
+       }
+
+       return buffer;
+}
+
+
+
+char * cpu_core::fill_pstate_name(int line_nr, char *buffer)
+{
+       buffer[0] = 0;
+
+       if (line_nr >= (int)pstates.size() || line_nr < 0)
+               return buffer;
+
+       sprintf(buffer,"%s", pstates[line_nr]->human_name);
+
+       return buffer;
+}
+
+
+void cpu_core::account_freq(uint64_t freq, uint64_t duration)
+{
+       struct frequency *state = NULL;
+       unsigned int i;
+
+       for (i = 0; i < pstates.size(); i++) {
+               if (freq == pstates[i]->freq) {
+                       state = pstates[i];
+                       break;
+               }
+       }
+
+
+       if (!state) {
+               state = new(std::nothrow) struct frequency;
+
+               if (!state)
+                       return;
+
+               memset(state, 0, sizeof(*state));
+
+               pstates.push_back(state);
+
+               state->freq = freq;
+               hz_to_human(freq, state->human_name);
+               if (freq == 0)
+                       strcpy(state->human_name, _("Idle"));
+               if (is_turbo(freq, max_frequency, max_minus_one_frequency))
+                       sprintf(state->human_name, _("Turbo Mode"));
+
+               state->after_count = 1;
+       }
+
+
+       state->time_after += duration;
+}
+
+
+void cpu_core::calculate_freq(uint64_t time)
+{
+       uint64_t freq = 0;
+       bool is_idle = true;
+       unsigned int i;
+
+       /* calculate the maximum frequency of all children */
+       for (i = 0; i < children.size(); i++)
+               if (children[i] && children[i]->has_pstates()) {
+                       uint64_t f = 0;
+                       if (!children[i]->idle) {
+                               f = children[i]->current_frequency;
+                               is_idle = false;
+                       }
+                       if (f > freq)
+                               freq = f;
+               }
+
+       current_frequency = freq;
+       idle = is_idle;
+       if (parent)
+               parent->calculate_freq(time);
+       old_idle = idle;
+}
+
+void cpu_core::change_effective_frequency(uint64_t time, uint64_t frequency)
+{
+       uint64_t freq = 0;
+       uint64_t time_delta, fr;
+
+
+       if (last_stamp)
+               time_delta = time - last_stamp;
+       else
+               time_delta = 1;
+
+       fr = effective_frequency;
+
+       if (old_idle)
+               fr = 0;
+
+       account_freq(fr, time_delta);
+
+       effective_frequency = freq;
+       last_stamp = time;
+       abstract_cpu::change_effective_frequency(time, frequency);
+}
+
+char * cpu_core::fill_pstate_line(int line_nr, char *buffer)
+{
+       buffer[0] = 0;
+       unsigned int i;
+
+       if (total_stamp ==0) {
+               for (i = 0; i < pstates.size(); i++)
+                       total_stamp += pstates[i]->time_after;
+               if (total_stamp == 0)
+                       total_stamp = 1;
+       }
+
+       if (line_nr == LEVEL_HEADER) {
+               sprintf(buffer,_("  Core"));
+               return buffer;
+       }
+
+       if (line_nr >= (int)pstates.size() || line_nr < 0)
+               return buffer;
+
+       sprintf(buffer," %5.1f%% ", percentage(1.0* (pstates[line_nr]->time_after) / total_stamp));
+       return buffer;
+}
diff --git a/src/cpu/cpu_linux.cpp b/src/cpu/cpu_linux.cpp
new file mode 100644 (file)
index 0000000..e7a3d37
--- /dev/null
@@ -0,0 +1,446 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ *     Arjan van de Ven <arjan@linux.intel.com>
+ */
+#include <iostream>
+#include <fstream>
+
+#include "cpu.h"
+#include "../lib.h"
+
+#include <stdlib.h>
+
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+
+static int is_turbo(uint64_t freq, uint64_t max, uint64_t maxmo)
+{
+       if (freq != max)
+               return 0;
+       if (maxmo + 1000 != max)
+               return 0;
+       return 1;
+}
+
+void cpu_linux::parse_cstates_start(void)
+{
+       ifstream file;
+       DIR *dir;
+       struct dirent *entry;
+       char filename[256];
+       int len;
+
+       len = sprintf(filename, "/sys/devices/system/cpu/cpu%i/cpuidle", number);
+
+       dir = opendir(filename);
+       if (!dir)
+               return;
+
+       /* For each C-state, there is a stateX directory which
+        * contains a 'usage' and a 'time' (duration) file */
+       while ((entry = readdir(dir))) {
+               char linux_name[64];
+               char human_name[64];
+               uint64_t usage = 0;
+               uint64_t duration = 0;
+
+
+               if (strlen(entry->d_name) < 3)
+                       continue;
+
+               strcpy(linux_name, entry->d_name);
+               strcpy(human_name, linux_name);
+
+               sprintf(filename + len, "/%s/name", entry->d_name);
+
+               file.open(filename, ios::in);
+               if (file) {
+                       file.getline(human_name, 64);
+                       file.close();
+               }
+
+               if (strcmp(human_name, "C0")==0)
+                       strcpy(human_name, _("C0 polling"));
+
+               sprintf(filename + len, "/%s/usage", entry->d_name);
+               file.open(filename, ios::in);
+               if (file) {
+                       file >> usage;
+                       file.close();
+               }
+
+               sprintf(filename + len, "/%s/time", entry->d_name);
+
+               file.open(filename, ios::in);
+               if (file) {
+                       file >> duration;
+                       file.close();
+               }
+
+
+               update_cstate(linux_name, human_name, usage, duration, 1);
+
+       }
+       closedir(dir);
+}
+
+
+void cpu_linux::parse_pstates_start(void)
+{
+       ifstream file;
+       char filename[256];
+       unsigned int i;
+
+       last_stamp = 0;
+       for (i = 0; i < children.size(); i++)
+               if (children[i])
+                       children[i]->wiggle();
+
+       sprintf(filename, "/sys/devices/system/cpu/cpu%i/cpufreq/stats/time_in_state", first_cpu);
+
+       file.open(filename, ios::in);
+
+       if (file) {
+               char line[1024];
+
+               while (file) {
+                       uint64_t f;
+                       file.getline(line, 1024);
+                       f = strtoull(line, NULL, 10);
+                       account_freq(f, 0);
+               }
+               file.close();
+       }
+       account_freq(0, 0);
+}
+
+void cpu_linux::measurement_start(void)
+{
+       abstract_cpu::measurement_start();
+       parse_cstates_start();
+       parse_pstates_start();
+}
+
+void cpu_linux::parse_cstates_end(void)
+{
+       DIR *dir;
+       struct dirent *entry;
+       char filename[256];
+       ifstream file;
+       int len;
+
+       len = sprintf(filename, "/sys/devices/system/cpu/cpu%i/cpuidle", number);
+
+       dir = opendir(filename);
+       if (!dir)
+               return;
+
+       /* For each C-state, there is a stateX directory which
+        * contains a 'usage' and a 'time' (duration) file */
+       while ((entry = readdir(dir))) {
+               char linux_name[64];
+               char human_name[64];
+               uint64_t usage = 0;
+               uint64_t duration = 0;
+
+
+               if (strlen(entry->d_name) < 3)
+                       continue;
+
+               strcpy(linux_name, entry->d_name);
+               strcpy(human_name, linux_name);
+
+
+               sprintf(filename + len, "/%s/usage", entry->d_name);
+               file.open(filename, ios::in);
+               if (file) {
+                       file >> usage;
+                       file.close();
+               }
+
+               sprintf(filename + len, "/%s/time", entry->d_name);
+
+               file.open(filename, ios::in);
+               if (file) {
+                       file >> duration;
+                       file.close();
+               }
+
+
+               finalize_cstate(linux_name, usage, duration, 1);
+
+       }
+       closedir(dir);
+}
+
+void cpu_linux::parse_pstates_end(void)
+{
+       char filename[256];
+       ifstream file;
+
+       sprintf(filename, "/sys/devices/system/cpu/cpu%i/cpufreq/stats/time_in_state", number);
+
+       file.open(filename, ios::in);
+
+       if (file) {
+               char line[1024];
+
+               while (file) {
+                       uint64_t f,count;
+                       char *c;
+
+                       memset(line, 0, 1024);
+
+                       file.getline(line, 1024);
+
+                       f = strtoull(line, &c, 10);
+                       if (!c)
+                               break;
+
+                       count = strtoull(c, NULL, 10);
+
+                       if (f > 0)
+                               finalize_pstate(f, count, 1);
+
+
+               }
+               file.close();
+       }
+}
+
+void cpu_linux::measurement_end(void)
+{
+       parse_cstates_end();
+       parse_pstates_end();
+       abstract_cpu::measurement_end();
+}
+
+char * cpu_linux::fill_cstate_line(int line_nr, char *buffer, const char *separator)
+{
+       unsigned int i;
+       buffer[0] = 0;
+
+       if (line_nr == LEVEL_HEADER) {
+               sprintf(buffer,_(" CPU %i"), number);
+               return buffer;
+       }
+
+       for (i = 0; i < cstates.size(); i++) {
+               if (cstates[i]->line_level != line_nr)
+                       continue;
+
+               if (line_nr == LEVEL_C0)
+                       sprintf(buffer,"%5.1f%%", percentage(cstates[i]->duration_delta / time_factor));
+               else
+                       sprintf(buffer,"%5.1f%%%s %6.1f ms",
+                               percentage(cstates[i]->duration_delta / time_factor),
+                               separator,
+                               1.0 * cstates[i]->duration_delta / (1 + cstates[i]->usage_delta) / 1000);
+       }
+
+       return buffer;
+}
+
+char * cpu_linux::fill_cstate_percentage(int line_nr, char *buffer)
+{
+       unsigned int i;
+       buffer[0] = 0;
+
+       for (i = 0; i < cstates.size(); i++) {
+               if (cstates[i]->line_level != line_nr)
+                       continue;
+
+               sprintf(buffer,"%5.1f%%",
+                       percentage(cstates[i]->duration_delta / time_factor));
+               break;
+       }
+
+       return buffer;
+}
+
+char * cpu_linux::fill_cstate_time(int line_nr, char *buffer)
+{
+       unsigned int i;
+       buffer[0] = 0;
+
+       if (line_nr == LEVEL_C0)
+               return buffer;
+
+       for (i = 0; i < cstates.size(); i++) {
+               if (cstates[i]->line_level != line_nr)
+                       continue;
+
+               sprintf(buffer,"%6.1f ms",
+                       1.0 * cstates[i]->duration_delta /
+                       (1 + cstates[i]->usage_delta) / 1000);
+               break;
+       }
+
+       return buffer;
+}
+
+char * cpu_linux::fill_cstate_name(int line_nr, char *buffer)
+{
+       unsigned int i;
+       buffer[0] = 0;
+
+       for (i = 0; i < cstates.size(); i++) {
+               if (cstates[i]->line_level != line_nr)
+                       continue;
+
+               sprintf(buffer,"%s", cstates[i]->human_name);
+       }
+
+       return buffer;
+}
+
+
+char * cpu_linux::fill_pstate_name(int line_nr, char *buffer)
+{
+       buffer[0] = 0;
+
+       if (line_nr >= (int)pstates.size() || line_nr < 0)
+               return buffer;
+
+       sprintf(buffer,"%s", pstates[line_nr]->human_name);
+
+       return buffer;
+}
+
+char * cpu_linux::fill_pstate_line(int line_nr, char *buffer)
+{
+       buffer[0] = 0;
+
+       if (total_stamp ==0) {
+               unsigned int i;
+               for (i = 0; i < pstates.size(); i++)
+                       total_stamp += pstates[i]->time_after;
+               if (total_stamp == 0)
+                       total_stamp = 1;
+       }
+
+       if (line_nr == LEVEL_HEADER) {
+               sprintf(buffer,_(" CPU %i"), number);
+               return buffer;
+       }
+
+       if (line_nr >= (int)pstates.size() || line_nr < 0)
+               return buffer;
+
+       sprintf(buffer," %5.1f%% ", percentage(1.0* (pstates[line_nr]->time_after) / total_stamp));
+       return buffer;
+}
+
+
+
+
+void cpu_linux::account_freq(uint64_t freq, uint64_t duration)
+{
+       struct frequency *state = NULL;
+       unsigned int i;
+
+
+       for (i = 0; i < pstates.size(); i++) {
+               if (freq == pstates[i]->freq) {
+                       state = pstates[i];
+                       break;
+               }
+       }
+
+       if (!state) {
+               state = new(std::nothrow) struct frequency;
+
+               if (!state)
+                       return;
+
+               memset(state, 0, sizeof(*state));
+
+               pstates.push_back(state);
+
+               state->freq = freq;
+               hz_to_human(freq, state->human_name);
+               if (freq == 0)
+                       strcpy(state->human_name, _("Idle"));
+               if (is_turbo(freq, max_frequency, max_minus_one_frequency))
+                       sprintf(state->human_name, _("Turbo Mode"));
+
+               state->after_count = 1;
+       }
+
+
+       state->time_after += duration;
+
+
+}
+
+void cpu_linux::change_freq(uint64_t time, int frequency)
+{
+       current_frequency = frequency;
+
+       if (parent)
+               parent->calculate_freq(time);
+       old_idle = idle;
+}
+
+void cpu_linux::change_effective_frequency(uint64_t time, uint64_t frequency)
+{
+       uint64_t time_delta, fr;
+
+       if (last_stamp)
+               time_delta = time - last_stamp;
+       else
+               time_delta = 1;
+
+       fr = effective_frequency;
+       if (old_idle)
+               fr = 0;
+
+       account_freq(fr, time_delta);
+
+       effective_frequency = frequency;
+       last_stamp = time;
+}
+
+void cpu_linux::go_idle(uint64_t time)
+{
+
+       idle = true;
+
+       if (parent)
+               parent->calculate_freq(time);
+       old_idle = idle;
+}
+
+
+void cpu_linux::go_unidle(uint64_t time)
+{
+       idle = false;
+       if (parent)
+               parent->calculate_freq(time);
+       old_idle = idle;
+}
diff --git a/src/cpu/cpu_package.cpp b/src/cpu/cpu_package.cpp
new file mode 100644 (file)
index 0000000..b9d4c19
--- /dev/null
@@ -0,0 +1,200 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ *     Arjan van de Ven <arjan@linux.intel.com>
+ */
+#include <stdio.h>
+#include "cpu.h"
+#include "../lib.h"
+#include "../parameters/parameters.h"
+
+static int is_turbo(uint64_t freq, uint64_t max, uint64_t maxmo)
+{
+       if (freq != max)
+               return 0;
+       if (maxmo + 1000 != max)
+               return 0;
+       return 1;
+}
+
+
+char * cpu_package::fill_cstate_line(int line_nr, char *buffer, const char *separator)
+{
+       unsigned int i;
+       buffer[0] = 0;
+
+       if (line_nr == LEVEL_HEADER) {
+               sprintf(buffer,_("Package"));
+               return buffer;
+       }
+
+       for (i = 0; i < cstates.size(); i++) {
+               if (cstates[i]->line_level != line_nr)
+                       continue;
+
+               sprintf(buffer,"%5.1f%%", percentage(cstates[i]->duration_delta / time_factor));
+       }
+
+       return buffer;
+}
+
+
+char * cpu_package::fill_cstate_name(int line_nr, char *buffer)
+{
+       unsigned int i;
+       buffer[0] = 0;
+
+       for (i = 0; i < cstates.size(); i++) {
+               if (cstates[i]->line_level != line_nr)
+                       continue;
+
+               sprintf(buffer,"%s", cstates[i]->human_name);
+       }
+
+       return buffer;
+}
+
+
+
+char * cpu_package::fill_pstate_name(int line_nr, char *buffer)
+{
+       buffer[0] = 0;
+
+       if (line_nr >= (int)pstates.size() || line_nr < 0)
+               return buffer;
+
+       sprintf(buffer,"%s", pstates[line_nr]->human_name);
+
+       return buffer;
+}
+
+char * cpu_package::fill_pstate_line(int line_nr, char *buffer)
+{
+       buffer[0] = 0;
+       unsigned int i;
+
+       if (total_stamp ==0) {
+               for (i = 0; i < pstates.size(); i++)
+                       total_stamp += pstates[i]->time_after;
+               if (total_stamp == 0)
+                       total_stamp = 1;
+       }
+
+
+       if (line_nr == LEVEL_HEADER) {
+               sprintf(buffer,_("  Package"));
+               return buffer;
+       }
+
+       if (line_nr >= (int)pstates.size() || line_nr < 0)
+               return buffer;
+
+       sprintf(buffer," %5.1f%% ", percentage(1.0* (pstates[line_nr]->time_after) / total_stamp));
+       return buffer;
+}
+
+
+
+
+void cpu_package::account_freq(uint64_t freq, uint64_t duration)
+{
+       struct frequency *state = NULL;
+       unsigned int i;
+
+       for (i = 0; i < pstates.size(); i++) {
+               if (freq == pstates[i]->freq) {
+                       state = pstates[i];
+                       break;
+               }
+       }
+
+
+       if (!state) {
+               state = new(std::nothrow) struct frequency;
+
+               if (!state)
+                       return;
+
+               memset(state, 0, sizeof(*state));
+
+               pstates.push_back(state);
+
+               state->freq = freq;
+               hz_to_human(freq, state->human_name);
+               if (freq == 0)
+                       strcpy(state->human_name, _("Idle"));
+               if (is_turbo(freq, max_frequency, max_minus_one_frequency))
+                       sprintf(state->human_name, _("Turbo Mode"));
+               state->after_count = 1;
+       }
+
+       state->time_after += duration;
+
+}
+
+
+void cpu_package::calculate_freq(uint64_t time)
+{
+       uint64_t freq = 0;
+       bool is_idle = true;
+       unsigned int i;
+
+       /* calculate the maximum frequency of all children */
+       for (i = 0; i < children.size(); i++)
+               if (children[i] && children[i]->has_pstates()) {
+                       uint64_t f = 0;
+                       if (!children[i]->idle) {
+                               f = children[i]->current_frequency;
+                               is_idle = false;
+                       }
+                       if (f > freq)
+                               freq = f;
+               }
+
+       current_frequency = freq;
+       idle = is_idle;
+       if (parent)
+               parent->calculate_freq(time);
+       change_effective_frequency(time, current_frequency);
+       old_idle = idle;
+}
+
+void cpu_package::change_effective_frequency(uint64_t time, uint64_t frequency)
+{
+       uint64_t time_delta, fr;
+
+       if (last_stamp)
+               time_delta = time - last_stamp;
+       else
+               time_delta = 1;
+
+       fr = effective_frequency;
+       if (old_idle)
+               fr = 0;
+
+       account_freq(fr, time_delta);
+
+       effective_frequency = frequency;
+       last_stamp = time;
+
+       abstract_cpu::change_effective_frequency(time, frequency);
+}
diff --git a/src/cpu/cpudevice.cpp b/src/cpu/cpudevice.cpp
new file mode 100644 (file)
index 0000000..48fbcf5
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ *     Arjan van de Ven <arjan@linux.intel.com>
+ */
+#include "cpudevice.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "../parameters/parameters.h"
+
+
+cpudevice::cpudevice(const char *classname, const char *dev_name, class abstract_cpu *_cpu)
+{
+       strcpy(_class, classname);
+       strcpy(_cpuname, dev_name);
+       cpu = _cpu;
+       wake_index = get_param_index("cpu-wakeups");;
+       consumption_index = get_param_index("cpu-consumption");;
+       r_wake_index = get_result_index("cpu-wakeups");;
+       r_consumption_index = get_result_index("cpu-consumption");;
+}
+
+
+double cpudevice::power_usage(struct result_bundle *result, struct parameter_bundle *bundle)
+{
+       double power;
+       double factor;
+       double _utilization;
+
+       power = 0;
+       factor = get_parameter_value(wake_index, bundle);
+       _utilization = get_result_value(r_wake_index, result);
+
+       power += _utilization * factor / 10000.0;
+
+       factor = get_parameter_value(consumption_index, bundle);
+       _utilization = get_result_value(r_consumption_index, result);
+
+       power += _utilization * factor;
+
+       return power;
+}
+
+double cpudevice::utilization(void)
+{
+       double _utilization;
+       _utilization = get_result_value(r_consumption_index);
+
+       return _utilization * 100;
+
+}
diff --git a/src/cpu/cpudevice.h b/src/cpu/cpudevice.h
new file mode 100644 (file)
index 0000000..6a5636f
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ *     Arjan van de Ven <arjan@linux.intel.com>
+ */
+#ifndef _INCLUDE_GUARD_CPUDEVICE_H
+#define _INCLUDE_GUARD_CPUDEVICE_H
+
+#include <vector>
+#include <string>
+
+using namespace std;
+
+#include "../devices/device.h"
+#include "cpu.h"
+
+class cpudevice: public device {
+       char _class[128];
+       char _cpuname[128];
+
+       vector<string> params;
+       class abstract_cpu *cpu;
+       int wake_index;
+       int consumption_index;
+       int r_wake_index;
+       int r_consumption_index;
+
+public:
+       cpudevice(const char *classname = "cpu", const char *device_name = "cpu0", class abstract_cpu *_cpu = NULL);
+       virtual const char * class_name(void) { return _class;};
+
+       virtual const char * device_name(void) {return "CPU use";};
+
+       virtual double power_usage(struct result_bundle *result, struct parameter_bundle *bundle);
+       virtual bool show_in_list(void) {return false;};
+       virtual double  utilization(void); /* percentage */
+};
+
+
+#endif
\ No newline at end of file
diff --git a/src/cpu/intel_cpus.cpp b/src/cpu/intel_cpus.cpp
new file mode 100644 (file)
index 0000000..4ae346b
--- /dev/null
@@ -0,0 +1,1368 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ *     Arjan van de Ven <arjan@linux.intel.com>
+ */
+#include "cpu.h"
+#include <iostream>
+#include <fstream>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/time.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <dirent.h>
+
+#include "../lib.h"
+#include "../parameters/parameters.h"
+#include "../display.h"
+
+static int is_turbo(uint64_t freq, uint64_t max, uint64_t maxmo)
+{
+       if (freq != max)
+               return 0;
+       if (maxmo + 1000 != max)
+               return 0;
+       return 1;
+}
+
+int has_c2c7_res;
+
+
+
+static uint64_t get_msr(int cpu, uint64_t offset)
+{
+       ssize_t retval;
+       uint64_t msr;
+       int fd;
+       char msr_path[256];
+
+       fd = sprintf(msr_path, "/dev/cpu/%d/msr", cpu);
+
+       if (access(msr_path, R_OK) != 0){
+               fd = sprintf(msr_path, "/dev/msr%d", cpu);
+
+               if (access(msr_path, R_OK) != 0){
+                       fprintf(stderr, _("msr reg not found"));
+                       exit(-2);
+               }
+       }
+
+       fd = open(msr_path, O_RDONLY);
+
+       retval = pread(fd, &msr, sizeof msr, offset);
+       if (retval != sizeof msr) {
+               reset_display();
+               fprintf(stderr, _("pread cpu%d 0x%llx : "), cpu, (unsigned long long)offset);
+               fprintf(stderr, "%s\n", strerror(errno));
+               exit(-2);
+       }
+       close(fd);
+       return msr;
+}
+
+void nhm_core::measurement_start(void)
+{
+       ifstream file;
+       char filename[4096];
+
+       /* the abstract function needs to be first since it clears all state */
+       abstract_cpu::measurement_start();
+
+       last_stamp = 0;
+
+       c3_before    = get_msr(first_cpu, MSR_CORE_C3_RESIDENCY);
+       c6_before    = get_msr(first_cpu, MSR_CORE_C6_RESIDENCY);
+       if (has_c2c7_res)
+               c7_before    = get_msr(first_cpu, MSR_CORE_C7_RESIDENCY);
+       tsc_before   = get_msr(first_cpu, MSR_TSC);
+
+       insert_cstate("core c3", "C3 (cc3)", 0, c3_before, 1);
+       insert_cstate("core c6", "C6 (cc6)", 0, c6_before, 1);
+       if (has_c2c7_res) {
+               insert_cstate("core c7", "C7 (cc7)", 0, c7_before, 1);
+       }
+
+
+       sprintf(filename, "/sys/devices/system/cpu/cpu%i/cpufreq/stats/time_in_state", first_cpu);
+
+       file.open(filename, ios::in);
+
+       if (file) {
+               char line[1024];
+
+               while (file) {
+                       uint64_t f;
+                       file.getline(line, 1024);
+                       f = strtoull(line, NULL, 10);
+                       account_freq(f, 0);
+               }
+               file.close();
+       }
+       account_freq(0, 0);
+
+}
+
+void nhm_core::measurement_end(void)
+{
+       unsigned int i;
+       uint64_t time_delta;
+       double ratio;
+
+       c3_after    = get_msr(first_cpu, MSR_CORE_C3_RESIDENCY);
+       c6_after    = get_msr(first_cpu, MSR_CORE_C6_RESIDENCY);
+       if (has_c2c7_res)
+               c7_after    = get_msr(first_cpu, MSR_CORE_C7_RESIDENCY);
+       tsc_after   = get_msr(first_cpu, MSR_TSC);
+
+
+
+       finalize_cstate("core c3", 0, c3_after, 1);
+       finalize_cstate("core c6", 0, c6_after, 1);
+       if (has_c2c7_res)
+               finalize_cstate("core c7", 0, c7_after, 1);
+
+       gettimeofday(&stamp_after, NULL);
+
+       time_factor = 1000000.0 * (stamp_after.tv_sec - stamp_before.tv_sec) + stamp_after.tv_usec - stamp_before.tv_usec;
+
+       for (i = 0; i < children.size(); i++)
+               if (children[i]) {
+                       children[i]->measurement_end();
+                       children[i]->wiggle();
+               }
+
+       time_delta = 1000000 * (stamp_after.tv_sec - stamp_before.tv_sec) + stamp_after.tv_usec - stamp_before.tv_usec;
+
+       ratio = 1.0 * time_delta / (tsc_after - tsc_before);
+
+       for (i = 0; i < cstates.size(); i++) {
+               struct idle_state *state = cstates[i];
+
+               if (state->after_count == 0) {
+                       cout << "after count is 0\n";
+                       continue;
+               }
+
+               if (state->after_count != state->before_count) {
+                       cout << "count mismatch\n";
+                       continue;
+               }
+
+               state->usage_delta =    ratio * (state->usage_after    - state->usage_before)    / state->after_count;
+               state->duration_delta = ratio * (state->duration_after - state->duration_before) / state->after_count;
+       }
+
+#if 0
+       for (i = 0; i < children.size(); i++)
+               if (children[i]) {
+                       for (j = 0; j < children[i]->pstates.size(); j++) {
+                               struct frequency *state;
+                               state = children[i]->pstates[j];
+                               if (!state)
+                                       continue;
+
+                               update_pstate(  state->freq, state->human_name, state->time_before, state->before_count);
+                               finalize_pstate(state->freq,                    state->time_after,  state->after_count);
+                       }
+               }
+#endif
+       total_stamp = 0;
+}
+
+void nhm_core::account_freq(uint64_t freq, uint64_t duration)
+{
+       struct frequency *state = NULL;
+       unsigned int i;
+
+       for (i = 0; i < pstates.size(); i++) {
+               if (freq == pstates[i]->freq) {
+                       state = pstates[i];
+                       break;
+               }
+       }
+
+
+       if (!state) {
+               state = new(std::nothrow) struct frequency;
+
+               if (!state)
+                       return;
+
+               memset(state, 0, sizeof(*state));
+
+               pstates.push_back(state);
+
+               state->freq = freq;
+               hz_to_human(freq, state->human_name);
+               if (freq == 0)
+                       strcpy(state->human_name, _("Idle"));
+               if (is_turbo(freq, max_frequency, max_minus_one_frequency))
+                       sprintf(state->human_name, _("Turbo Mode"));
+
+               state->after_count = 1;
+       }
+
+
+       state->time_after += duration;
+}
+
+
+void nhm_core::calculate_freq(uint64_t time)
+{
+       uint64_t freq = 0;
+       bool is_idle = true;
+       unsigned int i;
+
+
+       /* calculate the maximum frequency of all children */
+       for (i = 0; i < children.size(); i++)
+               if (children[i] && children[i]->has_pstates()) {
+                       uint64_t f = 0;
+                       if (!children[i]->idle) {
+                               f = children[i]->current_frequency;
+                               is_idle = false;
+                       }
+                       if (f > freq)
+                               freq = f;
+               }
+
+       current_frequency = freq;
+       idle = is_idle;
+       if (parent)
+               parent->calculate_freq(time);
+       old_idle = idle;
+}
+
+void nhm_core::change_effective_frequency(uint64_t time, uint64_t frequency)
+{
+       uint64_t freq = 0;
+       uint64_t time_delta, fr;
+
+
+       if (last_stamp)
+               time_delta = time - last_stamp;
+       else
+               time_delta = 1;
+
+       fr = effective_frequency;
+
+       if (old_idle)
+               fr = 0;
+
+       account_freq(fr, time_delta);
+
+       effective_frequency = freq;
+       last_stamp = time;
+       abstract_cpu::change_effective_frequency(time, frequency);
+}
+
+char * nhm_core::fill_pstate_line(int line_nr, char *buffer)
+{
+       buffer[0] = 0;
+       unsigned int i;
+
+       if (total_stamp ==0) {
+               for (i = 0; i < pstates.size(); i++)
+                       total_stamp += pstates[i]->time_after;
+               if (total_stamp == 0)
+                       total_stamp = 1;
+       }
+
+       if (line_nr == LEVEL_HEADER) {
+               sprintf(buffer,_("  Core"));
+               return buffer;
+       }
+
+       if (line_nr >= (int)pstates.size() || line_nr < 0)
+               return buffer;
+
+       sprintf(buffer," %5.1f%% ", percentage(1.0* (pstates[line_nr]->time_after) / total_stamp));
+       return buffer;
+}
+
+char * nhm_package::fill_pstate_line(int line_nr, char *buffer)
+{
+       buffer[0] = 0;
+       unsigned int i;
+
+       if (total_stamp ==0) {
+               for (i = 0; i < pstates.size(); i++)
+                       total_stamp += pstates[i]->time_after;
+               if (total_stamp == 0)
+                       total_stamp = 1;
+       }
+
+
+       if (line_nr == LEVEL_HEADER) {
+               sprintf(buffer,_("  Package"));
+               return buffer;
+       }
+
+       if (line_nr >= (int)pstates.size() || line_nr < 0)
+               return buffer;
+
+       sprintf(buffer," %5.1f%% ", percentage(1.0* (pstates[line_nr]->time_after) / total_stamp));
+       return buffer;
+}
+
+
+
+void nhm_package::measurement_start(void)
+{
+       abstract_cpu::measurement_start();
+
+       last_stamp = 0;
+
+       if (has_c2c7_res)
+               c2_before    = get_msr(number, MSR_PKG_C2_RESIDENCY);
+       c3_before    = get_msr(number, MSR_PKG_C3_RESIDENCY);
+       c6_before    = get_msr(number, MSR_PKG_C6_RESIDENCY);
+       if (has_c2c7_res)
+               c7_before    = get_msr(number, MSR_PKG_C7_RESIDENCY);
+       tsc_before   = get_msr(first_cpu, MSR_TSC);
+
+       if (has_c2c7_res)
+               insert_cstate("pkg c2", "C2 (pc2)", 0, c2_before, 1);
+
+       insert_cstate("pkg c3", "C3 (pc3)", 0, c3_before, 1);
+       insert_cstate("pkg c6", "C6 (pc6)", 0, c6_before, 1);
+       if (has_c2c7_res)
+               insert_cstate("pkg c7", "C7 (pc7)", 0, c7_before, 1);
+}
+
+void nhm_package::measurement_end(void)
+{
+       uint64_t time_delta;
+       double ratio;
+       unsigned int i, j;
+
+       for (i = 0; i < children.size(); i++)
+               if (children[i])
+                       children[i]->wiggle();
+
+
+       if (has_c2c7_res)
+               c2_after    = get_msr(number, MSR_PKG_C2_RESIDENCY);
+       c3_after    = get_msr(number, MSR_PKG_C3_RESIDENCY);
+       c6_after    = get_msr(number, MSR_PKG_C6_RESIDENCY);
+       if (has_c2c7_res)
+               c7_after    = get_msr(number, MSR_PKG_C7_RESIDENCY);
+       tsc_after   = get_msr(first_cpu, MSR_TSC);
+
+       gettimeofday(&stamp_after, NULL);
+
+       time_factor = 1000000.0 * (stamp_after.tv_sec - stamp_before.tv_sec) + stamp_after.tv_usec - stamp_before.tv_usec;
+
+
+       if (has_c2c7_res)
+               finalize_cstate("pkg c2", 0, c2_after, 1);
+       finalize_cstate("pkg c3", 0, c3_after, 1);
+       finalize_cstate("pkg c6", 0, c6_after, 1);
+       if (has_c2c7_res)
+               finalize_cstate("pkg c7", 0, c7_after, 1);
+
+       for (i = 0; i < children.size(); i++)
+               if (children[i])
+                       children[i]->measurement_end();
+
+       time_delta = 1000000 * (stamp_after.tv_sec - stamp_before.tv_sec) + stamp_after.tv_usec - stamp_before.tv_usec;
+
+       ratio = 1.0 * time_delta / (tsc_after - tsc_before);
+
+
+       for (i = 0; i < cstates.size(); i++) {
+               struct idle_state *state = cstates[i];
+
+               if (state->after_count == 0) {
+                       cout << "after count is 0\n";
+                       continue;
+               }
+
+               if (state->after_count != state->before_count) {
+                       cout << "count mismatch\n";
+                       continue;
+               }
+
+               state->usage_delta =    ratio * (state->usage_after    - state->usage_before)    / state->after_count;
+               state->duration_delta = ratio * (state->duration_after - state->duration_before) / state->after_count;
+       }
+       for (i = 0; i < children.size(); i++)
+               if (children[i]) {
+                       for (j = 0; j < children[i]->pstates.size(); j++) {
+                               struct frequency *state;
+                               state = children[i]->pstates[j];
+                               if (!state)
+                                       continue;
+
+                               update_pstate(  state->freq, state->human_name, state->time_before, state->before_count);
+                               finalize_pstate(state->freq,                    state->time_after,  state->after_count);
+                       }
+               }
+       total_stamp = 0;
+
+}
+
+void nhm_package::account_freq(uint64_t freq, uint64_t duration)
+{
+       struct frequency *state = NULL;
+       unsigned int i;
+
+       for (i = 0; i < pstates.size(); i++) {
+               if (freq == pstates[i]->freq) {
+                       state = pstates[i];
+                       break;
+               }
+       }
+
+
+       if (!state) {
+               state = new(std::nothrow) struct frequency;
+
+               if (!state)
+                       return;
+
+               memset(state, 0, sizeof(*state));
+
+               pstates.push_back(state);
+
+               state->freq = freq;
+               hz_to_human(freq, state->human_name);
+               if (freq == 0)
+                       strcpy(state->human_name, _("Idle"));
+               if (is_turbo(freq, max_frequency, max_minus_one_frequency))
+                       sprintf(state->human_name, _("Turbo Mode"));
+               state->after_count = 1;
+       }
+
+       state->time_after += duration;
+
+}
+
+
+void nhm_package::calculate_freq(uint64_t time)
+{
+       uint64_t freq = 0;
+       bool is_idle = true;
+       unsigned int i;
+
+       /* calculate the maximum frequency of all children */
+       for (i = 0; i < children.size(); i++)
+               if (children[i] && children[i]->has_pstates()) {
+                       uint64_t f = 0;
+                       if (!children[i]->idle) {
+                               f = children[i]->current_frequency;
+                               is_idle = false;
+                       }
+                       if (f > freq)
+                               freq = f;
+               }
+
+       current_frequency = freq;
+       idle = is_idle;
+       if (parent)
+               parent->calculate_freq(time);
+       change_effective_frequency(time, current_frequency);
+       old_idle = idle;
+}
+
+void nhm_package::change_effective_frequency(uint64_t time, uint64_t frequency)
+{
+       uint64_t time_delta, fr;
+
+       if (last_stamp)
+               time_delta = time - last_stamp;
+       else
+               time_delta = 1;
+
+       fr = effective_frequency;
+       if (old_idle)
+               fr = 0;
+
+       account_freq(fr, time_delta);
+
+       effective_frequency = frequency;
+       last_stamp = time;
+
+       abstract_cpu::change_effective_frequency(time, frequency);
+}
+
+
+void nhm_cpu::measurement_start(void)
+{
+       ifstream file;
+       char filename[4096];
+
+       cpu_linux::measurement_start();
+
+       last_stamp = 0;
+
+       aperf_before = get_msr(number, MSR_APERF);
+       mperf_before = get_msr(number, MSR_MPERF);
+       tsc_before   = get_msr(number, MSR_TSC);
+
+       insert_cstate("active", _("C0 active"), 0, aperf_before, 1);
+
+       sprintf(filename, "/sys/devices/system/cpu/cpu%i/cpufreq/stats/time_in_state", first_cpu);
+
+       file.open(filename, ios::in);
+
+       if (file) {
+               char line[1024];
+
+               while (file) {
+                       uint64_t f;
+                       file.getline(line, 1024);
+                       f = strtoull(line, NULL, 10);
+                       account_freq(f, 0);
+               }
+               file.close();
+       }
+       account_freq(0, 0);
+}
+
+void nhm_cpu::measurement_end(void)
+{
+       uint64_t time_delta;
+       double ratio;
+       unsigned int i;
+
+       aperf_after = get_msr(number, MSR_APERF);
+       mperf_after = get_msr(number, MSR_MPERF);
+       tsc_after   = get_msr(number, MSR_TSC);
+
+
+
+       finalize_cstate("active", 0, aperf_after, 1);
+
+
+       cpu_linux::measurement_end();
+
+       time_delta = 1000000 * (stamp_after.tv_sec - stamp_before.tv_sec) + stamp_after.tv_usec - stamp_before.tv_usec;
+
+       ratio = 1.0 * time_delta / (tsc_after - tsc_before);
+
+
+       for (i = 0; i < cstates.size(); i++) {
+               struct idle_state *state = cstates[i];
+               if (state->line_level != LEVEL_C0)
+                       continue;
+
+               state->usage_delta =    ratio * (state->usage_after    - state->usage_before)    / state->after_count;
+               state->duration_delta = ratio * (state->duration_after - state->duration_before) / state->after_count;
+       }
+
+       total_stamp = 0;
+
+}
+
+
+char * nhm_cpu::fill_pstate_name(int line_nr, char *buffer)
+{
+       if (line_nr == LEVEL_C0) {
+               sprintf(buffer, _("Actual"));
+               return buffer;
+       }
+       return cpu_linux::fill_pstate_name(line_nr, buffer);
+}
+
+char * nhm_cpu::fill_pstate_line(int line_nr, char *buffer)
+{
+       if (total_stamp ==0) {
+               unsigned int i;
+               for (i = 0; i < pstates.size(); i++)
+                       total_stamp += pstates[i]->time_after;
+               if (total_stamp == 0)
+                       total_stamp = 1;
+       }
+
+       if (line_nr == LEVEL_HEADER) {
+               sprintf(buffer,_(" CPU %i"), number);
+               return buffer;
+       }
+
+       if (line_nr == LEVEL_C0) {
+               double F;
+               F = 1.0 * (tsc_after - tsc_before) * (aperf_after - aperf_before) / (mperf_after - mperf_before) / time_factor * 1000;
+               hz_to_human(F, buffer, 1);
+               return buffer;
+       }
+       if (line_nr >= (int)pstates.size() || line_nr < 0)
+               return buffer;
+
+       sprintf(buffer," %5.1f%% ", percentage(1.0* (pstates[line_nr]->time_after) / total_stamp));
+       return buffer;
+
+}
+
+
+int nhm_cpu::has_pstate_level(int level)
+{
+       if (level == LEVEL_C0)
+               return 1;
+       return cpu_linux::has_pstate_level(level);
+}
+
+void nhm_cpu::account_freq(uint64_t freq, uint64_t duration)
+{
+       struct frequency *state = NULL;
+       unsigned int i;
+
+
+       for (i = 0; i < pstates.size(); i++) {
+               if (freq == pstates[i]->freq) {
+                       state = pstates[i];
+                       break;
+               }
+       }
+
+       if (!state) {
+               state = new(std::nothrow) struct frequency;
+
+               if (!state)
+                       return;
+
+               memset(state, 0, sizeof(*state));
+
+               pstates.push_back(state);
+
+               state->freq = freq;
+               hz_to_human(freq, state->human_name);
+               if (freq == 0)
+                       strcpy(state->human_name, _("Idle"));
+               state->after_count = 1;
+       }
+
+
+       state->time_after += duration;
+
+
+}
+
+void nhm_cpu::change_freq(uint64_t time, int frequency)
+{
+       current_frequency = frequency;
+
+       if (parent)
+               parent->calculate_freq(time);
+       old_idle = idle;
+}
+
+void nhm_cpu::change_effective_frequency(uint64_t time, uint64_t frequency)
+{
+       uint64_t time_delta, fr;
+
+       if (last_stamp)
+               time_delta = time - last_stamp;
+       else
+               time_delta = 1;
+
+       fr = effective_frequency;
+       if (old_idle)
+               fr = 0;
+
+       account_freq(fr, time_delta);
+
+       effective_frequency = frequency;
+       last_stamp = time;
+}
+
+void nhm_cpu::go_idle(uint64_t time)
+{
+
+       idle = true;
+
+       if (parent)
+               parent->calculate_freq(time);
+       old_idle = idle;
+}
+
+
+void nhm_cpu::go_unidle(uint64_t time)
+{
+       idle = false;
+       if (parent)
+               parent->calculate_freq(time);
+       old_idle = idle;
+}
+
+
+void atom_package::measurement_start(void)
+{
+       abstract_cpu::measurement_start();
+
+       last_stamp = 0;
+
+       c2_before    = get_msr(number, ATOM_MSR_PKG_C2_RESIDENCY);
+       c4_before    = get_msr(number, ATOM_MSR_PKG_C4_RESIDENCY);
+       c6_before    = get_msr(number, ATOM_MSR_PKG_C6_RESIDENCY);
+       tsc_before   = get_msr(first_cpu, MSR_TSC);
+
+       insert_cstate("pkg c2", "C2 (pc2)", 0, c2_before, 1);
+       insert_cstate("pkg c4", "C4 (pc4)", 0, c4_before, 1);
+       insert_cstate("pkg c6", "C6 (pc6)", 0, c6_before, 1);
+}
+
+void atom_package::measurement_end(void)
+{
+       uint64_t time_delta;
+       double ratio;
+       unsigned int i, j;
+
+       for (i = 0; i < children.size(); i++)
+               if (children[i])
+                       children[i]->wiggle();
+
+       c2_after    = get_msr(number, ATOM_MSR_PKG_C2_RESIDENCY);
+       c4_after    = get_msr(number, ATOM_MSR_PKG_C4_RESIDENCY);
+       c6_after    = get_msr(number, ATOM_MSR_PKG_C6_RESIDENCY);
+       tsc_after   = get_msr(first_cpu, MSR_TSC);
+
+       gettimeofday(&stamp_after, NULL);
+
+       time_factor = 1000000.0 * (stamp_after.tv_sec - stamp_before.tv_sec) + stamp_after.tv_usec - stamp_before.tv_usec;
+
+       finalize_cstate("pkg c2", 0, c2_after, 1);
+       finalize_cstate("pkg c4", 0, c4_after, 1);
+       finalize_cstate("pkg c6", 0, c6_after, 1);
+
+       for (i = 0; i < children.size(); i++)
+               if (children[i])
+                       children[i]->measurement_end();
+
+       time_delta = 1000000 * (stamp_after.tv_sec - stamp_before.tv_sec) + stamp_after.tv_usec - stamp_before.tv_usec;
+
+       ratio = 1.0 * time_delta / (tsc_after - tsc_before);
+
+       for (i = 0; i < cstates.size(); i++) {
+               struct idle_state *state = cstates[i];
+
+               if (state->after_count == 0) {
+                       cout << "after count is 0\n";
+                       continue;
+               }
+
+               if (state->after_count != state->before_count) {
+                       cout << "count mismatch\n";
+                       continue;
+               }
+
+               state->usage_delta =    ratio * (state->usage_after    - state->usage_before)    / state->after_count;
+               state->duration_delta = ratio * (state->duration_after - state->duration_before) / state->after_count;
+       }
+       for (i = 0; i < children.size(); i++)
+               if (children[i]) {
+                       for (j = 0; j < children[i]->pstates.size(); j++) {
+                               struct frequency *state;
+                               state = children[i]->pstates[j];
+                               if (!state)
+                                       continue;
+
+                               update_pstate(  state->freq, state->human_name, state->time_before, state->before_count);
+                               finalize_pstate(state->freq,                    state->time_after,  state->after_count);
+                       }
+               }
+       total_stamp = 0;
+}
+
+void atom_package::account_freq(uint64_t freq, uint64_t duration)
+{
+       struct frequency *state = NULL;
+       unsigned int i;
+
+       for (i = 0; i < pstates.size(); i++) {
+               if (freq == pstates[i]->freq) {
+                       state = pstates[i];
+                       break;
+               }
+       }
+
+       if (!state) {
+               state = new(std::nothrow) struct frequency;
+
+               if (!state)
+                       return;
+
+               memset(state, 0, sizeof(*state));
+
+               pstates.push_back(state);
+
+               state->freq = freq;
+               hz_to_human(freq, state->human_name);
+               if (freq == 0)
+                       strcpy(state->human_name, _("Idle"));
+               state->after_count = 1;
+       }
+
+       state->time_after += duration;
+}
+
+char * atom_package::fill_pstate_line(int line_nr, char *buffer)
+{
+       buffer[0] = 0;
+       unsigned int i;
+
+       if (total_stamp ==0) {
+               for (i = 0; i < pstates.size(); i++)
+                       total_stamp += pstates[i]->time_after;
+               if (total_stamp == 0)
+                       total_stamp = 1;
+       }
+
+       if (line_nr == LEVEL_HEADER) {
+               sprintf(buffer,_("  Package"));
+               return buffer;
+       }
+
+       if (line_nr >= (int)pstates.size() || line_nr < 0)
+               return buffer;
+
+       sprintf(buffer," %5.1f%% ", percentage(1.0* (pstates[line_nr]->time_after) / total_stamp));
+       return buffer;
+}
+
+void atom_package::calculate_freq(uint64_t time)
+{
+       uint64_t freq = 0;
+       bool is_idle = true;
+       unsigned int i;
+
+       /* calculate the maximum frequency of all children */
+       for (i = 0; i < children.size(); i++)
+               if (children[i] && children[i]->has_pstates()) {
+                       uint64_t f = 0;
+                       if (!children[i]->idle) {
+                               f = children[i]->current_frequency;
+                               is_idle = false;
+                       }
+                       if (f > freq)
+                               freq = f;
+               }
+
+       current_frequency = freq;
+       idle = is_idle;
+       if (parent)
+               parent->calculate_freq(time);
+       change_effective_frequency(time, current_frequency);
+       old_idle = idle;
+}
+
+void atom_package::change_effective_frequency(uint64_t time, uint64_t frequency)
+{
+       uint64_t time_delta, fr;
+
+       if (last_stamp)
+               time_delta = time - last_stamp;
+       else
+               time_delta = 1;
+
+       fr = effective_frequency;
+       if (old_idle)
+               fr = 0;
+
+       account_freq(fr, time_delta);
+
+       effective_frequency = frequency;
+       last_stamp = time;
+
+       abstract_cpu::change_effective_frequency(time, frequency);
+}
+
+void atom_core::measurement_start(void)
+{
+       ifstream file;
+       char filename[4096];
+
+       /* the abstract function needs to be first since it clears all state */
+       abstract_cpu::measurement_start();
+
+       last_stamp = 0;
+
+       c2_before    = get_msr(first_cpu, ATOM_MSR_PKG_C2_RESIDENCY);
+       c4_before    = get_msr(first_cpu, ATOM_MSR_PKG_C4_RESIDENCY);
+       c6_before    = get_msr(first_cpu, ATOM_MSR_PKG_C6_RESIDENCY);
+       tsc_before   = get_msr(first_cpu, MSR_TSC);
+
+       insert_cstate("core c2", "C2 (cc2)", 0, c2_before, 1);
+       insert_cstate("core c4", "C4 (cc4)", 0, c4_before, 1);
+       insert_cstate("core c6", "C6 (cc6)", 0, c6_before, 1);
+
+       sprintf(filename, "/sys/devices/system/cpu/cpu%i/cpufreq/stats/time_in_state", first_cpu);
+
+       file.open(filename, ios::in);
+
+       if (file) {
+               char line[1024];
+
+               while (file) {
+                       uint64_t f;
+                       file.getline(line, 1024);
+                       f = strtoull(line, NULL, 10);
+                       account_freq(f, 0);
+               }
+               file.close();
+       }
+       account_freq(0, 0);
+
+}
+
+void atom_core::measurement_end(void)
+{
+       unsigned int i;
+       uint64_t time_delta;
+       double ratio;
+
+       c2_after    = get_msr(first_cpu, ATOM_MSR_PKG_C2_RESIDENCY);
+       c4_after    = get_msr(first_cpu, ATOM_MSR_PKG_C4_RESIDENCY);
+       c6_after    = get_msr(first_cpu, ATOM_MSR_PKG_C6_RESIDENCY);
+       tsc_after   = get_msr(first_cpu, MSR_TSC);
+
+       finalize_cstate("core c2", 0, c2_after, 1);
+       finalize_cstate("core c4", 0, c4_after, 1);
+       finalize_cstate("core c6", 0, c6_after, 1);
+
+       gettimeofday(&stamp_after, NULL);
+
+       time_factor = 1000000.0 * (stamp_after.tv_sec - stamp_before.tv_sec) + stamp_after.tv_usec - stamp_before.tv_usec;
+
+       for (i = 0; i < children.size(); i++)
+               if (children[i]) {
+                       children[i]->measurement_end();
+                       children[i]->wiggle();
+               }
+
+       time_delta = 1000000 * (stamp_after.tv_sec - stamp_before.tv_sec) + stamp_after.tv_usec - stamp_before.tv_usec;
+
+       ratio = 1.0 * time_delta / (tsc_after - tsc_before);
+
+       for (i = 0; i < cstates.size(); i++) {
+               struct idle_state *state = cstates[i];
+
+               if (state->after_count == 0) {
+                       cout << "after count is 0\n";
+                       continue;
+               }
+
+               if (state->after_count != state->before_count) {
+                       cout << "count mismatch\n";
+                       continue;
+               }
+
+               state->usage_delta =    ratio * (state->usage_after    - state->usage_before)    / state->after_count;
+               state->duration_delta = ratio * (state->duration_after - state->duration_before) / state->after_count;
+       }
+
+       total_stamp = 0;
+}
+
+void atom_core::account_freq(uint64_t freq, uint64_t duration)
+{
+       struct frequency *state = NULL;
+       unsigned int i;
+
+       for (i = 0; i < pstates.size(); i++) {
+               if (freq == pstates[i]->freq) {
+                       state = pstates[i];
+                       break;
+               }
+       }
+
+       if (!state) {
+               state = new(std::nothrow) struct frequency;
+
+               if (!state)
+                       return;
+
+               memset(state, 0, sizeof(*state));
+
+               pstates.push_back(state);
+
+               state->freq = freq;
+               hz_to_human(freq, state->human_name);
+               if (freq == 0)
+                       strcpy(state->human_name, _("Idle"));
+
+               state->after_count = 1;
+       }
+
+       state->time_after += duration;
+}
+
+void atom_core::calculate_freq(uint64_t time)
+{
+       uint64_t freq = 0;
+       bool is_idle = true;
+       unsigned int i;
+
+       /* calculate the maximum frequency of all children */
+       for (i = 0; i < children.size(); i++)
+               if (children[i] && children[i]->has_pstates()) {
+                       uint64_t f = 0;
+                       if (!children[i]->idle) {
+                               f = children[i]->current_frequency;
+                               is_idle = false;
+                       }
+                       if (f > freq)
+                               freq = f;
+               }
+
+       current_frequency = freq;
+       idle = is_idle;
+       if (parent)
+               parent->calculate_freq(time);
+       old_idle = idle;
+}
+
+void atom_core::change_effective_frequency(uint64_t time, uint64_t frequency)
+{
+       uint64_t freq = 0;
+       uint64_t time_delta, fr;
+
+       if (last_stamp)
+               time_delta = time - last_stamp;
+       else
+               time_delta = 1;
+
+       fr = effective_frequency;
+
+       if (old_idle)
+               fr = 0;
+
+       account_freq(fr, time_delta);
+
+       effective_frequency = freq;
+       last_stamp = time;
+       abstract_cpu::change_effective_frequency(time, frequency);
+}
+
+char * atom_core::fill_pstate_line(int line_nr, char *buffer)
+{
+       buffer[0] = 0;
+       unsigned int i;
+
+       if (total_stamp ==0) {
+               for (i = 0; i < pstates.size(); i++)
+                       total_stamp += pstates[i]->time_after;
+               if (total_stamp == 0)
+                       total_stamp = 1;
+       }
+
+       if (line_nr == LEVEL_HEADER) {
+               sprintf(buffer,_("  Core"));
+               return buffer;
+       }
+
+       if (line_nr >= (int)pstates.size() || line_nr < 0)
+               return buffer;
+
+       sprintf(buffer," %5.1f%% ", percentage(1.0* (pstates[line_nr]->time_after) / total_stamp));
+       return buffer;
+}
+
+void atom_cpu::measurement_start(void)
+{
+       ifstream file;
+       char filename[4096];
+
+       abstract_cpu::measurement_start();
+       parse_cstates_start();
+       parse_pstates_start();
+
+       last_stamp = 0;
+
+       aperf_before = get_msr(number, MSR_APERF);
+       mperf_before = get_msr(number, MSR_MPERF);
+       tsc_before   = get_msr(number, MSR_TSC);
+
+       insert_cstate("active", _("C0 active"), 0, aperf_before, 1);
+
+       sprintf(filename, "/sys/devices/system/cpu/cpu%i/cpufreq/stats/time_in_state", first_cpu);
+
+       file.open(filename, ios::in);
+
+       if (file) {
+               char line[1024];
+
+               while (file) {
+                       uint64_t f;
+                       file.getline(line, 1024);
+                       f = strtoull(line, NULL, 10);
+                       account_freq(f, 0);
+               }
+               file.close();
+       }
+       account_freq(0, 0);
+}
+
+void atom_cpu::measurement_end(void)
+{
+       uint64_t time_delta;
+       double ratio;
+       unsigned int i;
+
+       aperf_after = get_msr(number, MSR_APERF);
+       mperf_after = get_msr(number, MSR_MPERF);
+       tsc_after   = get_msr(number, MSR_TSC);
+
+       finalize_cstate("active", 0, aperf_after, 1);
+
+       cpu_linux::measurement_end();
+
+       time_delta = 1000000 * (stamp_after.tv_sec - stamp_before.tv_sec) + stamp_after.tv_usec - stamp_before.tv_usec;
+
+       ratio = 1.0 * time_delta / (tsc_after - tsc_before);
+
+       for (i = 0; i < cstates.size(); i++) {
+               struct idle_state *state = cstates[i];
+               if (state->line_level != LEVEL_C0)
+                       continue;
+
+               state->usage_delta =    ratio * (state->usage_after    - state->usage_before)    / state->after_count;
+               state->duration_delta = ratio * (state->duration_after - state->duration_before) / state->after_count;
+       }
+
+       total_stamp = 0;
+}
+
+char * atom_cpu::fill_pstate_name(int line_nr, char *buffer)
+{
+       if (line_nr == LEVEL_C0) {
+               sprintf(buffer, _("Actual"));
+               return buffer;
+       }
+       return cpu_linux::fill_pstate_name(line_nr, buffer);
+}
+
+char * atom_cpu::fill_pstate_line(int line_nr, char *buffer)
+{
+       if (total_stamp ==0) {
+               unsigned int i;
+               for (i = 0; i < pstates.size(); i++)
+                       total_stamp += pstates[i]->time_after;
+               if (total_stamp == 0)
+                       total_stamp = 1;
+       }
+
+       if (line_nr == LEVEL_HEADER) {
+               sprintf(buffer,_(" CPU %i"), number);
+               return buffer;
+       }
+
+       if (line_nr == LEVEL_C0) {
+               double F;
+               F = 1.0 * (tsc_after - tsc_before) * (aperf_after - aperf_before) / (mperf_after - mperf_before) / time_factor * 1000;
+               hz_to_human(F, buffer, 1);
+               return buffer;
+       }
+       if (line_nr >= (int)pstates.size() || line_nr < 0)
+               return buffer;
+
+       sprintf(buffer," %5.1f%% ", percentage(1.0* (pstates[line_nr]->time_after) / total_stamp));
+       return buffer;
+}
+
+int atom_cpu::has_pstate_level(int level)
+{
+       if (level == LEVEL_C0)
+               return 1;
+       return cpu_linux::has_pstate_level(level);
+}
+
+void atom_cpu::account_freq(uint64_t freq, uint64_t duration)
+{
+       struct frequency *state = NULL;
+       unsigned int i;
+
+       for (i = 0; i < pstates.size(); i++) {
+               if (freq == pstates[i]->freq) {
+                       state = pstates[i];
+                       break;
+               }
+       }
+
+       if (!state) {
+               state = new(std::nothrow) struct frequency;
+
+               if (!state)
+                       return;
+
+               memset(state, 0, sizeof(*state));
+
+               pstates.push_back(state);
+
+               state->freq = freq;
+               hz_to_human(freq, state->human_name);
+               if (freq == 0)
+                       strcpy(state->human_name, _("Idle"));
+               state->after_count = 1;
+       }
+
+       state->time_after += duration;
+}
+
+void atom_cpu::change_freq(uint64_t time, int frequency)
+{
+       current_frequency = frequency;
+
+       if (parent)
+               parent->calculate_freq(time);
+       old_idle = idle;
+}
+
+void atom_cpu::change_effective_frequency(uint64_t time, uint64_t frequency)
+{
+       uint64_t time_delta, fr;
+
+       if (last_stamp)
+               time_delta = time - last_stamp;
+       else
+               time_delta = 1;
+
+       fr = effective_frequency;
+       if (old_idle)
+               fr = 0;
+
+       account_freq(fr, time_delta);
+
+       effective_frequency = frequency;
+       last_stamp = time;
+}
+
+void atom_cpu::go_idle(uint64_t time)
+{
+       idle = true;
+
+       if (parent)
+               parent->calculate_freq(time);
+       old_idle = idle;
+}
+
+
+void atom_cpu::go_unidle(uint64_t time)
+{
+       idle = false;
+       if (parent)
+               parent->calculate_freq(time);
+       old_idle = idle;
+}
+
+void atom_cpu::parse_cstates_start(void)
+{
+       ifstream file;
+       DIR *dir;
+       struct dirent *entry;
+       char filename[256];
+       int len;
+
+       len = sprintf(filename, "/sys/devices/system/cpu/cpu%i/cpuidle", number);
+
+       dir = opendir(filename);
+       if (!dir)
+               return;
+
+       /* For each C-state, there is a stateX directory which
+        * contains a 'usage' and a 'time' (duration) file */
+       while ((entry = readdir(dir))) {
+               char linux_name[64];
+               char human_name[64];
+               uint64_t usage = 0;
+               uint64_t duration = 0;
+
+               if (strlen(entry->d_name) < 3)
+                       continue;
+
+               strcpy(linux_name, entry->d_name);
+               strcpy(human_name, linux_name);
+
+               sprintf(filename + len, "/%s/name", entry->d_name);
+
+               file.open(filename, ios::in);
+               if (file) {
+                       file.getline(human_name, 64);
+                       file.close();
+               }
+
+               if (strcmp(human_name, "C0")==0)
+                       strcpy(human_name, _("C0 polling"));
+
+               sprintf(filename + len, "/%s/usage", entry->d_name);
+               file.open(filename, ios::in);
+               if (file) {
+                       file >> usage;
+                       file.close();
+               }
+
+               sprintf(filename + len, "/%s/time", entry->d_name);
+
+               file.open(filename, ios::in);
+               if (file) {
+                       file >> duration;
+                       file.close();
+               }
+
+               if (strcmp(human_name, "ATM-S0i1") == 0)
+                       update_cstate(linux_name, human_name, usage, duration, 1, 8);
+               else if (strcmp(human_name, "ATM-LpAudio") == 0)
+                       update_cstate(linux_name, human_name, usage, duration, 1, 9);
+               else if (strcmp(human_name, "ATM-S0i3") == 0)
+                       update_cstate(linux_name, human_name, usage, duration, 1, 10);
+               else
+                       update_cstate(linux_name, human_name, usage, duration, 1);
+
+       }
+       closedir(dir);
+}
+
+void atom_cpu::parse_pstates_start(void)
+{
+       ifstream file;
+       char filename[256];
+       unsigned int i;
+
+       last_stamp = 0;
+       for (i = 0; i < children.size(); i++)
+               if (children[i])
+                       children[i]->wiggle();
+
+       sprintf(filename, "/sys/devices/system/cpu/cpu%i/cpufreq/stats/time_in_state", first_cpu);
+
+       file.open(filename, ios::in);
+
+       if (file) {
+               char line[1024];
+
+               while (file) {
+                       uint64_t f;
+                       file.getline(line, 1024);
+                       f = strtoull(line, NULL, 10);
+                       account_freq(f, 0);
+               }
+               file.close();
+       }
+       account_freq(0, 0);
+}
+
diff --git a/src/cpu/intel_cpus.h b/src/cpu/intel_cpus.h
new file mode 100644 (file)
index 0000000..fa62930
--- /dev/null
@@ -0,0 +1,227 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ *     Arjan van de Ven <arjan@linux.intel.com>
+ */
+#include <stdint.h>
+#include <sys/time.h>
+
+
+#define MSR_TSC                                0x10
+#define MSR_NEHALEM_PLATFORM_INFO      0xCE
+#define MSR_NEHALEM_TURBO_RATIO_LIMIT  0x1AD
+#define MSR_APERF                      0xE8
+#define MSR_MPERF                      0xE7
+#define MSR_PKG_C2_RESIDENCY           0x60D
+#define MSR_PKG_C3_RESIDENCY           0x3F8
+#define MSR_PKG_C6_RESIDENCY           0x3F9
+#define MSR_PKG_C7_RESIDENCY           0x3FA
+#define MSR_CORE_C3_RESIDENCY          0x3FC
+#define MSR_CORE_C6_RESIDENCY          0x3FD
+#define MSR_CORE_C7_RESIDENCY          0x3FE
+
+#define ATOM_MSR_PKG_C2_RESIDENCY      0x3F8
+#define ATOM_MSR_PKG_C4_RESIDENCY      0x3F9
+#define ATOM_MSR_PKG_C6_RESIDENCY      0x3FA
+
+class nhm_package: public cpu_package
+{
+private:
+       uint64_t        c2_before, c2_after;
+       uint64_t        c3_before, c3_after;
+       uint64_t        c6_before, c6_after;
+       uint64_t        c7_before, c7_after;
+       uint64_t        tsc_before, tsc_after;
+
+       uint64_t        last_stamp;
+       uint64_t        total_stamp;
+
+       void            account_freq(uint64_t frequency, uint64_t duration);
+
+public:
+       virtual void    measurement_start(void);
+       virtual void    measurement_end(void);
+       virtual int     can_collapse(void) { return 0;};
+
+       virtual char *  fill_pstate_line(int line_nr, char *buffer);
+
+       virtual void    calculate_freq(uint64_t time);
+       virtual void    change_effective_frequency(uint64_t time, uint64_t freq);
+
+};
+
+class nhm_core: public cpu_core
+{
+private:
+       uint64_t        c3_before, c3_after;
+       uint64_t        c6_before, c6_after;
+       uint64_t        c7_before, c7_after;
+       uint64_t        tsc_before, tsc_after;
+
+       uint64_t        last_stamp;
+       uint64_t        total_stamp;
+
+       void            account_freq(uint64_t frequency, uint64_t duration);
+public:
+       virtual void    measurement_start(void);
+       virtual void    measurement_end(void);
+       virtual int     can_collapse(void) { return 0;};
+
+       virtual char *  fill_pstate_line(int line_nr, char *buffer);
+
+       virtual void    calculate_freq(uint64_t time);
+       virtual void    change_effective_frequency(uint64_t time, uint64_t freq);
+
+};
+
+class nhm_cpu: public cpu_linux
+{
+private:
+       uint64_t        aperf_before;
+       uint64_t        aperf_after;
+       uint64_t        mperf_before;
+       uint64_t        mperf_after;
+       uint64_t        tsc_before, tsc_after;
+
+       uint64_t        last_stamp;
+       uint64_t        total_stamp;
+
+       void            account_freq(uint64_t frequency, uint64_t duration);
+public:
+       virtual void    measurement_start(void);
+       virtual void    measurement_end(void);
+       virtual int     can_collapse(void) { return 0;};
+
+       virtual char *  fill_pstate_name(int line_nr, char *buffer);
+       virtual char *  fill_pstate_line(int line_nr, char *buffer);
+       virtual int     has_pstate_level(int level);
+
+       virtual void    change_freq(uint64_t time, int freq);
+       virtual void    change_effective_frequency(uint64_t time, uint64_t freq);
+       virtual void    go_idle(uint64_t time);
+       virtual void    go_unidle(uint64_t time);
+
+};
+
+class atom_package: public cpu_package
+{
+private:
+       uint64_t        c2_before, c2_after;
+       uint64_t        c4_before, c4_after;
+       uint64_t        c6_before, c6_after;
+       uint64_t        tsc_before, tsc_after;
+
+       uint64_t        last_stamp;
+       uint64_t        total_stamp;
+
+       void            account_freq(uint64_t frequency, uint64_t duration);
+
+public:
+       virtual void    measurement_start(void);
+       virtual void    measurement_end(void);
+       virtual int     can_collapse(void) { return 0;};
+
+       virtual char *  fill_pstate_line(int line_nr, char *buffer);
+
+       virtual void    calculate_freq(uint64_t time);
+       virtual void    change_effective_frequency(uint64_t time, uint64_t freq);
+};
+
+class atom_core: public cpu_core
+{
+private:
+       uint64_t        c2_before, c2_after;
+       uint64_t        c4_before, c4_after;
+       uint64_t        c6_before, c6_after;
+       uint64_t        tsc_before, tsc_after;
+
+       uint64_t        last_stamp;
+       uint64_t        total_stamp;
+
+       void            account_freq(uint64_t frequency, uint64_t duration);
+
+public:
+       virtual void    measurement_start(void);
+       virtual void    measurement_end(void);
+       virtual int     can_collapse(void) { return 0;};
+
+       virtual char *  fill_pstate_line(int line_nr, char *buffer);
+
+       virtual void    calculate_freq(uint64_t time);
+       virtual void    change_effective_frequency(uint64_t time, uint64_t freq);
+};
+
+class atom_cpu: public cpu_linux
+{
+private:
+       uint64_t        aperf_before;
+       uint64_t        aperf_after;
+       uint64_t        mperf_before;
+       uint64_t        mperf_after;
+       uint64_t        tsc_before, tsc_after;
+
+       uint64_t        last_stamp;
+       uint64_t        total_stamp;
+
+       void            account_freq(uint64_t frequency, uint64_t duration);
+       void            parse_pstates_start(void);
+       void            parse_cstates_start(void);
+
+public:
+       virtual void    measurement_start(void);
+       virtual void    measurement_end(void);
+       virtual int     can_collapse(void) { return 0;};
+
+       virtual char *  fill_pstate_name(int line_nr, char *buffer);
+       virtual char *  fill_pstate_line(int line_nr, char *buffer);
+       virtual int     has_pstate_level(int level);
+
+       virtual void    change_freq(uint64_t time, int freq);
+       virtual void    change_effective_frequency(uint64_t time, uint64_t freq);
+       virtual void    go_idle(uint64_t time);
+       virtual void    go_unidle(uint64_t time);
+};
+
+extern int has_c2c7_res;
+
+class i965_core: public cpu_core
+{
+private:
+       uint64_t        rc6_before, rc6_after;
+       uint64_t        rc6p_before, rc6p_after;
+       uint64_t        rc6pp_before, rc6pp_after;
+       
+       struct timeval  before;
+       struct timeval  after;
+
+public:
+       virtual void    measurement_start(void);
+       virtual void    measurement_end(void);
+       virtual int     can_collapse(void) { return 0;};
+
+       virtual char *  fill_pstate_line(int line_nr, char *buffer);
+       virtual char *  fill_pstate_name(int line_nr, char *buffer);
+       virtual char *  fill_cstate_line(int line_nr, char *buffer, const char *separator);
+       virtual int     has_pstate_level(int level) { return 0; };
+       virtual int     has_pstates(void) { return 0; };
+
+};
diff --git a/src/cpu/intel_gpu.cpp b/src/cpu/intel_gpu.cpp
new file mode 100644 (file)
index 0000000..57474f1
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ * Copyright 2012, Intel Corporation
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ *     Arjan van de Ven <arjan@linux.intel.com>
+ */
+#include "cpu.h"
+#include <iostream>
+#include <fstream>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/time.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include "../lib.h"
+#include "../parameters/parameters.h"
+#include "../display.h"
+
+void i965_core::measurement_start(void)
+{
+       ifstream file;
+
+       gettimeofday(&before, NULL);
+       rc6_before = read_sysfs("/sys/class/drm/card0/power/rc6_residency_ms", NULL);
+       rc6p_before = read_sysfs("/sys/class/drm/card0/power/rc6p_residency_ms", NULL);
+       rc6pp_before = read_sysfs("/sys/class/drm/card0/power/rc6pp_residency_ms", NULL);
+
+       update_cstate("gpu c0", "Powered On", 0, 0, 1, 0);
+       update_cstate("gpu rc6", "RC6", 0, rc6_before, 1, 1);
+       update_cstate("gpu rc6p", "RC6p", 0, rc6p_before, 1, 2);
+       update_cstate("gpu rc6pp", "RC6pp", 0, rc6pp_before, 1, 3);
+}
+
+char * i965_core::fill_cstate_line(int line_nr, char *buffer, const char *separator)
+{
+       buffer[0] = 0;
+       double ratio, d = -1.0, time_delta;
+
+       if (line_nr == LEVEL_HEADER) {
+               sprintf(buffer,_("  GPU "));
+               return buffer;
+       }
+
+       buffer[0] = 0;
+       
+       time_delta  = 1000000 * (after.tv_sec - before.tv_sec) + after.tv_usec - before.tv_usec;
+       ratio = 100000.0/time_delta;
+
+       switch (line_nr) {      
+       case 0:
+               d = 100.0 - ratio * (rc6_after + rc6p_after + rc6pp_after - rc6_before - rc6p_before - rc6pp_before);
+               break;
+       case 1:
+               d = ratio * (rc6_after - rc6_before);
+               break;
+       case 2:
+               d = ratio * (rc6p_after - rc6p_before);
+               break;
+       case 3:
+               d = ratio * (rc6pp_after - rc6pp_before);
+               break;
+       default:
+               return buffer;
+       }
+               
+       /* cope with rounding errors due to the measurement interval */
+       if (d < 0.0)
+               d = 0.0;
+       if (d > 100.0)
+               d = 100.0;
+       
+       sprintf(buffer,"%5.1f%%", d);
+
+       return buffer;
+}
+
+
+void i965_core::measurement_end(void)
+{
+       gettimeofday(&after, NULL);
+
+       rc6_after = read_sysfs("/sys/class/drm/card0/power/rc6_residency_ms", NULL);
+       rc6p_after = read_sysfs("/sys/class/drm/card0/power/rc6p_residency_ms", NULL);
+       rc6pp_after = read_sysfs("/sys/class/drm/card0/power/rc6pp_residency_ms", NULL);
+}
+
+char * i965_core::fill_pstate_line(int line_nr, char *buffer)
+{
+       buffer[0] = 0;
+       return buffer;
+}
+
+char * i965_core::fill_pstate_name(int line_nr, char *buffer)
+{
+       buffer[0] = 0;
+       return buffer;
+}
+
diff --git a/src/csstoh.c b/src/csstoh.c
new file mode 100644 (file)
index 0000000..28858f5
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ *     Arjan van de Ven <arjan@linux.intel.com>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+
+int main(int argc, char **argv)
+{
+       FILE *in, *out;
+       char line[4096];
+
+       if (argc < 2) {
+               printf("Usage:  csstoh cssfile header.h \n");
+               exit(0);
+       }
+       in = fopen(argv[1], "rm");
+       if (!in) {
+               printf("Failed to open input file %s (%s) \n", argv[1], strerror(errno));
+               return EXIT_FAILURE;
+       }
+       out = fopen(argv[2], "wm");
+       if (!out) {
+               printf("Failed to open output file %s (%s) \n", argv[1], strerror(errno));
+               return EXIT_FAILURE;
+       }
+
+       fprintf(out, "#ifndef __INCLUDE_GUARD_CCS_H\n");
+       fprintf(out, "#define __INCLUDE_GUARD_CCS_H\n");
+       fprintf(out, "\n");
+       fprintf(out, "const char css[] = \n");
+
+       while (!feof(in)) {
+               char *c;
+               if (fgets(line, 4095, in) == NULL)
+                       break;
+               c = strchr(line, '\n');
+               if (c) *c = 0;
+               fprintf(out, "\t\"%s\\n\"\n", line);
+       }       
+       fprintf(out, ";\n");    
+       fprintf(out, "#endif\n");
+       fclose(out);
+       fclose(in);
+       return EXIT_SUCCESS;
+}
diff --git a/src/devices/ahci.cpp b/src/devices/ahci.cpp
new file mode 100644 (file)
index 0000000..1fe39c7
--- /dev/null
@@ -0,0 +1,307 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ *     Arjan van de Ven <arjan@linux.intel.com>
+ */
+#include <iostream>
+#include <fstream>
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <dirent.h>
+
+
+using namespace std;
+
+#include "device.h"
+#include "ahci.h"
+#include "../parameters/parameters.h"
+
+#include <string.h>
+
+
+static string disk_name(char *path, char *target, char *shortname)
+{
+
+       DIR *dir;
+       struct dirent *dirent;
+       char pathname[PATH_MAX];
+       string diskname = "";
+
+       sprintf(pathname, "%s/%s", path, target);
+       dir = opendir(pathname);
+       if (!dir)
+               return diskname;
+
+       while ((dirent = readdir(dir))) {
+               char line[4096], *c;
+               FILE *file;
+               if (dirent->d_name[0]=='.')
+                       continue;
+
+               if (!strchr(dirent->d_name, ':'))
+                       continue;
+
+               sprintf(line, "%s/%s/model", pathname, dirent->d_name);
+               file = fopen(line, "r");
+               if (file) {
+                       if (fgets(line, 4096, file) == NULL)
+                               break;
+                       fclose(file);
+                       c = strchr(line, '\n');
+                       if (c)
+                               *c = 0;
+                       diskname = line;
+                       break;
+               }
+       }
+       closedir(dir);
+
+       return diskname;
+}
+
+static string model_name(char *path, char *shortname)
+{
+
+       DIR *dir;
+       struct dirent *dirent;
+       char pathname[PATH_MAX];
+
+       sprintf(pathname, "%s/device", path);
+
+       dir = opendir(pathname);
+       if (!dir)
+               return strdup(shortname);
+
+       while ((dirent = readdir(dir))) {
+               if (dirent->d_name[0]=='.')
+                       continue;
+
+               if (!strchr(dirent->d_name, ':'))
+                       continue;
+               if (!strstr(dirent->d_name, "target"))
+                       continue;
+               return disk_name(pathname, dirent->d_name, shortname);
+       }
+       closedir(dir);
+
+       return "";
+}
+
+ahci::ahci(char *_name, char *path): device()
+{
+       char buffer[4096];
+       char devname[128];
+       string diskname;
+
+       end_active = 0;
+       end_slumber = 0;
+       end_partial = 0;
+       start_active = 0;
+       start_slumber = 0;
+       start_partial = 0;
+       strncpy(sysfs_path, path, sizeof(sysfs_path));
+
+       register_sysfs_path(sysfs_path);
+
+       sprintf(devname, "ahci:%s", _name);
+       strncpy(name, devname, sizeof(name));
+       active_index = get_param_index("ahci-link-power-active");
+       partial_index = get_param_index("ahci-link-power-partial");
+
+       sprintf(buffer, "%s-active", name);
+       active_rindex = get_result_index(buffer);
+
+       sprintf(buffer, "%s-partial", name);
+       partial_rindex = get_result_index(buffer);
+
+       diskname = model_name(path, _name);
+
+       if (strlen(diskname.c_str()) == 0)
+               sprintf(humanname, _("SATA link: %s"), _name);
+       else
+               sprintf(humanname, _("SATA disk: %s"), diskname.c_str());
+
+}
+
+void ahci::start_measurement(void)
+{
+       char filename[4096];
+       ifstream file;
+
+       sprintf(filename, "%s/ahci_alpm_active", sysfs_path);
+       try {
+               file.open(filename, ios::in);
+               if (file) {
+                       file >> start_active;
+               }
+               file.close();
+               sprintf(filename, "%s/ahci_alpm_partial", sysfs_path);
+               file.open(filename, ios::in);
+
+               if (file) {
+                       file >> start_partial;
+               }
+               file.close();
+               sprintf(filename, "%s/ahci_alpm_slumber", sysfs_path);
+               file.open(filename, ios::in);
+               if (file) {
+                               file >> start_slumber;
+               }
+               file.close();
+       }
+       catch (std::ios_base::failure &c) {
+               fprintf(stderr, "%s\n", c.what());
+       }
+
+}
+
+void ahci::end_measurement(void)
+{
+       char filename[4096];
+       char powername[4096];
+       ifstream file;
+       double p;
+
+       try {
+               sprintf(filename, "%s/ahci_alpm_active", sysfs_path);
+               file.open(filename, ios::in);
+               if (file) {
+                       file >> end_active;
+               }
+               file.close();
+               sprintf(filename, "%s/ahci_alpm_partial", sysfs_path);
+               file.open(filename, ios::in);
+               if (file) {
+                       file >> end_partial;
+               }
+               file.close();
+               sprintf(filename, "%s/ahci_alpm_slumber", sysfs_path);
+               file.open(filename, ios::in);
+               if (file) {
+                       file >> end_slumber;
+               }
+               file.close();
+       }
+       catch (std::ios_base::failure &c) {
+               fprintf(stderr, "%s\n", c.what());
+       }
+       if (end_active < start_active)
+               end_active = start_active;
+
+       p = (end_active - start_active) / (0.001 + end_active + end_partial + end_slumber - start_active - start_partial - start_slumber) * 100.0;
+       if (p < 0)
+                p = 0;
+       sprintf(powername, "%s-active", name);
+       report_utilization(powername, p);
+
+       if (end_partial < start_partial)
+               end_partial = start_partial;
+
+       p = (end_partial - start_partial) / (0.001 + end_active + end_partial + end_slumber - start_active - start_partial - start_slumber) * 100.0;
+       if (p < 0)
+                p = 0;
+       sprintf(powername, "%s-partial", name);
+       report_utilization(powername, p);
+}
+
+
+double ahci::utilization(void)
+{
+       double p;
+
+       p = (end_partial - start_partial + end_active - start_active) / (0.001 + end_active + end_partial + end_slumber - start_active - start_partial - start_slumber) * 100.0;
+
+       if (p < 0)
+               p = 0;
+
+       return p;
+}
+
+const char * ahci::device_name(void)
+{
+       return name;
+}
+
+void create_all_ahcis(void)
+{
+       struct dirent *entry;
+       DIR *dir;
+       char filename[4096];
+
+       dir = opendir("/sys/class/scsi_host/");
+       if (!dir)
+               return;
+       while (1) {
+               class ahci *bl;
+               ofstream file;
+               ifstream check_file;
+               entry = readdir(dir);
+               if (!entry)
+                       break;
+               if (entry->d_name[0] == '.')
+                       continue;
+               sprintf(filename, "/sys/class/scsi_host/%s/ahci_alpm_accounting", entry->d_name);
+
+               check_file.open(filename, ios::in);
+               check_file.get();
+               check_file.close();
+               if (check_file.bad())
+                       continue;
+               
+               file.open(filename, ios::in);
+               if (!file)
+                       continue;
+               file << 1 ;
+               file.close();
+               sprintf(filename, "/sys/class/scsi_host/%s", entry->d_name);
+
+               bl = new class ahci(entry->d_name, filename);
+               all_devices.push_back(bl);
+               register_parameter("ahci-link-power-active", 0.6);  /* active sata link takes about 0.6 W */
+               register_parameter("ahci-link-power-partial");
+       }
+       closedir(dir);
+
+}
+
+
+
+double ahci::power_usage(struct result_bundle *result, struct parameter_bundle *bundle)
+{
+       double power;
+       double factor;
+       double util;
+
+       power = 0;
+
+       factor = get_parameter_value(active_index, bundle);
+       util = get_result_value(active_rindex, result);
+       power += util * factor / 100.0;
+
+
+       factor = get_parameter_value(partial_index, bundle);
+       util = get_result_value(partial_rindex, result);
+       power += util * factor / 100.0;
+
+       return power;
+}
diff --git a/src/devices/ahci.h b/src/devices/ahci.h
new file mode 100644 (file)
index 0000000..c2dda40
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ *     Arjan van de Ven <arjan@linux.intel.com>
+ */
+#ifndef _INCLUDE_GUARD_AHCI_H
+#define _INCLUDE_GUARD_AHCI_H
+
+
+#include <string>
+#include "device.h"
+#include "../parameters/parameters.h"
+#include <stdint.h>
+
+class ahci: public device {
+       uint64_t start_active, end_active;
+       uint64_t start_partial, end_partial;
+       uint64_t start_slumber, end_slumber;
+       char sysfs_path[4096];
+       char name[4096];
+       int partial_rindex;
+       int active_rindex;
+       int partial_index;
+       int active_index;
+       char humanname[4096];
+public:
+
+       ahci(char *_name, char *path);
+
+       virtual void start_measurement(void);
+       virtual void end_measurement(void);
+
+       virtual double  utilization(void); /* percentage */
+
+       virtual const char * class_name(void) { return "ahci";};
+
+       virtual const char * device_name(void);
+       virtual const char * human_name(void) { return humanname;};
+       virtual double power_usage(struct result_bundle *result, struct parameter_bundle *bundle);
+       virtual int power_valid(void) { return utilization_power_valid(partial_rindex) + utilization_power_valid(active_rindex);};
+       virtual int grouping_prio(void) { return 1; };
+};
+
+extern void create_all_ahcis(void);
+
+
+#endif
\ No newline at end of file
diff --git a/src/devices/alsa.cpp b/src/devices/alsa.cpp
new file mode 100644 (file)
index 0000000..33a52f5
--- /dev/null
@@ -0,0 +1,220 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ *     Arjan van de Ven <arjan@linux.intel.com>
+ */
+#include <iostream>
+#include <fstream>
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <unistd.h>
+
+
+using namespace std;
+
+#include "device.h"
+#include "alsa.h"
+#include "../parameters/parameters.h"
+
+#include "../devlist.h"
+
+#include <string.h>
+#include <unistd.h>
+
+alsa::alsa(char *_name, char *path): device()
+{
+       ifstream file;
+
+       char devname[4096];
+       char model[4096];
+       char vendor[4096];
+       end_active = 0;
+       start_active = 0;
+       end_inactive = 0;
+       start_inactive = 0;
+       strncpy(sysfs_path, path, sizeof(sysfs_path));
+
+       sprintf(devname, "alsa:%s", _name);
+       sprintf(humanname, "alsa:%s", _name);
+       strncpy(name, devname, sizeof(name));
+       rindex = get_result_index(name);
+
+       guilty[0] = 0;
+       model[0] = 0;
+       vendor[0] = 0;
+       sprintf(devname, "%s/modelname", path);
+       file.open(devname);
+       if (file) {
+               file.getline(model, 4096);
+               file.close();
+       }
+       sprintf(devname, "%s/vendor_name", path);
+       file.open(devname);
+       if (file) {
+               file.getline(vendor, 4096);
+               file.close();
+       }
+       if (strlen(model) && strlen(vendor))
+               sprintf(humanname, _("Audio codec %s: %s (%s)"), name, model, vendor);
+       else if (strlen(model))
+               sprintf(humanname, _("Audio codec %s: %s"), _name, model);
+       else if (strlen(vendor))
+               sprintf(humanname, _("Audio codec %s: %s"), _name, vendor);
+}
+
+void alsa::start_measurement(void)
+{
+       char filename[4096];
+       ifstream file;
+
+       sprintf(filename, "%s/power_off_acct", sysfs_path);
+       try {
+               file.open(filename, ios::in);
+               if (file) {
+                       file >> start_inactive;
+               }
+               file.close();
+               sprintf(filename, "%s/power_on_acct", sysfs_path);
+               file.open(filename, ios::in);
+
+               if (file) {
+                       file >> start_active;
+               }
+               file.close();
+       }
+       catch (std::ios_base::failure &c) {
+               fprintf(stderr, "%s\n", c.what());
+       }
+}
+
+void alsa::end_measurement(void)
+{
+       char filename[4096];
+       ifstream file;
+       double p;
+
+       sprintf(filename, "%s/power_off_acct", sysfs_path);
+       try {
+               file.open(filename, ios::in);
+               if (file) {
+                       file >> end_inactive;
+               }
+               file.close();
+               sprintf(filename, "%s/power_on_acct", sysfs_path);
+               file.open(filename, ios::in);
+
+               if (file) {
+                       file >> end_active;
+               }
+               file.close();
+       }
+       catch (std::ios_base::failure &c) {
+               fprintf(stderr, "%s\n", c.what());
+       }
+
+       p = (end_active - start_active) / (0.001 + end_active + end_inactive - start_active - start_inactive) * 100.0;
+       report_utilization(name, p);
+}
+
+
+double alsa::utilization(void)
+{
+       double p;
+
+       p = (end_active - start_active) / (0.001 + end_active - start_active + end_inactive - start_inactive) * 100.0;
+
+       return p;
+}
+
+const char * alsa::device_name(void)
+{
+       return name;
+}
+
+void create_all_alsa(void)
+{
+       struct dirent *entry;
+       DIR *dir;
+       char filename[4096];
+
+       dir = opendir("/sys/class/sound/card0/");
+       if (!dir)
+               return;
+       while (1) {
+               class alsa *bl;
+               ofstream file;
+               entry = readdir(dir);
+               if (!entry)
+                       break;
+               if (strncmp(entry->d_name, "hwC", 3) != 0)
+                       continue;
+               sprintf(filename, "/sys/class/sound/card0/%s/power_on_acct", entry->d_name);
+
+               if (access(filename, R_OK) != 0)
+                       continue;
+
+               sprintf(filename, "/sys/class/sound/card0/%s", entry->d_name);
+
+               bl = new class alsa(entry->d_name, filename);
+               all_devices.push_back(bl);
+               register_parameter("alsa-codec-power", 0.5);
+       }
+       closedir(dir);
+
+}
+
+
+
+double alsa::power_usage(struct result_bundle *result, struct parameter_bundle *bundle)
+{
+       double power;
+       double factor;
+       double util;
+       static int index = 0;
+
+       power = 0;
+       if (!index)
+               index = get_param_index("alsa-codec-power");
+
+       factor = get_parameter_value(index, bundle);
+
+       util = get_result_value(rindex, result);
+
+       power += util * factor / 100.0;
+
+       return power;
+}
+
+void alsa::register_power_with_devlist(struct result_bundle *results, struct parameter_bundle *bundle)
+{
+       register_devpower(&name[7], power_usage(results, bundle), this);
+}
+
+const char * alsa::human_name(void)
+{
+       sprintf(temp_buf, "%s", humanname);
+       if (strlen(guilty) > 0)
+               sprintf(temp_buf, "%s (%s)", humanname, guilty);
+       return temp_buf;
+}
diff --git a/src/devices/alsa.h b/src/devices/alsa.h
new file mode 100644 (file)
index 0000000..5aebfd7
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ *     Arjan van de Ven <arjan@linux.intel.com>
+ */
+#ifndef _INCLUDE_GUARD_ALSA_H
+#define _INCLUDE_GUARD_ALSA_H
+
+
+#include "device.h"
+#include "../parameters/parameters.h"
+
+#include <stdint.h>
+
+class alsa: public device {
+       uint64_t start_active, end_active;
+       uint64_t start_inactive, end_inactive;
+       char sysfs_path[4096];
+       char name[4096];
+       char humanname[4096];
+       char temp_buf[4096];
+       int rindex;
+public:
+
+       alsa(char *_name, char *path);
+
+       virtual void start_measurement(void);
+       virtual void end_measurement(void);
+
+       virtual double  utilization(void); /* percentage */
+
+       virtual const char * class_name(void) { return "alsa";};
+
+       virtual const char * device_name(void);
+       virtual const char * human_name(void);
+       virtual double power_usage(struct result_bundle *result, struct parameter_bundle *bundle);
+       virtual int power_valid(void) { return utilization_power_valid(rindex);};
+
+       virtual void register_power_with_devlist(struct result_bundle *results, struct parameter_bundle *bundle);
+       virtual int grouping_prio(void) { return 0; };
+
+};
+
+extern void create_all_alsa(void);
+
+
+#endif
\ No newline at end of file
diff --git a/src/devices/backlight.cpp b/src/devices/backlight.cpp
new file mode 100644 (file)
index 0000000..03aa5bc
--- /dev/null
@@ -0,0 +1,238 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ *     Arjan van de Ven <arjan@linux.intel.com>
+ */
+#include <iostream>
+#include <fstream>
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <dirent.h>
+
+
+using namespace std;
+
+#include "device.h"
+#include "backlight.h"
+#include "../parameters/parameters.h"
+
+#include <string.h>
+
+
+backlight::backlight(char *_name, char *path): device()
+{
+       char devname[128];
+       min_level = 0;
+       max_level = 0;
+       start_level = 0;
+       end_level = 0;
+       strncpy(sysfs_path, path, sizeof(sysfs_path));
+       register_sysfs_path(sysfs_path);
+       sprintf(devname, "backlight:%s", _name);
+       strncpy(name, devname, sizeof(name));
+       r_index = get_result_index(name);
+       r_index_power = 0;
+}
+
+void backlight::start_measurement(void)
+{
+       char filename[4096];
+       ifstream file;
+
+       sprintf(filename, "%s/max_brightness", sysfs_path);
+       file.open(filename, ios::in);
+       if (file) {
+               file >> max_level;
+       }
+       file.close();
+
+       sprintf(filename, "%s/actual_brightness", sysfs_path);
+       file.open(filename, ios::in);
+       if (file) {
+               file >> start_level;
+               file.close();
+       }
+}
+
+static int dpms_screen_on(void)
+{
+       DIR *dir;
+       struct dirent *entry;
+       char filename[4096];
+       char line[4096];
+       ifstream file;
+
+       dir = opendir("/sys/class/drm/card0");
+       if (!dir)
+               return 1;
+       while (1) {
+               entry = readdir(dir);
+               if (!entry)
+                       break;
+
+               if (strncmp(entry->d_name, "card", 4) != 0)
+                       continue;
+               sprintf(filename, "/sys/class/drm/card0/%s/enabled", entry->d_name);
+               file.open(filename, ios::in);
+               if (!file)
+                       continue;
+               file.getline(line, 4096);
+               file.close();
+               if (strcmp(line, "enabled") != 0)
+                       continue;
+               sprintf(filename, "/sys/class/drm/card0/%s/dpms", entry->d_name);
+               file.open(filename, ios::in);
+               if (!file)
+                       continue;
+               file.getline(line, 4096);
+               file.close();
+               if (strcmp(line, "On") == 0) {
+                       closedir(dir);
+                       return 1;
+               }
+       }
+       closedir(dir);
+       return 0;
+}
+
+void backlight::end_measurement(void)
+{
+       char filename[4096];
+       char powername[4096];
+       ifstream file;
+       double p;
+       int _backlight = 0;
+
+       sprintf(filename, "%s/actual_brightness", sysfs_path);
+       file.open(filename, ios::in);
+       if (file) {
+               file >> end_level;
+       }
+       file.close();
+
+       if (dpms_screen_on()) {
+               p = 100.0 * (end_level + start_level) / 2 / max_level;
+               _backlight = 100;
+       } else {
+               p = 0;
+       }
+
+       report_utilization(name, p);
+       sprintf(powername, "%s-power", name);
+       report_utilization(powername, _backlight);
+}
+
+
+double backlight::utilization(void)
+{
+       double p;
+
+       p = 100.0 * (end_level + start_level) / 2 / max_level;
+       return p;
+}
+
+const char * backlight::device_name(void)
+{
+       return name;
+}
+
+void create_all_backlights(void)
+{
+       struct dirent *entry;
+       DIR *dir;
+       char filename[4096];
+
+       dir = opendir("/sys/class/backlight/");
+       if (!dir)
+               return;
+       while (1) {
+               class backlight *bl;
+               entry = readdir(dir);
+               if (!entry)
+                       break;
+               if (entry->d_name[0] == '.')
+                       continue;
+               sprintf(filename, "/sys/class/backlight/%s", entry->d_name);
+               bl = new class backlight(entry->d_name, filename);
+               all_devices.push_back(bl);
+               register_parameter("backlight");
+               register_parameter("backlight-power");
+               register_parameter("backlight-boost-40", 0, 0.5);
+               register_parameter("backlight-boost-80", 0, 0.5);
+               register_parameter("backlight-boost-100", 0, 0.5);
+       }
+       closedir(dir);
+
+}
+
+
+
+double backlight::power_usage(struct result_bundle *result, struct parameter_bundle *bundle)
+{
+       double power;
+       double factor;
+       double _utilization;
+       char powername[4096];
+       static int bl_index = 0, blp_index = 0, bl_boost_index40 = 0, bl_boost_index80, bl_boost_index100;
+
+       if (!bl_index)
+               bl_index = get_param_index("backlight");
+       if (!blp_index)
+               blp_index = get_param_index("backlight-power");
+       if (!bl_boost_index40)
+               bl_boost_index40 = get_param_index("backlight-boost-40");
+       if (!bl_boost_index80)
+               bl_boost_index80 = get_param_index("backlight-boost-80");
+       if (!bl_boost_index100)
+               bl_boost_index100 = get_param_index("backlight-boost-100");
+
+       power = 0;
+       factor = get_parameter_value(bl_index, bundle);
+       _utilization = get_result_value(r_index, result);
+
+       power += _utilization * factor / 100.0;
+
+       /*
+        * most machines have a non-linear backlight scale. to compensate, add a fixed value
+        * once the brightness hits 40% and 80%
+        */
+
+       if (_utilization >=99)
+               power += get_parameter_value(bl_boost_index100, bundle);
+       else if (_utilization >=80)
+               power += get_parameter_value(bl_boost_index80, bundle);
+       else if (_utilization >=40)
+               power += get_parameter_value(bl_boost_index40, bundle);
+
+       factor = get_parameter_value(blp_index, bundle);
+
+       if (!r_index_power) {
+               sprintf(powername, "%s-power", name);
+               r_index_power = get_result_index(powername);
+       }
+       _utilization = get_result_value(r_index_power, result);
+
+       power += _utilization * factor / 100.0;
+
+       return power;
+}
diff --git a/src/devices/backlight.h b/src/devices/backlight.h
new file mode 100644 (file)
index 0000000..549654e
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ *     Arjan van de Ven <arjan@linux.intel.com>
+ */
+#ifndef _INCLUDE_GUARD_BACKLIGHT_H
+#define _INCLUDE_GUARD_BACKLIGHT_H
+
+
+#include "device.h"
+
+class backlight: public device {
+       int min_level, max_level;
+       int start_level, end_level;
+       char sysfs_path[4096];
+       char name[4096];
+       int r_index;
+       int r_index_power;
+public:
+
+       backlight(char *_name, char *path);
+
+       virtual void start_measurement(void);
+       virtual void end_measurement(void);
+
+       virtual double  utilization(void); /* percentage */
+
+       virtual const char * class_name(void) { return "backlight";};
+
+       virtual const char * device_name(void);
+       virtual const char * human_name(void) { return "Display backlight";};
+       virtual double power_usage(struct result_bundle *result, struct parameter_bundle *bundle);
+       virtual int grouping_prio(void) { return 10; };
+};
+
+extern void create_all_backlights(void);
+
+
+#endif
\ No newline at end of file
diff --git a/src/devices/device.cpp b/src/devices/device.cpp
new file mode 100644 (file)
index 0000000..00ec5e6
--- /dev/null
@@ -0,0 +1,317 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ *     Arjan van de Ven <arjan@linux.intel.com>
+ */
+
+#include "device.h"
+#include <vector>
+#include <algorithm>
+#include <stdio.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+using namespace std;
+
+#include "backlight.h"
+#include "usb.h"
+#include "ahci.h"
+#include "alsa.h"
+#include "rfkill.h"
+#include "i915-gpu.h"
+#include "thinkpad-fan.h"
+#include "thinkpad-light.h"
+#include "network.h"
+#include "runtime_pm.h"
+
+#include "../parameters/parameters.h"
+#include "../display.h"
+#include "../lib.h"
+#include "../report/report.h"
+#include "../report/report-maker.h"
+#include "../measurement/measurement.h"
+#include "../devlist.h"
+#include <unistd.h>
+
+device::device(void)
+{
+       cached_valid = 0;
+       hide = 0;
+
+       memset(guilty, 0, sizeof(guilty));
+       memset(real_path, 0, sizeof(real_path));
+}
+
+
+void device::register_sysfs_path(const char *path)
+{
+       char current_path[PATH_MAX + 1];
+       int iter = 0;
+       strcpy(current_path, path);
+
+       while (iter++ < 10) {
+               char test_path[PATH_MAX + 1];
+               sprintf(test_path, "%s/device", current_path);
+               if (access(test_path, R_OK) == 0)
+                       strcpy(current_path, test_path);
+               else
+                       break;
+       }
+
+       if (!realpath(current_path, real_path))
+               real_path[0] = 0;
+}
+
+void device::start_measurement(void)
+{
+       hide = false;
+}
+
+void device::end_measurement(void)
+{
+}
+
+double device::utilization(void)
+{
+       return 0.0;
+}
+
+
+
+vector<class device *> all_devices;
+
+
+void devices_start_measurement(void)
+{
+       unsigned int i;
+       for (i = 0; i < all_devices.size(); i++)
+               all_devices[i]->start_measurement();
+}
+
+void devices_end_measurement(void)
+{
+       unsigned int i;
+       for (i = 0; i < all_devices.size(); i++)
+               all_devices[i]->end_measurement();
+
+       clear_devpower();
+
+       for (i = 0; i < all_devices.size(); i++) {
+               all_devices[i]->hide = false;
+               all_devices[i]->register_power_with_devlist(&all_results, &all_parameters);
+       }
+}
+
+static bool power_device_sort(class device * i, class device * j)
+{
+       double pI, pJ;
+       pI = i->power_usage(&all_results, &all_parameters);
+       pJ = j->power_usage(&all_results, &all_parameters);
+
+       if (equals(pI, pJ)) {
+               int vI, vJ;
+               vI = i->power_valid();
+               vJ = j->power_valid();
+
+               if (vI != vJ)
+                       return vI > vJ;
+
+               return i->utilization() > j->utilization();
+       }
+       return pI > pJ;
+}
+
+
+void report_devices(void)
+{
+       WINDOW *win;
+       unsigned int i;
+       int show_power;
+       double pw;
+
+       char util[128];
+       char power[128];
+
+       win = get_ncurses_win("Device stats");
+        if (!win)
+                return;
+
+       show_power = global_power_valid();
+
+        wclear(win);
+        wmove(win, 2,0);
+
+       sort(all_devices.begin(), all_devices.end(), power_device_sort);
+
+
+
+       pw = global_joules_consumed();
+       if (pw > 0.0001) {
+               char buf[32];
+               wprintw(win, _("The battery reports a discharge rate of %sW\n"),
+                               fmt_prefix(pw, buf));
+       }
+
+       if (show_power) {
+               char buf[32];
+               wprintw(win, _("System baseline power is estimated at %sW\n"),
+                               fmt_prefix(get_parameter_value("base power"), buf));
+       }
+
+       if (pw > 0.0001 || show_power)
+               wprintw(win, "\n");
+       if (show_power)
+               wprintw(win, _("Power est.    Usage     Device name\n"));
+       else
+               wprintw(win, _("              Usage     Device name\n"));
+
+       for (i = 0; i < all_devices.size(); i++) {
+               double P;
+
+               util[0] = 0;
+
+               if (all_devices[i]->util_units()) {
+                       if (all_devices[i]->utilization() < 1000)
+                               sprintf(util, "%5.1f%s",  all_devices[i]->utilization(),  all_devices[i]->util_units());
+                       else
+                               sprintf(util, "%5i%s",  (int)all_devices[i]->utilization(),  all_devices[i]->util_units());
+               }
+               while (strlen(util) < 13) strcat(util, " ");
+
+               P = all_devices[i]->power_usage(&all_results, &all_parameters);
+
+               format_watts(P, power, 11);
+
+               if (!show_power || !all_devices[i]->power_valid())
+                       strcpy(power, "           ");
+
+
+               wprintw(win, "%s %s %s\n",
+                       power,
+                       util,
+                       all_devices[i]->human_name()
+                       );
+       }
+}
+
+void show_report_devices(void)
+{
+       unsigned int i;
+       int show_power;
+       double pw;
+
+       show_power = global_power_valid();
+       sort(all_devices.begin(), all_devices.end(), power_device_sort);
+
+       report.begin_section(SECTION_DEVPOWER);
+       report.add_header("Device Power Report");
+
+       pw = global_joules_consumed();
+       if (pw > 0.0001) {
+               char buf[32];
+
+               report.begin_paragraph();
+               report.addf("The battery reports a discharge rate of %sW",
+                           fmt_prefix(pw, buf));
+       }
+
+       if (show_power) {
+               char buf[32];
+
+               report.begin_paragraph();
+               report.addf("System baseline power is estimated at %sW",
+                           fmt_prefix(get_parameter_value("base power"), buf));
+       }
+
+       report.begin_table(TABLE_WIDE);
+       report.begin_row();
+       if (show_power) {
+               report.begin_cell(CELL_DEVPOWER_HEADER);
+               report.add("Power est.");
+       }
+
+       report.begin_cell(CELL_DEVPOWER_HEADER);
+       report.add("Usage");
+       report.begin_cell(CELL_DEVPOWER_DEV_NAME);
+       report.add("Device name");
+
+       for (i = 0; i < all_devices.size(); i++) {
+               double P;
+               char util[128];
+               char power[128];
+
+               util[0] = 0;
+               if (all_devices[i]->util_units()) {
+                       if (all_devices[i]->utilization() < 1000)
+                               sprintf(util, "%5.1f%s",
+                                       all_devices[i]->utilization(),
+                                       all_devices[i]->util_units());
+                       else
+                               sprintf(util, "%5i%s",
+                                       (int)all_devices[i]->utilization(),
+                                       all_devices[i]->util_units());
+               }
+
+               P = all_devices[i]->power_usage(&all_results, &all_parameters);
+               format_watts(P, power, 11);
+
+               if (!show_power || !all_devices[i]->power_valid())
+                       strcpy(power, "           ");
+
+               report.begin_row(ROW_DEVPOWER);
+               if (show_power) {
+                       report.begin_cell(CELL_DEVPOWER_POWER);
+                       report.add(power);
+               }
+
+               report.begin_cell(CELL_DEVPOWER_UTIL);
+               report.add(util);
+               report.begin_cell();
+               report.add(all_devices[i]->human_name());
+       }
+}
+
+
+void create_all_devices(void)
+{
+       create_all_backlights();
+       create_all_usb_devices();
+       create_all_ahcis();
+       create_all_alsa();
+       create_all_rfkills();
+       create_i915_gpu();
+       create_thinkpad_fan();
+       create_thinkpad_light();
+       create_all_nics();
+       create_all_runtime_pm_devices();
+}
+
+
+void clear_all_devices(void)
+{
+       unsigned int i;
+       for (i = 0; i < all_devices.size(); i++) {
+               delete all_devices[i];
+       }
+       all_devices.clear();
+}
diff --git a/src/devices/device.h b/src/devices/device.h
new file mode 100644 (file)
index 0000000..a373875
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ *     Arjan van de Ven <arjan@linux.intel.com>
+ */
+#ifndef _INCLUDE_GUARD_DEVICE_H
+#define _INCLUDE_GUARD_DEVICE_H
+
+
+#include <vector>
+#include <limits.h>
+
+struct parameter_bundle;
+struct result_bundle;
+
+class device {
+public:
+       int cached_valid;
+       bool hide;
+
+       char guilty[4096];
+       char real_path[PATH_MAX+1];
+
+       virtual void start_measurement(void);
+       virtual void end_measurement(void);
+
+       device(void);
+
+       virtual ~device() {};
+
+       void register_sysfs_path(const char *path);
+
+       virtual double  utilization(void); /* percentage */
+
+       virtual const char * util_units(void) { return "%"; };
+
+       virtual const char * class_name(void) { return "abstract device";};
+       virtual const char * device_name(void) { return "abstract device";};
+
+       virtual const char * human_name(void) { return device_name(); };
+
+       virtual double power_usage(struct result_bundle *results, struct parameter_bundle *bundle) { return 0.0; };
+
+       virtual bool show_in_list(void) {return !hide;};
+
+       virtual int power_valid(void) { return 1;};
+
+       virtual void register_power_with_devlist(struct result_bundle *results, struct parameter_bundle *bundle) { ; };
+
+       virtual int grouping_prio(void) { return 0; }; /* priority of this device class if multiple classes match to the same underlying device. 0 is lowest */
+};
+
+using namespace std;
+
+extern vector<class device *> all_devices;
+
+extern void devices_start_measurement(void);
+extern void devices_end_measurement(void);
+extern void show_report_devices(void);
+extern void report_devices(void);
+
+
+extern void create_all_devices(void);
+extern void clear_all_devices(void);
+
+#endif
diff --git a/src/devices/i915-gpu.cpp b/src/devices/i915-gpu.cpp
new file mode 100644 (file)
index 0000000..bcc07cc
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ *     Arjan van de Ven <arjan@linux.intel.com>
+ */
+#include <iostream>
+#include <fstream>
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <unistd.h>
+
+
+using namespace std;
+
+#include "device.h"
+#include "i915-gpu.h"
+#include "../parameters/parameters.h"
+#include "../process/powerconsumer.h"
+
+#include <string.h>
+#include <unistd.h>
+
+i915gpu::i915gpu(): device()
+{
+       index = get_param_index("gpu-operations");
+       rindex = get_result_index("gpu-operations");
+}
+
+void i915gpu::start_measurement(void)
+{
+}
+
+void i915gpu::end_measurement(void)
+{
+}
+
+
+double i915gpu::utilization(void)
+{
+       return  get_result_value(rindex);
+
+}
+
+void create_i915_gpu(void)
+{
+       char filename[4096];
+       class i915gpu *gpu;
+
+       strcpy(filename, "/sys/kernel/debug/tracing/events/i915/i915_gem_ring_dispatch/format");
+
+       if (access(filename, R_OK) !=0) {
+               /* try an older tracepoint */
+               strcpy(filename, "/sys/kernel/debug/tracing/events/i915/i915_gem_request_submit/format");
+               if (access(filename, R_OK) != 0)
+                       return;
+       }
+
+       register_parameter("gpu-operations");
+
+       gpu = new class i915gpu();
+       all_devices.push_back(gpu);
+}
+
+
+
+double i915gpu::power_usage(struct result_bundle *result, struct parameter_bundle *bundle)
+{
+       double power;
+       double factor;
+       double util;
+
+       power = 0;
+       factor = get_parameter_value(index, bundle);
+       util = get_result_value(rindex, result);
+
+       power += util * factor / 100.0;
+       return power;
+}
diff --git a/src/devices/i915-gpu.h b/src/devices/i915-gpu.h
new file mode 100644 (file)
index 0000000..25cf748
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ *     Arjan van de Ven <arjan@linux.intel.com>
+ */
+#ifndef _INCLUDE_GUARD_i915_GPU_H
+#define _INCLUDE_GUARD_i915_GPU_H
+
+
+#include "device.h"
+
+class i915gpu: public device {
+       int index;
+       int rindex;
+public:
+
+       i915gpu();
+
+       virtual void start_measurement(void);
+       virtual void end_measurement(void);
+
+       virtual double  utilization(void); /* percentage */
+
+       virtual const char * class_name(void) { return "GPU";};
+
+       virtual const char * device_name(void) { return "GPU";};
+       virtual double power_usage(struct result_bundle *result, struct parameter_bundle *bundle);
+       virtual bool show_in_list(void) {return false;};
+       virtual const char * util_units(void) { return " ops/s"; };
+};
+
+extern void create_i915_gpu(void);
+
+
+#endif
\ No newline at end of file
diff --git a/src/devices/network.cpp b/src/devices/network.cpp
new file mode 100644 (file)
index 0000000..3b67610
--- /dev/null
@@ -0,0 +1,419 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ *     Arjan van de Ven <arjan@linux.intel.com>
+ */
+#include <iostream>
+#include <fstream>
+#include <vector>
+#include <string>
+#include <map>
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <libgen.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <linux/ethtool.h>
+
+using namespace std;
+
+#include "device.h"
+#include "network.h"
+#include "../parameters/parameters.h"
+#include "../process/process.h"
+extern "C" {
+#include "../tuning/iw.h"
+}
+
+#include <string.h>
+#include <net/if.h>
+#include <linux/sockios.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+
+static map<string, class network *> nics;
+
+#ifdef DISABLE_TRYCATCH
+
+static inline void ethtool_cmd_speed_set(struct ethtool_cmd *ep,
+                                               __u32 speed)
+{
+
+       ep->speed = (__u16)speed;
+       ep->speed_hi = (__u16)(speed >> 16);
+}
+
+static inline __u32 ethtool_cmd_speed(struct ethtool_cmd *ep)
+{
+       return (ep->speed_hi << 16) | ep->speed;
+}
+
+#endif
+
+static void do_proc_net_dev(void)
+{
+       static time_t last_time;
+       class network *dev;
+       ifstream file;
+       char line[4096];
+       char *c, *c2;
+
+       if (time(NULL) == last_time)
+               return;
+
+       last_time = time(NULL);
+
+       file.open("/proc/net/dev", ios::in);
+       if (!file)
+               return;
+
+       file.getline(line, 4096);
+       file.getline(line, 4096);
+
+       while (file) {
+               int i = 0;
+               unsigned long val = 0;
+               uint64_t pkt = 0;
+               file.getline(line, 4096);
+               c = strchr(line, ':');
+               if (!c)
+                       continue;
+               *c = 0;
+               c2 = c +1;
+               c = line; while (c && *c == ' ') c++;
+               /* c now points to the name of the nic */
+
+               dev = nics[c];
+               if (!dev)
+                       continue;
+
+               c = c2++;
+               while (c != c2 && strlen(c) > 0) {
+                       c2 = c;
+                       val = strtoull(c, &c, 10);
+                       i++;
+                       if (i == 2 || i == 10)
+                               pkt += val;
+
+               }
+               dev->pkts = pkt;
+       }
+       file.close();
+}
+
+
+network::network(const char *_name, const char *path): device()
+{
+       char line[4096];
+       std::string filename(path);
+       char devname[128];
+       start_up = 0;
+       end_up = 0;
+       start_speed = 0;
+       end_speed = 0;
+       start_pkts = 0;
+       end_pkts = 0;
+       pkts = 0;
+       valid_100 = -1;
+       valid_1000 = -1;
+       valid_high = -1;
+       valid_powerunsave = -1;
+
+       strncpy(sysfs_path, path, sizeof(sysfs_path));
+       register_sysfs_path(sysfs_path);
+       sprintf(devname, "%s", _name);
+       sprintf(humanname, "nic:%s", _name);
+       strncpy(name, devname, sizeof(name));
+
+       sprintf(devname, "%s-up", _name);
+       index_up = get_param_index(devname);
+       rindex_up = get_result_index(devname);
+
+       sprintf(devname, "%s-powerunsave", _name);
+       index_powerunsave = get_param_index(devname);
+       rindex_powerunsave = get_result_index(devname);
+
+       sprintf(devname, "%s-link-100", _name);
+       index_link_100 = get_param_index(devname);
+       rindex_link_100 = get_result_index(devname);
+
+       sprintf(devname, "%s-link-1000", _name);
+       index_link_1000 = get_param_index(devname);
+       rindex_link_1000 = get_result_index(devname);
+
+       sprintf(devname, "%s-link-high", _name);
+       index_link_high = get_param_index(devname);
+       rindex_link_high = get_result_index(devname);
+
+       sprintf(devname, "%s-packets", _name);
+       index_pkts = get_param_index(devname);
+       rindex_pkts = get_result_index(devname);
+
+       memset(line, 0, 4096);
+       filename.append("/device/driver");
+       if (readlink(filename.c_str(), line, 4096) > 0) {
+               sprintf(humanname, _("Network interface: %s (%s)"), _name,  basename(line));
+       };
+}
+
+static int net_iface_up(const char *iface)
+{
+       int sock;
+       struct ifreq ifr;
+       int ret;
+
+       memset(&ifr, 0, sizeof(struct ifreq));
+
+       sock = socket(AF_INET, SOCK_DGRAM, 0);
+       if (sock<0)
+               return 0;
+
+       strcpy(ifr.ifr_name, iface);
+
+       /* Check if the interface is up */
+       ret = ioctl(sock, SIOCGIFFLAGS, &ifr);
+       if (ret<0) {
+               close(sock);
+               return 0;
+       }
+
+       if (ifr.ifr_flags & (IFF_UP | IFF_RUNNING)) {
+               close(sock);
+               return 1;
+       }
+
+       close(sock);
+
+       return 0;
+}
+
+static int iface_link(const char *name)
+{
+       int sock;
+       struct ifreq ifr;
+       struct ethtool_value cmd;
+       int link;
+
+       memset(&ifr, 0, sizeof(struct ifreq));
+
+       sock = socket(AF_INET, SOCK_DGRAM, 0);
+       if (sock<0)
+               return 0;
+
+       strcpy(ifr.ifr_name, name);
+
+       memset(&cmd, 0, sizeof(cmd));
+
+       cmd.cmd = ETHTOOL_GLINK;
+       ifr.ifr_data = (caddr_t)&cmd;
+        ioctl(sock, SIOCETHTOOL, &ifr);
+       close(sock);
+
+       link = cmd.data;
+
+       return link;
+}
+
+
+static int iface_speed(const char *name)
+{
+       int sock;
+       struct ifreq ifr;
+       struct ethtool_cmd cmd;
+       int speed;
+
+       memset(&ifr, 0, sizeof(struct ifreq));
+
+       sock = socket(AF_INET, SOCK_DGRAM, 0);
+       if (sock<0)
+               return 0;
+
+       strcpy(ifr.ifr_name, name);
+
+       memset(&cmd, 0, sizeof(cmd));
+
+       cmd.cmd = ETHTOOL_GSET;
+       ifr.ifr_data = (caddr_t)&cmd;
+        ioctl(sock, SIOCETHTOOL, &ifr);
+       close(sock);
+
+       speed = ethtool_cmd_speed(&cmd);
+
+
+       if (speed > 0 && speed <= 100)
+               speed = 100;
+       if (speed > 100 && speed <= 1000)
+               speed = 1000;
+       if (speed == 65535 || !iface_link(name))
+               speed = 0; /* no link */
+
+       return speed;
+}
+
+void network::start_measurement(void)
+{
+       start_up = 1;
+       start_speed = 0;
+       end_up = 1;
+       end_speed = 0;
+
+       start_speed = iface_speed(name);
+
+       start_up = net_iface_up(name);
+
+       do_proc_net_dev();
+       start_pkts = pkts;
+
+       gettimeofday(&before, NULL);
+}
+
+
+void network::end_measurement(void)
+{
+       int u_100, u_1000, u_high, u_powerunsave;
+
+       gettimeofday(&after, NULL);
+
+       end_speed = iface_speed(name);
+       end_up = net_iface_up(name);
+       do_proc_net_dev();
+       end_pkts = pkts;
+
+       duration = (after.tv_sec - before.tv_sec) + (after.tv_usec - before.tv_usec) / 1000000.0;
+
+       u_100 = 0;
+       u_1000 = 0;
+       u_high = 0;
+
+       if (start_speed == 100)
+               u_100 += 50;
+       if (start_speed == 1000)
+               u_1000 += 50;
+       if (start_speed > 1000)
+               u_high += 50;
+       if (end_speed == 100)
+               u_100 += 50;
+       if (end_speed == 1000)
+               u_1000 += 50;
+       if (end_speed > 1000)
+               u_high += 50;
+
+       if (start_pkts > end_pkts)
+               end_pkts = start_pkts;
+
+       u_powerunsave = 100 - 100 * get_wifi_power_saving(name);
+
+       report_utilization(rindex_link_100, u_100);
+       report_utilization(rindex_link_1000, u_1000);
+       report_utilization(rindex_link_high, u_high);
+       report_utilization(rindex_up, (start_up+end_up) / 2.0);
+       report_utilization(rindex_pkts, (end_pkts - start_pkts)/(duration + 0.001));
+       report_utilization(rindex_powerunsave, u_powerunsave);
+}
+
+
+double network::utilization(void)
+{
+       return (end_pkts - start_pkts) / (duration + 0.001);
+}
+
+const char * network::device_name(void)
+{
+       return name;
+}
+
+void netdev_callback(const char *d_name)
+{
+       std::string f_name("/sys/class/net/");
+       f_name.append(d_name);
+
+       network *bl = new(std::nothrow) class network(d_name, f_name.c_str());
+       if (bl) {
+               all_devices.push_back(bl);
+               nics[d_name] = bl;
+       }
+}
+
+
+void create_all_nics(callback fn)
+{
+       if (!fn)
+               fn = &netdev_callback;
+       process_directory("/sys/class/net/", fn);
+}
+
+double network::power_usage(struct result_bundle *result, struct parameter_bundle *bundle)
+{
+       double power;
+       double factor;
+       double util;
+
+       power = 0;
+       factor = get_parameter_value(index_up, bundle);
+       util = get_result_value(rindex_up, result);
+
+       power += util * factor;
+
+       if (valid_100 == -1) {
+               valid_100 = utilization_power_valid(rindex_link_100);
+               valid_1000 = utilization_power_valid(rindex_link_1000);
+               valid_high = utilization_power_valid(rindex_link_high);
+               valid_powerunsave = utilization_power_valid(rindex_powerunsave);
+       }
+
+       if (valid_100 > 0) {
+               factor = get_parameter_value(index_link_100, bundle);
+               util = get_result_value(rindex_link_100, result);
+               power += util * factor / 100;
+       }
+
+
+       if (valid_1000 > 0) {
+               factor = get_parameter_value(index_link_1000, bundle);
+               util = get_result_value(rindex_link_1000, result);
+               power += util * factor / 100;
+       }
+
+       if (valid_high > 0) {
+               factor = get_parameter_value(index_link_high, bundle);
+               util = get_result_value(rindex_link_high, result);
+               power += util * factor / 100;
+       }
+
+       if (valid_powerunsave > 0) {
+               factor = get_parameter_value(index_powerunsave, bundle);
+               util = get_result_value(rindex_powerunsave, result);
+               power += util * factor / 100;
+       }
+
+       factor = get_parameter_value(index_pkts, bundle);
+       util = get_result_value(rindex_pkts, result);
+       if (util > 5000)
+               util = 5000;
+
+       power += util * factor / 100;
+
+       return power;
+}
diff --git a/src/devices/network.h b/src/devices/network.h
new file mode 100644 (file)
index 0000000..45dc130
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ *     Arjan van de Ven <arjan@linux.intel.com>
+ */
+#ifndef _INCLUDE_GUARD_NETWORK_H
+#define _INCLUDE_GUARD_NETWORK_H
+
+#include <sys/time.h>
+
+#include "device.h"
+#include "../parameters/parameters.h"
+
+class network: public device {
+       int start_up, end_up;
+       uint64_t start_pkts, end_pkts;
+       struct timeval before, after;
+
+       int start_speed; /* 0 is "no link" */
+       int end_speed; /* 0 is "no link" */
+
+       char sysfs_path[4096];
+       char name[4096];
+       char humanname[4096];
+       int index_up;
+       int rindex_up;
+       int index_link_100;
+       int rindex_link_100;
+       int index_link_1000;
+       int rindex_link_1000;
+       int index_link_high;
+       int rindex_link_high;
+       int index_pkts;
+       int rindex_pkts;
+       int index_powerunsave;
+       int rindex_powerunsave;
+
+       int valid_100;
+       int valid_1000;
+       int valid_high;
+       int valid_powerunsave;
+public:
+       uint64_t pkts;
+       double duration;
+
+       network(const char *_name, const char *path);
+
+       virtual void start_measurement(void);
+       virtual void end_measurement(void);
+
+       virtual double  utilization(void);
+       virtual const char * util_units(void) { return " pkts/s"; };
+
+       virtual const char * class_name(void) { return "ethernet";};
+
+       virtual const char * device_name(void);
+       virtual const char * human_name(void) { return humanname; };
+       virtual double power_usage(struct result_bundle *result, struct parameter_bundle *bundle);
+       virtual int power_valid(void) { return utilization_power_valid(rindex_up) + utilization_power_valid(rindex_link_100) + utilization_power_valid(rindex_link_1000)  + utilization_power_valid(rindex_link_high);};
+       virtual int grouping_prio(void) { return 10; };
+};
+
+extern void create_all_nics(callback fn = NULL);
+
+#endif
diff --git a/src/devices/rfkill.cpp b/src/devices/rfkill.cpp
new file mode 100644 (file)
index 0000000..2404432
--- /dev/null
@@ -0,0 +1,188 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ *     Arjan van de Ven <arjan@linux.intel.com>
+ */
+#include <iostream>
+#include <fstream>
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <libgen.h>
+#include <unistd.h>
+
+
+using namespace std;
+
+#include "device.h"
+#include "rfkill.h"
+#include "../parameters/parameters.h"
+
+#include <string.h>
+#include <unistd.h>
+
+rfkill::rfkill(char *_name, char *path): device()
+{
+       char line[4096];
+       char filename[4096];
+       char devname[128];
+       start_soft = 0;
+       start_hard = 0;
+       end_soft = 0;
+       end_hard = 0;
+       strncpy(sysfs_path, path, sizeof(sysfs_path));
+       register_sysfs_path(sysfs_path);
+       sprintf(devname, "radio:%s", _name);
+       sprintf(humanname, "radio:%s", _name);
+       strncpy(name, devname, sizeof(name));
+       register_parameter(devname);
+       index = get_param_index(devname);
+       rindex = get_result_index(name);
+
+       memset(line, 0, 4096);
+       sprintf(filename, "%s/device/driver", path);
+       if (readlink(filename, line, 4096) > 0) {
+               sprintf(humanname, _("Radio device: %s"), basename(line));
+       }
+       sprintf(filename, "%s/device/device/driver", path);
+       if (readlink(filename, line, 4096) > 0) {
+               sprintf(humanname, _("Radio device: %s"), basename(line));
+       }
+}
+
+void rfkill::start_measurement(void)
+{
+       char filename[4096];
+       ifstream file;
+
+       start_hard = 1;
+       start_soft = 1;
+       end_hard = 1;
+       end_soft = 1;
+
+       sprintf(filename, "%s/hard", sysfs_path);
+       file.open(filename, ios::in);
+       if (file) {
+               file >> start_hard;
+       }
+       file.close();
+
+       sprintf(filename, "%s/soft", sysfs_path);
+       file.open(filename, ios::in);
+       if (file) {
+               file >> start_soft;
+       }
+       file.close();
+}
+
+void rfkill::end_measurement(void)
+{
+       char filename[4096];
+       ifstream file;
+
+       sprintf(filename, "%s/hard", sysfs_path);
+       file.open(filename, ios::in);
+       if (file) {
+               file >> end_hard;
+       }
+       file.close();
+       sprintf(filename, "%s/soft", sysfs_path);
+       file.open(filename, ios::in);
+       if (file) {
+               file >> end_soft;
+       }
+       file.close();
+
+       report_utilization(name, utilization());
+}
+
+
+double rfkill::utilization(void)
+{
+       double p;
+       int rfk;
+
+       rfk = start_soft+end_soft;
+       if (rfk <  start_hard+end_hard)
+               rfk = start_hard+end_hard;
+
+       p = 100 - 50.0 * rfk;
+
+       return p;
+}
+
+const char * rfkill::device_name(void)
+{
+       return name;
+}
+
+void create_all_rfkills(void)
+{
+       struct dirent *entry;
+       DIR *dir;
+       char filename[4096];
+       char name[4096];
+
+       dir = opendir("/sys/class/rfkill/");
+       if (!dir)
+               return;
+       while (1) {
+               class rfkill *bl;
+               ifstream file;
+               entry = readdir(dir);
+               if (!entry)
+                       break;
+               if (entry->d_name[0] == '.')
+                       continue;
+               sprintf(filename, "/sys/class/rfkill/%s/name", entry->d_name);
+               strcpy(name, entry->d_name);
+               file.open(filename, ios::in);
+               if (file) {
+                       file.getline(name, 100);
+                       file.close();
+               }
+
+               sprintf(filename, "/sys/class/rfkill/%s", entry->d_name);
+               bl = new class rfkill(name, filename);
+               all_devices.push_back(bl);
+       }
+       closedir(dir);
+
+}
+
+
+
+double rfkill::power_usage(struct result_bundle *result, struct parameter_bundle *bundle)
+{
+       double power;
+       double factor;
+       double util;
+
+       power = 0;
+       factor = get_parameter_value(index, bundle);
+       util = get_result_value(rindex, result);
+
+       power += util * factor / 100.0;
+
+       return power;
+}
\ No newline at end of file
diff --git a/src/devices/rfkill.h b/src/devices/rfkill.h
new file mode 100644 (file)
index 0000000..c24e03b
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ *     Arjan van de Ven <arjan@linux.intel.com>
+ */
+#ifndef _INCLUDE_GUARD_RFKILL_H
+#define _INCLUDE_GUARD_RFKILL_H
+
+
+#include "device.h"
+#include "../parameters/parameters.h"
+
+class rfkill: public device {
+       int start_soft, end_soft;
+       int start_hard, end_hard;
+       char sysfs_path[4096];
+       char name[4096];
+       char humanname[4096];
+       int index;
+       int rindex;
+public:
+
+       rfkill(char *_name, char *path);
+
+       virtual void start_measurement(void);
+       virtual void end_measurement(void);
+
+       virtual double  utilization(void); /* percentage */
+
+       virtual const char * class_name(void) { return "radio";};
+
+       virtual const char * device_name(void);
+       virtual const char * human_name(void) { return humanname; };
+       virtual double power_usage(struct result_bundle *result, struct parameter_bundle *bundle);
+       virtual int power_valid(void) { return utilization_power_valid(rindex);};
+       virtual int grouping_prio(void) { return 5; };
+};
+
+extern void create_all_rfkills(void);
+
+
+#endif
\ No newline at end of file
diff --git a/src/devices/runtime_pm.cpp b/src/devices/runtime_pm.cpp
new file mode 100644 (file)
index 0000000..0d13cab
--- /dev/null
@@ -0,0 +1,240 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ *     Arjan van de Ven <arjan@linux.intel.com>
+ */
+#include "runtime_pm.h"
+
+#include <string.h>
+
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <dirent.h>
+
+#include "../parameters/parameters.h"
+#include "../lib.h"
+
+#include <iostream>
+#include <fstream>
+
+runtime_pmdevice::runtime_pmdevice(const char *_name, const char *path) : device()
+{
+       strcpy(sysfs_path, path);
+       register_sysfs_path(sysfs_path);
+       strcpy(name, _name);
+       sprintf(humanname, "runtime-%s", _name);
+
+       index = get_param_index(humanname);
+       r_index = get_result_index(humanname);
+
+       before_suspended_time = 0;
+       before_active_time = 0;
+        after_suspended_time = 0;
+       after_active_time = 0;
+}
+
+
+
+void runtime_pmdevice::start_measurement(void)
+{
+       char filename[4096];
+       ifstream file;
+
+       before_suspended_time = 0;
+       before_active_time = 0;
+        after_suspended_time = 0;
+       after_active_time = 0;
+
+       sprintf(filename, "%s/power/runtime_suspended_time", sysfs_path);
+       file.open(filename, ios::in);
+       if (!file)
+               return;
+       file >> before_suspended_time;
+       file.close();
+
+       sprintf(filename, "%s/power/runtime_active_time", sysfs_path);
+       file.open(filename, ios::in);
+       if (!file)
+               return;
+       file >> before_active_time;
+       file.close();
+}
+
+void runtime_pmdevice::end_measurement(void)
+{
+       char filename[4096];
+       ifstream file;
+
+       sprintf(filename, "%s/power/runtime_suspended_time", sysfs_path);
+       file.open(filename, ios::in);
+       if (!file)
+               return;
+       file >> after_suspended_time;
+       file.close();
+
+       sprintf(filename, "%s/power/runtime_active_time", sysfs_path);
+       file.open(filename, ios::in);
+       if (!file)
+               return;
+       file >> after_active_time;
+       file.close();
+}
+
+double runtime_pmdevice::utilization(void) /* percentage */
+{
+       double d;
+       d = 100 * (after_active_time - before_active_time) / (0.0001 + after_active_time - before_active_time + after_suspended_time - before_suspended_time);
+
+       if (d < 0.00)
+               d = 0.0;
+       if (d > 99.9)
+               d = 100.0;
+       return d;
+}
+
+const char * runtime_pmdevice::device_name(void)
+{
+       return name;
+}
+
+const char * runtime_pmdevice::human_name(void)
+{
+       return humanname;
+}
+
+
+double runtime_pmdevice::power_usage(struct result_bundle *result, struct parameter_bundle *bundle)
+{
+       double power;
+       double factor;
+       double util;
+
+       power = 0;
+
+       factor = get_parameter_value(index, bundle);
+       util = get_result_value(r_index, result);
+        power += util * factor / 100.0;
+
+       return power;
+}
+
+void runtime_pmdevice::set_human_name(char *_name)
+{
+       strcpy(humanname, _name);
+}
+
+
+int device_has_runtime_pm(const char *sysfs_path)
+{
+       char filename[4096];
+       ifstream file;
+       unsigned long value;
+
+       sprintf(filename, "%s/power/runtime_suspended_time", sysfs_path);
+       file.open(filename, ios::in);
+       if (!file)
+               return 0;
+       file >> value;
+       file.close();
+       if (value)
+               return 1;
+
+       sprintf(filename, "%s/power/runtime_active_time", sysfs_path);
+       file.open(filename, ios::in);
+       if (!file)
+               return 0;
+       file >> value;
+       file.close();
+       if (value)
+               return 1;
+
+       return 0;
+}
+
+
+static void do_bus(const char *bus)
+{
+       /* /sys/bus/pci/devices/0000\:00\:1f.0/power/runtime_suspended_time */
+
+       struct dirent *entry;
+       DIR *dir;
+       char filename[4096];
+
+       sprintf(filename, "/sys/bus/%s/devices/", bus);
+       dir = opendir(filename);
+       if (!dir)
+               return;
+       while (1) {
+               ifstream file;
+               class runtime_pmdevice *dev;
+               entry = readdir(dir);
+
+               if (!entry)
+                       break;
+               if (entry->d_name[0] == '.')
+                       continue;
+
+               sprintf(filename, "/sys/bus/%s/devices/%s", bus, entry->d_name);
+
+               if (!device_has_runtime_pm(filename))
+                       continue;
+
+               dev = new class runtime_pmdevice(entry->d_name, filename);
+
+               if (strcmp(bus, "pci") == 0) {
+                       uint16_t vendor = 0, device = 0;
+
+                       sprintf(filename, "/sys/bus/%s/devices/%s/vendor", bus, entry->d_name);
+
+                       file.open(filename, ios::in);
+                       if (file) {
+                               file >> hex >> vendor;
+                               file.close();
+                       }
+
+
+                       sprintf(filename, "/sys/bus/%s/devices/%s/device", bus, entry->d_name);
+                       file.open(filename, ios::in);
+                       if (file) {
+                               file >> hex >> device;
+                               file.close();
+                       }
+
+                       if (vendor && device) {
+                               char devname[4096];
+                               sprintf(devname, _("PCI Device: %s"), pci_id_to_name(vendor, device, filename, 4095));
+                               dev->set_human_name(devname);
+                       }
+               }
+               all_devices.push_back(dev);
+       }
+       closedir(dir);
+}
+
+void create_all_runtime_pm_devices(void)
+{
+       do_bus("pci");
+       do_bus("spi");
+       do_bus("platform");
+       do_bus("i2c");
+}
\ No newline at end of file
diff --git a/src/devices/runtime_pm.h b/src/devices/runtime_pm.h
new file mode 100644 (file)
index 0000000..ea09dac
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ *     Arjan van de Ven <arjan@linux.intel.com>
+ */
+#ifndef _INCLUDE_GUARD_RUNTIMEPM_H
+#define _INCLUDE_GUARD_RUNTIMEPM_H
+
+
+#include "device.h"
+#include "../parameters/parameters.h"
+
+class runtime_pmdevice: public device {
+       uint64_t before_suspended_time, before_active_time;
+       uint64_t after_suspended_time, after_active_time;
+       char sysfs_path[4096];
+       char name[4096];
+       char humanname[4096];
+       int index;
+       int r_index;
+public:
+
+       runtime_pmdevice(const char *_name, const char *path);
+
+       virtual void start_measurement(void);
+       virtual void end_measurement(void);
+
+       virtual double  utilization(void); /* percentage */
+
+       virtual const char * class_name(void) { return "runtime_pm";};
+
+       virtual const char * device_name(void);
+       virtual const char * human_name(void);
+       virtual double power_usage(struct result_bundle *result, struct parameter_bundle *bundle);
+       virtual int power_valid(void) { return utilization_power_valid(r_index);};
+
+       void set_human_name(char *name);
+       virtual int grouping_prio(void) { return 1; };
+};
+
+extern void create_all_runtime_pm_devices(void);
+
+extern int device_has_runtime_pm(const char *sysfs_path);
+
+
+#endif
\ No newline at end of file
diff --git a/src/devices/thinkpad-fan.cpp b/src/devices/thinkpad-fan.cpp
new file mode 100644 (file)
index 0000000..9f470e4
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ *     Arjan van de Ven <arjan@linux.intel.com>
+ */
+#include <iostream>
+#include <fstream>
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <math.h>
+#include <unistd.h>
+
+#include "../lib.h"
+
+
+#include "device.h"
+#include "thinkpad-fan.h"
+#include "../parameters/parameters.h"
+#include "../process/powerconsumer.h"
+
+#include <string.h>
+#include <unistd.h>
+
+thinkpad_fan::thinkpad_fan(): device()
+{
+       start_rate = 0;
+       end_rate = 0;
+       fan_index = get_param_index("thinkpad-fan");
+       fansqr_index = get_param_index("thinkpad-fan-sqr");
+       fancub_index = get_param_index("thinkpad-fan-cub");
+       r_index = get_result_index("thinkpad-fan");
+       register_sysfs_path("/sys/devices/platform/thinkpad_hwmon");
+}
+
+void thinkpad_fan::start_measurement(void)
+{
+       /* read the rpms of the fan */
+       start_rate = read_sysfs("/sys/devices/platform/thinkpad_hwmon/fan1_input");
+}
+
+void thinkpad_fan::end_measurement(void)
+{
+       end_rate = read_sysfs("/sys/devices/platform/thinkpad_hwmon/fan1_input");
+
+       report_utilization("thinkpad-fan", utilization());
+}
+
+
+double thinkpad_fan::utilization(void)
+{
+       return (start_rate+end_rate) / 2;
+}
+
+void create_thinkpad_fan(void)
+{
+       char filename[4096];
+       class thinkpad_fan *fan;
+
+       strcpy(filename, "/sys/devices/platform/thinkpad_hwmon/fan1_input");
+
+       if (access(filename, R_OK) !=0)
+               return;
+
+       register_parameter("thinkpad-fan", 10);
+       register_parameter("thinkpad-fan-sqr", 5);
+       register_parameter("thinkpad-fan-cub", 10);
+
+       fan = new class thinkpad_fan();
+       all_devices.push_back(fan);
+}
+
+
+
+double thinkpad_fan::power_usage(struct result_bundle *result, struct parameter_bundle *bundle)
+{
+       double power;
+       double factor;
+       double util;
+
+
+       power = 0;
+       util = get_result_value(r_index, result);
+
+       if (util < 0)
+               util = 0;
+
+
+       /* physics dictact that fan power goes cubic with the rpms, but there's also a linear component for friction*/
+       factor = get_parameter_value(fancub_index, bundle);
+       power += factor * pow(util / 3600.0, 3);
+
+       factor = get_parameter_value(fansqr_index, bundle) - 5.0;
+       power += factor * pow(util / 3600.0, 2);
+
+       factor = get_parameter_value(fan_index, bundle) - 10.0;
+       power += util / 5000.0 * factor;
+
+       if (power <= 0.0)
+               power = 0.0;
+
+       return power;
+}
diff --git a/src/devices/thinkpad-fan.h b/src/devices/thinkpad-fan.h
new file mode 100644 (file)
index 0000000..34c4c43
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ *     Arjan van de Ven <arjan@linux.intel.com>
+ */
+#ifndef _INCLUDE_GUARD_THINKPAD_FAN_H
+#define _INCLUDE_GUARD_THINKPAD_FAN_H
+
+
+#include "device.h"
+#include "../parameters/parameters.h"
+
+class thinkpad_fan: public device {
+       double start_rate, end_rate;
+       int fan_index, fansqr_index, fancub_index;
+       int r_index;
+public:
+
+       thinkpad_fan();
+
+       virtual void start_measurement(void);
+       virtual void end_measurement(void);
+
+       virtual double  utilization(void); /* percentage */
+
+       virtual const char * class_name(void) { return "fan";};
+
+       virtual const char * device_name(void) { return "Fan-1";};
+       virtual const char * human_name(void) { return "Laptop fan";};
+       virtual double power_usage(struct result_bundle *result, struct parameter_bundle *bundle);
+       virtual const char * util_units(void) { return " rpm"; };
+       virtual int power_valid(void) { return utilization_power_valid(r_index);};
+       virtual int grouping_prio(void) { return 1; };
+};
+
+extern void create_thinkpad_fan(void);
+
+
+#endif
\ No newline at end of file
diff --git a/src/devices/thinkpad-light.cpp b/src/devices/thinkpad-light.cpp
new file mode 100644 (file)
index 0000000..e5fde10
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ *     Arjan van de Ven <arjan@linux.intel.com>
+ */
+#include <iostream>
+#include <fstream>
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <math.h>
+#include <unistd.h>
+
+#include "../lib.h"
+
+
+#include "device.h"
+#include "thinkpad-light.h"
+#include "../parameters/parameters.h"
+#include "../process/powerconsumer.h"
+
+#include <string.h>
+#include <unistd.h>
+
+thinkpad_light::thinkpad_light(): device()
+{
+       start_rate = 0;
+       end_rate = 0;
+       light_index = get_param_index("thinkpad-light");
+       r_index = get_result_index("thinkpad-light");
+       register_sysfs_path("/sys/devices/platform/thinkpad_acpi/leds/tpacpi::thinklight");
+}
+
+void thinkpad_light::start_measurement(void)
+{
+       /* read the rpms of the light */
+       start_rate = read_sysfs("/sys/devices/platform/thinkpad_acpi/leds/tpacpi::thinklight/brightness");
+}
+
+void thinkpad_light::end_measurement(void)
+{
+       end_rate   = read_sysfs("/sys/devices/platform/thinkpad_acpi/leds/tpacpi::thinklight/brightness");
+
+       report_utilization("thinkpad-light", utilization());
+}
+
+
+double thinkpad_light::utilization(void)
+{
+       return (start_rate+end_rate) / 2.55 / 2.0;
+}
+
+void create_thinkpad_light(void)
+{
+       char filename[4096];
+       class thinkpad_light *light;
+
+       strcpy(filename, "/sys/devices/platform/thinkpad_acpi/leds/tpacpi::thinklight/brightness");
+
+       if (access(filename, R_OK) !=0)
+               return;
+
+       register_parameter("thinkpad-light", 10);
+
+       light = new class thinkpad_light();
+       all_devices.push_back(light);
+}
+
+
+
+double thinkpad_light::power_usage(struct result_bundle *result, struct parameter_bundle *bundle)
+{
+       double power;
+       double factor;
+       double util;
+
+
+       power = 0;
+       util = get_result_value(r_index, result);
+
+       if (util < 0)
+               util = 0;
+
+
+       factor = get_parameter_value(light_index, bundle) - 10.0;
+       power += util / 100.0 * factor;
+
+       if (power <= 0.0)
+               power = 0.0;
+
+       return power;
+}
diff --git a/src/devices/thinkpad-light.h b/src/devices/thinkpad-light.h
new file mode 100644 (file)
index 0000000..64a1789
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ *     Arjan van de Ven <arjan@linux.intel.com>
+ */
+#ifndef _INCLUDE_GUARD_THINKPAD_LIGHT_H
+#define _INCLUDE_GUARD_THINKPAD_LIGHT_H
+
+
+#include "device.h"
+#include "../parameters/parameters.h"
+
+class thinkpad_light: public device {
+       double start_rate, end_rate;
+       int light_index;
+       int r_index;
+public:
+
+       thinkpad_light();
+
+       virtual void start_measurement(void);
+       virtual void end_measurement(void);
+
+       virtual double  utilization(void); /* percentage */
+
+       virtual const char * class_name(void) { return "light";};
+
+       virtual const char * device_name(void) { return "Light-1";};
+       virtual const char * human_name(void) { return "Thinkpad light";};
+       virtual double power_usage(struct result_bundle *result, struct parameter_bundle *bundle);
+       virtual const char * util_units(void) { return "%"; };
+       virtual int power_valid(void) { return utilization_power_valid(r_index);};
+       virtual int grouping_prio(void) { return 1; };
+};
+
+extern void create_thinkpad_light(void);
+
+
+#endif
\ No newline at end of file
diff --git a/src/devices/usb.cpp b/src/devices/usb.cpp
new file mode 100644 (file)
index 0000000..e7542a8
--- /dev/null
@@ -0,0 +1,242 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ *     Arjan van de Ven <arjan@linux.intel.com>
+ */
+#include "usb.h"
+
+#include <string.h>
+
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <dirent.h>
+
+#include "../lib.h"
+#include "../parameters/parameters.h"
+
+#include <iostream>
+#include <fstream>
+
+usbdevice::usbdevice(const char *_name, const char *path, const char *devid): device()
+{
+       ifstream file;
+       char filename[4096];
+       char vendor[4096];
+       char product[4096];
+
+       strcpy(sysfs_path, path);
+       register_sysfs_path(sysfs_path);
+       strcpy(name, _name);
+       strcpy(devname, devid);
+       sprintf(humanname, _("USB device: %s"), pretty_print(devid, vendor, 4096));
+       active_before = 0;
+       active_after = 0;
+       connected_before = 0;
+       connected_after = 0;
+
+       index = get_param_index(devname);
+       r_index = get_result_index(name);
+       rootport = 0;
+       cached_valid = 0;
+
+
+       /* root ports and hubs should count as 0 power ... their activity is derived */
+       sprintf(filename, "%s/bDeviceClass", path);
+       file.open(filename, ios::in);
+       if (file) {
+               int dclass = 0;
+
+               file >> dclass;
+               file.close();
+               if (dclass == 9)
+                       rootport = 1;
+       };
+
+       vendor[0] = 0;
+       product[0] = 0;
+       sprintf(filename, "%s/manufacturer", path);
+       file.open(filename, ios::in);
+       if (file) {
+               file.getline(vendor, 2047);
+               if (strstr(vendor, "Linux "))
+                       vendor[0] = 0;
+               file.close();
+       };
+       sprintf(filename, "%s/product", path);
+       file.open(filename, ios::in);
+       if (file) {
+               file.getline(product, 2040);
+               file.close();
+       };
+       if (strlen(vendor) && strlen(product))
+               sprintf(humanname, _("USB device: %s (%s)"), product, vendor);
+       else if (strlen(product))
+               sprintf(humanname, _("USB device: %s"), product);
+       else if (strlen(vendor))
+               sprintf(humanname, _("USB device: %s"), vendor);
+}
+
+
+
+void usbdevice::start_measurement(void)
+{
+       ifstream file;
+       char fullpath[4096];
+
+       active_before = 0;
+       active_after = 0;
+       connected_before = 0;
+       connected_after = 0;
+
+       sprintf(fullpath, "%s/power/active_duration", sysfs_path);
+       file.open(fullpath, ios::in);
+       if (file) {
+               file >> active_before;
+       }
+       file.close();
+
+       sprintf(fullpath, "%s/power/connected_duration", sysfs_path);
+       file.open(fullpath, ios::in);
+       if (file) {
+               file >> connected_before;
+       }
+       file.close();
+}
+
+void usbdevice::end_measurement(void)
+{
+       ifstream file;
+       char fullpath[4096];
+
+       sprintf(fullpath, "%s/power/active_duration", sysfs_path);
+       file.open(fullpath, ios::in);
+       if (file) {
+               file >> active_after;
+       }
+       file.close();
+
+       sprintf(fullpath, "%s/power/connected_duration", sysfs_path);
+       file.open(fullpath, ios::in);
+       if (file) {
+               file >> connected_after;
+       }
+       file.close();
+       report_utilization(name, utilization());
+
+}
+
+double usbdevice::utilization(void) /* percentage */
+{
+       double d;
+       d = 100.0 * (active_after - active_before) / (0.01 + connected_after - connected_before);
+       if (d < 0.0)
+               d = 0.0;
+       if (d > 99.8)
+               d = 100.0;
+       return d;
+}
+
+const char * usbdevice::device_name(void)
+{
+       return name;
+}
+
+const char * usbdevice::human_name(void)
+{
+       return humanname;
+}
+
+
+double usbdevice::power_usage(struct result_bundle *result, struct parameter_bundle *bundle)
+{
+       double power;
+       double factor;
+       double util;
+
+       if (rootport || !cached_valid)
+               return 0.0;
+
+
+       power = 0;
+       factor = get_parameter_value(index, bundle);
+       util = get_result_value(r_index, result);
+
+       power += util * factor / 100.0;
+
+       return power;
+}
+
+
+void create_all_usb_devices(void)
+{
+       struct dirent *entry;
+       DIR *dir;
+       char filename[4096];
+
+       dir = opendir("/sys/bus/usb/devices/");
+       if (!dir)
+               return;
+       while (1) {
+               ifstream file;
+               class usbdevice *usb;
+               char device_name[4096];
+               char vendorid[64], devid[64];
+               char devid_name[4096];
+               entry = readdir(dir);
+
+               if (!entry)
+                       break;
+               if (entry->d_name[0] == '.')
+                       continue;
+
+               sprintf(filename, "/sys/bus/usb/devices/%s", entry->d_name);
+
+               sprintf(device_name, "%s/power/active_duration", filename);
+               if (access(device_name, R_OK)!=0)
+                       continue;
+
+               sprintf(device_name, "%s/idVendor", filename);
+               file.open(device_name, ios::in);
+               if (file)
+                       file.getline(vendorid, 64);
+               file.close();
+               sprintf(device_name, "%s/idProduct", filename);
+               file.open(device_name, ios::in);
+               if (file)
+                       file.getline(devid, 64);
+               file.close();
+
+               sprintf(devid_name, "usb-device-%s-%s", vendorid, devid);
+
+               sprintf(device_name, "usb-device-%s-%s-%s", entry->d_name, vendorid, devid);
+
+               if (result_device_exists(device_name))
+                       continue;
+
+               usb = new class usbdevice(device_name, filename, devid_name);
+               all_devices.push_back(usb);
+
+               register_parameter(devid_name, 0.1);
+       }
+       closedir(dir);
+}
diff --git a/src/devices/usb.h b/src/devices/usb.h
new file mode 100644 (file)
index 0000000..39a746a
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ *     Arjan van de Ven <arjan@linux.intel.com>
+ */
+#ifndef _INCLUDE_GUARD_USB_H
+#define _INCLUDE_GUARD_USB_H
+
+
+#include "device.h"
+#include "../parameters/parameters.h"
+
+class usbdevice: public device {
+       int active_before, active_after;
+       int connected_before, connected_after;
+       char sysfs_path[4096];
+       char name[4096];
+       char devname[4096];
+       char humanname[4096];
+       int index;
+       int r_index;
+       int rootport;
+public:
+
+       usbdevice(const char *_name, const char *path, const char *devid);
+
+       virtual void start_measurement(void);
+       virtual void end_measurement(void);
+
+       virtual double  utilization(void); /* percentage */
+
+       virtual const char * class_name(void) { return "usb";};
+
+       virtual const char * device_name(void);
+       virtual const char * human_name(void);
+       virtual double power_usage(struct result_bundle *result, struct parameter_bundle *bundle);
+       virtual int power_valid(void) { return utilization_power_valid(r_index);};
+       virtual int grouping_prio(void) { return 4; };
+};
+
+extern void create_all_usb_devices(void);
+
+
+#endif
\ No newline at end of file
diff --git a/src/devlist.cpp b/src/devlist.cpp
new file mode 100644 (file)
index 0000000..633a568
--- /dev/null
@@ -0,0 +1,321 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ *     Arjan van de Ven <arjan@linux.intel.com>
+ */
+
+/*
+ * Code to track centrally which process has what /dev files open
+ */
+#include <iostream>
+#include <stdlib.h>
+#include <stdio.h>
+#include <time.h>
+#include <sys/stat.h>
+#include <vector>
+#include <algorithm>
+#include <unistd.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <string.h>
+#include <ctype.h>
+
+using namespace std;
+
+#include "devlist.h"
+#include "lib.h"
+#include "report/report.h"
+#include "report/report-maker.h"
+
+#include "process/process.h"
+#include "devices/device.h"
+/*
+
+* collect list of processes that have devices open
+  (alternate between before and after lists)
+
+* charge a "surcharge" to a device (sub)string
+  - count how many openers
+  - add proprotion to each process that has it open
+
+* list of devices + power they use for processing
+
+*/
+
+static vector<struct devuser *> one;
+static vector<struct devuser *> two;
+
+static int phase;
+/*
+ * 0 - one = before,  two = after
+ * 1 - one = after,   two = before
+ */
+
+
+
+void collect_open_devices(void)
+{
+       struct dirent *entry;
+       DIR *dir;
+       char filename[4096];
+       char link[4096];
+       unsigned int i;
+       vector<struct devuser *> *target;
+
+       if (phase == 1)
+               target = &one;
+       else
+               target = &two;
+
+       for (i = 0; i < target->size(); i++) {
+               free((*target)[i]);
+       }
+       target->resize(0);
+
+
+       dir = opendir("/proc/");
+       if (!dir)
+               return;
+       while (1) {
+               struct dirent *entry2;
+               DIR *dir2;
+               entry = readdir(dir);
+
+               if (!entry)
+                       break;
+               if (entry->d_name[0] == '.')
+                       continue;
+               if (strcmp(entry->d_name, "self") == 0)
+                       continue;
+
+               sprintf(filename, "/proc/%s/fd/", entry->d_name);
+
+               dir2 = opendir(filename);
+               if (!dir2)
+                       continue;
+               while (1) {
+                       int ret;
+                       struct devuser * dev;
+                       entry2 = readdir(dir2);
+                       if (!entry2)
+                               break;
+                       if (!isdigit(entry2->d_name[0]))
+                               continue;
+                       sprintf(filename, "/proc/%s/fd/%s", entry->d_name, entry2->d_name);
+                       memset(link, 0, 4096);
+                       ret = readlink(filename, link, 4095);
+                       if (ret < 0)
+                               continue;
+
+                       if (strcmp(link, "/dev/null") == 0)
+                               continue;
+                       if (strcmp(link, "/dev/.udev/queue.bin") == 0)
+                               continue;
+                       if (strcmp(link, "/dev/initctl") == 0)
+                               continue;
+                       if (strcmp(link, "/dev/ptmx") == 0)
+                               continue;
+                       if (strstr(link, "/dev/pts/"))
+                               continue;
+                       if (strstr(link, "/dev/shm/"))
+                               continue;
+                       if (strstr(link, "/dev/urandom"))
+                               continue;
+                       if (strstr(link, "/dev/tty"))
+                               continue;
+
+                       if (strncmp(link, "/dev", 4)==0) {
+                               dev = (struct devuser *)malloc(sizeof(struct devuser));
+                               if (!dev)
+                                       continue;
+                               dev->pid = strtoull(entry->d_name, NULL, 10);
+                               strncpy(dev->device, link, 251);
+                               dev->device[251] = '\0';
+                               strncpy(dev->comm, read_sysfs_string("/proc/%s/comm", entry->d_name).c_str(), 31);
+                               dev->comm[31] = '\0';
+                               target->push_back(dev);
+
+                       }
+               }
+               closedir(dir2);
+       }
+       closedir(dir);
+
+       if (phase)
+               phase = 0;
+       else
+               phase = 1;
+}
+
+
+/* returns 0 if no process is identified as having the device open and a value > 0 otherwise */
+int charge_device_to_openers(const char *devstring, double power, class device *_dev)
+{
+       unsigned int i;
+       int openers = 0;
+       class process *proc;
+       /* 1. count the number of openers */
+
+       for (i = 0; i < one.size(); i++) {
+               if (strstr(one[i]->device, devstring))
+                       openers++;
+               }
+       for (i = 0; i < two.size(); i++) {
+               if (strstr(two[i]->device, devstring))
+                       openers++;
+       }
+
+
+       /* 2. divide power by this number */
+
+       if (!openers)
+               return 0;
+       power = power / openers;
+
+
+       /* 3. for each process that has it open, add the charge */
+
+       for (i = 0; i < one.size(); i++)
+               if (strstr(one[i]->device, devstring)) {
+                       proc = find_create_process(one[i]->comm, one[i]->pid);
+                       if (proc) {
+                               proc->power_charge += power;
+                               if (strlen(_dev->guilty) < 2000 && strstr(_dev->guilty, one[i]->comm) == NULL) {
+                                       strcat(_dev->guilty, one[i]->comm);
+                                       strcat(_dev->guilty, " ");
+                               }
+                       }
+               }
+
+       for (i = 0; i < two.size(); i++)
+               if (strstr(two[i]->device, devstring)) {
+                       proc = find_create_process(two[i]->comm, two[i]->pid);
+                       if (proc) {
+                               proc->power_charge += power;
+                               if (strlen(_dev->guilty) < 2000 && strstr(_dev->guilty, two[i]->comm) == NULL) {
+                                       strcat(_dev->guilty, two[i]->comm);
+                                       strcat(_dev->guilty, " ");
+                               }
+                       }
+               }
+
+
+
+       return openers;
+}
+
+static vector<struct devpower *> devpower;
+
+void clear_devpower(void)
+{
+       unsigned int i;
+
+       for (i = 0; i < devpower.size(); i++) {
+               devpower[i]->power = 0.0;
+               devpower[i]->dev->guilty[0] = 0;
+       }
+}
+
+void register_devpower(const char *devstring, double power, class device *_dev)
+{
+       unsigned int i;
+       struct devpower *dev =  NULL;
+
+       for (i = 0; i < devpower.size(); i++)
+               if (strcmp(devstring, devpower[i]->device) == 0) {
+                       dev = devpower[i];
+               }
+
+       if (!dev) {
+               dev = (struct devpower *)malloc(sizeof (struct devpower));
+               strcpy(dev->device, devstring);
+               dev->power = 0.0;
+               devpower.push_back(dev);
+       }
+       dev->dev = _dev;
+       dev->power = power;
+}
+
+void run_devpower_list(void)
+{
+       unsigned int i;
+
+       for (i = 0; i < devpower.size(); i++) {
+               int ret;
+               ret = charge_device_to_openers(devpower[i]->device, devpower[i]->power, devpower[i]->dev);
+               if (ret)
+                       devpower[i]->dev->hide = true;
+               else
+                       devpower[i]->dev->hide = false;
+
+       }
+
+}
+
+static bool devlist_sort(struct devuser * i, struct devuser * j)
+{
+       if (i->pid != j->pid)
+               return i->pid < j->pid;
+
+       return (strcmp(i->device, j->device)< 0);
+}
+
+void report_show_open_devices(void)
+{
+       vector<struct devuser *> *target;
+       unsigned int i;
+       char prev[128], proc[128];
+
+       prev[0] = 0;
+
+       if (phase == 1)
+               target = &one;
+       else
+               target = &two;
+
+       if (target->size() == 0)
+               return;
+
+       sort(target->begin(), target->end(), devlist_sort);
+
+       report.add_header("Process device activity");
+       report.begin_table(TABLE_WIDE);
+       report.begin_row();
+       report.begin_cell(CELL_DEVACTIVITY_PROCESS);
+       report.add("Process");
+       report.begin_cell(CELL_DEVACTIVITY_DEVICE);
+       report.add("Device");
+
+       for (i = 0; i < target->size(); i++) {
+               proc[0] = 0;
+
+               if (strcmp(prev, (*target)[i]->comm) != 0)
+                       sprintf(proc, "%s", (*target)[i]->comm);
+
+               report.begin_row(ROW_DEVPOWER);
+               report.begin_cell();
+               report.add(proc);
+               report.begin_cell();
+               report.add((*target)[i]->device);
+               sprintf(prev, "%s", (*target)[i]->comm);
+       }
+}
diff --git a/src/devlist.h b/src/devlist.h
new file mode 100644 (file)
index 0000000..07e48c7
--- /dev/null
@@ -0,0 +1,26 @@
+#ifndef __INCLUDE_GUARD_DEVLIST_H__
+#define __INCLUDE_GUARD_DEVLIST_H__
+
+struct devuser {
+       unsigned int pid;
+       char comm[32];
+       char device[252];
+};
+
+class device;
+
+struct devpower {
+       char device[252];
+       double power;
+       class device *dev;
+};
+
+extern void collect_open_devices(void);
+
+extern void clear_devpower(void);
+extern void register_devpower(const char *devstring, double power, class device *dev);
+extern void run_devpower_list(void);
+
+extern void report_show_open_devices(void);
+
+#endif
diff --git a/src/display.cpp b/src/display.cpp
new file mode 100644 (file)
index 0000000..c76ba27
--- /dev/null
@@ -0,0 +1,345 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ *     Arjan van de Ven <arjan@linux.intel.com>
+ */
+#include "display.h"
+#include "lib.h"
+
+#include <ncurses.h>
+
+
+#include <vector>
+#include <map>
+#include <string>
+#include <string.h>
+
+using namespace std;
+
+static int display = 0;
+
+vector<string> tab_names;
+map<string, class tab_window *> tab_windows;
+map<string, string> tab_translations;
+
+map<string, string> bottom_lines;
+
+void create_tab(const string &name, const string &translation, class tab_window *w, string bottom_line)
+{
+       if (!w)
+               w = new(class tab_window);
+
+       w->win = newpad(1000,1000);
+       tab_names.push_back(name);
+       tab_windows[name] = w;
+       tab_translations[name] = translation;
+       bottom_lines[name] = bottom_line;
+}
+
+
+void init_display(void)
+{
+       initscr();
+       start_color();
+
+       cbreak(); /* character at a time input */
+       noecho(); /* don't show the user input */
+       keypad(stdscr, TRUE); /* enable cursor/etc keys */
+
+       use_default_colors();
+
+       create_tab("Overview", _("Overview"));
+       create_tab("Idle stats", _("Idle stats"));
+       create_tab("Frequency stats", _("Frequency stats"));
+       create_tab("Device stats", _("Device stats"));
+
+       display = 1;
+}
+
+void reset_display(void)
+{
+       if (!display)
+               return;
+
+       keypad(stdscr, FALSE);
+       echo();
+       nocbreak();
+
+       resetterm();
+}
+
+
+WINDOW *tab_bar = NULL;
+WINDOW *bottom_line = NULL;
+
+static int current_tab;
+
+void show_tab(unsigned int tab)
+{
+       class tab_window *win;
+       unsigned int i;
+       int tab_pos = 17;
+       const char *c;
+
+       if (!display)
+               return;
+
+       if (tab_bar) {
+               delwin(tab_bar);
+               tab_bar = NULL;
+       }
+
+       if (bottom_line) {
+               delwin(bottom_line);
+               bottom_line = NULL;
+       }
+
+       tab_bar = newwin(1, 0, 0, 0);
+
+       wattrset(tab_bar, A_REVERSE);
+       mvwprintw(tab_bar, 0,0, "%120s", "");
+       mvwprintw(tab_bar, 0,0, "PowerTOP %s", POWERTOP_SHORT_VERSION);
+
+       bottom_line = newwin(1, 0, LINES-1, 0);
+       wattrset(bottom_line, A_REVERSE);
+       mvwprintw(bottom_line, 0,0, "%120s", "");
+
+       c = bottom_lines[tab_names[tab]].c_str();
+       if (c && strlen(c) > 0)
+               mvwprintw(bottom_line, 0,0, c);
+       else
+               mvwprintw(bottom_line, 0,0,"<ESC> %s | ",_("Exit"));
+
+
+       current_tab = tab;
+
+       for (i = 0; i < tab_names.size(); i++) {
+                       if (i == tab)
+                               wattrset(tab_bar, A_NORMAL);
+                       else
+                               wattrset(tab_bar, A_REVERSE);
+                       mvwprintw(tab_bar, 0, tab_pos, " %s ", tab_translations[tab_names[i]].c_str());
+
+                       tab_pos += 3 + tab_names[i].length();
+       }
+
+       wrefresh(tab_bar);
+       wrefresh(bottom_line);
+
+       win = tab_windows[tab_names[tab]];
+       if (!win)
+               return;
+
+       prefresh(win->win, win->ypad_pos, win->xpad_pos, 1, 0, LINES - 3, COLS - 1);
+}
+
+WINDOW *get_ncurses_win(const char *name)
+{
+       class tab_window *w;
+       WINDOW *win;
+
+       w= tab_windows[name];
+       if (!w)
+               return NULL;
+
+       win = w->win;
+
+       return win;
+}
+
+WINDOW *get_ncurses_win(int nr)
+{
+       class tab_window *w;
+       WINDOW *win;
+
+       w= tab_windows[tab_names[nr]];
+       if (!w)
+               return NULL;
+
+       win = w->win;
+
+       return win;
+}
+
+WINDOW *get_ncurses_win(const string &name)
+{
+       return get_ncurses_win(name.c_str());
+}
+
+void show_prev_tab(void)
+{
+       class tab_window *w;
+
+       if (!display)
+               return;
+       w = tab_windows[tab_names[current_tab]];
+       if (w)
+               w->hide();
+
+       current_tab --;
+       if (current_tab < 0)
+               current_tab = tab_names.size() - 1;
+
+       w = tab_windows[tab_names[current_tab]];
+       if (w)
+               w->expose();
+
+       show_tab(current_tab);
+}
+
+void show_next_tab(void)
+{
+       class tab_window *w;
+
+       if (!display)
+               return;
+
+       w = tab_windows[tab_names[current_tab]];
+       if (w)
+               w->hide();
+
+       current_tab ++;
+       if (current_tab >= (int)tab_names.size())
+               current_tab = 0;
+
+       w = tab_windows[tab_names[current_tab]];
+       if (w)
+               w->expose();
+
+       show_tab(current_tab);
+}
+
+void show_cur_tab(void)
+{
+       if (!display)
+               return;
+       show_tab(current_tab);
+}
+
+void cursor_down(void)
+{
+       class tab_window *w;
+
+       w = tab_windows[tab_names[current_tab]];
+       if (w) {
+               if (w->ypad_pos < 1000) {
+                       if (tab_names[current_tab] == "Tunables") {
+                               if ((w->cursor_pos + 7) >= LINES) { 
+                                       prefresh(w->win, ++w->ypad_pos, w->xpad_pos, 
+                                               1, 0, LINES - 3, COLS - 1);
+                               }                       
+                                       w->cursor_down(); 
+                       } else {
+                               prefresh(w->win, ++w->ypad_pos, w->xpad_pos, 
+                                       1, 0, LINES - 3, COLS - 1);
+                       }
+               }
+       }
+
+       show_cur_tab();
+}
+
+void cursor_up(void)
+{
+       class tab_window *w;
+
+       w = tab_windows[tab_names[current_tab]];
+
+       if (w) {
+               w->cursor_up(); 
+               if(w->ypad_pos > 0) {
+                       if (tab_names[current_tab] == "Tunables") {
+                               prefresh(w->win, --w->ypad_pos, w->xpad_pos, 
+                                       1, 0, LINES - 3, COLS - 1);
+                       } else {
+                               prefresh(w->win, --w->ypad_pos, w->xpad_pos, 
+                                       1, 0, LINES - 3, COLS - 1);
+                       }
+               }
+       }
+       
+       show_cur_tab();
+}
+
+void cursor_left(void)
+{
+        class tab_window *w;
+
+       w = tab_windows[tab_names[current_tab]];
+       
+       if (w) {                        
+               if (w->xpad_pos > 0) {
+                       prefresh(w->win, w->ypad_pos,--w->xpad_pos, 
+                               1, 0, LINES - 3, COLS - 1);
+               }
+       }
+}
+
+void cursor_right(void) 
+{
+        class tab_window *w;
+
+       w = tab_windows[tab_names[current_tab]];
+
+       if (w) {
+               if (w->xpad_pos < 1000) {
+                       prefresh(w->win, w->ypad_pos, ++w->xpad_pos, 
+                               1, 0, LINES - 3, COLS - 1);
+               }
+       }
+}
+
+void cursor_enter(void)
+{
+       class tab_window *w;
+
+       w = tab_windows[tab_names[current_tab]];
+
+       if (w) {
+               w->cursor_enter();
+               w->repaint();
+       }
+       show_cur_tab();
+}
+
+void window_refresh()
+{
+       class tab_window *w;
+
+       w = tab_windows[tab_names[current_tab]];
+
+       if (w) {
+               w->ypad_pos = 0;
+               w->xpad_pos = 0;
+               w->window_refresh();
+               w->repaint();
+       }
+
+       show_cur_tab();
+}
+
+int ncurses_initialized(void)
+{
+       if (display)
+               return 1;
+       return 0;
+}
diff --git a/src/display.h b/src/display.h
new file mode 100644 (file)
index 0000000..b450f8b
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ *     Arjan van de Ven <arjan@linux.intel.com>
+ */
+#ifndef __INCLUDE_GUARD_DISPLAY_H_
+#define __INCLUDE_GUARD_DISPLAY_H_
+
+
+#include <map>
+#include <string>
+#include <ncurses.h>
+
+using namespace std;
+
+extern void init_display(void);
+extern void reset_display(void);
+extern int ncurses_initialized(void);
+extern void show_tab(unsigned int tab);
+extern void show_next_tab(void);
+extern void show_prev_tab(void);
+extern void show_cur_tab(void);
+extern void cursor_up(void);
+extern void cursor_down(void);
+extern void cursor_right(void);
+extern void cursor_left(void);
+extern void cursor_enter(void);
+extern void window_refresh(void);
+
+class tab_window {
+public:
+       int cursor_pos;
+       int cursor_max;
+       short int xpad_pos, ypad_pos; 
+       WINDOW *win;
+
+       virtual void cursor_down(void) { 
+               if (cursor_pos < cursor_max ) cursor_pos++; repaint(); 
+       } ;
+       virtual void cursor_up(void) { 
+               if (cursor_pos > 0) cursor_pos--; repaint(); 
+       };
+       virtual void cursor_left(void) { };
+       virtual void cursor_right(void) { };
+
+       virtual void cursor_enter(void) { };
+       virtual void window_refresh() { };
+
+       virtual void repaint(void) { };
+       virtual void expose(void) { cursor_pos = 0; repaint();};
+       virtual void hide(void) { };
+
+       virtual ~tab_window()
+       {
+               delwin(win);
+               win = NULL;
+       }
+};
+
+extern map<string, class tab_window *> tab_windows;
+
+WINDOW *get_ncurses_win(const char *name);
+WINDOW *get_ncurses_win(const string &name);
+WINDOW *get_ncurses_win(int nr);
+
+void create_tab(const string &name, const string &translation, class tab_window *w = NULL, string bottom_line = "");
+
+#endif
diff --git a/src/lib.cpp b/src/lib.cpp
new file mode 100644 (file)
index 0000000..9838c0b
--- /dev/null
@@ -0,0 +1,443 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ *     Arjan van de Ven <arjan@linux.intel.com>
+ *     Peter Anvin
+ */
+#include <map>
+#include <string.h>
+#include <iostream>
+#include <utility>
+#include <iostream>
+#include <fstream>
+#include <string>
+#include <ctype.h>
+#include <stdio.h>
+#include <math.h>
+#include <stdlib.h>
+
+#include "lib.h"
+
+#ifndef HAVE_NO_PCI
+extern "C" {
+#include <pci/pci.h>
+}
+#endif
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <locale.h>
+#include <libintl.h>
+#include <limits>
+#include <math.h>
+#include <ncurses.h>
+
+static int kallsyms_read = 0;
+
+double percentage(double F)
+{
+       F = F * 100.0;
+//     if (F > 100.0)
+//             F = 100.0;
+       if (F < 0.0)
+               F = 0.0;
+       return F;
+}
+
+char *hz_to_human(unsigned long hz, char *buffer, int digits)
+{
+       unsigned long long Hz;
+
+       buffer[0] = 0;
+
+       Hz = hz;
+
+       /* default: just put the Number in */
+       sprintf(buffer,"%9lli", Hz);
+
+       if (Hz>1000) {
+               if (digits == 2)
+                       sprintf(buffer, "%4lli MHz", (Hz+500)/1000);
+               else
+                       sprintf(buffer, "%6lli MHz", (Hz+500)/1000);
+       }
+
+       if (Hz>1500000) {
+               if (digits == 2)
+                       sprintf(buffer, "%4.2f GHz", (Hz+5000.0)/1000000);
+               else
+                       sprintf(buffer, "%3.1f GHz", (Hz+5000.0)/1000000);
+       }
+
+       return buffer;
+}
+
+using namespace std;
+
+map<unsigned long, string> kallsyms;
+
+static void read_kallsyms(void)
+{
+       ifstream file;
+       char line[1024];
+       kallsyms_read = 1;
+
+       file.open("/proc/kallsyms", ios::in);
+
+       while (file) {
+               char *c = NULL, *c2 = NULL;
+               unsigned long address = 0;
+               memset(line, 0, 1024);
+               file.getline(line, 1024);
+               c = strchr(line, ' ');
+               if (!c)
+                       continue;
+               *c = 0;
+               c2 = c + 1;
+               if (*c2) c2++;
+               if (*c2) c2++;
+
+               address = strtoull(line, NULL, 16);
+               c = strchr(c2, '\t');
+               if (c)
+                       *c = 0;
+               if (address != 0)
+                       kallsyms[address] = c2;
+       }
+       file.close();
+}
+
+const char *kernel_function(uint64_t address)
+{
+       const char *c;
+       if (!kallsyms_read)
+               read_kallsyms();
+
+       c = kallsyms[address].c_str();
+       if (!c)
+               return "";
+       return c;
+}
+
+static int _max_cpu;
+int get_max_cpu(void)
+{
+       return _max_cpu;
+}
+
+void set_max_cpu(int cpu)
+{
+       if (cpu > _max_cpu)
+               _max_cpu = cpu;
+}
+
+
+void write_sysfs(const string &filename, const string &value)
+{
+       ofstream file;
+
+       file.open(filename.c_str(), ios::out);
+       if (!file)
+               return;
+       try
+       {
+               file << value;
+               file.close();
+       } catch (std::exception &exc) {
+               return;
+       }
+}
+
+int read_sysfs(const string &filename, bool *ok)
+{
+       ifstream file;
+       int i;
+
+       file.open(filename.c_str(), ios::in);
+       if (!file) {
+               if (ok)
+                       *ok = false;
+               return 0;
+       }
+       try
+       {
+               file >> i;
+               if (ok)
+                       *ok = true;
+       } catch (std::exception &exc) {
+               if (ok)
+                       *ok = false;
+               i = 0;
+       }
+       file.close();
+       return i;
+}
+
+string read_sysfs_string(const string &filename)
+{
+       ifstream file;
+       char content[4096];
+       char *c;
+
+       file.open(filename.c_str(), ios::in);
+       if (!file)
+               return "";
+       try
+       {
+               file.getline(content, 4096);
+               file.close();
+               c = strchr(content, '\n');
+               if (c)
+                       *c = 0;
+       } catch (std::exception &exc) {
+               file.close();
+               return "";
+       }
+       return content;
+}
+
+string read_sysfs_string(const char *format, const char *param)
+{
+       ifstream file;
+       char content[4096];
+       char *c;
+       char filename[8192];
+
+
+       snprintf(filename, 8191, format, param);
+
+       file.open(filename, ios::in);
+       if (!file)
+               return "";
+       try
+       {
+               file.getline(content, 4096);
+               file.close();
+               c = strchr(content, '\n');
+               if (c)
+                       *c = 0;
+       } catch (std::exception &exc) {
+               file.close();
+               return "";
+       }
+       return content;
+}
+
+
+void format_watts(double W, char *buffer, unsigned int len)
+{
+       buffer[0] = 0;
+       char buf[32];
+
+       sprintf(buffer, _("%7sW"), fmt_prefix(W, buf));
+
+       if (W < 0.0001)
+               sprintf(buffer, _("    0 mW"));
+
+       while (mbstowcs(NULL,buffer,0) < len)
+               strcat(buffer, " ");
+}
+
+
+#ifndef HAVE_NO_PCI
+static struct pci_access *pci_access;
+
+char *pci_id_to_name(uint16_t vendor, uint16_t device, char *buffer, int len)
+{
+       char *ret;
+
+       buffer[0] = 0;
+
+       if (!pci_access) {
+               pci_access = pci_alloc();
+               pci_init(pci_access);
+       }
+
+       ret = pci_lookup_name(pci_access, buffer, len, PCI_LOOKUP_VENDOR | PCI_LOOKUP_DEVICE, vendor, device);
+
+       return ret;
+}
+
+void end_pci_access(void)
+{
+       if (pci_access)
+               pci_free_name_list(pci_access);
+}
+
+#else
+
+char *pci_id_to_name(uint16_t vendor, uint16_t device, char *buffer, int len)
+{
+       return NULL;
+}
+
+void end_pci_access(void)
+{
+}
+
+#endif /* HAVE_NO_PCI */
+
+int utf_ok = -1;
+
+
+
+/* pretty print numbers while limiting the precision */
+char *fmt_prefix(double n, char *buf)
+{
+       static const char prefixes[] = "yzafpnum kMGTPEZY";
+       char tmpbuf[16];
+       int omag, npfx;
+       char *p, *q, pfx, *c;
+       int i;
+
+       if (utf_ok == -1) {
+               char *g;
+               g = getenv("LANG");
+               if (g && strstr(g, "UTF-8"))
+                       utf_ok = 1;
+               else
+                       utf_ok = 0;
+       }
+
+       p = buf;
+
+       *p = ' ';
+       if (n < 0.0) {
+               *p = '-';
+               n = -n;
+               p++;
+       }
+
+       snprintf(tmpbuf, sizeof tmpbuf, "%.2e", n);
+       c = strchr(tmpbuf, 'e');
+       if (!c) {
+               sprintf(buf, "NaN");
+               return buf;
+       }
+       omag = atoi(c + 1);
+
+       npfx = ((omag + 27) / 3) - (27/3);
+       omag = (omag + 27) % 3;
+
+       q = tmpbuf;
+       if (omag == 2)
+               omag = -1;
+
+       for (i = 0; i < 3; i++) {
+               while (!isdigit(*q))
+                       q++;
+               *p++ = *q++;
+               if (i == omag)
+                       *p++ = '.';
+       }
+       *p++ = ' ';
+
+       pfx = prefixes[npfx + 8];
+
+       if (pfx == ' ') {
+               /* do nothing */
+       } else if (pfx == 'u' && utf_ok > 0) {
+               strcpy(p, "µ");                /* Mu is a multibyte sequence */
+               while (*p)
+                       p++;
+       } else {
+               *p++ = pfx;
+       }
+       *p = '\0';
+
+       return buf;
+}
+
+static map<string, string> pretty_prints;
+static int pretty_print_init = 0;
+
+static void init_pretty_print(void)
+{
+       pretty_prints["[12] i8042"] = _("PS/2 Touchpad / Keyboard / Mouse");
+       pretty_prints["ahci"] = _("SATA controller");
+       pretty_prints["usb-device-8087-0020"] = _("Intel built in USB hub");
+}
+
+
+char *pretty_print(const char *str, char *buf, int len)
+{
+       const char *p;
+
+       if (!pretty_print_init)
+               init_pretty_print();
+
+       p = pretty_prints[str].c_str();
+
+       if (strlen(p) == 0)
+               p = str;
+
+       snprintf(buf, len,  "%s", p);
+
+       if (len)
+               buf[len - 1] = 0;
+       return buf;
+}
+
+int equals(double a, double b)
+{
+       return fabs(a - b) <= std::numeric_limits<double>::epsilon();
+}
+
+void process_directory(const char *d_name, callback fn)
+{
+       struct dirent *entry;
+       DIR *dir;
+       dir = opendir(d_name);
+       if (!dir)
+               return;
+       while (1) {
+               entry = readdir(dir);
+               if (!entry)
+                       break;
+               if (entry->d_name[0] == '.')
+                       continue;
+               if (strcmp(entry->d_name, "lo")==0)
+                       continue;
+
+               fn(entry->d_name);
+       }
+
+       closedir(dir);
+}
+
+int get_user_input(char *buf, unsigned sz)
+{
+       fflush(stdout);
+       echo();
+       /* Upon successful completion, these functions return OK. Otherwise, they return ERR. */
+       int ret = getnstr(buf, sz);
+       noecho();
+       fflush(stdout);
+       /* to distinguish between getnstr error and empty line */
+       return ret || strlen(buf);
+}
diff --git a/src/lib.h b/src/lib.h
new file mode 100644 (file)
index 0000000..209421a
--- /dev/null
+++ b/src/lib.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ *     Arjan van de Ven <arjan@linux.intel.com>
+ */
+#ifndef INCLUDE_GUARD_LIB_H
+#define INCLUDE_GUARD_LIB_H
+
+#include <libintl.h>
+#include <stdint.h>
+
+/* Include only for Automake builds */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#define _(STRING)    gettext(STRING)
+
+#define POWERTOP_VERSION "v"PACKAGE_VERSION
+#define POWERTOP_SHORT_VERSION PACKAGE_VERSION
+
+
+extern int get_max_cpu(void);
+extern void set_max_cpu(int cpu);
+
+extern double percentage(double F);
+extern char *hz_to_human(unsigned long hz, char *buffer, int digits = 2);
+
+
+extern const char *kernel_function(uint64_t address);
+
+
+
+
+#include <string>
+using namespace std;
+
+extern void write_sysfs(const string &filename, const string &value);
+extern int read_sysfs(const string &filename, bool *ok = NULL);
+extern string read_sysfs_string(const string &filename);
+extern string read_sysfs_string(const char *format, const char *param);
+
+extern void format_watts(double W, char *buffer, unsigned int len);
+
+extern char *pci_id_to_name(uint16_t vendor, uint16_t device, char *buffer, int len);
+extern void end_pci_access(void);
+
+
+extern char *fmt_prefix(double n, char *buf);
+extern char *pretty_print(const char *str, char *buf, int len);
+extern int equals(double a, double b);
+
+typedef void (*callback)(const char*);
+extern void process_directory(const char *d_name, callback fn);
+extern int utf_ok;
+extern int get_user_input(char *buf, unsigned sz);
+
+#endif
diff --git a/src/main.cpp b/src/main.cpp
new file mode 100644 (file)
index 0000000..e6036ae
--- /dev/null
@@ -0,0 +1,459 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * This is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * getopt code is taken from "The GNU C Library" reference manual,
+ * section 24.2 "Parsing program options using getopt"
+ * http://www.gnu.org/s/libc/manual/html_node/Getopt-Long-Option-Example.html
+ * Manual published under the terms of the Free Documentation License.
+ *
+ * Authors:
+ *     Arjan van de Ven <arjan@linux.intel.com>
+ */
+#include <iostream>
+#include <stdlib.h>
+#include <stdio.h>
+#include <time.h>
+#include <sys/stat.h>
+#include <sys/statfs.h>
+#include <getopt.h>
+#include <unistd.h>
+#include <locale.h>
+
+#include "cpu/cpu.h"
+#include "process/process.h"
+#include "perf/perf.h"
+#include "perf/perf_bundle.h"
+#include "lib.h"
+#include "../config.h"
+
+
+#include "devices/device.h"
+#include "devices/usb.h"
+#include "measurement/measurement.h"
+#include "parameters/parameters.h"
+#include "calibrate/calibrate.h"
+
+
+#include "tuning/tuning.h"
+
+#include "display.h"
+#include "devlist.h"
+#include "report/report.h"
+
+#define DEBUGFS_MAGIC          0x64626720
+
+int debug_learning = 0;
+unsigned time_out = 20;
+int leave_powertop = 0;
+
+static const struct option long_options[] =
+{
+       /* These options set a flag. */
+       {"debug", no_argument, &debug_learning, 'd'},
+       {"version", no_argument, NULL, 'V'},
+       {"help",no_argument, NULL, 'u'}, /* u for usage */
+       {"calibrate",no_argument, NULL, 'c'},
+       {"html", optional_argument, NULL, 'h'},
+       {"csv", optional_argument, NULL, 'C'},
+       {"extech", optional_argument, NULL, 'e'},
+       {"time", optional_argument, NULL, 't'},
+       {"iteration", optional_argument, NULL, 'i'},
+       {"workload", optional_argument, NULL, 'w'},
+       {"quiet", optional_argument, NULL, 'q'},
+       {NULL, 0, NULL, 0}
+};
+
+static void print_version()
+{
+       printf(_("PowerTOP version" POWERTOP_VERSION ", compiled on " __DATE__ "\n"));
+}
+
+static bool set_refresh_timeout()
+{
+       static char buf[4];
+       mvprintw(1, 0, "%s (currently %u): ", _("Set refresh time out"), time_out);
+       memset(buf, '\0', sizeof(buf));
+       get_user_input(buf, sizeof(buf) - 1);
+       show_tab(0);
+       unsigned time = strtoul(buf, NULL, 0);
+       if (!time) return 0;
+       if (time > 32) time = 32;
+       time_out = time;
+       return 1;
+}
+
+static void print_usage()
+{
+       printf("%s\n\n",_("Usage: powertop [OPTIONS]"));
+       printf("--debug \t\t %s\n",_("run in \"debug\" mode"));
+       printf("--version \t\t %s\n",_("print version information"));
+       printf("--calibrate \t\t %s\n",_("runs powertop in calibration mode"));
+       printf("--extech%s \t %s\n",_("[=devnode]"),_("uses an Extech Power Analyzer for measurements"));
+       printf("--html%s \t %s\n",_("[=FILENAME]"),_("generate a html report"));
+       printf("--csv%s \t %s\n",_("[=FILENAME]"),_("generate a csv report"));
+       printf("--time%s \t %s\n",_("[=seconds]"), _("generate a report for 'x' seconds"));
+       printf("--iteration%s\n", _("[=iterations] number of times to run each test"));
+       printf("--workload%s \t %s\n", _("[=workload]"), _("file to execute for workload"));
+       printf("--quiet \t\t %s\n", _("suppress stderr output"));
+       printf("--help \t\t\t %s\n",_("print this help menu"));
+       printf("\n");
+       printf("%s\n\n",_("For more help please refer to the README"));
+}
+
+static void do_sleep(int seconds)
+{
+       time_t target;
+       int delta;
+
+       if (!ncurses_initialized()) {
+               sleep(seconds);
+               return;
+       }
+       target = time(NULL) + seconds;
+       delta = seconds;
+       do {
+               int c;
+               usleep(6000);
+               halfdelay(delta * 10);
+
+               c = getch();
+               switch (c) {
+               case 353: 
+                       show_prev_tab();
+                       break;
+               case 9:
+                       show_next_tab(); 
+                       break;
+               case KEY_RIGHT:
+                       cursor_right(); 
+                       break;
+               case KEY_LEFT:
+                       cursor_left(); 
+                       break;
+               case KEY_NPAGE:
+               case KEY_DOWN:
+                       cursor_down();
+                       break;
+               case KEY_PPAGE:
+               case KEY_UP:
+                       cursor_up();
+                       break;
+               case 32:
+               case 10:
+                       cursor_enter();
+                       break;
+               case 's':
+                       if (set_refresh_timeout())
+                               return;
+                       break;
+               case 'r':
+                       window_refresh();
+                       return;
+               case KEY_EXIT:
+               case 'q':
+               case 27:
+                       leave_powertop = 1;
+                       return;
+               }
+
+               delta = target - time(NULL);
+               if (delta <= 0)
+                       break;
+
+       } while (1);
+}
+
+
+void one_measurement(int seconds, char *workload)
+{
+       create_all_usb_devices();
+       start_power_measurement();
+       devices_start_measurement();
+       start_process_measurement();
+       start_cpu_measurement();
+
+       if (workload && workload[0]) {
+               if (!system(workload))
+                       fprintf(stderr, _("Unknown issue running workload!\n"));
+       } else {
+               do_sleep(seconds);
+       }
+       end_cpu_measurement();
+       end_process_measurement();
+       collect_open_devices();
+       devices_end_measurement();
+       end_power_measurement();
+
+       process_cpu_data();
+       process_process_data();
+
+       /* output stats */
+       process_update_display();
+       report_summary();
+       w_display_cpu_cstates();
+       w_display_cpu_pstates();
+       report_display_cpu_cstates();
+       report_display_cpu_pstates();
+       report_process_update_display();
+
+       tuning_update_display();
+
+       end_process_data();
+
+       global_joules_consumed();
+       compute_bundle();
+
+       show_report_devices();
+       report_show_open_devices();
+
+       report_devices();
+
+       store_results(measurement_time);
+       end_cpu_data();
+}
+
+void out_of_memory()
+{
+       reset_display();
+       printf("%s...\n",_("PowerTOP is out of memory. PowerTOP is Aborting"));
+       abort();
+}
+
+void make_report(int time, char *workload, int iterations, char *file)
+{
+
+       /* one to warm up everything */
+       fprintf(stderr, _("Preparing to take measurements\n"));
+       utf_ok = 0;
+       one_measurement(1, NULL);
+
+       if (!workload[0])
+         fprintf(stderr, _("Taking %d measurement(s) for a duration of %d second(s) each.\n"),iterations,time);
+       else
+          fprintf(stderr, _("Measuring workload %s.\n"), workload);
+       for (int i=0; i != iterations; i++){
+               init_report_output(file, iterations);
+               initialize_tuning();
+               /* and then the real measurement */
+               one_measurement(time, workload);
+               report_show_tunables();
+               finish_report_output();
+               clear_tuning();
+       }
+       /* and wrap up */
+       learn_parameters(50, 0);
+       save_all_results("saved_results.powertop");
+       save_parameters("saved_parameters.powertop");
+       end_pci_access();
+       exit(0);
+}
+
+static void checkroot() {
+       int uid;
+       uid = getuid();
+
+       if (uid != 0) {
+               printf(_("PowerTOP " POWERTOP_VERSION " must be run with root privileges.\n"));
+               printf(_("exiting...\n"));
+               exit(EXIT_FAILURE);
+       }
+
+}
+
+static void powertop_init(void)
+{
+       static char initialized = 0;
+       int ret;
+       struct statfs st_fs;
+
+       if (initialized)
+               return;
+
+       checkroot();
+       ret = system("/sbin/modprobe cpufreq_stats > /dev/null 2>&1");
+       ret = system("/sbin/modprobe msr > /dev/null 2>&1");
+       statfs("/sys/kernel/debug", &st_fs);
+
+       if (st_fs.f_type != (long) DEBUGFS_MAGIC) {
+               if (access("/bin/mount", X_OK) == 0) {
+                       ret = system("/bin/mount -t debugfs debugfs /sys/kernel/debug > /dev/null 2>&1");
+               } else {
+                       ret = system("mount -t debugfs debugfs /sys/kernel/debug > /dev/null 2>&1");
+               }
+               if (ret != 0) {
+                       printf(_("Failed to mount debugfs!\n"));
+                       printf(_("exiting...\n"));
+                       exit(EXIT_FAILURE);
+               }
+       }
+
+       srand(time(NULL));
+
+       if (access("/var/cache/", W_OK) == 0)
+               mkdir("/var/cache/powertop", 0600);
+       else
+               mkdir("/data/local/powertop", 0600);
+
+       load_results("saved_results.powertop");
+       load_parameters("saved_parameters.powertop");
+
+       enumerate_cpus();
+       create_all_devices();
+       detect_power_meters();
+
+       register_parameter("base power", 100, 0.5);
+       register_parameter("cpu-wakeups", 39.5);
+       register_parameter("cpu-consumption", 1.56);
+       register_parameter("gpu-operations", 0.5576);
+       register_parameter("disk-operations-hard", 0.2);
+       register_parameter("disk-operations", 0.0);
+       register_parameter("xwakes", 0.1);
+
+        load_parameters("saved_parameters.powertop");
+
+       initialized = 1;
+}
+
+
+int main(int argc, char **argv)
+{
+       int option_index;
+       int c;
+       char filename[4096];
+       char workload[4096] = {0,};
+       int  iterations = 1;
+
+       set_new_handler(out_of_memory);
+
+       setlocale (LC_ALL, "");
+       bindtextdomain (PACKAGE, LOCALEDIR);
+       textdomain (PACKAGE);
+
+       while (1) { /* parse commandline options */
+               c = getopt_long (argc, argv, "ch:C:i:t:uVw:q", long_options, &option_index);
+               /* Detect the end of the options. */
+               if (c == -1)
+                       break;
+
+               switch (c) {
+                       case 'V':
+                               print_version();
+                               exit(0);
+                               break;
+
+                       case 'e': /* Extech power analyzer support */
+                               checkroot();
+                               extech_power_meter(optarg ? optarg : "/dev/ttyUSB0");
+                               break;
+                       case 'u':
+                               print_usage();
+                               exit(0);
+                               break;
+
+                       case 'c':
+                               powertop_init();
+                               calibrate();
+                               break;
+
+                       case 'h': /* html report */
+                               reporttype = REPORT_HTML;
+                               sprintf(filename, "%s", optarg ? optarg : "powertop.html" );
+                               break;
+
+                       case 't':
+                               time_out = (optarg ? atoi(optarg) : 20);
+                               break;
+
+                       case 'i':
+                               iterations = (optarg ? atoi(optarg) : 1);
+                               break;
+
+                       case 'w': /* measure workload */
+                               sprintf(workload, "%s", optarg ? optarg :'\0' );
+                               break;
+                       case 'q':
+                               if(freopen("/dev/null", "a", stderr))
+                                       fprintf(stderr, _("Quite mode failed!\n"));
+                               break;
+
+                       case 'C': /* csv report*/
+                               reporttype = REPORT_CSV;
+                               sprintf(filename, "%s", optarg ? optarg : "powertop.csv");
+                               break;
+                       case '?': /* Unknown option */
+                               /* getopt_long already printed an error message. */
+                               exit(0);
+                               break;
+               }
+       }
+
+       powertop_init();
+
+       if (reporttype != REPORT_OFF)
+               make_report(time_out, workload, iterations, filename);
+
+       if (debug_learning)
+               printf("Learning debugging enabled\n");
+
+       learn_parameters(250, 0);
+       save_parameters("saved_parameters.powertop");
+
+
+       if (debug_learning) {
+               learn_parameters(1000, 1);
+               dump_parameter_bundle();
+               end_pci_access();
+               exit(0);
+       }
+
+       /* first one is short to not let the user wait too long */
+       init_display();
+       one_measurement(1, NULL);
+       initialize_tuning();
+       tuning_update_display();
+       show_tab(0);
+
+       while (!leave_powertop) {
+               show_cur_tab();
+               one_measurement(time_out, NULL);
+               learn_parameters(15, 0);
+       }
+       endwin();
+       printf("%s\n", _("Leaving PowerTOP"));
+
+       end_process_data();
+       clear_process_data();
+       end_cpu_data();
+       clear_cpu_data();
+
+       save_all_results("saved_results.powertop");
+       save_parameters("saved_parameters.powertop");
+       learn_parameters(500, 0);
+       save_parameters("saved_parameters.powertop");
+       end_pci_access();
+       clear_tuning();
+       reset_display();
+
+       clear_all_devices();
+       clear_all_cpus();
+
+       return 0;
+}
diff --git a/src/measurement/acpi.cpp b/src/measurement/acpi.cpp
new file mode 100644 (file)
index 0000000..b9b10fb
--- /dev/null
@@ -0,0 +1,211 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ *     Arjan van de Ven <arjan@linux.intel.com>
+ */
+#include "measurement.h"
+#include "acpi.h"
+#include <iostream>
+#include <fstream>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+using namespace std;
+
+acpi_power_meter::acpi_power_meter(const char *acpi_name)
+{
+       rate = 0.0;
+       capacity = 0.0;
+       voltage = 0.0;
+       strncpy(battery_name, acpi_name, sizeof(battery_name));
+}
+
+/*
+present:                 yes
+capacity state:          ok
+charging state:          discharging
+present rate:            8580 mW
+remaining capacity:      34110 mWh
+present voltage:         12001 mV
+*/
+
+void acpi_power_meter::measure(void)
+{
+       char filename[4096];
+       char line[4096];
+       ifstream file;
+
+       double _rate = 0;
+       double _capacity = 0;
+       double _voltage = 0;
+
+       char rate_units[16];
+       char capacity_units[16];
+       char voltage_units[16];
+
+       rate_units[0] = 0;
+       capacity_units[0] = 0;
+       voltage_units[0] = 0;
+
+       rate = 0;
+       voltage = 0;
+       capacity = 0;
+
+       sprintf(filename, "/proc/acpi/battery/%s/state", battery_name);
+
+       file.open(filename, ios::in);
+       if (!file)
+               return;
+
+       while (file) {
+               char *c;
+               file.getline(line, 4096);
+
+               if (strstr(line, "present:") && (strstr(line, "yes") == NULL)) {
+                       return;
+               }
+               if (strstr(line, "charging state:") && (strstr(line, "discharging") == NULL)) {
+                       return; /* not discharging */
+               }
+               if (strstr(line, "present rate:")) {
+                       c = strchr(line, ':');
+                       c++;
+                       while (*c == ' ') c++;
+                       _rate = strtoull(c, NULL, 10);
+                       c = strchr(c, ' ');
+                       if (c) {
+                               c++;
+                               strcpy(rate_units, c);
+                       } else {
+                               _rate = 0;
+                               strcpy(rate_units, "Unknown");
+                       }
+
+               }
+               if (strstr(line, "remaining capacity:")) {
+                       c = strchr(line, ':');
+                       c++;
+                       while (*c == ' ') c++;
+                       _capacity = strtoull(c, NULL, 10);
+                       c = strchr(c, ' ');
+                       if (c) {
+                               c++;
+                               strcpy(capacity_units, c);
+                       } else {
+                               _capacity = 0;
+                               strcpy(capacity_units, "Unknown");
+                       }
+               }
+               if (strstr(line, "present voltage:")) {
+                       c = strchr(line, ':');
+                       c++;
+                       while (*c == ' ') c++;
+                       _voltage = strtoull(c, NULL, 10);
+                       c = strchr(c, ' ');
+                       if (c) {
+                               c++;
+                               strcpy(voltage_units, c);
+                       } else {
+                               _voltage = 0;
+                               strcpy(voltage_units, "Unknown");
+                       }
+               }
+       }
+       file.close();
+
+       /* BIOS report random crack-inspired units. Lets try to get to the Si-system units */
+
+       if (strcmp(voltage_units, "mV") == 0) {
+               _voltage = _voltage / 1000.0;
+               strcpy(voltage_units, "V");
+       }
+
+       if (strcmp(rate_units, "mW") == 0) {
+               _rate = _rate / 1000.0;
+               strcpy(rate_units, "W");
+       }
+
+       if (strcmp(rate_units, "mA") == 0) {
+               _rate = _rate / 1000.0;
+               strcpy(rate_units, "A");
+       }
+
+       if (strcmp(capacity_units, "mAh") == 0) {
+               _capacity = _capacity / 1000.0;
+               strcpy(capacity_units, "Ah");
+       }
+       if (strcmp(capacity_units, "mWh") == 0) {
+               _capacity = _capacity / 1000.0;
+               strcpy(capacity_units, "Wh");
+       }
+       if (strcmp(capacity_units, "Wh") == 0) {
+               _capacity = _capacity * 3600.0;
+               strcpy(capacity_units, "J");
+       }
+
+
+       if (strcmp(capacity_units, "Ah") == 0 && strcmp(voltage_units, "V") == 0) {
+               _capacity = _capacity * 3600.0 * _voltage;
+               strcpy(capacity_units, "J");
+       }
+
+       if (strcmp(rate_units, "A") == 0 && strcmp(voltage_units, "V")==0 ) {
+               _rate = _rate * _voltage;
+               strcpy(rate_units, "W");
+       }
+
+
+
+
+       if (strcmp(capacity_units, "J") == 0)
+               capacity = _capacity;
+       else
+               capacity = 0.0;
+
+       if (strcmp(rate_units, "W")==0)
+               rate = _rate;
+       else
+               rate = 0.0;
+
+       if (strcmp(voltage_units, "V")==0)
+               voltage = _voltage;
+       else
+               voltage = 0.0;
+}
+
+
+void acpi_power_meter::end_measurement(void)
+{
+       measure();
+}
+
+void acpi_power_meter::start_measurement(void)
+{
+       /* ACPI battery state is a lagging indication, lets only measure at the end */
+}
+
+
+double acpi_power_meter::joules_consumed(void)
+{
+       return rate;
+}
diff --git a/src/measurement/acpi.h b/src/measurement/acpi.h
new file mode 100644 (file)
index 0000000..315fddf
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ *     Arjan van de Ven <arjan@linux.intel.com>
+ */
+#ifndef __INCLUDE_GUARD_ACPI_H
+#define __INCLUDE_GUARD_ACPI_H
+
+#include "measurement.h"
+
+class acpi_power_meter: public power_meter {
+       char battery_name[256];
+
+       double capacity;
+       double rate;
+       double voltage;
+       void measure(void);
+public:
+       acpi_power_meter(const char *_battery_name);
+       virtual void start_measurement(void);
+       virtual void end_measurement(void);
+
+       virtual double joules_consumed(void);
+       virtual double dev_capacity(void) { return capacity; };
+};
+
+#endif
diff --git a/src/measurement/extech.cpp b/src/measurement/extech.cpp
new file mode 100644 (file)
index 0000000..4e8bf8a
--- /dev/null
@@ -0,0 +1,352 @@
+/*
+ *     extech - Program for controlling the extech Device
+ *     This file is part of PowerTOP
+ *
+ *      Based on earlier client by Patrick Mochel for Wattsup Pro device
+ *     Copyright (c) 2005 Patrick Mochel
+ *     Copyright (c) 2006 Intel Corporation
+ *     Copyright (c) 2011 Intel Corporation
+ *
+ *     Authors:
+ *         Patrick Mochel
+ *         Venkatesh Pallipadi
+ *         Arjan van de Ven
+ *
+ *     Thanks to Rajiv Kapoor for finding out the DTR, RTS line bits issue below
+ *     Without that this program would never work.
+ *
+ *
+ *     This program file is free software; you can redistribute it and/or modify it
+ *     under the terms of the GNU General Public License as published by the
+ *     Free Software Foundation; version 2 of the License.
+ *
+ *     This program is distributed in the hope that it will be useful, but WITHOUT
+ *     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ *     FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ *     for more details.
+ *
+ *     You should have received a copy of the GNU General Public License
+ *     along with this program in a file named COPYING; if not, write to the
+ *     Free Software Foundation, Inc,
+ *     51 Franklin Street, Fifth Floor,
+ *     Boston, MA 02110-1301 USA
+ *     or just google for it.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <termios.h>
+#include <ctype.h>
+#include <getopt.h>
+#include <time.h>
+#include <signal.h>
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+
+#include <sys/stat.h>
+
+#include "measurement.h"
+#include "extech.h"
+#include <iostream>
+#include <fstream>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+using namespace std;
+
+struct packet {
+       char    buf[256];
+       char    op[32];
+       double  watts;
+       int     len;
+};
+
+
+static int open_device(const char *device_name)
+{
+       struct stat s;
+       int ret;
+
+       ret = stat(device_name, &s);
+       if (ret < 0)
+               return -1;
+
+       if (!S_ISCHR(s.st_mode))
+               return -1;
+
+       ret = access(device_name, R_OK | W_OK);
+       if (ret)
+               return -1;
+
+       ret = open(device_name, O_RDWR | O_NONBLOCK | O_NOCTTY);
+       if (ret < 0)
+               return -1;
+
+       return ret;
+}
+
+
+static int setup_serial_device(int dev_fd)
+{
+       struct termios t;
+       int ret;
+       int flgs;
+
+       ret = tcgetattr(dev_fd, &t);
+       if (ret)
+               return ret;
+
+       cfmakeraw(&t);
+       cfsetispeed(&t, B9600);
+       cfsetospeed(&t, B9600);
+       tcflush(dev_fd, TCIFLUSH);
+
+       t.c_iflag = IGNPAR;
+       t.c_cflag = B9600 | CS8 | CREAD | CLOCAL;
+       t.c_oflag = 0;
+       t.c_lflag = 0;
+       t.c_cc[VMIN] = 2;
+       t.c_cc[VTIME] = 0;
+
+       t.c_iflag &= ~(IXON | IXOFF | IXANY);
+       t.c_oflag &= ~(IXON | IXOFF | IXANY);
+
+       ret = tcsetattr(dev_fd, TCSANOW, &t);
+
+       if (ret)
+               return ret;
+
+       /*
+        * Root caused by Rajiv Kapoor. Without this extech reads
+        * will fail
+        */
+
+       /* get DTR and RTS line bits settings */
+       ioctl(dev_fd, TIOCMGET, &flgs);
+
+       /* set DTR to 1 and RTS to 0 */
+       flgs |= TIOCM_DTR;
+       flgs &= ~TIOCM_RTS;
+       ioctl(dev_fd, TIOCMSET, &flgs);
+
+       return 0;
+}
+
+
+static unsigned int decode_extech_value(unsigned char byt3, unsigned char byt4, char *a)
+{
+       unsigned int input = ((unsigned int)byt4 << 8) + byt3;
+       unsigned int i;
+       unsigned int idx;
+       unsigned char revnum[] = { 0x0, 0x8, 0x4, 0xc,
+                                  0x2, 0xa, 0x6, 0xe,
+                                  0x1, 0x9, 0x5, 0xd,
+                                  0x3, 0xb, 0x7, 0xf};
+       unsigned char revdec[] = { 0x0, 0x2, 0x1, 0x3};
+
+       unsigned int digit_map[] = {0x2, 0x3c, 0x3c0, 0x3c00};
+       unsigned int digit_shift[] = {1, 2, 6, 10};
+
+       unsigned int sign;
+       unsigned int decimal;
+
+       /* this is basically BCD encoded floating point... but kinda weird */
+
+       decimal = (input & 0xc000) >> 14;
+       decimal = revdec[decimal];
+
+       sign = input & 0x1;
+
+       idx = 0;
+       if (sign)
+               a[idx++] = '+';
+       else
+               a[idx++] = '-';
+
+       /* first digit is only one or zero */
+       a[idx] = '0';
+       if ((input & digit_map[0]) >> digit_shift[0])
+               a[idx] += 1;
+
+       idx++;
+       /* Reverse the remaining three digits and store in the array */
+       for (i = 1; i < 4; i++) {
+               int dig = ((input & digit_map[i]) >> digit_shift[i]);
+               dig = revnum[dig];
+               if (dig > 0xa)
+                       goto error_exit;
+
+               a[idx++] = '0' + dig;
+       }
+
+       /* Fit the decimal point where appropriate */
+       for (i = 0; i < decimal; i++)
+               a[idx - i] = a[idx - i - 1];
+
+       a[idx - decimal] = '.';
+       a[++idx] = '0';
+       a[++idx] = '\0';
+
+       return 0;
+error_exit:
+       return -1;
+}
+
+static int parse_packet(struct packet * p)
+{
+       int i;
+       int ret;
+
+       p->buf[p->len] = '\0';
+
+       /*
+        * First character in 5 character block should be '02'
+        * Fifth character in 5 character block should be '03'
+        */
+       for (i = 0; i < 4; i++) {
+               if (p->buf[i * 0] != 2 || p->buf[i * 0 + 4] != 3) {
+                       printf("Invalid packet\n");
+                       return -1;
+               }
+       }
+
+       for (i = 0; i < 1; i++) {
+               ret = decode_extech_value(p->buf[5 * i + 2],
+                                         p->buf[5 * i + 3],
+                                         &(p->op[8 * i]));
+               if (ret) {
+                       printf("Invalid packet, conversion failed\n");
+                       return -1;
+               }
+               p->watts = strtod( &(p->op[8 * i]), NULL);
+       }
+       return 0;
+}
+
+
+static double extech_read(int fd)
+{
+       struct packet p;
+       fd_set read_fd;
+       struct timeval tv;
+       int ret;
+
+       if (fd < 0)
+               return 0.0;
+
+       FD_ZERO(&read_fd);
+       FD_SET(fd, &read_fd);
+
+       tv.tv_sec = 0;
+       tv.tv_usec = 500000;
+
+       memset(&p, 0, sizeof(p));
+
+       ret = select(fd + 1, &read_fd, NULL, NULL, &tv);
+       if (ret <= 0)
+               return -1;
+
+       ret = read(fd, &p.buf, 250);
+       if (ret < 0)
+               return ret;
+       p.len = ret;
+
+       if (!parse_packet(&p))
+               return p.watts;
+
+       return -1000.0;
+}
+
+extech_power_meter::extech_power_meter(const char *extech_name)
+{
+       rate = 0.0;
+       strncpy(dev_name, extech_name, sizeof(dev_name));
+       int ret;
+
+       fd = open_device(dev_name);
+       if (fd < 0)
+               return;
+
+       ret = setup_serial_device(fd);
+       if (ret) {
+               close(fd);
+               fd = -1;
+               return;
+       }
+}
+
+
+void extech_power_meter::measure(void)
+{
+       /* trigger the extech to send data */
+       write(fd, " ", 1);
+
+       rate = extech_read(fd);
+
+}
+
+void extech_power_meter::sample(void) 
+{
+       ssize_t ret;
+       struct timespec tv;
+
+       tv.tv_sec = 0;
+       tv.tv_nsec = 200000000;
+       while (!end_thread) {
+               nanosleep(&tv, NULL);
+               /* trigger the extech to send data */
+               ret = write(fd, " ", 1);
+               if (ret < 0)
+                       continue;
+               
+               sum += extech_read(fd);
+               samples++;
+       
+       }
+}
+
+extern "C"
+{
+       void* thread_proc(void *arg) 
+       {
+               class extech_power_meter *parent;
+               parent = (class extech_power_meter*)arg;
+               parent->sample();
+               return 0;
+       }
+}
+
+void extech_power_meter::end_measurement(void)
+{
+       end_thread = 1;
+       pthread_join( thread, NULL);
+       if (samples){
+               rate = sum / samples;
+       }
+       else
+               measure();
+}
+
+void extech_power_meter::start_measurement(void)
+{
+       end_thread = 0;
+       sum = samples = 0;
+       
+       if (pthread_create(&thread, NULL, thread_proc, this))
+               fprintf(stderr, "ERROR: extech measurement thread creation failed\n");
+
+}
+
+
+double extech_power_meter::joules_consumed(void)
+{
+       return rate;
+}
diff --git a/src/measurement/extech.h b/src/measurement/extech.h
new file mode 100644 (file)
index 0000000..5f4c338
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ *     Arjan van de Ven <arjan@linux.intel.com>
+ */
+#ifndef __INCLUDE_GUARD_EXTECH_H
+#define __INCLUDE_GUARD_EXTECH_H
+
+#include <pthread.h>
+#include "measurement.h"
+
+class extech_power_meter: public power_meter {
+       char dev_name[256];
+       int fd;
+
+       double rate;
+       void measure(void);
+       double sum;
+       int samples;
+       int end_thread;
+       pthread_t thread;
+public:
+       extech_power_meter(const char *_dev_name);
+       virtual void start_measurement(void);
+       virtual void end_measurement(void);
+       virtual void sample(void);
+       
+       virtual double joules_consumed(void);
+       virtual double dev_capacity(void) { return 0.0; };
+};
+
+#endif
diff --git a/src/measurement/measurement.cpp b/src/measurement/measurement.cpp
new file mode 100644 (file)
index 0000000..4a33db9
--- /dev/null
@@ -0,0 +1,177 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ *     Arjan van de Ven <arjan@linux.intel.com>
+ */
+#include "measurement.h"
+#include "acpi.h"
+#include "extech.h"
+#include "power_supply.h"
+#include "sysfs.h"
+#include "../parameters/parameters.h"
+#include "../lib.h"
+
+#include <string>
+#include <sys/types.h>
+#include <dirent.h>
+#include <stdio.h>
+#include <fstream>
+#include <unistd.h>
+
+double min_power = 50000.0;
+
+void power_meter::start_measurement(void)
+{
+}
+
+
+void power_meter::end_measurement(void)
+{
+}
+
+
+double power_meter::joules_consumed(void)
+{
+       return 0.0;
+}
+
+double power_meter::time_left(void)
+{
+       double cap, rate;
+       double left;
+
+       cap = dev_capacity();
+       rate = joules_consumed();
+
+       if (cap < 0.001)
+               return 0.0;
+
+       left = cap / rate;
+
+       return left;
+}
+
+
+vector<class power_meter *> power_meters;
+
+void start_power_measurement(void)
+{
+       unsigned int i;
+       for (i = 0; i < power_meters.size(); i++)
+               power_meters[i]->start_measurement();
+}
+void end_power_measurement(void)
+{
+       unsigned int i;
+       for (i = 0; i < power_meters.size(); i++)
+               power_meters[i]->end_measurement();
+}
+
+double global_joules_consumed(void)
+{
+       double total = 0.0;
+       unsigned int i;
+       for (i = 0; i < power_meters.size(); i++)
+               total += power_meters[i]->joules_consumed();
+
+       all_results.power = total;
+       if (total < min_power && total > 0.01)
+               min_power = total;
+       return total;
+}
+
+double global_time_left(void)
+{
+       double total = 0.0;
+       unsigned int i;
+       for (i = 0; i < power_meters.size(); i++)
+               total += power_meters[i]->time_left();
+
+       return total;
+}
+
+void sysfs_power_meters_callback(const char *d_name)
+{
+       std::string type = read_sysfs_string("/sys/class/power_supply/%s/type", d_name);
+
+       if (type != "Battery" && type != "UPS")
+               return;
+
+       class sysfs_power_meter *meter;
+       meter = new(std::nothrow) class sysfs_power_meter(d_name);
+       if (meter)
+               power_meters.push_back(meter);
+}
+
+void acpi_power_meters_callback(const char *d_name)
+{
+       class acpi_power_meter *meter;
+       meter = new(std::nothrow) class acpi_power_meter(d_name);
+       if (meter)
+               power_meters.push_back(meter);
+}
+
+void power_supply_callback(const char *d_name)
+{
+       char filename[4096];
+       char line[4096];
+       ifstream file;
+       bool discharging = false;
+
+       sprintf(filename, "/sys/class/power_supply/%s/uevent", d_name);
+       file.open(filename, ios::in);
+       if (!file)
+               return;
+
+       while (file) {
+               file.getline(line, 4096);
+
+               if (strstr(line, "POWER_SUPPLY_STATUS") && strstr(line, "Discharging"))
+                     discharging = true;
+       }
+       file.close();
+
+       if (!discharging)
+           return;
+
+       class power_supply *power;
+       power = new(std::nothrow) class power_supply(d_name);
+       if (power)
+               power_meters.push_back(power);
+}
+
+void detect_power_meters(void)
+{
+       process_directory("/sys/class/power_supply", sysfs_power_meters_callback);
+       if (power_meters.size() == 0) {
+               process_directory("/proc/acpi/battery", acpi_power_meters_callback);
+       }
+}
+
+void extech_power_meter(const char *devnode)
+{
+       class extech_power_meter *meter;
+
+       meter = new class extech_power_meter(devnode);
+
+       power_meters.push_back(meter);
+}
diff --git a/src/measurement/measurement.h b/src/measurement/measurement.h
new file mode 100644 (file)
index 0000000..5bcd8e2
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ *     Arjan van de Ven <arjan@linux.intel.com>
+ */
+#ifndef __INCLUDE_GUARD_MEASUREMENT_H
+#define __INCLUDE_GUARD_MEASUREMENT_H
+
+#include <vector>
+
+using namespace std;
+
+class power_meter {
+public:
+       virtual void start_measurement(void);
+       virtual void end_measurement(void);
+
+       virtual double joules_consumed(void);
+       virtual double dev_capacity(void) { return 0.0;};  /* in Joules */
+
+       virtual double time_left(void);
+
+       virtual ~power_meter() {};
+};
+
+
+extern vector<class power_meter *> power_meters;
+
+extern void start_power_measurement(void);
+extern void end_power_measurement(void);
+extern double global_joules_consumed(void);
+extern double global_time_left(void);
+
+extern void detect_power_meters(void);
+extern void extech_power_meter(const char *devnode);
+
+
+extern double min_power;
+
+#endif
\ No newline at end of file
diff --git a/src/measurement/power_supply.cpp b/src/measurement/power_supply.cpp
new file mode 100644 (file)
index 0000000..f514740
--- /dev/null
@@ -0,0 +1,190 @@
+/*
+ * Copyright 2011, Intel Corporation
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ *     John Mathew <johnx.mathew@intel.com>
+ */
+#include "measurement.h"
+#include "power_supply.h"
+#include <iostream>
+#include <fstream>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+using namespace std;
+
+power_supply::power_supply(const char *supply_name)
+{
+       rate = 0.0;
+       capacity = 0.0;
+       voltage = 0.0;
+       strncpy(battery_name, supply_name, sizeof(battery_name));
+}
+
+/*
+POWER_SUPPLY_NAME=msic-battery
+POWER_SUPPLY_STATUS=Discharging
+POWER_SUPPLY_HEALTH=Cold
+POWER_SUPPLY_PRESENT=1
+POWER_SUPPLY_TECHNOLOGY=Li-ion
+POWER_SUPPLY_VOLTAGE_MAX_DESIGN=4200000
+POWER_SUPPLY_VOLTAGE_NOW=4119000
+POWER_SUPPLY_CURRENT_NOW=-290000
+POWER_SUPPLY_CHARGE_NOW=1503000
+POWER_SUPPLY_CHARGE_COUNTER=-254923
+POWER_SUPPLY_CHARGE_FULL_DESIGN=1500000
+POWER_SUPPLY_CHARGE_FULL=1500000
+POWER_SUPPLY_CHARGE_AVG=32762000
+POWER_SUPPLY_ENERGY_FULL=6300000
+POWER_SUPPLY_ENERGY_NOW=6235000
+POWER_SUPPLY_CAPACITY_LEVEL=Full
+POWER_SUPPLY_CAPACITY=100
+POWER_SUPPLY_TEMP=-340
+POWER_SUPPLY_MODEL_NAME=CDK0
+POWER_SUPPLY_MANUFACTURER=IN
+
+Quoting include/linux/power_supply.h:
+
+All voltages, currents, charges, energies, time and temperatures in µV,
+µA, µAh, µWh, seconds and tenths of degree Celsius unless otherwise
+stated. It's driver's job to convert its raw values to units in which
+this class operates.
+*/
+
+void power_supply::measure(void)
+{
+       char filename[4096];
+       char line[4096];
+       ifstream file;
+
+       double _power_rate = 0;
+       double _current_rate = 0;
+       double _capacity = 0;
+       double _voltage = 0;
+
+       rate = 0;
+       voltage = 0;
+       capacity = 0;
+
+       sprintf(filename, "/sys/class/power_supply/%s/uevent", battery_name);
+
+       file.open(filename, ios::in);
+       if (!file)
+               return;
+
+       while (file) {
+               char *c;
+               file.getline(line, 4096);
+
+               if (strstr(line, "PRESENT")) {
+                       c = strchr(line, '=');
+                       c++;
+                       if(*c == '0'){
+                               printf ("Battery not present");
+                               return;
+                       }
+               }
+               if (strstr(line, "CURRENT_NOW")) {
+                       c = strchr(line, '=');
+                       c++;
+                       if(*c == '-') c++; // ignoring the negative sign
+                       _current_rate = strtoull(c, NULL, 10);
+                       if (c) {
+                               //printf ("CURRENT: %f. \n",_current_rate);
+                       } else {
+                               _current_rate = 0;
+                       }
+               }
+               if (strstr(line, "POWER_NOW")) {
+                       c = strchr(line, '=');
+                       c++;
+                       _power_rate = strtoull(c, NULL, 10);
+                       if (c) {
+                               //printf ("POWER: %f. \n",_power_rate);
+                       } else {
+                               _power_rate = 0;
+                       }
+               }
+               if (strstr(line, "CAPACITY=")) {
+                       c = strchr(line, '=');
+                       c++;
+                       _capacity = strtoull(c, NULL, 10);
+                       if (c) {
+                               //printf ("CAPACITY: %f. \n",_capacity);
+                       } else {
+                               _capacity = 0;
+                       }
+               }
+               if (strstr(line, "VOLTAGE_NOW")) {
+                       c = strchr(line, '=');
+                       c++;
+                       while (*c == ' ') c++;
+                       _voltage = strtoull(c, NULL, 10);
+                       if (c) {
+                               //printf ("VOLTAGE_NOW: %f. \n",_voltage);
+                       } else {
+                               _voltage = 0;
+                       }
+               }
+       }
+       file.close();
+
+       if(_voltage) {
+               _voltage = _voltage / 1000.0;
+               voltage = _voltage;
+       } else {
+               voltage = 0.0;
+       }
+
+       if(_power_rate)
+       {
+               rate = _power_rate / 1000000.0;
+       }
+       else if(_current_rate) {
+               _current_rate = _current_rate / 1000.0;
+               rate = _current_rate * _voltage;
+       } else {
+               rate = 0.0;
+       }
+
+       if(_capacity)
+               capacity = _capacity;
+       else
+               capacity = 0.0;
+}
+
+
+void power_supply::end_measurement(void)
+{
+       measure();
+}
+
+void power_supply::start_measurement(void)
+{
+       /* ACPI battery state is a lagging indication, lets only measure at the end */
+}
+
+
+double power_supply::joules_consumed(void)
+{
+       return rate;
+}
diff --git a/src/measurement/power_supply.h b/src/measurement/power_supply.h
new file mode 100644 (file)
index 0000000..5ad776e
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2011, Intel Corporation
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ *     John Mathew <johnx.mathew@intel.com>
+ */
+#ifndef __INCLUDE_GUARD_POWER_SUPPLY_H
+#define __INCLUDE_GUARD_POWER_SUPPLY_H
+
+#include "measurement.h"
+
+class power_supply:public power_meter {
+       char battery_name[256];
+
+       double capacity;
+       double rate;
+       double voltage;
+       void measure(void);
+public:
+       power_supply(const char *_battery_name);
+       virtual void start_measurement(void);
+       virtual void end_measurement(void);
+
+       virtual double joules_consumed(void);
+       virtual double dev_capacity(void) { return capacity; };
+};
+
+#endif
diff --git a/src/measurement/sysfs.cpp b/src/measurement/sysfs.cpp
new file mode 100644 (file)
index 0000000..66cb1cd
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 2011 Anssi Hannula
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ *     Anssi Hannula <anssi.hannula@iki.fi>
+ */
+#include "measurement.h"
+#include "sysfs.h"
+#include "../lib.h"
+#include <string.h>
+#include <stdio.h>
+
+sysfs_power_meter::sysfs_power_meter(const char *power_supply_name)
+{
+       rate = 0.0;
+       capacity = 0.0;
+       strncpy(name, power_supply_name, sizeof(name));
+}
+
+bool sysfs_power_meter::get_sysfs_attr(const char *attribute, int *value)
+{
+       char filename[4096];
+       bool ok;
+
+       snprintf(filename, sizeof(filename), "/sys/class/power_supply/%s/%s", name, attribute);
+       *value = read_sysfs(filename, &ok);
+
+       return ok;
+}
+
+bool sysfs_power_meter::is_present()
+{
+       int present = 0;
+
+       if (!get_sysfs_attr("present", &present))
+               return true; /* assume always present */
+
+       return present;
+}
+
+double sysfs_power_meter::get_voltage()
+{
+       int voltage;
+
+       if (!get_sysfs_attr("voltage_now", &voltage))
+               return -1.0;
+
+       /* µV to V */
+       return voltage / 1000000.0;
+}
+
+bool sysfs_power_meter::set_rate_from_power()
+{
+       int power;
+
+       if (!get_sysfs_attr("power_now", &power))
+               return false;
+
+       /* µW to W */
+       rate = power / 1000000.0;
+       return true;
+}
+
+bool sysfs_power_meter::set_rate_from_current(double voltage)
+{
+       int current;
+
+       if (!get_sysfs_attr("current_now", &current))
+               return false;
+
+       /* current: µA
+        * voltage: V
+        * rate: W */
+       rate = (current / 1000000.0) * voltage;
+       return true;
+}
+
+bool sysfs_power_meter::set_capacity_from_energy()
+{
+       int energy;
+
+       if (!get_sysfs_attr("energy_now", &energy))
+               return false;
+
+       /* µWh to J */
+       capacity = energy / 1000000.0 * 3600.0;
+       return true;
+}
+
+bool sysfs_power_meter::set_capacity_from_charge(double voltage)
+{
+       int charge;
+
+       if (!get_sysfs_attr("charge_now", &charge))
+               return false;
+
+       /* charge: µAh
+        * voltage: V
+        * capacity: J */
+       capacity = (charge / 1000000.0) * voltage * 3600.0;
+       return true;
+}
+
+void sysfs_power_meter::measure()
+{
+       bool got_rate = false;
+       bool got_capacity = false;
+
+       rate = 0.0;
+       capacity = 0.0;
+
+       if (!is_present())
+               return;
+       if (read_sysfs_string("/sys/class/power_supply/%s/status", name) != "Discharging")
+               return;
+
+       got_rate = set_rate_from_power();
+       got_capacity = set_capacity_from_energy();
+
+       if (!got_rate || !got_capacity) {
+               double voltage = get_voltage();
+               if (voltage < 0.0)
+                       return;
+               if (!got_rate)
+                       set_rate_from_current(voltage);
+               if (!got_capacity)
+                       set_capacity_from_charge(voltage);
+       }
+}
+
+
+void sysfs_power_meter::end_measurement(void)
+{
+       measure();
+}
+
+void sysfs_power_meter::start_measurement(void)
+{
+       /* Battery state is generally a lagging indication, lets only measure at the end */
+}
diff --git a/src/measurement/sysfs.h b/src/measurement/sysfs.h
new file mode 100644 (file)
index 0000000..b7efa3d
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2011 Anssi Hannula
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ *     Anssi Hannula <anssi.hannula@iki.fi>
+ */
+#ifndef INCLUDE_GUARD_SYSFS_H
+#define INCLUDE_GUARD_SYSFS_H
+
+#include "measurement.h"
+
+class sysfs_power_meter: public power_meter {
+       char name[256];
+
+       double capacity;
+       double rate;
+
+       bool get_sysfs_attr(const char *attribute, int *value);
+       bool is_present();
+       double get_voltage();
+
+       bool set_rate_from_power();
+       bool set_rate_from_current(double voltage);
+       bool set_capacity_from_energy();
+       bool set_capacity_from_charge(double voltage);
+
+       void measure();
+public:
+       sysfs_power_meter(const char *power_supply_name);
+       virtual void start_measurement(void);
+       virtual void end_measurement(void);
+
+       virtual double joules_consumed(void) { return rate; }
+       virtual double dev_capacity(void) { return capacity; }
+};
+
+#endif
diff --git a/src/parameters/learn.cpp b/src/parameters/learn.cpp
new file mode 100644 (file)
index 0000000..aaef5a2
--- /dev/null
@@ -0,0 +1,282 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ *     Arjan van de Ven <arjan@linux.intel.com>
+ */
+#include "parameters.h"
+#include "../measurement/measurement.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+
+extern int debug_learning;
+
+double calculate_params(struct parameter_bundle *params)
+{
+       unsigned int i;
+
+       params->score = 0;
+
+
+       for (i = 0; i < past_results.size(); i++)
+               compute_bundle(params, past_results[i]);
+
+       return params->score;
+}
+
+
+/*
+ * gradual linear convergence of non-independent variables works better if once in a while
+ * you make a wrong move....
+ */
+static int random_disturb(int retry_left)
+{
+       if (retry_left < 10)
+               return 0;
+
+       if ( (rand() % 500) == 7)
+               return 1;
+       return 0;
+}
+
+static int try_zero(double value)
+{
+       if (value > 0.01)
+       if ( (rand() % 100) == 1)
+               return 1;
+
+       if ( (rand() % 5) == 1)
+               return 1;
+       return 0;
+}
+
+static unsigned int previous_measurements;
+
+static void weed_empties(struct parameter_bundle *best_so_far)
+{
+       double best_score;
+       unsigned int i;
+
+       best_score = best_so_far->score;
+
+
+       for (i = 0; i < best_so_far->parameters.size(); i++) {
+               double orgvalue;
+
+               orgvalue = best_so_far->parameters[i];
+
+
+               best_so_far->parameters[i] = 0.0;
+
+               calculate_params(best_so_far);
+               if (best_so_far->score > best_score) {
+                               best_so_far->parameters[i] = orgvalue;
+               } else {
+                       best_score = best_so_far->score;
+               }
+
+       }
+       calculate_params(best_so_far);
+
+}
+
+/* leaks like a sieve */
+void learn_parameters(int iterations, int do_base_power)
+{
+       struct parameter_bundle *best_so_far;
+       double best_score = 10000000000000000.0;
+       int retry = iterations;
+       int prevparam = -1;
+       int locked = 0;
+       static unsigned int bpi = 0;
+       unsigned int i;
+       time_t start;
+
+       /* don't start fitting anything until we have at least 1 more measurement than we have parameters */
+       if (past_results.size() <= all_parameters.parameters.size())
+               return;
+
+
+
+//     if (past_results.size() == previous_measurements)
+//             return;
+
+       precompute_valid();
+
+
+       previous_measurements = past_results.size();
+
+       double delta = 0.50;
+
+       best_so_far = &all_parameters;
+
+       if (!bpi)
+               bpi = get_param_index("base power");
+
+       calculate_params(best_so_far);
+       best_score = best_so_far->score;
+
+       delta = 0.001 / pow(0.8, iterations / 2.0);
+       if (iterations < 25)
+               delta = 0.001 / pow(0.5, iterations / 2.0);
+
+       if (delta > 0.2)
+               delta = 0.2;
+
+       if (1.0 * best_score / past_results.size() < 4 && delta > 0.05)
+               delta = 0.05;
+
+       if (debug_learning)
+               printf("Delta starts at %5.3f\n", delta);
+
+       if (best_so_far->parameters[bpi] > min_power * 0.9)
+               best_so_far->parameters[bpi] = min_power * 0.9;
+
+       /* We want to give up a little of base power, to give other parameters room to change;
+          base power is the end post for everything after all
+         */
+       if (do_base_power && !debug_learning)
+               best_so_far->parameters[bpi] = best_so_far->parameters[bpi] * 0.9998;
+
+       start = time(NULL);
+
+       while (retry--) {
+               int changed  = 0;
+               int bestparam;
+               double newvalue = 0;
+               double orgscore;
+               double weight;
+
+               bestparam = -1;
+
+               if (time(NULL) - start > 1 && !debug_learning)
+                       retry = 0;
+
+               calculate_params(best_so_far);
+               orgscore = best_score = best_so_far->score;
+
+
+               for (i = 1; i < best_so_far->parameters.size(); i++) {
+                       double value, orgvalue;
+
+                       weight = delta * best_so_far->weights[i];
+
+                       orgvalue = value = best_so_far->parameters[i];
+                       if (value <= 0.001) {
+                               value = 0.1;
+                       } else
+                               value = value * (1 + weight);
+
+                       if (i == bpi && value > min_power)
+                               value = min_power;
+
+                       if (i == bpi && orgvalue > min_power)
+                               orgvalue = min_power;
+
+                       if (value > 5000)
+                               value = 5000;
+
+//                     printf("Trying %s %4.2f -> %4.2f\n", param.c_str(), best_so_far->parameters[param], value);
+                       best_so_far->parameters[i] = value;
+
+                       calculate_params(best_so_far);
+                       if (best_so_far->score < best_score || random_disturb(retry)) {
+                               best_score = best_so_far->score;
+                               newvalue = value;
+                               bestparam = i;
+                               changed++;
+                       }
+
+                       value = orgvalue * 1 / (1 + weight);
+
+                       if (value < 0.0001)
+                               value = 0.0;
+
+                       if (try_zero(value))
+                               value = 0.0;
+
+
+                       if (value > 5000)
+                               value = 5000;
+
+
+//                     printf("Trying %s %4.2f -> %4.2f\n", param.c_str(), orgvalue, value);
+
+                       if (orgvalue != value) {
+                               best_so_far->parameters[i] = value;
+
+                               calculate_params(best_so_far);
+
+                               if (best_so_far->score + 0.00001 < best_score || (random_disturb(retry) && value > 0.0)) {
+                                       best_score = best_so_far->score;
+                                       newvalue = value;
+                                       bestparam = i;
+                                       changed++;
+                               }
+                       }
+                       best_so_far->parameters[i] = orgvalue;
+
+               }
+               if (!changed) {
+                       double mult;
+
+                       if (!locked) {
+                               mult = 0.8;
+                               if (iterations < 25)
+                                       mult = 0.5;
+                               delta = delta * mult;
+                       }
+                       locked = 0;
+                       prevparam = -1;
+               } else {
+                       if (debug_learning) {
+                               printf("Retry is %i \n", retry);
+                                       printf("delta is %5.4f\n", delta);
+                               printf("Best parameter is %i \n", bestparam);
+                               printf("Changing score from %4.3f to %4.3f\n", orgscore, best_score);
+                               printf("Changing value from %4.3f to %4.3f\n", best_so_far->parameters[bestparam], newvalue);
+                       }
+                       best_so_far->parameters[bestparam] = newvalue;
+                       if (prevparam == bestparam)
+                               delta = delta * 1.1;
+                       prevparam = bestparam;
+                       locked = 1;
+               }
+
+               if (delta < 0.001 && !locked)
+                       break;
+
+               if (retry % 50 == 49)
+                       weed_empties(best_so_far);
+       }
+
+
+       /* now we weed out all parameters that don't have value */
+       if (iterations > 50)
+               weed_empties(best_so_far);
+
+       if (debug_learning)
+               printf("Final score %4.2f (%i points)\n", best_so_far->score / past_results.size(), (int)past_results.size());
+//     dump_parameter_bundle(best_so_far);
+//     dump_past_results();
+}
diff --git a/src/parameters/parameters.cpp b/src/parameters/parameters.cpp
new file mode 100644 (file)
index 0000000..1a89b14
--- /dev/null
@@ -0,0 +1,452 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ *     Arjan van de Ven <arjan@linux.intel.com>
+ */
+#include "parameters.h"
+#include "../measurement/measurement.h"
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <math.h>
+#include <vector>
+#include <unistd.h>
+
+
+struct parameter_bundle all_parameters;
+struct result_bundle all_results;
+
+vector <struct result_bundle *> past_results;
+
+map <string, int> param_index;
+static int maxindex = 1;
+map <string, int> result_index;
+static int maxresindex = 1;
+
+int get_param_index(const char *name)
+{
+       int index;
+       index = param_index[name];
+       if (index == 0) {
+               index = param_index[name] = ++maxindex;
+       }
+
+       if (index == 0)
+               printf("OH BLA\n");
+       return index;
+}
+
+int get_result_index(const char *name)
+{
+       int index;
+       index = result_index[name];
+       if (index == 0) {
+               index = result_index[name] = ++maxresindex;
+       }
+
+       return index;
+}
+
+
+void register_parameter(const char *name, double default_value, double weight)
+{
+       int index;
+
+       index = get_param_index(name);
+
+       if (index >= (int)all_parameters.parameters.size()) {
+               all_parameters.parameters.resize(index+1, 0.0);
+               all_parameters.weights.resize(index+1, 1.0);
+       }
+
+       if (all_parameters.parameters[index] <= 0.0001)
+               all_parameters.parameters[index] = default_value;
+
+       all_parameters.weights[index] = weight;
+}
+
+void set_parameter_value(const char *name, double value, struct parameter_bundle *bundle)
+{
+       int index;
+
+       index = get_param_index(name);
+
+       if (index >= (int)bundle->parameters.size()) {
+               bundle->parameters.resize(index+1, 0.0);
+               bundle->weights.resize(index+1, 1.0);
+       }
+
+       bundle->parameters[index] = value;
+}
+
+double get_parameter_value(const char *name, struct parameter_bundle *the_bundle)
+{
+       unsigned int index;
+
+       index = get_param_index(name);
+       if (index >= the_bundle->parameters.size()) {
+               fprintf(stderr, "BUG: requesting unregistered parameter %s\n", name);
+       }
+       return the_bundle->parameters[index];
+}
+
+double get_parameter_value(int index, struct parameter_bundle *the_bundle)
+{
+       return the_bundle->parameters[index];
+}
+
+double get_parameter_weight(int index, struct parameter_bundle *the_bundle)
+{
+       return the_bundle->weights[index];
+}
+
+double get_result_value(const char *name, struct result_bundle *the_bundle)
+{
+       return get_result_value(get_result_index(name), the_bundle);
+}
+
+void set_result_value(const char *name, double value, struct result_bundle *the_bundle)
+{
+       unsigned int index = get_result_index(name);
+       if (index >= the_bundle->utilization.size())
+               the_bundle->utilization.resize(index+1);
+       the_bundle->utilization[index] = value;
+}
+
+void set_result_value(unsigned int index, double value, struct result_bundle *the_bundle)
+{
+       if (index >= the_bundle->utilization.size())
+               the_bundle->utilization.resize(index+1);
+       the_bundle->utilization[index] = value;
+}
+
+double get_result_value(int index, struct result_bundle *the_bundle)
+{
+       if (!the_bundle)
+               return 0;
+       if (index >= (int) the_bundle->utilization.size())
+               return 0;
+       return the_bundle->utilization[index];
+}
+
+
+int result_device_exists(const char *name)
+{
+       unsigned int i;
+       for (i = 0; i < all_devices.size(); i++) {
+               if (strcmp(all_devices[i]->device_name(), name) == 0)
+                       return 1;
+       }
+       return 0;
+}
+
+void report_utilization(const char *name, double value, struct result_bundle *bundle)
+{
+       set_result_value(name, value, bundle);
+}
+void report_utilization(int index, double value, struct result_bundle *bundle)
+{
+       set_result_value(index, value, bundle);
+}
+
+
+
+double compute_bundle(struct parameter_bundle *parameters, struct result_bundle *results)
+{
+       double power = 0;
+       unsigned int i;
+
+       static int bpi = 0;
+
+       if (!bpi)
+               bpi = get_param_index("base power");
+
+       power = parameters->parameters[bpi];
+
+       for (i = 0; i < all_devices.size(); i++) {
+
+               power += all_devices[i]->power_usage(results, parameters);
+       }
+//     printf("result power is %6.2f  guessed is %6.2f\n", results->power, power);
+       parameters->actual_power = results->power;
+       parameters->guessed_power = power;
+       /* scale the squared error by the actual power so that non-idle data points weigh heavier */
+       parameters->score += results->power * (power - results->power) * (power - results->power);
+
+       return power;
+}
+
+static int precomputed_valid = 0;
+void precompute_valid(void)
+{
+       unsigned int i;
+
+
+       for (i = 0; i < all_devices.size(); i++) {
+               all_devices[i]->cached_valid = all_devices[i]->power_valid();
+       }
+       precomputed_valid = 1;
+}
+
+double bundle_power(struct parameter_bundle *parameters, struct result_bundle *results)
+{
+       double power = 0;
+       unsigned int i;
+       static int bpi = 0;
+
+       if (!bpi)
+               bpi = get_param_index("base power");
+
+       if (!precomputed_valid)
+               precompute_valid();
+
+
+       power = parameters->parameters[bpi];
+
+       for (i = 0; i < all_devices.size(); i++) {
+
+               if (all_devices[i]->cached_valid)
+                       power += all_devices[i]->power_usage(results, parameters);
+       }
+
+       return power;
+}
+
+
+void dump_parameter_bundle(struct parameter_bundle *para)
+{
+       map<string, int>::iterator it;
+       int index;
+
+       printf("\n\n");
+       printf("Parameter state \n");
+       printf("----------------------------------\n");
+       printf("Value\t\tName\n");
+       for (it = param_index.begin(); it != param_index.end(); it++) {
+               index = it->second;
+               printf("%5.2f\t\t%s (%i)\n", para->parameters[index], it->first.c_str(), index);
+       }
+
+       printf("\n");
+       printf("Score:  %5.1f  (%5.1f)\n", sqrt(para->score / (0.001 + past_results.size()) / average_power()), para->score);
+       printf("Guess:  %5.1f\n", para->guessed_power);
+       printf("Actual: %5.1f\n", para->actual_power);
+
+       printf("----------------------------------\n");
+}
+
+void dump_result_bundle(struct result_bundle *res)
+{
+       map<string, int>::iterator it;
+       unsigned int index;
+
+       printf("\n\n");
+       printf("Utilisation state \n");
+       printf("----------------------------------\n");
+       printf("Value\t\tName\n");
+       for (it = result_index.begin(); it != result_index.end(); it++) {
+               index = get_result_index(it->first.c_str());
+               printf("%5.2f%%\t\t%s(%i)\n", res->utilization[index], it->first.c_str(), index);
+       }
+
+       printf("\n");
+       printf("Power: %5.1f\n", res->power);
+
+       printf("----------------------------------\n");
+}
+
+struct result_bundle * clone_results(struct result_bundle *bundle)
+{
+       struct result_bundle *b2;
+       map<string, double>::iterator it;
+       unsigned int i;
+
+       b2 = new struct result_bundle;
+
+       if (!b2)
+               return NULL;
+
+       b2->power = bundle->power;
+       b2->utilization.resize(bundle->utilization.size());
+
+       for (i = 0; i < bundle->utilization.size(); i++) {
+               b2->utilization[i] = bundle->utilization[i];
+       }
+
+       return b2;
+}
+
+
+struct parameter_bundle * clone_parameters(struct parameter_bundle *bundle)
+{
+       struct parameter_bundle *b2;
+       unsigned int i;
+
+       b2 = new struct parameter_bundle;
+
+       if (!b2)
+               return NULL;
+
+       b2->score = 0;
+       b2->guessed_power = 0;
+       b2->actual_power = bundle->actual_power;
+       b2->parameters.resize(bundle->parameters.size());
+       for (i = 0; i < bundle->parameters.size(); i++) {
+               b2->parameters[i] = bundle->parameters[i];
+       }
+
+       return b2;
+}
+
+
+void store_results(double duration)
+{
+       if (duration < 5)
+               return;
+       global_joules_consumed();
+       if (all_results.power > 0.01) {
+               unsigned int overflow_index;
+               overflow_index = 50 + (rand() % MAX_KEEP);
+               if (past_results.size() >= MAX_PARAM) {
+                       /* memory leak, must free old one first */
+                       past_results[overflow_index] = clone_results(&all_results);
+               } else {
+                       past_results.push_back(clone_results(&all_results));
+               }
+               if ((past_results.size() % 10) == 0)
+                       save_all_results("saved_results.powertop");
+       }
+
+}
+
+
+
+void dump_past_results(void)
+{
+       unsigned int j;
+       unsigned int i;
+       struct result_bundle *result;
+
+       for (j = 0; j < past_results.size(); j+=10) {
+               printf("Est    ");
+               for (i = j; i < past_results.size() && i < j + 10; i++) {
+                       result = past_results[i];
+                       printf("%6.2f  ", bundle_power(&all_parameters, result));
+               }
+               printf("\n");
+               printf("Actual ");
+               for (i = j; i < past_results.size() && i < j + 10; i++) {
+                       result = past_results[i];
+                       printf("%6.2f  ", result->power);
+               }
+               printf("\n\n");
+       }
+}
+
+double average_power(void)
+{
+       double sum = 0.0;
+       unsigned int i;
+       for (i = 0; i < past_results.size(); i++)
+               sum += past_results[i]->power;
+
+       if (past_results.size())
+               sum = sum / past_results.size() + 0.0001;
+       else
+               sum = 0.0001;
+       return sum;
+}
+
+int utilization_power_valid(const char *u)
+{
+       unsigned int i;
+       unsigned int index;
+       double first_value;
+
+       index = get_result_index(u);
+       if (index <= 0)
+               return 0;
+
+       first_value = past_results[0]->utilization[index];
+       for (i = 1; i < past_results.size(); i++) {
+               if (get_result_value(index, past_results[i]) < first_value - 0.0001)
+                       return 1;
+               if (get_result_value(index, past_results[i]) > first_value + 0.0001)
+                       return 1;
+       }
+
+       return 0;
+}
+
+int utilization_power_valid(int index)
+{
+       unsigned int i;
+       double first_value;
+
+       if (index <= 0)
+               return 0;
+
+       if (past_results.size() == 0)
+               return 0;
+
+       if (index >= (int)past_results[0]->utilization.size())
+               return 0;
+       first_value = past_results[0]->utilization[index];
+       for (i = 1; i < past_results.size(); i++) {
+               if (get_result_value(index, past_results[i]) < first_value - 0.0001)
+                       return 1;
+               if (get_result_value(index, past_results[i]) > first_value + 0.0001)
+                       return 1;
+       }
+
+       return 0;
+}
+
+
+/* force power data to be valid to the rest of the system  */
+int global_power_override = 0;
+
+/*
+ * only report power numbers once we have 3* more measurements than
+ * we have parameters; anything less and our model fit is highly suspect
+ */
+int global_power_valid(void)
+{
+       if (past_results.size() > 3 * all_parameters.parameters.size())
+               return 1;
+
+
+       return global_power_override;
+}
+
+/* find the directory to store powertop results/parameters based on distribution*/
+char* get_param_directory(const char *filename)
+{
+       static char tempfilename[4096];
+
+       if (access("/var/cache/powertop", W_OK ) == 0)
+               sprintf(tempfilename, "/var/cache/powertop/%s", filename);
+       if (access("/data/local/powertop", W_OK ) == 0)
+               sprintf(tempfilename, "/data/local/powertop/%s", filename);
+
+       return tempfilename;
+};
diff --git a/src/parameters/parameters.h b/src/parameters/parameters.h
new file mode 100644 (file)
index 0000000..a8c1154
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ *     Arjan van de Ven <arjan@linux.intel.com>
+ */
+#ifndef __INCLUDE_GUARD_PARAMETERS_H_
+#define __INCLUDE_GUARD_PARAMETERS_H_
+
+
+#include <map>
+#include <vector>
+#include <string>
+
+#include "string.h"
+#include "../devices/device.h"
+#include "../lib.h"
+
+using namespace std;
+
+#define MAX_KEEP 700
+#define MAX_PARAM 750
+
+
+struct parameter_bundle
+{
+       double score;
+       double guessed_power;
+       double actual_power;
+
+       vector<double> parameters;
+       vector<double> weights;
+};
+
+extern struct parameter_bundle all_parameters;
+extern map <string, int> param_index;
+extern map <string, int> result_index;
+
+extern int get_param_index(const char *param);
+extern int get_result_index(const char *param);
+
+
+extern void register_parameter(const char *name, double default_value = 0.00, double weight = 1.0);
+extern double get_parameter_value(const char *name, struct parameter_bundle *bundle = &all_parameters);
+extern double get_parameter_value(int index, struct parameter_bundle *bundle = &all_parameters);
+extern void set_parameter_value(const char *name, double value, struct parameter_bundle *bundle = &all_parameters);
+
+
+struct result_bundle
+{
+       double power;
+       vector <double> utilization; /* device name, device utilization %age */
+};
+
+extern struct result_bundle all_results;
+extern vector <struct result_bundle *> past_results;
+
+extern double get_result_value(const char *name, struct result_bundle *bundle = &all_results);
+extern double get_result_value(int index, struct result_bundle *bundle = &all_results);
+
+extern void set_result_value(const char *name, double value, struct result_bundle *bundle = &all_results);
+
+
+extern int result_device_exists(const char *name);
+
+extern void report_utilization(const char *name, double value, struct result_bundle *bundle = &all_results);
+extern void report_utilization(int index, double value, struct result_bundle *bundle = &all_results);
+
+
+extern void precompute_valid(void);
+
+extern double compute_bundle(struct parameter_bundle *parameters = &all_parameters, struct result_bundle *results = &all_results);
+
+
+void dump_parameter_bundle(struct parameter_bundle *patameters = &all_parameters);
+void dump_result_bundle(struct result_bundle *res = &all_results);
+
+extern struct result_bundle * clone_results(struct result_bundle *bundle);
+extern struct parameter_bundle * clone_parameters(struct parameter_bundle *bundle);
+
+extern void store_results(double duration);
+extern void learn_parameters(int iterations, int do_base_power);
+extern char *get_param_directory(const char *filename);
+extern void save_all_results(const char *filename = "saved_results.powertop");
+extern void load_results(const char *filename);
+extern void save_parameters(const char *filename);
+extern void load_parameters(const char *filename);
+
+extern void dump_past_results(void);
+extern double bundle_power(struct parameter_bundle *parameters, struct result_bundle *results);
+
+extern double average_power(void);
+
+extern int utilization_power_valid(const char *u);
+extern int utilization_power_valid(int index);
+extern double calculate_params(struct parameter_bundle *params = &all_parameters);
+int global_power_valid(void);
+
+
+extern int global_power_override;
+
+
+#endif
diff --git a/src/parameters/persistent.cpp b/src/parameters/persistent.cpp
new file mode 100644 (file)
index 0000000..483227b
--- /dev/null
@@ -0,0 +1,186 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ *     Arjan van de Ven <arjan@linux.intel.com>
+ */
+#include <iostream>
+#include <fstream>
+#include <iomanip>
+#include <stdlib.h>
+
+#include "parameters.h"
+#include "../measurement/measurement.h"
+
+using namespace std;
+
+void save_all_results(const char *filename)
+{
+       ofstream file;
+       unsigned int i;
+       struct result_bundle *bundle;
+       char* pathname;
+
+       pathname = get_param_directory(filename);
+
+       file.open(pathname, ios::out);
+       if (!file) {
+               cout << _("Cannot save to file") << " " << pathname << "\n";
+               return;
+       }
+       for (i = 0; i < past_results.size(); i++) {
+               bundle = past_results[i];
+               map<string, int>::iterator it;
+               file << setiosflags(ios::fixed) <<  setprecision(5) << bundle->power << "\n";
+
+               for (it = result_index.begin(); it != result_index.end(); it++) {
+                       file << it->first << "\t" << setprecision(5) << get_result_value(it->second, bundle) << "\n";
+               }
+               file << ":\n";
+       }
+
+       file.close();
+
+}
+
+void load_results(const char *filename)
+{
+       ifstream file;
+       char line[4096];
+       char *c1;
+       struct result_bundle *bundle;
+       int first = 1;
+       unsigned int count = 0;
+       char* pathname;
+
+       pathname = get_param_directory(filename);
+
+       file.open(pathname, ios::in);
+       if (!file) {
+               cout << _("Cannot load from file") << " " << pathname << "\n";
+               return;
+       }
+
+       bundle = new struct result_bundle;
+
+       while (file) {
+               double d;
+               if (first) {
+                       file.getline(line, 4096);
+                       if (strlen(line)>0) {
+                               sscanf(line, "%lf", &bundle->power);
+                               if (bundle->power < min_power)
+                                       min_power = bundle->power;
+                       }
+                       first = 0;
+                       continue;
+               }
+               file.getline(line, 4096);
+               if (strlen(line) < 3) {
+                       int overflow_index;
+
+                       overflow_index = 50 + (rand() % MAX_KEEP);
+                       if (past_results.size() >= MAX_PARAM) {
+                       /* memory leak, must free old one first */
+                               past_results[overflow_index] = bundle;
+                       } else {
+                               past_results.push_back(bundle);
+                       }
+                       bundle = new struct result_bundle;
+                       first = 1;
+                       count++;
+                       continue;
+               }
+               c1 = strchr(line, '\t');
+               if (!c1)
+                       continue;
+               *c1 = 0;
+               c1++;
+               sscanf(c1, "%lf", &d);
+               set_result_value(line, d, bundle);
+       }
+
+       file.close();
+       // '%i" is for count, do not translate
+       fprintf(stderr, _("Loaded %i prior measurements\n"), count);
+}
+
+void save_parameters(const char *filename)
+{
+       ofstream file;
+       char* pathname;
+
+//     printf("result size is %i, #parameters is %i \n", (int)past_results.size(), (int)all_parameters.parameters.size());
+
+       if (!global_power_valid())
+               return;
+
+       pathname = get_param_directory(filename);
+
+       file.open(pathname, ios::out);
+       if (!file) {
+               cout << _("Cannot save to file") << " " << pathname << "\n";
+               return;
+       }
+
+       map<string, int>::iterator it;
+
+       for (it = param_index.begin(); it != param_index.end(); it++) {
+               int index;
+               index = it->second;
+               file << it->first << "\t" << setprecision(9) << all_parameters.parameters[index] << "\n";
+       }
+       file.close();
+}
+
+void load_parameters(const char *filename)
+{
+       ifstream file;
+       char line[4096];
+       char *c1;
+       char* pathname;
+
+       pathname = get_param_directory(filename);
+
+       file.open(pathname, ios::in);
+       if (!file) {
+               cout << _("Cannot load from file") << " " << pathname << "\n";
+               return;
+       }
+
+       while (file) {
+               double d;
+               memset(line, 0, 4096);
+               file.getline(line, 4095);
+
+               c1 = strchr(line, '\t');
+               if (!c1)
+                       continue;
+               *c1 = 0;
+               c1++;
+               sscanf(c1, "%lf", &d);
+
+
+               set_parameter_value(line, d);
+       }
+
+       file.close();
+}
diff --git a/src/perf/perf.cpp b/src/perf/perf.cpp
new file mode 100644 (file)
index 0000000..35b4017
--- /dev/null
@@ -0,0 +1,260 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ *     Arjan van de Ven <arjan@linux.intel.com>
+ */
+
+#include <iostream>
+#include <fstream>
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+
+#include <fcntl.h>
+
+#include "perf_event.h"
+#include "perf.h"
+#include "../lib.h"
+#include "../display.h"
+
+struct pevent *perf_event::pevent;
+
+static int get_trace_type(const char *eventname)
+{
+       string str;
+       int this_trace;
+
+       str = read_sysfs_string("/sys/kernel/debug/tracing/events/%s/id",
+                                       eventname);
+       if (str.length() < 1)
+               return -1;
+
+       this_trace = strtoull(str.c_str(), NULL, 10);
+       return this_trace;
+}
+
+static inline int sys_perf_event_open(struct perf_event_attr *attr,
+                      pid_t pid, int cpu, int group_fd,
+                      unsigned long flags)
+{
+       attr->size = sizeof(*attr);
+       return syscall(__NR_perf_event_open, attr, pid, cpu,
+                       group_fd, flags);
+}
+
+void perf_event::create_perf_event(char *eventname, int _cpu)
+{
+       struct perf_event_attr attr;
+       int ret;
+
+       struct {
+               __u64 count;
+               __u64 time_enabled;
+               __u64 time_running;
+               __u64 id;
+       } read_data;
+
+       if (perf_fd != -1)
+               clear();
+
+       memset(&attr, 0, sizeof(attr));
+
+       attr.read_format        = PERF_FORMAT_TOTAL_TIME_ENABLED |
+                                 PERF_FORMAT_TOTAL_TIME_RUNNING |
+                                 PERF_FORMAT_ID;
+
+       attr.sample_freq        = 0;
+       attr.sample_period      = 1;
+       attr.sample_type        |= PERF_SAMPLE_RAW | PERF_SAMPLE_CPU | PERF_SAMPLE_TIME;
+
+       attr.mmap               = 1;
+       attr.comm               = 1;
+       attr.inherit            = 0;
+       attr.disabled           = 1;
+
+       attr.type               = PERF_TYPE_TRACEPOINT;
+       attr.config             = trace_type;
+
+       if (attr.config <= 0)
+               return;
+
+       perf_fd = sys_perf_event_open(&attr, -1, _cpu, -1, 0);
+
+       if (perf_fd < 0) {
+               reset_display();
+               fprintf(stderr, _("PowerTOP %s needs the kernel to support the 'perf' subsystem\n"), POWERTOP_VERSION);
+               fprintf(stderr, _("as well as support for trace points in the kernel:\n"));
+               fprintf(stderr, "CONFIG_PERF_EVENTS=y\nCONFIG_PERF_COUNTERS=y\nCONFIG_TRACEPOINTS=y\nCONFIG_TRACING=y\n");
+               exit(EXIT_FAILURE);
+       }
+       if (read(perf_fd, &read_data, sizeof(read_data)) == -1) {
+               reset_display();
+               perror("Unable to read perf file descriptor\n");
+               exit(-1);
+       }
+
+       fcntl(perf_fd, F_SETFL, O_NONBLOCK);
+
+       perf_mmap = mmap(NULL, (bufsize+1)*getpagesize(),
+                               PROT_READ | PROT_WRITE, MAP_SHARED, perf_fd, 0);
+       if (perf_mmap == MAP_FAILED) {
+               fprintf(stderr, "failed to mmap with %d (%s)\n", errno, strerror(errno));
+               return;
+       }
+
+       ret = ioctl(perf_fd, PERF_EVENT_IOC_ENABLE, 0);
+
+       if (ret < 0) {
+               fprintf(stderr, "failed to enable perf \n");
+       }
+
+       pc = (perf_event_mmap_page *)perf_mmap;
+       data_mmap = (unsigned char *)perf_mmap + getpagesize();
+
+
+}
+
+void perf_event::set_event_name(const char *event_name)
+{
+       if (name)
+               free(name);
+       name = strdup(event_name);
+       if (!name) {
+               fprintf(stderr, "failed to allocate event name\n");
+               return;
+       }
+
+       char *c;
+
+       c = strchr(name, ':');
+       if (c)
+               *c = '/';
+
+       trace_type = get_trace_type(name);
+}
+
+perf_event::~perf_event(void)
+{
+       if (name)
+               free(name);
+
+       if (perf_event::pevent->ref_count == 1) {
+               pevent_free(perf_event::pevent);
+               perf_event::pevent = NULL;
+       } else
+               pevent_unref(perf_event::pevent);
+}
+
+void perf_event::set_cpu(int _cpu)
+{
+       cpu = _cpu;
+}
+
+static void allocate_pevent(void)
+{
+       if (!perf_event::pevent)
+               perf_event::pevent = pevent_alloc();
+       else
+               pevent_ref(perf_event::pevent);
+}
+
+perf_event::perf_event(const char *event_name, int _cpu, int buffer_size)
+{
+       allocate_pevent();
+       name = NULL;
+       perf_fd = -1;
+       bufsize = buffer_size;
+       cpu = _cpu;
+       perf_mmap = NULL;
+       trace_type = 0;
+       set_event_name(event_name);
+}
+
+perf_event::perf_event(void)
+{
+       allocate_pevent();
+       name = NULL;
+       perf_fd = -1;
+       bufsize = 128;
+       perf_mmap = NULL;
+       cpu = 0;
+       trace_type = 0;
+}
+
+void perf_event::start(void)
+{
+       create_perf_event(name, cpu);
+}
+
+void perf_event::stop(void)
+{
+       int ret;
+       ret = ioctl(perf_fd, PERF_EVENT_IOC_DISABLE, 0);
+       if (ret)
+               cout << "stop failing\n";
+}
+
+void perf_event::process(void *cookie)
+{
+       struct perf_event_header *header;
+
+       if (perf_fd < 0)
+               return;
+
+       while (pc->data_tail != pc->data_head ) {
+               while (pc->data_tail >= (unsigned int)bufsize * getpagesize())
+                       pc->data_tail -= bufsize * getpagesize();
+
+               header = (struct perf_event_header *)( (unsigned char *)data_mmap + pc->data_tail);
+
+               if (header->size == 0)
+                       break;
+
+               pc->data_tail += header->size;
+
+               while (pc->data_tail >= (unsigned int)bufsize * getpagesize())
+                       pc->data_tail -= bufsize * getpagesize();
+
+               if (header->type == PERF_RECORD_SAMPLE)
+                       handle_event(header, cookie);
+       }
+       pc->data_tail = pc->data_head;
+}
+
+void perf_event::clear(void)
+{
+       if (perf_mmap) {
+//             memset(perf_mmap, 0, (bufsize)*getpagesize());
+               munmap(perf_mmap, (bufsize+1)*getpagesize());
+               perf_mmap = NULL;
+       }
+       if (perf_fd != -1)
+               close(perf_fd);
+       perf_fd = -1;
+}
diff --git a/src/perf/perf.h b/src/perf/perf.h
new file mode 100644 (file)
index 0000000..ee072ae
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ *     Arjan van de Ven <arjan@linux.intel.com>
+ */
+#ifndef _INCLUDE_GUARD_PERF_H_
+#define _INCLUDE_GUARD_PERF_H_
+
+#include <iostream>
+
+
+extern "C" {
+       #include "../traceevent/event-parse.h"
+}
+
+
+using namespace std;
+
+class  perf_event {
+protected:
+       int perf_fd;
+       void * perf_mmap;
+       void * data_mmap;
+       struct perf_event_mmap_page *pc;
+
+
+
+       int bufsize;
+       char *name;
+       int cpu;
+       void create_perf_event(char *eventname, int cpu);
+
+public:
+       unsigned int trace_type;
+
+       perf_event(void);
+       perf_event(const char *event_name, int cpu = 0, int buffer_size = 128);
+
+       virtual ~perf_event(void);
+
+
+       void set_event_name(const char *event_name);
+       void set_cpu(int cpu);
+
+       void start(void);
+       void stop(void);
+       void clear(void);
+
+       void process(void *cookie);
+
+       virtual void handle_event(struct perf_event_header *header, void *cookie) { };
+
+       static struct pevent *pevent;
+
+};
+
+#endif
diff --git a/src/perf/perf_bundle.cpp b/src/perf/perf_bundle.cpp
new file mode 100644 (file)
index 0000000..38e1e91
--- /dev/null
@@ -0,0 +1,318 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ *     Arjan van de Ven <arjan@linux.intel.com>
+ */
+#include <iostream>
+#include <malloc.h>
+#include <algorithm>
+#include <string.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "perf_bundle.h"
+#include "perf_event.h"
+#include "perf.h"
+
+#include "../cpu/cpu.h"
+
+#if defined(__GXX_EXPERIMENTAL_CXX0X__) || (__cplusplus >= 201103L)
+# define USE_DECLTYPE
+#endif
+
+class perf_bundle_event: public perf_event
+{
+public:
+       perf_bundle_event(void);
+       virtual void handle_event(struct perf_event_header *header, void *cookie);
+};
+
+perf_bundle_event::perf_bundle_event(void) : perf_event()
+{
+}
+
+
+void perf_bundle_event::handle_event(struct perf_event_header *header, void *cookie)
+{
+       unsigned char *buffer;
+       vector<void *> *vector;
+
+       buffer = (unsigned char *)malloc(header->size);
+       memcpy(buffer, header, header->size);
+
+#ifdef USE_DECLTYPE
+       vector = (decltype(vector))cookie;
+#else
+       vector = (typeof(vector))cookie;
+#endif
+       vector->push_back(buffer);
+}
+
+
+void perf_bundle::release(void)
+{
+       class perf_event *ev;
+       unsigned int i = 0;
+
+       for (i = 0; i < events.size(); i++) {
+               ev = events[i];
+               if (!ev)
+                       continue;
+               ev->clear();
+               delete ev;
+       }
+       events.clear();
+
+       for (i = 0; i < event_names.size(); i++) {
+               free((void*)event_names[i]);
+       }
+       event_names.clear();
+
+       for(i = 0; i < records.size(); i++) {
+               free(records[i]);
+       }
+       records.clear();
+}
+
+static char * read_file(const char *file)
+{
+       char *buffer = NULL; /* quient gcc */
+       char buf[4096];
+       int len = 0;
+       int fd;
+       int r;
+
+       fd = open(file, O_RDONLY);
+       if (fd < 0)
+               exit(-1);
+
+       while((r = read(fd, buf, 4096)) > 0) {
+               if (len) {
+                       char *tmp = (char *)realloc(buffer, len + r + 1);
+                       if (!tmp)
+                               free(buffer);
+                       buffer = tmp;
+               } else
+                       buffer = (char *)malloc(r + 1);
+               if (!buffer)
+                       goto out;
+               memcpy(buffer + len, buf, r);
+               len += r;
+               buffer[len] = '\0';
+       }
+out:
+       return buffer;
+}
+
+static void parse_event_format(const char *event_name)
+{
+       char *tptr;
+       char *name = strdup(event_name);
+       char *sys = strtok_r(name, ":", &tptr);
+       char *event = strtok_r(NULL, ":", &tptr);
+       char *file;
+       char *buf;
+
+       file = (char *)malloc(strlen(sys) + strlen(event) +
+                     strlen("/sys/kernel/debug/tracing/events////format") + 2);
+       sprintf(file, "/sys/kernel/debug/tracing/events/%s/%s/format", sys, event);
+
+       buf = read_file(file);
+       free(file);
+       if (!buf)
+               return;
+
+       pevent_parse_event(perf_event::pevent, buf, strlen(buf), sys);
+       free(name);
+       free(buf);
+}
+
+bool perf_bundle::add_event(const char *event_name)
+{
+       unsigned int i;
+       int event_added = false;
+       class perf_event *ev;
+
+
+       for (i = 0; i < all_cpus.size(); i++) {
+
+               if (!all_cpus[i])
+                       continue;
+
+               ev = new class perf_bundle_event();
+
+               ev->set_event_name(event_name);
+               ev->set_cpu(i);
+
+               if ((int)ev->trace_type >= 0) {
+                       if (event_names.find(ev->trace_type) == event_names.end()) {
+                               event_names[ev->trace_type] = strdup(event_name);
+                               parse_event_format(event_name);
+                       }
+                       events.push_back(ev);
+                       event_added = true;
+               } else {
+                       delete ev;
+               }
+       }
+       return event_added;
+}
+
+void perf_bundle::start(void)
+{
+       unsigned int i;
+       class perf_event *ev;
+
+       for (i = 0; i < events.size(); i++) {
+               ev = events[i];
+               if (!ev)
+                       continue;
+               ev->start();
+       }
+}
+void perf_bundle::stop(void)
+{
+       unsigned int i;
+       class perf_event *ev;
+
+       for (i = 0; i < events.size(); i++) {
+               ev = events[i];
+               if (!ev)
+                       continue;
+               ev->stop();
+       }
+}
+void perf_bundle::clear(void)
+{
+       unsigned int i;
+
+       class perf_event *ev;
+
+       for (i = 0; i < events.size(); i++) {
+               ev = events[i];
+               if (!ev)
+                       continue;
+               ev->clear();
+       }
+
+       for (i = 0; i < records.size(); i++) {
+               free(records[i]);
+       }
+       records.resize(0);
+}
+
+
+struct trace_entry {
+       uint64_t                time;
+       uint32_t                cpu;
+       uint32_t                res;
+       __u32                   size;
+} __attribute__((packed));;
+
+
+struct perf_sample {
+       struct perf_event_header        header;
+       struct trace_entry              trace;
+       unsigned char                   data[0];
+} __attribute__((packed));
+
+static uint64_t timestamp(perf_event_header *event)
+{
+       struct perf_sample *sample;
+
+       if (event->type != PERF_RECORD_SAMPLE)
+               return 0;
+
+       sample = (struct perf_sample *)event;
+
+#if 0
+       int i;
+       unsigned char *x;
+
+       printf("header:\n");
+       printf("        type  is %x \n", sample->header.type);
+       printf("        misc  is %x \n", sample->header.misc);
+       printf("        size  is %i \n", sample->header.size);
+       printf("sample:\n");
+       printf("        time  is %llx \n", sample->trace.time);
+       printf("        cpu   is %i / %x \n", sample->trace.cpu, sample->trace.cpu);
+       printf("        res   is %i / %x \n", sample->trace.res, sample->trace.res);
+       printf("        size  is %i / %x \n", sample->trace.size, sample->trace.size);
+       printf("        type  is %i / %x \n", sample->trace.type, sample->trace.type);
+       printf("        flags is %i / %x \n", sample->trace.flags, sample->trace.flags);
+       printf("        p/c   is %i / %x \n", sample->trace.preempt_count, sample->trace.preempt_count);
+       printf("        pid   is %i / %x \n", sample->trace.pid, sample->trace.pid);
+       printf("        lock dept  is %i / %x \n", sample->trace.lock_depth, sample->trace.lock_depth);
+
+       x = (unsigned char *)sample;
+       for (i = 0; i < sample->header.size; i++)
+               printf("%02x ", *(x+i));
+       printf("\n");
+#endif
+       return sample->trace.time;
+
+}
+
+static bool event_sort_function (void *i, void *j)
+{
+       struct perf_event_header *I, *J;
+
+       I = (struct perf_event_header *) i;
+       J = (struct perf_event_header *) j;
+       return (timestamp(I)<timestamp(J));
+}
+
+void perf_bundle::process(void)
+{
+       unsigned int i;
+       class perf_event *ev;
+
+       /* fixme: reserve enough space in the array in one go */
+       for (i = 0; i < events.size(); i++) {
+               ev = events[i];
+               if (!ev)
+                       continue;
+               ev->process(&records);
+       }
+       sort(records.begin(), records.end(), event_sort_function);
+
+       for (i = 0; i < records.size(); i++) {
+               struct perf_sample *sample;
+
+               sample = (struct perf_sample *)records[i];
+               if (!sample)
+                       continue;
+
+               if (sample->header.type != PERF_RECORD_SAMPLE)
+                       continue;
+
+               handle_trace_point(&sample->data, sample->trace.cpu, sample->trace.time);
+       }
+}
+
+void perf_bundle::handle_trace_point(void *trace, int cpu, uint64_t time)
+{
+       printf("UH OH... abstract handle_trace_point called\n");
+}
diff --git a/src/perf/perf_bundle.h b/src/perf/perf_bundle.h
new file mode 100644 (file)
index 0000000..ec50744
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ *     Arjan van de Ven <arjan@linux.intel.com>
+ */
+#ifndef _INCLUDE_GUARD_PERF_BUNDLE_H_
+#define _INCLUDE_GUARD_PERF_BUNDLE_H_
+
+#include <iostream>
+#include <vector>
+#include <map>
+
+using namespace std;
+
+#include "perf.h"
+class perf_event;
+
+
+class  perf_bundle {
+protected:
+       vector<class perf_event *> events;
+       std::map<int, char*> event_names;
+public:
+       vector<void *> records;
+       virtual ~perf_bundle() {};
+
+       virtual void release(void);
+       bool add_event(const char *event_name);
+
+       void start(void);
+       void stop(void);
+       void clear(void);
+
+       void process(void);
+
+       virtual void handle_trace_point(void *trace, int cpu = 0, uint64_t time = 0);
+};
+
+
+#endif
diff --git a/src/perf/perf_event.h b/src/perf/perf_event.h
new file mode 100644 (file)
index 0000000..92a38b8
--- /dev/null
@@ -0,0 +1,910 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ *     Arjan van de Ven <arjan@linux.intel.com>
+ */
+/*
+ * Performance events:
+ *
+ *    Copyright (C) 2008-2009, Thomas Gleixner <tglx@linutronix.de>
+ *    Copyright (C) 2008-2009, Red Hat, Inc., Ingo Molnar
+ *    Copyright (C) 2008-2009, Red Hat, Inc., Peter Zijlstra
+ *
+ * Data type definitions, declarations, prototypes.
+ *
+ *    Started by: Thomas Gleixner and Ingo Molnar
+ *
+ * For licencing details see kernel-base/COPYING
+ */
+#ifndef _LINUX_PERF_EVENT_H
+#define _LINUX_PERF_EVENT_H
+
+#include <linux/types.h>
+#include <linux/ioctl.h>
+#include <asm/byteorder.h>
+#include <sys/syscall.h>
+
+
+/*
+ * User-space ABI bits:
+ */
+
+/*
+ * attr.type
+ */
+enum perf_type_id {
+       PERF_TYPE_HARDWARE                      = 0,
+       PERF_TYPE_SOFTWARE                      = 1,
+       PERF_TYPE_TRACEPOINT                    = 2,
+       PERF_TYPE_HW_CACHE                      = 3,
+       PERF_TYPE_RAW                           = 4,
+
+       PERF_TYPE_MAX,                          /* non-ABI */
+};
+
+/*
+ * Generalized performance event event_id types, used by the
+ * attr.event_id parameter of the sys_perf_event_open()
+ * syscall:
+ */
+enum perf_hw_id {
+       /*
+        * Common hardware events, generalized by the kernel:
+        */
+       PERF_COUNT_HW_CPU_CYCLES                = 0,
+       PERF_COUNT_HW_INSTRUCTIONS              = 1,
+       PERF_COUNT_HW_CACHE_REFERENCES          = 2,
+       PERF_COUNT_HW_CACHE_MISSES              = 3,
+       PERF_COUNT_HW_BRANCH_INSTRUCTIONS       = 4,
+       PERF_COUNT_HW_BRANCH_MISSES             = 5,
+       PERF_COUNT_HW_BUS_CYCLES                = 6,
+
+       PERF_COUNT_HW_MAX,                      /* non-ABI */
+};
+
+/*
+ * Generalized hardware cache events:
+ *
+ *       { L1-D, L1-I, LLC, ITLB, DTLB, BPU } x
+ *       { read, write, prefetch } x
+ *       { accesses, misses }
+ */
+enum perf_hw_cache_id {
+       PERF_COUNT_HW_CACHE_L1D                 = 0,
+       PERF_COUNT_HW_CACHE_L1I                 = 1,
+       PERF_COUNT_HW_CACHE_LL                  = 2,
+       PERF_COUNT_HW_CACHE_DTLB                = 3,
+       PERF_COUNT_HW_CACHE_ITLB                = 4,
+       PERF_COUNT_HW_CACHE_BPU                 = 5,
+
+       PERF_COUNT_HW_CACHE_MAX,                /* non-ABI */
+};
+
+enum perf_hw_cache_op_id {
+       PERF_COUNT_HW_CACHE_OP_READ             = 0,
+       PERF_COUNT_HW_CACHE_OP_WRITE            = 1,
+       PERF_COUNT_HW_CACHE_OP_PREFETCH         = 2,
+
+       PERF_COUNT_HW_CACHE_OP_MAX,             /* non-ABI */
+};
+
+enum perf_hw_cache_op_result_id {
+       PERF_COUNT_HW_CACHE_RESULT_ACCESS       = 0,
+       PERF_COUNT_HW_CACHE_RESULT_MISS         = 1,
+
+       PERF_COUNT_HW_CACHE_RESULT_MAX,         /* non-ABI */
+};
+
+/*
+ * Special "software" events provided by the kernel, even if the hardware
+ * does not support performance events. These events measure various
+ * physical and sw events of the kernel (and allow the profiling of them as
+ * well):
+ */
+enum perf_sw_ids {
+       PERF_COUNT_SW_CPU_CLOCK                 = 0,
+       PERF_COUNT_SW_TASK_CLOCK                = 1,
+       PERF_COUNT_SW_PAGE_FAULTS               = 2,
+       PERF_COUNT_SW_CONTEXT_SWITCHES          = 3,
+       PERF_COUNT_SW_CPU_MIGRATIONS            = 4,
+       PERF_COUNT_SW_PAGE_FAULTS_MIN           = 5,
+       PERF_COUNT_SW_PAGE_FAULTS_MAJ           = 6,
+
+       PERF_COUNT_SW_MAX,                      /* non-ABI */
+};
+
+/*
+ * Bits that can be set in attr.sample_type to request information
+ * in the overflow packets.
+ */
+enum perf_event_sample_format {
+       PERF_SAMPLE_IP                          = 1U << 0,
+       PERF_SAMPLE_TID                         = 1U << 1,
+       PERF_SAMPLE_TIME                        = 1U << 2,
+       PERF_SAMPLE_ADDR                        = 1U << 3,
+       PERF_SAMPLE_READ                        = 1U << 4,
+       PERF_SAMPLE_CALLCHAIN                   = 1U << 5,
+       PERF_SAMPLE_ID                          = 1U << 6,
+       PERF_SAMPLE_CPU                         = 1U << 7,
+       PERF_SAMPLE_PERIOD                      = 1U << 8,
+       PERF_SAMPLE_STREAM_ID                   = 1U << 9,
+       PERF_SAMPLE_RAW                         = 1U << 10,
+
+       PERF_SAMPLE_MAX = 1U << 11,             /* non-ABI */
+};
+
+/*
+ * The format of the data returned by read() on a perf event fd,
+ * as specified by attr.read_format:
+ *
+ * struct read_format {
+ *     { u64           value;
+ *       { u64         time_enabled; } && PERF_FORMAT_ENABLED
+ *       { u64         time_running; } && PERF_FORMAT_RUNNING
+ *       { u64         id;           } && PERF_FORMAT_ID
+ *     } && !PERF_FORMAT_GROUP
+ *
+ *     { u64           nr;
+ *       { u64         time_enabled; } && PERF_FORMAT_ENABLED
+ *       { u64         time_running; } && PERF_FORMAT_RUNNING
+ *       { u64         value;
+ *         { u64       id;           } && PERF_FORMAT_ID
+ *       }             cntr[nr];
+ *     } && PERF_FORMAT_GROUP
+ * };
+ */
+enum perf_event_read_format {
+       PERF_FORMAT_TOTAL_TIME_ENABLED          = 1U << 0,
+       PERF_FORMAT_TOTAL_TIME_RUNNING          = 1U << 1,
+       PERF_FORMAT_ID                          = 1U << 2,
+       PERF_FORMAT_GROUP                       = 1U << 3,
+
+       PERF_FORMAT_MAX = 1U << 4,              /* non-ABI */
+};
+
+#define PERF_ATTR_SIZE_VER0    64      /* sizeof first published struct */
+
+/*
+ * Hardware event_id to monitor via a performance monitoring event:
+ */
+struct perf_event_attr {
+
+       /*
+        * Major type: hardware/software/tracepoint/etc.
+        */
+       __u32                   type;
+
+       /*
+        * Size of the attr structure, for fwd/bwd compat.
+        */
+       __u32                   size;
+
+       /*
+        * Type specific configuration information.
+        */
+       __u64                   config;
+
+       union {
+               __u64           sample_period;
+               __u64           sample_freq;
+       };
+
+       __u64                   sample_type;
+       __u64                   read_format;
+
+       __u64                   disabled       :  1, /* off by default        */
+                               inherit        :  1, /* children inherit it   */
+                               pinned         :  1, /* must always be on PMU */
+                               exclusive      :  1, /* only group on PMU     */
+                               exclude_user   :  1, /* don't count user      */
+                               exclude_kernel :  1, /* ditto kernel          */
+                               exclude_hv     :  1, /* ditto hypervisor      */
+                               exclude_idle   :  1, /* don't count when idle */
+                               mmap           :  1, /* include mmap data     */
+                               comm           :  1, /* include comm data     */
+                               freq           :  1, /* use freq, not period  */
+                               inherit_stat   :  1, /* per task counts       */
+                               enable_on_exec :  1, /* next exec enables     */
+                               task           :  1, /* trace fork/exit       */
+                               watermark      :  1, /* wakeup_watermark      */
+
+                               __reserved_1   : 49;
+
+       union {
+               __u32           wakeup_events;    /* wakeup every n events */
+               __u32           wakeup_watermark; /* bytes before wakeup   */
+       };
+       __u32                   __reserved_2;
+
+       __u64                   __reserved_3;
+};
+
+/*
+ * Ioctls that can be done on a perf event fd:
+ */
+#define PERF_EVENT_IOC_ENABLE          _IO ('$', 0)
+#define PERF_EVENT_IOC_DISABLE         _IO ('$', 1)
+#define PERF_EVENT_IOC_REFRESH         _IO ('$', 2)
+#define PERF_EVENT_IOC_RESET           _IO ('$', 3)
+#define PERF_EVENT_IOC_PERIOD          _IOW('$', 4, u64)
+#define PERF_EVENT_IOC_SET_OUTPUT      _IO ('$', 5)
+
+enum perf_event_ioc_flags {
+       PERF_IOC_FLAG_GROUP             = 1U << 0,
+};
+
+/*
+ * Structure of the page that can be mapped via mmap
+ */
+struct perf_event_mmap_page {
+       __u32   version;                /* version number of this structure */
+       __u32   compat_version;         /* lowest version this is compat with */
+
+       /*
+        * Bits needed to read the hw events in user-space.
+        *
+        *   u32 seq;
+        *   s64 count;
+        *
+        *   do {
+        *     seq = pc->lock;
+        *
+        *     barrier()
+        *     if (pc->index) {
+        *       count = pmc_read(pc->index - 1);
+        *       count += pc->offset;
+        *     } else
+        *       goto regular_read;
+        *
+        *     barrier();
+        *   } while (pc->lock != seq);
+        *
+        * NOTE: for obvious reason this only works on self-monitoring
+        *       processes.
+        */
+       __u32   lock;                   /* seqlock for synchronization */
+       __u32   index;                  /* hardware event identifier */
+       __s64   offset;                 /* add to hardware event value */
+       __u64   time_enabled;           /* time event active */
+       __u64   time_running;           /* time event on cpu */
+
+               /*
+                * Hole for extension of the self monitor capabilities
+                */
+
+       __u64   __reserved[123];        /* align to 1k */
+
+       /*
+        * Control data for the mmap() data buffer.
+        *
+        * User-space reading the @data_head value should issue an rmb(), on
+        * SMP capable platforms, after reading this value -- see
+        * perf_event_wakeup().
+        *
+        * When the mapping is PROT_WRITE the @data_tail value should be
+        * written by userspace to reflect the last read data. In this case
+        * the kernel will not over-write unread data.
+        */
+       __u64   data_head;              /* head in the data section */
+       __u64   data_tail;              /* user-space written tail */
+};
+
+#define PERF_RECORD_MISC_CPUMODE_MASK          (3 << 0)
+#define PERF_RECORD_MISC_CPUMODE_UNKNOWN               (0 << 0)
+#define PERF_RECORD_MISC_KERNEL                        (1 << 0)
+#define PERF_RECORD_MISC_USER                  (2 << 0)
+#define PERF_RECORD_MISC_HYPERVISOR            (3 << 0)
+
+struct perf_event_header {
+       __u32   type;
+       __u16   misc;
+       __u16   size;
+};
+
+enum perf_event_type {
+
+       /*
+        * The MMAP events record the PROT_EXEC mappings so that we can
+        * correlate userspace IPs to code. They have the following structure:
+        *
+        * struct {
+        *      struct perf_event_header        header;
+        *
+        *      u32                             pid, tid;
+        *      u64                             addr;
+        *      u64                             len;
+        *      u64                             pgoff;
+        *      char                            filename[];
+        * };
+        */
+       PERF_RECORD_MMAP                        = 1,
+
+       /*
+        * struct {
+        *      struct perf_event_header        header;
+        *      u64                             id;
+        *      u64                             lost;
+        * };
+        */
+       PERF_RECORD_LOST                        = 2,
+
+       /*
+        * struct {
+        *      struct perf_event_header        header;
+        *
+        *      u32                             pid, tid;
+        *      char                            comm[];
+        * };
+        */
+       PERF_RECORD_COMM                        = 3,
+
+       /*
+        * struct {
+        *      struct perf_event_header        header;
+        *      u32                             pid, ppid;
+        *      u32                             tid, ptid;
+        *      u64                             time;
+        * };
+        */
+       PERF_RECORD_EXIT                        = 4,
+
+       /*
+        * struct {
+        *      struct perf_event_header        header;
+        *      u64                             time;
+        *      u64                             id;
+        *      u64                             stream_id;
+        * };
+        */
+       PERF_RECORD_THROTTLE            = 5,
+       PERF_RECORD_UNTHROTTLE          = 6,
+
+       /*
+        * struct {
+        *      struct perf_event_header        header;
+        *      u32                             pid, ppid;
+        *      u32                             tid, ptid;
+        *      u64                             time;
+        * };
+        */
+       PERF_RECORD_FORK                        = 7,
+
+       /*
+        * struct {
+        *      struct perf_event_header        header;
+        *      u32                             pid, tid;
+        *
+        *      struct read_format              values;
+        * };
+        */
+       PERF_RECORD_READ                        = 8,
+
+       /*
+        * struct {
+        *      struct perf_event_header        header;
+        *
+        *      { u64                   ip;       } && PERF_SAMPLE_IP
+        *      { u32                   pid, tid; } && PERF_SAMPLE_TID
+        *      { u64                   time;     } && PERF_SAMPLE_TIME
+        *      { u64                   addr;     } && PERF_SAMPLE_ADDR
+        *      { u64                   id;       } && PERF_SAMPLE_ID
+        *      { u64                   stream_id;} && PERF_SAMPLE_STREAM_ID
+        *      { u32                   cpu, res; } && PERF_SAMPLE_CPU
+        *      { u64                   period;   } && PERF_SAMPLE_PERIOD
+        *
+        *      { struct read_format    values;   } && PERF_SAMPLE_READ
+        *
+        *      { u64                   nr,
+        *        u64                   ips[nr];  } && PERF_SAMPLE_CALLCHAIN
+        *
+        *      #
+        *      # The RAW record below is opaque data wrt the ABI
+        *      #
+        *      # That is, the ABI doesn't make any promises wrt to
+        *      # the stability of its content, it may vary depending
+        *      # on event, hardware, kernel version and phase of
+        *      # the moon.
+        *      #
+        *      # In other words, PERF_SAMPLE_RAW contents are not an ABI.
+        *      #
+        *
+        *      { u32                   size;
+        *        char                  data[size];}&& PERF_SAMPLE_RAW
+        * };
+        */
+       PERF_RECORD_SAMPLE              = 9,
+
+       PERF_RECORD_MAX,                        /* non-ABI */
+};
+
+enum perf_callchain_context {
+       PERF_CONTEXT_HV                 = (__u64)-32,
+       PERF_CONTEXT_KERNEL             = (__u64)-128,
+       PERF_CONTEXT_USER               = (__u64)-512,
+
+       PERF_CONTEXT_GUEST              = (__u64)-2048,
+       PERF_CONTEXT_GUEST_KERNEL       = (__u64)-2176,
+       PERF_CONTEXT_GUEST_USER         = (__u64)-2560,
+
+       PERF_CONTEXT_MAX                = (__u64)-4095,
+};
+
+#define PERF_FLAG_FD_NO_GROUP  (1U << 0)
+#define PERF_FLAG_FD_OUTPUT    (1U << 1)
+
+#ifdef __KERNEL__
+/*
+ * Kernel-internal data types and definitions:
+ */
+
+#ifdef CONFIG_PERF_EVENTS
+# include <asm/perf_event.h>
+#endif
+
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/rculist.h>
+#include <linux/rcupdate.h>
+#include <linux/spinlock.h>
+#include <linux/hrtimer.h>
+#include <linux/fs.h>
+#include <linux/pid_namespace.h>
+#include <linux/workqueue.h>
+#include <asm/atomic.h>
+
+#define PERF_MAX_STACK_DEPTH           255
+
+struct perf_callchain_entry {
+       __u64                           nr;
+       __u64                           ip[PERF_MAX_STACK_DEPTH];
+};
+
+struct perf_raw_record {
+       u32                             size;
+       void                            *data;
+};
+
+struct task_struct;
+
+/**
+ * struct hw_perf_event - performance event hardware details:
+ */
+struct hw_perf_event {
+#ifdef CONFIG_PERF_EVENTS
+       union {
+               struct { /* hardware */
+                       u64             config;
+                       unsigned long   config_base;
+                       unsigned long   event_base;
+                       int             idx;
+               };
+               struct { /* software */
+                       s64             remaining;
+                       struct hrtimer  hrtimer;
+               };
+       };
+       atomic64_t                      prev_count;
+       u64                             sample_period;
+       u64                             last_period;
+       atomic64_t                      period_left;
+       u64                             interrupts;
+
+       u64                             freq_count;
+       u64                             freq_interrupts;
+       u64                             freq_stamp;
+#endif
+};
+
+struct perf_event;
+
+/**
+ * struct pmu - generic performance monitoring unit
+ */
+struct pmu {
+       int (*enable)                   (struct perf_event *event);
+       void (*disable)                 (struct perf_event *event);
+       void (*read)                    (struct perf_event *event);
+       void (*unthrottle)              (struct perf_event *event);
+};
+
+/**
+ * enum perf_event_active_state - the states of a event
+ */
+enum perf_event_active_state {
+       PERF_EVENT_STATE_ERROR          = -2,
+       PERF_EVENT_STATE_OFF            = -1,
+       PERF_EVENT_STATE_INACTIVE       =  0,
+       PERF_EVENT_STATE_ACTIVE         =  1,
+};
+
+struct file;
+
+struct perf_mmap_data {
+       struct rcu_head                 rcu_head;
+#ifdef CONFIG_PERF_USE_VMALLOC
+       struct work_struct              work;
+#endif
+       int                             data_order;
+       int                             nr_pages;       /* nr of data pages  */
+       int                             writable;       /* are we writable   */
+       int                             nr_locked;      /* nr pages mlocked  */
+
+       atomic_t                        poll;           /* POLL_ for wakeups */
+       atomic_t                        events;         /* event_id limit       */
+
+       atomic_long_t                   head;           /* write position    */
+       atomic_long_t                   done_head;      /* completed head    */
+
+       atomic_t                        lock;           /* concurrent writes */
+       atomic_t                        wakeup;         /* needs a wakeup    */
+       atomic_t                        lost;           /* nr records lost   */
+
+       long                            watermark;      /* wakeup watermark  */
+
+       struct perf_event_mmap_page     *user_page;
+       void                            *data_pages[0];
+};
+
+struct perf_pending_entry {
+       struct perf_pending_entry *next;
+       void (*func)(struct perf_pending_entry *);
+};
+
+/**
+ * struct perf_event - performance event kernel representation:
+ */
+struct perf_event {
+#ifdef CONFIG_PERF_EVENTS
+       struct list_head                group_entry;
+       struct list_head                event_entry;
+       struct list_head                sibling_list;
+       int                             nr_siblings;
+       struct perf_event               *group_leader;
+       struct perf_event               *output;
+       const struct pmu                *pmu;
+
+       enum perf_event_active_state    state;
+       atomic64_t                      count;
+
+       /*
+        * These are the total time in nanoseconds that the event
+        * has been enabled (i.e. eligible to run, and the task has
+        * been scheduled in, if this is a per-task event)
+        * and running (scheduled onto the CPU), respectively.
+        *
+        * They are computed from tstamp_enabled, tstamp_running and
+        * tstamp_stopped when the event is in INACTIVE or ACTIVE state.
+        */
+       u64                             total_time_enabled;
+       u64                             total_time_running;
+
+       /*
+        * These are timestamps used for computing total_time_enabled
+        * and total_time_running when the event is in INACTIVE or
+        * ACTIVE state, measured in nanoseconds from an arbitrary point
+        * in time.
+        * tstamp_enabled: the notional time when the event was enabled
+        * tstamp_running: the notional time when the event was scheduled on
+        * tstamp_stopped: in INACTIVE state, the notional time when the
+        *      event was scheduled off.
+        */
+       u64                             tstamp_enabled;
+       u64                             tstamp_running;
+       u64                             tstamp_stopped;
+
+       struct perf_event_attr  attr;
+       struct hw_perf_event            hw;
+
+       struct perf_event_context       *ctx;
+       struct file                     *filp;
+
+       /*
+        * These accumulate total time (in nanoseconds) that children
+        * events have been enabled and running, respectively.
+        */
+       atomic64_t                      child_total_time_enabled;
+       atomic64_t                      child_total_time_running;
+
+       /*
+        * Protect attach/detach and child_list:
+        */
+       struct mutex                    child_mutex;
+       struct list_head                child_list;
+       struct perf_event               *parent;
+
+       int                             oncpu;
+       int                             cpu;
+
+       struct list_head                owner_entry;
+       struct task_struct              *owner;
+
+       /* mmap bits */
+       struct mutex                    mmap_mutex;
+       atomic_t                        mmap_count;
+       struct perf_mmap_data           *data;
+
+       /* poll related */
+       wait_queue_head_t               waitq;
+       struct fasync_struct            *fasync;
+
+       /* delayed work for NMIs and such */
+       int                             pending_wakeup;
+       int                             pending_kill;
+       int                             pending_disable;
+       struct perf_pending_entry       pending;
+
+       atomic_t                        event_limit;
+
+       void (*destroy)(struct perf_event *);
+       struct rcu_head                 rcu_head;
+
+       struct pid_namespace            *ns;
+       u64                             id;
+#endif
+};
+
+/**
+ * struct perf_event_context - event context structure
+ *
+ * Used as a container for task events and CPU events as well:
+ */
+struct perf_event_context {
+       /*
+        * Protect the states of the events in the list,
+        * nr_active, and the list:
+        */
+       spinlock_t                      lock;
+       /*
+        * Protect the list of events.  Locking either mutex or lock
+        * is sufficient to ensure the list doesn't change; to change
+        * the list you need to lock both the mutex and the spinlock.
+        */
+       struct mutex                    mutex;
+
+       struct list_head                group_list;
+       struct list_head                event_list;
+       int                             nr_events;
+       int                             nr_active;
+       int                             is_active;
+       int                             nr_stat;
+       atomic_t                        refcount;
+       struct task_struct              *task;
+
+       /*
+        * Context clock, runs when context enabled.
+        */
+       u64                             time;
+       u64                             timestamp;
+
+       /*
+        * These fields let us detect when two contexts have both
+        * been cloned (inherited) from a common ancestor.
+        */
+       struct perf_event_context       *parent_ctx;
+       u64                             parent_gen;
+       u64                             generation;
+       int                             pin_count;
+       struct rcu_head                 rcu_head;
+};
+
+/**
+ * struct perf_event_cpu_context - per cpu event context structure
+ */
+struct perf_cpu_context {
+       struct perf_event_context       ctx;
+       struct perf_event_context       *task_ctx;
+       int                             active_oncpu;
+       int                             max_pertask;
+       int                             exclusive;
+
+       /*
+        * Recursion avoidance:
+        *
+        * task, softirq, irq, nmi context
+        */
+       int                             recursion[4];
+};
+
+struct perf_output_handle {
+       struct perf_event               *event;
+       struct perf_mmap_data           *data;
+       unsigned long                   head;
+       unsigned long                   offset;
+       int                             nmi;
+       int                             sample;
+       int                             locked;
+       unsigned long                   flags;
+};
+
+#ifdef CONFIG_PERF_EVENTS
+
+/*
+ * Set by architecture code:
+ */
+extern int perf_max_events;
+
+extern const struct pmu *hw_perf_event_init(struct perf_event *event);
+
+extern void perf_event_task_sched_in(struct task_struct *task, int cpu);
+extern void perf_event_task_sched_out(struct task_struct *task,
+                                       struct task_struct *next, int cpu);
+extern void perf_event_task_tick(struct task_struct *task, int cpu);
+extern int perf_event_init_task(struct task_struct *child);
+extern void perf_event_exit_task(struct task_struct *child);
+extern void perf_event_free_task(struct task_struct *task);
+extern void set_perf_event_pending(void);
+extern void perf_event_do_pending(void);
+extern void perf_event_print_debug(void);
+extern void __perf_disable(void);
+extern bool __perf_enable(void);
+extern void perf_disable(void);
+extern void perf_enable(void);
+extern int perf_event_task_disable(void);
+extern int perf_event_task_enable(void);
+extern int hw_perf_group_sched_in(struct perf_event *group_leader,
+              struct perf_cpu_context *cpuctx,
+              struct perf_event_context *ctx, int cpu);
+extern void perf_event_update_userpage(struct perf_event *event);
+
+struct perf_sample_data {
+       u64                             type;
+
+       u64                             ip;
+       struct {
+               u32     pid;
+               u32     tid;
+       }                               tid_entry;
+       u64                             time;
+       u64                             addr;
+       u64                             id;
+       u64                             stream_id;
+       struct {
+               u32     cpu;
+               u32     reserved;
+       }                               cpu_entry;
+       u64                             period;
+       struct perf_callchain_entry     *callchain;
+       struct perf_raw_record          *raw;
+};
+
+extern void perf_output_sample(struct perf_output_handle *handle,
+                              struct perf_event_header *header,
+                              struct perf_sample_data *data,
+                              struct perf_event *event);
+extern void perf_prepare_sample(struct perf_event_header *header,
+                               struct perf_sample_data *data,
+                               struct perf_event *event,
+                               struct pt_regs *regs);
+
+extern int perf_event_overflow(struct perf_event *event, int nmi,
+                                struct perf_sample_data *data,
+                                struct pt_regs *regs);
+
+/*
+ * Return 1 for a software event, 0 for a hardware event
+ */
+static inline int is_software_event(struct perf_event *event)
+{
+       return (event->attr.type != PERF_TYPE_RAW) &&
+               (event->attr.type != PERF_TYPE_HARDWARE) &&
+               (event->attr.type != PERF_TYPE_HW_CACHE);
+}
+
+extern atomic_t perf_swevent_enabled[PERF_COUNT_SW_MAX];
+
+extern void __perf_sw_event(u32, u64, int, struct pt_regs *, u64);
+
+static inline void
+perf_sw_event(u32 event_id, u64 nr, int nmi, struct pt_regs *regs, u64 addr)
+{
+       if (atomic_read(&perf_swevent_enabled[event_id]))
+               __perf_sw_event(event_id, nr, nmi, regs, addr);
+}
+
+extern void __perf_event_mmap(struct vm_area_struct *vma);
+
+static inline void perf_event_mmap(struct vm_area_struct *vma)
+{
+       if (vma->vm_flags & VM_EXEC)
+               __perf_event_mmap(vma);
+}
+
+extern void perf_event_comm(struct task_struct *tsk);
+extern void perf_event_fork(struct task_struct *tsk);
+
+extern struct perf_callchain_entry *perf_callchain(struct pt_regs *regs);
+
+extern int sysctl_perf_event_paranoid;
+extern int sysctl_perf_event_mlock;
+extern int sysctl_perf_event_sample_rate;
+
+extern void perf_event_init(void);
+extern void perf_tp_event(int event_id, u64 addr, u64 count,
+                                void *record, int entry_size);
+
+#ifndef perf_misc_flags
+#define perf_misc_flags(regs)  (user_mode(regs) ? PERF_RECORD_MISC_USER : \
+                                PERF_RECORD_MISC_KERNEL)
+#define perf_instruction_pointer(regs) instruction_pointer(regs)
+#endif
+
+extern int perf_output_begin(struct perf_output_handle *handle,
+                            struct perf_event *event, unsigned int size,
+                            int nmi, int sample);
+extern void perf_output_end(struct perf_output_handle *handle);
+extern void perf_output_copy(struct perf_output_handle *handle,
+                            const void *buf, unsigned int len);
+#else
+static inline void
+perf_event_task_sched_in(struct task_struct *task, int cpu)            { }
+static inline void
+perf_event_task_sched_out(struct task_struct *task,
+                           struct task_struct *next, int cpu)          { }
+static inline void
+perf_event_task_tick(struct task_struct *task, int cpu)                        { }
+static inline int perf_event_init_task(struct task_struct *child)      { return 0; }
+static inline void perf_event_exit_task(struct task_struct *child)     { }
+static inline void perf_event_free_task(struct task_struct *task)      { }
+static inline void perf_event_do_pending(void)                         { }
+static inline void perf_event_print_debug(void)                                { }
+static inline void perf_disable(void)                                  { }
+static inline void perf_enable(void)                                   { }
+static inline int perf_event_task_disable(void)                                { return -EINVAL; }
+static inline int perf_event_task_enable(void)                         { return -EINVAL; }
+
+static inline void
+perf_sw_event(u32 event_id, u64 nr, int nmi,
+                    struct pt_regs *regs, u64 addr)                    { }
+
+static inline void perf_event_mmap(struct vm_area_struct *vma)         { }
+static inline void perf_event_comm(struct task_struct *tsk)            { }
+static inline void perf_event_fork(struct task_struct *tsk)            { }
+static inline void perf_event_init(void)                               { }
+
+#endif
+
+#define perf_output_put(handle, x) \
+       perf_output_copy((handle), &(x), sizeof(x))
+
+#endif /* __KERNEL__ */
+
+
+#if 0
+/*
+ * trace_flag_type is an enumeration that holds different
+ * states when a trace occurs. These are:
+ *  IRQS_OFF            - interrupts were disabled
+ *  IRQS_NOSUPPORT      - arch does not support irqs_disabled_flags
+ *  NEED_RESCED         - reschedule is requested
+ *  HARDIRQ             - inside an interrupt handler
+ *  SOFTIRQ             - inside a softirq handler
+ */
+enum trace_flag_type {
+       TRACE_FLAG_IRQS_OFF             = 0x01,
+       TRACE_FLAG_IRQS_NOSUPPORT       = 0x02,
+       TRACE_FLAG_NEED_RESCHED         = 0x04,
+       TRACE_FLAG_HARDIRQ              = 0x08,
+       TRACE_FLAG_SOFTIRQ              = 0x10,
+};
+#endif
+
+#endif /* _LINUX_PERF_EVENT_H */
diff --git a/src/powertop.css b/src/powertop.css
new file mode 100644 (file)
index 0000000..c73d3e2
--- /dev/null
@@ -0,0 +1,554 @@
+<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">
+<html>
+<head>
+<title>PowerTOP report</title>
+<meta http-equiv=\"content-type\" content=\"text/html;charset=utf-8\">
+<script type=\"text/javascript\" src=\"http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js\"></script>
+<script type=\"text/javascript\">
+$(document).ready(function(){
+
+       $('#system h2').addClass('hide');
+       $('#system table').addClass('hide');
+       $('#cpuidle h2').addClass('hide');
+       $('#cpuidle table').addClass('hide');
+       $('#cpufreq h2').addClass('hide');
+       $('#cpufreq table').addClass('hide');
+       $('#software h2').addClass('hide');
+       $('#software table').addClass('hide');
+       $('#device h2').addClass('hide');
+       $('#device table').addClass('hide');
+       $('#device p').addClass('hide');
+       $('#tuning h2').addClass('hide');
+       $('#tuning table').addClass('hide');
+
+       $('#top').append('<div class=\"SystemButton\"   onclick=\"toggleSystem()\">System Info</div>');
+       $('#top').append('<div class=\"SummaryButton\"  onclick=\"toggleSummary()\">Summary</div>');
+       $('#top').append('<div class=\"CpuidleButton\"  onclick=\"toggleCpuidle()\">CPU Idle</div>');
+       $('#top').append('<div class=\"CpufreqButton\"  onclick=\"toggleCpufreq()\">CPU Frequency</div>');
+       $('#top').append('<div class=\"SoftwareButton\" onclick=\"toggleSoftware()\">Software info</div>');
+       $('#top').append('<div class=\"DeviceButton\"   onclick=\"toggleDevice()\">Device Info</div>');
+       $('#top').append('<div class=\"TuningButton\"   onclick=\"toggleTuning()\">Tuning</div>');
+       $('#top').append('<div class=\"AllButton\"      onclick=\"toggleAll()\">All</div>');
+       $('#top .SummaryButton').toggleClass('pressed');
+
+    }
+       );
+function toggleDummy() {
+               $('#system table').toggleClass('hide', true);
+               $('#system h2').toggleClass('hide', true);
+               $('#summary table').toggleClass('hide', true);
+               $('#summary h2').toggleClass('hide', true);
+               $('#summary p').toggleClass('hide', true);
+               $('#cpuidle table').toggleClass('hide', true);
+               $('#cpuidle h2').toggleClass('hide', true);
+               $('#cpufreq table').toggleClass('hide', true);
+               $('#cpufreq h2').toggleClass('hide', true);
+               $('#software table').toggleClass('hide', true);
+               $('#software h2').toggleClass('hide', true);
+               $('#device table').toggleClass('hide', true);
+               $('#device h2').toggleClass('hide', true);
+               $('#device p').toggleClass('hide', true);
+               $('#tuning table').toggleClass('hide', true);
+               $('#tuning h2').toggleClass('hide', true);
+               $('#top .SystemButton').toggleClass('pressed', false);
+               $('#top .SummaryButton').toggleClass('pressed', false);
+               $('#top .CpuidleButton').toggleClass('pressed', false);
+               $('#top .CpufreqButton').toggleClass('pressed', false);
+               $('#top .SoftwareButton').toggleClass('pressed', false);
+               $('#top .DeviceButton').toggleClass('pressed', false);
+               $('#top .TuningButton').toggleClass('pressed', false);
+               $('#top .AllButton').toggleClass('pressed', false);
+}
+function toggleSystem() {
+               $('#system table').toggleClass('hide', false);
+               $('#system h2').toggleClass('hide', false);
+               $('#summary table').toggleClass('hide', true);
+               $('#summary h2').toggleClass('hide', true);
+               $('#summary p').toggleClass('hide', true);
+               $('#cpuidle table').toggleClass('hide', true);
+               $('#cpuidle h2').toggleClass('hide', true);
+               $('#cpufreq table').toggleClass('hide', true);
+               $('#cpufreq h2').toggleClass('hide', true);
+               $('#software table').toggleClass('hide', true);
+               $('#software h2').toggleClass('hide', true);
+               $('#device table').toggleClass('hide', true);
+               $('#device h2').toggleClass('hide', true);
+               $('#device p').toggleClass('hide', true);
+               $('#tuning table').toggleClass('hide', true);
+               $('#tuning h2').toggleClass('hide', true);
+               $('#top .SystemButton').toggleClass('pressed', true);
+               $('#top .SummaryButton').toggleClass('pressed', false);
+               $('#top .CpuidleButton').toggleClass('pressed', false);
+               $('#top .CpufreqButton').toggleClass('pressed', false);
+               $('#top .SoftwareButton').toggleClass('pressed', false);
+               $('#top .DeviceButton').toggleClass('pressed', false);
+               $('#top .TuningButton').toggleClass('pressed', false);
+               $('#top .AllButton').toggleClass('pressed', false);
+}
+function toggleSummary() {
+               $('#system table').toggleClass('hide', true);
+               $('#system h2').toggleClass('hide', true);
+               $('#summary table').toggleClass('hide', false);
+               $('#summary h2').toggleClass('hide', false);
+               $('#summary p').toggleClass('hide', false);
+               $('#cpuidle table').toggleClass('hide', true);
+               $('#cpuidle h2').toggleClass('hide', true);
+               $('#cpufreq table').toggleClass('hide', true);
+               $('#cpufreq h2').toggleClass('hide', true);
+               $('#software table').toggleClass('hide', true);
+               $('#software h2').toggleClass('hide', true);
+               $('#device table').toggleClass('hide', true);
+               $('#device h2').toggleClass('hide', true);
+               $('#device p').toggleClass('hide', true);
+               $('#tuning table').toggleClass('hide', true);
+               $('#tuning h2').toggleClass('hide', true);
+               $('#top .SystemButton').toggleClass('pressed', false);
+               $('#top .SummaryButton').toggleClass('pressed', true);
+               $('#top .CpuidleButton').toggleClass('pressed', false);
+               $('#top .CpufreqButton').toggleClass('pressed', false);
+               $('#top .SoftwareButton').toggleClass('pressed', false);
+               $('#top .DeviceButton').toggleClass('pressed', false);
+               $('#top .TuningButton').toggleClass('pressed', false);
+               $('#top .AllButton').toggleClass('pressed', false);
+}
+function toggleCpuidle() {
+               $('#system table').toggleClass('hide', true);
+               $('#system h2').toggleClass('hide', true);
+               $('#summary table').toggleClass('hide', true);
+               $('#summary h2').toggleClass('hide', true);
+               $('#summary p').toggleClass('hide', true);
+               $('#cpuidle table').toggleClass('hide', false);
+               $('#cpuidle h2').toggleClass('hide', false);
+               $('#cpufreq table').toggleClass('hide', true);
+               $('#cpufreq h2').toggleClass('hide', true);
+               $('#software table').toggleClass('hide', true);
+               $('#software h2').toggleClass('hide', true);
+               $('#device table').toggleClass('hide', true);
+               $('#device h2').toggleClass('hide', true);
+               $('#device p').toggleClass('hide', true);
+               $('#tuning table').toggleClass('hide', true);
+               $('#tuning h2').toggleClass('hide', true);
+               $('#top .SystemButton').toggleClass('pressed', false);
+               $('#top .SummaryButton').toggleClass('pressed', false);
+               $('#top .CpuidleButton').toggleClass('pressed', true);
+               $('#top .CpufreqButton').toggleClass('pressed', false);
+               $('#top .SoftwareButton').toggleClass('pressed', false);
+               $('#top .DeviceButton').toggleClass('pressed', false);
+               $('#top .TuningButton').toggleClass('pressed', false);
+               $('#top .AllButton').toggleClass('pressed', false);
+
+}
+function toggleCpufreq() {
+               $('#system table').toggleClass('hide', true);
+               $('#system h2').toggleClass('hide', true);
+               $('#summary table').toggleClass('hide', true);
+               $('#summary h2').toggleClass('hide', true);
+               $('#summary p').toggleClass('hide', true);
+               $('#cpuidle table').toggleClass('hide', true);
+               $('#cpuidle h2').toggleClass('hide', true);
+               $('#cpufreq table').toggleClass('hide', false);
+               $('#cpufreq h2').toggleClass('hide', false);
+               $('#software table').toggleClass('hide', true);
+               $('#software h2').toggleClass('hide', true);
+               $('#device table').toggleClass('hide', true);
+               $('#device h2').toggleClass('hide', true);
+               $('#device p').toggleClass('hide', true);
+               $('#tuning table').toggleClass('hide', true);
+               $('#tuning h2').toggleClass('hide', true);
+               $('#top .SystemButton').toggleClass('pressed', false);
+               $('#top .SummaryButton').toggleClass('pressed', false);
+               $('#top .CpuidleButton').toggleClass('pressed', false);
+               $('#top .CpufreqButton').toggleClass('pressed', true);
+               $('#top .SoftwareButton').toggleClass('pressed', false);
+               $('#top .DeviceButton').toggleClass('pressed', false);
+               $('#top .TuningButton').toggleClass('pressed', false);
+               $('#top .AllButton').toggleClass('pressed', false);
+}
+
+function toggleSoftware() {
+               $('#system table').toggleClass('hide', true);
+               $('#system h2').toggleClass('hide', true);
+               $('#summary table').toggleClass('hide', true);
+               $('#summary h2').toggleClass('hide', true);
+               $('#summary p').toggleClass('hide', true);
+               $('#cpuidle table').toggleClass('hide', true);
+               $('#cpuidle h2').toggleClass('hide', true);
+               $('#cpufreq table').toggleClass('hide', true);
+               $('#cpufreq h2').toggleClass('hide', true);
+               $('#software table').toggleClass('hide', false);
+               $('#software h2').toggleClass('hide', false);
+               $('#device table').toggleClass('hide', true);
+               $('#device h2').toggleClass('hide', true);
+               $('#device p').toggleClass('hide', true);
+               $('#tuning table').toggleClass('hide', true);
+               $('#tuning h2').toggleClass('hide', true);
+               $('#top .SystemButton').toggleClass('pressed', false);
+               $('#top .SummaryButton').toggleClass('pressed', false);
+               $('#top .CpuidleButton').toggleClass('pressed', false);
+               $('#top .CpufreqButton').toggleClass('pressed', false);
+               $('#top .SoftwareButton').toggleClass('pressed', true);
+               $('#top .DeviceButton').toggleClass('pressed', false);
+               $('#top .TuningButton').toggleClass('pressed', false);
+               $('#top .AllButton').toggleClass('pressed', false);
+}
+
+function toggleDevice() {
+               $('#system table').toggleClass('hide', true);
+               $('#system h2').toggleClass('hide', true);
+               $('#summary table').toggleClass('hide', true);
+               $('#summary h2').toggleClass('hide', true);
+               $('#summary p').toggleClass('hide', true);
+               $('#cpuidle table').toggleClass('hide', true);
+               $('#cpuidle h2').toggleClass('hide', true);
+               $('#cpufreq table').toggleClass('hide', true);
+               $('#cpufreq h2').toggleClass('hide', true);
+               $('#software table').toggleClass('hide', true);
+               $('#software h2').toggleClass('hide', true);
+               $('#device table').toggleClass('hide', false);
+               $('#device h2').toggleClass('hide', false);
+               $('#device p').toggleClass('hide', false);
+               $('#tuning table').toggleClass('hide', true);
+               $('#tuning h2').toggleClass('hide', true);
+               $('#top .SystemButton').toggleClass('pressed', false);
+               $('#top .SummaryButton').toggleClass('pressed', false);
+               $('#top .CpuidleButton').toggleClass('pressed', false);
+               $('#top .CpufreqButton').toggleClass('pressed', false);
+               $('#top .SoftwareButton').toggleClass('pressed', false);
+               $('#top .DeviceButton').toggleClass('pressed', true);
+               $('#top .TuningButton').toggleClass('pressed', false);
+               $('#top .AllButton').toggleClass('pressed', false);
+}
+
+function toggleTuning() {
+               $('#system table').toggleClass('hide', true);
+               $('#system h2').toggleClass('hide', true);
+               $('#summary table').toggleClass('hide', true);
+               $('#summary h2').toggleClass('hide', true);
+               $('#summary p').toggleClass('hide', true);
+               $('#cpuidle table').toggleClass('hide', true);
+               $('#cpuidle h2').toggleClass('hide', true);
+               $('#cpufreq table').toggleClass('hide', true);
+               $('#cpufreq h2').toggleClass('hide', true);
+               $('#software table').toggleClass('hide', true);
+               $('#software h2').toggleClass('hide', true);
+               $('#device table').toggleClass('hide', true);
+               $('#device h2').toggleClass('hide', true);
+               $('#device p').toggleClass('hide', true);
+               $('#tuning table').toggleClass('hide', false);
+               $('#tuning h2').toggleClass('hide', false);
+               $('#top .SystemButton').toggleClass('pressed', false);
+               $('#top .SummaryButton').toggleClass('pressed', false);
+               $('#top .CpuidleButton').toggleClass('pressed', false);
+               $('#top .CpufreqButton').toggleClass('pressed', false);
+               $('#top .SoftwareButton').toggleClass('pressed', false);
+               $('#top .DeviceButton').toggleClass('pressed', false);
+               $('#top .TuningButton').toggleClass('pressed', true);
+               $('#top .AllButton').toggleClass('pressed', false);
+}
+function toggleAll() {
+               $('#system table').toggleClass('hide', false);
+               $('#system h2').toggleClass('hide', false);
+               $('#summary table').toggleClass('hide', false);
+               $('#summary h2').toggleClass('hide', false);
+               $('#summary p').toggleClass('hide', false);
+               $('#cpuidle table').toggleClass('hide', false);
+               $('#cpuidle h2').toggleClass('hide', false);
+               $('#cpufreq table').toggleClass('hide', false);
+               $('#cpufreq h2').toggleClass('hide', false);
+               $('#software table').toggleClass('hide', false);
+               $('#software h2').toggleClass('hide', false);
+               $('#device table').toggleClass('hide', false);
+               $('#device h2').toggleClass('hide', false);
+               $('#device p').toggleClass('hide', false);
+               $('#tuning table').toggleClass('hide', false);
+               $('#tuning h2').toggleClass('hide', false);
+               $('#top .SystemButton').toggleClass('pressed', false);
+               $('#top .SummaryButton').toggleClass('pressed', false);
+               $('#top .CpuidleButton').toggleClass('pressed', false);
+               $('#top .CpufreqButton').toggleClass('pressed', false);
+               $('#top .SoftwareButton').toggleClass('pressed', false);
+               $('#top .DeviceButton').toggleClass('pressed', false);
+               $('#top .TuningButton').toggleClass('pressed', false);
+               $('#top .AllButton').toggleClass('pressed', true);
+}
+</script>
+<style type=\"text/css\">
+table
+{
+       background-color: #F8F8F8;
+       color: black;
+}
+
+th
+{
+       text-align: right;
+}
+th.device
+{
+       text-align: left;
+}
+th.process
+{
+       text-align: left;
+}
+
+th.tunable
+{
+       text-align: left;
+}
+
+td.package_odd
+{
+       background-color: #E0ffE0;
+       color: black;
+       text-align: right;
+}
+td.package_even
+{
+       background-color: #F0ffF0;
+       color: black;
+       text-align: right;
+}
+
+td.core_even
+{
+       background-color: #F0ffF0;
+       color: black;
+       text-align: right;
+}
+
+td.core_odd
+{
+       background-color: #E0E0ff;
+       color: black;
+       text-align: right;
+}
+
+td.cpu_even_freq
+{
+       background-color: #E2E2E2;
+       color: black;
+}
+
+td.cpu_odd_freq
+{
+       background-color: #F4f4F4;
+       color: black;
+}
+
+td.cpu_even_even
+{
+       background-color: #E0E0f0;
+       color: black;
+       text-align: right;
+}
+
+td.cpu_even_odd
+{
+       background-color: #F0f0F0;
+       color: black;
+       text-align: right;
+}
+td.cpu_odd_even
+{
+       background-color: #E0E0ff;
+       color: black;
+       text-align: right;
+}
+
+td.cpu_odd_odd
+{
+       background-color: #F0ffF0;
+       color: black;
+       text-align: right;
+}
+
+tr.device_odd
+{
+       background-color: #E0E0E0;
+       color: black;
+}
+tr.device_even
+{
+       background-color: #F0f0F0;
+       color: black;
+}
+
+tr.process_odd
+{
+       background-color: #E0E0E0;
+       color: black;
+}
+tr.process_even
+{
+       background-color: #F0f0F0;
+       color: black;
+}
+
+td.device_power
+{
+       text-align: right;
+}
+
+td.process_power
+{
+       text-align: right;
+}
+
+td.device_util
+{
+       text-align: right;
+}
+
+tr.tunable_odd
+{
+       background-color: #E0E0E0;
+       color: black;
+}
+tr.tunable_even
+{
+       background-color: #F0f0F0;
+       color: black;
+}
+
+tr.tunable_odd_bad
+{
+       background-color: #FFE0E0;
+       color: black;
+}
+tr.tunable_even_bad
+{
+       background-color: #FFf0F0;
+       color: black;
+}
+
+tr.system_odd
+{
+       background-color: #E0E0E0;
+       color: black;
+}
+tr.system_even
+{
+       background-color: #F0f0F0;
+       color: black;
+}
+
+tr.device_odd
+{
+       background-color: #E0E0E0;
+       color: black;
+}
+tr.device_even
+{
+       background-color: #F0f0F0;
+       color: black;
+}
+
+body {
+       background-color: #eee; /* Background color */
+       color: #222;            /* Foreground color used for text */
+       font-family: Helvetica;
+       font-size: 14px;
+       margin: 0;              /* Amount of negative space around the
+                                   outside of the body */
+       padding: 0;             /* Amount of negative space around the
+                                   inside of the body */
+}
+#top h1 {
+       margin: 0;
+       padding: 0;
+}
+#top h1 a {
+       background-color: #ccc;
+       border-bottom: 1px solid #666;
+       color: #222;
+       display: block;
+       font-size: 20px;
+       font-weight: bold;
+       padding: 10px 0;
+       text-align: center;
+       text-decoration: none;
+       text-shadow: 0px 1px 1px #fff;
+       background-image: -webkit-gradient(linear, left top, left bottom,
+                                               from(#ccc), to(#999));
+}
+
+
+#top div {
+       height: 30px;
+       font-weight: bold;
+       text-align: center;
+       color: white;
+       text-shadow: rgba(0,0,0,0.6) 0px -1px 1px;
+       line-height: 28px;
+       border-width:0px 8px 0px 8px;
+}
+#top div.SystemButton {
+       position: absolute;
+       top: 7px;
+       left: 6px;
+}
+#top div.SummaryButton {
+       position: absolute;
+       top: 7px;
+       left: 160px;
+}
+#top div.CpuidleButton {
+       position: absolute;
+       top: 7px;
+       left: 320px;
+}
+#top div.CpufreqButton {
+       position: absolute;
+       top: 7px;
+       left: 480px;
+}
+#top div.SoftwareButton {
+       position: absolute;
+       top: 7px;
+       left: 640px;
+}
+#top div.DeviceButton {
+       position: absolute;
+       top: 7px;
+       left: 800px;
+}
+#top div.TuningButton {
+       position: absolute;
+       top: 7px;
+       left: 960px;
+}
+#top div.AllButton {
+       position: absolute;
+       top: 7px;
+       left: 1120px;
+}
+div.pressed {
+       background-color: #000000;
+       border: 1px solid #000000;
+       color: #000000;
+       display: block;
+       border-width:0px 8px 0px 8px;
+       -webkit-border-top-left-radius: 8px;
+       -webkit-border-top-right-radius: 8px;
+       -webkit-border-bottom-left-radius: 8px;
+       -webkit-border-bottom-right-radius: 8px;
+}
+table.hide {
+       display: none;
+}
+h2.hide {
+       display: none;
+}
+p.hide {
+       display: none
+}
+</style>
+</head>
+
+<body>
+
+<div id='top'>
+<h1><a href='#top'>&nbsp;</a></h1>
+</div>
+
diff --git a/src/process/do_process.cpp b/src/process/do_process.cpp
new file mode 100644 (file)
index 0000000..8f73083
--- /dev/null
@@ -0,0 +1,1185 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ *     Arjan van de Ven <arjan@linux.intel.com>
+ */
+#include "process.h"
+#include "interrupt.h"
+#include "timer.h"
+#include "work.h"
+#include "processdevice.h"
+#include "../lib.h"
+#include "../report/report.h"
+#include "../report/report-maker.h"
+#include "../devlist.h"
+
+#include <vector>
+#include <algorithm>
+#include <stack>
+
+#include <stdio.h>
+#include <string.h>
+#include <ncurses.h>
+
+#include "../perf/perf_bundle.h"
+#include "../perf/perf_event.h"
+#include "../parameters/parameters.h"
+#include "../display.h"
+#include "../measurement/measurement.h"
+
+static  class perf_bundle * perf_events;
+
+vector <class power_consumer *> all_power;
+
+vector< vector<class power_consumer *> > cpu_stack;
+
+vector<int> cpu_level;
+vector<int> cpu_credit;
+vector<class power_consumer *> cpu_blame;
+
+#define LEVEL_HARDIRQ  1
+#define LEVEL_SOFTIRQ  2
+#define LEVEL_TIMER    3
+#define LEVEL_WAKEUP   4
+#define LEVEL_PROCESS  5
+#define LEVEL_WORK     6
+
+static uint64_t first_stamp, last_stamp;
+
+double measurement_time;
+
+static void push_consumer(unsigned int cpu, class power_consumer *consumer)
+{
+       if (cpu_stack.size() <= cpu)
+               cpu_stack.resize(cpu + 1);
+       cpu_stack[cpu].push_back(consumer);
+}
+
+static void pop_consumer(unsigned int cpu)
+{
+       if (cpu_stack.size() <= cpu)
+               cpu_stack.resize(cpu + 1);
+
+       if (cpu_stack[cpu].size())
+               cpu_stack[cpu].resize(cpu_stack[cpu].size()-1);
+}
+
+static int consumer_depth(unsigned int cpu)
+{
+       if (cpu_stack.size() <= cpu)
+               cpu_stack.resize(cpu + 1);
+       return cpu_stack[cpu].size();
+}
+
+static class power_consumer *current_consumer(unsigned int cpu)
+{
+       if (cpu_stack.size() <= cpu)
+               cpu_stack.resize(cpu + 1);
+       if (cpu_stack[cpu].size())
+
+               return cpu_stack[cpu][cpu_stack[cpu].size()-1];
+
+       return NULL;
+}
+
+static void clear_consumers(void)
+{
+       unsigned int i;
+       for (i = 0; i < cpu_stack.size(); i++)
+               cpu_stack[i].resize(0);
+}
+
+static void consumer_child_time(unsigned int cpu, uint64_t time)
+{
+       unsigned int i;
+       if (cpu_stack.size() <= cpu)
+               cpu_stack.resize(cpu + 1);
+       for (i = 0; i < cpu_stack[cpu].size(); i++)
+               cpu_stack[cpu][i]->child_runtime += time;
+}
+
+static void set_wakeup_pending(unsigned int cpu)
+{
+       if (cpu_credit.size() <= cpu)
+               cpu_credit.resize(cpu + 1);
+
+       cpu_credit[cpu] = 1;
+}
+
+static void clear_wakeup_pending(unsigned int cpu)
+{
+       if (cpu_credit.size() <= cpu)
+               cpu_credit.resize(cpu + 1);
+
+       cpu_credit[cpu] = 0;
+}
+
+static int get_wakeup_pending(unsigned int cpu)
+{
+       if (cpu_credit.size() <= cpu)
+               cpu_credit.resize(cpu + 1);
+       return cpu_credit[cpu];
+}
+
+static void change_blame(unsigned int cpu, class power_consumer *consumer, int level)
+{
+       if (cpu_level[cpu] >= level)
+               return;
+       cpu_blame[cpu] = consumer;
+       cpu_level[cpu] = level;
+}
+
+static void consume_blame(unsigned int cpu)
+{
+       if (!get_wakeup_pending(cpu))
+               return;
+       if (cpu_level.size() <= cpu)
+               return;
+       if (cpu_blame.size() <= cpu)
+               return;
+       if (!cpu_blame[cpu])
+               return;
+
+       cpu_blame[cpu]->wake_ups++;
+       cpu_blame[cpu] = NULL;
+       cpu_level[cpu] = 0;
+       clear_wakeup_pending(cpu);
+}
+
+
+class perf_process_bundle: public perf_bundle
+{
+       virtual void handle_trace_point(void *trace, int cpu, uint64_t time);
+};
+
+static bool comm_is_xorg(char *comm)
+{
+       return strcmp(comm, "Xorg") == 0 || strcmp(comm, "X") == 0;
+}
+
+/* some processes shouldn't be blamed for the wakeup if they wake a process up... for now this is a hardcoded list */
+int dont_blame_me(char *comm)
+{
+       if (comm_is_xorg(comm))
+               return 1;
+       if (strcmp(comm, "dbus-daemon") == 0)
+               return 1;
+
+       return 0;
+}
+
+static void dbg_printf_pevent_info(struct event_format *event, struct pevent_record *rec)
+{
+       static struct trace_seq s;
+
+       event->pevent->print_raw = 1;
+       trace_seq_init(&s);
+       pevent_event_info(&s, event, rec);
+       trace_seq_putc(&s, '\n');
+       trace_seq_terminate(&s);
+       fprintf(stderr, "%.*s", s.len, s.buffer);
+       trace_seq_destroy(&s);
+}
+
+static char * get_pevent_field_str(void *trace, struct event_format *event, struct format_field *field)
+{
+       unsigned long long offset, len;
+       if (field->flags & FIELD_IS_DYNAMIC) {
+               offset = field->offset;
+               len = field->size;
+               offset = pevent_read_number(event->pevent, (char *)trace + offset, len);
+               offset &= 0xffff;
+               return (char *)trace + offset;
+       }
+       /** no __data_loc field type*/
+       return (char *)trace + field->offset;
+}
+
+void perf_process_bundle::handle_trace_point(void *trace, int cpu, uint64_t time)
+{
+       struct event_format *event;
+       struct pevent_record rec; /* holder */
+       struct format_field *field;
+       unsigned long long val;
+       int type;
+       int ret;
+
+       rec.data = trace;
+
+       type = pevent_data_type(perf_event::pevent, &rec);
+       event = pevent_find_event(perf_event::pevent, type);
+       if (!event)
+               return;
+
+       if (time < first_stamp)
+               first_stamp = time;
+
+       if (time > last_stamp) {
+               last_stamp = time;
+               measurement_time = (0.0001 + last_stamp - first_stamp) / 1000000000 ;
+       }
+
+       if (strcmp(event->name, "sched_switch") == 0) {
+               class process *old_proc = NULL;
+               class process *new_proc  = NULL;
+               const char *next_comm;
+               int next_pid;
+               int prev_pid;
+
+               field = pevent_find_any_field(event, "next_comm");
+               if (!field || !(field->flags & FIELD_IS_STRING))
+                       return; /* ?? */
+       
+               next_comm = get_pevent_field_str(trace, event, field);
+
+               ret = pevent_get_field_val(NULL, event, "next_pid", &rec, &val, 0);
+               if (ret < 0)
+                       return;
+               next_pid = (int)val;
+
+               ret = pevent_get_field_val(NULL, event, "prev_pid", &rec, &val, 0);
+               if (ret < 0)
+                       return;
+               prev_pid = (int)val;
+
+               /* find new process pointer */
+               new_proc = find_create_process(next_comm, next_pid);
+
+               /* find the old process pointer */
+
+               while  (consumer_depth(cpu) > 1) {
+                       pop_consumer(cpu);
+               }
+
+               if (consumer_depth(cpu) == 1)
+                       old_proc = (class process *)current_consumer(cpu);
+
+               if (old_proc && strcmp(old_proc->name(), "process"))
+                       old_proc = NULL;
+
+               /* retire the old process */
+
+               if (old_proc) {
+                       old_proc->deschedule_thread(time, prev_pid);
+                       old_proc->waker = NULL;
+               }
+
+               if (consumer_depth(cpu))
+                       pop_consumer(cpu);
+
+               push_consumer(cpu, new_proc);
+
+               /* start new process */
+               new_proc->schedule_thread(time, next_pid);
+
+               if (strncmp(next_comm,"migration/", 10) && strncmp(next_comm,"kworker/", 8) && strncmp(next_comm, "kondemand/",10)) {
+                       if (next_pid) {
+                               /* If someone woke us up.. blame him instead */
+                               if (new_proc->waker) {
+                                       change_blame(cpu, new_proc->waker, LEVEL_PROCESS);
+                               } else {
+                                       change_blame(cpu, new_proc, LEVEL_PROCESS);
+                               }
+                       }
+
+                       consume_blame(cpu);
+               }
+               new_proc->waker = NULL;
+       }
+       else if (strcmp(event->name, "sched_wakeup") == 0) {
+               class power_consumer *from = NULL;
+               class process *dest_proc = NULL;  
+               class process *from_proc = NULL; 
+               const char *comm;
+               int flags;
+               int pid;
+
+               ret = pevent_get_common_field_val(NULL, event, "common_flags", &rec, &val, 0);
+               if (ret < 0)
+                       return;
+               flags = (int)val;
+
+               if ( (flags & TRACE_FLAG_HARDIRQ) || (flags & TRACE_FLAG_SOFTIRQ)) {
+                       class timer *timer;
+                       timer = (class timer *) current_consumer(cpu);
+                       if (timer && strcmp(timer->name(), "timer")==0) {
+                               if (strcmp(timer->handler, "delayed_work_timer_fn") &&
+                                   strcmp(timer->handler, "hrtimer_wakeup") &&
+                                   strcmp(timer->handler, "it_real_fn"))
+                                       from = timer;
+                       }
+                       /* woken from interrupt */
+                       /* TODO: find the current irq handler and set "from" to that */
+               } else {
+                       from = current_consumer(cpu);
+               }
+
+
+               field = pevent_find_any_field(event, "comm");
+
+               if (!field || !(field->flags & FIELD_IS_STRING))
+                       return; 
+
+               comm = get_pevent_field_str(trace, event, field);
+
+               ret = pevent_get_field_val(NULL, event, "pid", &rec, &val, 0);
+               if (ret < 0)
+                       return;
+               pid = (int)val;
+
+               dest_proc = find_create_process(comm, pid);
+
+               if (from && strcmp(from->name(), "process")!=0){
+                       /* not a process doing the wakeup */
+                       from = NULL;
+                       from_proc = NULL;
+               } else {
+                       from_proc = (class process *) from;
+               }
+
+               if (from_proc && (dest_proc->running == 0) && (dest_proc->waker == NULL) && (pid != 0) && !dont_blame_me(from_proc->comm))
+                       dest_proc->waker = from;
+               if (from)
+                       dest_proc->last_waker = from;
+
+               /* Account processes that wake up X specially */
+               if (from && dest_proc && comm_is_xorg(dest_proc->comm))
+                       from->xwakes ++ ;
+
+       }
+       else if (strcmp(event->name, "irq_handler_entry") == 0) {
+               class interrupt *irq = NULL;
+               const char *handler;
+               int nr;
+
+               field = pevent_find_any_field(event, "name");
+               if (!field || !(field->flags & FIELD_IS_STRING))
+                       return; /* ?? */
+
+               handler = get_pevent_field_str(trace, event, field);
+
+               ret = pevent_get_field_val(NULL, event, "irq", &rec, &val, 0);
+               if (ret < 0)
+                       return;
+               nr = (int)val;
+
+               irq = find_create_interrupt(handler, nr, cpu);
+
+
+               push_consumer(cpu, irq);
+
+               irq->start_interrupt(time);
+
+               if (strstr(irq->handler, "timer") ==NULL)
+                       change_blame(cpu, irq, LEVEL_HARDIRQ);
+
+       }
+
+       else if (strcmp(event->name, "irq_handler_exit") == 0) {
+               class interrupt *irq = NULL;
+               uint64_t t;
+
+               /* find interrupt (top of stack) */
+               irq = (class interrupt *)current_consumer(cpu);
+               if (!irq || strcmp(irq->name(), "interrupt"))
+                       return;
+               pop_consumer(cpu);
+               /* retire interrupt */
+               t = irq->end_interrupt(time);
+               consumer_child_time(cpu, t);
+       }
+
+       else if (strcmp(event->name, "softirq_entry") == 0) {
+               class interrupt *irq = NULL;
+               const char *handler = NULL;
+               int vec;
+
+               ret = pevent_get_field_val(NULL, event, "vec", &rec, &val, 0);
+                if (ret < 0) {
+                        fprintf(stderr, "softirq_entry event returned no vector number?\n");
+                        return;
+                }
+               vec = (int)val;
+
+               if (vec <= 9)
+                       handler = softirqs[vec];
+
+               if (!handler)
+                       return;
+
+               irq = find_create_interrupt(handler, vec, cpu);
+
+               push_consumer(cpu, irq);
+
+               irq->start_interrupt(time);
+               change_blame(cpu, irq, LEVEL_SOFTIRQ);
+       }
+       else if (strcmp(event->name, "softirq_exit") == 0) {
+               class interrupt *irq = NULL;
+               uint64_t t;
+
+               irq = (class interrupt *) current_consumer(cpu);
+               if (!irq  || strcmp(irq->name(), "interrupt"))
+                       return;
+               pop_consumer(cpu);
+               /* pop irq */
+               t = irq->end_interrupt(time);
+               consumer_child_time(cpu, t);
+       }
+       else if (strcmp(event->name, "timer_expire_entry") == 0) {
+               class timer *timer = NULL;
+               uint64_t function;
+               uint64_t tmr;
+
+               ret = pevent_get_field_val(NULL, event, "function", &rec, &val, 0);
+               if (ret < 0) {
+                       fprintf(stderr, "timer_expire_entry event returned no function value?\n");
+                       return;
+               }
+               function = (uint64_t)val;
+
+               timer = find_create_timer(function);
+
+               if (timer->is_deferred())
+                       return;
+
+               ret = pevent_get_field_val(NULL, event, "timer", &rec, &val, 0);
+               if (ret < 0) {
+                       fprintf(stderr, "softirq_entry event returned no timer ?\n");
+                       return;
+               }
+               tmr = (uint64_t)val;
+
+               push_consumer(cpu, timer);
+               timer->fire(time, tmr);
+
+               if (strcmp(timer->handler, "delayed_work_timer_fn"))
+                       change_blame(cpu, timer, LEVEL_TIMER);
+       }
+       else if (strcmp(event->name, "timer_expire_exit") == 0) {
+               class timer *timer = NULL;
+               uint64_t tmr;
+               uint64_t t;
+
+               ret = pevent_get_field_val(NULL, event, "timer", &rec, &val, 0);
+               if (ret < 0)
+                       return;
+               tmr = (uint64_t)val;
+
+               timer = (class timer *) current_consumer(cpu);
+               if (!timer || strcmp(timer->name(), "timer")) {
+                       return;
+               }
+               pop_consumer(cpu);
+               t = timer->done(time, tmr);
+               if (t == ~0ULL) {
+                       timer->fire(first_stamp, tmr);
+                       t = timer->done(time, tmr);
+               }
+               consumer_child_time(cpu, t);
+       }
+       else if (strcmp(event->name, "hrtimer_expire_entry") == 0) {
+               class timer *timer = NULL;
+               uint64_t function;
+               uint64_t tmr;
+
+               ret = pevent_get_field_val(NULL, event, "function", &rec, &val, 0);
+               if (ret < 0)
+                       return;
+               function = (uint64_t)val;
+
+               timer = find_create_timer(function);
+
+               ret = pevent_get_field_val(NULL, event, "hrtimer", &rec, &val, 0);
+               if (ret < 0)
+                       return;
+               tmr = (uint64_t)val;
+
+               push_consumer(cpu, timer);
+               timer->fire(time, tmr);
+
+               if (strcmp(timer->handler, "delayed_work_timer_fn"))
+                       change_blame(cpu, timer, LEVEL_TIMER);
+       }
+       else if (strcmp(event->name, "hrtimer_expire_exit") == 0) {
+               class timer *timer = NULL;
+               uint64_t tmr;
+               uint64_t t;
+
+               timer = (class timer *) current_consumer(cpu);
+               if (!timer || strcmp(timer->name(), "timer")) {
+                       return;
+               }
+
+               ret = pevent_get_field_val(NULL, event, "hrtimer", &rec, &val, 0);
+               if (ret < 0)
+                       return;
+               tmr = (uint64_t)val;
+
+               pop_consumer(cpu);
+               t = timer->done(time, tmr);
+               if (t == ~0ULL) {
+                       timer->fire(first_stamp, tmr);
+                       t = timer->done(time, tmr);
+               }
+               consumer_child_time(cpu, t);
+       }
+       else if (strcmp(event->name, "workqueue_execute_start") == 0) {
+               class work *work = NULL;
+               uint64_t function;
+               uint64_t wk;
+
+               ret = pevent_get_field_val(NULL, event, "function", &rec, &val, 0);
+               if (ret < 0)
+                       return;
+               function = (uint64_t)val;
+
+               ret = pevent_get_field_val(NULL, event, "work", &rec, &val, 0);
+               if (ret < 0)
+                       return;
+               wk = (uint64_t)val;
+
+               work = find_create_work(function);
+
+
+               push_consumer(cpu, work);
+               work->fire(time, wk);
+
+
+               if (strcmp(work->handler, "do_dbs_timer") != 0 && strcmp(work->handler, "vmstat_update") != 0)
+                       change_blame(cpu, work, LEVEL_WORK);
+       }
+       else if (strcmp(event->name, "workqueue_execute_end") == 0) {
+               class work *work = NULL;
+               uint64_t t;
+               uint64_t wk;
+
+               ret = pevent_get_field_val(NULL, event, "work", &rec, &val, 0);
+               if (ret < 0)
+                       return;
+               wk = (uint64_t)val;
+
+               work = (class work *) current_consumer(cpu);
+               if (!work || strcmp(work->name(), "work")) {
+                       return;
+               }
+               pop_consumer(cpu);
+               t = work->done(time, wk);
+               if (t == ~0ULL) {
+                       work->fire(first_stamp, wk);
+                       t = work->done(time, wk);
+               }
+               consumer_child_time(cpu, t);
+       }
+       else if (strcmp(event->name, "cpu_idle") == 0) {
+               ret = pevent_get_field_val(NULL, event, "state", &rec, &val, 0);
+               if (val == 4294967295)
+                       consume_blame(cpu);
+               else
+                       set_wakeup_pending(cpu);
+       }
+       else if (strcmp(event->name, "power_start") == 0) {
+               set_wakeup_pending(cpu);
+       }
+       else if (strcmp(event->name, "power_end") == 0) {
+               consume_blame(cpu);
+       }
+       else if (strcmp(event->name, "i915_gem_ring_dispatch") == 0
+        || strcmp(event->name, "i915_gem_request_submit") == 0) {
+               /* any kernel contains only one of the these tracepoints,
+                * the latter one got replaced by the former one */
+               class power_consumer *consumer = NULL;
+               int flags;
+
+               ret = pevent_get_common_field_val(NULL, event, "common_flags", &rec, &val, 0);
+               if (ret < 0)
+                       return;
+               flags = (int)val;
+
+               consumer = current_consumer(cpu);
+               /* currently we don't count graphic requests submitted from irq contect */
+               if ( (flags & TRACE_FLAG_HARDIRQ) || (flags & TRACE_FLAG_SOFTIRQ)) {
+                       consumer = NULL;
+               }
+
+
+               /* if we are X, and someone just woke us, account the GPU op to the guy waking us */
+               if (consumer && strcmp(consumer->name(), "process")==0) {
+                       class process *proc = NULL;
+                       proc = (class process *) consumer;
+                       if (comm_is_xorg(proc->comm) && proc->last_waker) {
+                               consumer = proc->last_waker;
+                       }
+               }
+
+
+
+               if (consumer) {
+                       consumer->gpu_ops++;
+               }
+       }
+       else if (strcmp(event->name, "writeback_inode_dirty") == 0) {
+               static uint64_t prev_time;
+               class power_consumer *consumer = NULL;
+               int dev;
+
+               consumer = current_consumer(cpu);
+
+               ret = pevent_get_field_val(NULL, event, "dev", &rec, &val, 0);
+               if (ret < 0)
+                       
+                       return;
+               dev = (int)val;
+
+               if (consumer && strcmp(consumer->name(),
+                       "process")==0 && dev > 0) {
+
+                       consumer->disk_hits++;
+
+                       /* if the previous inode dirty was > 1 second ago, it becomes a hard hit */
+                       if ((time - prev_time) > 1000000000)
+                               consumer->hard_disk_hits++;
+
+                       prev_time = time;
+               }
+       }
+}
+
+void start_process_measurement(void)
+{
+       if (!perf_events) {
+               perf_events = new perf_process_bundle();
+               perf_events->add_event("sched:sched_switch");
+               perf_events->add_event("sched:sched_wakeup");
+               perf_events->add_event("irq:irq_handler_entry");
+               perf_events->add_event("irq:irq_handler_exit");
+               perf_events->add_event("irq:softirq_entry");
+               perf_events->add_event("irq:softirq_exit");
+               perf_events->add_event("timer:timer_expire_entry");
+               perf_events->add_event("timer:timer_expire_exit");
+               perf_events->add_event("timer:hrtimer_expire_entry");
+               perf_events->add_event("timer:hrtimer_expire_exit");
+               if (!perf_events->add_event("power:cpu_idle")){
+                       perf_events->add_event("power:power_start");
+                       perf_events->add_event("power:power_end");
+               }
+               perf_events->add_event("workqueue:workqueue_execute_start");
+               perf_events->add_event("workqueue:workqueue_execute_end");
+               perf_events->add_event("i915:i915_gem_ring_dispatch");
+               perf_events->add_event("i915:i915_gem_request_submit");
+               perf_events->add_event("writeback:writeback_inode_dirty");
+       }
+
+       first_stamp = ~0ULL;
+       last_stamp = 0;
+       perf_events->start();
+}
+
+void end_process_measurement(void)
+{
+       if (!perf_events)
+               return;
+
+       perf_events->stop();
+}
+
+
+static bool power_cpu_sort(class power_consumer * i, class power_consumer * j)
+{
+       double iW, jW;
+
+       iW = i->Witts();
+       jW = j->Witts();
+
+       if (equals(iW, jW)) {
+               double iR, jR;
+
+               iR = i->accumulated_runtime - i->child_runtime;
+               jR = j->accumulated_runtime - j->child_runtime;
+
+               if (equals(iR, jR))
+                       return i->wake_ups > j->wake_ups;
+               return (iR > jR);
+       }
+
+        return (iW > jW);
+}
+
+double total_wakeups(void)
+{
+       double total = 0;
+       unsigned int i;
+       for (i = 0; i < all_power.size() ; i++)
+               total += all_power[i]->wake_ups;
+
+       total = total / measurement_time;
+
+
+       return total;
+}
+
+double total_gpu_ops(void)
+{
+       double total = 0;
+       unsigned int i;
+       for (i = 0; i < all_power.size() ; i++)
+               total += all_power[i]->gpu_ops;
+
+
+       total = total / measurement_time;
+
+
+       return total;
+}
+
+double total_disk_hits(void)
+{
+       double total = 0;
+       unsigned int i;
+       for (i = 0; i < all_power.size() ; i++)
+               total += all_power[i]->disk_hits;
+
+
+       total = total / measurement_time;
+
+
+       return total;
+}
+
+
+double total_hard_disk_hits(void)
+{
+       double total = 0;
+       unsigned int i;
+       for (i = 0; i < all_power.size() ; i++)
+               total += all_power[i]->hard_disk_hits;
+
+
+       total = total / measurement_time;
+
+
+       return total;
+}
+
+double total_xwakes(void)
+{
+       double total = 0;
+       unsigned int i;
+       for (i = 0; i < all_power.size() ; i++)
+               total += all_power[i]->xwakes;
+
+
+       total = total / measurement_time;
+
+
+       return total;
+}
+
+void process_update_display(void)
+{
+       unsigned int i;
+       WINDOW *win;
+       double pw;
+       int tl;
+       int tlt; 
+       int tlr;
+
+       int show_power;
+       int need_linebreak = 0;
+
+       sort(all_power.begin(), all_power.end(), power_cpu_sort);
+
+       show_power = global_power_valid();
+
+       win = get_ncurses_win("Overview");
+       if (!win)
+               return;
+
+       wclear(win);
+
+       wmove(win, 1,0);
+
+#if 0
+       double sum;
+       calculate_params();
+       sum = 0.0;
+       sum += get_parameter_value("base power");
+       for (i = 0; i < all_power.size(); i++) {
+               sum += all_power[i]->Witts();
+       }
+
+       wprintw(win, _("Estimated power: %5.1f    Measured power: %5.1f    Sum: %5.1f\n\n"),
+                               all_parameters.guessed_power, global_joules_consumed(), sum);
+#endif
+
+       pw = global_joules_consumed();
+       tl = global_time_left() / 60;
+       tlt = (tl /60);
+       tlr = tl % 60;
+
+       if (pw > 0.0001) {
+               char buf[32];
+               wprintw(win, _("The battery reports a discharge rate of %sW\n"),
+                               fmt_prefix(pw, buf));
+               need_linebreak = 1;
+       }
+       if (tl > 0 && pw > 0.0001) {
+               wprintw(win, _("The estimated remaining time is %i hours, %i minutes\n"), tlt, tlr);
+               need_linebreak = 1;
+       }
+
+       if (need_linebreak)
+               wprintw(win, "\n");
+
+
+       wprintw(win, "%s: %3.1f %s,  %3.1f %s, %3.1f %s %3.1f%% %s\n\n",_("Summary"), total_wakeups(), _("wakeups/second"), total_gpu_ops(), _("GPU ops/seconds"), total_disk_hits(), _("VFS ops/sec and"), total_cpu_time()*100, _("CPU use"));
+
+
+       if (show_power)
+               wprintw(win, "%s              %s       %s    %s       %s\n", _("Power est."), _("Usage"), _("Events/s"), _("Category"), _("Description"));
+       else
+               wprintw(win, "                %s       %s    %s       %s\n", _("Usage"), _("Events/s"), _("Category"), _("Description"));
+
+       for (i = 0; i < all_power.size(); i++) {
+               char power[16];
+               char name[20];
+               char usage[20];
+               char events[20];
+               char descr[128];
+               format_watts(all_power[i]->Witts(), power, 10);
+
+               if (!show_power)
+                       strcpy(power, "          ");
+               sprintf(name, "%s", all_power[i]->type());
+               while (mbstowcs(NULL,name,0) < 14) strcat(name, " ");
+
+
+               if (all_power[i]->events() == 0 && all_power[i]->usage() == 0 && all_power[i]->Witts() == 0)
+                       break;
+
+               usage[0] = 0;
+               if (all_power[i]->usage_units()) {
+                       if (all_power[i]->usage() < 1000)
+                               sprintf(usage, "%5.1f%s", all_power[i]->usage(), all_power[i]->usage_units());
+                       else
+                               sprintf(usage, "%5i%s", (int)all_power[i]->usage(), all_power[i]->usage_units());
+               }
+               while (mbstowcs(NULL,usage,0) < 14) strcat(usage, " ");
+               sprintf(events, "%5.1f", all_power[i]->events());
+               if (!all_power[i]->show_events())
+                       events[0] = 0;
+               else if (all_power[i]->events() <= 0.3)
+                       sprintf(events, "%5.2f", all_power[i]->events());
+
+               while (strlen(events) < 12) strcat(events, " ");
+               wprintw(win, "%s  %s %s %s %s\n", power, usage, events, name, pretty_print(all_power[i]->description(), descr, 128));
+       }
+}
+
+void report_process_update_display(void)
+{
+       unsigned int i;
+       unsigned int total;
+
+       int show_power;
+
+       sort(all_power.begin(), all_power.end(), power_cpu_sort);
+
+       show_power = global_power_valid();
+
+       report.begin_section(SECTION_SOFTWARE);
+       report.add_header(__("Overview of Software Power Consumers"));
+       report.begin_table(TABLE_WIDE);
+       report.begin_row();
+       if (show_power) {
+               report.begin_cell(CELL_SOFTWARE_HEADER);
+               report.add(__("Power est."));
+       }
+
+       report.begin_cell(CELL_SOFTWARE_HEADER);
+       report.add(__("Usage"));
+       report.begin_cell(CELL_SOFTWARE_HEADER);
+       report.add(__("Wakeups/s"));
+       report.begin_cell(CELL_SOFTWARE_HEADER);
+       report.add(__("GPU ops/s"));
+       report.begin_cell(CELL_SOFTWARE_HEADER);
+       report.add(__("Disk IO/s"));
+       report.begin_cell(CELL_SOFTWARE_HEADER);
+       report.add(__("GFX Wakeups/s"));
+       report.begin_cell(CELL_SOFTWARE_PROCESS);
+       report.add(__("Category"));
+       report.begin_cell(CELL_SOFTWARE_DESCRIPTION);
+       report.add(__("Description"));
+
+       total = all_power.size();
+
+       if (total > 100)
+               total = 100;
+
+       for (i = 0; i < total; i++) {
+               char power[16];
+               char name[20];
+               char usage[20];
+               char wakes[20];
+               char gpus[20];
+               char disks[20];
+               char xwakes[20];
+               char descr[128];
+               format_watts(all_power[i]->Witts(), power, 10);
+
+               if (!show_power)
+                       strcpy(power, "          ");
+               sprintf(name, "%s", all_power[i]->type());
+
+               if (strcmp(name, "Device") == 0)
+                       continue;
+
+               if (all_power[i]->events() == 0 && all_power[i]->usage() == 0 && all_power[i]->Witts() == 0)
+                       break;
+
+               usage[0] = 0;
+               if (all_power[i]->usage_units()) {
+                       if (all_power[i]->usage() < 1000)
+                               sprintf(usage, "%5.1f%s", all_power[i]->usage(), all_power[i]->usage_units());
+                       else
+                               sprintf(usage, "%5i%s", (int)all_power[i]->usage(), all_power[i]->usage_units());
+               }
+               sprintf(wakes, "%5.1f", all_power[i]->wake_ups / measurement_time);
+               if (all_power[i]->wake_ups / measurement_time <= 0.3)
+                       sprintf(wakes, "%5.2f", all_power[i]->wake_ups / measurement_time);
+               sprintf(gpus, "%5.1f", all_power[i]->gpu_ops / measurement_time);
+               sprintf(disks, "%5.1f (%5.1f)", all_power[i]->hard_disk_hits / measurement_time,
+                       all_power[i]->disk_hits / measurement_time);
+               sprintf(xwakes, "%5.1f", all_power[i]->xwakes / measurement_time);
+               if (!all_power[i]->show_events()) {
+                       wakes[0] = 0;
+                       gpus[0] = 0;
+                       disks[0] = 0;
+               }
+
+               if (all_power[i]->gpu_ops == 0)
+                       gpus[0] = 0;
+               if (all_power[i]->wake_ups == 0)
+                       wakes[0] = 0;
+               if (all_power[i]->disk_hits == 0)
+                       disks[0] = 0;
+               if (all_power[i]->xwakes == 0)
+                       xwakes[0] = 0;
+
+               report.begin_row(ROW_SOFTWARE);
+               if (show_power) {
+                       report.begin_cell(CELL_SOFTWARE_POWER);
+                       report.add(power);
+               }
+               
+               report.begin_cell(CELL_SOFTWARE_POWER);
+               report.add(usage);
+               report.begin_cell(CELL_SOFTWARE_POWER);
+               report.add(wakes);
+               report.begin_cell(CELL_SOFTWARE_POWER);
+               report.add(gpus);
+               report.begin_cell(CELL_SOFTWARE_POWER);
+               report.add(disks);
+               report.begin_cell(CELL_SOFTWARE_POWER);
+               report.add(xwakes);
+               report.begin_cell();
+               report.add(name);
+               report.begin_cell();
+               report.add(pretty_print(all_power[i]->description(), descr, 128));
+       }
+}
+
+void report_summary(void)
+{
+       unsigned int i;
+       unsigned int total;
+       int show_power;
+
+       sort(all_power.begin(), all_power.end(), power_cpu_sort);
+       show_power = global_power_valid();
+
+       report.begin_section(SECTION_SUMMARY);
+       report.add_header(__("Power Consumption Summary"));
+       report.begin_paragraph();
+       report.addf("%.1f %s, %.1f %s, %.1f %s, %.1f %s %.1f%% %s",
+                   total_wakeups(),     __("wakeups/second"),
+                   total_gpu_ops(),     __("GPU ops/second"),
+                   total_disk_hits(),   __("VFS ops/sec"),
+                   total_xwakes(),      __("GFX wakes/sec and"),
+                   total_cpu_time() * 100, __("CPU use"));
+
+       report.begin_table(TABLE_WIDE);
+       report.begin_row();
+       if (show_power) {
+               report.begin_cell(CELL_SUMMARY_HEADER);
+               report.add(__("Power est."));
+       }
+
+       report.begin_cell(CELL_SUMMARY_HEADER);
+       report.add(__("Usage"));
+       report.begin_cell(CELL_SUMMARY_HEADER);
+       report.add(__("Events/s"));
+       report.begin_cell(CELL_SUMMARY_CATEGORY);
+       report.add(__("Category"));
+       report.begin_cell(CELL_SUMMARY_DESCRIPTION);
+       report.add(__("Description"));
+
+       total = all_power.size();
+       if (total > 10)
+               total = 10;
+
+       for (i = 0; i < all_power.size(); i++) {
+               char power[16];
+               char name[20];
+               char usage[20];
+               char events[20];
+               char descr[128];
+               format_watts(all_power[i]->Witts(), power, 10);
+
+               if (!show_power)
+                       strcpy(power, "          ");
+               sprintf(name, "%s", all_power[i]->type());
+
+               if (i > total)
+                       break;
+
+               if (all_power[i]->events() == 0 && all_power[i]->usage() == 0 &&
+                   all_power[i]->Witts() == 0)
+                       break;
+
+               usage[0] = 0;
+               if (all_power[i]->usage_units()) {
+                       if (all_power[i]->usage() < 1000)
+                               sprintf(usage, "%5.1f%s", all_power[i]->usage_summary(),
+                                       all_power[i]->usage_units_summary());
+                       else
+                               sprintf(usage, "%5i%s", (int)all_power[i]->usage_summary(),
+                                       all_power[i]->usage_units_summary());
+               }
+               sprintf(events, "%5.1f", all_power[i]->events());
+               if (!all_power[i]->show_events())
+                       events[0] = 0;
+               else if (all_power[i]->events() <= 0.3)
+                       sprintf(events, "%5.2f", all_power[i]->events());
+
+               report.begin_row(ROW_SUMMARY);
+               if (show_power) {
+                       report.begin_cell(CELL_SUMMARY_ITEM);
+                       report.add(power);
+               }
+
+               report.begin_cell(CELL_SUMMARY_ITEM);
+               report.add(usage);
+               report.begin_cell(CELL_SUMMARY_ITEM);
+               report.add(events);
+               report.begin_cell();
+               report.add(name);
+               report.begin_cell();
+               report.add(pretty_print(all_power[i]->description(), descr, 128));
+       }
+}
+
+
+void process_process_data(void)
+{
+       if (!perf_events)
+               return;
+
+       clear_processes();
+       clear_interrupts();
+
+       all_power.erase(all_power.begin(), all_power.end());
+       clear_consumers();
+
+
+       cpu_credit.resize(0, 0);
+       cpu_credit.resize(get_max_cpu()+1, 0);
+       cpu_level.resize(0, 0);
+       cpu_level.resize(get_max_cpu()+1, 0);
+       cpu_blame.resize(0, NULL);
+       cpu_blame.resize(get_max_cpu()+1, NULL);
+
+
+
+       /* process data */
+       perf_events->process();
+       perf_events->clear();
+
+       run_devpower_list();
+
+       merge_processes();
+
+       all_processes_to_all_power();
+       all_interrupts_to_all_power();
+       all_timers_to_all_power();
+       all_work_to_all_power();
+       all_devices_to_all_power();
+
+       sort(all_power.begin(), all_power.end(), power_cpu_sort);
+}
+
+
+double total_cpu_time(void)
+{
+       unsigned int i;
+       double total = 0.0;
+       for (i = 0; i < all_power.size() ; i++) {
+               if (all_power[i]->child_runtime > all_power[i]->accumulated_runtime)
+                       all_power[i]->child_runtime = 0;
+               total += all_power[i]->accumulated_runtime - all_power[i]->child_runtime;
+       }
+
+       total =  (total / (0.0001 + last_stamp - first_stamp));
+
+       return total;
+}
+
+
+
+void end_process_data(void)
+{
+       report_utilization("cpu-consumption", total_cpu_time());
+       report_utilization("cpu-wakeups", total_wakeups());
+       report_utilization("gpu-operations", total_gpu_ops());
+       report_utilization("disk-operations", total_disk_hits());
+       report_utilization("disk-operations-hard", total_hard_disk_hits());
+       report_utilization("xwakes", total_xwakes());
+
+       all_power.erase(all_power.begin(), all_power.end());
+       clear_processes();
+       clear_proc_devices();
+       clear_interrupts();
+       clear_timers();
+       clear_work();
+       clear_consumers();
+
+       perf_events->clear();
+
+}
+
+void clear_process_data(void)
+{
+       if (perf_events)
+               perf_events->release();
+       delete perf_events;
+}
+
diff --git a/src/process/interrupt.cpp b/src/process/interrupt.cpp
new file mode 100644 (file)
index 0000000..8ca756f
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ *     Arjan van de Ven <arjan@linux.intel.com>
+ */
+#include <stdint.h>
+#include <string.h>
+#include <stdio.h>
+#include "process.h"
+#include "interrupt.h"
+#include "../lib.h"
+
+const char* softirqs[] = {
+       "HI_SOFTIRQ",
+       "timer(softirq)",
+       "net tx(softirq)",
+       "net_rx(softirq)",
+       "block(softirq)",
+       "block_iopoll(softirq)",
+       "tasklet(softirq)",
+       "sched(softirq)",
+       "hrtimer(softirq)",
+       "RCU(softirq)",
+       NULL
+};
+
+
+interrupt::interrupt(const char *_handler, int _number) : power_consumer()
+{
+       char buf[128];
+       running_since = 0;
+       number = _number;
+       strncpy(handler, _handler, 31);
+       raw_count = 0;
+       sprintf(desc, "[%i] %s", number, pretty_print(handler, buf, 128));
+}
+
+
+vector <class interrupt *> all_interrupts;
+
+void interrupt::start_interrupt(uint64_t time)
+{
+       running_since = time;
+       raw_count ++;
+}
+
+uint64_t interrupt::end_interrupt(uint64_t time)
+{
+       uint64_t delta;
+
+       delta = time - running_since;
+       accumulated_runtime += delta;
+       return delta;
+}
+
+const char * interrupt::description(void)
+{
+       if (child_runtime > accumulated_runtime)
+               child_runtime = 0;
+       return desc;
+}
+
+double interrupt::usage_summary(void)
+{
+       double t;
+       t = (accumulated_runtime - child_runtime) / 1000000.0 / measurement_time / 10;
+       return t;
+}
+
+const char * interrupt::usage_units_summary(void)
+{
+       return "%";
+}
+
+
+class interrupt * find_create_interrupt(const char *_handler, int nr, int cpu)
+{
+       char handler[64];
+       unsigned int i;
+       class interrupt *new_irq;
+
+       strcpy(handler, _handler);
+       if (strcmp(handler, "timer")==0)
+               sprintf(handler, "timer/%i", cpu);
+
+
+       for (i = 0; i < all_interrupts.size(); i++) {
+               if (all_interrupts[i] && all_interrupts[i]->number == nr && strcmp(handler, all_interrupts[i]->handler) == 0)
+                       return all_interrupts[i];
+       }
+
+       new_irq = new class interrupt(handler, nr);
+       all_interrupts.push_back(new_irq);
+       return new_irq;
+}
+
+void all_interrupts_to_all_power(void)
+{
+       unsigned int i;
+       for (i = 0; i < all_interrupts.size() ; i++)
+               if (all_interrupts[i]->accumulated_runtime)
+                       all_power.push_back(all_interrupts[i]);
+}
+
+void clear_interrupts(void)
+{
+       std::vector<class interrupt *>::iterator it = all_interrupts.begin();
+       while (it != all_interrupts.end()) {
+               delete *it;
+               it = all_interrupts.erase(it);
+       }
+}
diff --git a/src/process/interrupt.h b/src/process/interrupt.h
new file mode 100644 (file)
index 0000000..8d3a4d7
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ *     Arjan van de Ven <arjan@linux.intel.com>
+ */
+#ifndef _INCLUDE_GUARD_INTERRUPT_H
+#define _INCLUDE_GUARD_INTERRUPT_H
+
+#include <stdint.h>
+
+#include "powerconsumer.h"
+
+class interrupt : public power_consumer {
+       uint64_t        running_since;
+       char            desc[256];
+public:
+       char            handler[32];
+       int             number;
+
+       int             raw_count;
+
+       interrupt(const char *_handler, int _number);
+
+       virtual void start_interrupt(uint64_t time);
+       virtual uint64_t end_interrupt(uint64_t time);
+
+       virtual const char * description(void);
+
+       virtual const char * name(void) { return "interrupt"; };
+       virtual const char * type(void) { return "Interrupt"; };
+       virtual double usage_summary(void);
+       virtual const char * usage_units_summary(void);
+};
+
+extern vector <class interrupt *> all_interrupts;
+extern const char* softirqs[];
+
+
+extern class interrupt * find_create_interrupt(const char *_handler, int nr, int cpu);
+extern void all_interrupts_to_all_power(void);
+extern void clear_interrupts(void);
+
+#endif
diff --git a/src/process/powerconsumer.cpp b/src/process/powerconsumer.cpp
new file mode 100644 (file)
index 0000000..2ff2132
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ *     Arjan van de Ven <arjan@linux.intel.com>
+ */
+
+#include "powerconsumer.h"
+#include "process.h"
+#include "../parameters/parameters.h"
+
+double power_consumer::Witts(void)
+{
+       double cost;
+       double timecost;
+       double wakeupcost;
+       double gpucost;
+       double disk_cost;
+       double hard_disk_cost;
+       double xwake_cost;
+
+       if (child_runtime > accumulated_runtime)
+               child_runtime = 0;
+
+       timecost = get_parameter_value("cpu-consumption");
+       wakeupcost = get_parameter_value("cpu-wakeups");
+       gpucost = get_parameter_value("gpu-operations");
+       disk_cost = get_parameter_value("disk-operations");
+       hard_disk_cost = get_parameter_value("disk-operations-hard");
+       xwake_cost = get_parameter_value("xwakes");
+
+       cost = 0;
+
+       cost += wakeupcost * wake_ups / 10000.0;
+       cost += ( (accumulated_runtime - child_runtime) / 1000000000.0) * timecost;
+       cost += gpucost * gpu_ops / 100.0;
+       cost += hard_disk_cost * hard_disk_hits / 100.0;
+       cost += disk_cost * disk_hits / 100.0;
+       cost += xwake_cost * xwakes / 100.0;
+
+       cost = cost / measurement_time;
+
+       cost += power_charge;
+
+       return cost;
+}
+
+power_consumer::power_consumer(void)
+{
+       accumulated_runtime = 0;
+       child_runtime = 0;
+       disk_hits = 0;
+       wake_ups = 0;
+       gpu_ops = 0;
+       hard_disk_hits = 0;
+       xwakes = 0;
+       waker = NULL;
+       last_waker = NULL;
+       power_charge = 0.0;
+}
+
+double power_consumer::usage(void)
+{
+       double t;
+       t = (accumulated_runtime - child_runtime) / 1000000.0 / measurement_time;
+       if (t < 0.7)
+               t = t * 1000;
+       return t;
+}
+
+const char * power_consumer::usage_units(void)
+{
+       double t;
+       t = (accumulated_runtime - child_runtime) / 1000000.0 / measurement_time;
+       if (t < 0.7) {
+               if (utf_ok)
+                       return " µs/s";
+               else
+                       return " us/s";
+       }
+       return " ms/s";
+}
diff --git a/src/process/powerconsumer.h b/src/process/powerconsumer.h
new file mode 100644 (file)
index 0000000..0ae384a
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ *     Arjan van de Ven <arjan@linux.intel.com>
+ */
+#ifndef __INCLUDE_GUARD_POWER_CONSUMER_
+#define __INCLUDE_GUARD_POWER_CONSUMER_
+
+#include <stdint.h>
+#include <vector>
+#include <algorithm>
+
+using namespace std;
+
+extern double measurement_time;
+
+class power_consumer;
+
+class power_consumer {
+
+public:
+       uint64_t        accumulated_runtime;
+       uint64_t        child_runtime;
+       int             disk_hits;
+       int             wake_ups;
+       int             gpu_ops;
+       int             hard_disk_hits;  /* those which are likely a wakeup of the disk */
+       int             xwakes;
+
+       double          power_charge;    /* power consumed by devices opened by this process */
+       class power_consumer *waker;
+       class power_consumer *last_waker;
+
+       power_consumer(void);
+       virtual ~power_consumer() {};
+
+       virtual double Witts(void);
+       virtual const char * description(void) { return ""; };
+
+       virtual const char * name(void) { return "abstract"; };
+       virtual const char * type(void) { return "abstract"; };
+
+       virtual double usage(void);
+       virtual const char * usage_units(void);
+
+       virtual double usage_summary(void) { return usage();};
+       virtual const char * usage_units_summary(void) { return usage_units(); };
+       virtual double events(void) { return  (wake_ups + gpu_ops + hard_disk_hits) / measurement_time;};
+       virtual int show_events(void) { return 1; };
+};
+
+extern vector <class power_consumer *> all_power;
+
+extern double total_wakeups(void);
+extern double total_cpu_time(void);
+extern double total_gpu_ops(void);
+
+
+
+#endif
\ No newline at end of file
diff --git a/src/process/process.cpp b/src/process/process.cpp
new file mode 100644 (file)
index 0000000..34dc68d
--- /dev/null
@@ -0,0 +1,243 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ *     Arjan van de Ven <arjan@linux.intel.com>
+ */
+
+
+
+#include "process.h"
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <iostream>
+#include <fstream>
+
+
+vector <class process *> all_processes;
+
+void process::account_disk_dirty(void)
+{
+       disk_hits++;
+}
+
+void process::schedule_thread(uint64_t time, int thread_id)
+{
+       running_since = time;
+       running = 1;
+}
+
+
+uint64_t process::deschedule_thread(uint64_t time, int thread_id)
+{
+       uint64_t delta;
+
+       if (!running_since)
+               return 0;
+
+       delta = time - running_since;
+
+       if (time < running_since)
+               printf("%llu time    %llu since \n", (unsigned long long)time,
+                                                    (unsigned long long)running_since);
+
+       if (thread_id == 0) /* idle thread */
+               delta = 0;
+       accumulated_runtime += delta;
+       running = 0;
+
+       return delta;
+}
+
+static void cmdline_to_string(char *str)
+{
+       char *c = str;
+       char prev = 0;
+
+       while (prev != 0 || *c  != 0) {
+               prev = *c;
+               if (*c == 0)
+                       *c = ' ';
+               c++;
+       }
+}
+
+
+process::process(const char *_comm, int _pid, int _tid) : power_consumer()
+{
+       char line[4097];
+       ifstream file;
+
+       strcpy(comm, _comm);
+       pid = _pid;
+       is_idle = 0;
+       running = 0;
+       last_waker = NULL;
+       waker = NULL;
+       is_kernel = 0;
+       tgid = _tid;
+
+       if (_tid == 0) {
+               sprintf(line, "/proc/%i/status", _pid);
+               file.open(line);
+               while (file) {
+                       file.getline(line, 4096);
+                       line[4096] = '\0';
+                       if (strstr(line, "Tgid")) {
+                               char *c;
+                               c = strchr(line, ':');
+                               if (!c)
+                                       continue;
+                               c++;
+                               tgid = strtoull(c, NULL, 10);
+                               break;
+                       }
+               }
+               file.close();
+       }
+
+       if (strncmp(_comm, "kondemand/", 10) == 0)
+               is_idle = 1;
+
+       strcpy(desc, comm);
+
+       sprintf(line, "/proc/%i/cmdline", _pid);
+       file.open(line, ios::binary);
+       if (file) {
+               memset(line, 0, sizeof(line));
+               file.read(line, 4096);
+               file.close();
+               if (strlen(line) < 1) {
+                       is_kernel = 1;
+                       sprintf(desc, "[%s]", comm);
+               } else {
+                       int sz = sizeof(desc) - 1;
+                       cmdline_to_string(line);
+                       strncpy(desc, line, sz);
+                       desc[sz] = 0x00;
+               }
+       }
+}
+
+const char * process::description(void)
+{
+
+       if (child_runtime > accumulated_runtime)
+               child_runtime = 0;
+
+       return desc;
+}
+
+double process::usage_summary(void)
+{
+       double t;
+       t = (accumulated_runtime - child_runtime) / 1000000.0 / measurement_time / 10;
+       return t;
+}
+
+const char * process::usage_units_summary(void)
+{
+       return "%";
+}
+
+class process * find_create_process(const char *comm, int pid)
+{
+       unsigned int i;
+       class process *new_proc;
+
+       for (i = 0; i < all_processes.size(); i++) {
+               if (all_processes[i]->pid == pid && strcmp(comm, all_processes[i]->comm) == 0)
+                       return all_processes[i];
+       }
+
+       new_proc = new class process(comm, pid);
+       all_processes.push_back(new_proc);
+       return new_proc;
+}
+
+class process * find_create_process(char *comm, int pid)
+{
+       return find_create_process((const char*)comm, pid);
+}
+
+static void merge_process(class process *one, class process *two)
+{
+       one->accumulated_runtime += two->accumulated_runtime;
+       one->child_runtime += two->child_runtime;
+       one->wake_ups += two->wake_ups;
+       one->disk_hits += two->disk_hits;
+       one->hard_disk_hits += two->hard_disk_hits;
+       one->xwakes += two->xwakes;
+       one->gpu_ops += two->gpu_ops;
+       one->power_charge += two->power_charge;
+}
+
+
+void merge_processes(void)
+{
+       std::vector<class process*>::iterator it1, it2;
+       class process *one, *two;
+
+       it1 = all_processes.begin();
+       while (it1 != all_processes.end()) {
+               it2 = it1 + 1;
+               one = *it1;
+               while (it2 != all_processes.end()) {
+                       two = *it2;
+                       /* fold threads */
+                       if (one->pid == two->tgid && two->tgid != 0) {
+                               merge_process(one, two);
+                               delete *it2;
+                               it2 = all_processes.erase(it2);
+                               continue;
+                       }
+                       /* find dupes and add up */
+                       if (!strcmp(one->desc, two->desc)) {
+                               merge_process(one, two);
+                               delete *it2;
+                               it2 = all_processes.erase(it2);
+                               continue;
+                       }
+                       ++it2;
+               }
+               ++it1;
+       }
+}
+
+void all_processes_to_all_power(void)
+{
+       unsigned int i;
+       for (i = 0; i < all_processes.size() ; i++)
+               if (all_processes[i]->accumulated_runtime)
+                       all_power.push_back(all_processes[i]);
+}
+
+void clear_processes(void)
+{
+       std::vector <class process *>::iterator it = all_processes.begin();
+       while (it != all_processes.end()) {
+               delete *it;
+               it = all_processes.erase(it);
+       }
+}
diff --git a/src/process/process.h b/src/process/process.h
new file mode 100644 (file)
index 0000000..66293f7
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ *     Arjan van de Ven <arjan@linux.intel.com>
+ */
+#ifndef _INCLUDE_GUARD_PROCESS_H
+#define _INCLUDE_GUARD_PROCESS_H
+
+#include <stdint.h>
+
+#include "powerconsumer.h"
+
+#ifdef __x86_64__
+#define BIT64 1
+#endif
+
+/*
+Need to collect
+ * CPU time consumed by each application
+ * Number of wakeups out of idle -- received and wakeups sent
+ * Number of disk dirties (inode for now)
+ */
+class process : public power_consumer {
+       uint64_t        running_since;
+public:
+       char            desc[256];
+       int             tgid;
+       char            comm[16];
+       int             pid;
+
+
+       int             is_idle;   /* count this as if the cpu was idle */
+       int             running;
+       int             is_kernel; /* kernel thread */
+
+       process(const char *_comm, int _pid, int _tid = 0);
+
+       virtual void schedule_thread(uint64_t time, int thread_id);
+       virtual uint64_t deschedule_thread(uint64_t time, int thread_id = 0);
+
+       virtual void account_disk_dirty(void);
+
+       virtual const char * description(void);
+       virtual const char * name(void) { return "process"; };
+       virtual const char * type(void) { return "Process"; };
+
+       virtual double usage_summary(void);
+       virtual const char * usage_units_summary(void);
+
+};
+
+extern vector <class process *> all_processes;
+
+extern double measurement_time;
+
+
+extern void start_process_measurement(void);
+extern void end_process_measurement(void);
+extern void process_process_data(void);
+extern void end_process_data(void);
+extern void clear_process_data(void);
+extern void merge_processes(void);
+
+extern class process * find_create_process(const char *comm, int pid);
+extern class process * find_create_process(char *comm, int pid);
+extern void all_processes_to_all_power(void);
+
+extern void clear_processes(void);
+extern void process_update_display(void);
+extern void report_process_update_display(void);
+extern void report_summary(void);
+
+
+
+extern void clear_timers(void);
+
+#endif
diff --git a/src/process/processdevice.cpp b/src/process/processdevice.cpp
new file mode 100644 (file)
index 0000000..5bb269e
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ *     Arjan van de Ven <arjan@linux.intel.com>
+ */
+#include "processdevice.h"
+#include "../parameters/parameters.h"
+#include <stdio.h>
+
+vector<class device_consumer *> all_proc_devices;
+
+
+device_consumer::device_consumer(class device *dev) : power_consumer()
+{
+       device = dev;
+       power = device->power_usage(&all_results, &all_parameters);
+       prio = dev->grouping_prio();
+}
+
+
+const char * device_consumer::description(void)
+{
+       sprintf(str, "%s", device->human_name());
+       return str;
+}
+
+double device_consumer::Witts(void)
+{
+       return power;
+}
+
+static void add_device(class device *device)
+{
+       class device_consumer *dev;
+       unsigned int i;
+
+       /* first check if we want to be shown at all */
+
+       if (device->show_in_list() == 0)
+               return;
+
+       /* then check if a device with the same underlying object is already registered */
+       for (i = 0; i < all_proc_devices.size(); i++) {
+               class device_consumer *cdev;
+               cdev = all_proc_devices[i];
+               if (device->real_path[0] != 0 && strcmp(cdev->device->real_path, device->real_path) == 0) {
+                       /* we have a device with the same underlying object */
+
+                       /* aggregate the power */
+                       cdev->power += device->power_usage(&all_results, &all_parameters);
+
+                       if (cdev->prio < device->grouping_prio()) {
+                               cdev->device = device;
+                               cdev->prio = device->grouping_prio();
+                       }
+
+                       return;
+               }
+       }
+
+       dev = new class device_consumer(device);
+       all_power.push_back(dev);
+       all_proc_devices.push_back(dev);
+}
+
+void all_devices_to_all_power(void)
+{
+       unsigned int i;
+       for (i = 0; i < all_devices.size(); i++)
+               add_device(all_devices[i]);
+}
+
+void clear_proc_devices(void)
+{
+       std::vector<class device_consumer *>::iterator it = all_proc_devices.begin();
+       while (it != all_proc_devices.end()) {
+               delete *it;
+               it = all_proc_devices.erase(it);
+       }
+}
diff --git a/src/process/processdevice.h b/src/process/processdevice.h
new file mode 100644 (file)
index 0000000..3392d3e
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ *     Arjan van de Ven <arjan@linux.intel.com>
+ */
+#ifndef _INCLUDE_GUARD_DEVICE2_H
+#define _INCLUDE_GUARD_DEVICE2_H
+
+#include <stdint.h>
+
+#include "powerconsumer.h"
+#include "../devices/device.h"
+
+class device_consumer : public power_consumer {
+       char str[4096];
+public:
+       int prio;
+       double power;
+       class device *device;
+       device_consumer(class device *dev);
+
+       virtual const char * description(void);
+       virtual const char * name(void) { return "device"; };
+       virtual const char * type(void) { return "Device"; };
+       virtual double Witts(void);
+       virtual double usage(void) { return device->utilization();};
+       virtual const char * usage_units(void) {return device->util_units();};
+       virtual int show_events(void) { return 0; };
+};
+
+extern void all_devices_to_all_power(void);
+extern vector<class device_consumer *> all_proc_devices;
+
+extern void clear_proc_devices(void);
+
+#endif
diff --git a/src/process/timer.cpp b/src/process/timer.cpp
new file mode 100644 (file)
index 0000000..1ca8c25
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ *     Arjan van de Ven <arjan@linux.intel.com>
+ */
+#include <map>
+#include <utility>
+
+#include <stdint.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "timer.h"
+#include "../lib.h"
+#include "process.h"
+
+using namespace std;
+
+static bool timer_is_deferred(const char *handler)
+{
+       FILE    *file;
+       bool    ret = false;
+       char    line[4096];
+
+       file = fopen("/proc/timer_stats", "r"); 
+       if (!file) {
+               return ret;
+       }
+
+       while (!feof(file)) {
+               if (fgets(line, 4096, file) == NULL)
+                       break;
+               if (strstr(line, handler)) {
+                       ret = (strstr(line, "D,") != NULL);
+                       if (ret == true)
+                               break;
+               }
+       }
+       fclose(file);
+       return ret;
+}
+
+timer::timer(unsigned long address) : power_consumer()
+{
+       strncpy(handler, kernel_function(address), 31);
+       raw_count = 0;
+       deferred = timer_is_deferred(handler);
+}
+
+
+static map<unsigned long, class timer *> all_timers;
+static map<unsigned long, uint64_t> running_since;
+
+void timer::fire(uint64_t time, uint64_t timer_struct)
+{
+       running_since[timer_struct] = time;
+}
+
+uint64_t timer::done(uint64_t time, uint64_t timer_struct)
+{
+       int64_t delta;
+
+       if (running_since.find(timer_struct) == running_since.end())
+               return ~0ULL;
+
+       if (running_since[timer_struct] > time)
+               return 0;
+
+       delta = time - running_since[timer_struct];
+
+       accumulated_runtime += delta;
+
+       raw_count++;
+
+       return delta;
+}
+
+double timer::usage_summary(void)
+{
+       double t;
+       t = (accumulated_runtime - child_runtime) / 1000000.0 / measurement_time / 10;
+       return t;
+}
+
+const char * timer::usage_units_summary(void)
+{
+       return "%";
+}
+
+
+
+static void add_timer(const pair<unsigned long, class timer*>& elem)
+{
+       all_power.push_back(elem.second);
+}
+
+void all_timers_to_all_power(void)
+{
+       for_each(all_timers.begin(), all_timers.end(), add_timer);
+
+}
+
+
+const char * timer::description(void)
+{
+       if (child_runtime > accumulated_runtime)
+               child_runtime = 0;
+
+       sprintf(desc, "%s", handler);
+       return desc;
+}
+
+
+class timer * find_create_timer(uint64_t func)
+{
+       class timer * timer;
+       if (all_timers.find(func) != all_timers.end())
+               return all_timers[func];
+
+       timer = new class timer(func);
+       all_timers[func] = timer;
+       return timer;
+
+}
+
+void clear_timers(void)
+{
+       std::map<unsigned long, class timer *>::iterator it = all_timers.begin();
+       while (it != all_timers.end()) {
+               delete it->second;
+               all_timers.erase(it);
+               it = all_timers.begin();
+       }
+       running_since.clear();
+}
+
+bool timer::is_deferred(void)
+{
+       return deferred;
+}
diff --git a/src/process/timer.h b/src/process/timer.h
new file mode 100644 (file)
index 0000000..7718c3b
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ *     Arjan van de Ven <arjan@linux.intel.com>
+ */
+#ifndef _INCLUDE_GUARD_TIMER_H
+#define _INCLUDE_GUARD_TIMER_H
+
+#include <stdint.h>
+
+#include "powerconsumer.h"
+
+class timer : public power_consumer {
+       char desc[256];
+public:
+       char            handler[32];
+       int             raw_count;
+       bool            deferred;
+
+       timer(unsigned long timer_func);
+
+       void fire(uint64_t time, uint64_t timer_struct);
+       uint64_t done(uint64_t time, uint64_t timer_struct);
+       bool is_deferred(void);
+
+       virtual const char * description(void);
+       virtual const char * name(void) { return "timer"; };
+       virtual const char * type(void) { return "Timer"; };
+       virtual double usage_summary(void);
+       virtual const char * usage_units_summary(void);
+
+};
+
+class timer_list {
+public:
+       uint64_t        timer_address;
+       uint64_t        timer_func;
+};
+
+
+extern void all_timers_to_all_power(void);
+extern class timer * find_create_timer(uint64_t func);
+extern void clear_timers(void);
+
+#endif
diff --git a/src/process/work.cpp b/src/process/work.cpp
new file mode 100644 (file)
index 0000000..e62e5d3
--- /dev/null
@@ -0,0 +1,130 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ *     Arjan van de Ven <arjan@linux.intel.com>
+ */
+#include <map>
+#include <utility>
+
+#include <stdint.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "work.h"
+#include "../lib.h"
+#include "process.h"
+
+using namespace std;
+
+
+work::work(unsigned long address) : power_consumer()
+{
+       strncpy(handler, kernel_function(address), 31);
+       raw_count = 0;
+       sprintf(desc, "%s", handler);
+}
+
+
+static map<unsigned long, class work *> all_work;
+static map<unsigned long, uint64_t> running_since;
+
+void work::fire(uint64_t time, uint64_t work_struct)
+{
+       running_since[work_struct] = time;
+}
+
+uint64_t work::done(uint64_t time, uint64_t work_struct)
+{
+       int64_t delta;
+
+       if (running_since.find(work_struct) == running_since.end())
+               return ~0ULL;
+
+       if (running_since[work_struct] > time)
+               return 0;
+
+       delta = time - running_since[work_struct];
+
+       accumulated_runtime += delta;
+
+       raw_count++;
+
+       return delta;
+}
+
+double work::usage_summary(void)
+{
+       double t;
+       t = (accumulated_runtime - child_runtime) / 1000000.0 / measurement_time / 10;
+       return t;
+}
+
+const char * work::usage_units_summary(void)
+{
+       return "%";
+}
+
+
+
+
+static void add_work(const pair<unsigned long, class work*>& elem)
+{
+       all_power.push_back(elem.second);
+}
+
+void all_work_to_all_power(void)
+{
+       for_each(all_work.begin(), all_work.end(), add_work);
+
+}
+
+void clear_work(void)
+{
+       std::map<unsigned long, class work *>::iterator it = all_work.begin();
+       while (it != all_work.end()) {
+               delete it->second;
+               all_work.erase(it);
+               it = all_work.begin();
+       }
+       running_since.clear();
+}
+
+
+const char * work::description(void)
+{
+       if (child_runtime > accumulated_runtime)
+               child_runtime = 0;
+
+       return desc;
+}
+
+
+class work * find_create_work(uint64_t func)
+{
+       class work * work;
+       if (all_work.find(func) != all_work.end())
+               return all_work[func];
+
+       work = new class work(func);
+       all_work[func] = work;
+       return work;
+}
diff --git a/src/process/work.h b/src/process/work.h
new file mode 100644 (file)
index 0000000..ddd7c87
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ *     Arjan van de Ven <arjan@linux.intel.com>
+ */
+#ifndef _INCLUDE_GUARD_WORK_H
+#define _INCLUDE_GUARD_WORK_H
+
+#include <stdint.h>
+
+#include "powerconsumer.h"
+
+class work : public power_consumer {
+       char desc[256];
+public:
+       char            handler[32];
+       int             raw_count;
+
+       work(unsigned long work_func);
+
+       void fire(uint64_t time, uint64_t work_struct);
+       uint64_t done(uint64_t time, uint64_t work_struct);
+
+       virtual const char * description(void);
+       virtual const char * name(void) { return "work"; };
+       virtual const char * type(void) { return "kWork"; };
+       virtual double usage_summary(void);
+       virtual const char * usage_units_summary(void);
+
+};
+
+
+extern void all_work_to_all_power(void);
+extern class work * find_create_work(uint64_t func);
+
+extern void clear_work(void);
+
+#endif
diff --git a/src/report/report-formatter-base.cpp b/src/report/report-formatter-base.cpp
new file mode 100644 (file)
index 0000000..7c5159e
--- /dev/null
@@ -0,0 +1,116 @@
+/* Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ *     http://www.samsung.com/
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Common part of report_formatter_csv and report_formatter_html.
+ * Written by Igor Zhbanov <i.zhbanov@samsung.com>
+ * 2012.10 */
+
+#define _BSD_SOURCE
+
+/* Uncomment to disable asserts */
+/*#define NDEBUG*/
+
+#include <stdio.h>
+#include <assert.h>
+#include <stdarg.h>
+
+#include "report-formatter-base.h"
+
+/* ************************************************************************ */
+
+const char *
+report_formatter_string_base::get_result()
+{
+       return result.c_str();
+}
+
+/* ************************************************************************ */
+
+void
+report_formatter_string_base::clear_result()
+{
+       result.clear();
+}
+
+/* ************************************************************************ */
+
+void
+report_formatter_string_base::add(const char *str)
+{
+       assert(str);
+
+       result += escape_string(str);
+}
+
+/* ************************************************************************ */
+
+void
+report_formatter_string_base::add_exact(const char *str)
+{
+       assert(str);
+
+       result += std::string(str);
+}
+
+/* ************************************************************************ */
+
+#define LINE_SIZE 8192
+
+void
+report_formatter_string_base::addv(const char *fmt, va_list ap)
+{
+       char str[LINE_SIZE];
+
+       assert(fmt);
+
+       vsnprintf(str, sizeof(str), fmt, ap);
+       add(str);
+}
+
+/* ************************************************************************ */
+
+void
+report_formatter_string_base::addf(const char *fmt, ...)
+{
+       va_list ap;
+
+       assert(fmt);
+
+       va_start(ap, fmt);
+       addv(fmt, ap);
+       va_end(ap);
+}
+
+/* ************************************************************************ */
+
+void
+report_formatter_string_base::addf_exact(const char *fmt, ...)
+{
+       char str[LINE_SIZE];
+       va_list ap;
+
+       assert(fmt);
+
+       va_start(ap, fmt);
+       vsnprintf(str, sizeof(str), fmt, ap);
+       add_exact(str);
+       va_end(ap);
+}
diff --git a/src/report/report-formatter-base.h b/src/report/report-formatter-base.h
new file mode 100644 (file)
index 0000000..e35a2ff
--- /dev/null
@@ -0,0 +1,52 @@
+/* Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ *     http://www.samsung.com/
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Common part of report_formatter_csv and report_formatter_html.
+ * Written by Igor Zhbanov <i.zhbanov@samsung.com>
+ * 2012.10 */
+
+#ifndef _REPORT_FORMATTER_BASE_H_
+#define _REPORT_FORMATTER_BASE_H_
+
+#include "report-formatter.h"
+
+class report_formatter_string_base: public report_formatter
+{
+public:
+       virtual const char *get_result();
+       virtual void clear_result();
+
+       virtual void add(const char *str);
+       virtual void addv(const char *fmt, va_list ap);
+
+protected:
+       void add_exact(const char *str);
+       void addf(const char *fmt, ...)
+                               __attribute__ ((format (printf, 2, 3)));
+       void addf_exact(const char *fmt, ...)
+                               __attribute__ ((format (printf, 2, 3)));
+
+       virtual std::string escape_string(const char *str) = 0;
+
+       std::string result;
+};
+
+#endif /* _REPORT_FORMATTER_BASE_H_ */
diff --git a/src/report/report-formatter-csv.cpp b/src/report/report-formatter-csv.cpp
new file mode 100644 (file)
index 0000000..cd70d91
--- /dev/null
@@ -0,0 +1,224 @@
+/* Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ *     http://www.samsung.com/
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * CSV report generator.
+ * Written by Igor Zhbanov <i.zhbanov@samsung.com>
+ * 2012.10 */
+
+#define _BSD_SOURCE
+
+/* Uncomment to disable asserts */
+/*#define NDEBUG*/
+
+#include <stdio.h>
+#include <assert.h>
+#include <stdarg.h>
+
+#include "report-formatter-csv.h"
+
+static const char report_csv_header[] = "PowerTOP Report";
+
+/* ************************************************************************ */
+
+report_formatter_csv::report_formatter_csv()
+{
+       add_doc_header();
+}
+
+/* ************************************************************************ */
+
+void
+report_formatter_csv::finish_report()
+{
+       /* Do nothing special */
+}
+
+/* ************************************************************************ */
+
+void
+report_formatter_csv::add_doc_header()
+{
+       add_header(report_csv_header, 1);
+}
+
+/* ************************************************************************ */
+
+void
+report_formatter_csv::add_header(const char *header, int level)
+{
+       assert(header);
+
+       text_start = result.length();
+       csv_need_quotes = false;
+       addf("%.*s%s%.*s", 4 - level, "***", header, 4 - level, "***");
+       add_quotes();
+       add_exact("\n");
+}
+
+/* ************************************************************************ */
+
+void
+report_formatter_csv::begin_section(section_type stype)
+{
+       /* Do nothing special */
+}
+
+/* ************************************************************************ */
+
+void
+report_formatter_csv::end_section()
+{
+       /* Do nothing special */
+}
+
+/* ************************************************************************ */
+
+void
+report_formatter_csv::begin_table(table_type ttype)
+{
+       add_exact("\n");
+}
+
+/* ************************************************************************ */
+
+void
+report_formatter_csv::end_table()
+{
+       add_exact("\n");
+}
+
+/* ************************************************************************ */
+
+void
+report_formatter_csv::begin_row(row_type rtype)
+{
+       table_cell_number = 0;
+}
+
+/* ************************************************************************ */
+
+void
+report_formatter_csv::end_row()
+{
+       add_exact("\n");
+}
+
+/* ************************************************************************ */
+
+void
+report_formatter_csv::begin_cell(cell_type ctype)
+{
+       if (table_cell_number > 0) {
+               addf_exact("%c", REPORT_CSV_DELIMITER);
+#ifdef REPORT_CSV_ADD_SPACE
+               add_exact(" ");
+#endif /* !REPORT_CSV_ADD_SPACE */
+       }
+
+       text_start = result.length();
+       csv_need_quotes = false;
+}
+
+/* ************************************************************************ */
+
+void
+report_formatter_csv::add_quotes()
+{
+#ifdef REPORT_CSV_ESCAPE_EMPTY
+       if (csv_need_quotes || result.length() == text_start) {
+#else /* !REPORT_CSV_ESCAPE_EMPTY */
+       if (csv_need_quotes) {
+#endif /* !REPORT_CSV_ESCAPE_EMPTY */
+               result.insert(text_start, "\"");
+               add_exact("\"");
+       }
+}
+
+/* ************************************************************************ */
+
+void
+report_formatter_csv::end_cell()
+{
+       add_quotes();
+       table_cell_number++;
+}
+
+/* ************************************************************************ */
+
+void
+report_formatter_csv::add_empty_cell()
+{
+       /* Do nothing special */
+}
+
+/* ************************************************************************ */
+
+void
+report_formatter_csv::begin_paragraph()
+{
+       text_start = result.length();
+       csv_need_quotes = false;
+}
+
+/* ************************************************************************ */
+
+void
+report_formatter_csv::end_paragraph()
+{
+       add_quotes();
+       add_exact("\n");
+}
+
+/* ************************************************************************ */
+
+std::string
+report_formatter_csv::escape_string(const char *str)
+{
+       std::string res;
+
+       assert(str);
+
+       for (const char *i = str; *i; i++) {
+               switch (*i) {
+                       case '"':
+                               res += '"';
+#ifdef REPORT_CSV_SPACE_NEED_QUOTES
+                       case ' ':
+#endif /* REPORT_CSV_SPACE_NEED_QUOTES */
+                       case '\n':
+                       case REPORT_CSV_DELIMITER:
+                               csv_need_quotes = true;
+                               break;
+               }
+
+               res += *i;
+       }
+
+       return res;
+}
+
+/* ************************************************************************ */
+
+void
+report_formatter_csv::set_cpu_number(int nr UNUSED)
+{
+       /* Do nothing */
+}
diff --git a/src/report/report-formatter-csv.h b/src/report/report-formatter-csv.h
new file mode 100644 (file)
index 0000000..8dd2976
--- /dev/null
@@ -0,0 +1,85 @@
+/* Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ *     http://www.samsung.com/
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * CSV report generator.
+ * Written by Igor Zhbanov <i.zhbanov@samsung.com>
+ * 2012.10 */
+
+#ifndef _REPORT_FORMATTER_CSV_H_
+#define _REPORT_FORMATTER_CSV_H_
+
+#include <string>
+
+#include "report-formatter-base.h"
+
+/* Offices like semicolon separated values instead of comma */
+#define REPORT_CSV_DELIMITER ';'
+
+/* "a,b,c" vs "a, b, c" */
+/*#define REPORT_CSV_ADD_SPACE*/
+
+/* Whether to escape with quotes empty cell values */
+/*#define REPORT_CSV_ESCAPE_EMPTY*/
+
+/* Whether to escape with quotes empty cell values with spaces */
+/*#define REPORT_CSV_SPACE_NEED_QUOTES*/
+
+/* ************************************************************************ */
+
+class report_formatter_csv: public report_formatter_string_base
+{
+public:
+       report_formatter_csv();
+
+       void finish_report();
+
+       void add_header(const char *header, int level);
+
+       void begin_section(section_type stype);
+       void end_section();
+
+       void begin_table(table_type ttype);
+       void end_table();
+
+       void begin_row(row_type rtype);
+       void end_row();
+
+       void begin_cell(cell_type ctype);
+       void end_cell();
+       void add_empty_cell();
+
+       void begin_paragraph();
+       void end_paragraph();
+
+       void set_cpu_number(int nr);
+
+private:
+       void add_doc_header();
+
+       void add_quotes();
+
+       std::string escape_string(const char *str);
+
+       bool csv_need_quotes;
+       size_t table_cell_number, text_start;
+};
+
+#endif /* _REPORT_FORMATTER_CSV_H_ */
diff --git a/src/report/report-formatter-html.cpp b/src/report/report-formatter-html.cpp
new file mode 100644 (file)
index 0000000..5851575
--- /dev/null
@@ -0,0 +1,465 @@
+/* Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ *     http://www.samsung.com/
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * HTML report generator.
+ * Written by Igor Zhbanov <i.zhbanov@samsung.com>
+ * 2012.10 */
+
+#define _BSD_SOURCE
+
+/* Uncomment to disable asserts */
+/*#define NDEBUG*/
+
+#include <stdio.h>
+#include <assert.h>
+#include <stdarg.h>
+
+#include "report-formatter-html.h"
+#include "css.h" /* For HTML-report header */
+
+/* ************************************************************************ */
+
+#ifdef EXTERNAL_CSS_FILE /* Where is it defined? */
+static const char report_html_alternative_head[] =
+       "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" "
+               "\"http://www.w3.org/TR/html4/loose.dtd\">\n"
+       "<html>\n"
+       "<head>\n"
+       "<title>PowerTOP report</title>\n"
+       "<link rel=\"stylesheet\" href=\"powertop.css\">\n"
+       "</head>\n"
+       "<body>\n";
+#endif /* EXTERNAL_CSS_FILE */
+
+/* ************************************************************************ */
+
+static const char report_html_footer[] =
+       "</body>\n"
+       "</html>\n";
+
+/* ************************************************************************ */
+
+void
+report_formatter_html::init_markup()
+{
+       /*          stype               id */
+       set_section(SECTION_DEFAULT);
+       set_section(SECTION_SYSINFO,    "system");
+       set_section(SECTION_CPUIDLE,    "cpuidle");
+       set_section(SECTION_CPUFREQ,    "cpufreq");
+       set_section(SECTION_DEVPOWER,   "device");
+       set_section(SECTION_SOFTWARE,   "software");
+       set_section(SECTION_SUMMARY,    "summary");
+       set_section(SECTION_TUNING,     "tuning");
+
+       /*        ttype          width */
+       set_table(TABLE_DEFAULT, "");
+       set_table(TABLE_WIDE,    "100%");
+
+       /*       ctype                          is_header, width, colspan */
+       set_cell(CELL_DEFAULT);
+       set_cell(CELL_SEPARATOR,                false,  "2%");
+       set_cell(CELL_SYSINFO,                  false,  "20%");
+       set_cell(CELL_FIRST_PACKAGE_HEADER,     true,   "25%",  2);
+       set_cell(CELL_EMPTY_PACKAGE_HEADER,     true,   "",     2);
+       set_cell(CELL_CORE_HEADER,              true,   "25%",  2);
+       set_cell(CELL_CPU_CSTATE_HEADER,        true,   "",     3);
+       set_cell(CELL_CPU_PSTATE_HEADER,        true,   "",     2);
+       set_cell(CELL_STATE_NAME,               false,  "10%");
+       set_cell(CELL_EMPTY_PACKAGE_STATE,      false,  "",     2);
+       set_cell(CELL_PACKAGE_STATE_VALUE);
+       set_cell(CELL_CORE_STATE_VALUE);
+       set_cell(CELL_CPU_STATE_VALUE);
+       set_cell(CELL_DEVPOWER_HEADER,          true,   "10%");
+       set_cell(CELL_DEVPOWER_DEV_NAME,        true);
+       set_cell(CELL_DEVPOWER_POWER);
+       set_cell(CELL_DEVPOWER_UTIL);
+       set_cell(CELL_DEVACTIVITY_PROCESS,      true,   "40%");
+       set_cell(CELL_DEVACTIVITY_DEVICE,       true);
+       set_cell(CELL_SOFTWARE_HEADER,          true,   "10%");
+       set_cell(CELL_SOFTWARE_PROCESS,         true,   "10%");
+       set_cell(CELL_SOFTWARE_DESCRIPTION,     true);
+       set_cell(CELL_SOFTWARE_POWER);
+       set_cell(CELL_SUMMARY_HEADER,           true,   "10%");
+       set_cell(CELL_SUMMARY_CATEGORY,         true,   "10%");
+       set_cell(CELL_SUMMARY_DESCRIPTION,      true);
+       set_cell(CELL_SUMMARY_ITEM);
+       set_cell(CELL_TUNABLE_HEADER,           true);
+}
+
+/* ************************************************************************ */
+
+const char *
+report_formatter_html::get_row_style(row_type rtype)
+{
+       switch (rtype) {
+               case ROW_SYSINFO:
+                       return get_style_pair("system_even", "system_odd");
+               case ROW_DEVPOWER:
+                       return get_style_pair("device_even", "device_odd");
+               case ROW_SOFTWARE:
+               case ROW_SUMMARY:
+                       return get_style_pair("process_even", "process_odd");
+               case ROW_TUNABLE:
+                       return get_style_pair("tunable_even", "tunable_odd");
+               case ROW_TUNABLE_BAD:
+                       return get_style_pair("tunable_even_bad",
+                                                          "tunable_odd_bad");
+               default:
+                       return "";
+       };
+}
+
+/* ************************************************************************ */
+
+const char *
+report_formatter_html::get_cell_style(cell_type ctype)
+{
+       switch (ctype) {
+               case CELL_FIRST_PACKAGE_HEADER:
+               case CELL_EMPTY_PACKAGE_HEADER:
+                       return "package_header";
+               case CELL_CORE_HEADER:
+                       return "core_header";
+               case CELL_CPU_CSTATE_HEADER:
+               case CELL_CPU_PSTATE_HEADER:
+                       return "cpu_header";
+               case CELL_STATE_NAME:
+                       return get_style_pair("cpu_even_freq",
+                                             "cpu_odd_freq");
+               case CELL_PACKAGE_STATE_VALUE:
+                       return get_style_pair("package_even",
+                                             "package_odd");
+               case CELL_CORE_STATE_VALUE:
+                       return get_style_pair("core_even",
+                                             "core_odd");
+               case CELL_CPU_STATE_VALUE:
+                       return get_style_quad("cpu_even_even", "cpu_even_odd",
+                                             "cpu_odd_even", "cpu_odd_odd",
+                                             cpu_nr);
+               case CELL_DEVPOWER_DEV_NAME:
+               case CELL_DEVACTIVITY_PROCESS:
+               case CELL_DEVACTIVITY_DEVICE:
+                       return "device";
+               case CELL_DEVPOWER_POWER:
+                       return "device_power";
+               case CELL_DEVPOWER_UTIL:
+                       return "device_util";
+               case CELL_SOFTWARE_PROCESS:
+               case CELL_SOFTWARE_DESCRIPTION:
+               case CELL_SUMMARY_CATEGORY:
+               case CELL_SUMMARY_DESCRIPTION:
+                       return "process";
+               case CELL_SOFTWARE_POWER:
+               case CELL_SUMMARY_ITEM:
+                       return "process_power";
+               case CELL_TUNABLE_HEADER:
+                       return "tunable";
+               default:
+                       return "";
+       };
+}
+
+/* ************************************************************************ */
+
+report_formatter_html::report_formatter_html()
+{
+       init_markup();
+       add_doc_header();
+}
+
+/* ************************************************************************ */
+
+const char *
+report_formatter_html::get_style_pair(const char *even, const char *odd)
+{
+       if (!(table_row_number & 1) && even)
+               return even;
+
+       if ((table_row_number & 1) && odd)
+               return odd;
+
+       return "";
+}
+
+/* ************************************************************************ */
+
+const char *
+report_formatter_html::get_style_quad(const char *even_even,
+                                  const char *even_odd, const char *odd_even,
+                                  const char *odd_odd, int alt_cell_number)
+{
+       int cell;
+
+       cell = (alt_cell_number != -1 ? alt_cell_number : table_cell_number);
+       if (!(table_row_number & 1) && !(cell & 1) && even_even)
+               return even_even;
+
+       if (!(table_row_number & 1) && (cell & 1) && even_odd)
+               return even_odd;
+
+       if ((table_row_number & 1) && !(cell & 1) && odd_even)
+               return odd_even;
+
+       if ((table_row_number & 1) && (cell & 1) && odd_odd)
+               return odd_odd;
+
+       return "";
+}
+
+/* ************************************************************************ */
+
+void
+report_formatter_html::finish_report()
+{
+       add_doc_footer();
+}
+
+/* ************************************************************************ */
+
+void
+report_formatter_html::set_section(section_type stype, const char *id)
+{
+       sections[stype].id = id;
+}
+
+/* ************************************************************************ */
+
+void
+report_formatter_html::set_table(table_type ttype, const char *width)
+{
+       tables[ttype].width = width;
+}
+
+/* ************************************************************************ */
+
+void
+report_formatter_html::set_cell(cell_type ctype, bool is_header,
+                            const char *width, int colspan)
+{
+       cells[ctype].is_header = is_header;
+       cells[ctype].width     = width;
+       cells[ctype].colspan   = colspan;
+}
+
+/* ************************************************************************ */
+
+void
+report_formatter_html::add_doc_header()
+{
+#ifdef EXTERNAL_CSS_FILE /* Where is it defined? */
+       add_exact(report_html_alternative_head);
+#else /* !EXTERNAL_CSS_FILE */
+       add_exact(css);
+#endif /* !EXTERNAL_CSS_FILE */
+}
+
+/* ************************************************************************ */
+
+void
+report_formatter_html::add_doc_footer()
+{
+       add_exact(report_html_footer);
+}
+
+/* ************************************************************************ */
+
+void
+report_formatter_html::add_header(const char *header, int level)
+{
+       addf_exact("<h%d>", level);
+       add(header);
+       addf_exact("</h%d>\n", level);
+}
+
+/* ************************************************************************ */
+
+void
+report_formatter_html::begin_section(section_type stype)
+{
+       if (sections[stype].id[0])
+               addf_exact("<div id=\"%s\">", sections[stype].id);
+       else
+               add_exact("<div>");
+}
+
+/* ************************************************************************ */
+
+void
+report_formatter_html::end_section()
+{
+       add_exact("</div>\n\n");
+}
+
+/* ************************************************************************ */
+
+void
+report_formatter_html::begin_table(table_type ttype)
+{
+       table_row_number = 0;
+       add_exact("<table");
+       if (tables[ttype].width[0])
+               addf_exact(" width=\"%s\"", tables[ttype].width);
+
+       add_exact(">\n");
+}
+
+/* ************************************************************************ */
+
+void
+report_formatter_html::end_table()
+{
+       add_exact("</table>\n\n");
+}
+
+/* ************************************************************************ */
+
+void
+report_formatter_html::begin_row(row_type rtype)
+{
+       const char *row_style;
+
+       table_cell_number = 0;
+       add_exact("<tr");
+       row_style = get_row_style(rtype);
+       if (row_style[0])
+               addf_exact(" class=\"%s\"", row_style);
+
+       add_exact(">\n");
+}
+
+/* ************************************************************************ */
+
+void
+report_formatter_html::end_row()
+{
+       add_exact("</tr>\n");
+       table_row_number++;
+}
+
+/* ************************************************************************ */
+
+void
+report_formatter_html::begin_cell(cell_type ctype)
+{
+       const char *cell_style;
+
+       current_cell = ctype;
+       if (cells[ctype].is_header)
+               add_exact("\t<th");
+       else
+               add_exact("\t<td");
+
+       if (cells[ctype].width[0])
+               addf_exact(" width=\"%s\"", cells[ctype].width);
+
+       if (cells[ctype].colspan > 1)
+               addf_exact(" colspan=\"%d\"", cells[ctype].colspan);
+
+       cell_style = get_cell_style(ctype);
+       if (cell_style[0])
+               addf_exact(" class=\"%s\"", cell_style);
+
+       add_exact(">");
+}
+
+/* ************************************************************************ */
+
+void
+report_formatter_html::end_cell()
+{
+       if (!cells[current_cell].is_header)
+               add_exact("</td>\n");
+       else
+               add_exact("</th>\n");
+
+       table_cell_number++;
+}
+
+/* ************************************************************************ */
+
+void
+report_formatter_html::add_empty_cell()
+{
+       add_exact("&nbsp;");
+}
+
+/* ************************************************************************ */
+
+void
+report_formatter_html::begin_paragraph()
+{
+       add_exact("<p>");
+}
+
+/* ************************************************************************ */
+
+void
+report_formatter_html::end_paragraph()
+{
+       add_exact("</p>\n");
+}
+
+/* ************************************************************************ */
+
+std::string
+report_formatter_html::escape_string(const char *str)
+{
+       std::string res;
+
+       assert(str);
+
+       for (const char *i = str; *i; i++) {
+               switch (*i) {
+                       case '<':
+                               res += "&lt;";
+                               continue;
+                       case '>':
+                               res += "&gt;";
+                               continue;
+                       case '&':
+                               res += "&amp;";
+                               continue;
+#ifdef REPORT_HTML_ESCAPE_QUOTES
+                       case '"':
+                               res += "&quot;";
+                               continue;
+                       case '\'':
+                               res += "&apos;";
+                               continue;
+#endif /* REPORT_HTML_ESCAPE_QUOTES */
+               }
+
+               res += *i;
+       }
+
+       return res;
+}
+
+/* ************************************************************************ */
+
+void
+report_formatter_html::set_cpu_number(int nr)
+{
+       assert(nr >= 0);
+
+       cpu_nr = nr;
+}
diff --git a/src/report/report-formatter-html.h b/src/report/report-formatter-html.h
new file mode 100644 (file)
index 0000000..4d00efe
--- /dev/null
@@ -0,0 +1,116 @@
+/* Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ *     http://www.samsung.com/
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * HTML report generator.
+ * Written by Igor Zhbanov <i.zhbanov@samsung.com>
+ * 2012.10 */
+
+#ifndef _REPORT_FORMATTER_HTML_H_
+#define _REPORT_FORMATTER_HTML_H_
+
+#include <string>
+
+#include "report-formatter-base.h"
+
+/* Whether to replace " and ' in HTML by &quot; and &apos; respectively */
+/*#define REPORT_HTML_ESCAPE_QUOTES*/
+
+/* ************************************************************************ */
+
+struct html_section {
+       const char *id;
+};
+
+/* ************************************************************************ */
+
+struct html_table {
+       const char *width;
+};
+
+/* ************************************************************************ */
+
+struct html_cell {
+       bool is_header;
+       const char *width;
+       int colspan;
+};
+
+/* ************************************************************************ */
+
+class report_formatter_html: public report_formatter_string_base
+{
+public:
+       report_formatter_html();
+
+       void finish_report();
+
+       void add_header(const char *header, int level);
+
+       void begin_section(section_type stype);
+       void end_section();
+
+       void begin_table(table_type ttype);
+       void end_table();
+
+       void begin_row(row_type rtype);
+       void end_row();
+
+       void begin_cell(cell_type ctype);
+       void end_cell();
+       void add_empty_cell();
+
+       void begin_paragraph();
+       void end_paragraph();
+
+       void set_cpu_number(int nr);
+
+private:
+       /* Document structure related functions */
+       void init_markup();
+       void set_section(section_type stype, const char *id = "");
+       void set_table(table_type ttype, const char *width = "");
+       void set_cell(cell_type ctype, bool is_header = false,
+                       const char *width = "", int colspan = 1);
+
+       /* HTML table elements CSS classes */
+       const char *get_cell_style(cell_type ctype);
+       const char *get_row_style(row_type rtype);
+       const char *get_style_pair(const char *even, const char *odd);
+       const char *get_style_quad(const char *even_even,
+                                  const char *even_odd,
+                                  const char *odd_even,
+                                  const char *odd_odd,
+                                  int alt_cell_number = -1);
+
+       void add_doc_header();
+       void add_doc_footer();
+
+       std::string escape_string(const char *str);
+
+       html_section sections[SECTION_MAX];
+       html_table tables[TABLE_MAX];
+       html_cell cells[CELL_MAX];
+       size_t table_row_number, table_cell_number;
+       cell_type current_cell;
+       int cpu_nr;
+};
+
+#endif /* _REPORT_FORMATTER_HTML_H_ */
diff --git a/src/report/report-formatter.h b/src/report/report-formatter.h
new file mode 100644 (file)
index 0000000..d532f30
--- /dev/null
@@ -0,0 +1,65 @@
+/* Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ *     http://www.samsung.com/
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * report_formatter interface.
+ * Written by Igor Zhbanov <i.zhbanov@samsung.com>
+ * 2012.10 */
+
+#ifndef _REPORT_FORMATTER_H_
+#define _REPORT_FORMATTER_H_
+
+#include "report-maker.h"
+
+class report_formatter
+{
+public:
+       virtual ~report_formatter() {}
+
+       virtual void finish_report() {}
+       virtual const char *get_result() {return "Basic report_formatter::get_result() call\n";}
+       virtual void clear_result() {}
+
+       virtual void add(const char *str) {}
+       virtual void addv(const char *fmt, va_list ap) {}
+
+       virtual void add_header(const char *header, int level) {}
+
+       virtual void begin_section(section_type stype) {}
+       virtual void end_section() {}
+
+       virtual void begin_table(table_type ttype) {}
+       virtual void end_table() {}
+
+       virtual void begin_row(row_type rtype) {}
+       virtual void end_row() {}
+
+       virtual void begin_cell(cell_type ctype) {}
+       virtual void end_cell() {}
+       virtual void add_empty_cell() {}
+
+       virtual void begin_paragraph() {}
+       virtual void end_paragraph() {}
+
+       /* For quad-colouring CPU tables in HTML */
+       virtual void set_cpu_number(int nr) {}
+};
+
+#endif /* _REPORT_FORMATTER_H_ */
diff --git a/src/report/report-maker.cpp b/src/report/report-maker.cpp
new file mode 100644 (file)
index 0000000..59e83d9
--- /dev/null
@@ -0,0 +1,331 @@
+/* Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ *     http://www.samsung.com/
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Generic report generator.
+ * Written by Igor Zhbanov <i.zhbanov@samsung.com>
+ * 2012.10 */
+
+/* Uncomment to disable asserts */
+/*#define NDEBUG*/
+
+#include <assert.h>
+#include <stdarg.h>
+
+#include "report-maker.h"
+#include "report-formatter-csv.h"
+#include "report-formatter-html.h"
+
+/* ************************************************************************ */
+
+report_maker::report_maker(report_type t)
+{
+       type = t;
+       formatter = NULL;
+       setup_report_formatter();
+       clear_result(); /* To reset state and add document header */
+}
+
+/* ************************************************************************ */
+
+report_maker::~report_maker()
+{
+       if (formatter)
+               delete formatter;
+}
+
+/* ************************************************************************ */
+
+void
+report_maker::finish_report()
+{
+       if (section_opened)
+               end_section();
+
+       formatter->finish_report();
+}
+
+/* ************************************************************************ */
+
+const char *
+report_maker::get_result()
+{
+       return formatter->get_result();
+}
+
+/* ************************************************************************ */
+
+void
+report_maker::clear_result()
+{
+       formatter->clear_result();
+       section_opened   = false;
+       table_opened     = false;
+       cell_opened      = false;
+       row_opened       = false;
+       paragraph_opened = false;
+}
+
+/* ************************************************************************ */
+
+report_type
+report_maker::get_type()
+{
+       return type;
+}
+
+/* ************************************************************************ */
+
+void
+report_maker::set_type(report_type t)
+{
+       clear_result();
+       type = t;
+       setup_report_formatter();
+}
+
+/* ************************************************************************ */
+
+void
+report_maker::setup_report_formatter()
+{
+       if (formatter)
+               delete formatter;
+
+       if (type == REPORT_HTML)
+               formatter = new report_formatter_html();
+       else if (type == REPORT_CSV)
+               formatter = new report_formatter_csv();
+       else if (type == REPORT_OFF)
+               formatter = new report_formatter();
+       else
+               assert(false);
+}
+
+/* ************************************************************************ */
+
+void
+report_maker::add(const char *str)
+{
+       assert(str);
+       assert(section_opened);
+
+       formatter->add(str);
+}
+
+/* ************************************************************************ */
+
+void
+report_maker::addf(const char *fmt, ...)
+{
+       va_list ap;
+
+       assert(fmt);
+       assert(section_opened);
+
+       va_start(ap, fmt);
+       formatter->addv(fmt, ap);
+       va_end(ap);
+}
+
+/* ************************************************************************ */
+
+void
+report_maker::add_header(const char *header, int level)
+{
+       assert(header);
+       assert(section_opened);
+       assert(level > 0 && level < 4);
+
+       if (table_opened)
+               end_table();
+       else if (paragraph_opened)
+               end_paragraph();
+
+       formatter->add_header(header, level);
+}
+
+/* ************************************************************************ */
+
+void
+report_maker::begin_section(section_type stype)
+{
+       assert(stype >= 0 && stype < SECTION_MAX);
+
+       if (section_opened)
+               end_section(); /* Close previous */
+
+       section_opened = true;
+       formatter->begin_section(stype);
+}
+
+/* ************************************************************************ */
+
+void
+report_maker::end_section()
+{
+       assert(section_opened);
+
+       if (table_opened)
+               end_table();
+       else if (paragraph_opened)
+               end_paragraph();
+
+       section_opened = false;
+       formatter->end_section();
+}
+
+/* ************************************************************************ */
+
+void
+report_maker::begin_table(table_type ttype)
+{
+       assert(ttype >= 0 && ttype < TABLE_MAX);
+       assert(section_opened);
+
+       if (table_opened)
+               end_table(); /* Close previous */
+       else if (paragraph_opened)
+               end_paragraph();
+
+       table_opened = true;
+       formatter->begin_table(ttype);
+}
+
+/* ************************************************************************ */
+
+void
+report_maker::end_table()
+{
+       assert(section_opened);
+       assert(table_opened);
+
+       if (row_opened)
+               end_row();
+
+       table_opened = false;
+       formatter->end_table();
+}
+
+/* ************************************************************************ */
+
+void
+report_maker::begin_row(row_type rtype)
+{
+       assert(section_opened);
+       assert(table_opened);
+       assert(rtype >= 0 && rtype < ROW_MAX);
+
+       if (row_opened)
+               end_row(); /* Close previous */
+
+       row_opened = true;
+       formatter->begin_row(rtype);
+}
+
+/* ************************************************************************ */
+
+void
+report_maker::end_row()
+{
+       assert(section_opened);
+       assert(table_opened);
+       assert(row_opened);
+
+       if (cell_opened)
+               end_cell();
+
+       row_opened = false;
+       formatter->end_row();
+}
+
+/* ************************************************************************ */
+
+void
+report_maker::begin_cell(cell_type ctype)
+{
+       assert(section_opened);
+       assert(table_opened);
+       assert(row_opened);
+       assert(ctype >= 0 && ctype < CELL_MAX);
+
+       if (cell_opened)
+               end_cell(); /* Close previous */
+
+       cell_opened = true;
+       formatter->begin_cell(ctype);
+}
+
+/* ************************************************************************ */
+
+void
+report_maker::end_cell()
+{
+       assert(section_opened);
+       assert(table_opened);
+       assert(row_opened);
+       assert(cell_opened);
+
+       cell_opened = false;
+       formatter->end_cell();
+}
+
+/* ************************************************************************ */
+
+void
+report_maker::add_empty_cell()
+{
+       formatter->add_empty_cell();
+}
+
+/* ************************************************************************ */
+
+void
+report_maker::set_cpu_number(int nr)
+{
+       formatter->set_cpu_number(nr);
+}
+
+/* ************************************************************************ */
+
+void
+report_maker::begin_paragraph()
+{
+       assert(section_opened);
+
+       if (table_opened)
+               end_table();
+       else if (paragraph_opened)
+               end_paragraph(); /* Close previous */
+
+       paragraph_opened = true;
+       formatter->begin_paragraph();
+}
+
+/* ************************************************************************ */
+
+void
+report_maker::end_paragraph()
+{
+       assert(paragraph_opened);
+
+       paragraph_opened = false;
+       formatter->end_paragraph();
+}
diff --git a/src/report/report-maker.h b/src/report/report-maker.h
new file mode 100644 (file)
index 0000000..75e0d06
--- /dev/null
@@ -0,0 +1,210 @@
+/* Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ *     http://www.samsung.com/
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Generic report generator.
+ * Written by Igor Zhbanov <i.zhbanov@samsung.com>
+ * 2012.10 */
+
+#ifndef _REPORT_MAKER_H_
+#define _REPORT_MAKER_H_
+
+/* This report generator implements the following document structure:
+ *     body
+ *       \---> section
+ *               |---> header
+ *               |---> paragraph
+ *               \---> table
+ *                       \---> table row
+ *                               \---> table cell
+ *
+ * The report body consists of a number of sections (a.k.a. <div>s,
+ * a.k.a. tabs).
+ * Each section can contain headers (<h1>, <h2>, <h3>), paragraphs (<p>)
+ * and tables (<table>).
+ *
+ * A header is a single line of text.
+ *
+ * Paragraphs can contain only text.
+ *
+ * A table consists of table rows. A table row consists of table cells.
+ * A table cell can contain only text.
+ *
+ * Each section, table, row or cell could have its own formatting.
+ * To distinguish elements from others of its type, each element could have
+ * an unique identifier (see enums section_type, table_type, row_type and
+ * cell_type below). These identifiers are used in formatter implementations
+ * to produce special formatting.
+ *
+ * Example of usage:
+ *     report_maker report(REPORT_OFF);
+ *
+ *     report.set_type(REPORT_HTML);
+ *     report.begin_section();
+ *             report.add_header("Big report");
+ *             report.begin_paragraph("Some text");
+ *             report.begin_table();
+ *                     report.begin_row();
+ *                             report.begin_cell();
+ *                                     report.add("Something");
+ *                             report.begin_cell(CELL_SPECIAL);
+ *                                     report.add("Foo bar");
+ *     report.finish_report();
+ *     const char *result = report.get_result();
+ */
+
+#include <stdarg.h>
+
+#include <string>
+
+/* Conditional gettext. We need original strings for CSV. */
+#define __(STRING) \
+       ((report.get_type() == REPORT_CSV) ? (STRING) : gettext(STRING))
+
+#ifndef UNUSED
+#define UNUSED __attribute__((unused))
+#endif /* UNUSED */
+
+/* ************************************************************************ */
+
+enum report_type {
+       REPORT_OFF,
+       REPORT_HTML,
+       REPORT_CSV
+};
+
+/* ************************************************************************ */
+
+enum section_type {
+       SECTION_DEFAULT,
+       SECTION_SYSINFO,
+       SECTION_CPUIDLE,
+       SECTION_CPUFREQ,
+       SECTION_DEVPOWER,
+       SECTION_SOFTWARE,
+       SECTION_SUMMARY,
+       SECTION_TUNING,
+       SECTION_MAX /* Must be last in this enum */
+};
+
+/* ************************************************************************ */
+
+enum table_type {
+       TABLE_DEFAULT,
+       TABLE_WIDE,
+       TABLE_MAX /* Must be last in this enum */
+};
+
+/* ************************************************************************ */
+
+enum row_type {
+       ROW_DEFAULT,
+       ROW_SYSINFO,
+       ROW_DEVPOWER,
+       ROW_SOFTWARE,
+       ROW_SUMMARY,
+       ROW_TUNABLE,
+       ROW_TUNABLE_BAD,
+       ROW_MAX /* Must be last in this enum */
+};
+
+/* ************************************************************************ */
+
+enum cell_type {
+       CELL_DEFAULT,
+       CELL_SYSINFO,
+       CELL_FIRST_PACKAGE_HEADER,
+       CELL_EMPTY_PACKAGE_HEADER,
+       CELL_CORE_HEADER,
+       CELL_CPU_CSTATE_HEADER,
+       CELL_CPU_PSTATE_HEADER,
+       CELL_STATE_NAME,
+       CELL_EMPTY_PACKAGE_STATE,
+       CELL_PACKAGE_STATE_VALUE,
+       CELL_CORE_STATE_VALUE,
+       CELL_CPU_STATE_VALUE,
+       CELL_SEPARATOR,
+       CELL_DEVPOWER_HEADER,
+       CELL_DEVPOWER_DEV_NAME,
+       CELL_DEVPOWER_POWER,
+       CELL_DEVPOWER_UTIL,
+       CELL_DEVACTIVITY_PROCESS,
+       CELL_DEVACTIVITY_DEVICE,
+       CELL_SOFTWARE_HEADER,
+       CELL_SOFTWARE_PROCESS,
+       CELL_SOFTWARE_DESCRIPTION,
+       CELL_SOFTWARE_POWER,
+       CELL_SUMMARY_HEADER,
+       CELL_SUMMARY_CATEGORY,
+       CELL_SUMMARY_DESCRIPTION,
+       CELL_SUMMARY_ITEM,
+       CELL_TUNABLE_HEADER,
+       CELL_UNTUNABLE_HEADER,
+       CELL_MAX /* Must be last in this enum */
+};
+
+/* ************************************************************************ */
+
+class report_formatter;
+
+class report_maker
+{
+public:
+       report_maker(report_type t);
+       ~report_maker();
+
+       report_type get_type();
+       void set_type(report_type t);
+
+       void addf(const char *fmt, ...)
+                               __attribute__ ((format (printf, 2, 3)));
+
+       void finish_report();
+       const char *get_result();
+       void clear_result();
+
+       void add(const char *str);
+
+       void add_header(const char *header, int level = 2);
+       void begin_section(section_type stype = SECTION_DEFAULT);
+       void begin_table(table_type ttype = TABLE_DEFAULT);
+       void begin_row(row_type rtype = ROW_DEFAULT);
+       void begin_cell(cell_type ctype = CELL_DEFAULT);
+       void add_empty_cell();
+       void begin_paragraph();
+
+       void set_cpu_number(int nr);
+
+private:
+       void setup_report_formatter();
+
+       void end_section();
+       void end_table();
+       void end_row();
+       void end_cell();
+       void end_paragraph();
+
+       report_type type;
+       report_formatter *formatter;
+       bool cell_opened, row_opened, table_opened, section_opened,
+            paragraph_opened;
+};
+
+#endif /* _REPORT_MAKER_H_ */
diff --git a/src/report/report.cpp b/src/report/report.cpp
new file mode 100644 (file)
index 0000000..c018bb1
--- /dev/null
@@ -0,0 +1,198 @@
+/*
+ * Copyright 2011, Intel Corporation
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ *     Arjan van de Ven <arjan@linux.intel.com>
+ *  Chris Ferron <chris.e.ferron@linux.intel.com>
+ */
+
+#include "lib.h"
+#include "report.h"
+#include "report-maker.h"
+#include <errno.h>
+#include <string.h>
+#include <utility>
+#include <iostream>
+#include <fstream>
+#include <string.h>
+#include <malloc.h>
+#include <unistd.h>
+
+using namespace std;
+
+struct reportstream reportout;
+report_type reporttype = REPORT_OFF;
+report_maker report(REPORT_OFF);
+
+string cpu_model(void)
+{
+       ifstream file;
+
+       file.open("/proc/cpuinfo", ios::in);
+
+       if (!file)
+               return "";
+
+       while (file) {
+               char line[4096];
+               file.getline(line, 4096);
+               if (strstr(line, "model name")) {
+                       char *c;
+                       c = strchr(line, ':');
+                       if (c) {
+                               file.close();
+                               c++;
+                               return c;
+                       }
+               }
+       }
+       file.close();
+       return "";
+}
+
+static string read_os_release(const string &filename)
+{
+       ifstream file;
+       char content[4096];
+       char *c;
+       const char *pname = "PRETTY_NAME=";
+       string os("");
+
+       file.open(filename.c_str(), ios::in);
+       if (!file)
+               return "";
+       while (file.getline(content, 4096)) {
+               if (strncasecmp(pname, content, strlen(pname)) == 0) {
+                       c = strchr(content, '=');
+                       if (!c)
+                               break;
+                       c += 1;
+                       if (*c == '"' || *c == '\'')
+                               c += 1;
+                       *strchrnul(c, '"') = 0;
+                       *strchrnul(c, '\'') = 0;
+                       os = c;
+                       break;
+               }
+       }
+       file.close();
+       return os;
+}
+
+static void system_info(void)
+{
+       string str, str2, str3;
+
+       report.begin_section(SECTION_SYSINFO);
+       report.add_header("System Information");
+       report.begin_table();
+       report.begin_row(ROW_SYSINFO);
+       report.begin_cell(CELL_SYSINFO);
+       report.add("PowerTOP Version");
+       report.begin_cell();
+       report.add(POWERTOP_VERSION);
+
+       str = read_sysfs_string("/proc/version");
+       report.begin_row(ROW_SYSINFO);
+       report.begin_cell();
+       report.add("Kernel Version");
+       report.begin_cell();
+       report.add(str.c_str());
+
+       str  = read_sysfs_string("/sys/devices/virtual/dmi/id/board_vendor");
+       str2 = read_sysfs_string("/sys/devices/virtual/dmi/id/board_name");
+       str3 = read_sysfs_string("/sys/devices/virtual/dmi/id/product_version");
+       report.begin_row(ROW_SYSINFO);
+       report.begin_cell();
+       report.add("System Name");
+       report.begin_cell();
+       report.addf("%s %s %s", str.c_str(), str2.c_str(), str3.c_str());
+
+       str = cpu_model();
+       report.begin_row(ROW_SYSINFO);
+       report.begin_cell();
+       report.add("CPU Information");
+       report.begin_cell();
+       report.addf("%lix %s", sysconf(_SC_NPROCESSORS_ONLN), str.c_str());
+
+       str = read_sysfs_string("/etc/system-release");
+       if (str.length() < 1)
+               str = read_sysfs_string("/etc/redhat-release");
+       if (str.length() < 1)
+               str = read_os_release("/etc/os-release");
+
+       report.begin_row(ROW_SYSINFO);
+       report.begin_cell();
+       report.add("OS Information");
+       report.begin_cell();
+       report.add(str.c_str());
+}
+
+void init_report_output(char *filename_str, int iterations)
+{
+       size_t period;
+       char file_prefix[4096];
+       char file_postfix[8];
+       time_t stamp;
+       char datestr[200];
+
+       string mystring = string(filename_str);
+       sprintf(file_postfix, "%s",
+               (reporttype == REPORT_HTML ? "html" : "csv"));
+       period=mystring.find_last_of(".");
+       sprintf(file_prefix, "%s",mystring.substr(0,period).c_str());
+       memset(&datestr, 0, 200);
+       memset(&stamp, 0, sizeof(time_t));
+       stamp=time(NULL);
+       strftime(datestr, sizeof(datestr), "%Y%m%d-%H%M%S", localtime(&stamp));
+
+       if (iterations != 1)
+               sprintf(reportout.filename, "%s-%s.%s",
+                       file_prefix, datestr,file_postfix);
+       else
+               sprintf(reportout.filename, "%s.%s",
+                       file_prefix, file_postfix);
+
+       reportout.report_file = fopen(reportout.filename, "wm");
+       if (!reportout.report_file) {
+               fprintf(stderr, _("Cannot open output file %s (%s)\n"),
+                       reportout.filename, strerror(errno));
+       }
+
+       report.set_type(reporttype);
+       system_info();
+}
+
+void finish_report_output(void)
+{
+       if (reporttype == REPORT_OFF)
+               return;
+
+       report.finish_report();
+       if (reportout.report_file)
+       {
+               fprintf(stderr, _("PowerTOP outputing using base filename %s\n"), reportout.filename);
+               fputs(report.get_result(), reportout.report_file);
+               fdatasync(fileno(reportout.report_file));
+               fclose(reportout.report_file);
+       }
+       report.clear_result();
+}
diff --git a/src/report/report.h b/src/report/report.h
new file mode 100644 (file)
index 0000000..77bf2d7
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ *     Arjan van de Ven <arjan@linux.intel.com>
+ */
+#ifndef __INCLUDE_GUARD_REPORT_H_
+#define __INCLUDE_GUARD_REPORT_H_
+
+#include <string>
+#include <stdio.h>
+
+#include "report-maker.h"
+
+using namespace std;
+
+struct reportstream {
+       FILE *report_file;
+       char filename[4096];
+};
+
+extern report_type reporttype;
+extern report_maker report;
+extern struct reportstream reportout;
+extern void init_report_output(char *filename_str, int iterations);
+extern void finish_report_output(void);
+
+#endif
diff --git a/src/tuning/bluetooth.cpp b/src/tuning/bluetooth.cpp
new file mode 100644 (file)
index 0000000..e0bdf12
--- /dev/null
@@ -0,0 +1,226 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ *     Arjan van de Ven <arjan@linux.intel.com>
+ */
+
+#include "tuning.h"
+#include "tunable.h"
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <utility>
+#include <iostream>
+#include <fstream>
+#include <unistd.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+
+#include "../lib.h"
+#include "bluetooth.h"
+
+bt_tunable::bt_tunable(void) : tunable("", 1.0, "Good", "Bad", "Unknown")
+{
+       sprintf(desc, _("Bluetooth device interface status"));
+       strcpy(toggle_bad, "/usr/sbin/hciconfig hci0 up &> /dev/null &");
+       strcpy(toggle_good, "/usr/sbin/hciconfig hci0 down &> /dev/null");
+}
+
+
+
+/* structure definitions copied from include/net/bluetooth/hci.h from the 2.6.20 kernel */
+#define HCIGETDEVINFO   _IOR('H', 211, int)
+#define BTPROTO_HCI     1
+
+#define __u16 uint16_t
+#define __u8 uint8_t
+#define __u32 uint32_t
+
+typedef struct {
+        __u8 b[6];
+} __attribute__((packed)) bdaddr_t;
+
+struct hci_dev_stats {
+        __u32 err_rx;
+        __u32 err_tx;
+        __u32 cmd_tx;
+        __u32 evt_rx;
+        __u32 acl_tx;
+        __u32 acl_rx;
+        __u32 sco_tx;
+        __u32 sco_rx;
+        __u32 byte_rx;
+        __u32 byte_tx;
+};
+
+
+struct hci_dev_info {
+       __u16 dev_id;
+       char  name[8];
+
+       bdaddr_t bdaddr;
+
+       __u32 flags;
+       __u8  type;
+
+       __u8  features[8];
+
+       __u32 pkt_type;
+       __u32 link_policy;
+       __u32 link_mode;
+
+       __u16 acl_mtu;
+       __u16 acl_pkts;
+       __u16 sco_mtu;
+       __u16 sco_pkts;
+
+       struct hci_dev_stats stat;
+};
+
+static int previous_bytes = -1;
+static time_t last_check_time = 0;
+static int last_check_result;
+
+int bt_tunable::good_bad(void)
+{
+       struct hci_dev_info devinfo;
+       FILE *file;
+       int fd;
+       int thisbytes = 0;
+       int ret;
+       int result = TUNE_GOOD;
+
+       fd = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
+       if (fd < 0)
+               return TUNE_GOOD;
+
+       memset(&devinfo, 0, sizeof(devinfo));
+       strcpy(devinfo.name, "hci0");
+       ret = ioctl(fd, HCIGETDEVINFO, (void *) &devinfo);
+       if (ret < 0)
+               goto out;
+
+       if ( (devinfo.flags & 1) == 0 &&
+               access("/sys/module/hci_usb",F_OK)) /* interface down already */
+               goto out;
+
+       thisbytes += devinfo.stat.byte_rx;
+       thisbytes += devinfo.stat.byte_tx;
+
+       /* device is active... so we need to leave it on */
+       if (thisbytes != previous_bytes)
+               goto out;
+
+
+       /* this check is expensive.. only do it once per minute */
+       if (time(NULL) - last_check_time > 60) {
+               last_check_result = TUNE_BAD;
+               /* now, also check for active connections */
+               file = popen("/usr/bin/hcitool con 2> /dev/null", "r");
+               if (file) {
+                       char line[2048];
+                       /* first line is standard header */
+                       if (fgets(line, 2047, file) == NULL)
+                               goto out;
+                       memset(line, 0, 2048);
+                       if (fgets(line, 2047, file) == NULL) {
+                               result = last_check_result = TUNE_GOOD;
+                               pclose(file);
+                               goto out;
+                       }
+
+                       pclose(file);
+                       if (strlen(line) > 0) {
+                               result = last_check_result = TUNE_GOOD;
+                               goto out;
+                       }
+               }
+               last_check_time = time(NULL);
+       };
+
+       result = last_check_result;
+
+out:
+       previous_bytes = thisbytes;
+       close(fd);
+       return result;
+}
+
+void bt_tunable::toggle(void)
+{
+       int good;
+       good = good_bad();
+
+       if (good == TUNE_GOOD) {
+               system("/usr/sbin/hciconfig hci0 up &> /dev/null &");
+               return;
+       }
+       system("/usr/sbin/hciconfig hci0 down &> /dev/null");
+}
+
+const char *bt_tunable::toggle_script(void)
+{
+       int good;
+       good = good_bad();
+
+       if (good == TUNE_GOOD) {
+               return toggle_bad;
+       }
+       return toggle_good;
+}
+
+
+void add_bt_tunable(void)
+{
+       struct hci_dev_info devinfo;
+       class bt_tunable *bt;
+       int fd;
+       int ret;
+
+       /* first check if /sys/modules/bluetooth exists, if not, don't probe bluetooth because
+          it would trigger an autoload */
+
+//     if (access("/sys/module/bluetooth",F_OK))
+//             return;
+
+
+       /* check if hci0 exists */
+       fd = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
+       if (fd < 0)
+               return;
+
+       memset(&devinfo, 0, sizeof(devinfo));
+       strcpy(devinfo.name, "hci0");
+       ret = ioctl(fd, HCIGETDEVINFO, (void *) &devinfo);
+       close(fd);
+       if (ret < 0)
+               return;
+
+
+       bt = new class bt_tunable();
+       all_tunables.push_back(bt);
+}
diff --git a/src/tuning/bluetooth.h b/src/tuning/bluetooth.h
new file mode 100644 (file)
index 0000000..ecb667d
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ *     Arjan van de Ven <arjan@linux.intel.com>
+ */
+#ifndef _INCLUDE_GUARD_BLUETOOTH_TUNE_H
+#define _INCLUDE_GUARD_BLUETOOTH_TUNE_H
+
+#include <vector>
+
+#include "tunable.h"
+
+using namespace std;
+
+class bt_tunable : public tunable {
+public:
+       bt_tunable(void);
+
+       virtual int good_bad(void);
+
+       virtual void toggle(void);
+
+       virtual const char *toggle_script(void);
+
+};
+
+extern void add_bt_tunable(void);
+
+
+#endif
diff --git a/src/tuning/cpufreq.cpp b/src/tuning/cpufreq.cpp
new file mode 100644 (file)
index 0000000..e870559
--- /dev/null
@@ -0,0 +1,213 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ *     Arjan van de Ven <arjan@linux.intel.com>
+ */
+
+#include "tuning.h"
+#include "tunable.h"
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <utility>
+#include <iostream>
+#include <fstream>
+#include <unistd.h>
+#include <dirent.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <ctype.h>
+
+#include "../lib.h"
+#include "cpufreq.h"
+
+cpufreq_tunable::cpufreq_tunable(void) : tunable("", 0.3, _("Good"), _("Bad"), _("Unknown"))
+{
+       string str;
+       sprintf(desc, _("Using 'ondemand' cpufreq governor"));
+
+       str = read_sysfs_string("/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor");
+       strcpy(original, str.c_str());
+       if (strlen(original) < 1)
+               strcpy(original, "ondemand");
+}
+
+
+int cpufreq_tunable::good_bad(void)
+{
+       DIR *dir;
+       struct dirent *dirent;
+       FILE *file;
+       char filename[PATH_MAX];
+       char line[1024];
+
+       char gov[1024];
+       int ret = TUNE_GOOD;
+
+
+       gov[0] = 0;
+
+
+       dir = opendir("/sys/devices/system/cpu");
+       if (!dir)
+               return ret;
+
+       while ((dirent = readdir(dir))) {
+               if (strncmp(dirent->d_name, "cpu", 3) != 0 || !isdigit(dirent->d_name[3]))
+                       continue;
+               sprintf(filename, "/sys/devices/system/cpu/%s/cpufreq/scaling_governor", dirent->d_name);
+               file = fopen(filename, "r");
+               if (!file)
+                       continue;
+               memset(line, 0, 1024);
+               if (fgets(line, 1023,file)==NULL) {
+                       fclose(file);
+                       continue;
+               }
+               if (strlen(gov)==0)
+                       strcpy(gov, line);
+               else
+                       /* if the governors are inconsistent, warn */
+                       if (strcmp(gov, line))
+                               ret = TUNE_BAD;
+               fclose(file);
+       }
+
+       closedir(dir);
+
+       /* if the governor is set to userspace, also warn */
+       if (strstr(gov, "userspace"))
+               ret = TUNE_BAD;
+
+       /* if the governor is set to performance, also warn */
+       /* FIXME: check if this is fair on all cpus */
+       if (strstr(gov, "performance"))
+               ret = TUNE_BAD;
+
+       return ret;
+}
+
+void cpufreq_tunable::toggle(void)
+{
+       DIR *dir;
+       struct dirent *dirent;
+       FILE *file;
+       char filename[PATH_MAX];
+       int good;
+       good = good_bad();
+
+       system("/sbin/modprobe cpufreq_ondemand > /dev/null 2>&1");
+
+       if (good == TUNE_GOOD) {
+               dir = opendir("/sys/devices/system/cpu");
+               if (!dir)
+                       return;
+
+               while ((dirent = readdir(dir))) {
+                       if (strncmp(dirent->d_name, "cpu", 3) != 0 || !isdigit(dirent->d_name[3]))
+                               continue;
+                       sprintf(filename, "/sys/devices/system/cpu/%s/cpufreq/scaling_governor", dirent->d_name);
+                       file = fopen(filename, "w");
+                       if (!file)
+                               continue;
+                       fprintf(file, "%s\n", original);
+                       fclose(file);
+               }
+
+               closedir(dir);
+               return;
+       }
+       dir = opendir("/sys/devices/system/cpu");
+       if (!dir)
+               return;
+
+       while ((dirent = readdir(dir))) {
+               if (strncmp(dirent->d_name, "cpu", 3) != 0 || !isdigit(dirent->d_name[3]))
+                       continue;
+               sprintf(filename, "/sys/devices/system/cpu/%s/cpufreq/scaling_governor", dirent->d_name);
+               file = fopen(filename, "w");
+               if (!file)
+                       continue;
+               fprintf(file, "ondemand\n");
+               fclose(file);
+       }
+
+       closedir(dir);
+}
+
+const char *cpufreq_tunable::toggle_script(void) {
+       DIR *dir;
+       struct dirent *dirent;
+       char filename[PATH_MAX];
+       char tmp[4096];
+       struct stat statbuf;
+       int good;
+       good = good_bad();
+
+       strcpy(toggle_good, "/sbin/modprobe cpufreq_ondemand > /dev/null 2>&1\n");
+
+       if (good == TUNE_GOOD) {
+               dir = opendir("/sys/devices/system/cpu");
+               if (!dir)
+                       return NULL;
+
+               while ((dirent = readdir(dir))) {
+                       if (strncmp(dirent->d_name, "cpu", 3) != 0 || !isdigit(dirent->d_name[3]))
+                               continue;
+                       sprintf(filename, "/sys/devices/system/cpu/%s/cpufreq/scaling_governor", dirent->d_name);
+                       if (stat(filename, &statbuf) == -1)
+                               continue;
+                       sprintf(tmp, "echo '%s' > '%s';\n", original, filename);
+                       strcat(toggle_good, tmp);
+               }
+
+               closedir(dir);
+               return toggle_good;
+       }
+
+       dir = opendir("/sys/devices/system/cpu");
+       if (!dir)
+               return NULL;
+
+       while ((dirent = readdir(dir))) {
+               if (strncmp(dirent->d_name, "cpu", 3) != 0 || !isdigit(dirent->d_name[3]))
+                       continue;
+               sprintf(filename, "/sys/devices/system/cpu/%s/cpufreq/scaling_governor", dirent->d_name);
+               if (stat(filename, &statbuf) == -1)
+                       continue;
+               sprintf(tmp, "echo 'ondemand' > '%s';\n", filename);
+               strcat(toggle_good, tmp);
+       }
+
+       closedir(dir);
+       return toggle_good;
+}
+
+
+void add_cpufreq_tunable(void)
+{
+       class cpufreq_tunable *cf;
+
+       cf = new class cpufreq_tunable();
+       all_tunables.push_back(cf);
+}
diff --git a/src/tuning/cpufreq.h b/src/tuning/cpufreq.h
new file mode 100644 (file)
index 0000000..983f813
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ *     Arjan van de Ven <arjan@linux.intel.com>
+ */
+#ifndef _INCLUDE_GUARD_CPUFREQ_TUNE_H
+#define _INCLUDE_GUARD_CPUFREQ_TUNE_H
+
+#include <vector>
+
+#include "tunable.h"
+
+using namespace std;
+
+class cpufreq_tunable : public tunable {
+       char original[4096];
+public:
+       cpufreq_tunable(void);
+
+       virtual int good_bad(void);
+
+       virtual void toggle(void);
+
+       virtual const char *toggle_script(void);
+
+};
+
+extern void add_cpufreq_tunable(void);
+
+
+#endif
diff --git a/src/tuning/ethernet.cpp b/src/tuning/ethernet.cpp
new file mode 100644 (file)
index 0000000..3164b31
--- /dev/null
@@ -0,0 +1,157 @@
+;/*
+ * Copyright 2010, Intel Corporation
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ *     Arjan van de Ven <arjan@linux.intel.com>
+ */
+
+#include "tuning.h"
+#include "tunable.h"
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <utility>
+#include <iostream>
+#include <fstream>
+#include <unistd.h>
+#include <dirent.h>
+#include <sys/socket.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <linux/types.h>
+#include <net/if.h>
+#include <linux/sockios.h>
+#include <sys/ioctl.h>
+
+#include <linux/ethtool.h>
+
+#include "../lib.h"
+#include "ethernet.h"
+
+extern void create_all_nics(callback fn);
+
+ethernet_tunable::ethernet_tunable(const char *iface) : tunable("", 0.3, _("Good"), _("Bad"), _("Unknown"))
+{
+       memset(interf, 0, sizeof(interf));
+       strncpy(interf, iface, sizeof(interf));
+       sprintf(desc, _("Wake-on-lan status for device %s"), iface);
+       sprintf(toggle_good, "ethtool -s %s wol d;", iface);
+
+}
+
+
+int ethernet_tunable::good_bad(void)
+{
+       int sock;
+       struct ifreq ifr;
+       struct ethtool_wolinfo wol;
+       int ret;
+       int result = TUNE_GOOD;
+
+       memset(&ifr, 0, sizeof(struct ifreq));
+
+       sock = socket(AF_INET, SOCK_DGRAM, 0);
+       if (sock<0)
+               return result;
+
+       strcpy(ifr.ifr_name, interf);
+
+       /* Check if the interf is up */
+       ret = ioctl(sock, SIOCGIFFLAGS, &ifr);
+       if (ret<0) {
+               close(sock);
+               return result;
+       }
+
+       memset(&wol, 0, sizeof(wol));
+
+       wol.cmd = ETHTOOL_GWOL;
+       ifr.ifr_data = (caddr_t)&wol;
+        ioctl(sock, SIOCETHTOOL, &ifr);
+
+       if (wol.wolopts)
+               result = TUNE_BAD;
+
+       close(sock);
+
+       return result;
+}
+
+void ethernet_tunable::toggle(void)
+{
+       int sock;
+       struct ifreq ifr;
+       struct ethtool_wolinfo wol;
+       int ret;
+
+       memset(&ifr, 0, sizeof(struct ifreq));
+
+       sock = socket(AF_INET, SOCK_DGRAM, 0);
+       if (sock<0)
+               return;
+
+       strcpy(ifr.ifr_name, interf);
+
+       /* Check if the interface is up */
+       ret = ioctl(sock, SIOCGIFFLAGS, &ifr);
+       if (ret<0) {
+               close(sock);
+               return;
+       }
+
+       memset(&wol, 0, sizeof(wol));
+
+       wol.cmd = ETHTOOL_GWOL;
+       ifr.ifr_data = (caddr_t)&wol;
+        ioctl(sock, SIOCETHTOOL, &ifr);
+       wol.cmd = ETHTOOL_SWOL;
+       wol.wolopts = 0;
+        ioctl(sock, SIOCETHTOOL, &ifr);
+
+       close(sock);
+}
+
+const char *ethernet_tunable::toggle_script(void)
+{
+       int good;
+       good = good_bad();
+
+       if (good != TUNE_GOOD) {
+               return toggle_good;
+       }
+
+       return NULL;
+}
+
+
+void ethtunable_callback(const char *d_name)
+{
+       class ethernet_tunable *eth = new(std::nothrow) class ethernet_tunable(d_name);
+       if (eth)
+               all_tunables.push_back(eth);
+}
+
+void add_ethernet_tunable(void)
+{
+       create_all_nics(&ethtunable_callback);
+}
diff --git a/src/tuning/ethernet.h b/src/tuning/ethernet.h
new file mode 100644 (file)
index 0000000..85810fb
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ *     Arjan van de Ven <arjan@linux.intel.com>
+ */
+#ifndef _INCLUDE_GUARD_ETHERNET_TUNE_H
+#define _INCLUDE_GUARD_ETHERNET_TUNE_H
+
+#include <vector>
+
+#include "tunable.h"
+
+using namespace std;
+
+class ethernet_tunable : public tunable {
+public:
+       char interf[4096];
+       ethernet_tunable(const char *iface);
+
+       virtual int good_bad(void);
+
+       virtual void toggle(void);
+
+       virtual const char *toggle_script(void);
+
+};
+
+extern void add_ethernet_tunable(void);
+
+#endif
diff --git a/src/tuning/iw.c b/src/tuning/iw.c
new file mode 100644 (file)
index 0000000..68eb6dc
--- /dev/null
@@ -0,0 +1,303 @@
+/*
+ * This code has been blatently stolen from
+ *
+ * nl80211 userspace tool
+ *
+ * Copyright 2007, 2008        Johannes Berg <johannes@sipsolutions.net>
+ *
+ * and has been stripped down to just the pieces needed.
+ */
+
+/*
+
+Copyright (c) 2007, 2008       Johannes Berg
+Copyright (c) 2007             Andy Lutomirski
+Copyright (c) 2007             Mike Kershaw
+Copyright (c) 2008-2009                Luis R. Rodriguez
+
+Permission to use, copy, modify, and/or distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+*/
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <net/if.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdbool.h>
+
+#include "nl80211.h"
+#include <netlink/genl/genl.h>
+#include <netlink/genl/family.h>
+#include <netlink/genl/ctrl.h>
+#include <netlink/msg.h>
+#include <netlink/attr.h>
+
+#include <asm/errno.h>
+#include <linux/genetlink.h>
+#include "iw.h"
+
+
+#ifndef HAVE_LIBNL20
+/* libnl 2.0 compatibility code */
+
+static inline struct nl_handle *nl_socket_alloc(void)
+{
+       return nl_handle_alloc();
+}
+
+static inline void nl_socket_free(struct nl_sock *h)
+{
+       nl_handle_destroy(h);
+}
+
+static inline int __genl_ctrl_alloc_cache(struct nl_sock *h, struct nl_cache **cache)
+{
+       struct nl_cache *tmp = genl_ctrl_alloc_cache(h);
+       if (!tmp)
+               return -ENOMEM;
+       *cache = tmp;
+       return 0;
+}
+#define genl_ctrl_alloc_cache __genl_ctrl_alloc_cache
+#endif /* HAVE_LIBNL20 */
+
+
+static int nl80211_init(struct nl80211_state *state)
+{
+       int err;
+
+       state->nl_sock = nl_socket_alloc();
+       if (!state->nl_sock) {
+               fprintf(stderr, "Failed to allocate netlink socket.\n");
+               return -ENOMEM;
+       }
+
+       if (genl_connect(state->nl_sock)) {
+               fprintf(stderr, "Failed to connect to generic netlink.\n");
+               err = -ENOLINK;
+               goto out_handle_destroy;
+       }
+
+       if (genl_ctrl_alloc_cache(state->nl_sock, &state->nl_cache)) {
+               fprintf(stderr, "Failed to allocate generic netlink cache.\n");
+               err = -ENOMEM;
+               goto out_handle_destroy;
+       }
+
+       state->nl80211 = genl_ctrl_search_by_name(state->nl_cache, "nl80211");
+       if (!state->nl80211) {
+               err = -ENOENT;
+               goto out_cache_free;
+       }
+
+       return 0;
+
+ out_cache_free:
+       nl_cache_free(state->nl_cache);
+ out_handle_destroy:
+       nl_socket_free(state->nl_sock);
+       return err;
+}
+
+static void nl80211_cleanup(struct nl80211_state *state)
+{
+       genl_family_put(state->nl80211);
+       nl_cache_free(state->nl_cache);
+       nl_socket_free(state->nl_sock);
+}
+
+static int enable_power_save;
+
+
+static int set_power_save(struct nl80211_state *state,
+                         struct nl_cb *cb,
+                         struct nl_msg *msg)
+{
+       enum nl80211_ps_state ps_state;
+
+       ps_state = NL80211_PS_DISABLED;
+       if (enable_power_save)
+               ps_state = NL80211_PS_ENABLED;
+
+       NLA_PUT_U32(msg, NL80211_ATTR_PS_STATE, ps_state);
+
+       return 0;
+
+ nla_put_failure:
+       return -ENOBUFS;
+}
+
+static int print_power_save_handler(struct nl_msg *msg, void *arg)
+{
+       struct nlattr *attrs[NL80211_ATTR_MAX + 1];
+       struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+
+       nla_parse(attrs, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+                 genlmsg_attrlen(gnlh, 0), NULL);
+
+       if (!attrs[NL80211_ATTR_PS_STATE])
+               return 0;
+
+       switch (nla_get_u32(attrs[NL80211_ATTR_PS_STATE])) {
+       case NL80211_PS_ENABLED:
+               enable_power_save = 1;
+               break;
+       case NL80211_PS_DISABLED:
+       default:
+               enable_power_save = 0;
+               break;
+       }
+
+       return NL_SKIP;
+}
+
+static int get_power_save(struct nl80211_state *state,
+                                  struct nl_cb *cb,
+                                  struct nl_msg *msg)
+{
+       nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM,
+                 print_power_save_handler, NULL);
+       return 0;
+}
+
+static int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err,
+                        void *arg)
+{
+       int *ret = arg;
+       *ret = err->error;
+       return NL_STOP;
+}
+
+static int finish_handler(struct nl_msg *msg, void *arg)
+{
+       int *ret = arg;
+       *ret = 0;
+       return NL_SKIP;
+}
+
+static int ack_handler(struct nl_msg *msg, void *arg)
+{
+       int *ret = arg;
+       *ret = 0;
+       return NL_STOP;
+}
+
+static int __handle_cmd(struct nl80211_state *state, const char *iface, int get)
+{
+       struct nl_cb *cb;
+       struct nl_msg *msg;
+       int devidx = 0;
+       int err;
+
+       devidx = if_nametoindex(iface);
+       if (devidx == 0)
+               devidx = -1;
+       if (devidx < 0)
+               return -errno;
+
+       msg = nlmsg_alloc();
+       if (!msg) {
+               fprintf(stderr, "failed to allocate netlink message\n");
+               return 2;
+       }
+
+       cb = nl_cb_alloc(NL_CB_DEFAULT);
+       if (!cb) {
+               fprintf(stderr, "failed to allocate netlink callbacks\n");
+               err = 2;
+               goto out_free_msg;
+       }
+
+       if (get)
+               genlmsg_put(msg, 0, 0, genl_family_get_id(state->nl80211), 0,
+                           0, NL80211_CMD_GET_POWER_SAVE, 0);
+       else
+               genlmsg_put(msg, 0, 0, genl_family_get_id(state->nl80211), 0,
+                           0, NL80211_CMD_SET_POWER_SAVE, 0);
+
+
+       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, devidx);
+
+       if (get)
+               err = get_power_save(state, cb, msg);
+       else
+               err = set_power_save(state, cb, msg);
+
+       if (err)
+               goto out;
+
+       err = nl_send_auto_complete(state->nl_sock, msg);
+       if (err < 0)
+               goto out;
+
+       err = 1;
+
+       nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &err);
+       nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &err);
+       nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &err);
+
+       while (err > 0)
+               nl_recvmsgs(state->nl_sock, cb);
+ out:
+       nl_cb_put(cb);
+ out_free_msg:
+       nlmsg_free(msg);
+       return err;
+ nla_put_failure:
+       fprintf(stderr, "building message failed\n");
+       return 2;
+}
+
+
+int set_wifi_power_saving(const char *iface, int state)
+{
+       struct nl80211_state nlstate;
+       int err;
+
+       err = nl80211_init(&nlstate);
+       if (err)
+               return 1;
+
+       enable_power_save = state;
+       err = __handle_cmd(&nlstate, iface, 0);
+
+       nl80211_cleanup(&nlstate);
+
+       return err;
+}
+
+
+int get_wifi_power_saving(const char *iface)
+{
+       struct nl80211_state nlstate;
+       int err;
+
+       enable_power_save = 0;
+
+       err = nl80211_init(&nlstate);
+       if (err)
+               return 1;
+
+       err = __handle_cmd(&nlstate, iface, 1);
+
+       nl80211_cleanup(&nlstate);
+
+       if (err) /* not a wifi interface */
+               return 1;
+
+       return enable_power_save;
+}
diff --git a/src/tuning/iw.h b/src/tuning/iw.h
new file mode 100644 (file)
index 0000000..6ea5a3d
--- /dev/null
@@ -0,0 +1,69 @@
+#ifndef __IW_H
+#define __IW_H
+
+/*
+ * This code has been blatently stolen from
+ *
+ * nl80211 userspace tool
+ *
+ * Copyright 2007, 2008        Johannes Berg <johannes@sipsolutions.net>
+ *
+ * and has been stripped down to just the pieces needed.
+ */
+
+/*
+
+Copyright (c) 2007, 2008       Johannes Berg
+Copyright (c) 2007             Andy Lutomirski
+Copyright (c) 2007             Mike Kershaw
+Copyright (c) 2008-2009                Luis R. Rodriguez
+
+Permission to use, copy, modify, and/or distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+*/
+
+#include <stdbool.h>
+
+#define ETH_ALEN 6
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifndef HAVE_LIBNL20
+#define nl_sock nl_handle
+#endif
+
+struct nl80211_state {
+       struct nl_sock *nl_sock;
+       struct nl_cache *nl_cache;
+       struct genl_family *nl80211;
+};
+
+enum command_identify_by {
+       CIB_NONE,
+       CIB_PHY,
+       CIB_NETDEV,
+};
+
+enum id_input {
+       II_NONE,
+       II_NETDEV,
+       II_PHY_NAME,
+       II_PHY_IDX,
+};
+
+int get_wifi_power_saving(const char *iface);
+int set_wifi_power_saving(const char *iface, int state);
+
+#endif /* __IW_H */
diff --git a/src/tuning/nl80211.h b/src/tuning/nl80211.h
new file mode 100644 (file)
index 0000000..e4a8839
--- /dev/null
@@ -0,0 +1,1897 @@
+#ifndef __LINUX_NL80211_H
+#define __LINUX_NL80211_H
+/*
+ * 802.11 netlink interface public header
+ *
+ * Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net>
+ * Copyright 2008 Michael Wu <flamingice@sourmilk.net>
+ * Copyright 2008 Luis Carlos Cobo <luisca@cozybit.com>
+ * Copyright 2008 Michael Buesch <mb@bu3sch.de>
+ * Copyright 2008, 2009 Luis R. Rodriguez <lrodriguez@atheros.com>
+ * Copyright 2008 Jouni Malinen <jouni.malinen@atheros.com>
+ * Copyright 2008 Colin McCabe <colin@cozybit.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include <linux/types.h>
+
+/**
+ * DOC: Station handling
+ *
+ * Stations are added per interface, but a special case exists with VLAN
+ * interfaces. When a station is bound to an AP interface, it may be moved
+ * into a VLAN identified by a VLAN interface index (%NL80211_ATTR_STA_VLAN).
+ * The station is still assumed to belong to the AP interface it was added
+ * to.
+ *
+ * TODO: need more info?
+ */
+
+/**
+ * DOC: Frame transmission/registration support
+ *
+ * Frame transmission and registration support exists to allow userspace
+ * management entities such as wpa_supplicant react to management frames
+ * that are not being handled by the kernel. This includes, for example,
+ * certain classes of action frames that cannot be handled in the kernel
+ * for various reasons.
+ *
+ * Frame registration is done on a per-interface basis and registrations
+ * cannot be removed other than by closing the socket. It is possible to
+ * specify a registration filter to register, for example, only for a
+ * certain type of action frame. In particular with action frames, those
+ * that userspace registers for will not be returned as unhandled by the
+ * driver, so that the registered application has to take responsibility
+ * for doing that.
+ *
+ * The type of frame that can be registered for is also dependent on the
+ * driver and interface type. The frame types are advertised in wiphy
+ * attributes so applications know what to expect.
+ *
+ * NOTE: When an interface changes type while registrations are active,
+ *       these registrations are ignored until the interface type is
+ *       changed again. This means that changing the interface type can
+ *       lead to a situation that couldn't otherwise be produced, but
+ *       any such registrations will be dormant in the sense that they
+ *       will not be serviced, i.e. they will not receive any frames.
+ *
+ * Frame transmission allows userspace to send for example the required
+ * responses to action frames. It is subject to some sanity checking,
+ * but many frames can be transmitted. When a frame was transmitted, its
+ * status is indicated to the sending socket.
+ *
+ * For more technical details, see the corresponding command descriptions
+ * below.
+ */
+
+/**
+ * enum nl80211_commands - supported nl80211 commands
+ *
+ * @NL80211_CMD_UNSPEC: unspecified command to catch errors
+ *
+ * @NL80211_CMD_GET_WIPHY: request information about a wiphy or dump request
+ *     to get a list of all present wiphys.
+ * @NL80211_CMD_SET_WIPHY: set wiphy parameters, needs %NL80211_ATTR_WIPHY or
+ *     %NL80211_ATTR_IFINDEX; can be used to set %NL80211_ATTR_WIPHY_NAME,
+ *     %NL80211_ATTR_WIPHY_TXQ_PARAMS, %NL80211_ATTR_WIPHY_FREQ,
+ *     %NL80211_ATTR_WIPHY_CHANNEL_TYPE, %NL80211_ATTR_WIPHY_RETRY_SHORT,
+ *     %NL80211_ATTR_WIPHY_RETRY_LONG, %NL80211_ATTR_WIPHY_FRAG_THRESHOLD,
+ *     and/or %NL80211_ATTR_WIPHY_RTS_THRESHOLD.
+ *     However, for setting the channel, see %NL80211_CMD_SET_CHANNEL
+ *     instead, the support here is for backward compatibility only.
+ * @NL80211_CMD_NEW_WIPHY: Newly created wiphy, response to get request
+ *     or rename notification. Has attributes %NL80211_ATTR_WIPHY and
+ *     %NL80211_ATTR_WIPHY_NAME.
+ * @NL80211_CMD_DEL_WIPHY: Wiphy deleted. Has attributes
+ *     %NL80211_ATTR_WIPHY and %NL80211_ATTR_WIPHY_NAME.
+ *
+ * @NL80211_CMD_GET_INTERFACE: Request an interface's configuration;
+ *     either a dump request on a %NL80211_ATTR_WIPHY or a specific get
+ *     on an %NL80211_ATTR_IFINDEX is supported.
+ * @NL80211_CMD_SET_INTERFACE: Set type of a virtual interface, requires
+ *     %NL80211_ATTR_IFINDEX and %NL80211_ATTR_IFTYPE.
+ * @NL80211_CMD_NEW_INTERFACE: Newly created virtual interface or response
+ *     to %NL80211_CMD_GET_INTERFACE. Has %NL80211_ATTR_IFINDEX,
+ *     %NL80211_ATTR_WIPHY and %NL80211_ATTR_IFTYPE attributes. Can also
+ *     be sent from userspace to request creation of a new virtual interface,
+ *     then requires attributes %NL80211_ATTR_WIPHY, %NL80211_ATTR_IFTYPE and
+ *     %NL80211_ATTR_IFNAME.
+ * @NL80211_CMD_DEL_INTERFACE: Virtual interface was deleted, has attributes
+ *     %NL80211_ATTR_IFINDEX and %NL80211_ATTR_WIPHY. Can also be sent from
+ *     userspace to request deletion of a virtual interface, then requires
+ *     attribute %NL80211_ATTR_IFINDEX.
+ *
+ * @NL80211_CMD_GET_KEY: Get sequence counter information for a key specified
+ *     by %NL80211_ATTR_KEY_IDX and/or %NL80211_ATTR_MAC.
+ * @NL80211_CMD_SET_KEY: Set key attributes %NL80211_ATTR_KEY_DEFAULT,
+ *     %NL80211_ATTR_KEY_DEFAULT_MGMT, or %NL80211_ATTR_KEY_THRESHOLD.
+ * @NL80211_CMD_NEW_KEY: add a key with given %NL80211_ATTR_KEY_DATA,
+ *     %NL80211_ATTR_KEY_IDX, %NL80211_ATTR_MAC, %NL80211_ATTR_KEY_CIPHER,
+ *     and %NL80211_ATTR_KEY_SEQ attributes.
+ * @NL80211_CMD_DEL_KEY: delete a key identified by %NL80211_ATTR_KEY_IDX
+ *     or %NL80211_ATTR_MAC.
+ *
+ * @NL80211_CMD_GET_BEACON: retrieve beacon information (returned in a
+ *     %NL80222_CMD_NEW_BEACON message)
+ * @NL80211_CMD_SET_BEACON: set the beacon on an access point interface
+ *     using the %NL80211_ATTR_BEACON_INTERVAL, %NL80211_ATTR_DTIM_PERIOD,
+ *     %NL80211_ATTR_BEACON_HEAD and %NL80211_ATTR_BEACON_TAIL attributes.
+ * @NL80211_CMD_NEW_BEACON: add a new beacon to an access point interface,
+ *     parameters are like for %NL80211_CMD_SET_BEACON.
+ * @NL80211_CMD_DEL_BEACON: remove the beacon, stop sending it
+ *
+ * @NL80211_CMD_GET_STATION: Get station attributes for station identified by
+ *     %NL80211_ATTR_MAC on the interface identified by %NL80211_ATTR_IFINDEX.
+ * @NL80211_CMD_SET_STATION: Set station attributes for station identified by
+ *     %NL80211_ATTR_MAC on the interface identified by %NL80211_ATTR_IFINDEX.
+ * @NL80211_CMD_NEW_STATION: Add a station with given attributes to the
+ *     the interface identified by %NL80211_ATTR_IFINDEX.
+ * @NL80211_CMD_DEL_STATION: Remove a station identified by %NL80211_ATTR_MAC
+ *     or, if no MAC address given, all stations, on the interface identified
+ *     by %NL80211_ATTR_IFINDEX.
+ *
+ * @NL80211_CMD_GET_MPATH: Get mesh path attributes for mesh path to
+ *     destination %NL80211_ATTR_MAC on the interface identified by
+ *     %NL80211_ATTR_IFINDEX.
+ * @NL80211_CMD_SET_MPATH:  Set mesh path attributes for mesh path to
+ *     destination %NL80211_ATTR_MAC on the interface identified by
+ *     %NL80211_ATTR_IFINDEX.
+ * @NL80211_CMD_NEW_PATH: Add a mesh path with given attributes to the
+ *     the interface identified by %NL80211_ATTR_IFINDEX.
+ * @NL80211_CMD_DEL_PATH: Remove a mesh path identified by %NL80211_ATTR_MAC
+ *     or, if no MAC address given, all mesh paths, on the interface identified
+ *     by %NL80211_ATTR_IFINDEX.
+ * @NL80211_CMD_SET_BSS: Set BSS attributes for BSS identified by
+ *     %NL80211_ATTR_IFINDEX.
+ *
+ * @NL80211_CMD_GET_REG: ask the wireless core to send us its currently set
+ *     regulatory domain.
+ * @NL80211_CMD_SET_REG: Set current regulatory domain. CRDA sends this command
+ *     after being queried by the kernel. CRDA replies by sending a regulatory
+ *     domain structure which consists of %NL80211_ATTR_REG_ALPHA set to our
+ *     current alpha2 if it found a match. It also provides
+ *     NL80211_ATTR_REG_RULE_FLAGS, and a set of regulatory rules. Each
+ *     regulatory rule is a nested set of attributes  given by
+ *     %NL80211_ATTR_REG_RULE_FREQ_[START|END] and
+ *     %NL80211_ATTR_FREQ_RANGE_MAX_BW with an attached power rule given by
+ *     %NL80211_ATTR_REG_RULE_POWER_MAX_ANT_GAIN and
+ *     %NL80211_ATTR_REG_RULE_POWER_MAX_EIRP.
+ * @NL80211_CMD_REQ_SET_REG: ask the wireless core to set the regulatory domain
+ *     to the specified ISO/IEC 3166-1 alpha2 country code. The core will
+ *     store this as a valid request and then query userspace for it.
+ *
+ * @NL80211_CMD_GET_MESH_PARAMS: Get mesh networking properties for the
+ *     interface identified by %NL80211_ATTR_IFINDEX
+ *
+ * @NL80211_CMD_SET_MESH_PARAMS: Set mesh networking properties for the
+ *      interface identified by %NL80211_ATTR_IFINDEX
+ *
+ * @NL80211_CMD_SET_MGMT_EXTRA_IE: Set extra IEs for management frames. The
+ *     interface is identified with %NL80211_ATTR_IFINDEX and the management
+ *     frame subtype with %NL80211_ATTR_MGMT_SUBTYPE. The extra IE data to be
+ *     added to the end of the specified management frame is specified with
+ *     %NL80211_ATTR_IE. If the command succeeds, the requested data will be
+ *     added to all specified management frames generated by
+ *     kernel/firmware/driver.
+ *     Note: This command has been removed and it is only reserved at this
+ *     point to avoid re-using existing command number. The functionality this
+ *     command was planned for has been provided with cleaner design with the
+ *     option to specify additional IEs in NL80211_CMD_TRIGGER_SCAN,
+ *     NL80211_CMD_AUTHENTICATE, NL80211_CMD_ASSOCIATE,
+ *     NL80211_CMD_DEAUTHENTICATE, and NL80211_CMD_DISASSOCIATE.
+ *
+ * @NL80211_CMD_GET_SCAN: get scan results
+ * @NL80211_CMD_TRIGGER_SCAN: trigger a new scan with the given parameters
+ * @NL80211_CMD_NEW_SCAN_RESULTS: scan notification (as a reply to
+ *     NL80211_CMD_GET_SCAN and on the "scan" multicast group)
+ * @NL80211_CMD_SCAN_ABORTED: scan was aborted, for unspecified reasons,
+ *     partial scan results may be available
+ *
+ * @NL80211_CMD_GET_SURVEY: get survey resuls, e.g. channel occupation
+ *      or noise level
+ * @NL80211_CMD_NEW_SURVEY_RESULTS: survey data notification (as a reply to
+ *     NL80211_CMD_GET_SURVEY and on the "scan" multicast group)
+ *
+ * @NL80211_CMD_REG_CHANGE: indicates to userspace the regulatory domain
+ *     has been changed and provides details of the request information
+ *     that caused the change such as who initiated the regulatory request
+ *     (%NL80211_ATTR_REG_INITIATOR), the wiphy_idx
+ *     (%NL80211_ATTR_REG_ALPHA2) on which the request was made from if
+ *     the initiator was %NL80211_REGDOM_SET_BY_COUNTRY_IE or
+ *     %NL80211_REGDOM_SET_BY_DRIVER, the type of regulatory domain
+ *     set (%NL80211_ATTR_REG_TYPE), if the type of regulatory domain is
+ *     %NL80211_REG_TYPE_COUNTRY the alpha2 to which we have moved on
+ *     to (%NL80211_ATTR_REG_ALPHA2).
+ * @NL80211_CMD_REG_BEACON_HINT: indicates to userspace that an AP beacon
+ *     has been found while world roaming thus enabling active scan or
+ *     any mode of operation that initiates TX (beacons) on a channel
+ *     where we would not have been able to do either before. As an example
+ *     if you are world roaming (regulatory domain set to world or if your
+ *     driver is using a custom world roaming regulatory domain) and while
+ *     doing a passive scan on the 5 GHz band you find an AP there (if not
+ *     on a DFS channel) you will now be able to actively scan for that AP
+ *     or use AP mode on your card on that same channel. Note that this will
+ *     never be used for channels 1-11 on the 2 GHz band as they are always
+ *     enabled world wide. This beacon hint is only sent if your device had
+ *     either disabled active scanning or beaconing on a channel. We send to
+ *     userspace the wiphy on which we removed a restriction from
+ *     (%NL80211_ATTR_WIPHY) and the channel on which this occurred
+ *     before (%NL80211_ATTR_FREQ_BEFORE) and after (%NL80211_ATTR_FREQ_AFTER)
+ *     the beacon hint was processed.
+ *
+ * @NL80211_CMD_AUTHENTICATE: authentication request and notification.
+ *     This command is used both as a command (request to authenticate) and
+ *     as an event on the "mlme" multicast group indicating completion of the
+ *     authentication process.
+ *     When used as a command, %NL80211_ATTR_IFINDEX is used to identify the
+ *     interface. %NL80211_ATTR_MAC is used to specify PeerSTAAddress (and
+ *     BSSID in case of station mode). %NL80211_ATTR_SSID is used to specify
+ *     the SSID (mainly for association, but is included in authentication
+ *     request, too, to help BSS selection. %NL80211_ATTR_WIPHY_FREQ is used
+ *     to specify the frequence of the channel in MHz. %NL80211_ATTR_AUTH_TYPE
+ *     is used to specify the authentication type. %NL80211_ATTR_IE is used to
+ *     define IEs (VendorSpecificInfo, but also including RSN IE and FT IEs)
+ *     to be added to the frame.
+ *     When used as an event, this reports reception of an Authentication
+ *     frame in station and IBSS modes when the local MLME processed the
+ *     frame, i.e., it was for the local STA and was received in correct
+ *     state. This is similar to MLME-AUTHENTICATE.confirm primitive in the
+ *     MLME SAP interface (kernel providing MLME, userspace SME). The
+ *     included %NL80211_ATTR_FRAME attribute contains the management frame
+ *     (including both the header and frame body, but not FCS). This event is
+ *     also used to indicate if the authentication attempt timed out. In that
+ *     case the %NL80211_ATTR_FRAME attribute is replaced with a
+ *     %NL80211_ATTR_TIMED_OUT flag (and %NL80211_ATTR_MAC to indicate which
+ *     pending authentication timed out).
+ * @NL80211_CMD_ASSOCIATE: association request and notification; like
+ *     NL80211_CMD_AUTHENTICATE but for Association and Reassociation
+ *     (similar to MLME-ASSOCIATE.request, MLME-REASSOCIATE.request,
+ *     MLME-ASSOCIATE.confirm or MLME-REASSOCIATE.confirm primitives).
+ * @NL80211_CMD_DEAUTHENTICATE: deauthentication request and notification; like
+ *     NL80211_CMD_AUTHENTICATE but for Deauthentication frames (similar to
+ *     MLME-DEAUTHENTICATION.request and MLME-DEAUTHENTICATE.indication
+ *     primitives).
+ * @NL80211_CMD_DISASSOCIATE: disassociation request and notification; like
+ *     NL80211_CMD_AUTHENTICATE but for Disassociation frames (similar to
+ *     MLME-DISASSOCIATE.request and MLME-DISASSOCIATE.indication primitives).
+ *
+ * @NL80211_CMD_MICHAEL_MIC_FAILURE: notification of a locally detected Michael
+ *     MIC (part of TKIP) failure; sent on the "mlme" multicast group; the
+ *     event includes %NL80211_ATTR_MAC to describe the source MAC address of
+ *     the frame with invalid MIC, %NL80211_ATTR_KEY_TYPE to show the key
+ *     type, %NL80211_ATTR_KEY_IDX to indicate the key identifier, and
+ *     %NL80211_ATTR_KEY_SEQ to indicate the TSC value of the frame; this
+ *     event matches with MLME-MICHAELMICFAILURE.indication() primitive
+ *
+ * @NL80211_CMD_JOIN_IBSS: Join a new IBSS -- given at least an SSID and a
+ *     FREQ attribute (for the initial frequency if no peer can be found)
+ *     and optionally a MAC (as BSSID) and FREQ_FIXED attribute if those
+ *     should be fixed rather than automatically determined. Can only be
+ *     executed on a network interface that is UP, and fixed BSSID/FREQ
+ *     may be rejected. Another optional parameter is the beacon interval,
+ *     given in the %NL80211_ATTR_BEACON_INTERVAL attribute, which if not
+ *     given defaults to 100 TU (102.4ms).
+ * @NL80211_CMD_LEAVE_IBSS: Leave the IBSS -- no special arguments, the IBSS is
+ *     determined by the network interface.
+ *
+ * @NL80211_CMD_TESTMODE: testmode command, takes a wiphy (or ifindex) attribute
+ *     to identify the device, and the TESTDATA blob attribute to pass through
+ *     to the driver.
+ *
+ * @NL80211_CMD_CONNECT: connection request and notification; this command
+ *     requests to connect to a specified network but without separating
+ *     auth and assoc steps. For this, you need to specify the SSID in a
+ *     %NL80211_ATTR_SSID attribute, and can optionally specify the association
+ *     IEs in %NL80211_ATTR_IE, %NL80211_ATTR_AUTH_TYPE, %NL80211_ATTR_MAC,
+ *     %NL80211_ATTR_WIPHY_FREQ, %NL80211_ATTR_CONTROL_PORT,
+ *     %NL80211_ATTR_CONTROL_PORT_ETHERTYPE and
+ *     %NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT.
+ *     It is also sent as an event, with the BSSID and response IEs when the
+ *     connection is established or failed to be established. This can be
+ *     determined by the STATUS_CODE attribute.
+ * @NL80211_CMD_ROAM: request that the card roam (currently not implemented),
+ *     sent as an event when the card/driver roamed by itself.
+ * @NL80211_CMD_DISCONNECT: drop a given connection; also used to notify
+ *     userspace that a connection was dropped by the AP or due to other
+ *     reasons, for this the %NL80211_ATTR_DISCONNECTED_BY_AP and
+ *     %NL80211_ATTR_REASON_CODE attributes are used.
+ *
+ * @NL80211_CMD_SET_WIPHY_NETNS: Set a wiphy's netns. Note that all devices
+ *     associated with this wiphy must be down and will follow.
+ *
+ * @NL80211_CMD_REMAIN_ON_CHANNEL: Request to remain awake on the specified
+ *     channel for the specified amount of time. This can be used to do
+ *     off-channel operations like transmit a Public Action frame and wait for
+ *     a response while being associated to an AP on another channel.
+ *     %NL80211_ATTR_IFINDEX is used to specify which interface (and thus
+ *     radio) is used. %NL80211_ATTR_WIPHY_FREQ is used to specify the
+ *     frequency for the operation and %NL80211_ATTR_WIPHY_CHANNEL_TYPE may be
+ *     optionally used to specify additional channel parameters.
+ *     %NL80211_ATTR_DURATION is used to specify the duration in milliseconds
+ *     to remain on the channel. This command is also used as an event to
+ *     notify when the requested duration starts (it may take a while for the
+ *     driver to schedule this time due to other concurrent needs for the
+ *     radio).
+ *     When called, this operation returns a cookie (%NL80211_ATTR_COOKIE)
+ *     that will be included with any events pertaining to this request;
+ *     the cookie is also used to cancel the request.
+ * @NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL: This command can be used to cancel a
+ *     pending remain-on-channel duration if the desired operation has been
+ *     completed prior to expiration of the originally requested duration.
+ *     %NL80211_ATTR_WIPHY or %NL80211_ATTR_IFINDEX is used to specify the
+ *     radio. The %NL80211_ATTR_COOKIE attribute must be given as well to
+ *     uniquely identify the request.
+ *     This command is also used as an event to notify when a requested
+ *     remain-on-channel duration has expired.
+ *
+ * @NL80211_CMD_SET_TX_BITRATE_MASK: Set the mask of rates to be used in TX
+ *     rate selection. %NL80211_ATTR_IFINDEX is used to specify the interface
+ *     and @NL80211_ATTR_TX_RATES the set of allowed rates.
+ *
+ * @NL80211_CMD_REGISTER_FRAME: Register for receiving certain mgmt frames
+ *     (via @NL80211_CMD_FRAME) for processing in userspace. This command
+ *     requires an interface index, a frame type attribute (optional for
+ *     backward compatibility reasons, if not given assumes action frames)
+ *     and a match attribute containing the first few bytes of the frame
+ *     that should match, e.g. a single byte for only a category match or
+ *     four bytes for vendor frames including the OUI. The registration
+ *     cannot be dropped, but is removed automatically when the netlink
+ *     socket is closed. Multiple registrations can be made.
+ * @NL80211_CMD_REGISTER_ACTION: Alias for @NL80211_CMD_REGISTER_FRAME for
+ *     backward compatibility
+ * @NL80211_CMD_FRAME: Management frame TX request and RX notification. This
+ *     command is used both as a request to transmit a management frame and
+ *     as an event indicating reception of a frame that was not processed in
+ *     kernel code, but is for us (i.e., which may need to be processed in a
+ *     user space application). %NL80211_ATTR_FRAME is used to specify the
+ *     frame contents (including header). %NL80211_ATTR_WIPHY_FREQ (and
+ *     optionally %NL80211_ATTR_WIPHY_CHANNEL_TYPE) is used to indicate on
+ *     which channel the frame is to be transmitted or was received. If this
+ *     channel is not the current channel (remain-on-channel or the
+ *     operational channel) the device will switch to the given channel and
+ *     transmit the frame, optionally waiting for a response for the time
+ *     specified using %NL80211_ATTR_DURATION. When called, this operation
+ *     returns a cookie (%NL80211_ATTR_COOKIE) that will be included with the
+ *     TX status event pertaining to the TX request.
+ * @NL80211_CMD_FRAME_WAIT_CANCEL: When an off-channel TX was requested, this
+ *     command may be used with the corresponding cookie to cancel the wait
+ *     time if it is known that it is no longer necessary.
+ * @NL80211_CMD_ACTION: Alias for @NL80211_CMD_FRAME for backward compatibility.
+ * @NL80211_CMD_FRAME_TX_STATUS: Report TX status of a management frame
+ *     transmitted with %NL80211_CMD_FRAME. %NL80211_ATTR_COOKIE identifies
+ *     the TX command and %NL80211_ATTR_FRAME includes the contents of the
+ *     frame. %NL80211_ATTR_ACK flag is included if the recipient acknowledged
+ *     the frame.
+ * @NL80211_CMD_ACTION_TX_STATUS: Alias for @NL80211_CMD_FRAME_TX_STATUS for
+ *     backward compatibility.
+ * @NL80211_CMD_SET_CQM: Connection quality monitor configuration. This command
+ *     is used to configure connection quality monitoring notification trigger
+ *     levels.
+ * @NL80211_CMD_NOTIFY_CQM: Connection quality monitor notification. This
+ *     command is used as an event to indicate the that a trigger level was
+ *     reached.
+ * @NL80211_CMD_SET_CHANNEL: Set the channel (using %NL80211_ATTR_WIPHY_FREQ
+ *     and %NL80211_ATTR_WIPHY_CHANNEL_TYPE) the given interface (identifed
+ *     by %NL80211_ATTR_IFINDEX) shall operate on.
+ *     In case multiple channels are supported by the device, the mechanism
+ *     with which it switches channels is implementation-defined.
+ *     When a monitor interface is given, it can only switch channel while
+ *     no other interfaces are operating to avoid disturbing the operation
+ *     of any other interfaces, and other interfaces will again take
+ *     precedence when they are used.
+ *
+ * @NL80211_CMD_SET_WDS_PEER: Set the MAC address of the peer on a WDS interface.
+ *
+ * @NL80211_CMD_JOIN_MESH: Join a mesh. The mesh ID must be given, and initial
+ *     mesh config parameters may be given.
+ * @NL80211_CMD_LEAVE_MESH: Leave the mesh network -- no special arguments, the
+ *     network is determined by the network interface.
+ *
+ * @NL80211_CMD_MAX: highest used command number
+ * @__NL80211_CMD_AFTER_LAST: internal use
+ */
+enum nl80211_commands {
+/* don't change the order or add anything inbetween, this is ABI! */
+       NL80211_CMD_UNSPEC,
+
+       NL80211_CMD_GET_WIPHY,          /* can dump */
+       NL80211_CMD_SET_WIPHY,
+       NL80211_CMD_NEW_WIPHY,
+       NL80211_CMD_DEL_WIPHY,
+
+       NL80211_CMD_GET_INTERFACE,      /* can dump */
+       NL80211_CMD_SET_INTERFACE,
+       NL80211_CMD_NEW_INTERFACE,
+       NL80211_CMD_DEL_INTERFACE,
+
+       NL80211_CMD_GET_KEY,
+       NL80211_CMD_SET_KEY,
+       NL80211_CMD_NEW_KEY,
+       NL80211_CMD_DEL_KEY,
+
+       NL80211_CMD_GET_BEACON,
+       NL80211_CMD_SET_BEACON,
+       NL80211_CMD_NEW_BEACON,
+       NL80211_CMD_DEL_BEACON,
+
+       NL80211_CMD_GET_STATION,
+       NL80211_CMD_SET_STATION,
+       NL80211_CMD_NEW_STATION,
+       NL80211_CMD_DEL_STATION,
+
+       NL80211_CMD_GET_MPATH,
+       NL80211_CMD_SET_MPATH,
+       NL80211_CMD_NEW_MPATH,
+       NL80211_CMD_DEL_MPATH,
+
+       NL80211_CMD_SET_BSS,
+
+       NL80211_CMD_SET_REG,
+       NL80211_CMD_REQ_SET_REG,
+
+       NL80211_CMD_GET_MESH_PARAMS,
+       NL80211_CMD_SET_MESH_PARAMS,
+
+       NL80211_CMD_SET_MGMT_EXTRA_IE /* reserved; not used */,
+
+       NL80211_CMD_GET_REG,
+
+       NL80211_CMD_GET_SCAN,
+       NL80211_CMD_TRIGGER_SCAN,
+       NL80211_CMD_NEW_SCAN_RESULTS,
+       NL80211_CMD_SCAN_ABORTED,
+
+       NL80211_CMD_REG_CHANGE,
+
+       NL80211_CMD_AUTHENTICATE,
+       NL80211_CMD_ASSOCIATE,
+       NL80211_CMD_DEAUTHENTICATE,
+       NL80211_CMD_DISASSOCIATE,
+
+       NL80211_CMD_MICHAEL_MIC_FAILURE,
+
+       NL80211_CMD_REG_BEACON_HINT,
+
+       NL80211_CMD_JOIN_IBSS,
+       NL80211_CMD_LEAVE_IBSS,
+
+       NL80211_CMD_TESTMODE,
+
+       NL80211_CMD_CONNECT,
+       NL80211_CMD_ROAM,
+       NL80211_CMD_DISCONNECT,
+
+       NL80211_CMD_SET_WIPHY_NETNS,
+
+       NL80211_CMD_GET_SURVEY,
+       NL80211_CMD_NEW_SURVEY_RESULTS,
+
+       NL80211_CMD_SET_PMKSA,
+       NL80211_CMD_DEL_PMKSA,
+       NL80211_CMD_FLUSH_PMKSA,
+
+       NL80211_CMD_REMAIN_ON_CHANNEL,
+       NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL,
+
+       NL80211_CMD_SET_TX_BITRATE_MASK,
+
+       NL80211_CMD_REGISTER_FRAME,
+       NL80211_CMD_REGISTER_ACTION = NL80211_CMD_REGISTER_FRAME,
+       NL80211_CMD_FRAME,
+       NL80211_CMD_ACTION = NL80211_CMD_FRAME,
+       NL80211_CMD_FRAME_TX_STATUS,
+       NL80211_CMD_ACTION_TX_STATUS = NL80211_CMD_FRAME_TX_STATUS,
+
+       NL80211_CMD_SET_POWER_SAVE,
+       NL80211_CMD_GET_POWER_SAVE,
+
+       NL80211_CMD_SET_CQM,
+       NL80211_CMD_NOTIFY_CQM,
+
+       NL80211_CMD_SET_CHANNEL,
+       NL80211_CMD_SET_WDS_PEER,
+
+       NL80211_CMD_FRAME_WAIT_CANCEL,
+
+       NL80211_CMD_JOIN_MESH,
+       NL80211_CMD_LEAVE_MESH,
+
+       /* add new commands above here */
+
+       /* used to define NL80211_CMD_MAX below */
+       __NL80211_CMD_AFTER_LAST,
+       NL80211_CMD_MAX = __NL80211_CMD_AFTER_LAST - 1
+};
+
+/*
+ * Allow user space programs to use #ifdef on new commands by defining them
+ * here
+ */
+#define NL80211_CMD_SET_BSS NL80211_CMD_SET_BSS
+#define NL80211_CMD_SET_MGMT_EXTRA_IE NL80211_CMD_SET_MGMT_EXTRA_IE
+#define NL80211_CMD_REG_CHANGE NL80211_CMD_REG_CHANGE
+#define NL80211_CMD_AUTHENTICATE NL80211_CMD_AUTHENTICATE
+#define NL80211_CMD_ASSOCIATE NL80211_CMD_ASSOCIATE
+#define NL80211_CMD_DEAUTHENTICATE NL80211_CMD_DEAUTHENTICATE
+#define NL80211_CMD_DISASSOCIATE NL80211_CMD_DISASSOCIATE
+#define NL80211_CMD_REG_BEACON_HINT NL80211_CMD_REG_BEACON_HINT
+
+/**
+ * enum nl80211_attrs - nl80211 netlink attributes
+ *
+ * @NL80211_ATTR_UNSPEC: unspecified attribute to catch errors
+ *
+ * @NL80211_ATTR_WIPHY: index of wiphy to operate on, cf.
+ *     /sys/class/ieee80211/<phyname>/index
+ * @NL80211_ATTR_WIPHY_NAME: wiphy name (used for renaming)
+ * @NL80211_ATTR_WIPHY_TXQ_PARAMS: a nested array of TX queue parameters
+ * @NL80211_ATTR_WIPHY_FREQ: frequency of the selected channel in MHz
+ * @NL80211_ATTR_WIPHY_CHANNEL_TYPE: included with NL80211_ATTR_WIPHY_FREQ
+ *     if HT20 or HT40 are allowed (i.e., 802.11n disabled if not included):
+ *     NL80211_CHAN_NO_HT = HT not allowed (i.e., same as not including
+ *             this attribute)
+ *     NL80211_CHAN_HT20 = HT20 only
+ *     NL80211_CHAN_HT40MINUS = secondary channel is below the primary channel
+ *     NL80211_CHAN_HT40PLUS = secondary channel is above the primary channel
+ * @NL80211_ATTR_WIPHY_RETRY_SHORT: TX retry limit for frames whose length is
+ *     less than or equal to the RTS threshold; allowed range: 1..255;
+ *     dot11ShortRetryLimit; u8
+ * @NL80211_ATTR_WIPHY_RETRY_LONG: TX retry limit for frames whose length is
+ *     greater than the RTS threshold; allowed range: 1..255;
+ *     dot11ShortLongLimit; u8
+ * @NL80211_ATTR_WIPHY_FRAG_THRESHOLD: fragmentation threshold, i.e., maximum
+ *     length in octets for frames; allowed range: 256..8000, disable
+ *     fragmentation with (u32)-1; dot11FragmentationThreshold; u32
+ * @NL80211_ATTR_WIPHY_RTS_THRESHOLD: RTS threshold (TX frames with length
+ *     larger than or equal to this use RTS/CTS handshake); allowed range:
+ *     0..65536, disable with (u32)-1; dot11RTSThreshold; u32
+ * @NL80211_ATTR_WIPHY_COVERAGE_CLASS: Coverage Class as defined by IEEE 802.11
+ *     section 7.3.2.9; dot11CoverageClass; u8
+ *
+ * @NL80211_ATTR_IFINDEX: network interface index of the device to operate on
+ * @NL80211_ATTR_IFNAME: network interface name
+ * @NL80211_ATTR_IFTYPE: type of virtual interface, see &enum nl80211_iftype
+ *
+ * @NL80211_ATTR_MAC: MAC address (various uses)
+ *
+ * @NL80211_ATTR_KEY_DATA: (temporal) key data; for TKIP this consists of
+ *     16 bytes encryption key followed by 8 bytes each for TX and RX MIC
+ *     keys
+ * @NL80211_ATTR_KEY_IDX: key ID (u8, 0-3)
+ * @NL80211_ATTR_KEY_CIPHER: key cipher suite (u32, as defined by IEEE 802.11
+ *     section 7.3.2.25.1, e.g. 0x000FAC04)
+ * @NL80211_ATTR_KEY_SEQ: transmit key sequence number (IV/PN) for TKIP and
+ *     CCMP keys, each six bytes in little endian
+ *
+ * @NL80211_ATTR_BEACON_INTERVAL: beacon interval in TU
+ * @NL80211_ATTR_DTIM_PERIOD: DTIM period for beaconing
+ * @NL80211_ATTR_BEACON_HEAD: portion of the beacon before the TIM IE
+ * @NL80211_ATTR_BEACON_TAIL: portion of the beacon after the TIM IE
+ *
+ * @NL80211_ATTR_STA_AID: Association ID for the station (u16)
+ * @NL80211_ATTR_STA_FLAGS: flags, nested element with NLA_FLAG attributes of
+ *     &enum nl80211_sta_flags (deprecated, use %NL80211_ATTR_STA_FLAGS2)
+ * @NL80211_ATTR_STA_LISTEN_INTERVAL: listen interval as defined by
+ *     IEEE 802.11 7.3.1.6 (u16).
+ * @NL80211_ATTR_STA_SUPPORTED_RATES: supported rates, array of supported
+ *     rates as defined by IEEE 802.11 7.3.2.2 but without the length
+ *     restriction (at most %NL80211_MAX_SUPP_RATES).
+ * @NL80211_ATTR_STA_VLAN: interface index of VLAN interface to move station
+ *     to, or the AP interface the station was originally added to to.
+ * @NL80211_ATTR_STA_INFO: information about a station, part of station info
+ *     given for %NL80211_CMD_GET_STATION, nested attribute containing
+ *     info as possible, see &enum nl80211_sta_info.
+ *
+ * @NL80211_ATTR_WIPHY_BANDS: Information about an operating bands,
+ *     consisting of a nested array.
+ *
+ * @NL80211_ATTR_MESH_ID: mesh id (1-32 bytes).
+ * @NL80211_ATTR_PLINK_ACTION: action to perform on the mesh peer link.
+ * @NL80211_ATTR_MPATH_NEXT_HOP: MAC address of the next hop for a mesh path.
+ * @NL80211_ATTR_MPATH_INFO: information about a mesh_path, part of mesh path
+ *     info given for %NL80211_CMD_GET_MPATH, nested attribute described at
+ *     &enum nl80211_mpath_info.
+ *
+ * @NL80211_ATTR_MNTR_FLAGS: flags, nested element with NLA_FLAG attributes of
+ *      &enum nl80211_mntr_flags.
+ *
+ * @NL80211_ATTR_REG_ALPHA2: an ISO-3166-alpha2 country code for which the
+ *     current regulatory domain should be set to or is already set to.
+ *     For example, 'CR', for Costa Rica. This attribute is used by the kernel
+ *     to query the CRDA to retrieve one regulatory domain. This attribute can
+ *     also be used by userspace to query the kernel for the currently set
+ *     regulatory domain. We chose an alpha2 as that is also used by the
+ *     IEEE-802.11d country information element to identify a country.
+ *     Users can also simply ask the wireless core to set regulatory domain
+ *     to a specific alpha2.
+ * @NL80211_ATTR_REG_RULES: a nested array of regulatory domain regulatory
+ *     rules.
+ *
+ * @NL80211_ATTR_BSS_CTS_PROT: whether CTS protection is enabled (u8, 0 or 1)
+ * @NL80211_ATTR_BSS_SHORT_PREAMBLE: whether short preamble is enabled
+ *     (u8, 0 or 1)
+ * @NL80211_ATTR_BSS_SHORT_SLOT_TIME: whether short slot time enabled
+ *     (u8, 0 or 1)
+ * @NL80211_ATTR_BSS_BASIC_RATES: basic rates, array of basic
+ *     rates in format defined by IEEE 802.11 7.3.2.2 but without the length
+ *     restriction (at most %NL80211_MAX_SUPP_RATES).
+ *
+ * @NL80211_ATTR_HT_CAPABILITY: HT Capability information element (from
+ *     association request when used with NL80211_CMD_NEW_STATION)
+ *
+ * @NL80211_ATTR_SUPPORTED_IFTYPES: nested attribute containing all
+ *     supported interface types, each a flag attribute with the number
+ *     of the interface mode.
+ *
+ * @NL80211_ATTR_MGMT_SUBTYPE: Management frame subtype for
+ *     %NL80211_CMD_SET_MGMT_EXTRA_IE.
+ *
+ * @NL80211_ATTR_IE: Information element(s) data (used, e.g., with
+ *     %NL80211_CMD_SET_MGMT_EXTRA_IE).
+ *
+ * @NL80211_ATTR_MAX_NUM_SCAN_SSIDS: number of SSIDs you can scan with
+ *     a single scan request, a wiphy attribute.
+ * @NL80211_ATTR_MAX_SCAN_IE_LEN: maximum length of information elements
+ *     that can be added to a scan request
+ *
+ * @NL80211_ATTR_SCAN_FREQUENCIES: nested attribute with frequencies (in MHz)
+ * @NL80211_ATTR_SCAN_SSIDS: nested attribute with SSIDs, leave out for passive
+ *     scanning and include a zero-length SSID (wildcard) for wildcard scan
+ * @NL80211_ATTR_BSS: scan result BSS
+ *
+ * @NL80211_ATTR_REG_INITIATOR: indicates who requested the regulatory domain
+ *     currently in effect. This could be any of the %NL80211_REGDOM_SET_BY_*
+ * @NL80211_ATTR_REG_TYPE: indicates the type of the regulatory domain currently
+ *     set. This can be one of the nl80211_reg_type (%NL80211_REGDOM_TYPE_*)
+ *
+ * @NL80211_ATTR_SUPPORTED_COMMANDS: wiphy attribute that specifies
+ *     an array of command numbers (i.e. a mapping index to command number)
+ *     that the driver for the given wiphy supports.
+ *
+ * @NL80211_ATTR_FRAME: frame data (binary attribute), including frame header
+ *     and body, but not FCS; used, e.g., with NL80211_CMD_AUTHENTICATE and
+ *     NL80211_CMD_ASSOCIATE events
+ * @NL80211_ATTR_SSID: SSID (binary attribute, 0..32 octets)
+ * @NL80211_ATTR_AUTH_TYPE: AuthenticationType, see &enum nl80211_auth_type,
+ *     represented as a u32
+ * @NL80211_ATTR_REASON_CODE: ReasonCode for %NL80211_CMD_DEAUTHENTICATE and
+ *     %NL80211_CMD_DISASSOCIATE, u16
+ *
+ * @NL80211_ATTR_KEY_TYPE: Key Type, see &enum nl80211_key_type, represented as
+ *     a u32
+ *
+ * @NL80211_ATTR_FREQ_BEFORE: A channel which has suffered a regulatory change
+ *     due to considerations from a beacon hint. This attribute reflects
+ *     the state of the channel _before_ the beacon hint processing. This
+ *     attributes consists of a nested attribute containing
+ *     NL80211_FREQUENCY_ATTR_*
+ * @NL80211_ATTR_FREQ_AFTER: A channel which has suffered a regulatory change
+ *     due to considerations from a beacon hint. This attribute reflects
+ *     the state of the channel _after_ the beacon hint processing. This
+ *     attributes consists of a nested attribute containing
+ *     NL80211_FREQUENCY_ATTR_*
+ *
+ * @NL80211_ATTR_CIPHER_SUITES: a set of u32 values indicating the supported
+ *     cipher suites
+ *
+ * @NL80211_ATTR_FREQ_FIXED: a flag indicating the IBSS should not try to look
+ *     for other networks on different channels
+ *
+ * @NL80211_ATTR_TIMED_OUT: a flag indicating than an operation timed out; this
+ *     is used, e.g., with %NL80211_CMD_AUTHENTICATE event
+ *
+ * @NL80211_ATTR_USE_MFP: Whether management frame protection (IEEE 802.11w) is
+ *     used for the association (&enum nl80211_mfp, represented as a u32);
+ *     this attribute can be used
+ *     with %NL80211_CMD_ASSOCIATE request
+ *
+ * @NL80211_ATTR_STA_FLAGS2: Attribute containing a
+ *     &struct nl80211_sta_flag_update.
+ *
+ * @NL80211_ATTR_CONTROL_PORT: A flag indicating whether user space controls
+ *     IEEE 802.1X port, i.e., sets/clears %NL80211_STA_FLAG_AUTHORIZED, in
+ *     station mode. If the flag is included in %NL80211_CMD_ASSOCIATE
+ *     request, the driver will assume that the port is unauthorized until
+ *     authorized by user space. Otherwise, port is marked authorized by
+ *     default in station mode.
+ * @NL80211_ATTR_CONTROL_PORT_ETHERTYPE: A 16-bit value indicating the
+ *     ethertype that will be used for key negotiation. It can be
+ *     specified with the associate and connect commands. If it is not
+ *     specified, the value defaults to 0x888E (PAE, 802.1X). This
+ *     attribute is also used as a flag in the wiphy information to
+ *     indicate that protocols other than PAE are supported.
+ * @NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT: When included along with
+ *     %NL80211_ATTR_CONTROL_PORT_ETHERTYPE, indicates that the custom
+ *     ethertype frames used for key negotiation must not be encrypted.
+ *
+ * @NL80211_ATTR_TESTDATA: Testmode data blob, passed through to the driver.
+ *     We recommend using nested, driver-specific attributes within this.
+ *
+ * @NL80211_ATTR_DISCONNECTED_BY_AP: A flag indicating that the DISCONNECT
+ *     event was due to the AP disconnecting the station, and not due to
+ *     a local disconnect request.
+ * @NL80211_ATTR_STATUS_CODE: StatusCode for the %NL80211_CMD_CONNECT
+ *     event (u16)
+ * @NL80211_ATTR_PRIVACY: Flag attribute, used with connect(), indicating
+ *     that protected APs should be used.
+ *
+ * @NL80211_ATTR_CIPHERS_PAIRWISE: Used with CONNECT and ASSOCIATE to
+ *     indicate which unicast key ciphers will be used with the connection
+ *     (an array of u32).
+ * @NL80211_ATTR_CIPHER_GROUP: Used with CONNECT and ASSOCIATE to indicate
+ *     which group key cipher will be used with the connection (a u32).
+ * @NL80211_ATTR_WPA_VERSIONS: Used with CONNECT and ASSOCIATE to indicate
+ *     which WPA version(s) the AP we want to associate with is using
+ *     (a u32 with flags from &enum nl80211_wpa_versions).
+ * @NL80211_ATTR_AKM_SUITES: Used with CONNECT and ASSOCIATE to indicate
+ *     which key management algorithm(s) to use (an array of u32).
+ *
+ * @NL80211_ATTR_REQ_IE: (Re)association request information elements as
+ *     sent out by the card, for ROAM and successful CONNECT events.
+ * @NL80211_ATTR_RESP_IE: (Re)association response information elements as
+ *     sent by peer, for ROAM and successful CONNECT events.
+ *
+ * @NL80211_ATTR_PREV_BSSID: previous BSSID, to be used by in ASSOCIATE
+ *     commands to specify using a reassociate frame
+ *
+ * @NL80211_ATTR_KEY: key information in a nested attribute with
+ *     %NL80211_KEY_* sub-attributes
+ * @NL80211_ATTR_KEYS: array of keys for static WEP keys for connect()
+ *     and join_ibss(), key information is in a nested attribute each
+ *     with %NL80211_KEY_* sub-attributes
+ *
+ * @NL80211_ATTR_PID: Process ID of a network namespace.
+ *
+ * @NL80211_ATTR_GENERATION: Used to indicate consistent snapshots for
+ *     dumps. This number increases whenever the object list being
+ *     dumped changes, and as such userspace can verify that it has
+ *     obtained a complete and consistent snapshot by verifying that
+ *     all dump messages contain the same generation number. If it
+ *     changed then the list changed and the dump should be repeated
+ *     completely from scratch.
+ *
+ * @NL80211_ATTR_4ADDR: Use 4-address frames on a virtual interface
+ *
+ * @NL80211_ATTR_SURVEY_INFO: survey information about a channel, part of
+ *      the survey response for %NL80211_CMD_GET_SURVEY, nested attribute
+ *      containing info as possible, see &enum survey_info.
+ *
+ * @NL80211_ATTR_PMKID: PMK material for PMKSA caching.
+ * @NL80211_ATTR_MAX_NUM_PMKIDS: maximum number of PMKIDs a firmware can
+ *     cache, a wiphy attribute.
+ *
+ * @NL80211_ATTR_DURATION: Duration of an operation in milliseconds, u32.
+ *
+ * @NL80211_ATTR_COOKIE: Generic 64-bit cookie to identify objects.
+ *
+ * @NL80211_ATTR_TX_RATES: Nested set of attributes
+ *     (enum nl80211_tx_rate_attributes) describing TX rates per band. The
+ *     enum nl80211_band value is used as the index (nla_type() of the nested
+ *     data. If a band is not included, it will be configured to allow all
+ *     rates based on negotiated supported rates information. This attribute
+ *     is used with %NL80211_CMD_SET_TX_BITRATE_MASK.
+ *
+ * @NL80211_ATTR_FRAME_MATCH: A binary attribute which typically must contain
+ *     at least one byte, currently used with @NL80211_CMD_REGISTER_FRAME.
+ * @NL80211_ATTR_FRAME_TYPE: A u16 indicating the frame type/subtype for the
+ *     @NL80211_CMD_REGISTER_FRAME command.
+ * @NL80211_ATTR_TX_FRAME_TYPES: wiphy capability attribute, which is a
+ *     nested attribute of %NL80211_ATTR_FRAME_TYPE attributes, containing
+ *     information about which frame types can be transmitted with
+ *     %NL80211_CMD_FRAME.
+ * @NL80211_ATTR_RX_FRAME_TYPES: wiphy capability attribute, which is a
+ *     nested attribute of %NL80211_ATTR_FRAME_TYPE attributes, containing
+ *     information about which frame types can be registered for RX.
+ *
+ * @NL80211_ATTR_ACK: Flag attribute indicating that the frame was
+ *     acknowledged by the recipient.
+ *
+ * @NL80211_ATTR_CQM: connection quality monitor configuration in a
+ *     nested attribute with %NL80211_ATTR_CQM_* sub-attributes.
+ *
+ * @NL80211_ATTR_LOCAL_STATE_CHANGE: Flag attribute to indicate that a command
+ *     is requesting a local authentication/association state change without
+ *     invoking actual management frame exchange. This can be used with
+ *     NL80211_CMD_AUTHENTICATE, NL80211_CMD_DEAUTHENTICATE,
+ *     NL80211_CMD_DISASSOCIATE.
+ *
+ * @NL80211_ATTR_AP_ISOLATE: (AP mode) Do not forward traffic between stations
+ *     connected to this BSS.
+ *
+ * @NL80211_ATTR_WIPHY_TX_POWER_SETTING: Transmit power setting type. See
+ *      &enum nl80211_tx_power_setting for possible values.
+ * @NL80211_ATTR_WIPHY_TX_POWER_LEVEL: Transmit power level in signed mBm units.
+ *      This is used in association with @NL80211_ATTR_WIPHY_TX_POWER_SETTING
+ *      for non-automatic settings.
+ *
+ * @NL80211_ATTR_SUPPORT_IBSS_RSN: The device supports IBSS RSN, which mostly
+ *     means support for per-station GTKs.
+ *
+ * @NL80211_ATTR_WIPHY_ANTENNA_TX: Bitmap of allowed antennas for transmitting.
+ *     This can be used to mask out antennas which are not attached or should
+ *     not be used for transmitting. If an antenna is not selected in this
+ *     bitmap the hardware is not allowed to transmit on this antenna.
+ *
+ *     Each bit represents one antenna, starting with antenna 1 at the first
+ *     bit. Depending on which antennas are selected in the bitmap, 802.11n
+ *     drivers can derive which chainmasks to use (if all antennas belonging to
+ *     a particular chain are disabled this chain should be disabled) and if
+ *     a chain has diversity antennas wether diversity should be used or not.
+ *     HT capabilities (STBC, TX Beamforming, Antenna selection) can be
+ *     derived from the available chains after applying the antenna mask.
+ *     Non-802.11n drivers can derive wether to use diversity or not.
+ *     Drivers may reject configurations or RX/TX mask combinations they cannot
+ *     support by returning -EINVAL.
+ *
+ * @NL80211_ATTR_WIPHY_ANTENNA_RX: Bitmap of allowed antennas for receiving.
+ *     This can be used to mask out antennas which are not attached or should
+ *     not be used for receiving. If an antenna is not selected in this bitmap
+ *     the hardware should not be configured to receive on this antenna.
+ *     For a more detailed description see @NL80211_ATTR_WIPHY_ANTENNA_TX.
+ *
+ * @NL80211_ATTR_MCAST_RATE: Multicast tx rate (in 100 kbps) for IBSS
+ *
+ * @NL80211_ATTR_OFFCHANNEL_TX_OK: For management frame TX, the frame may be
+ *     transmitted on another channel when the channel given doesn't match
+ *     the current channel. If the current channel doesn't match and this
+ *     flag isn't set, the frame will be rejected. This is also used as an
+ *     nl80211 capability flag.
+ *
+ * @NL80211_ATTR_BSS_HTOPMODE: HT operation mode (u16)
+ *
+ * @NL80211_ATTR_MAX: highest attribute number currently defined
+ * @__NL80211_ATTR_AFTER_LAST: internal use
+ */
+enum nl80211_attrs {
+/* don't change the order or add anything inbetween, this is ABI! */
+       NL80211_ATTR_UNSPEC,
+
+       NL80211_ATTR_WIPHY,
+       NL80211_ATTR_WIPHY_NAME,
+
+       NL80211_ATTR_IFINDEX,
+       NL80211_ATTR_IFNAME,
+       NL80211_ATTR_IFTYPE,
+
+       NL80211_ATTR_MAC,
+
+       NL80211_ATTR_KEY_DATA,
+       NL80211_ATTR_KEY_IDX,
+       NL80211_ATTR_KEY_CIPHER,
+       NL80211_ATTR_KEY_SEQ,
+       NL80211_ATTR_KEY_DEFAULT,
+
+       NL80211_ATTR_BEACON_INTERVAL,
+       NL80211_ATTR_DTIM_PERIOD,
+       NL80211_ATTR_BEACON_HEAD,
+       NL80211_ATTR_BEACON_TAIL,
+
+       NL80211_ATTR_STA_AID,
+       NL80211_ATTR_STA_FLAGS,
+       NL80211_ATTR_STA_LISTEN_INTERVAL,
+       NL80211_ATTR_STA_SUPPORTED_RATES,
+       NL80211_ATTR_STA_VLAN,
+       NL80211_ATTR_STA_INFO,
+
+       NL80211_ATTR_WIPHY_BANDS,
+
+       NL80211_ATTR_MNTR_FLAGS,
+
+       NL80211_ATTR_MESH_ID,
+       NL80211_ATTR_STA_PLINK_ACTION,
+       NL80211_ATTR_MPATH_NEXT_HOP,
+       NL80211_ATTR_MPATH_INFO,
+
+       NL80211_ATTR_BSS_CTS_PROT,
+       NL80211_ATTR_BSS_SHORT_PREAMBLE,
+       NL80211_ATTR_BSS_SHORT_SLOT_TIME,
+
+       NL80211_ATTR_HT_CAPABILITY,
+
+       NL80211_ATTR_SUPPORTED_IFTYPES,
+
+       NL80211_ATTR_REG_ALPHA2,
+       NL80211_ATTR_REG_RULES,
+
+       NL80211_ATTR_MESH_PARAMS,
+
+       NL80211_ATTR_BSS_BASIC_RATES,
+
+       NL80211_ATTR_WIPHY_TXQ_PARAMS,
+       NL80211_ATTR_WIPHY_FREQ,
+       NL80211_ATTR_WIPHY_CHANNEL_TYPE,
+
+       NL80211_ATTR_KEY_DEFAULT_MGMT,
+
+       NL80211_ATTR_MGMT_SUBTYPE,
+       NL80211_ATTR_IE,
+
+       NL80211_ATTR_MAX_NUM_SCAN_SSIDS,
+
+       NL80211_ATTR_SCAN_FREQUENCIES,
+       NL80211_ATTR_SCAN_SSIDS,
+       NL80211_ATTR_GENERATION, /* replaces old SCAN_GENERATION */
+       NL80211_ATTR_BSS,
+
+       NL80211_ATTR_REG_INITIATOR,
+       NL80211_ATTR_REG_TYPE,
+
+       NL80211_ATTR_SUPPORTED_COMMANDS,
+
+       NL80211_ATTR_FRAME,
+       NL80211_ATTR_SSID,
+       NL80211_ATTR_AUTH_TYPE,
+       NL80211_ATTR_REASON_CODE,
+
+       NL80211_ATTR_KEY_TYPE,
+
+       NL80211_ATTR_MAX_SCAN_IE_LEN,
+       NL80211_ATTR_CIPHER_SUITES,
+
+       NL80211_ATTR_FREQ_BEFORE,
+       NL80211_ATTR_FREQ_AFTER,
+
+       NL80211_ATTR_FREQ_FIXED,
+
+
+       NL80211_ATTR_WIPHY_RETRY_SHORT,
+       NL80211_ATTR_WIPHY_RETRY_LONG,
+       NL80211_ATTR_WIPHY_FRAG_THRESHOLD,
+       NL80211_ATTR_WIPHY_RTS_THRESHOLD,
+
+       NL80211_ATTR_TIMED_OUT,
+
+       NL80211_ATTR_USE_MFP,
+
+       NL80211_ATTR_STA_FLAGS2,
+
+       NL80211_ATTR_CONTROL_PORT,
+
+       NL80211_ATTR_TESTDATA,
+
+       NL80211_ATTR_PRIVACY,
+
+       NL80211_ATTR_DISCONNECTED_BY_AP,
+       NL80211_ATTR_STATUS_CODE,
+
+       NL80211_ATTR_CIPHER_SUITES_PAIRWISE,
+       NL80211_ATTR_CIPHER_SUITE_GROUP,
+       NL80211_ATTR_WPA_VERSIONS,
+       NL80211_ATTR_AKM_SUITES,
+
+       NL80211_ATTR_REQ_IE,
+       NL80211_ATTR_RESP_IE,
+
+       NL80211_ATTR_PREV_BSSID,
+
+       NL80211_ATTR_KEY,
+       NL80211_ATTR_KEYS,
+
+       NL80211_ATTR_PID,
+
+       NL80211_ATTR_4ADDR,
+
+       NL80211_ATTR_SURVEY_INFO,
+
+       NL80211_ATTR_PMKID,
+       NL80211_ATTR_MAX_NUM_PMKIDS,
+
+       NL80211_ATTR_DURATION,
+
+       NL80211_ATTR_COOKIE,
+
+       NL80211_ATTR_WIPHY_COVERAGE_CLASS,
+
+       NL80211_ATTR_TX_RATES,
+
+       NL80211_ATTR_FRAME_MATCH,
+
+       NL80211_ATTR_ACK,
+
+       NL80211_ATTR_PS_STATE,
+
+       NL80211_ATTR_CQM,
+
+       NL80211_ATTR_LOCAL_STATE_CHANGE,
+
+       NL80211_ATTR_AP_ISOLATE,
+
+       NL80211_ATTR_WIPHY_TX_POWER_SETTING,
+       NL80211_ATTR_WIPHY_TX_POWER_LEVEL,
+
+       NL80211_ATTR_TX_FRAME_TYPES,
+       NL80211_ATTR_RX_FRAME_TYPES,
+       NL80211_ATTR_FRAME_TYPE,
+
+       NL80211_ATTR_CONTROL_PORT_ETHERTYPE,
+       NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT,
+
+       NL80211_ATTR_SUPPORT_IBSS_RSN,
+
+       NL80211_ATTR_WIPHY_ANTENNA_TX,
+       NL80211_ATTR_WIPHY_ANTENNA_RX,
+
+       NL80211_ATTR_MCAST_RATE,
+
+       NL80211_ATTR_OFFCHANNEL_TX_OK,
+
+       NL80211_ATTR_BSS_HT_OPMODE,
+
+       /* add attributes here, update the policy in nl80211.c */
+
+       __NL80211_ATTR_AFTER_LAST,
+       NL80211_ATTR_MAX = __NL80211_ATTR_AFTER_LAST - 1
+};
+
+/* source-level API compatibility */
+#define NL80211_ATTR_SCAN_GENERATION NL80211_ATTR_GENERATION
+
+/*
+ * Allow user space programs to use #ifdef on new attributes by defining them
+ * here
+ */
+#define NL80211_CMD_CONNECT NL80211_CMD_CONNECT
+#define NL80211_ATTR_HT_CAPABILITY NL80211_ATTR_HT_CAPABILITY
+#define NL80211_ATTR_BSS_BASIC_RATES NL80211_ATTR_BSS_BASIC_RATES
+#define NL80211_ATTR_WIPHY_TXQ_PARAMS NL80211_ATTR_WIPHY_TXQ_PARAMS
+#define NL80211_ATTR_WIPHY_FREQ NL80211_ATTR_WIPHY_FREQ
+#define NL80211_ATTR_WIPHY_CHANNEL_TYPE NL80211_ATTR_WIPHY_CHANNEL_TYPE
+#define NL80211_ATTR_MGMT_SUBTYPE NL80211_ATTR_MGMT_SUBTYPE
+#define NL80211_ATTR_IE NL80211_ATTR_IE
+#define NL80211_ATTR_REG_INITIATOR NL80211_ATTR_REG_INITIATOR
+#define NL80211_ATTR_REG_TYPE NL80211_ATTR_REG_TYPE
+#define NL80211_ATTR_FRAME NL80211_ATTR_FRAME
+#define NL80211_ATTR_SSID NL80211_ATTR_SSID
+#define NL80211_ATTR_AUTH_TYPE NL80211_ATTR_AUTH_TYPE
+#define NL80211_ATTR_REASON_CODE NL80211_ATTR_REASON_CODE
+#define NL80211_ATTR_CIPHER_SUITES_PAIRWISE NL80211_ATTR_CIPHER_SUITES_PAIRWISE
+#define NL80211_ATTR_CIPHER_SUITE_GROUP NL80211_ATTR_CIPHER_SUITE_GROUP
+#define NL80211_ATTR_WPA_VERSIONS NL80211_ATTR_WPA_VERSIONS
+#define NL80211_ATTR_AKM_SUITES NL80211_ATTR_AKM_SUITES
+#define NL80211_ATTR_KEY NL80211_ATTR_KEY
+#define NL80211_ATTR_KEYS NL80211_ATTR_KEYS
+
+#define NL80211_MAX_SUPP_RATES                 32
+#define NL80211_MAX_SUPP_REG_RULES             32
+#define NL80211_TKIP_DATA_OFFSET_ENCR_KEY      0
+#define NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY    16
+#define NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY    24
+#define NL80211_HT_CAPABILITY_LEN              26
+
+#define NL80211_MAX_NR_CIPHER_SUITES           5
+#define NL80211_MAX_NR_AKM_SUITES              2
+
+/**
+ * enum nl80211_iftype - (virtual) interface types
+ *
+ * @NL80211_IFTYPE_UNSPECIFIED: unspecified type, driver decides
+ * @NL80211_IFTYPE_ADHOC: independent BSS member
+ * @NL80211_IFTYPE_STATION: managed BSS member
+ * @NL80211_IFTYPE_AP: access point
+ * @NL80211_IFTYPE_AP_VLAN: VLAN interface for access points
+ * @NL80211_IFTYPE_WDS: wireless distribution interface
+ * @NL80211_IFTYPE_MONITOR: monitor interface receiving all frames
+ * @NL80211_IFTYPE_MESH_POINT: mesh point
+ * @NL80211_IFTYPE_P2P_CLIENT: P2P client
+ * @NL80211_IFTYPE_P2P_GO: P2P group owner
+ * @NL80211_IFTYPE_MAX: highest interface type number currently defined
+ * @NUM_NL80211_IFTYPES: number of defined interface types
+ *
+ * These values are used with the %NL80211_ATTR_IFTYPE
+ * to set the type of an interface.
+ *
+ */
+enum nl80211_iftype {
+       NL80211_IFTYPE_UNSPECIFIED,
+       NL80211_IFTYPE_ADHOC,
+       NL80211_IFTYPE_STATION,
+       NL80211_IFTYPE_AP,
+       NL80211_IFTYPE_AP_VLAN,
+       NL80211_IFTYPE_WDS,
+       NL80211_IFTYPE_MONITOR,
+       NL80211_IFTYPE_MESH_POINT,
+       NL80211_IFTYPE_P2P_CLIENT,
+       NL80211_IFTYPE_P2P_GO,
+
+       /* keep last */
+       NUM_NL80211_IFTYPES,
+       NL80211_IFTYPE_MAX = NUM_NL80211_IFTYPES - 1
+};
+
+/**
+ * enum nl80211_sta_flags - station flags
+ *
+ * Station flags. When a station is added to an AP interface, it is
+ * assumed to be already associated (and hence authenticated.)
+ *
+ * @__NL80211_STA_FLAG_INVALID: attribute number 0 is reserved
+ * @NL80211_STA_FLAG_AUTHORIZED: station is authorized (802.1X)
+ * @NL80211_STA_FLAG_SHORT_PREAMBLE: station is capable of receiving frames
+ *     with short barker preamble
+ * @NL80211_STA_FLAG_WME: station is WME/QoS capable
+ * @NL80211_STA_FLAG_MFP: station uses management frame protection
+ * @NL80211_STA_FLAG_MAX: highest station flag number currently defined
+ * @__NL80211_STA_FLAG_AFTER_LAST: internal use
+ */
+enum nl80211_sta_flags {
+       __NL80211_STA_FLAG_INVALID,
+       NL80211_STA_FLAG_AUTHORIZED,
+       NL80211_STA_FLAG_SHORT_PREAMBLE,
+       NL80211_STA_FLAG_WME,
+       NL80211_STA_FLAG_MFP,
+
+       /* keep last */
+       __NL80211_STA_FLAG_AFTER_LAST,
+       NL80211_STA_FLAG_MAX = __NL80211_STA_FLAG_AFTER_LAST - 1
+};
+
+/**
+ * struct nl80211_sta_flag_update - station flags mask/set
+ * @mask: mask of station flags to set
+ * @set: which values to set them to
+ *
+ * Both mask and set contain bits as per &enum nl80211_sta_flags.
+ */
+struct nl80211_sta_flag_update {
+       __u32 mask;
+       __u32 set;
+} __attribute__((packed));
+
+/**
+ * enum nl80211_rate_info - bitrate information
+ *
+ * These attribute types are used with %NL80211_STA_INFO_TXRATE
+ * when getting information about the bitrate of a station.
+ *
+ * @__NL80211_RATE_INFO_INVALID: attribute number 0 is reserved
+ * @NL80211_RATE_INFO_BITRATE: total bitrate (u16, 100kbit/s)
+ * @NL80211_RATE_INFO_MCS: mcs index for 802.11n (u8)
+ * @NL80211_RATE_INFO_40_MHZ_WIDTH: 40 MHz dualchannel bitrate
+ * @NL80211_RATE_INFO_SHORT_GI: 400ns guard interval
+ * @NL80211_RATE_INFO_MAX: highest rate_info number currently defined
+ * @__NL80211_RATE_INFO_AFTER_LAST: internal use
+ */
+enum nl80211_rate_info {
+       __NL80211_RATE_INFO_INVALID,
+       NL80211_RATE_INFO_BITRATE,
+       NL80211_RATE_INFO_MCS,
+       NL80211_RATE_INFO_40_MHZ_WIDTH,
+       NL80211_RATE_INFO_SHORT_GI,
+
+       /* keep last */
+       __NL80211_RATE_INFO_AFTER_LAST,
+       NL80211_RATE_INFO_MAX = __NL80211_RATE_INFO_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_sta_info - station information
+ *
+ * These attribute types are used with %NL80211_ATTR_STA_INFO
+ * when getting information about a station.
+ *
+ * @__NL80211_STA_INFO_INVALID: attribute number 0 is reserved
+ * @NL80211_STA_INFO_INACTIVE_TIME: time since last activity (u32, msecs)
+ * @NL80211_STA_INFO_RX_BYTES: total received bytes (u32, from this station)
+ * @NL80211_STA_INFO_TX_BYTES: total transmitted bytes (u32, to this station)
+ * @__NL80211_STA_INFO_AFTER_LAST: internal
+ * @NL80211_STA_INFO_MAX: highest possible station info attribute
+ * @NL80211_STA_INFO_SIGNAL: signal strength of last received PPDU (u8, dBm)
+ * @NL80211_STA_INFO_TX_BITRATE: current unicast tx rate, nested attribute
+ *     containing info as possible, see &enum nl80211_sta_info_txrate.
+ * @NL80211_STA_INFO_RX_PACKETS: total received packet (u32, from this station)
+ * @NL80211_STA_INFO_TX_PACKETS: total transmitted packets (u32, to this
+ *     station)
+ * @NL80211_STA_INFO_TX_RETRIES: total retries (u32, to this station)
+ * @NL80211_STA_INFO_TX_FAILED: total failed packets (u32, to this station)
+ * @NL80211_STA_INFO_SIGNAL_AVG: signal strength average (u8, dBm)
+ */
+enum nl80211_sta_info {
+       __NL80211_STA_INFO_INVALID,
+       NL80211_STA_INFO_INACTIVE_TIME,
+       NL80211_STA_INFO_RX_BYTES,
+       NL80211_STA_INFO_TX_BYTES,
+       NL80211_STA_INFO_LLID,
+       NL80211_STA_INFO_PLID,
+       NL80211_STA_INFO_PLINK_STATE,
+       NL80211_STA_INFO_SIGNAL,
+       NL80211_STA_INFO_TX_BITRATE,
+       NL80211_STA_INFO_RX_PACKETS,
+       NL80211_STA_INFO_TX_PACKETS,
+       NL80211_STA_INFO_TX_RETRIES,
+       NL80211_STA_INFO_TX_FAILED,
+       NL80211_STA_INFO_SIGNAL_AVG,
+
+       /* keep last */
+       __NL80211_STA_INFO_AFTER_LAST,
+       NL80211_STA_INFO_MAX = __NL80211_STA_INFO_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_mpath_flags - nl80211 mesh path flags
+ *
+ * @NL80211_MPATH_FLAG_ACTIVE: the mesh path is active
+ * @NL80211_MPATH_FLAG_RESOLVING: the mesh path discovery process is running
+ * @NL80211_MPATH_FLAG_SN_VALID: the mesh path contains a valid SN
+ * @NL80211_MPATH_FLAG_FIXED: the mesh path has been manually set
+ * @NL80211_MPATH_FLAG_RESOLVED: the mesh path discovery process succeeded
+ */
+enum nl80211_mpath_flags {
+       NL80211_MPATH_FLAG_ACTIVE =     1<<0,
+       NL80211_MPATH_FLAG_RESOLVING =  1<<1,
+       NL80211_MPATH_FLAG_SN_VALID =   1<<2,
+       NL80211_MPATH_FLAG_FIXED =      1<<3,
+       NL80211_MPATH_FLAG_RESOLVED =   1<<4,
+};
+
+/**
+ * enum nl80211_mpath_info - mesh path information
+ *
+ * These attribute types are used with %NL80211_ATTR_MPATH_INFO when getting
+ * information about a mesh path.
+ *
+ * @__NL80211_MPATH_INFO_INVALID: attribute number 0 is reserved
+ * @NL80211_MPATH_INFO_FRAME_QLEN: number of queued frames for this destination
+ * @NL80211_MPATH_INFO_SN: destination sequence number
+ * @NL80211_MPATH_INFO_METRIC: metric (cost) of this mesh path
+ * @NL80211_MPATH_INFO_EXPTIME: expiration time for the path, in msec from now
+ * @NL80211_MPATH_INFO_FLAGS: mesh path flags, enumerated in
+ *     &enum nl80211_mpath_flags;
+ * @NL80211_MPATH_INFO_DISCOVERY_TIMEOUT: total path discovery timeout, in msec
+ * @NL80211_MPATH_INFO_DISCOVERY_RETRIES: mesh path discovery retries
+ * @NL80211_MPATH_INFO_MAX: highest mesh path information attribute number
+ *     currently defind
+ * @__NL80211_MPATH_INFO_AFTER_LAST: internal use
+ */
+enum nl80211_mpath_info {
+       __NL80211_MPATH_INFO_INVALID,
+       NL80211_MPATH_INFO_FRAME_QLEN,
+       NL80211_MPATH_INFO_SN,
+       NL80211_MPATH_INFO_METRIC,
+       NL80211_MPATH_INFO_EXPTIME,
+       NL80211_MPATH_INFO_FLAGS,
+       NL80211_MPATH_INFO_DISCOVERY_TIMEOUT,
+       NL80211_MPATH_INFO_DISCOVERY_RETRIES,
+
+       /* keep last */
+       __NL80211_MPATH_INFO_AFTER_LAST,
+       NL80211_MPATH_INFO_MAX = __NL80211_MPATH_INFO_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_band_attr - band attributes
+ * @__NL80211_BAND_ATTR_INVALID: attribute number 0 is reserved
+ * @NL80211_BAND_ATTR_FREQS: supported frequencies in this band,
+ *     an array of nested frequency attributes
+ * @NL80211_BAND_ATTR_RATES: supported bitrates in this band,
+ *     an array of nested bitrate attributes
+ * @NL80211_BAND_ATTR_HT_MCS_SET: 16-byte attribute containing the MCS set as
+ *     defined in 802.11n
+ * @NL80211_BAND_ATTR_HT_CAPA: HT capabilities, as in the HT information IE
+ * @NL80211_BAND_ATTR_HT_AMPDU_FACTOR: A-MPDU factor, as in 11n
+ * @NL80211_BAND_ATTR_HT_AMPDU_DENSITY: A-MPDU density, as in 11n
+ * @NL80211_BAND_ATTR_MAX: highest band attribute currently defined
+ * @__NL80211_BAND_ATTR_AFTER_LAST: internal use
+ */
+enum nl80211_band_attr {
+       __NL80211_BAND_ATTR_INVALID,
+       NL80211_BAND_ATTR_FREQS,
+       NL80211_BAND_ATTR_RATES,
+
+       NL80211_BAND_ATTR_HT_MCS_SET,
+       NL80211_BAND_ATTR_HT_CAPA,
+       NL80211_BAND_ATTR_HT_AMPDU_FACTOR,
+       NL80211_BAND_ATTR_HT_AMPDU_DENSITY,
+
+       /* keep last */
+       __NL80211_BAND_ATTR_AFTER_LAST,
+       NL80211_BAND_ATTR_MAX = __NL80211_BAND_ATTR_AFTER_LAST - 1
+};
+
+#define NL80211_BAND_ATTR_HT_CAPA NL80211_BAND_ATTR_HT_CAPA
+
+/**
+ * enum nl80211_frequency_attr - frequency attributes
+ * @__NL80211_FREQUENCY_ATTR_INVALID: attribute number 0 is reserved
+ * @NL80211_FREQUENCY_ATTR_FREQ: Frequency in MHz
+ * @NL80211_FREQUENCY_ATTR_DISABLED: Channel is disabled in current
+ *     regulatory domain.
+ * @NL80211_FREQUENCY_ATTR_PASSIVE_SCAN: Only passive scanning is
+ *     permitted on this channel in current regulatory domain.
+ * @NL80211_FREQUENCY_ATTR_NO_IBSS: IBSS networks are not permitted
+ *     on this channel in current regulatory domain.
+ * @NL80211_FREQUENCY_ATTR_RADAR: Radar detection is mandatory
+ *     on this channel in current regulatory domain.
+ * @NL80211_FREQUENCY_ATTR_MAX_TX_POWER: Maximum transmission power in mBm
+ *     (100 * dBm).
+ * @NL80211_FREQUENCY_ATTR_MAX: highest frequency attribute number
+ *     currently defined
+ * @__NL80211_FREQUENCY_ATTR_AFTER_LAST: internal use
+ */
+enum nl80211_frequency_attr {
+       __NL80211_FREQUENCY_ATTR_INVALID,
+       NL80211_FREQUENCY_ATTR_FREQ,
+       NL80211_FREQUENCY_ATTR_DISABLED,
+       NL80211_FREQUENCY_ATTR_PASSIVE_SCAN,
+       NL80211_FREQUENCY_ATTR_NO_IBSS,
+       NL80211_FREQUENCY_ATTR_RADAR,
+       NL80211_FREQUENCY_ATTR_MAX_TX_POWER,
+
+       /* keep last */
+       __NL80211_FREQUENCY_ATTR_AFTER_LAST,
+       NL80211_FREQUENCY_ATTR_MAX = __NL80211_FREQUENCY_ATTR_AFTER_LAST - 1
+};
+
+#define NL80211_FREQUENCY_ATTR_MAX_TX_POWER NL80211_FREQUENCY_ATTR_MAX_TX_POWER
+
+/**
+ * enum nl80211_bitrate_attr - bitrate attributes
+ * @__NL80211_BITRATE_ATTR_INVALID: attribute number 0 is reserved
+ * @NL80211_BITRATE_ATTR_RATE: Bitrate in units of 100 kbps
+ * @NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE: Short preamble supported
+ *     in 2.4 GHz band.
+ * @NL80211_BITRATE_ATTR_MAX: highest bitrate attribute number
+ *     currently defined
+ * @__NL80211_BITRATE_ATTR_AFTER_LAST: internal use
+ */
+enum nl80211_bitrate_attr {
+       __NL80211_BITRATE_ATTR_INVALID,
+       NL80211_BITRATE_ATTR_RATE,
+       NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE,
+
+       /* keep last */
+       __NL80211_BITRATE_ATTR_AFTER_LAST,
+       NL80211_BITRATE_ATTR_MAX = __NL80211_BITRATE_ATTR_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_initiator - Indicates the initiator of a reg domain request
+ * @NL80211_REGDOM_SET_BY_CORE: Core queried CRDA for a dynamic world
+ *     regulatory domain.
+ * @NL80211_REGDOM_SET_BY_USER: User asked the wireless core to set the
+ *     regulatory domain.
+ * @NL80211_REGDOM_SET_BY_DRIVER: a wireless drivers has hinted to the
+ *     wireless core it thinks its knows the regulatory domain we should be in.
+ * @NL80211_REGDOM_SET_BY_COUNTRY_IE: the wireless core has received an
+ *     802.11 country information element with regulatory information it
+ *     thinks we should consider. cfg80211 only processes the country
+ *     code from the IE, and relies on the regulatory domain information
+ *     structure passed by userspace (CRDA) from our wireless-regdb.
+ *     If a channel is enabled but the country code indicates it should
+ *     be disabled we disable the channel and re-enable it upon disassociation.
+ */
+enum nl80211_reg_initiator {
+       NL80211_REGDOM_SET_BY_CORE,
+       NL80211_REGDOM_SET_BY_USER,
+       NL80211_REGDOM_SET_BY_DRIVER,
+       NL80211_REGDOM_SET_BY_COUNTRY_IE,
+};
+
+/**
+ * enum nl80211_reg_type - specifies the type of regulatory domain
+ * @NL80211_REGDOM_TYPE_COUNTRY: the regulatory domain set is one that pertains
+ *     to a specific country. When this is set you can count on the
+ *     ISO / IEC 3166 alpha2 country code being valid.
+ * @NL80211_REGDOM_TYPE_WORLD: the regulatory set domain is the world regulatory
+ *     domain.
+ * @NL80211_REGDOM_TYPE_CUSTOM_WORLD: the regulatory domain set is a custom
+ *     driver specific world regulatory domain. These do not apply system-wide
+ *     and are only applicable to the individual devices which have requested
+ *     them to be applied.
+ * @NL80211_REGDOM_TYPE_INTERSECTION: the regulatory domain set is the product
+ *     of an intersection between two regulatory domains -- the previously
+ *     set regulatory domain on the system and the last accepted regulatory
+ *     domain request to be processed.
+ */
+enum nl80211_reg_type {
+       NL80211_REGDOM_TYPE_COUNTRY,
+       NL80211_REGDOM_TYPE_WORLD,
+       NL80211_REGDOM_TYPE_CUSTOM_WORLD,
+       NL80211_REGDOM_TYPE_INTERSECTION,
+};
+
+/**
+ * enum nl80211_reg_rule_attr - regulatory rule attributes
+ * @__NL80211_REG_RULE_ATTR_INVALID: attribute number 0 is reserved
+ * @NL80211_ATTR_REG_RULE_FLAGS: a set of flags which specify additional
+ *     considerations for a given frequency range. These are the
+ *     &enum nl80211_reg_rule_flags.
+ * @NL80211_ATTR_FREQ_RANGE_START: starting frequencry for the regulatory
+ *     rule in KHz. This is not a center of frequency but an actual regulatory
+ *     band edge.
+ * @NL80211_ATTR_FREQ_RANGE_END: ending frequency for the regulatory rule
+ *     in KHz. This is not a center a frequency but an actual regulatory
+ *     band edge.
+ * @NL80211_ATTR_FREQ_RANGE_MAX_BW: maximum allowed bandwidth for this
+ *     frequency range, in KHz.
+ * @NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN: the maximum allowed antenna gain
+ *     for a given frequency range. The value is in mBi (100 * dBi).
+ *     If you don't have one then don't send this.
+ * @NL80211_ATTR_POWER_RULE_MAX_EIRP: the maximum allowed EIRP for
+ *     a given frequency range. The value is in mBm (100 * dBm).
+ * @NL80211_REG_RULE_ATTR_MAX: highest regulatory rule attribute number
+ *     currently defined
+ * @__NL80211_REG_RULE_ATTR_AFTER_LAST: internal use
+ */
+enum nl80211_reg_rule_attr {
+       __NL80211_REG_RULE_ATTR_INVALID,
+       NL80211_ATTR_REG_RULE_FLAGS,
+
+       NL80211_ATTR_FREQ_RANGE_START,
+       NL80211_ATTR_FREQ_RANGE_END,
+       NL80211_ATTR_FREQ_RANGE_MAX_BW,
+
+       NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN,
+       NL80211_ATTR_POWER_RULE_MAX_EIRP,
+
+       /* keep last */
+       __NL80211_REG_RULE_ATTR_AFTER_LAST,
+       NL80211_REG_RULE_ATTR_MAX = __NL80211_REG_RULE_ATTR_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_reg_rule_flags - regulatory rule flags
+ *
+ * @NL80211_RRF_NO_OFDM: OFDM modulation not allowed
+ * @NL80211_RRF_NO_CCK: CCK modulation not allowed
+ * @NL80211_RRF_NO_INDOOR: indoor operation not allowed
+ * @NL80211_RRF_NO_OUTDOOR: outdoor operation not allowed
+ * @NL80211_RRF_DFS: DFS support is required to be used
+ * @NL80211_RRF_PTP_ONLY: this is only for Point To Point links
+ * @NL80211_RRF_PTMP_ONLY: this is only for Point To Multi Point links
+ * @NL80211_RRF_PASSIVE_SCAN: passive scan is required
+ * @NL80211_RRF_NO_IBSS: no IBSS is allowed
+ */
+enum nl80211_reg_rule_flags {
+       NL80211_RRF_NO_OFDM             = 1<<0,
+       NL80211_RRF_NO_CCK              = 1<<1,
+       NL80211_RRF_NO_INDOOR           = 1<<2,
+       NL80211_RRF_NO_OUTDOOR          = 1<<3,
+       NL80211_RRF_DFS                 = 1<<4,
+       NL80211_RRF_PTP_ONLY            = 1<<5,
+       NL80211_RRF_PTMP_ONLY           = 1<<6,
+       NL80211_RRF_PASSIVE_SCAN        = 1<<7,
+       NL80211_RRF_NO_IBSS             = 1<<8,
+};
+
+/**
+ * enum nl80211_survey_info - survey information
+ *
+ * These attribute types are used with %NL80211_ATTR_SURVEY_INFO
+ * when getting information about a survey.
+ *
+ * @__NL80211_SURVEY_INFO_INVALID: attribute number 0 is reserved
+ * @NL80211_SURVEY_INFO_FREQUENCY: center frequency of channel
+ * @NL80211_SURVEY_INFO_NOISE: noise level of channel (u8, dBm)
+ * @NL80211_SURVEY_INFO_IN_USE: channel is currently being used
+ * @NL80211_SURVEY_INFO_CHANNEL_TIME: amount of time (in ms) that the radio
+ *     spent on this channel
+ * @NL80211_SURVEY_INFO_CHANNEL_TIME_BUSY: amount of the time the primary
+ *     channel was sensed busy (either due to activity or energy detect)
+ * @NL80211_SURVEY_INFO_CHANNEL_TIME_EXT_BUSY: amount of time the extension
+ *     channel was sensed busy
+ * @NL80211_SURVEY_INFO_CHANNEL_TIME_RX: amount of time the radio spent
+ *     receiving data
+ * @NL80211_SURVEY_INFO_CHANNEL_TIME_TX: amount of time the radio spent
+ *     transmitting data
+ * @NL80211_SURVEY_INFO_MAX: highest survey info attribute number
+ *     currently defined
+ * @__NL80211_SURVEY_INFO_AFTER_LAST: internal use
+ */
+enum nl80211_survey_info {
+       __NL80211_SURVEY_INFO_INVALID,
+       NL80211_SURVEY_INFO_FREQUENCY,
+       NL80211_SURVEY_INFO_NOISE,
+       NL80211_SURVEY_INFO_IN_USE,
+       NL80211_SURVEY_INFO_CHANNEL_TIME,
+       NL80211_SURVEY_INFO_CHANNEL_TIME_BUSY,
+       NL80211_SURVEY_INFO_CHANNEL_TIME_EXT_BUSY,
+       NL80211_SURVEY_INFO_CHANNEL_TIME_RX,
+       NL80211_SURVEY_INFO_CHANNEL_TIME_TX,
+
+       /* keep last */
+       __NL80211_SURVEY_INFO_AFTER_LAST,
+       NL80211_SURVEY_INFO_MAX = __NL80211_SURVEY_INFO_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_mntr_flags - monitor configuration flags
+ *
+ * Monitor configuration flags.
+ *
+ * @__NL80211_MNTR_FLAG_INVALID: reserved
+ *
+ * @NL80211_MNTR_FLAG_FCSFAIL: pass frames with bad FCS
+ * @NL80211_MNTR_FLAG_PLCPFAIL: pass frames with bad PLCP
+ * @NL80211_MNTR_FLAG_CONTROL: pass control frames
+ * @NL80211_MNTR_FLAG_OTHER_BSS: disable BSSID filtering
+ * @NL80211_MNTR_FLAG_COOK_FRAMES: report frames after processing.
+ *     overrides all other flags.
+ *
+ * @__NL80211_MNTR_FLAG_AFTER_LAST: internal use
+ * @NL80211_MNTR_FLAG_MAX: highest possible monitor flag
+ */
+enum nl80211_mntr_flags {
+       __NL80211_MNTR_FLAG_INVALID,
+       NL80211_MNTR_FLAG_FCSFAIL,
+       NL80211_MNTR_FLAG_PLCPFAIL,
+       NL80211_MNTR_FLAG_CONTROL,
+       NL80211_MNTR_FLAG_OTHER_BSS,
+       NL80211_MNTR_FLAG_COOK_FRAMES,
+
+       /* keep last */
+       __NL80211_MNTR_FLAG_AFTER_LAST,
+       NL80211_MNTR_FLAG_MAX = __NL80211_MNTR_FLAG_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_meshconf_params - mesh configuration parameters
+ *
+ * Mesh configuration parameters
+ *
+ * @__NL80211_MESHCONF_INVALID: internal use
+ *
+ * @NL80211_MESHCONF_RETRY_TIMEOUT: specifies the initial retry timeout in
+ * millisecond units, used by the Peer Link Open message
+ *
+ * @NL80211_MESHCONF_CONFIRM_TIMEOUT: specifies the initial confirm timeout, in
+ * millisecond units, used by the peer link management to close a peer link
+ *
+ * @NL80211_MESHCONF_HOLDING_TIMEOUT: specifies the holding timeout, in
+ * millisecond units
+ *
+ * @NL80211_MESHCONF_MAX_PEER_LINKS: maximum number of peer links allowed
+ * on this mesh interface
+ *
+ * @NL80211_MESHCONF_MAX_RETRIES: specifies the maximum number of peer link
+ * open retries that can be sent to establish a new peer link instance in a
+ * mesh
+ *
+ * @NL80211_MESHCONF_TTL: specifies the value of TTL field set at a source mesh
+ * point.
+ *
+ * @NL80211_MESHCONF_ELEMENT_TTL: specifies the value of TTL field set at a
+ * source mesh point for path selection elements.
+ *
+ * @NL80211_MESHCONF_AUTO_OPEN_PLINKS: whether we should automatically
+ * open peer links when we detect compatible mesh peers.
+ *
+ * @NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES: the number of action frames
+ * containing a PREQ that an MP can send to a particular destination (path
+ * target)
+ *
+ * @NL80211_MESHCONF_PATH_REFRESH_TIME: how frequently to refresh mesh paths
+ * (in milliseconds)
+ *
+ * @NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT: minimum length of time to wait
+ * until giving up on a path discovery (in milliseconds)
+ *
+ * @NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT: The time (in TUs) for which mesh
+ * points receiving a PREQ shall consider the forwarding information from the
+ * root to be valid. (TU = time unit)
+ *
+ * @NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL: The minimum interval of time (in
+ * TUs) during which an MP can send only one action frame containing a PREQ
+ * reference element
+ *
+ * @NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME: The interval of time (in TUs)
+ * that it takes for an HWMP information element to propagate across the mesh
+ *
+ * @NL80211_MESHCONF_ROOTMODE: whether root mode is enabled or not
+ *
+ * @NL80211_MESHCONF_ATTR_MAX: highest possible mesh configuration attribute
+ *
+ * @__NL80211_MESHCONF_ATTR_AFTER_LAST: internal use
+ */
+enum nl80211_meshconf_params {
+       __NL80211_MESHCONF_INVALID,
+       NL80211_MESHCONF_RETRY_TIMEOUT,
+       NL80211_MESHCONF_CONFIRM_TIMEOUT,
+       NL80211_MESHCONF_HOLDING_TIMEOUT,
+       NL80211_MESHCONF_MAX_PEER_LINKS,
+       NL80211_MESHCONF_MAX_RETRIES,
+       NL80211_MESHCONF_TTL,
+       NL80211_MESHCONF_AUTO_OPEN_PLINKS,
+       NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES,
+       NL80211_MESHCONF_PATH_REFRESH_TIME,
+       NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT,
+       NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT,
+       NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL,
+       NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME,
+       NL80211_MESHCONF_HWMP_ROOTMODE,
+       NL80211_MESHCONF_ELEMENT_TTL,
+
+       /* keep last */
+       __NL80211_MESHCONF_ATTR_AFTER_LAST,
+       NL80211_MESHCONF_ATTR_MAX = __NL80211_MESHCONF_ATTR_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_txq_attr - TX queue parameter attributes
+ * @__NL80211_TXQ_ATTR_INVALID: Attribute number 0 is reserved
+ * @NL80211_TXQ_ATTR_QUEUE: TX queue identifier (NL80211_TXQ_Q_*)
+ * @NL80211_TXQ_ATTR_TXOP: Maximum burst time in units of 32 usecs, 0 meaning
+ *     disabled
+ * @NL80211_TXQ_ATTR_CWMIN: Minimum contention window [a value of the form
+ *     2^n-1 in the range 1..32767]
+ * @NL80211_TXQ_ATTR_CWMAX: Maximum contention window [a value of the form
+ *     2^n-1 in the range 1..32767]
+ * @NL80211_TXQ_ATTR_AIFS: Arbitration interframe space [0..255]
+ * @__NL80211_TXQ_ATTR_AFTER_LAST: Internal
+ * @NL80211_TXQ_ATTR_MAX: Maximum TXQ attribute number
+ */
+enum nl80211_txq_attr {
+       __NL80211_TXQ_ATTR_INVALID,
+       NL80211_TXQ_ATTR_QUEUE,
+       NL80211_TXQ_ATTR_TXOP,
+       NL80211_TXQ_ATTR_CWMIN,
+       NL80211_TXQ_ATTR_CWMAX,
+       NL80211_TXQ_ATTR_AIFS,
+
+       /* keep last */
+       __NL80211_TXQ_ATTR_AFTER_LAST,
+       NL80211_TXQ_ATTR_MAX = __NL80211_TXQ_ATTR_AFTER_LAST - 1
+};
+
+enum nl80211_txq_q {
+       NL80211_TXQ_Q_VO,
+       NL80211_TXQ_Q_VI,
+       NL80211_TXQ_Q_BE,
+       NL80211_TXQ_Q_BK
+};
+
+enum nl80211_channel_type {
+       NL80211_CHAN_NO_HT,
+       NL80211_CHAN_HT20,
+       NL80211_CHAN_HT40MINUS,
+       NL80211_CHAN_HT40PLUS
+};
+
+/**
+ * enum nl80211_bss - netlink attributes for a BSS
+ *
+ * @__NL80211_BSS_INVALID: invalid
+ * @NL80211_BSS_BSSID: BSSID of the BSS (6 octets)
+ * @NL80211_BSS_FREQUENCY: frequency in MHz (u32)
+ * @NL80211_BSS_TSF: TSF of the received probe response/beacon (u64)
+ * @NL80211_BSS_BEACON_INTERVAL: beacon interval of the (I)BSS (u16)
+ * @NL80211_BSS_CAPABILITY: capability field (CPU order, u16)
+ * @NL80211_BSS_INFORMATION_ELEMENTS: binary attribute containing the
+ *     raw information elements from the probe response/beacon (bin);
+ *     if the %NL80211_BSS_BEACON_IES attribute is present, the IEs here are
+ *     from a Probe Response frame; otherwise they are from a Beacon frame.
+ *     However, if the driver does not indicate the source of the IEs, these
+ *     IEs may be from either frame subtype.
+ * @NL80211_BSS_SIGNAL_MBM: signal strength of probe response/beacon
+ *     in mBm (100 * dBm) (s32)
+ * @NL80211_BSS_SIGNAL_UNSPEC: signal strength of the probe response/beacon
+ *     in unspecified units, scaled to 0..100 (u8)
+ * @NL80211_BSS_STATUS: status, if this BSS is "used"
+ * @NL80211_BSS_SEEN_MS_AGO: age of this BSS entry in ms
+ * @NL80211_BSS_BEACON_IES: binary attribute containing the raw information
+ *     elements from a Beacon frame (bin); not present if no Beacon frame has
+ *     yet been received
+ * @__NL80211_BSS_AFTER_LAST: internal
+ * @NL80211_BSS_MAX: highest BSS attribute
+ */
+enum nl80211_bss {
+       __NL80211_BSS_INVALID,
+       NL80211_BSS_BSSID,
+       NL80211_BSS_FREQUENCY,
+       NL80211_BSS_TSF,
+       NL80211_BSS_BEACON_INTERVAL,
+       NL80211_BSS_CAPABILITY,
+       NL80211_BSS_INFORMATION_ELEMENTS,
+       NL80211_BSS_SIGNAL_MBM,
+       NL80211_BSS_SIGNAL_UNSPEC,
+       NL80211_BSS_STATUS,
+       NL80211_BSS_SEEN_MS_AGO,
+       NL80211_BSS_BEACON_IES,
+
+       /* keep last */
+       __NL80211_BSS_AFTER_LAST,
+       NL80211_BSS_MAX = __NL80211_BSS_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_bss_status - BSS "status"
+ * @NL80211_BSS_STATUS_AUTHENTICATED: Authenticated with this BSS.
+ * @NL80211_BSS_STATUS_ASSOCIATED: Associated with this BSS.
+ * @NL80211_BSS_STATUS_IBSS_JOINED: Joined to this IBSS.
+ *
+ * The BSS status is a BSS attribute in scan dumps, which
+ * indicates the status the interface has wrt. this BSS.
+ */
+enum nl80211_bss_status {
+       NL80211_BSS_STATUS_AUTHENTICATED,
+       NL80211_BSS_STATUS_ASSOCIATED,
+       NL80211_BSS_STATUS_IBSS_JOINED,
+};
+
+/**
+ * enum nl80211_auth_type - AuthenticationType
+ *
+ * @NL80211_AUTHTYPE_OPEN_SYSTEM: Open System authentication
+ * @NL80211_AUTHTYPE_SHARED_KEY: Shared Key authentication (WEP only)
+ * @NL80211_AUTHTYPE_FT: Fast BSS Transition (IEEE 802.11r)
+ * @NL80211_AUTHTYPE_NETWORK_EAP: Network EAP (some Cisco APs and mainly LEAP)
+ * @__NL80211_AUTHTYPE_NUM: internal
+ * @NL80211_AUTHTYPE_MAX: maximum valid auth algorithm
+ * @NL80211_AUTHTYPE_AUTOMATIC: determine automatically (if necessary by
+ *     trying multiple times); this is invalid in netlink -- leave out
+ *     the attribute for this on CONNECT commands.
+ */
+enum nl80211_auth_type {
+       NL80211_AUTHTYPE_OPEN_SYSTEM,
+       NL80211_AUTHTYPE_SHARED_KEY,
+       NL80211_AUTHTYPE_FT,
+       NL80211_AUTHTYPE_NETWORK_EAP,
+
+       /* keep last */
+       __NL80211_AUTHTYPE_NUM,
+       NL80211_AUTHTYPE_MAX = __NL80211_AUTHTYPE_NUM - 1,
+       NL80211_AUTHTYPE_AUTOMATIC
+};
+
+/**
+ * enum nl80211_key_type - Key Type
+ * @NL80211_KEYTYPE_GROUP: Group (broadcast/multicast) key
+ * @NL80211_KEYTYPE_PAIRWISE: Pairwise (unicast/individual) key
+ * @NL80211_KEYTYPE_PEERKEY: PeerKey (DLS)
+ * @NUM_NL80211_KEYTYPES: number of defined key types
+ */
+enum nl80211_key_type {
+       NL80211_KEYTYPE_GROUP,
+       NL80211_KEYTYPE_PAIRWISE,
+       NL80211_KEYTYPE_PEERKEY,
+
+       NUM_NL80211_KEYTYPES
+};
+
+/**
+ * enum nl80211_mfp - Management frame protection state
+ * @NL80211_MFP_NO: Management frame protection not used
+ * @NL80211_MFP_REQUIRED: Management frame protection required
+ */
+enum nl80211_mfp {
+       NL80211_MFP_NO,
+       NL80211_MFP_REQUIRED,
+};
+
+enum nl80211_wpa_versions {
+       NL80211_WPA_VERSION_1 = 1 << 0,
+       NL80211_WPA_VERSION_2 = 1 << 1,
+};
+
+/**
+ * enum nl80211_key_attributes - key attributes
+ * @__NL80211_KEY_INVALID: invalid
+ * @NL80211_KEY_DATA: (temporal) key data; for TKIP this consists of
+ *     16 bytes encryption key followed by 8 bytes each for TX and RX MIC
+ *     keys
+ * @NL80211_KEY_IDX: key ID (u8, 0-3)
+ * @NL80211_KEY_CIPHER: key cipher suite (u32, as defined by IEEE 802.11
+ *     section 7.3.2.25.1, e.g. 0x000FAC04)
+ * @NL80211_KEY_SEQ: transmit key sequence number (IV/PN) for TKIP and
+ *     CCMP keys, each six bytes in little endian
+ * @NL80211_KEY_DEFAULT: flag indicating default key
+ * @NL80211_KEY_DEFAULT_MGMT: flag indicating default management key
+ * @NL80211_KEY_TYPE: the key type from enum nl80211_key_type, if not
+ *     specified the default depends on whether a MAC address was
+ *     given with the command using the key or not (u32)
+ * @__NL80211_KEY_AFTER_LAST: internal
+ * @NL80211_KEY_MAX: highest key attribute
+ */
+enum nl80211_key_attributes {
+       __NL80211_KEY_INVALID,
+       NL80211_KEY_DATA,
+       NL80211_KEY_IDX,
+       NL80211_KEY_CIPHER,
+       NL80211_KEY_SEQ,
+       NL80211_KEY_DEFAULT,
+       NL80211_KEY_DEFAULT_MGMT,
+       NL80211_KEY_TYPE,
+
+       /* keep last */
+       __NL80211_KEY_AFTER_LAST,
+       NL80211_KEY_MAX = __NL80211_KEY_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_tx_rate_attributes - TX rate set attributes
+ * @__NL80211_TXRATE_INVALID: invalid
+ * @NL80211_TXRATE_LEGACY: Legacy (non-MCS) rates allowed for TX rate selection
+ *     in an array of rates as defined in IEEE 802.11 7.3.2.2 (u8 values with
+ *     1 = 500 kbps) but without the IE length restriction (at most
+ *     %NL80211_MAX_SUPP_RATES in a single array).
+ * @__NL80211_TXRATE_AFTER_LAST: internal
+ * @NL80211_TXRATE_MAX: highest TX rate attribute
+ */
+enum nl80211_tx_rate_attributes {
+       __NL80211_TXRATE_INVALID,
+       NL80211_TXRATE_LEGACY,
+
+       /* keep last */
+       __NL80211_TXRATE_AFTER_LAST,
+       NL80211_TXRATE_MAX = __NL80211_TXRATE_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_band - Frequency band
+ * @NL80211_BAND_2GHZ: 2.4 GHz ISM band
+ * @NL80211_BAND_5GHZ: around 5 GHz band (4.9 - 5.7 GHz)
+ */
+enum nl80211_band {
+       NL80211_BAND_2GHZ,
+       NL80211_BAND_5GHZ,
+};
+
+enum nl80211_ps_state {
+       NL80211_PS_DISABLED,
+       NL80211_PS_ENABLED,
+};
+
+/**
+ * enum nl80211_attr_cqm - connection quality monitor attributes
+ * @__NL80211_ATTR_CQM_INVALID: invalid
+ * @NL80211_ATTR_CQM_RSSI_THOLD: RSSI threshold in dBm. This value specifies
+ *     the threshold for the RSSI level at which an event will be sent. Zero
+ *     to disable.
+ * @NL80211_ATTR_CQM_RSSI_HYST: RSSI hysteresis in dBm. This value specifies
+ *     the minimum amount the RSSI level must change after an event before a
+ *     new event may be issued (to reduce effects of RSSI oscillation).
+ * @NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT: RSSI threshold event
+ * @NL80211_ATTR_CQM_PKT_LOSS_EVENT: a u32 value indicating that this many
+ *     consecutive packets were not acknowledged by the peer
+ * @__NL80211_ATTR_CQM_AFTER_LAST: internal
+ * @NL80211_ATTR_CQM_MAX: highest key attribute
+ */
+enum nl80211_attr_cqm {
+       __NL80211_ATTR_CQM_INVALID,
+       NL80211_ATTR_CQM_RSSI_THOLD,
+       NL80211_ATTR_CQM_RSSI_HYST,
+       NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT,
+       NL80211_ATTR_CQM_PKT_LOSS_EVENT,
+
+       /* keep last */
+       __NL80211_ATTR_CQM_AFTER_LAST,
+       NL80211_ATTR_CQM_MAX = __NL80211_ATTR_CQM_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_cqm_rssi_threshold_event - RSSI threshold event
+ * @NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW: The RSSI level is lower than the
+ *      configured threshold
+ * @NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH: The RSSI is higher than the
+ *      configured threshold
+ */
+enum nl80211_cqm_rssi_threshold_event {
+       NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW,
+       NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH,
+};
+
+
+/**
+ * enum nl80211_tx_power_setting - TX power adjustment
+ * @NL80211_TX_POWER_AUTOMATIC: automatically determine transmit power
+ * @NL80211_TX_POWER_LIMITED: limit TX power by the mBm parameter
+ * @NL80211_TX_POWER_FIXED: fix TX power to the mBm parameter
+ */
+enum nl80211_tx_power_setting {
+       NL80211_TX_POWER_AUTOMATIC,
+       NL80211_TX_POWER_LIMITED,
+       NL80211_TX_POWER_FIXED,
+};
+
+#endif /* __LINUX_NL80211_H */
diff --git a/src/tuning/runtime.cpp b/src/tuning/runtime.cpp
new file mode 100644 (file)
index 0000000..b57d53e
--- /dev/null
@@ -0,0 +1,163 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ *     Arjan van de Ven <arjan@linux.intel.com>
+ */
+
+#include "tuning.h"
+#include "tunable.h"
+#include "unistd.h"
+#include "runtime.h"
+#include <string.h>
+#include <utility>
+#include <iostream>
+#include <fstream>
+#include <unistd.h>
+#include <sys/types.h>
+#include <dirent.h>
+
+#include "../lib.h"
+#include "../devices/runtime_pm.h"
+
+runtime_tunable::runtime_tunable(const char *path, const char *bus, const char *dev) : tunable("", 0.4, _("Good"), _("Bad"), _("Unknown"))
+{
+       ifstream file;
+       sprintf(runtime_path, "%s/power/control", path);
+
+
+       sprintf(desc, _("Runtime PM for %s device %s"), bus, dev);
+       if (!device_has_runtime_pm(path))
+               sprintf(desc, _("%s device %s has no runtime power management"), bus, dev);
+
+       if (strcmp(bus, "pci") == 0) {
+               char filename[4096];
+               uint16_t vendor = 0, device = 0;
+
+               sprintf(filename, "/sys/bus/%s/devices/%s/vendor", bus, dev);
+
+               file.open(filename, ios::in);
+               if (file) {
+                       file >> hex >> vendor;
+                       file.close();
+               }
+
+
+               sprintf(filename, "/sys/bus/%s/devices/%s/device", bus, dev);
+               file.open(filename, ios::in);
+               if (file) {
+                       file >> hex >> device;
+                       file.close();
+               }
+
+               if (vendor && device) {
+                       if (!device_has_runtime_pm(path))
+                               sprintf(desc, _("PCI Device %s has no runtime power management"), pci_id_to_name(vendor, device, filename, 4095));
+                       else
+                               sprintf(desc, _("Runtime PM for PCI Device %s"), pci_id_to_name(vendor, device, filename, 4095));
+               }
+
+
+       }
+       sprintf(toggle_good, "echo 'auto' > '%s';", runtime_path);
+       sprintf(toggle_bad, "echo 'on' > '%s';", runtime_path);
+}
+
+int runtime_tunable::good_bad(void)
+{
+       string content;
+
+       content = read_sysfs_string(runtime_path);
+
+       if (strcmp(content.c_str(), "auto") == 0)
+               return TUNE_GOOD;
+
+       return TUNE_BAD;
+}
+
+void runtime_tunable::toggle(void)
+{
+       int good;
+       good = good_bad();
+
+       if (good == TUNE_GOOD) {
+               write_sysfs(runtime_path, "on");
+               return;
+       }
+
+       write_sysfs(runtime_path, "auto");
+}
+
+const char *runtime_tunable::toggle_script(void)
+{
+       int good;
+       good = good_bad();
+
+       if (good == TUNE_GOOD) {
+               return toggle_bad;
+       }
+
+       return toggle_good;
+}
+
+
+void add_runtime_tunables(const char *bus)
+{
+       struct dirent *entry;
+       DIR *dir;
+       char filename[4096];
+
+       sprintf(filename, "/sys/bus/%s/devices/", bus);
+       dir = opendir(filename);
+       if (!dir)
+               return;
+       while (1) {
+               class runtime_tunable *runtime;
+
+               entry = readdir(dir);
+
+               if (!entry)
+                       break;
+               if (entry->d_name[0] == '.')
+                       continue;
+
+               sprintf(filename, "/sys/bus/%s/devices/%s", bus, entry->d_name);
+
+
+
+               sprintf(filename, "/sys/bus/%s/devices/%s/power/control", bus, entry->d_name);
+
+               if (access(filename, R_OK) != 0)
+                       continue;
+
+
+               sprintf(filename, "/sys/bus/%s/devices/%s", bus, entry->d_name);
+
+               runtime = new class runtime_tunable(filename, bus, entry->d_name);
+
+               if (!device_has_runtime_pm(filename))
+                       all_untunables.push_back(runtime);
+               else
+                       all_tunables.push_back(runtime);
+
+       }
+       closedir(dir);
+}
diff --git a/src/tuning/runtime.h b/src/tuning/runtime.h
new file mode 100644 (file)
index 0000000..a3c3e20
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ *     Arjan van de Ven <arjan@linux.intel.com>
+ */
+#ifndef _INCLUDE_GUARD_RUNTIME_TUNE_H
+#define _INCLUDE_GUARD_RUNTIME_TUNE_H
+
+#include <vector>
+
+#include "tunable.h"
+using namespace std;
+
+class runtime_tunable : public tunable {
+       char runtime_path[4096];
+public:
+       runtime_tunable(const char *runtime_path, const char *bus, const char *dev);
+
+       virtual int good_bad(void);
+
+       virtual void toggle(void);
+
+       virtual const char *toggle_script(void);
+
+};
+
+extern void add_runtime_tunables(const char *bus);
+
+
+#endif
diff --git a/src/tuning/tunable.cpp b/src/tuning/tunable.cpp
new file mode 100644 (file)
index 0000000..83595ea
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ *     Arjan van de Ven <arjan@linux.intel.com>
+ */
+
+#include "tuning.h"
+#include "tunable.h"
+#include <string.h>
+
+vector<class tunable *> all_tunables;
+vector<class tunable *> all_untunables;
+
+
+tunable::tunable(const char *str, double _score, const char *good, const char *bad, const char *neutral)
+{
+       score = _score;
+       strcpy(desc, str);
+       strcpy(good_string, good);
+       strcpy(bad_string, bad);
+       strcpy(neutral_string, neutral);
+}
+
+
+tunable::tunable(void)
+{
+       score = 0;
+       desc[0] = 0;
+       strcpy(good_string, _("Good"));
+       strcpy(bad_string, _("Bad"));
+       strcpy(neutral_string, _("Unknown"));
+}
diff --git a/src/tuning/tunable.h b/src/tuning/tunable.h
new file mode 100644 (file)
index 0000000..3372378
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ *     Arjan van de Ven <arjan@linux.intel.com>
+ */
+#ifndef _INCLUDE_GUARD_TUNABLE_H
+#define _INCLUDE_GUARD_TUNABLE_H
+
+#include <vector>
+
+#include "../lib.h"
+
+using namespace std;
+
+#define TUNE_GOOD    1
+#define TUNE_BAD     -1
+#define TUNE_UNFIXABLE -2
+#define TUNE_UNKNOWN 0
+#define TUNE_NEUTRAL 0
+
+class tunable {
+
+       char good_string[128];
+       char bad_string[128];
+       char neutral_string[128];
+protected:
+       char toggle_good[4096];
+       char toggle_bad[4096];
+public:
+       char desc[4096];
+       double score;
+
+       tunable(void);
+       tunable(const char *str, double _score, const char *good = "", const char *bad = "", const char *neutral ="");
+       virtual ~tunable() {};
+
+       virtual int good_bad(void) { return TUNE_NEUTRAL; }
+
+       virtual char *result_string(void)
+       {
+               switch (good_bad()) {
+               case TUNE_GOOD:
+                       return good_string;
+               case TUNE_BAD:
+               case TUNE_UNFIXABLE:
+                       return bad_string;
+               }
+               return neutral_string;
+       }
+
+
+       virtual const char *description(void) { return desc; };
+
+       virtual void toggle(void) { };
+
+       virtual const char *toggle_script(void) { return NULL; }
+};
+
+extern vector<class tunable *> all_tunables;
+extern vector<class tunable *> all_untunables;
+
+#endif
diff --git a/src/tuning/tuning.cpp b/src/tuning/tuning.cpp
new file mode 100644 (file)
index 0000000..08d8251
--- /dev/null
@@ -0,0 +1,275 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ *     Arjan van de Ven <arjan@linux.intel.com>
+ */
+
+#include <algorithm>
+
+#include <stdio.h>
+#include <string.h>
+#include <ncurses.h>
+
+
+#include "tuning.h"
+#include "tuningsysfs.h"
+#include "tuningusb.h"
+#include "runtime.h"
+#include "bluetooth.h"
+#include "cpufreq.h"
+#include "ethernet.h"
+#include "wifi.h"
+#include "../display.h"
+#include "../report/report.h"
+#include "../report/report-maker.h"
+#include "../lib.h"
+
+static void sort_tunables(void);
+static bool should_clear = false;
+
+class tuning_window: public tab_window {
+public:
+       virtual void repaint(void);
+       virtual void cursor_enter(void);
+       virtual void expose(void);
+       virtual void window_refresh(void);
+};
+
+static void init_tuning(void)
+{
+       add_sysfs_tunable(_("Enable Audio codec power management"), "/sys/module/snd_hda_intel/parameters/power_save", "1");
+       add_sysfs_tunable(_("NMI watchdog should be turned off"), "/proc/sys/kernel/nmi_watchdog", "0");
+       add_sysfs_tunable(_("Power Aware CPU scheduler"), "/sys/devices/system/cpu/sched_mc_power_savings", "1");
+       add_sysfs_tunable(_("VM writeback timeout"), "/proc/sys/vm/dirty_writeback_centisecs", "1500");
+       add_sata_tunables();
+       add_usb_tunables();
+       add_runtime_tunables("pci");
+       add_ethernet_tunable();
+       add_bt_tunable();
+       add_wifi_tunables();
+       add_cpufreq_tunable();
+
+       sort_tunables();
+}
+
+void initialize_tuning(void)
+{
+       class tuning_window *w;
+
+       w = new tuning_window();
+       create_tab("Tunables", _("Tunables"), w, _(" <ESC> Exit | <Enter> Toggle tunable | <r> Window refresh"));
+
+       init_tuning();
+
+       w->cursor_max = all_tunables.size() - 1;
+}
+
+
+
+static void __tuning_update_display(int cursor_pos)
+{
+       WINDOW *win;
+       unsigned int i;
+
+       win = get_ncurses_win("Tunables");
+
+       if (!win)
+               return;
+
+       if (should_clear) {
+               should_clear = false;
+               wclear(win);
+       }
+
+       wmove(win, 2,0);
+
+       for (i = 0; i < all_tunables.size(); i++) {
+               char res[128];
+               char desc[4096];
+               strcpy(res, all_tunables[i]->result_string());
+               strcpy(desc, all_tunables[i]->description());
+               while (strlen(res) < 12)
+                       strcat(res, " ");
+
+               while (strlen(desc) < 103)
+                       strcat(desc, " ");
+               if ((int)i != cursor_pos) {
+                       wattrset(win, A_NORMAL);
+                       wprintw(win, "   ");
+               } else {
+                       wattrset(win, A_REVERSE);
+                       wprintw(win, ">> ");
+               }
+               wprintw(win, "%s  %s\n", _(res), _(desc));
+       }
+}
+
+void tuning_update_display(void)
+{
+       class tab_window *w;
+
+       w = tab_windows["Tunables"];
+       if (!w)
+               return;
+       w->repaint();
+}
+
+void tuning_window::repaint(void)
+{
+       __tuning_update_display(cursor_pos);
+}
+
+void tuning_window::cursor_enter(void)
+{
+       class tunable *tun;
+
+       tun = all_tunables[cursor_pos];
+       if (!tun)
+               return;
+       tun->toggle();
+}
+
+static bool tunables_sort(class tunable * i, class tunable * j)
+{
+       int i_g, j_g;
+       double d;
+
+       i_g = i->good_bad();
+       j_g = j->good_bad();
+
+       if (!equals(i_g, j_g))
+               return i_g < j_g;
+
+       d = i->score - j->score;
+       if (d < 0.0)
+               d = -d;
+       if (d > 0.0001)
+               return i->score > j->score;
+
+       if (strcasecmp(i->description(), j->description()) == -1)
+               return true;
+
+       return false;
+}
+
+void tuning_window::window_refresh()
+{
+       clear_tuning();
+       should_clear = true;
+       init_tuning();
+}
+
+static void sort_tunables(void)
+{
+       sort(all_tunables.begin(), all_tunables.end(), tunables_sort);
+}
+
+void tuning_window::expose(void)
+{
+       cursor_pos = 0;
+       sort_tunables();
+       repaint();
+}
+
+void report_show_tunables(void)
+{
+       unsigned int i;
+       bool is_header;
+       /* three tables; bad, unfixable, good */
+
+       sort_tunables();
+       report.begin_section(SECTION_TUNING);
+
+       for (is_header = true, i = 0; i < all_tunables.size(); i++) {
+               int gb;
+
+               gb = all_tunables[i]->good_bad();
+               if (gb != TUNE_BAD)
+                       continue;
+
+               if (is_header) {
+                       report.add_header("Software Settings in need of Tuning");
+                       report.begin_table(TABLE_WIDE);
+                       report.begin_row();
+                       report.begin_cell(CELL_TUNABLE_HEADER);
+                       report.add("Description");
+                       report.begin_cell(CELL_TUNABLE_HEADER);
+                       report.add("Script");
+                       is_header = false;
+               }
+
+               report.begin_row(ROW_TUNABLE_BAD);
+               report.begin_cell();
+               report.add(all_tunables[i]->description());
+               report.begin_cell();
+               report.add(all_tunables[i]->toggle_script());
+       }
+
+       for (i = 0, is_header = true; i < all_untunables.size(); i++) {
+               if (is_header) {
+                       report.add_header("Untunable Software Issues");
+                       report.begin_table(TABLE_WIDE);
+                       report.begin_row();
+                       report.begin_cell(CELL_TUNABLE_HEADER);
+                       report.add("Description");
+                       is_header = false;
+               }
+
+               report.begin_row(ROW_TUNABLE_BAD);
+               report.begin_cell();
+               report.add(all_untunables[i]->description());
+       }
+
+       for (i = 0, is_header = true; i < all_tunables.size(); i++) {
+               int gb;
+
+               gb = all_tunables[i]->good_bad();
+               if (gb != TUNE_GOOD)
+                       continue;
+
+               if (is_header) {
+                       report.add_header("Optimal Tuned Software Settings");
+                       report.begin_table(TABLE_WIDE);
+                       report.begin_row();
+                       report.begin_cell(CELL_TUNABLE_HEADER);
+                       report.add("Description");
+                       is_header = false;
+               }
+
+               report.begin_row(ROW_TUNABLE);
+               report.begin_cell();
+               report.add(all_tunables[i]->description());
+       }
+}
+
+void clear_tuning()
+{
+       for (size_t i = 0; i < all_tunables.size(); i++) {
+               delete all_tunables[i];
+       }
+       all_tunables.clear();
+
+       for (size_t i = 0; i < all_untunables.size(); i++) {
+               delete all_untunables[i];
+       }
+       all_untunables.clear();
+}
diff --git a/src/tuning/tuning.h b/src/tuning/tuning.h
new file mode 100644 (file)
index 0000000..7c4921f
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ *     Arjan van de Ven <arjan@linux.intel.com>
+ */
+#ifndef _INCLUDE_GUARD_TUNING_H
+#define _INCLUDE_GUARD_TUNING_H
+
+extern void initialize_tuning(void);
+extern void tuning_update_display(void);
+extern void report_show_tunables(void);
+extern void clear_tuning(void);
+
+
+
+#endif
diff --git a/src/tuning/tuningsysfs.cpp b/src/tuning/tuningsysfs.cpp
new file mode 100644 (file)
index 0000000..ec1ca6b
--- /dev/null
@@ -0,0 +1,146 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ *     Arjan van de Ven <arjan@linux.intel.com>
+ */
+
+#include "tuning.h"
+#include "tunable.h"
+#include "unistd.h"
+#include "tuningsysfs.h"
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <utility>
+#include <iostream>
+#include <fstream>
+#include <unistd.h>
+#include <sys/types.h>
+#include <dirent.h>
+
+
+#include "../lib.h"
+
+sysfs_tunable::sysfs_tunable(const char *str, const char *_sysfs_path, const char *_target_content) : tunable(str, 1.0, _("Good"), _("Bad"), _("Unknown"))
+{
+       strcpy(sysfs_path, _sysfs_path);
+       strcpy(target_value, _target_content);
+       bad_value[0] = 0;
+       sprintf(toggle_good, "echo '%s' > '%s';", target_value, sysfs_path);
+       sprintf(toggle_bad, "echo '%s' > '%s';", bad_value, sysfs_path);
+}
+
+int sysfs_tunable::good_bad(void)
+{
+       char current_value[4096], *c;
+       ifstream file;
+
+       file.open(sysfs_path, ios::in);
+       if (!file)
+               return TUNE_NEUTRAL;
+       file.getline(current_value, 4096);
+       file.close();
+
+       c = strchr(current_value, '\n');
+       if (c)
+               *c = 0;
+
+       if (strcmp(current_value, target_value) == 0)
+               return TUNE_GOOD;
+
+       strcpy(bad_value, current_value);
+       return TUNE_BAD;
+}
+
+void sysfs_tunable::toggle(void)
+{
+       int good;
+       good = good_bad();
+
+       if (good == TUNE_GOOD) {
+               if (strlen(bad_value) > 0)
+                       write_sysfs(sysfs_path, bad_value);
+               return;
+       }
+
+       write_sysfs(sysfs_path, target_value);
+}
+
+const char *sysfs_tunable::toggle_script(void) {
+       int good;
+       good = good_bad();
+
+       if (good == TUNE_GOOD) {
+               if (strlen(bad_value) > 0)
+                       return toggle_bad;
+               return NULL;
+       }
+
+       return toggle_good;
+}
+
+
+void add_sysfs_tunable(const char *str, const char *_sysfs_path, const char *_target_content)
+{
+       class sysfs_tunable *tunable;
+
+       if (access(_sysfs_path, R_OK) != 0)
+               return;
+
+       tunable = new class sysfs_tunable(str, _sysfs_path, _target_content);
+
+
+       all_tunables.push_back(tunable);
+}
+
+void add_sata_tunables(void)
+{
+       struct dirent *entry;
+       DIR *dir;
+       char filename[4096];
+       char msg[4096];
+
+       dir = opendir("/sys/class/scsi_host");
+
+       if (!dir)
+               return;
+
+        while (1) {
+               entry = readdir(dir);
+
+               if (!entry)
+                       break;
+
+               if (entry->d_name[0] == '.')
+                       continue;
+
+               sprintf(filename, "/sys/class/scsi_host/%s/link_power_management_policy", entry->d_name);
+
+               sprintf(msg, _("Enable SATA link power Managmenet for %s"),entry->d_name);
+
+               add_sysfs_tunable(msg, filename,"min_power");
+
+        }
+
+        closedir(dir);
+}
diff --git a/src/tuning/tuningsysfs.h b/src/tuning/tuningsysfs.h
new file mode 100644 (file)
index 0000000..ad89717
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ *     Arjan van de Ven <arjan@linux.intel.com>
+ */
+#ifndef _INCLUDE_GUARD_SYSFS_TUNE_H
+#define _INCLUDE_GUARD_SYSFS_TUNE_H
+
+#include <vector>
+
+#include "tunable.h"
+
+using namespace std;
+
+class sysfs_tunable : public tunable {
+       char sysfs_path[4096];
+       char target_value[4096];
+       char bad_value[4096];
+public:
+       sysfs_tunable(const char *str, const char *sysfs_path, const char *target_content);
+
+       virtual int good_bad(void);
+
+       virtual void toggle(void);
+
+       virtual const char *toggle_script(void);
+
+};
+
+extern void add_sysfs_tunable(const char *str, const char *_sysfs_path, const char *_target_content);
+extern void add_sata_tunables(void);
+
+#endif
diff --git a/src/tuning/tuningusb.cpp b/src/tuning/tuningusb.cpp
new file mode 100644 (file)
index 0000000..74bbacf
--- /dev/null
@@ -0,0 +1,155 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ *     Arjan van de Ven <arjan@linux.intel.com>
+ */
+
+#include "tuning.h"
+#include "tunable.h"
+#include "unistd.h"
+#include "tuningusb.h"
+#include <string.h>
+#include <utility>
+#include <iostream>
+#include <fstream>
+#include <unistd.h>
+#include <sys/types.h>
+#include <dirent.h>
+
+#include "../lib.h"
+
+usb_tunable::usb_tunable(const char *path, const char *name) : tunable("", 0.9, _("Good"), _("Bad"), _("Unknown"))
+{
+       ifstream file;
+       char filename[4096];
+       char vendor[2048];
+       char product[2048];
+       string str1, str2;
+       sprintf(usb_path, "%s/power/control", path);
+
+       vendor[0] = 0;
+       product[0] = 0;
+
+       str1 = read_sysfs_string("%s/idVendor", path);
+       str2 = read_sysfs_string("%s/idProduct", path);
+
+       sprintf(desc, _("Autosuspend for unknown USB device %s (%s:%s)"), name, str1.c_str(), str2.c_str());
+
+       sprintf(filename, "%s/manufacturer", path);
+       file.open(filename, ios::in);
+       if (file) {
+               file.getline(vendor, 2047);
+               if (strstr(vendor, "Linux "))
+                       vendor[0] = 0;
+               file.close();
+       };
+       sprintf(filename, "%s/product", path);
+       file.open(filename, ios::in);
+       if (file) {
+               file.getline(product, 2040);
+               file.close();
+       };
+       if (strlen(vendor) && strlen(product))
+               sprintf(desc, _("Autosuspend for USB device %s [%s]"), product, vendor);
+       else if (strlen(product))
+               sprintf(desc, _("Autosuspend for USB device %s [%s]"), product, name);
+       else if (strlen(vendor))
+               sprintf(desc, _("Autosuspend for USB device %s [%s]"), vendor, name);
+
+       sprintf(toggle_good, "echo 'auto' > '%s';", usb_path);
+       sprintf(toggle_bad, "echo 'on' > '%s';", usb_path);
+}
+
+int usb_tunable::good_bad(void)
+{
+       string content;
+
+       content = read_sysfs_string(usb_path);
+
+       if (strcmp(content.c_str(), "auto") == 0)
+               return TUNE_GOOD;
+
+       return TUNE_BAD;
+}
+
+void usb_tunable::toggle(void)
+{
+       int good;
+       good = good_bad();
+
+       if (good == TUNE_GOOD) {
+               write_sysfs(usb_path, "on");
+               return;
+       }
+
+       write_sysfs(usb_path, "auto");
+}
+
+const char *usb_tunable::toggle_script(void)
+{
+       int good;
+       good = good_bad();
+
+       if (good == TUNE_GOOD) {
+               return toggle_bad;
+       }
+
+       return toggle_good;
+}
+
+void add_usb_tunables(void)
+{
+       struct dirent *entry;
+       DIR *dir;
+       char filename[4096];
+
+       dir = opendir("/sys/bus/usb/devices/");
+       if (!dir)
+               return;
+       while (1) {
+               class usb_tunable *usb;
+
+               entry = readdir(dir);
+
+               if (!entry)
+                       break;
+               if (entry->d_name[0] == '.')
+                       continue;
+
+               sprintf(filename, "/sys/bus/usb/devices/%s/power/control", entry->d_name);
+
+               if (access(filename, R_OK) != 0)
+                       continue;
+
+               sprintf(filename, "/sys/bus/usb/devices/%s/power/active_duration", entry->d_name);
+               if (access(filename, R_OK)!=0)
+                       continue;
+
+               sprintf(filename, "/sys/bus/usb/devices/%s", entry->d_name);
+
+               usb = new class usb_tunable(filename, entry->d_name);
+
+               all_tunables.push_back(usb);
+
+       }
+       closedir(dir);
+}
diff --git a/src/tuning/tuningusb.h b/src/tuning/tuningusb.h
new file mode 100644 (file)
index 0000000..a257904
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ *     Arjan van de Ven <arjan@linux.intel.com>
+ */
+#ifndef _INCLUDE_GUARD_USB_TUNE_H
+#define _INCLUDE_GUARD_USB_TUNE_H
+
+#include <vector>
+
+#include "tunable.h"
+
+using namespace std;
+
+class usb_tunable : public tunable {
+       char usb_path[4096];
+public:
+       usb_tunable(const char *usb_path, const char *path);
+
+       virtual int good_bad(void);
+
+       virtual void toggle(void);
+
+       virtual const char *toggle_script(void);
+
+};
+
+extern void add_usb_tunables(void);
+
+
+#endif
diff --git a/src/tuning/wifi.cpp b/src/tuning/wifi.cpp
new file mode 100644 (file)
index 0000000..77cdfcc
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ *     Arjan van de Ven <arjan@linux.intel.com>
+ */
+
+#include "tuning.h"
+#include "tunable.h"
+#include "unistd.h"
+#include "wifi.h"
+#include <string.h>
+#include <utility>
+#include <iostream>
+#include <fstream>
+#include <unistd.h>
+#include <sys/types.h>
+#include <dirent.h>
+
+#include "../lib.h"
+
+extern "C" {
+#include "iw.h"
+}
+
+
+wifi_tunable::wifi_tunable(const char *_iface) : tunable("", 1.5, _("Good"), _("Bad"), _("Unknown"))
+{
+       strcpy(iface, _iface);
+       sprintf(desc, _("Wireless Power Saving for interface %s"), iface);
+
+       sprintf(toggle_good, "iw dev %s set power_save on", iface);
+       sprintf(toggle_bad, "iw dev %s set power_save off", iface);
+}
+
+int wifi_tunable::good_bad(void)
+{
+       if (get_wifi_power_saving(iface))
+               return TUNE_GOOD;
+
+       return TUNE_BAD;
+}
+
+void wifi_tunable::toggle(void)
+{
+       int good;
+       good = good_bad();
+
+       if (good == TUNE_GOOD) {
+               set_wifi_power_saving(iface, 0);
+               return;
+       }
+
+       set_wifi_power_saving(iface, 1);
+}
+
+const char *wifi_tunable::toggle_script(void)
+{
+       int good;
+       good = good_bad();
+
+       if (good == TUNE_GOOD) {
+               return toggle_bad;
+       }
+
+       return toggle_good;
+}
+
+void add_wifi_tunables(void)
+{
+       struct dirent *entry;
+       DIR *dir;
+       char* wlan_name;
+       class wifi_tunable *wifi;
+
+
+       dir = opendir("/sys/class/net/");
+       if (!dir)
+               return;
+       while (1) {
+               entry = readdir(dir);
+               if (!entry)
+                       break;
+               wlan_name = strstr(entry->d_name, "wlan");
+               if (wlan_name) {
+                       wifi = new class wifi_tunable(wlan_name);
+                       all_tunables.push_back(wifi);
+               }
+       
+       }
+
+       closedir(dir);
+
+}
diff --git a/src/tuning/wifi.h b/src/tuning/wifi.h
new file mode 100644 (file)
index 0000000..50ca68c
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ *     Arjan van de Ven <arjan@linux.intel.com>
+ */
+#ifndef _INCLUDE_GUARD_WIFI_TUNE_H
+#define _INCLUDE_GUARD_WIFI_TUNE_H
+
+#include <vector>
+
+#include "tunable.h"
+
+using namespace std;
+
+class wifi_tunable : public tunable {
+       char iface[4096];
+public:
+       wifi_tunable(const char *_iface);
+
+       virtual int good_bad(void);
+
+       virtual void toggle(void);
+
+       virtual const char *toggle_script(void);
+
+};
+
+extern void add_wifi_tunables(void);
+
+
+#endif
diff --git a/traceevent/Makefile.am b/traceevent/Makefile.am
new file mode 100644 (file)
index 0000000..d3ee608
--- /dev/null
@@ -0,0 +1,7 @@
+noinst_LTLIBRARIES = libtraceevnet.la
+libtraceevnet_la_SOURCES = event-parse.c \
+                       event-parse.h \
+                       event-utils.h \
+                       parse-filter.c\
+                       parse-utils.c \
+                       trace-seq.c
diff --git a/traceevent/event-parse.c b/traceevent/event-parse.c
new file mode 100644 (file)
index 0000000..aa16443
--- /dev/null
@@ -0,0 +1,5269 @@
+/*
+ * Copyright (C) 2009, 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License (not later!)
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *  The parts for function graph printing was taken and modified from the
+ *  Linux Kernel that were written by
+ *    - Copyright (C) 2009  Frederic Weisbecker,
+ *  Frederic Weisbecker gave his permission to relicense the code to
+ *  the Lesser General Public License.
+ */
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include "event-parse.h"
+#include "event-utils.h"
+
+static const char *input_buf;
+static unsigned long long input_buf_ptr;
+static unsigned long long input_buf_siz;
+
+static int is_flag_field;
+static int is_symbolic_field;
+
+static int show_warning = 1;
+
+#define do_warning(fmt, ...)                           \
+       do {                                            \
+               if (show_warning)                       \
+                       warning(fmt, ##__VA_ARGS__);    \
+       } while (0)
+
+static void init_input_buf(const char *buf, unsigned long long size)
+{
+       input_buf = buf;
+       input_buf_siz = size;
+       input_buf_ptr = 0;
+}
+
+const char *pevent_get_input_buf(void)
+{
+       return input_buf;
+}
+
+unsigned long long pevent_get_input_buf_ptr(void)
+{
+       return input_buf_ptr;
+}
+
+struct event_handler {
+       struct event_handler            *next;
+       int                             id;
+       const char                      *sys_name;
+       const char                      *event_name;
+       pevent_event_handler_func       func;
+       void                            *context;
+};
+
+struct pevent_func_params {
+       struct pevent_func_params       *next;
+       enum pevent_func_arg_type       type;
+};
+
+struct pevent_function_handler {
+       struct pevent_function_handler  *next;
+       enum pevent_func_arg_type       ret_type;
+       char                            *name;
+       pevent_func_handler             func;
+       struct pevent_func_params       *params;
+       int                             nr_args;
+};
+
+static unsigned long long
+process_defined_func(struct trace_seq *s, void *data, int size,
+                    struct event_format *event, struct print_arg *arg);
+
+static void free_func_handle(struct pevent_function_handler *func);
+
+/**
+ * pevent_buffer_init - init buffer for parsing
+ * @buf: buffer to parse
+ * @size: the size of the buffer
+ *
+ * For use with pevent_read_token(), this initializes the internal
+ * buffer that pevent_read_token() will parse.
+ */
+void pevent_buffer_init(const char *buf, unsigned long long size)
+{
+       init_input_buf(buf, size);
+}
+
+void breakpoint(void)
+{
+       static int x;
+       x++;
+}
+
+struct print_arg *alloc_arg(void)
+{
+       struct print_arg *arg;
+
+       arg = malloc_or_die(sizeof(*arg));
+       if (!arg)
+               return NULL;
+       memset(arg, 0, sizeof(*arg));
+
+       return arg;
+}
+
+struct cmdline {
+       char *comm;
+       int pid;
+};
+
+static int cmdline_cmp(const void *a, const void *b)
+{
+       const struct cmdline *ca = a;
+       const struct cmdline *cb = b;
+
+       if (ca->pid < cb->pid)
+               return -1;
+       if (ca->pid > cb->pid)
+               return 1;
+
+       return 0;
+}
+
+struct cmdline_list {
+       struct cmdline_list     *next;
+       char                    *comm;
+       int                     pid;
+};
+
+static int cmdline_init(struct pevent *pevent)
+{
+       struct cmdline_list *cmdlist = pevent->cmdlist;
+       struct cmdline_list *item;
+       struct cmdline *cmdlines;
+       int i;
+
+       cmdlines = malloc_or_die(sizeof(*cmdlines) * pevent->cmdline_count);
+
+       i = 0;
+       while (cmdlist) {
+               cmdlines[i].pid = cmdlist->pid;
+               cmdlines[i].comm = cmdlist->comm;
+               i++;
+               item = cmdlist;
+               cmdlist = cmdlist->next;
+               free(item);
+       }
+
+       qsort(cmdlines, pevent->cmdline_count, sizeof(*cmdlines), cmdline_cmp);
+
+       pevent->cmdlines = cmdlines;
+       pevent->cmdlist = NULL;
+
+       return 0;
+}
+
+static char *find_cmdline(struct pevent *pevent, int pid)
+{
+       const struct cmdline *comm;
+       struct cmdline key;
+
+       if (!pid)
+               return "<idle>";
+
+       if (!pevent->cmdlines)
+               cmdline_init(pevent);
+
+       key.pid = pid;
+
+       comm = bsearch(&key, pevent->cmdlines, pevent->cmdline_count,
+                      sizeof(*pevent->cmdlines), cmdline_cmp);
+
+       if (comm)
+               return comm->comm;
+       return "<...>";
+}
+
+/**
+ * pevent_pid_is_registered - return if a pid has a cmdline registered
+ * @pevent: handle for the pevent
+ * @pid: The pid to check if it has a cmdline registered with.
+ *
+ * Returns 1 if the pid has a cmdline mapped to it
+ * 0 otherwise.
+ */
+int pevent_pid_is_registered(struct pevent *pevent, int pid)
+{
+       const struct cmdline *comm;
+       struct cmdline key;
+
+       if (!pid)
+               return 1;
+
+       if (!pevent->cmdlines)
+               cmdline_init(pevent);
+
+       key.pid = pid;
+
+       comm = bsearch(&key, pevent->cmdlines, pevent->cmdline_count,
+                      sizeof(*pevent->cmdlines), cmdline_cmp);
+
+       if (comm)
+               return 1;
+       return 0;
+}
+
+/*
+ * If the command lines have been converted to an array, then
+ * we must add this pid. This is much slower than when cmdlines
+ * are added before the array is initialized.
+ */
+static int add_new_comm(struct pevent *pevent, const char *comm, int pid)
+{
+       struct cmdline *cmdlines = pevent->cmdlines;
+       const struct cmdline *cmdline;
+       struct cmdline key;
+
+       if (!pid)
+               return 0;
+
+       /* avoid duplicates */
+       key.pid = pid;
+
+       cmdline = bsearch(&key, pevent->cmdlines, pevent->cmdline_count,
+                      sizeof(*pevent->cmdlines), cmdline_cmp);
+       if (cmdline) {
+               errno = EEXIST;
+               return -1;
+       }
+
+       cmdlines = realloc(cmdlines, sizeof(*cmdlines) * (pevent->cmdline_count + 1));
+       if (!cmdlines) {
+               errno = ENOMEM;
+               return -1;
+       }
+
+       cmdlines[pevent->cmdline_count].pid = pid;
+       cmdlines[pevent->cmdline_count].comm = strdup(comm);
+       if (!cmdlines[pevent->cmdline_count].comm)
+               die("malloc comm");
+               
+       if (cmdlines[pevent->cmdline_count].comm)
+               pevent->cmdline_count++;
+
+       qsort(cmdlines, pevent->cmdline_count, sizeof(*cmdlines), cmdline_cmp);
+       pevent->cmdlines = cmdlines;
+
+       return 0;
+}
+
+/**
+ * pevent_register_comm - register a pid / comm mapping
+ * @pevent: handle for the pevent
+ * @comm: the command line to register
+ * @pid: the pid to map the command line to
+ *
+ * This adds a mapping to search for command line names with
+ * a given pid. The comm is duplicated.
+ */
+int pevent_register_comm(struct pevent *pevent, const char *comm, int pid)
+{
+       struct cmdline_list *item;
+
+       if (pevent->cmdlines)
+               return add_new_comm(pevent, comm, pid);
+
+       item = malloc_or_die(sizeof(*item));
+       item->comm = strdup(comm);
+       if (!item->comm)
+               die("malloc comm");
+       item->pid = pid;
+       item->next = pevent->cmdlist;
+
+       pevent->cmdlist = item;
+       pevent->cmdline_count++;
+
+       return 0;
+}
+
+struct func_map {
+       unsigned long long              addr;
+       char                            *func;
+       char                            *mod;
+};
+
+struct func_list {
+       struct func_list        *next;
+       unsigned long long      addr;
+       char                    *func;
+       char                    *mod;
+};
+
+static int func_cmp(const void *a, const void *b)
+{
+       const struct func_map *fa = a;
+       const struct func_map *fb = b;
+
+       if (fa->addr < fb->addr)
+               return -1;
+       if (fa->addr > fb->addr)
+               return 1;
+
+       return 0;
+}
+
+/*
+ * We are searching for a record in between, not an exact
+ * match.
+ */
+static int func_bcmp(const void *a, const void *b)
+{
+       const struct func_map *fa = a;
+       const struct func_map *fb = b;
+
+       if ((fa->addr == fb->addr) ||
+
+           (fa->addr > fb->addr &&
+            fa->addr < (fb+1)->addr))
+               return 0;
+
+       if (fa->addr < fb->addr)
+               return -1;
+
+       return 1;
+}
+
+static int func_map_init(struct pevent *pevent)
+{
+       struct func_list *funclist;
+       struct func_list *item;
+       struct func_map *func_map;
+       int i;
+
+       func_map = malloc_or_die(sizeof(*func_map) * (pevent->func_count + 1));
+       funclist = pevent->funclist;
+
+       i = 0;
+       while (funclist) {
+               func_map[i].func = funclist->func;
+               func_map[i].addr = funclist->addr;
+               func_map[i].mod = funclist->mod;
+               i++;
+               item = funclist;
+               funclist = funclist->next;
+               free(item);
+       }
+
+       qsort(func_map, pevent->func_count, sizeof(*func_map), func_cmp);
+
+       /*
+        * Add a special record at the end.
+        */
+       func_map[pevent->func_count].func = NULL;
+       func_map[pevent->func_count].addr = 0;
+       func_map[pevent->func_count].mod = NULL;
+
+       pevent->func_map = func_map;
+       pevent->funclist = NULL;
+
+       return 0;
+}
+
+static struct func_map *
+find_func(struct pevent *pevent, unsigned long long addr)
+{
+       struct func_map *func;
+       struct func_map key;
+
+       if (!pevent->func_map)
+               func_map_init(pevent);
+
+       key.addr = addr;
+
+       func = bsearch(&key, pevent->func_map, pevent->func_count,
+                      sizeof(*pevent->func_map), func_bcmp);
+
+       return func;
+}
+
+/**
+ * pevent_find_function - find a function by a given address
+ * @pevent: handle for the pevent
+ * @addr: the address to find the function with
+ *
+ * Returns a pointer to the function stored that has the given
+ * address. Note, the address does not have to be exact, it
+ * will select the function that would contain the address.
+ */
+const char *pevent_find_function(struct pevent *pevent, unsigned long long addr)
+{
+       struct func_map *map;
+
+       map = find_func(pevent, addr);
+       if (!map)
+               return NULL;
+
+       return map->func;
+}
+
+/**
+ * pevent_find_function_address - find a function address by a given address
+ * @pevent: handle for the pevent
+ * @addr: the address to find the function with
+ *
+ * Returns the address the function starts at. This can be used in
+ * conjunction with pevent_find_function to print both the function
+ * name and the function offset.
+ */
+unsigned long long
+pevent_find_function_address(struct pevent *pevent, unsigned long long addr)
+{
+       struct func_map *map;
+
+       map = find_func(pevent, addr);
+       if (!map)
+               return 0;
+
+       return map->addr;
+}
+
+/**
+ * pevent_register_function - register a function with a given address
+ * @pevent: handle for the pevent
+ * @function: the function name to register
+ * @addr: the address the function starts at
+ * @mod: the kernel module the function may be in (NULL for none)
+ *
+ * This registers a function name with an address and module.
+ * The @func passed in is duplicated.
+ */
+int pevent_register_function(struct pevent *pevent, char *func,
+                            unsigned long long addr, char *mod)
+{
+       struct func_list *item;
+
+       item = malloc_or_die(sizeof(*item));
+
+       item->next = pevent->funclist;
+       item->func = strdup(func);
+       if (mod)
+               item->mod = strdup(mod);
+       else
+               item->mod = NULL;
+       item->addr = addr;
+
+       if (!item->func || (mod && !item->mod))
+               die("malloc func");
+
+       pevent->funclist = item;
+       pevent->func_count++;
+
+       return 0;
+}
+
+/**
+ * pevent_print_funcs - print out the stored functions
+ * @pevent: handle for the pevent
+ *
+ * This prints out the stored functions.
+ */
+void pevent_print_funcs(struct pevent *pevent)
+{
+       int i;
+
+       if (!pevent->func_map)
+               func_map_init(pevent);
+
+       for (i = 0; i < (int)pevent->func_count; i++) {
+               printf("%016llx %s",
+                      pevent->func_map[i].addr,
+                      pevent->func_map[i].func);
+               if (pevent->func_map[i].mod)
+                       printf(" [%s]\n", pevent->func_map[i].mod);
+               else
+                       printf("\n");
+       }
+}
+
+struct printk_map {
+       unsigned long long              addr;
+       char                            *printk;
+};
+
+struct printk_list {
+       struct printk_list      *next;
+       unsigned long long      addr;
+       char                    *printk;
+};
+
+static int printk_cmp(const void *a, const void *b)
+{
+       const struct printk_map *pa = a;
+       const struct printk_map *pb = b;
+
+       if (pa->addr < pb->addr)
+               return -1;
+       if (pa->addr > pb->addr)
+               return 1;
+
+       return 0;
+}
+
+static void printk_map_init(struct pevent *pevent)
+{
+       struct printk_list *printklist;
+       struct printk_list *item;
+       struct printk_map *printk_map;
+       int i;
+
+       printk_map = malloc_or_die(sizeof(*printk_map) * (pevent->printk_count + 1));
+
+       printklist = pevent->printklist;
+
+       i = 0;
+       while (printklist) {
+               printk_map[i].printk = printklist->printk;
+               printk_map[i].addr = printklist->addr;
+               i++;
+               item = printklist;
+               printklist = printklist->next;
+               free(item);
+       }
+
+       qsort(printk_map, pevent->printk_count, sizeof(*printk_map), printk_cmp);
+
+       pevent->printk_map = printk_map;
+       pevent->printklist = NULL;
+}
+
+static struct printk_map *
+find_printk(struct pevent *pevent, unsigned long long addr)
+{
+       struct printk_map *printk;
+       struct printk_map key;
+
+       if (!pevent->printk_map)
+               printk_map_init(pevent);
+
+       key.addr = addr;
+
+       printk = bsearch(&key, pevent->printk_map, pevent->printk_count,
+                        sizeof(*pevent->printk_map), printk_cmp);
+
+       return printk;
+}
+
+/**
+ * pevent_register_print_string - register a string by its address
+ * @pevent: handle for the pevent
+ * @fmt: the string format to register
+ * @addr: the address the string was located at
+ *
+ * This registers a string by the address it was stored in the kernel.
+ * The @fmt passed in is duplicated.
+ */
+int pevent_register_print_string(struct pevent *pevent, char *fmt,
+                                unsigned long long addr)
+{
+       struct printk_list *item;
+
+       item = malloc_or_die(sizeof(*item));
+
+       item->next = pevent->printklist;
+       item->printk = strdup(fmt);
+       item->addr = addr;
+
+       if (!item->printk)
+               die("malloc fmt");
+
+       pevent->printklist = item;
+       pevent->printk_count++;
+
+       return 0;
+}
+
+/**
+ * pevent_print_printk - print out the stored strings
+ * @pevent: handle for the pevent
+ *
+ * This prints the string formats that were stored.
+ */
+void pevent_print_printk(struct pevent *pevent)
+{
+       int i;
+
+       if (!pevent->printk_map)
+               printk_map_init(pevent);
+
+       for (i = 0; i < (int)pevent->printk_count; i++) {
+               printf("%016llx %s\n",
+                      pevent->printk_map[i].addr,
+                      pevent->printk_map[i].printk);
+       }
+}
+
+static struct event_format *alloc_event(void)
+{
+       struct event_format *event;
+
+       event = malloc(sizeof(*event));
+       if (!event)
+               return NULL;
+       memset(event, 0, sizeof(*event));
+
+       return event;
+}
+
+static void add_event(struct pevent *pevent, struct event_format *event)
+{
+       int i;
+
+       pevent->events = realloc(pevent->events, sizeof(event) *
+                                (pevent->nr_events + 1));
+       if (!pevent->events)
+               die("Can not allocate events");
+
+       for (i = 0; i < pevent->nr_events; i++) {
+               if (pevent->events[i]->id > event->id)
+                       break;
+       }
+       if (i < pevent->nr_events)
+               memmove(&pevent->events[i + 1],
+                       &pevent->events[i],
+                       sizeof(event) * (pevent->nr_events - i));
+
+       pevent->events[i] = event;
+       pevent->nr_events++;
+
+       event->pevent = pevent;
+}
+
+static int event_item_type(enum event_type type)
+{
+       switch (type) {
+       case EVENT_ITEM ... EVENT_SQUOTE:
+               return 1;
+       case EVENT_ERROR ... EVENT_DELIM:
+       default:
+               return 0;
+       }
+}
+
+static void free_flag_sym(struct print_flag_sym *fsym)
+{
+       struct print_flag_sym *next;
+
+       while (fsym) {
+               next = fsym->next;
+               free(fsym->value);
+               free(fsym->str);
+               free(fsym);
+               fsym = next;
+       }
+}
+
+static void free_arg(struct print_arg *arg)
+{
+       struct print_arg *farg;
+
+       if (!arg)
+               return;
+
+       switch (arg->type) {
+       case PRINT_ATOM:
+               free(arg->atom.atom);
+               break;
+       case PRINT_FIELD:
+               free(arg->field.name);
+               break;
+       case PRINT_FLAGS:
+               free_arg(arg->flags.field);
+               free(arg->flags.delim);
+               free_flag_sym(arg->flags.flags);
+               break;
+       case PRINT_SYMBOL:
+               free_arg(arg->symbol.field);
+               free_flag_sym(arg->symbol.symbols);
+               break;
+       case PRINT_HEX:
+               free_arg(arg->hex.field);
+               free_arg(arg->hex.size);
+               break;
+       case PRINT_TYPE:
+               free(arg->typecast.type);
+               free_arg(arg->typecast.item);
+               break;
+       case PRINT_STRING:
+       case PRINT_BSTRING:
+               free(arg->string.string);
+               break;
+       case PRINT_DYNAMIC_ARRAY:
+               free(arg->dynarray.index);
+               break;
+       case PRINT_OP:
+               free(arg->op.op);
+               free_arg(arg->op.left);
+               free_arg(arg->op.right);
+               break;
+       case PRINT_FUNC:
+               while (arg->func.args) {
+                       farg = arg->func.args;
+                       arg->func.args = farg->next;
+                       free_arg(farg);
+               }
+               break;
+
+       case PRINT_NULL:
+       default:
+               break;
+       }
+
+       free(arg);
+}
+
+static enum event_type get_type(int ch)
+{
+       if (ch == '\n')
+               return EVENT_NEWLINE;
+       if (isspace(ch))
+               return EVENT_SPACE;
+       if (isalnum(ch) || ch == '_')
+               return EVENT_ITEM;
+       if (ch == '\'')
+               return EVENT_SQUOTE;
+       if (ch == '"')
+               return EVENT_DQUOTE;
+       if (!isprint(ch))
+               return EVENT_NONE;
+       if (ch == '(' || ch == ')' || ch == ',')
+               return EVENT_DELIM;
+
+       return EVENT_OP;
+}
+
+static int __read_char(void)
+{
+       if (input_buf_ptr >= input_buf_siz)
+               return -1;
+
+       return input_buf[input_buf_ptr++];
+}
+
+static int __peek_char(void)
+{
+       if (input_buf_ptr >= input_buf_siz)
+               return -1;
+
+       return input_buf[input_buf_ptr];
+}
+
+/**
+ * pevent_peek_char - peek at the next character that will be read
+ *
+ * Returns the next character read, or -1 if end of buffer.
+ */
+int pevent_peek_char(void)
+{
+       return __peek_char();
+}
+
+static int extend_token(char **tok, char *buf, int size)
+{
+       char *newtok = realloc(*tok, size);
+
+       if (!newtok) {
+               free(*tok);
+               *tok = NULL;
+               return -1;
+       }
+
+       if (!*tok)
+               strcpy(newtok, buf);
+       else
+               strcat(newtok, buf);
+       *tok = newtok;
+
+       return 0;
+}
+
+static enum event_type force_token(const char *str, char **tok);
+
+static enum event_type __read_token(char **tok)
+{
+       char buf[BUFSIZ];
+       int ch, last_ch, quote_ch, next_ch;
+       int i = 0;
+       int tok_size = 0;
+       enum event_type type;
+
+       *tok = NULL;
+
+
+       ch = __read_char();
+       if (ch < 0)
+               return EVENT_NONE;
+
+       type = get_type(ch);
+       if (type == EVENT_NONE)
+               return type;
+
+       buf[i++] = ch;
+
+       switch (type) {
+       case EVENT_NEWLINE:
+       case EVENT_DELIM:
+               *tok = malloc_or_die(2);
+               (*tok)[0] = ch;
+               (*tok)[1] = 0;
+               return type;
+
+       case EVENT_OP:
+               switch (ch) {
+               case '-':
+                       next_ch = __peek_char();
+                       if (next_ch == '>') {
+                               buf[i++] = __read_char();
+                               break;
+                       }
+                       /* fall through */
+               case '+':
+               case '|':
+               case '&':
+               case '>':
+               case '<':
+                       last_ch = ch;
+                       ch = __peek_char();
+                       if (ch != last_ch)
+                               goto test_equal;
+                       buf[i++] = __read_char();
+                       switch (last_ch) {
+                       case '>':
+                       case '<':
+                               goto test_equal;
+                       default:
+                               break;
+                       }
+                       break;
+               case '!':
+               case '=':
+                       goto test_equal;
+               default: /* what should we do instead? */
+                       break;
+               }
+               buf[i] = 0;
+               *tok = strdup(buf);
+               return type;
+
+ test_equal:
+               ch = __peek_char();
+               if (ch == '=')
+                       buf[i++] = __read_char();
+               goto out;
+
+       case EVENT_DQUOTE:
+       case EVENT_SQUOTE:
+               /* don't keep quotes */
+               i--;
+               quote_ch = ch;
+               last_ch = 0;
+ concat:
+               do {
+                       if (i == (BUFSIZ - 1)) {
+                               buf[i] = 0;
+                               tok_size += BUFSIZ;
+
+                               if (extend_token(tok, buf, tok_size) < 0)
+                                       return EVENT_NONE;
+                               i = 0;
+                       }
+                       last_ch = ch;
+                       ch = __read_char();
+                       buf[i++] = ch;
+                       /* the '\' '\' will cancel itself */
+                       if (ch == '\\' && last_ch == '\\')
+                               last_ch = 0;
+               } while (ch != quote_ch || last_ch == '\\');
+               /* remove the last quote */
+               i--;
+
+               /*
+                * For strings (double quotes) check the next token.
+                * If it is another string, concatinate the two.
+                */
+               if (type == EVENT_DQUOTE) {
+                       unsigned long long save_input_buf_ptr = input_buf_ptr;
+
+                       do {
+                               ch = __read_char();
+                       } while (isspace(ch));
+                       if (ch == '"')
+                               goto concat;
+                       input_buf_ptr = save_input_buf_ptr;
+               }
+
+               goto out;
+
+       case EVENT_ERROR ... EVENT_SPACE:
+       case EVENT_ITEM:
+       default:
+               break;
+       }
+
+       while (get_type(__peek_char()) == type) {
+               if (i == (BUFSIZ - 1)) {
+                       buf[i] = 0;
+                       tok_size += BUFSIZ;
+
+                       if (extend_token(tok, buf, tok_size) < 0)
+                               return EVENT_NONE;
+                       i = 0;
+               }
+               ch = __read_char();
+               buf[i++] = ch;
+       }
+
+ out:
+       buf[i] = 0;
+       if (extend_token(tok, buf, tok_size + i + 1) < 0)
+               return EVENT_NONE;
+
+       if (type == EVENT_ITEM) {
+               /*
+                * Older versions of the kernel has a bug that
+                * creates invalid symbols and will break the mac80211
+                * parsing. This is a work around to that bug.
+                *
+                * See Linux kernel commit:
+                *  811cb50baf63461ce0bdb234927046131fc7fa8b
+                */
+               if (strcmp(*tok, "LOCAL_PR_FMT") == 0) {
+                       free(*tok);
+                       *tok = NULL;
+                       return force_token("\"\%s\" ", tok);
+               } else if (strcmp(*tok, "STA_PR_FMT") == 0) {
+                       free(*tok);
+                       *tok = NULL;
+                       return force_token("\" sta:%pM\" ", tok);
+               } else if (strcmp(*tok, "VIF_PR_FMT") == 0) {
+                       free(*tok);
+                       *tok = NULL;
+                       return force_token("\" vif:%p(%d)\" ", tok);
+               }
+       }
+
+       return type;
+}
+
+static enum event_type force_token(const char *str, char **tok)
+{
+       const char *save_input_buf;
+       unsigned long long save_input_buf_ptr;
+       unsigned long long save_input_buf_siz;
+       enum event_type type;
+       
+       /* save off the current input pointers */
+       save_input_buf = input_buf;
+       save_input_buf_ptr = input_buf_ptr;
+       save_input_buf_siz = input_buf_siz;
+
+       init_input_buf(str, strlen(str));
+
+       type = __read_token(tok);
+
+       /* reset back to original token */
+       input_buf = save_input_buf;
+       input_buf_ptr = save_input_buf_ptr;
+       input_buf_siz = save_input_buf_siz;
+
+       return type;
+}
+
+static void free_token(char *tok)
+{
+       if (tok)
+               free(tok);
+}
+
+static enum event_type read_token(char **tok)
+{
+       enum event_type type;
+
+       for (;;) {
+               type = __read_token(tok);
+               if (type != EVENT_SPACE)
+                       return type;
+
+               free_token(*tok);
+       }
+
+       /* not reached */
+       *tok = NULL;
+       return EVENT_NONE;
+}
+
+/**
+ * pevent_read_token - access to utilites to use the pevent parser
+ * @tok: The token to return
+ *
+ * This will parse tokens from the string given by
+ * pevent_init_data().
+ *
+ * Returns the token type.
+ */
+enum event_type pevent_read_token(char **tok)
+{
+       return read_token(tok);
+}
+
+/**
+ * pevent_free_token - free a token returned by pevent_read_token
+ * @token: the token to free
+ */
+void pevent_free_token(char *token)
+{
+       free_token(token);
+}
+
+/* no newline */
+static enum event_type read_token_item(char **tok)
+{
+       enum event_type type;
+
+       for (;;) {
+               type = __read_token(tok);
+               if (type != EVENT_SPACE && type != EVENT_NEWLINE)
+                       return type;
+               free_token(*tok);
+               *tok = NULL;
+       }
+
+       /* not reached */
+       *tok = NULL;
+       return EVENT_NONE;
+}
+
+static int test_type(enum event_type type, enum event_type expect)
+{
+       if (type != expect) {
+               do_warning("Error: expected type %d but read %d",
+                   expect, type);
+               return -1;
+       }
+       return 0;
+}
+
+static int test_type_token(enum event_type type, const char *token,
+                   enum event_type expect, const char *expect_tok)
+{
+       if (type != expect) {
+               do_warning("Error: expected type %d but read %d",
+                   expect, type);
+               return -1;
+       }
+
+       if (strcmp(token, expect_tok) != 0) {
+               do_warning("Error: expected '%s' but read '%s'",
+                   expect_tok, token);
+               return -1;
+       }
+       return 0;
+}
+
+static int __read_expect_type(enum event_type expect, char **tok, int newline_ok)
+{
+       enum event_type type;
+
+       if (newline_ok)
+               type = read_token(tok);
+       else
+               type = read_token_item(tok);
+       return test_type(type, expect);
+}
+
+static int read_expect_type(enum event_type expect, char **tok)
+{
+       return __read_expect_type(expect, tok, 1);
+}
+
+static int __read_expected(enum event_type expect, const char *str,
+                          int newline_ok)
+{
+       enum event_type type;
+       char *token;
+       int ret;
+
+       if (newline_ok)
+               type = read_token(&token);
+       else
+               type = read_token_item(&token);
+
+       ret = test_type_token(type, token, expect, str);
+
+       free_token(token);
+
+       return ret;
+}
+
+static int read_expected(enum event_type expect, const char *str)
+{
+       return __read_expected(expect, str, 1);
+}
+
+static int read_expected_item(enum event_type expect, const char *str)
+{
+       return __read_expected(expect, str, 0);
+}
+
+static char *event_read_name(void)
+{
+       char *token;
+
+       if (read_expected(EVENT_ITEM, "name") < 0)
+               return NULL;
+
+       if (read_expected(EVENT_OP, ":") < 0)
+               return NULL;
+
+       if (read_expect_type(EVENT_ITEM, &token) < 0)
+               goto fail;
+
+       return token;
+
+ fail:
+       free_token(token);
+       return NULL;
+}
+
+static int event_read_id(void)
+{
+       char *token;
+       int id;
+
+       if (read_expected_item(EVENT_ITEM, "ID") < 0)
+               return -1;
+
+       if (read_expected(EVENT_OP, ":") < 0)
+               return -1;
+
+       if (read_expect_type(EVENT_ITEM, &token) < 0)
+               goto fail;
+
+       id = strtoul(token, NULL, 0);
+       free_token(token);
+       return id;
+
+ fail:
+       free_token(token);
+       return -1;
+}
+
+static int field_is_string(struct format_field *field)
+{
+       if ((field->flags & FIELD_IS_ARRAY) &&
+           (strstr(field->type, "char") || strstr(field->type, "u8") ||
+            strstr(field->type, "s8")))
+               return 1;
+
+       return 0;
+}
+
+static int field_is_dynamic(struct format_field *field)
+{
+       if (strncmp(field->type, "__data_loc", 10) == 0)
+               return 1;
+
+       return 0;
+}
+
+static int field_is_long(struct format_field *field)
+{
+       /* includes long long */
+       if (strstr(field->type, "long"))
+               return 1;
+
+       return 0;
+}
+
+static int event_read_fields(struct event_format *event, struct format_field **fields)
+{
+       struct format_field *field = NULL;
+       enum event_type type;
+       char *token;
+       char *last_token;
+       int count = 0;
+
+       do {
+               type = read_token(&token);
+               if (type == EVENT_NEWLINE) {
+                       free_token(token);
+                       return count;
+               }
+
+               count++;
+
+               if (test_type_token(type, token, EVENT_ITEM, "field"))
+                       goto fail;
+               free_token(token);
+
+               type = read_token(&token);
+               /*
+                * The ftrace fields may still use the "special" name.
+                * Just ignore it.
+                */
+               if (event->flags & EVENT_FL_ISFTRACE &&
+                   type == EVENT_ITEM && strcmp(token, "special") == 0) {
+                       free_token(token);
+                       type = read_token(&token);
+               }
+
+               if (test_type_token(type, token, EVENT_OP, ":") < 0)
+                       goto fail;
+
+               free_token(token);
+               if (read_expect_type(EVENT_ITEM, &token) < 0)
+                       goto fail;
+
+               last_token = token;
+
+               field = malloc_or_die(sizeof(*field));
+               memset(field, 0, sizeof(*field));
+               field->event = event;
+
+               /* read the rest of the type */
+               for (;;) {
+                       type = read_token(&token);
+                       if (type == EVENT_ITEM ||
+                           (type == EVENT_OP && strcmp(token, "*") == 0) ||
+                           /*
+                            * Some of the ftrace fields are broken and have
+                            * an illegal "." in them.
+                            */
+                           (event->flags & EVENT_FL_ISFTRACE &&
+                            type == EVENT_OP && strcmp(token, ".") == 0)) {
+
+                               if (strcmp(token, "*") == 0)
+                                       field->flags |= FIELD_IS_POINTER;
+
+                               if (field->type) {
+                                       char *new_type;
+                                       new_type = realloc(field->type,
+                                                          strlen(field->type) +
+                                                          strlen(last_token) + 2);
+                                       if (!new_type) {
+                                               free(last_token);
+                                               goto fail;
+                                       }
+                                       field->type = new_type;
+                                       strcat(field->type, " ");
+                                       strcat(field->type, last_token);
+                                       free(last_token);
+                               } else
+                                       field->type = last_token;
+                               last_token = token;
+                               continue;
+                       }
+
+                       break;
+               }
+
+               if (!field->type) {
+                       die("no type found");
+                       goto fail;
+               }
+               field->name = last_token;
+
+               if (test_type(type, EVENT_OP))
+                       goto fail;
+
+               if (strcmp(token, "[") == 0) {
+                       enum event_type last_type = type;
+                       char *brackets = token;
+                       char *new_brackets;
+                       int len;
+
+                       field->flags |= FIELD_IS_ARRAY;
+
+                       type = read_token(&token);
+
+                       if (type == EVENT_ITEM)
+                               field->arraylen = strtoul(token, NULL, 0);
+                       else
+                               field->arraylen = 0;
+
+                       while (strcmp(token, "]") != 0) {
+                               if (last_type == EVENT_ITEM &&
+                                   type == EVENT_ITEM)
+                                       len = 2;
+                               else
+                                       len = 1;
+                               last_type = type;
+
+                               new_brackets = realloc(brackets,
+                                                      strlen(brackets) +
+                                                      strlen(token) + len);
+                               if (!new_brackets) {
+                                       free(brackets);
+                                       goto fail;
+                               }
+                               brackets = new_brackets;
+                               if (len == 2)
+                                       strcat(brackets, " ");
+                               strcat(brackets, token);
+                               /* We only care about the last token */
+                               field->arraylen = strtoul(token, NULL, 0);
+                               free_token(token);
+                               type = read_token(&token);
+                               if (type == EVENT_NONE) {
+                                       die("failed to find token");
+                                       goto fail;
+                               }
+                       }
+
+                       free_token(token);
+
+                       new_brackets = realloc(brackets, strlen(brackets) + 2);
+                       if (!new_brackets) {
+                               free(brackets);
+                               goto fail;
+                       }
+                       brackets = new_brackets;
+                       strcat(brackets, "]");
+
+                       /* add brackets to type */
+
+                       type = read_token(&token);
+                       /*
+                        * If the next token is not an OP, then it is of
+                        * the format: type [] item;
+                        */
+                       if (type == EVENT_ITEM) {
+                               char *new_type;
+                               new_type = realloc(field->type,
+                                                  strlen(field->type) +
+                                                  strlen(field->name) +
+                                                  strlen(brackets) + 2);
+                               if (!new_type) {
+                                       free(brackets);
+                                       goto fail;
+                               }
+                               field->type = new_type;
+                               strcat(field->type, " ");
+                               strcat(field->type, field->name);
+                               free_token(field->name);
+                               strcat(field->type, brackets);
+                               field->name = token;
+                               type = read_token(&token);
+                       } else {
+                               char *new_type;
+                               new_type = realloc(field->type,
+                                                  strlen(field->type) +
+                                                  strlen(brackets) + 1);
+                               if (!new_type) {
+                                       free(brackets);
+                                       goto fail;
+                               }
+                               field->type = new_type;
+                               strcat(field->type, brackets);
+                       }
+                       free(brackets);
+               }
+
+               if (field_is_string(field))
+                       field->flags |= FIELD_IS_STRING;
+               if (field_is_dynamic(field))
+                       field->flags |= FIELD_IS_DYNAMIC;
+               if (field_is_long(field))
+                       field->flags |= FIELD_IS_LONG;
+
+               if (test_type_token(type, token,  EVENT_OP, ";"))
+                       goto fail;
+               free_token(token);
+
+               if (read_expected(EVENT_ITEM, "offset") < 0)
+                       goto fail_expect;
+
+               if (read_expected(EVENT_OP, ":") < 0)
+                       goto fail_expect;
+
+               if (read_expect_type(EVENT_ITEM, &token))
+                       goto fail;
+               field->offset = strtoul(token, NULL, 0);
+               free_token(token);
+
+               if (read_expected(EVENT_OP, ";") < 0)
+                       goto fail_expect;
+
+               if (read_expected(EVENT_ITEM, "size") < 0)
+                       goto fail_expect;
+
+               if (read_expected(EVENT_OP, ":") < 0)
+                       goto fail_expect;
+
+               if (read_expect_type(EVENT_ITEM, &token))
+                       goto fail;
+               field->size = strtoul(token, NULL, 0);
+               free_token(token);
+
+               if (read_expected(EVENT_OP, ";") < 0)
+                       goto fail_expect;
+
+               type = read_token(&token);
+               if (type != EVENT_NEWLINE) {
+                       /* newer versions of the kernel have a "signed" type */
+                       if (test_type_token(type, token, EVENT_ITEM, "signed"))
+                               goto fail;
+
+                       free_token(token);
+
+                       if (read_expected(EVENT_OP, ":") < 0)
+                               goto fail_expect;
+
+                       if (read_expect_type(EVENT_ITEM, &token))
+                               goto fail;
+
+                       /* add signed type */
+
+                       free_token(token);
+                       if (read_expected(EVENT_OP, ";") < 0)
+                               goto fail_expect;
+
+                       if (read_expect_type(EVENT_NEWLINE, &token))
+                               goto fail;
+               }
+
+               free_token(token);
+
+               if (field->flags & FIELD_IS_ARRAY) {
+                       if (field->arraylen)
+                               field->elementsize = field->size / field->arraylen;
+                       else if (field->flags & FIELD_IS_STRING)
+                               field->elementsize = 1;
+                       else
+                               field->elementsize = event->pevent->long_size;
+               } else
+                       field->elementsize = field->size;
+
+               *fields = field;
+               fields = &field->next;
+
+       } while (1);
+
+       return 0;
+
+fail:
+       free_token(token);
+fail_expect:
+       if (field) {
+               free(field->type);
+               free(field->name);
+               free(field);
+       }
+       return -1;
+}
+
+static int event_read_format(struct event_format *event)
+{
+       char *token;
+       int ret;
+
+       if (read_expected_item(EVENT_ITEM, "format") < 0)
+               return -1;
+
+       if (read_expected(EVENT_OP, ":") < 0)
+               return -1;
+
+       if (read_expect_type(EVENT_NEWLINE, &token))
+               goto fail;
+       free_token(token);
+
+       ret = event_read_fields(event, &event->format.common_fields);
+       if (ret < 0)
+               return ret;
+       event->format.nr_common = ret;
+
+       ret = event_read_fields(event, &event->format.fields);
+       if (ret < 0)
+               return ret;
+       event->format.nr_fields = ret;
+
+       return 0;
+
+ fail:
+       free_token(token);
+       return -1;
+}
+
+static enum event_type
+process_arg_token(struct event_format *event, struct print_arg *arg,
+                 char **tok, enum event_type type);
+
+static enum event_type
+process_arg(struct event_format *event, struct print_arg *arg, char **tok)
+{
+       enum event_type type;
+       char *token;
+
+       type = read_token(&token);
+       *tok = token;
+
+       return process_arg_token(event, arg, tok, type);
+}
+
+static enum event_type
+process_op(struct event_format *event, struct print_arg *arg, char **tok);
+
+static enum event_type
+process_cond(struct event_format *event, struct print_arg *top, char **tok)
+{
+       struct print_arg *arg, *left, *right;
+       enum event_type type;
+       char *token = NULL;
+
+       arg = alloc_arg();
+       left = alloc_arg();
+       right = alloc_arg();
+
+       arg->type = PRINT_OP;
+       arg->op.left = left;
+       arg->op.right = right;
+
+       *tok = NULL;
+       type = process_arg(event, left, &token);
+
+ again:
+       /* Handle other operations in the arguments */
+       if (type == EVENT_OP && strcmp(token, ":") != 0) {
+               type = process_op(event, left, &token);
+               goto again;
+       }
+
+       if (test_type_token(type, token, EVENT_OP, ":"))
+               goto out_free;
+
+       arg->op.op = token;
+
+       type = process_arg(event, right, &token);
+
+       top->op.right = arg;
+
+       *tok = token;
+       return type;
+
+out_free:
+       /* Top may point to itself */
+       top->op.right = NULL;
+       free_token(token);
+       free_arg(arg);
+       return EVENT_ERROR;
+}
+
+static enum event_type
+process_array(struct event_format *event, struct print_arg *top, char **tok)
+{
+       struct print_arg *arg;
+       enum event_type type;
+       char *token = NULL;
+
+       arg = alloc_arg();
+
+       *tok = NULL;
+       type = process_arg(event, arg, &token);
+       if (test_type_token(type, token, EVENT_OP, "]"))
+               goto out_free;
+
+       top->op.right = arg;
+
+       free_token(token);
+       type = read_token_item(&token);
+       *tok = token;
+
+       return type;
+
+out_free:
+       free_token(*tok);
+       *tok = NULL;
+       free_arg(arg);
+       return EVENT_ERROR;
+}
+
+static int get_op_prio(char *op)
+{
+       if (!op[1]) {
+               switch (op[0]) {
+               case '~':
+               case '!':
+                       return 4;
+               case '*':
+               case '/':
+               case '%':
+                       return 6;
+               case '+':
+               case '-':
+                       return 7;
+                       /* '>>' and '<<' are 8 */
+               case '<':
+               case '>':
+                       return 9;
+                       /* '==' and '!=' are 10 */
+               case '&':
+                       return 11;
+               case '^':
+                       return 12;
+               case '|':
+                       return 13;
+               case '?':
+                       return 16;
+               default:
+                       do_warning("unknown op '%c'", op[0]);
+                       return -1;
+               }
+       } else {
+               if (strcmp(op, "++") == 0 ||
+                   strcmp(op, "--") == 0) {
+                       return 3;
+               } else if (strcmp(op, ">>") == 0 ||
+                          strcmp(op, "<<") == 0) {
+                       return 8;
+               } else if (strcmp(op, ">=") == 0 ||
+                          strcmp(op, "<=") == 0) {
+                       return 9;
+               } else if (strcmp(op, "==") == 0 ||
+                          strcmp(op, "!=") == 0) {
+                       return 10;
+               } else if (strcmp(op, "&&") == 0) {
+                       return 14;
+               } else if (strcmp(op, "||") == 0) {
+                       return 15;
+               } else {
+                       do_warning("unknown op '%s'", op);
+                       return -1;
+               }
+       }
+}
+
+static int set_op_prio(struct print_arg *arg)
+{
+
+       /* single ops are the greatest */
+       if (!arg->op.left || arg->op.left->type == PRINT_NULL)
+               arg->op.prio = 0;
+       else
+               arg->op.prio = get_op_prio(arg->op.op);
+
+       return arg->op.prio;
+}
+
+/* Note, *tok does not get freed, but will most likely be saved */
+static enum event_type
+process_op(struct event_format *event, struct print_arg *arg, char **tok)
+{
+       struct print_arg *left, *right = NULL;
+       enum event_type type;
+       char *token;
+
+       /* the op is passed in via tok */
+       token = *tok;
+
+       if (arg->type == PRINT_OP && !arg->op.left) {
+               /* handle single op */
+               if (token[1]) {
+                       die("bad op token %s", token);
+                       goto out_free;
+               }
+               switch (token[0]) {
+               case '~':
+               case '!':
+               case '+':
+               case '-':
+                       break;
+               default:
+                       do_warning("bad op token %s", token);
+                       goto out_free;
+
+               }
+
+               /* make an empty left */
+               left = alloc_arg();
+               left->type = PRINT_NULL;
+               arg->op.left = left;
+
+               right = alloc_arg();
+               arg->op.right = right;
+
+               /* do not free the token, it belongs to an op */
+               *tok = NULL;
+               type = process_arg(event, right, tok);
+
+       } else if (strcmp(token, "?") == 0) {
+
+               left = alloc_arg();
+               /* copy the top arg to the left */
+               *left = *arg;
+
+               arg->type = PRINT_OP;
+               arg->op.op = token;
+               arg->op.left = left;
+               arg->op.prio = 0;
+
+               type = process_cond(event, arg, tok);
+
+       } else if (strcmp(token, ">>") == 0 ||
+                  strcmp(token, "<<") == 0 ||
+                  strcmp(token, "&") == 0 ||
+                  strcmp(token, "|") == 0 ||
+                  strcmp(token, "&&") == 0 ||
+                  strcmp(token, "||") == 0 ||
+                  strcmp(token, "-") == 0 ||
+                  strcmp(token, "+") == 0 ||
+                  strcmp(token, "*") == 0 ||
+                  strcmp(token, "^") == 0 ||
+                  strcmp(token, "/") == 0 ||
+                  strcmp(token, "<") == 0 ||
+                  strcmp(token, ">") == 0 ||
+                  strcmp(token, "==") == 0 ||
+                  strcmp(token, "!=") == 0) {
+
+               left = alloc_arg();
+
+               /* copy the top arg to the left */
+               *left = *arg;
+
+               arg->type = PRINT_OP;
+               arg->op.op = token;
+               arg->op.left = left;
+
+               if (set_op_prio(arg) == -1) {
+                       event->flags |= EVENT_FL_FAILED;
+                       /* arg->op.op (= token) will be freed at out_free */
+                       arg->op.op = NULL;
+                       goto out_free;
+               }
+
+               type = read_token_item(&token);
+               *tok = token;
+
+               /* could just be a type pointer */
+               if ((strcmp(arg->op.op, "*") == 0) &&
+                   type == EVENT_DELIM && (strcmp(token, ")") == 0)) {
+                       char *new_atom;
+
+                       if (left->type != PRINT_ATOM)
+                               die("bad pointer type");
+                       new_atom = realloc(left->atom.atom,
+                                           strlen(left->atom.atom) + 3);
+                       if (!new_atom)
+                               goto out_free;
+
+                       left->atom.atom = new_atom;
+                       strcat(left->atom.atom, " *");
+                       free(arg->op.op);
+                       *arg = *left;
+                       free(left);
+
+                       return type;
+               }
+
+               right = alloc_arg();
+               type = process_arg_token(event, right, tok, type);
+               arg->op.right = right;
+
+       } else if (strcmp(token, "[") == 0) {
+
+               left = alloc_arg();
+               *left = *arg;
+
+               arg->type = PRINT_OP;
+               arg->op.op = token;
+               arg->op.left = left;
+
+               arg->op.prio = 0;
+
+               type = process_array(event, arg, tok);
+
+       } else {
+               do_warning("unknown op '%s'", token);
+               event->flags |= EVENT_FL_FAILED;
+               /* the arg is now the left side */
+               goto out_free;
+       }
+
+       if (type == EVENT_OP && strcmp(*tok, ":") != 0) {
+               int prio;
+
+               /* higher prios need to be closer to the root */
+               prio = get_op_prio(*tok);
+
+               if (prio > arg->op.prio)
+                       return process_op(event, arg, tok);
+
+               return process_op(event, right, tok);
+       }
+
+       return type;
+
+ out_free:
+       free_token(token);
+       *tok = NULL;
+       return EVENT_ERROR;
+}
+
+static enum event_type
+process_entry(struct event_format *event __unused, struct print_arg *arg,
+             char **tok)
+{
+       enum event_type type;
+       char *field;
+       char *token;
+
+       if (read_expected(EVENT_OP, "->") < 0)
+               goto out_err;
+
+       if (read_expect_type(EVENT_ITEM, &token) < 0)
+               goto out_free;
+       field = token;
+
+       arg->type = PRINT_FIELD;
+       arg->field.name = field;
+
+       if (is_flag_field) {
+               arg->field.field = pevent_find_any_field(event, arg->field.name);
+               arg->field.field->flags |= FIELD_IS_FLAG;
+               is_flag_field = 0;
+       } else if (is_symbolic_field) {
+               arg->field.field = pevent_find_any_field(event, arg->field.name);
+               arg->field.field->flags |= FIELD_IS_SYMBOLIC;
+               is_symbolic_field = 0;
+       }
+
+       type = read_token(&token);
+       *tok = token;
+
+       return type;
+
+ out_free:
+       free_token(token);
+ out_err:
+       *tok = NULL;
+       return EVENT_ERROR;
+}
+
+static char *arg_eval (struct print_arg *arg);
+
+static unsigned long long
+eval_type_str(unsigned long long val, const char *type, int pointer)
+{
+       int sign = 0;
+       char *ref;
+       int len;
+
+       len = strlen(type);
+
+       if (pointer) {
+
+               if (type[len-1] != '*') {
+                       do_warning("pointer expected with non pointer type");
+                       return val;
+               }
+
+               ref = malloc_or_die(len);
+               memcpy(ref, type, len);
+
+               /* chop off the " *" */
+               ref[len - 2] = 0;
+
+               val = eval_type_str(val, ref, 0);
+               free(ref);
+               return val;
+       }
+
+       /* check if this is a pointer */
+       if (type[len - 1] == '*')
+               return val;
+
+       /* Try to figure out the arg size*/
+       if (strncmp(type, "struct", 6) == 0)
+               /* all bets off */
+               return val;
+
+       if (strcmp(type, "u8") == 0)
+               return val & 0xff;
+
+       if (strcmp(type, "u16") == 0)
+               return val & 0xffff;
+
+       if (strcmp(type, "u32") == 0)
+               return val & 0xffffffff;
+
+       if (strcmp(type, "u64") == 0 ||
+           strcmp(type, "s64"))
+               return val;
+
+       if (strcmp(type, "s8") == 0)
+               return (unsigned long long)(char)val & 0xff;
+
+       if (strcmp(type, "s16") == 0)
+               return (unsigned long long)(short)val & 0xffff;
+
+       if (strcmp(type, "s32") == 0)
+               return (unsigned long long)(int)val & 0xffffffff;
+
+       if (strncmp(type, "unsigned ", 9) == 0) {
+               sign = 0;
+               type += 9;
+       }
+
+       if (strcmp(type, "char") == 0) {
+               if (sign)
+                       return (unsigned long long)(char)val & 0xff;
+               else
+                       return val & 0xff;
+       }
+
+       if (strcmp(type, "short") == 0) {
+               if (sign)
+                       return (unsigned long long)(short)val & 0xffff;
+               else
+                       return val & 0xffff;
+       }
+
+       if (strcmp(type, "int") == 0) {
+               if (sign)
+                       return (unsigned long long)(int)val & 0xffffffff;
+               else
+                       return val & 0xffffffff;
+       }
+
+       return val;
+}
+
+/*
+ * Try to figure out the type.
+ */
+static unsigned long long
+eval_type(unsigned long long val, struct print_arg *arg, int pointer)
+{
+       if (arg->type != PRINT_TYPE)
+               die("expected type argument");
+
+       return eval_type_str(val, arg->typecast.type, pointer);
+}
+
+static int arg_num_eval(struct print_arg *arg, long long *val)
+{
+       long long left, right;
+       int ret = 1;
+
+       switch (arg->type) {
+       case PRINT_ATOM:
+               *val = strtoll(arg->atom.atom, NULL, 0);
+               break;
+       case PRINT_TYPE:
+               ret = arg_num_eval(arg->typecast.item, val);
+               if (!ret)
+                       break;
+               *val = eval_type(*val, arg, 0);
+               break;
+       case PRINT_OP:
+               switch (arg->op.op[0]) {
+               case '|':
+                       ret = arg_num_eval(arg->op.left, &left);
+                       if (!ret)
+                               break;
+                       ret = arg_num_eval(arg->op.right, &right);
+                       if (!ret)
+                               break;
+                       if (arg->op.op[1])
+                               *val = left || right;
+                       else
+                               *val = left | right;
+                       break;
+               case '&':
+                       ret = arg_num_eval(arg->op.left, &left);
+                       if (!ret)
+                               break;
+                       ret = arg_num_eval(arg->op.right, &right);
+                       if (!ret)
+                               break;
+                       if (arg->op.op[1])
+                               *val = left && right;
+                       else
+                               *val = left & right;
+                       break;
+               case '<':
+                       ret = arg_num_eval(arg->op.left, &left);
+                       if (!ret)
+                               break;
+                       ret = arg_num_eval(arg->op.right, &right);
+                       if (!ret)
+                               break;
+                       switch (arg->op.op[1]) {
+                       case 0:
+                               *val = left < right;
+                               break;
+                       case '<':
+                               *val = left << right;
+                               break;
+                       case '=':
+                               *val = left <= right;
+                               break;
+                       default:
+                               do_warning("unknown op '%s'", arg->op.op);
+                               ret = 0;
+                       }
+                       break;
+               case '>':
+                       ret = arg_num_eval(arg->op.left, &left);
+                       if (!ret)
+                               break;
+                       ret = arg_num_eval(arg->op.right, &right);
+                       if (!ret)
+                               break;
+                       switch (arg->op.op[1]) {
+                       case 0:
+                               *val = left > right;
+                               break;
+                       case '>':
+                               *val = left >> right;
+                               break;
+                       case '=':
+                               *val = left >= right;
+                               break;
+                       default:
+                               do_warning("unknown op '%s'", arg->op.op);
+                               ret = 0;
+                       }
+                       break;
+               case '=':
+                       ret = arg_num_eval(arg->op.left, &left);
+                       if (!ret)
+                               break;
+                       ret = arg_num_eval(arg->op.right, &right);
+                       if (!ret)
+                               break;
+
+                       if (arg->op.op[1] != '=') {
+                               do_warning("unknown op '%s'", arg->op.op);
+                               ret = 0;
+                       } else
+                               *val = left == right;
+                       break;
+               case '!':
+                       ret = arg_num_eval(arg->op.left, &left);
+                       if (!ret)
+                               break;
+                       ret = arg_num_eval(arg->op.right, &right);
+                       if (!ret)
+                               break;
+
+                       switch (arg->op.op[1]) {
+                       case '=':
+                               *val = left != right;
+                               break;
+                       default:
+                               do_warning("unknown op '%s'", arg->op.op);
+                               ret = 0;
+                       }
+                       break;
+               case '-':
+                       /* check for negative */
+                       if (arg->op.left->type == PRINT_NULL)
+                               left = 0;
+                       else
+                               ret = arg_num_eval(arg->op.left, &left);
+                       if (!ret)
+                               break;
+                       ret = arg_num_eval(arg->op.right, &right);
+                       if (!ret)
+                               break;
+                       *val = left - right;
+                       break;
+               case '+':
+                       if (arg->op.left->type == PRINT_NULL)
+                               left = 0;
+                       else
+                               ret = arg_num_eval(arg->op.left, &left);
+                       if (!ret)
+                               break;
+                       ret = arg_num_eval(arg->op.right, &right);
+                       if (!ret)
+                               break;
+                       *val = left + right;
+                       break;
+               default:
+                       do_warning("unknown op '%s'", arg->op.op);
+                       ret = 0;
+               }
+               break;
+
+       case PRINT_NULL:
+       case PRINT_FIELD ... PRINT_SYMBOL:
+       case PRINT_STRING:
+       case PRINT_BSTRING:
+       default:
+               do_warning("invalid eval type %d", arg->type);
+               ret = 0;
+
+       }
+       return ret;
+}
+
+static char *arg_eval (struct print_arg *arg)
+{
+       long long val;
+       static char buf[20];
+
+       switch (arg->type) {
+       case PRINT_ATOM:
+               return arg->atom.atom;
+       case PRINT_TYPE:
+               return arg_eval(arg->typecast.item);
+       case PRINT_OP:
+               if (!arg_num_eval(arg, &val))
+                       break;
+               sprintf(buf, "%lld", val);
+               return buf;
+
+       case PRINT_NULL:
+       case PRINT_FIELD ... PRINT_SYMBOL:
+       case PRINT_STRING:
+       case PRINT_BSTRING:
+       default:
+               die("invalid eval type %d", arg->type);
+               break;
+       }
+
+       return NULL;
+}
+
+static enum event_type
+process_fields(struct event_format *event, struct print_flag_sym **list, char **tok)
+{
+       enum event_type type;
+       struct print_arg *arg = NULL;
+       struct print_flag_sym *field;
+       char *token = *tok;
+       char *value;
+
+       do {
+               free_token(token);
+               type = read_token_item(&token);
+               if (test_type_token(type, token, EVENT_OP, "{"))
+                       break;
+
+               arg = alloc_arg();
+
+               free_token(token);
+               type = process_arg(event, arg, &token);
+
+               if (type == EVENT_OP)
+                       type = process_op(event, arg, &token);
+
+               if (type == EVENT_ERROR)
+                       goto out_free;
+
+               if (test_type_token(type, token, EVENT_DELIM, ","))
+                       goto out_free;
+
+               field = malloc_or_die(sizeof(*field));
+               memset(field, 0, sizeof(*field));
+
+               value = arg_eval(arg);
+               if (value == NULL)
+                       goto out_free;
+               field->value = strdup(value);
+               if (field->value == NULL)
+                       goto out_free;
+
+               free_arg(arg);
+               arg = alloc_arg();
+
+               free_token(token);
+               type = process_arg(event, arg, &token);
+               if (test_type_token(type, token, EVENT_OP, "}"))
+                       goto out_free;
+
+               value = arg_eval(arg);
+               if (value == NULL)
+                       goto out_free;
+               field->str = strdup(value);
+               if (field->str == NULL)
+                       goto out_free;
+               free_arg(arg);
+               arg = NULL;
+
+               *list = field;
+               list = &field->next;
+
+               free_token(token);
+               type = read_token_item(&token);
+       } while (type == EVENT_DELIM && strcmp(token, ",") == 0);
+
+       *tok = token;
+       return type;
+
+out_free:
+       free_arg(arg);
+       free_token(token);
+       *tok = NULL;
+
+       return EVENT_ERROR;
+}
+
+static enum event_type
+process_flags(struct event_format *event, struct print_arg *arg, char **tok)
+{
+       struct print_arg *field;
+       enum event_type type;
+       char *token;
+
+       memset(arg, 0, sizeof(*arg));
+       arg->type = PRINT_FLAGS;
+
+       field = alloc_arg();
+
+       type = process_arg(event, field, &token);
+
+       /* Handle operations in the first argument */
+       while (type == EVENT_OP)
+               type = process_op(event, field, &token);
+
+       if (test_type_token(type, token, EVENT_DELIM, ","))
+               goto out_free;
+       free_token(token);
+
+       arg->flags.field = field;
+
+       type = read_token_item(&token);
+       if (event_item_type(type)) {
+               arg->flags.delim = token;
+               type = read_token_item(&token);
+       }
+
+       if (test_type_token(type, token, EVENT_DELIM, ","))
+               goto out_free;
+
+       type = process_fields(event, &arg->flags.flags, &token);
+       if (test_type_token(type, token, EVENT_DELIM, ")"))
+               goto out_free;
+
+       free_token(token);
+       type = read_token_item(tok);
+       return type;
+
+ out_free:
+       free_token(token);
+       *tok = NULL;
+       return EVENT_ERROR;
+}
+
+static enum event_type
+process_symbols(struct event_format *event, struct print_arg *arg, char **tok)
+{
+       struct print_arg *field;
+       enum event_type type;
+       char *token;
+
+       memset(arg, 0, sizeof(*arg));
+       arg->type = PRINT_SYMBOL;
+
+       field = alloc_arg();
+
+       type = process_arg(event, field, &token);
+       if (test_type_token(type, token, EVENT_DELIM, ","))
+               goto out_free;
+
+       arg->symbol.field = field;
+
+       type = process_fields(event, &arg->symbol.symbols, &token);
+       if (test_type_token(type, token, EVENT_DELIM, ")"))
+               goto out_free;
+
+       free_token(token);
+       type = read_token_item(tok);
+       return type;
+
+ out_free:
+       free_token(token);
+       *tok = NULL;
+       return EVENT_ERROR;
+}
+
+static enum event_type
+process_hex(struct event_format *event, struct print_arg *arg, char **tok)
+{
+       struct print_arg *field;
+       enum event_type type;
+       char *token;
+
+       memset(arg, 0, sizeof(*arg));
+       arg->type = PRINT_HEX;
+
+       field = alloc_arg();
+       type = process_arg(event, field, &token);
+
+       if (test_type_token(type, token, EVENT_DELIM, ","))
+               goto out_free;
+
+       arg->hex.field = field;
+
+       free_token(token);
+
+       field = alloc_arg();
+       type = process_arg(event, field, &token);
+
+       if (test_type_token(type, token, EVENT_DELIM, ")"))
+               goto out_free;
+
+       arg->hex.size = field;
+
+       free_token(token);
+       type = read_token_item(tok);
+       return type;
+
+ out_free:
+       free_arg(field);
+       free_token(token);
+       *tok = NULL;
+       return EVENT_ERROR;
+}
+
+static enum event_type
+process_dynamic_array(struct event_format *event, struct print_arg *arg, char **tok)
+{
+       struct format_field *field;
+       enum event_type type;
+       char *token;
+
+       memset(arg, 0, sizeof(*arg));
+       arg->type = PRINT_DYNAMIC_ARRAY;
+
+       /*
+        * The item within the parenthesis is another field that holds
+        * the index into where the array starts.
+        */
+       type = read_token(&token);
+       *tok = token;
+       if (type != EVENT_ITEM)
+               goto out_free;
+
+       /* Find the field */
+
+       field = pevent_find_field(event, token);
+       if (!field)
+               goto out_free;
+
+       arg->dynarray.field = field;
+       arg->dynarray.index = 0;
+
+       if (read_expected(EVENT_DELIM, ")") < 0)
+               goto out_free;
+
+       free_token(token);
+       type = read_token_item(&token);
+       *tok = token;
+       if (type != EVENT_OP || strcmp(token, "[") != 0)
+               return type;
+
+       free_token(token);
+       arg = alloc_arg();
+       type = process_arg(event, arg, &token);
+       if (type == EVENT_ERROR)
+               goto out_free_arg;
+
+       if (!test_type_token(type, token, EVENT_OP, "]"))
+               goto out_free_arg;
+
+       free_token(token);
+       type = read_token_item(tok);
+       return type;
+
+ out_free_arg:
+       free_arg(arg);
+ out_free:
+       free_token(token);
+       *tok = NULL;
+       return EVENT_ERROR;
+}
+
+static enum event_type
+process_paren(struct event_format *event, struct print_arg *arg, char **tok)
+{
+       struct print_arg *item_arg;
+       enum event_type type;
+       char *token;
+
+       type = process_arg(event, arg, &token);
+
+       if (type == EVENT_ERROR)
+               goto out_free;
+
+       if (type == EVENT_OP)
+               type = process_op(event, arg, &token);
+
+       if (type == EVENT_ERROR)
+               goto out_free;
+
+       if (test_type_token(type, token, EVENT_DELIM, ")"))
+               goto out_free;
+
+       free_token(token);
+       type = read_token_item(&token);
+
+       /*
+        * If the next token is an item or another open paren, then
+        * this was a typecast.
+        */
+       if (event_item_type(type) ||
+           (type == EVENT_DELIM && strcmp(token, "(") == 0)) {
+
+               /* make this a typecast and contine */
+
+               /* prevous must be an atom */
+               if (arg->type != PRINT_ATOM)
+                       die("previous needed to be PRINT_ATOM");
+
+               item_arg = alloc_arg();
+
+               arg->type = PRINT_TYPE;
+               arg->typecast.type = arg->atom.atom;
+               arg->typecast.item = item_arg;
+               type = process_arg_token(event, item_arg, &token, type);
+
+       }
+
+       *tok = token;
+       return type;
+
+ out_free:
+       free_token(token);
+       *tok = NULL;
+       return EVENT_ERROR;
+}
+
+
+static enum event_type
+process_str(struct event_format *event __unused, struct print_arg *arg, char **tok)
+{
+       enum event_type type;
+       char *token;
+
+       if (read_expect_type(EVENT_ITEM, &token) < 0)
+               goto out_free;
+
+       arg->type = PRINT_STRING;
+       arg->string.string = token;
+       arg->string.offset = -1;
+
+       if (read_expected(EVENT_DELIM, ")") < 0)
+               goto out_err;
+
+       type = read_token(&token);
+       *tok = token;
+
+       return type;
+
+ out_free:
+       free_token(token);
+ out_err:
+       *tok = NULL;
+       return EVENT_ERROR;
+}
+
+static struct pevent_function_handler *
+find_func_handler(struct pevent *pevent, char *func_name)
+{
+       struct pevent_function_handler *func;
+
+       for (func = pevent->func_handlers; func; func = func->next) {
+               if (strcmp(func->name, func_name) == 0)
+                       break;
+       }
+
+       return func;
+}
+
+static void remove_func_handler(struct pevent *pevent, char *func_name)
+{
+       struct pevent_function_handler *func;
+       struct pevent_function_handler **next;
+
+       next = &pevent->func_handlers;
+       while ((func = *next)) {
+               if (strcmp(func->name, func_name) == 0) {
+                       *next = func->next;
+                       free_func_handle(func);
+                       break;
+               }
+               next = &func->next;
+       }
+}
+
+static enum event_type
+process_func_handler(struct event_format *event, struct pevent_function_handler *func,
+                    struct print_arg *arg, char **tok)
+{
+       struct print_arg **next_arg;
+       struct print_arg *farg;
+       enum event_type type;
+       char *token;
+       char *test;
+       int i;
+
+       arg->type = PRINT_FUNC;
+       arg->func.func = func;
+
+       *tok = NULL;
+
+       next_arg = &(arg->func.args);
+       for (i = 0; i < func->nr_args; i++) {
+               farg = alloc_arg();
+               type = process_arg(event, farg, &token);
+               if (i < (func->nr_args - 1))
+                       test = ",";
+               else
+                       test = ")";
+
+               if (test_type_token(type, token, EVENT_DELIM, test)) {
+                       free_arg(farg);
+                       free_token(token);
+                       return EVENT_ERROR;
+               }
+
+               *next_arg = farg;
+               next_arg = &(farg->next);
+               free_token(token);
+       }
+
+       type = read_token(&token);
+       *tok = token;
+
+       return type;
+}
+
+static enum event_type
+process_function(struct event_format *event, struct print_arg *arg,
+                char *token, char **tok)
+{
+       struct pevent_function_handler *func;
+
+       if (strcmp(token, "__print_flags") == 0) {
+               free_token(token);
+               is_flag_field = 1;
+               return process_flags(event, arg, tok);
+       }
+       if (strcmp(token, "__print_symbolic") == 0) {
+               free_token(token);
+               is_symbolic_field = 1;
+               return process_symbols(event, arg, tok);
+       }
+       if (strcmp(token, "__print_hex") == 0) {
+               free_token(token);
+               return process_hex(event, arg, tok);
+       }
+       if (strcmp(token, "__get_str") == 0) {
+               free_token(token);
+               return process_str(event, arg, tok);
+       }
+       if (strcmp(token, "__get_dynamic_array") == 0) {
+               free_token(token);
+               return process_dynamic_array(event, arg, tok);
+       }
+
+       func = find_func_handler(event->pevent, token);
+       if (func) {
+               free_token(token);
+               return process_func_handler(event, func, arg, tok);
+       }
+
+       do_warning("function %s not defined", token);
+       free_token(token);
+       return EVENT_ERROR;
+}
+
+static enum event_type
+process_arg_token(struct event_format *event, struct print_arg *arg,
+                 char **tok, enum event_type type)
+{
+       char *token;
+       char *atom;
+
+       token = *tok;
+
+       switch (type) {
+       case EVENT_ITEM:
+               if (strcmp(token, "REC") == 0) {
+                       free_token(token);
+                       type = process_entry(event, arg, &token);
+                       break;
+               }
+               atom = token;
+               /* test the next token */
+               type = read_token_item(&token);
+
+               /*
+                * If the next token is a parenthesis, then this
+                * is a function.
+                */
+               if (type == EVENT_DELIM && strcmp(token, "(") == 0) {
+                       free_token(token);
+                       token = NULL;
+                       /* this will free atom. */
+                       type = process_function(event, arg, atom, &token);
+                       break;
+               }
+               /* atoms can be more than one token long */
+               while (type == EVENT_ITEM) {
+                       char *new_atom;
+                       new_atom = realloc(atom,
+                                          strlen(atom) + strlen(token) + 2);
+                       if (!new_atom) {
+                               free(atom);
+                               *tok = NULL;
+                               free_token(token);
+                               return EVENT_ERROR;
+                       }
+                       atom = new_atom;
+                       strcat(atom, " ");
+                       strcat(atom, token);
+                       free_token(token);
+                       type = read_token_item(&token);
+               }
+
+               arg->type = PRINT_ATOM;
+               arg->atom.atom = atom;
+               break;
+
+       case EVENT_DQUOTE:
+       case EVENT_SQUOTE:
+               arg->type = PRINT_ATOM;
+               arg->atom.atom = token;
+               type = read_token_item(&token);
+               break;
+       case EVENT_DELIM:
+               if (strcmp(token, "(") == 0) {
+                       free_token(token);
+                       type = process_paren(event, arg, &token);
+                       break;
+               }
+       case EVENT_OP:
+               /* handle single ops */
+               arg->type = PRINT_OP;
+               arg->op.op = token;
+               arg->op.left = NULL;
+               type = process_op(event, arg, &token);
+
+               /* On error, the op is freed */
+               if (type == EVENT_ERROR)
+                       arg->op.op = NULL;
+
+               /* return error type if errored */
+               break;
+
+       case EVENT_ERROR ... EVENT_NEWLINE:
+       default:
+               die("unexpected type %d", type);
+       }
+       *tok = token;
+
+       return type;
+}
+
+static int event_read_print_args(struct event_format *event, struct print_arg **list)
+{
+       enum event_type type = EVENT_ERROR;
+       struct print_arg *arg;
+       char *token;
+       int args = 0;
+
+       do {
+               if (type == EVENT_NEWLINE) {
+                       type = read_token_item(&token);
+                       continue;
+               }
+
+               arg = alloc_arg();
+
+               type = process_arg(event, arg, &token);
+
+               if (type == EVENT_ERROR) {
+                       free_token(token);
+                       free_arg(arg);
+                       return -1;
+               }
+
+               *list = arg;
+               args++;
+
+               if (type == EVENT_OP) {
+                       type = process_op(event, arg, &token);
+                       free_token(token);
+                       if (type == EVENT_ERROR) {
+                               *list = NULL;
+                               free_arg(arg);
+                               return -1;
+                       }
+                       list = &arg->next;
+                       continue;
+               }
+
+               if (type == EVENT_DELIM && strcmp(token, ",") == 0) {
+                       free_token(token);
+                       *list = arg;
+                       list = &arg->next;
+                       continue;
+               }
+               break;
+       } while (type != EVENT_NONE);
+
+       if (type != EVENT_NONE && type != EVENT_ERROR)
+               free_token(token);
+
+       return args;
+}
+
+static int event_read_print(struct event_format *event)
+{
+       enum event_type type;
+       char *token;
+       int ret;
+
+       if (read_expected_item(EVENT_ITEM, "print") < 0)
+               return -1;
+
+       if (read_expected(EVENT_ITEM, "fmt") < 0)
+               return -1;
+
+       if (read_expected(EVENT_OP, ":") < 0)
+               return -1;
+
+       if (read_expect_type(EVENT_DQUOTE, &token) < 0)
+               goto fail;
+
+ concat:
+       event->print_fmt.format = token;
+       event->print_fmt.args = NULL;
+
+       /* ok to have no arg */
+       type = read_token_item(&token);
+
+       if (type == EVENT_NONE)
+               return 0;
+
+       /* Handle concatenation of print lines */
+       if (type == EVENT_DQUOTE) {
+               char *cat;
+
+               cat = malloc_or_die(strlen(event->print_fmt.format) +
+                                   strlen(token) + 1);
+               strcpy(cat, event->print_fmt.format);
+               strcat(cat, token);
+               free_token(token);
+               free_token(event->print_fmt.format);
+               event->print_fmt.format = NULL;
+               token = cat;
+               goto concat;
+       }
+                            
+       if (test_type_token(type, token, EVENT_DELIM, ","))
+               goto fail;
+
+       free_token(token);
+
+       ret = event_read_print_args(event, &event->print_fmt.args);
+       if (ret < 0)
+               return -1;
+
+       return ret;
+
+ fail:
+       free_token(token);
+       return -1;
+}
+
+/**
+ * pevent_find_common_field - return a common field by event
+ * @event: handle for the event
+ * @name: the name of the common field to return
+ *
+ * Returns a common field from the event by the given @name.
+ * This only searchs the common fields and not all field.
+ */
+struct format_field *
+pevent_find_common_field(struct event_format *event, const char *name)
+{
+       struct format_field *format;
+
+       for (format = event->format.common_fields;
+            format; format = format->next) {
+               if (strcmp(format->name, name) == 0)
+                       break;
+       }
+
+       return format;
+}
+
+/**
+ * pevent_find_field - find a non-common field
+ * @event: handle for the event
+ * @name: the name of the non-common field
+ *
+ * Returns a non-common field by the given @name.
+ * This does not search common fields.
+ */
+struct format_field *
+pevent_find_field(struct event_format *event, const char *name)
+{
+       struct format_field *format;
+
+       for (format = event->format.fields;
+            format; format = format->next) {
+               if (strcmp(format->name, name) == 0)
+                       break;
+       }
+
+       return format;
+}
+
+/**
+ * pevent_find_any_field - find any field by name
+ * @event: handle for the event
+ * @name: the name of the field
+ *
+ * Returns a field by the given @name.
+ * This searchs the common field names first, then
+ * the non-common ones if a common one was not found.
+ */
+struct format_field *
+pevent_find_any_field(struct event_format *event, const char *name)
+{
+       struct format_field *format;
+
+       format = pevent_find_common_field(event, name);
+       if (format)
+               return format;
+       return pevent_find_field(event, name);
+}
+
+/**
+ * pevent_read_number - read a number from data
+ * @pevent: handle for the pevent
+ * @ptr: the raw data
+ * @size: the size of the data that holds the number
+ *
+ * Returns the number (converted to host) from the
+ * raw data.
+ */
+unsigned long long pevent_read_number(struct pevent *pevent,
+                                     const void *ptr, int size)
+{
+       switch (size) {
+       case 1:
+               return *(unsigned char *)ptr;
+       case 2:
+               return data2host2(pevent, ptr);
+       case 4:
+               return data2host4(pevent, ptr);
+       case 8:
+               return data2host8(pevent, ptr);
+       default:
+               /* BUG! */
+               return 0;
+       }
+}
+
+/**
+ * pevent_read_number_field - read a number from data
+ * @field: a handle to the field
+ * @data: the raw data to read
+ * @value: the value to place the number in
+ *
+ * Reads raw data according to a field offset and size,
+ * and translates it into @value.
+ *
+ * Returns 0 on success, -1 otherwise.
+ */
+int pevent_read_number_field(struct format_field *field, const void *data,
+                            unsigned long long *value)
+{
+       if (!field)
+               return -1;
+       switch (field->size) {
+       case 1:
+       case 2:
+       case 4:
+       case 8:
+               *value = pevent_read_number(field->event->pevent,
+                                           data + field->offset, field->size);
+               return 0;
+       default:
+               return -1;
+       }
+}
+
+static int get_common_info(struct pevent *pevent,
+                          const char *type, int *offset, int *size)
+{
+       struct event_format *event;
+       struct format_field *field;
+
+       /*
+        * All events should have the same common elements.
+        * Pick any event to find where the type is;
+        */
+       if (!pevent->events)
+               die("no event_list!");
+
+       event = pevent->events[0];
+       field = pevent_find_common_field(event, type);
+       if (!field)
+               return -1;
+
+       *offset = field->offset;
+       *size = field->size;
+
+       return 0;
+}
+
+static int __parse_common(struct pevent *pevent, void *data,
+                         int *size, int *offset, const char *name)
+{
+       int ret;
+
+       if (!*size) {
+               ret = get_common_info(pevent, name, offset, size);
+               if (ret < 0)
+                       return ret;
+       }
+       return pevent_read_number(pevent, data + *offset, *size);
+}
+
+static int trace_parse_common_type(struct pevent *pevent, void *data)
+{
+       return __parse_common(pevent, data,
+                             &pevent->type_size, &pevent->type_offset,
+                             "common_type");
+}
+
+static int parse_common_pid(struct pevent *pevent, void *data)
+{
+       return __parse_common(pevent, data,
+                             &pevent->pid_size, &pevent->pid_offset,
+                             "common_pid");
+}
+
+static int parse_common_pc(struct pevent *pevent, void *data)
+{
+       return __parse_common(pevent, data,
+                             &pevent->pc_size, &pevent->pc_offset,
+                             "common_preempt_count");
+}
+
+static int parse_common_flags(struct pevent *pevent, void *data)
+{
+       return __parse_common(pevent, data,
+                             &pevent->flags_size, &pevent->flags_offset,
+                             "common_flags");
+}
+
+static int parse_common_lock_depth(struct pevent *pevent, void *data)
+{
+       return __parse_common(pevent, data,
+                             &pevent->ld_size, &pevent->ld_offset,
+                             "common_lock_depth");
+}
+
+static int parse_common_migrate_disable(struct pevent *pevent, void *data)
+{
+       return __parse_common(pevent, data,
+                             &pevent->ld_size, &pevent->ld_offset,
+                             "common_migrate_disable");
+}
+
+static int events_id_cmp(const void *a, const void *b);
+
+/**
+ * pevent_find_event - find an event by given id
+ * @pevent: a handle to the pevent
+ * @id: the id of the event
+ *
+ * Returns an event that has a given @id.
+ */
+struct event_format *pevent_find_event(struct pevent *pevent, int id)
+{
+       struct event_format **eventptr;
+       struct event_format key;
+       struct event_format *pkey = &key;
+
+       /* Check cache first */
+       if (pevent->last_event && pevent->last_event->id == id)
+               return pevent->last_event;
+
+       key.id = id;
+
+       eventptr = bsearch(&pkey, pevent->events, pevent->nr_events,
+                          sizeof(*pevent->events), events_id_cmp);
+
+       if (eventptr) {
+               pevent->last_event = *eventptr;
+               return *eventptr;
+       }
+
+       return NULL;
+}
+
+/**
+ * pevent_find_event_by_name - find an event by given name
+ * @pevent: a handle to the pevent
+ * @sys: the system name to search for
+ * @name: the name of the event to search for
+ *
+ * This returns an event with a given @name and under the system
+ * @sys. If @sys is NULL the first event with @name is returned.
+ */
+struct event_format *
+pevent_find_event_by_name(struct pevent *pevent,
+                         const char *sys, const char *name)
+{
+       struct event_format *event;
+       int i;
+
+       if (pevent->last_event &&
+           strcmp(pevent->last_event->name, name) == 0 &&
+           (!sys || strcmp(pevent->last_event->system, sys) == 0))
+               return pevent->last_event;
+
+       for (i = 0; i < pevent->nr_events; i++) {
+               event = pevent->events[i];
+               if (strcmp(event->name, name) == 0) {
+                       if (!sys)
+                               break;
+                       if (strcmp(event->system, sys) == 0)
+                               break;
+               }
+       }
+       if (i == pevent->nr_events)
+               event = NULL;
+
+       pevent->last_event = event;
+       return event;
+}
+
+static unsigned long long
+eval_num_arg(void *data, int size, struct event_format *event, struct print_arg *arg)
+{
+       struct pevent *pevent = event->pevent;
+       unsigned long long val = 0;
+       unsigned long long left, right;
+       struct print_arg *typearg = NULL;
+       struct print_arg *larg;
+       unsigned long offset;
+       unsigned int field_size;
+
+       switch (arg->type) {
+       case PRINT_NULL:
+               /* ?? */
+               return 0;
+       case PRINT_ATOM:
+               return strtoull(arg->atom.atom, NULL, 0);
+       case PRINT_FIELD:
+               if (!arg->field.field) {
+                       arg->field.field = pevent_find_any_field(event, arg->field.name);
+                       if (!arg->field.field)
+                               die("field %s not found", arg->field.name);
+               }
+               /* must be a number */
+               val = pevent_read_number(pevent, data + arg->field.field->offset,
+                               arg->field.field->size);
+               break;
+       case PRINT_FLAGS:
+       case PRINT_SYMBOL:
+       case PRINT_HEX:
+               break;
+       case PRINT_TYPE:
+               val = eval_num_arg(data, size, event, arg->typecast.item);
+               return eval_type(val, arg, 0);
+       case PRINT_STRING:
+       case PRINT_BSTRING:
+               return 0;
+       case PRINT_FUNC: {
+               struct trace_seq s;
+               trace_seq_init(&s);
+               val = process_defined_func(&s, data, size, event, arg);
+               trace_seq_destroy(&s);
+               return val;
+       }
+       case PRINT_OP:
+               if (strcmp(arg->op.op, "[") == 0) {
+                       /*
+                        * Arrays are special, since we don't want
+                        * to read the arg as is.
+                        */
+                       right = eval_num_arg(data, size, event, arg->op.right);
+
+                       /* handle typecasts */
+                       larg = arg->op.left;
+                       while (larg->type == PRINT_TYPE) {
+                               if (!typearg)
+                                       typearg = larg;
+                               larg = larg->typecast.item;
+                       }
+
+                       /* Default to long size */
+                       field_size = pevent->long_size;
+
+                       switch (larg->type) {
+                       case PRINT_DYNAMIC_ARRAY:
+                               offset = pevent_read_number(pevent,
+                                                  data + larg->dynarray.field->offset,
+                                                  larg->dynarray.field->size);
+                               if (larg->dynarray.field->elementsize)
+                                       field_size = larg->dynarray.field->elementsize;
+                               /*
+                                * The actual length of the dynamic array is stored
+                                * in the top half of the field, and the offset
+                                * is in the bottom half of the 32 bit field.
+                                */
+                               offset &= 0xffff;
+                               offset += right;
+                               break;
+                       case PRINT_FIELD:
+                               if (!larg->field.field) {
+                                       larg->field.field =
+                                               pevent_find_any_field(event, larg->field.name);
+                                       if (!larg->field.field)
+                                               die("field %s not found", larg->field.name);
+                               }
+                               field_size = larg->field.field->elementsize;
+                               offset = larg->field.field->offset +
+                                       right * larg->field.field->elementsize;
+                               break;
+                       default:
+                               goto default_op; /* oops, all bets off */
+                       }
+                       val = pevent_read_number(pevent,
+                                                data + offset, field_size);
+                       if (typearg)
+                               val = eval_type(val, typearg, 1);
+                       break;
+               } else if (strcmp(arg->op.op, "?") == 0) {
+                       left = eval_num_arg(data, size, event, arg->op.left);
+                       arg = arg->op.right;
+                       if (left)
+                               val = eval_num_arg(data, size, event, arg->op.left);
+                       else
+                               val = eval_num_arg(data, size, event, arg->op.right);
+                       break;
+               }
+ default_op:
+               left = eval_num_arg(data, size, event, arg->op.left);
+               right = eval_num_arg(data, size, event, arg->op.right);
+               switch (arg->op.op[0]) {
+               case '!':
+                       switch (arg->op.op[1]) {
+                       case 0:
+                               val = !right;
+                               break;
+                       case '=':
+                               val = left != right;
+                               break;
+                       default:
+                               die("unknown op '%s'", arg->op.op);
+                       }
+                       break;
+               case '~':
+                       val = ~right;
+                       break;
+               case '|':
+                       if (arg->op.op[1])
+                               val = left || right;
+                       else
+                               val = left | right;
+                       break;
+               case '&':
+                       if (arg->op.op[1])
+                               val = left && right;
+                       else
+                               val = left & right;
+                       break;
+               case '<':
+                       switch (arg->op.op[1]) {
+                       case 0:
+                               val = left < right;
+                               break;
+                       case '<':
+                               val = left << right;
+                               break;
+                       case '=':
+                               val = left <= right;
+                               break;
+                       default:
+                               die("unknown op '%s'", arg->op.op);
+                       }
+                       break;
+               case '>':
+                       switch (arg->op.op[1]) {
+                       case 0:
+                               val = left > right;
+                               break;
+                       case '>':
+                               val = left >> right;
+                               break;
+                       case '=':
+                               val = left >= right;
+                               break;
+                       default:
+                               die("unknown op '%s'", arg->op.op);
+                       }
+                       break;
+               case '=':
+                       if (arg->op.op[1] != '=')
+                               die("unknown op '%s'", arg->op.op);
+                       val = left == right;
+                       break;
+               case '-':
+                       val = left - right;
+                       break;
+               case '+':
+                       val = left + right;
+                       break;
+               case '/':
+                       val = left / right;
+                       break;
+               case '*':
+                       val = left * right;
+                       break;
+               default:
+                       die("unknown op '%s'", arg->op.op);
+               }
+               break;
+       default: /* not sure what to do there */
+               return 0;
+       }
+       return val;
+}
+
+struct flag {
+       const char *name;
+       unsigned long long value;
+};
+
+static const struct flag flags[] = {
+       { "HI_SOFTIRQ", 0 },
+       { "TIMER_SOFTIRQ", 1 },
+       { "NET_TX_SOFTIRQ", 2 },
+       { "NET_RX_SOFTIRQ", 3 },
+       { "BLOCK_SOFTIRQ", 4 },
+       { "BLOCK_IOPOLL_SOFTIRQ", 5 },
+       { "TASKLET_SOFTIRQ", 6 },
+       { "SCHED_SOFTIRQ", 7 },
+       { "HRTIMER_SOFTIRQ", 8 },
+       { "RCU_SOFTIRQ", 9 },
+
+       { "HRTIMER_NORESTART", 0 },
+       { "HRTIMER_RESTART", 1 },
+};
+
+static unsigned long long eval_flag(const char *flag)
+{
+       int i;
+
+       /*
+        * Some flags in the format files do not get converted.
+        * If the flag is not numeric, see if it is something that
+        * we already know about.
+        */
+       if (isdigit(flag[0]))
+               return strtoull(flag, NULL, 0);
+
+       for (i = 0; i < (int)(sizeof(flags)/sizeof(flags[0])); i++)
+               if (strcmp(flags[i].name, flag) == 0)
+                       return flags[i].value;
+
+       return 0;
+}
+
+static void print_str_to_seq(struct trace_seq *s, const char *format,
+                            int len_arg, const char *str)
+{
+       if (len_arg >= 0)
+               trace_seq_printf(s, format, len_arg, str);
+       else
+               trace_seq_printf(s, format, str);
+}
+
+static void print_str_arg(struct trace_seq *s, void *data, int size,
+                         struct event_format *event, const char *format,
+                         int len_arg, struct print_arg *arg)
+{
+       struct pevent *pevent = event->pevent;
+       struct print_flag_sym *flag;
+       struct format_field *field;
+       unsigned long long val, fval;
+       unsigned long addr;
+       char *str;
+       unsigned char *hex;
+       int print;
+       int i, len;
+
+       switch (arg->type) {
+       case PRINT_NULL:
+               /* ?? */
+               return;
+       case PRINT_ATOM:
+               print_str_to_seq(s, format, len_arg, arg->atom.atom);
+               return;
+       case PRINT_FIELD:
+               field = arg->field.field;
+               if (!field) {
+                       field = pevent_find_any_field(event, arg->field.name);
+                       if (!field)
+                               die("field %s not found", arg->field.name);
+                       arg->field.field = field;
+               }
+               /* Zero sized fields, mean the rest of the data */
+               len = field->size ? : size - field->offset;
+
+               /*
+                * Some events pass in pointers. If this is not an array
+                * and the size is the same as long_size, assume that it
+                * is a pointer.
+                */
+               if (!(field->flags & FIELD_IS_ARRAY) &&
+                   field->size == pevent->long_size) {
+                       addr = *(unsigned long *)(data + field->offset);
+                       trace_seq_printf(s, "%lx", addr);
+                       break;
+               }
+               str = malloc_or_die(len + 1);
+               memcpy(str, data + field->offset, len);
+               str[len] = 0;
+               print_str_to_seq(s, format, len_arg, str);
+               free(str);
+               break;
+       case PRINT_FLAGS:
+               val = eval_num_arg(data, size, event, arg->flags.field);
+               print = 0;
+               for (flag = arg->flags.flags; flag; flag = flag->next) {
+                       fval = eval_flag(flag->value);
+                       if (!val && !fval) {
+                               print_str_to_seq(s, format, len_arg, flag->str);
+                               break;
+                       }
+                       if (fval && (val & fval) == fval) {
+                               if (print && arg->flags.delim)
+                                       trace_seq_puts(s, arg->flags.delim);
+                               print_str_to_seq(s, format, len_arg, flag->str);
+                               print = 1;
+                               val &= ~fval;
+                       }
+               }
+               break;
+       case PRINT_SYMBOL:
+               val = eval_num_arg(data, size, event, arg->symbol.field);
+               for (flag = arg->symbol.symbols; flag; flag = flag->next) {
+                       fval = eval_flag(flag->value);
+                       if (val == fval) {
+                               print_str_to_seq(s, format, len_arg, flag->str);
+                               break;
+                       }
+               }
+               break;
+       case PRINT_HEX:
+               field = arg->hex.field->field.field;
+               if (!field) {
+                       str = arg->hex.field->field.name;
+                       field = pevent_find_any_field(event, str);
+                       if (!field)
+                               die("field %s not found", str);
+                       arg->hex.field->field.field = field;
+               }
+               hex = data + field->offset;
+               len = eval_num_arg(data, size, event, arg->hex.size);
+               for (i = 0; i < len; i++) {
+                       if (i)
+                               trace_seq_putc(s, ' ');
+                       trace_seq_printf(s, "%02x", hex[i]);
+               }
+               break;
+
+       case PRINT_TYPE:
+               break;
+       case PRINT_STRING: {
+               int str_offset;
+
+               if (arg->string.offset == -1) {
+                       struct format_field *f;
+
+                       f = pevent_find_any_field(event, arg->string.string);
+                       arg->string.offset = f->offset;
+               }
+               str_offset = data2host4(pevent, data + arg->string.offset);
+               str_offset &= 0xffff;
+               print_str_to_seq(s, format, len_arg, ((char *)data) + str_offset);
+               break;
+       }
+       case PRINT_BSTRING:
+               print_str_to_seq(s, format, len_arg, arg->string.string);
+               break;
+       case PRINT_OP:
+               /*
+                * The only op for string should be ? :
+                */
+               if (arg->op.op[0] != '?')
+                       return;
+               val = eval_num_arg(data, size, event, arg->op.left);
+               if (val)
+                       print_str_arg(s, data, size, event,
+                                     format, len_arg, arg->op.right->op.left);
+               else
+                       print_str_arg(s, data, size, event,
+                                     format, len_arg, arg->op.right->op.right);
+               break;
+       case PRINT_FUNC:
+               process_defined_func(s, data, size, event, arg);
+               break;
+       default:
+               /* well... */
+               break;
+       }
+}
+
+static unsigned long long
+process_defined_func(struct trace_seq *s, void *data, int size,
+                    struct event_format *event, struct print_arg *arg)
+{
+       struct pevent_function_handler *func_handle = arg->func.func;
+       struct pevent_func_params *param;
+       unsigned long long *args;
+       unsigned long long ret;
+       struct print_arg *farg;
+       struct trace_seq str;
+       struct save_str {
+               struct save_str *next;
+               char *str;
+       } *strings = NULL, *string;
+       int i;
+
+       if (!func_handle->nr_args) {
+               ret = (*func_handle->func)(s, NULL);
+               goto out;
+       }
+
+       farg = arg->func.args;
+       param = func_handle->params;
+
+       args = malloc_or_die(sizeof(*args) * func_handle->nr_args);
+       for (i = 0; i < func_handle->nr_args; i++) {
+               switch (param->type) {
+               case PEVENT_FUNC_ARG_INT:
+               case PEVENT_FUNC_ARG_LONG:
+               case PEVENT_FUNC_ARG_PTR:
+                       args[i] = eval_num_arg(data, size, event, farg);
+                       break;
+               case PEVENT_FUNC_ARG_STRING:
+                       trace_seq_init(&str);
+                       print_str_arg(&str, data, size, event, "%s", -1, farg);
+                       trace_seq_terminate(&str);
+                       string = malloc_or_die(sizeof(*string));
+                       string->next = strings;
+                       string->str = strdup(str.buffer);
+                       if (!string->str)
+                               die("malloc str");
+
+                       args[i] = (unsigned long long)string->str;
+                       strings = string;
+                       trace_seq_destroy(&str);
+                       break;
+               default:
+                       /*
+                        * Something went totally wrong, this is not
+                        * an input error, something in this code broke.
+                        */
+                       die("Unexpected end of arguments\n");
+                       break;
+               }
+               farg = farg->next;
+               param = param->next;
+       }
+
+       ret = (*func_handle->func)(s, args);
+       free(args);
+       while (strings) {
+               string = strings;
+               strings = string->next;
+               free(string->str);
+               free(string);
+       }
+
+ out:
+       /* TBD : handle return type here */
+       return ret;
+}
+
+static struct print_arg *make_bprint_args(char *fmt, void *data, int size, struct event_format *event)
+{
+       struct pevent *pevent = event->pevent;
+       struct format_field *field, *ip_field;
+       struct print_arg *args, *arg, **next;
+       unsigned long long ip, val;
+       char *ptr;
+       void *bptr;
+       int vsize;
+
+       field = pevent->bprint_buf_field;
+       ip_field = pevent->bprint_ip_field;
+
+       if (!field) {
+               field = pevent_find_field(event, "buf");
+               if (!field)
+                       die("can't find buffer field for binary printk");
+               ip_field = pevent_find_field(event, "ip");
+               if (!ip_field)
+                       die("can't find ip field for binary printk");
+               pevent->bprint_buf_field = field;
+               pevent->bprint_ip_field = ip_field;
+       }
+
+       ip = pevent_read_number(pevent, data + ip_field->offset, ip_field->size);
+
+       /*
+        * The first arg is the IP pointer.
+        */
+       args = alloc_arg();
+       arg = args;
+       arg->next = NULL;
+       next = &arg->next;
+
+       arg->type = PRINT_ATOM;
+       arg->atom.atom = malloc_or_die(32);
+       sprintf(arg->atom.atom, "%lld", ip);
+
+       /* skip the first "%pf : " */
+       for (ptr = fmt + 6, bptr = data + field->offset;
+            bptr < data + size && *ptr; ptr++) {
+               int ls = 0;
+
+               if (*ptr == '%') {
+ process_again:
+                       ptr++;
+                       switch (*ptr) {
+                       case '%':
+                               break;
+                       case 'l':
+                               ls++;
+                               goto process_again;
+                       case 'L':
+                               ls = 2;
+                               goto process_again;
+                       case '0' ... '9':
+                               goto process_again;
+                       case '.':
+                               goto process_again;
+                       case 'p':
+                               ls = 1;
+                               /* fall through */
+                       case 'd':
+                       case 'u':
+                       case 'x':
+                       case 'i':
+                               switch (ls) {
+                               case 0:
+                                       vsize = 4;
+                                       break;
+                               case 1:
+                                       vsize = pevent->long_size;
+                                       break;
+                               case 2:
+                                       vsize = 8;
+                                       break;
+                               default:
+                                       vsize = ls; /* ? */
+                                       break;
+                               }
+                       /* fall through */
+                       case '*':
+                               if (*ptr == '*')
+                                       vsize = 4;
+
+                               /* the pointers are always 4 bytes aligned */
+                               bptr = (void *)(((unsigned long)bptr + 3) &
+                                               ~3);
+                               val = pevent_read_number(pevent, bptr, vsize);
+                               bptr += vsize;
+                               arg = alloc_arg();
+                               arg->next = NULL;
+                               arg->type = PRINT_ATOM;
+                               arg->atom.atom = malloc_or_die(32);
+                               sprintf(arg->atom.atom, "%lld", val);
+                               *next = arg;
+                               next = &arg->next;
+                               /*
+                                * The '*' case means that an arg is used as the length.
+                                * We need to continue to figure out for what.
+                                */
+                               if (*ptr == '*')
+                                       goto process_again;
+
+                               break;
+                       case 's':
+                               arg = alloc_arg();
+                               arg->next = NULL;
+                               arg->type = PRINT_BSTRING;
+                               arg->string.string = strdup(bptr);
+                               if (!arg->string.string)
+                                       break;
+                               bptr += strlen(bptr) + 1;
+                               *next = arg;
+                               next = &arg->next;
+                       default:
+                               break;
+                       }
+               }
+       }
+
+       return args;
+}
+
+static void free_args(struct print_arg *args)
+{
+       struct print_arg *next;
+
+       while (args) {
+               next = args->next;
+
+               free_arg(args);
+               args = next;
+       }
+}
+
+static char *
+get_bprint_format(void *data, int size __unused, struct event_format *event)
+{
+       struct pevent *pevent = event->pevent;
+       unsigned long long addr;
+       struct format_field *field;
+       struct printk_map *printk;
+       char *format;
+       char *p;
+
+       field = pevent->bprint_fmt_field;
+
+       if (!field) {
+               field = pevent_find_field(event, "fmt");
+               if (!field)
+                       die("can't find format field for binary printk");
+               pevent->bprint_fmt_field = field;
+       }
+
+       addr = pevent_read_number(pevent, data + field->offset, field->size);
+
+       printk = find_printk(pevent, addr);
+       if (!printk) {
+               format = malloc_or_die(45);
+               sprintf(format, "%%pf : (NO FORMAT FOUND at %llx)\n",
+                       addr);
+               return format;
+       }
+
+       p = printk->printk;
+       /* Remove any quotes. */
+       if (*p == '"')
+               p++;
+       format = malloc_or_die(strlen(p) + 10);
+       sprintf(format, "%s : %s", "%pf", p);
+       /* remove ending quotes and new line since we will add one too */
+       p = format + strlen(format) - 1;
+       if (*p == '"')
+               *p = 0;
+
+       p -= 2;
+       if (strcmp(p, "\\n") == 0)
+               *p = 0;
+
+       return format;
+}
+
+static void print_mac_arg(struct trace_seq *s, int mac, void *data, int size,
+                         struct event_format *event, struct print_arg *arg)
+{
+       unsigned char *buf;
+       char *fmt = "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x";
+
+       if (arg->type == PRINT_FUNC) {
+               process_defined_func(s, data, size, event, arg);
+               return;
+       }
+
+       if (arg->type != PRINT_FIELD) {
+               trace_seq_printf(s, "ARG TYPE NOT FIELD BUT %d",
+                                arg->type);
+               return;
+       }
+
+       if (mac == 'm')
+               fmt = "%.2x%.2x%.2x%.2x%.2x%.2x";
+       if (!arg->field.field) {
+               arg->field.field =
+                       pevent_find_any_field(event, arg->field.name);
+               if (!arg->field.field)
+                       die("field %s not found", arg->field.name);
+       }
+       if (arg->field.field->size != 6) {
+               trace_seq_printf(s, "INVALIDMAC");
+               return;
+       }
+       buf = data + arg->field.field->offset;
+       trace_seq_printf(s, fmt, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]);
+}
+
+static int is_printable_array(char *p, unsigned int len)
+{
+       unsigned int i;
+
+       for (i = 0; i < len && p[i]; i++)
+               if (!isprint(p[i]))
+                   return 0;
+       return 1;
+}
+
+static void print_event_fields(struct trace_seq *s, void *data, int size,
+                              struct event_format *event)
+{
+       struct format_field *field;
+       unsigned long long val;
+       unsigned int offset, len, i;
+
+       field = event->format.fields;
+       while (field) {
+               trace_seq_printf(s, " %s=", field->name);
+               if (field->flags & FIELD_IS_ARRAY) {
+                       offset = field->offset;
+                       len = field->size;
+                       if (field->flags & FIELD_IS_DYNAMIC) {
+                               val = pevent_read_number(event->pevent, data + offset, len);
+                               offset = val;
+                               len = offset >> 16;
+                               offset &= 0xffff;
+                       }
+                       if (field->flags & FIELD_IS_STRING &&
+                           is_printable_array(data + offset, len)) {
+                               trace_seq_printf(s, "%s", (char *)data + offset);
+                       } else {
+                               trace_seq_puts(s, "ARRAY[");
+                               for (i = 0; i < len; i++) {
+                                       if (i)
+                                               trace_seq_puts(s, ", ");
+                                       trace_seq_printf(s, "%02x",
+                                                        *((unsigned char *)data + offset + i));
+                               }
+                               trace_seq_putc(s, ']');
+                               field->flags &= ~FIELD_IS_STRING;
+                       }
+               } else {
+                       val = pevent_read_number(event->pevent, data + field->offset,
+                                                field->size);
+                       if (field->flags & FIELD_IS_POINTER) {
+                               trace_seq_printf(s, "0x%llx", val);
+                       } else if (field->flags & FIELD_IS_SIGNED) {
+                               switch (field->size) {
+                               case 4:
+                                       /*
+                                        * If field is long then print it in hex.
+                                        * A long usually stores pointers.
+                                        */
+                                       if (field->flags & FIELD_IS_LONG)
+                                               trace_seq_printf(s, "0x%x", (int)val);
+                                       else
+                                               trace_seq_printf(s, "%d", (int)val);
+                                       break;
+                               case 2:
+                                       trace_seq_printf(s, "%2d", (short)val);
+                                       break;
+                               case 1:
+                                       trace_seq_printf(s, "%1d", (char)val);
+                                       break;
+                               default:
+                                       trace_seq_printf(s, "%lld", val);
+                               }
+                       } else {
+                               if (field->flags & FIELD_IS_LONG)
+                                       trace_seq_printf(s, "0x%llx", val);
+                               else
+                                       trace_seq_printf(s, "%llu", val);
+                       }
+               }
+               field = field->next;
+       }
+}
+
+static void pretty_print(struct trace_seq *s, void *data, int size, struct event_format *event)
+{
+       struct pevent *pevent = event->pevent;
+       struct print_fmt *print_fmt = &event->print_fmt;
+       struct print_arg *arg = print_fmt->args;
+       struct print_arg *args = NULL;
+       const char *ptr = print_fmt->format;
+       unsigned long long val;
+       struct func_map *func;
+       const char *saveptr;
+       char *bprint_fmt = NULL;
+       char format[32];
+       int show_func;
+       int len_as_arg;
+       int len_arg;
+       int len;
+       int ls;
+
+       if (event->flags & EVENT_FL_FAILED) {
+               trace_seq_printf(s, "[FAILED TO PARSE]");
+               print_event_fields(s, data, size, event);
+               return;
+       }
+
+       if (event->flags & EVENT_FL_ISBPRINT) {
+               bprint_fmt = get_bprint_format(data, size, event);
+               args = make_bprint_args(bprint_fmt, data, size, event);
+               arg = args;
+               ptr = bprint_fmt;
+       }
+
+       for (; *ptr; ptr++) {
+               ls = 0;
+               if (*ptr == '\\') {
+                       ptr++;
+                       switch (*ptr) {
+                       case 'n':
+                               trace_seq_putc(s, '\n');
+                               break;
+                       case 't':
+                               trace_seq_putc(s, '\t');
+                               break;
+                       case 'r':
+                               trace_seq_putc(s, '\r');
+                               break;
+                       case '\\':
+                               trace_seq_putc(s, '\\');
+                               break;
+                       default:
+                               trace_seq_putc(s, *ptr);
+                               break;
+                       }
+
+               } else if (*ptr == '%') {
+                       saveptr = ptr;
+                       show_func = 0;
+                       len_as_arg = 0;
+ cont_process:
+                       ptr++;
+                       switch (*ptr) {
+                       case '%':
+                               trace_seq_putc(s, '%');
+                               break;
+                       case '#':
+                               /* FIXME: need to handle properly */
+                               goto cont_process;
+                       case 'h':
+                               ls--;
+                               goto cont_process;
+                       case 'l':
+                               ls++;
+                               goto cont_process;
+                       case 'L':
+                               ls = 2;
+                               goto cont_process;
+                       case '*':
+                               /* The argument is the length. */
+                               if (!arg)
+                                       die("no argument match");
+                               len_arg = eval_num_arg(data, size, event, arg);
+                               len_as_arg = 1;
+                               arg = arg->next;
+                               goto cont_process;
+                       case '.':
+                       case 'z':
+                       case 'Z':
+                       case '0' ... '9':
+                               goto cont_process;
+                       case 'p':
+                               if (pevent->long_size == 4)
+                                       ls = 1;
+                               else
+                                       ls = 2;
+
+                               if (*(ptr+1) == 'F' ||
+                                   *(ptr+1) == 'f') {
+                                       ptr++;
+                                       show_func = *ptr;
+                               } else if (*(ptr+1) == 'M' || *(ptr+1) == 'm') {
+                                       print_mac_arg(s, *(ptr+1), data, size, event, arg);
+                                       ptr++;
+                                       arg = arg->next;
+                                       break;
+                               }
+
+                               /* fall through */
+                       case 'd':
+                       case 'i':
+                       case 'x':
+                       case 'X':
+                       case 'u':
+                               if (!arg)
+                                       die("no argument match");
+
+                               len = ((unsigned long)ptr + 1) -
+                                       (unsigned long)saveptr;
+
+                               /* should never happen */
+                               if (len > 31)
+                                       die("bad format!");
+
+                               memcpy(format, saveptr, len);
+                               format[len] = 0;
+
+                               val = eval_num_arg(data, size, event, arg);
+                               arg = arg->next;
+
+                               if (show_func) {
+                                       func = find_func(pevent, val);
+                                       if (func) {
+                                               trace_seq_puts(s, func->func);
+                                               if (show_func == 'F')
+                                                       trace_seq_printf(s,
+                                                              "+0x%llx",
+                                                              val - func->addr);
+                                               break;
+                                       }
+                               }
+                               if (pevent->long_size == 8 && ls &&
+                                   sizeof(long) != 8) {
+                                       char *p;
+
+                                       ls = 2;
+                                       /* make %l into %ll */
+                                       p = strchr(format, 'l');
+                                       if (p)
+                                               memmove(p+1, p, strlen(p)+1);
+                                       else if (strcmp(format, "%p") == 0)
+                                               strcpy(format, "0x%llx");
+                               }
+                               switch (ls) {
+                               case -2:
+                                       if (len_as_arg)
+                                               trace_seq_printf(s, format, len_arg, (char)val);
+                                       else
+                                               trace_seq_printf(s, format, (char)val);
+                                       break;
+                               case -1:
+                                       if (len_as_arg)
+                                               trace_seq_printf(s, format, len_arg, (short)val);
+                                       else
+                                               trace_seq_printf(s, format, (short)val);
+                                       break;
+                               case 0:
+                                       if (len_as_arg)
+                                               trace_seq_printf(s, format, len_arg, (int)val);
+                                       else
+                                               trace_seq_printf(s, format, (int)val);
+                                       break;
+                               case 1:
+                                       if (len_as_arg)
+                                               trace_seq_printf(s, format, len_arg, (long)val);
+                                       else
+                                               trace_seq_printf(s, format, (long)val);
+                                       break;
+                               case 2:
+                                       if (len_as_arg)
+                                               trace_seq_printf(s, format, len_arg,
+                                                                (long long)val);
+                                       else
+                                               trace_seq_printf(s, format, (long long)val);
+                                       break;
+                               default:
+                                       die("bad count (%d)", ls);
+                               }
+                               break;
+                       case 's':
+                               if (!arg)
+                                       die("no matching argument");
+
+                               len = ((unsigned long)ptr + 1) -
+                                       (unsigned long)saveptr;
+
+                               /* should never happen */
+                               if (len > 31)
+                                       die("bad format!");
+
+                               memcpy(format, saveptr, len);
+                               format[len] = 0;
+                               if (!len_as_arg)
+                                       len_arg = -1;
+                               print_str_arg(s, data, size, event,
+                                             format, len_arg, arg);
+                               arg = arg->next;
+                               break;
+                       default:
+                               trace_seq_printf(s, ">%c<", *ptr);
+
+                       }
+               } else
+                       trace_seq_putc(s, *ptr);
+       }
+
+       if (args) {
+               free_args(args);
+               free(bprint_fmt);
+       }
+}
+
+/**
+ * pevent_data_lat_fmt - parse the data for the latency format
+ * @pevent: a handle to the pevent
+ * @s: the trace_seq to write to
+ * @record: the record to read from
+ *
+ * This parses out the Latency format (interrupts disabled,
+ * need rescheduling, in hard/soft interrupt, preempt count
+ * and lock depth) and places it into the trace_seq.
+ */
+void pevent_data_lat_fmt(struct pevent *pevent,
+                        struct trace_seq *s, struct pevent_record *record)
+{
+       static int check_lock_depth = 1;
+       static int check_migrate_disable = 1;
+       static int lock_depth_exists;
+       static int migrate_disable_exists;
+       unsigned int lat_flags;
+       unsigned int pc;
+       int lock_depth;
+       int migrate_disable;
+       int hardirq;
+       int softirq;
+       void *data = record->data;
+
+       lat_flags = parse_common_flags(pevent, data);
+       pc = parse_common_pc(pevent, data);
+       /* lock_depth may not always exist */
+       if (lock_depth_exists)
+               lock_depth = parse_common_lock_depth(pevent, data);
+       else if (check_lock_depth) {
+               lock_depth = parse_common_lock_depth(pevent, data);
+               if (lock_depth < 0)
+                       check_lock_depth = 0;
+               else
+                       lock_depth_exists = 1;
+       }
+
+       /* migrate_disable may not always exist */
+       if (migrate_disable_exists)
+               migrate_disable = parse_common_migrate_disable(pevent, data);
+       else if (check_migrate_disable) {
+               migrate_disable = parse_common_migrate_disable(pevent, data);
+               if (migrate_disable < 0)
+                       check_migrate_disable = 0;
+               else
+                       migrate_disable_exists = 1;
+       }
+
+       hardirq = lat_flags & TRACE_FLAG_HARDIRQ;
+       softirq = lat_flags & TRACE_FLAG_SOFTIRQ;
+
+       trace_seq_printf(s, "%c%c%c",
+              (lat_flags & TRACE_FLAG_IRQS_OFF) ? 'd' :
+              (lat_flags & TRACE_FLAG_IRQS_NOSUPPORT) ?
+              'X' : '.',
+              (lat_flags & TRACE_FLAG_NEED_RESCHED) ?
+              'N' : '.',
+              (hardirq && softirq) ? 'H' :
+              hardirq ? 'h' : softirq ? 's' : '.');
+
+       if (pc)
+               trace_seq_printf(s, "%x", pc);
+       else
+               trace_seq_putc(s, '.');
+
+       if (migrate_disable_exists) {
+               if (migrate_disable < 0)
+                       trace_seq_putc(s, '.');
+               else
+                       trace_seq_printf(s, "%d", migrate_disable);
+       }
+
+       if (lock_depth_exists) {
+               if (lock_depth < 0)
+                       trace_seq_putc(s, '.');
+               else
+                       trace_seq_printf(s, "%d", lock_depth);
+       }
+
+       trace_seq_terminate(s);
+}
+
+/**
+ * pevent_data_type - parse out the given event type
+ * @pevent: a handle to the pevent
+ * @rec: the record to read from
+ *
+ * This returns the event id from the @rec.
+ */
+int pevent_data_type(struct pevent *pevent, struct pevent_record *rec)
+{
+       return trace_parse_common_type(pevent, rec->data);
+}
+
+/**
+ * pevent_data_event_from_type - find the event by a given type
+ * @pevent: a handle to the pevent
+ * @type: the type of the event.
+ *
+ * This returns the event form a given @type;
+ */
+struct event_format *pevent_data_event_from_type(struct pevent *pevent, int type)
+{
+       return pevent_find_event(pevent, type);
+}
+
+/**
+ * pevent_data_pid - parse the PID from raw data
+ * @pevent: a handle to the pevent
+ * @rec: the record to parse
+ *
+ * This returns the PID from a raw data.
+ */
+int pevent_data_pid(struct pevent *pevent, struct pevent_record *rec)
+{
+       return parse_common_pid(pevent, rec->data);
+}
+
+/**
+ * pevent_data_comm_from_pid - return the command line from PID
+ * @pevent: a handle to the pevent
+ * @pid: the PID of the task to search for
+ *
+ * This returns a pointer to the command line that has the given
+ * @pid.
+ */
+const char *pevent_data_comm_from_pid(struct pevent *pevent, int pid)
+{
+       const char *comm;
+
+       comm = find_cmdline(pevent, pid);
+       return comm;
+}
+
+/**
+ * pevent_data_comm_from_pid - parse the data into the print format
+ * @s: the trace_seq to write to
+ * @event: the handle to the event
+ * @record: the record to read from
+ *
+ * This parses the raw @data using the given @event information and
+ * writes the print format into the trace_seq.
+ */
+void pevent_event_info(struct trace_seq *s, struct event_format *event,
+                      struct pevent_record *record)
+{
+       int print_pretty = 1;
+
+       if (event->pevent->print_raw)
+               print_event_fields(s, record->data, record->size, event);
+       else {
+
+               if (event->handler)
+                       print_pretty = event->handler(s, record, event,
+                                                     event->context);
+
+               if (print_pretty)
+                       pretty_print(s, record->data, record->size, event);
+       }
+
+       trace_seq_terminate(s);
+}
+
+void pevent_print_event(struct pevent *pevent, struct trace_seq *s,
+                       struct pevent_record *record)
+{
+       static char *spaces = "                    "; /* 20 spaces */
+       struct event_format *event;
+       unsigned long secs;
+       unsigned long usecs;
+       unsigned long nsecs;
+       const char *comm;
+       void *data = record->data;
+       int type;
+       int pid;
+       int len;
+       int p;
+
+       secs = record->ts / NSECS_PER_SEC;
+       nsecs = record->ts - secs * NSECS_PER_SEC;
+
+       if (record->size < 0) {
+               do_warning("ug! negative record size %d", record->size);
+               return;
+       }
+
+       type = trace_parse_common_type(pevent, data);
+
+       event = pevent_find_event(pevent, type);
+       if (!event) {
+               do_warning("ug! no event found for type %d", type);
+               return;
+       }
+
+       pid = parse_common_pid(pevent, data);
+       comm = find_cmdline(pevent, pid);
+
+       if (pevent->latency_format) {
+               trace_seq_printf(s, "%8.8s-%-5d %3d",
+                      comm, pid, record->cpu);
+               pevent_data_lat_fmt(pevent, s, record);
+       } else
+               trace_seq_printf(s, "%16s-%-5d [%03d]", comm, pid, record->cpu);
+
+       if (pevent->flags & PEVENT_NSEC_OUTPUT) {
+               usecs = nsecs;
+               p = 9;
+       } else {
+               usecs = (nsecs + 500) / NSECS_PER_USEC;
+               p = 6;
+       }
+
+       trace_seq_printf(s, " %5lu.%0*lu: %s: ", secs, p, usecs, event->name);
+
+       /* Space out the event names evenly. */
+       len = strlen(event->name);
+       if (len < 20)
+               trace_seq_printf(s, "%.*s", 20 - len, spaces);
+
+       pevent_event_info(s, event, record);
+}
+
+static int events_id_cmp(const void *a, const void *b)
+{
+       struct event_format * const * ea = a;
+       struct event_format * const * eb = b;
+
+       if ((*ea)->id < (*eb)->id)
+               return -1;
+
+       if ((*ea)->id > (*eb)->id)
+               return 1;
+
+       return 0;
+}
+
+static int events_name_cmp(const void *a, const void *b)
+{
+       struct event_format * const * ea = a;
+       struct event_format * const * eb = b;
+       int res;
+
+       res = strcmp((*ea)->name, (*eb)->name);
+       if (res)
+               return res;
+
+       res = strcmp((*ea)->system, (*eb)->system);
+       if (res)
+               return res;
+
+       return events_id_cmp(a, b);
+}
+
+static int events_system_cmp(const void *a, const void *b)
+{
+       struct event_format * const * ea = a;
+       struct event_format * const * eb = b;
+       int res;
+
+       res = strcmp((*ea)->system, (*eb)->system);
+       if (res)
+               return res;
+
+       res = strcmp((*ea)->name, (*eb)->name);
+       if (res)
+               return res;
+
+       return events_id_cmp(a, b);
+}
+
+struct event_format **pevent_list_events(struct pevent *pevent, enum event_sort_type sort_type)
+{
+       struct event_format **events;
+       int (*sort)(const void *a, const void *b);
+
+       events = pevent->sort_events;
+
+       if (events && pevent->last_type == sort_type)
+               return events;
+
+       if (!events) {
+               events = malloc(sizeof(*events) * (pevent->nr_events + 1));
+               if (!events)
+                       return NULL;
+
+               memcpy(events, pevent->events, sizeof(*events) * pevent->nr_events);
+               events[pevent->nr_events] = NULL;
+
+               pevent->sort_events = events;
+
+               /* the internal events are sorted by id */
+               if (sort_type == EVENT_SORT_ID) {
+                       pevent->last_type = sort_type;
+                       return events;
+               }
+       }
+
+       switch (sort_type) {
+       case EVENT_SORT_ID:
+               sort = events_id_cmp;
+               break;
+       case EVENT_SORT_NAME:
+               sort = events_name_cmp;
+               break;
+       case EVENT_SORT_SYSTEM:
+               sort = events_system_cmp;
+               break;
+       default:
+               return events;
+       }
+
+       qsort(events, pevent->nr_events, sizeof(*events), sort);
+       pevent->last_type = sort_type;
+
+       return events;
+}
+
+static struct format_field **
+get_event_fields(const char *type, const char *name,
+                int count, struct format_field *list)
+{
+       struct format_field **fields;
+       struct format_field *field;
+       int i = 0;
+
+       fields = malloc_or_die(sizeof(*fields) * (count + 1));
+       for (field = list; field; field = field->next) {
+               fields[i++] = field;
+               if (i == count + 1) {
+                       do_warning("event %s has more %s fields than specified",
+                               name, type);
+                       i--;
+                       break;
+               }
+       }
+
+       if (i != count)
+               do_warning("event %s has less %s fields than specified",
+                       name, type);
+
+       fields[i] = NULL;
+
+       return fields;
+}
+
+/**
+ * pevent_event_common_fields - return a list of common fields for an event
+ * @event: the event to return the common fields of.
+ *
+ * Returns an allocated array of fields. The last item in the array is NULL.
+ * The array must be freed with free().
+ */
+struct format_field **pevent_event_common_fields(struct event_format *event)
+{
+       return get_event_fields("common", event->name,
+                               event->format.nr_common,
+                               event->format.common_fields);
+}
+
+/**
+ * pevent_event_fields - return a list of event specific fields for an event
+ * @event: the event to return the fields of.
+ *
+ * Returns an allocated array of fields. The last item in the array is NULL.
+ * The array must be freed with free().
+ */
+struct format_field **pevent_event_fields(struct event_format *event)
+{
+       return get_event_fields("event", event->name,
+                               event->format.nr_fields,
+                               event->format.fields);
+}
+
+static void print_fields(struct trace_seq *s, struct print_flag_sym *field)
+{
+       trace_seq_printf(s, "{ %s, %s }", field->value, field->str);
+       if (field->next) {
+               trace_seq_puts(s, ", ");
+               print_fields(s, field->next);
+       }
+}
+
+/* for debugging */
+static void print_args(struct print_arg *args)
+{
+       int print_paren = 1;
+       struct trace_seq s;
+
+       switch (args->type) {
+       case PRINT_NULL:
+               printf("null");
+               break;
+       case PRINT_ATOM:
+               printf("%s", args->atom.atom);
+               break;
+       case PRINT_FIELD:
+               printf("REC->%s", args->field.name);
+               break;
+       case PRINT_FLAGS:
+               printf("__print_flags(");
+               print_args(args->flags.field);
+               printf(", %s, ", args->flags.delim);
+               trace_seq_init(&s);
+               print_fields(&s, args->flags.flags);
+               trace_seq_do_printf(&s);
+               trace_seq_destroy(&s);
+               printf(")");
+               break;
+       case PRINT_SYMBOL:
+               printf("__print_symbolic(");
+               print_args(args->symbol.field);
+               printf(", ");
+               trace_seq_init(&s);
+               print_fields(&s, args->symbol.symbols);
+               trace_seq_do_printf(&s);
+               trace_seq_destroy(&s);
+               printf(")");
+               break;
+       case PRINT_HEX:
+               printf("__print_hex(");
+               print_args(args->hex.field);
+               printf(", ");
+               print_args(args->hex.size);
+               printf(")");
+               break;
+       case PRINT_STRING:
+       case PRINT_BSTRING:
+               printf("__get_str(%s)", args->string.string);
+               break;
+       case PRINT_TYPE:
+               printf("(%s)", args->typecast.type);
+               print_args(args->typecast.item);
+               break;
+       case PRINT_OP:
+               if (strcmp(args->op.op, ":") == 0)
+                       print_paren = 0;
+               if (print_paren)
+                       printf("(");
+               print_args(args->op.left);
+               printf(" %s ", args->op.op);
+               print_args(args->op.right);
+               if (print_paren)
+                       printf(")");
+               break;
+       default:
+               /* we should warn... */
+               return;
+       }
+       if (args->next) {
+               printf("\n");
+               print_args(args->next);
+       }
+}
+
+static void parse_header_field(const char *field,
+                              int *offset, int *size, int mandatory)
+{
+       unsigned long long save_input_buf_ptr;
+       unsigned long long save_input_buf_siz;
+       char *token;
+       int type;
+
+       save_input_buf_ptr = input_buf_ptr;
+       save_input_buf_siz = input_buf_siz;
+
+       if (read_expected(EVENT_ITEM, "field") < 0)
+               return;
+       if (read_expected(EVENT_OP, ":") < 0)
+               return;
+
+       /* type */
+       if (read_expect_type(EVENT_ITEM, &token) < 0)
+               goto fail;
+       free_token(token);
+
+       /*
+        * If this is not a mandatory field, then test it first.
+        */
+       if (mandatory) {
+               if (read_expected(EVENT_ITEM, field) < 0)
+                       return;
+       } else {
+               if (read_expect_type(EVENT_ITEM, &token) < 0)
+                       goto fail;
+               if (strcmp(token, field) != 0)
+                       goto discard;
+               free_token(token);
+       }
+
+       if (read_expected(EVENT_OP, ";") < 0)
+               return;
+       if (read_expected(EVENT_ITEM, "offset") < 0)
+               return;
+       if (read_expected(EVENT_OP, ":") < 0)
+               return;
+       if (read_expect_type(EVENT_ITEM, &token) < 0)
+               goto fail;
+       *offset = atoi(token);
+       free_token(token);
+       if (read_expected(EVENT_OP, ";") < 0)
+               return;
+       if (read_expected(EVENT_ITEM, "size") < 0)
+               return;
+       if (read_expected(EVENT_OP, ":") < 0)
+               return;
+       if (read_expect_type(EVENT_ITEM, &token) < 0)
+               goto fail;
+       *size = atoi(token);
+       free_token(token);
+       if (read_expected(EVENT_OP, ";") < 0)
+               return;
+       type = read_token(&token);
+       if (type != EVENT_NEWLINE) {
+               /* newer versions of the kernel have a "signed" type */
+               if (type != EVENT_ITEM)
+                       goto fail;
+
+               if (strcmp(token, "signed") != 0)
+                       goto fail;
+
+               free_token(token);
+
+               if (read_expected(EVENT_OP, ":") < 0)
+                       return;
+
+               if (read_expect_type(EVENT_ITEM, &token))
+                       goto fail;
+
+               free_token(token);
+               if (read_expected(EVENT_OP, ";") < 0)
+                       return;
+
+               if (read_expect_type(EVENT_NEWLINE, &token))
+                       goto fail;
+       }
+ fail:
+       free_token(token);
+       return;
+
+ discard:
+       input_buf_ptr = save_input_buf_ptr;
+       input_buf_siz = save_input_buf_siz;
+       *offset = 0;
+       *size = 0;
+       free_token(token);
+}
+
+/**
+ * pevent_parse_header_page - parse the data stored in the header page
+ * @pevent: the handle to the pevent
+ * @buf: the buffer storing the header page format string
+ * @size: the size of @buf
+ * @long_size: the long size to use if there is no header
+ *
+ * This parses the header page format for information on the
+ * ring buffer used. The @buf should be copied from
+ *
+ * /sys/kernel/debug/tracing/events/header_page
+ */
+int pevent_parse_header_page(struct pevent *pevent, char *buf, unsigned long size,
+                            int long_size)
+{
+       int ignore;
+
+       if (!size) {
+               /*
+                * Old kernels did not have header page info.
+                * Sorry but we just use what we find here in user space.
+                */
+               pevent->header_page_ts_size = sizeof(long long);
+               pevent->header_page_size_size = long_size;
+               pevent->header_page_data_offset = sizeof(long long) + long_size;
+               pevent->old_format = 1;
+               return -1;
+       }
+       init_input_buf(buf, size);
+
+       parse_header_field("timestamp", &pevent->header_page_ts_offset,
+                          &pevent->header_page_ts_size, 1);
+       parse_header_field("commit", &pevent->header_page_size_offset,
+                          &pevent->header_page_size_size, 1);
+       parse_header_field("overwrite", &pevent->header_page_overwrite,
+                          &ignore, 0);
+       parse_header_field("data", &pevent->header_page_data_offset,
+                          &pevent->header_page_data_size, 1);
+
+       return 0;
+}
+
+static int event_matches(struct event_format *event,
+                        int id, const char *sys_name,
+                        const char *event_name)
+{
+       if (id >= 0 && id != event->id)
+               return 0;
+
+       if (event_name && (strcmp(event_name, event->name) != 0))
+               return 0;
+
+       if (sys_name && (strcmp(sys_name, event->system) != 0))
+               return 0;
+
+       return 1;
+}
+
+static void free_handler(struct event_handler *handle)
+{
+       free((void *)handle->sys_name);
+       free((void *)handle->event_name);
+       free(handle);
+}
+
+static int find_event_handle(struct pevent *pevent, struct event_format *event)
+{
+       struct event_handler *handle, **next;
+
+       for (next = &pevent->handlers; *next;
+            next = &(*next)->next) {
+               handle = *next;
+               if (event_matches(event, handle->id,
+                                 handle->sys_name,
+                                 handle->event_name))
+                       break;
+       }
+
+       if (!(*next))
+               return 0;
+
+       pr_stat("overriding event (%d) %s:%s with new print handler",
+               event->id, event->system, event->name);
+
+       event->handler = handle->func;
+       event->context = handle->context;
+
+       *next = handle->next;
+       free_handler(handle);
+
+       return 1;
+}
+
+/**
+ * pevent_parse_event - parse the event format
+ * @pevent: the handle to the pevent
+ * @buf: the buffer storing the event format string
+ * @size: the size of @buf
+ * @sys: the system the event belongs to
+ *
+ * This parses the event format and creates an event structure
+ * to quickly parse raw data for a given event.
+ *
+ * These files currently come from:
+ *
+ * /sys/kernel/debug/tracing/events/.../.../format
+ */
+int pevent_parse_event(struct pevent *pevent,
+                      const char *buf, unsigned long size,
+                      const char *sys)
+{
+       struct event_format *event;
+       int ret;
+
+       init_input_buf(buf, size);
+
+       event = alloc_event();
+       if (!event)
+               return -ENOMEM;
+
+       event->name = event_read_name();
+       if (!event->name) {
+               /* Bad event? */
+               free(event);
+               return -1;
+       }
+
+       if (strcmp(sys, "ftrace") == 0) {
+
+               event->flags |= EVENT_FL_ISFTRACE;
+
+               if (strcmp(event->name, "bprint") == 0)
+                       event->flags |= EVENT_FL_ISBPRINT;
+       }
+               
+       event->id = event_read_id();
+       if (event->id < 0)
+               die("failed to read event id");
+
+       event->system = strdup(sys);
+       if (!event->system)
+               die("failed to allocate system");
+
+       /* Add pevent to event so that it can be referenced */
+       event->pevent = pevent;
+
+       ret = event_read_format(event);
+       if (ret < 0) {
+               do_warning("failed to read event format for %s", event->name);
+               goto event_failed;
+       }
+
+       /*
+        * If the event has an override, don't print warnings if the event
+        * print format fails to parse.
+        */
+       show_warning = 0;
+
+       ret = event_read_print(event);
+       if (ret < 0) {
+               do_warning("failed to read event print fmt for %s",
+                          event->name);
+               show_warning = 1;
+               goto event_failed;
+       }
+       show_warning = 1;
+
+       add_event(pevent, event);
+
+       if (!ret && (event->flags & EVENT_FL_ISFTRACE)) {
+               struct format_field *field;
+               struct print_arg *arg, **list;
+
+               /* old ftrace had no args */
+
+               list = &event->print_fmt.args;
+               for (field = event->format.fields; field; field = field->next) {
+                       arg = alloc_arg();
+                       *list = arg;
+                       list = &arg->next;
+                       arg->type = PRINT_FIELD;
+                       arg->field.name = strdup(field->name);
+                       if (!arg->field.name) {
+                               do_warning("failed to allocate field name");
+                               event->flags |= EVENT_FL_FAILED;
+                               return -1;
+                       }
+                       arg->field.field = field;
+               }
+               return 0;
+       }
+
+#define PRINT_ARGS 0
+       if (PRINT_ARGS && event->print_fmt.args)
+               print_args(event->print_fmt.args);
+
+       return 0;
+
+ event_failed:
+       event->flags |= EVENT_FL_FAILED;
+       /* still add it even if it failed */
+       add_event(pevent, event);
+       return -1;
+}
+
+int get_field_val(struct trace_seq *s, struct format_field *field,
+                 const char *name, struct pevent_record *record,
+                 unsigned long long *val, int err)
+{
+       if (!field) {
+               if (err)
+                       trace_seq_printf(s, "<CANT FIND FIELD %s>", name);
+               return -1;
+       }
+
+       if (pevent_read_number_field(field, record->data, val)) {
+               if (err)
+                       trace_seq_printf(s, " %s=INVALID", name);
+               return -1;
+       }
+
+       return 0;
+}
+
+/**
+ * pevent_get_field_raw - return the raw pointer into the data field
+ * @s: The seq to print to on error
+ * @event: the event that the field is for
+ * @name: The name of the field
+ * @record: The record with the field name.
+ * @len: place to store the field length.
+ * @err: print default error if failed.
+ *
+ * Returns a pointer into record->data of the field and places
+ * the length of the field in @len.
+ *
+ * On failure, it returns NULL.
+ */
+void *pevent_get_field_raw(struct trace_seq *s, struct event_format *event,
+                          const char *name, struct pevent_record *record,
+                          int *len, int err)
+{
+       struct format_field *field;
+       void *data = record->data;
+       unsigned offset;
+       int dummy;
+
+       if (!event)
+               return NULL;
+
+       field = pevent_find_field(event, name);
+
+       if (!field) {
+               if (err)
+                       trace_seq_printf(s, "<CANT FIND FIELD %s>", name);
+               return NULL;
+       }
+
+       /* Allow @len to be NULL */
+       if (!len)
+               len = &dummy;
+
+       offset = field->offset;
+       if (field->flags & FIELD_IS_DYNAMIC) {
+               offset = pevent_read_number(event->pevent,
+                                           data + offset, field->size);
+               *len = offset >> 16;
+               offset &= 0xffff;
+       } else
+               *len = field->size;
+
+       return data + offset;
+}
+
+/**
+ * pevent_get_field_val - find a field and return its value
+ * @s: The seq to print to on error
+ * @event: the event that the field is for
+ * @name: The name of the field
+ * @record: The record with the field name.
+ * @val: place to store the value of the field.
+ * @err: print default error if failed.
+ *
+ * Returns 0 on success -1 on field not found.
+ */
+int pevent_get_field_val(struct trace_seq *s, struct event_format *event,
+                        const char *name, struct pevent_record *record,
+                        unsigned long long *val, int err)
+{
+       struct format_field *field;
+
+       if (!event)
+               return -1;
+
+       field = pevent_find_field(event, name);
+
+       return get_field_val(s, field, name, record, val, err);
+}
+
+/**
+ * pevent_get_common_field_val - find a common field and return its value
+ * @s: The seq to print to on error
+ * @event: the event that the field is for
+ * @name: The name of the field
+ * @record: The record with the field name.
+ * @val: place to store the value of the field.
+ * @err: print default error if failed.
+ *
+ * Returns 0 on success -1 on field not found.
+ */
+int pevent_get_common_field_val(struct trace_seq *s, struct event_format *event,
+                               const char *name, struct pevent_record *record,
+                               unsigned long long *val, int err)
+{
+       struct format_field *field;
+
+       if (!event)
+               return -1;
+
+       field = pevent_find_common_field(event, name);
+
+       return get_field_val(s, field, name, record, val, err);
+}
+
+/**
+ * pevent_get_any_field_val - find a any field and return its value
+ * @s: The seq to print to on error
+ * @event: the event that the field is for
+ * @name: The name of the field
+ * @record: The record with the field name.
+ * @val: place to store the value of the field.
+ * @err: print default error if failed.
+ *
+ * Returns 0 on success -1 on field not found.
+ */
+int pevent_get_any_field_val(struct trace_seq *s, struct event_format *event,
+                            const char *name, struct pevent_record *record,
+                            unsigned long long *val, int err)
+{
+       struct format_field *field;
+
+       if (!event)
+               return -1;
+
+       field = pevent_find_any_field(event, name);
+
+       return get_field_val(s, field, name, record, val, err);
+}
+
+/**
+ * pevent_print_num_field - print a field and a format
+ * @s: The seq to print to
+ * @fmt: The printf format to print the field with.
+ * @event: the event that the field is for
+ * @name: The name of the field
+ * @record: The record with the field name.
+ * @err: print default error if failed.
+ *
+ * Returns: 0 on success, -1 field not found, or 1 if buffer is full.
+ */
+int pevent_print_num_field(struct trace_seq *s, const char *fmt,
+                          struct event_format *event, const char *name,
+                          struct pevent_record *record, int err)
+{
+       struct format_field *field = pevent_find_field(event, name);
+       unsigned long long val;
+
+       if (!field)
+               goto failed;
+
+       if (pevent_read_number_field(field, record->data, &val))
+               goto failed;
+
+       return trace_seq_printf(s, fmt, val);
+
+ failed:
+       if (err)
+               trace_seq_printf(s, "CAN'T FIND FIELD \"%s\"", name);
+       return -1;
+}
+
+static void free_func_handle(struct pevent_function_handler *func)
+{
+       struct pevent_func_params *params;
+
+       free(func->name);
+
+       while (func->params) {
+               params = func->params;
+               func->params = params->next;
+               free(params);
+       }
+
+       free(func);
+}
+
+/**
+ * pevent_register_print_function - register a helper function
+ * @pevent: the handle to the pevent
+ * @func: the function to process the helper function
+ * @ret_type: the return type of the helper function
+ * @name: the name of the helper function
+ * @parameters: A list of enum pevent_func_arg_type
+ *
+ * Some events may have helper functions in the print format arguments.
+ * This allows a plugin to dynamically create a way to process one
+ * of these functions.
+ *
+ * The @parameters is a variable list of pevent_func_arg_type enums that
+ * must end with PEVENT_FUNC_ARG_VOID.
+ */
+int pevent_register_print_function(struct pevent *pevent,
+                                  pevent_func_handler func,
+                                  enum pevent_func_arg_type ret_type,
+                                  char *name, ...)
+{
+       struct pevent_function_handler *func_handle;
+       struct pevent_func_params **next_param;
+       struct pevent_func_params *param;
+       enum pevent_func_arg_type type;
+       va_list ap;
+
+       func_handle = find_func_handler(pevent, name);
+       if (func_handle) {
+               /*
+                * This is most like caused by the users own
+                * plugins updating the function. This overrides the
+                * system defaults.
+                */
+               pr_stat("override of function helper '%s'", name);
+               remove_func_handler(pevent, name);
+       }
+
+       func_handle = malloc_or_die(sizeof(*func_handle));
+       memset(func_handle, 0, sizeof(*func_handle));
+
+       func_handle->ret_type = ret_type;
+       func_handle->name = strdup(name);
+       func_handle->func = func;
+       if (!func_handle->name)
+               die("Failed to allocate function name");
+
+       next_param = &(func_handle->params);
+       va_start(ap, name);
+       for (;;) {
+               type = va_arg(ap, enum pevent_func_arg_type);
+               if (type == PEVENT_FUNC_ARG_VOID)
+                       break;
+
+               if (type < 0 || type >= PEVENT_FUNC_ARG_MAX_TYPES) {
+                       warning("Invalid argument type %d", type);
+                       goto out_free;
+               }
+
+               param = malloc_or_die(sizeof(*param));
+               param->type = type;
+               param->next = NULL;
+
+               *next_param = param;
+               next_param = &(param->next);
+
+               func_handle->nr_args++;
+       }
+       va_end(ap);
+
+       func_handle->next = pevent->func_handlers;
+       pevent->func_handlers = func_handle;
+
+       return 0;
+ out_free:
+       va_end(ap);
+       free_func_handle(func_handle);
+       return -1;
+}
+
+/**
+ * pevent_register_event_handler - register a way to parse an event
+ * @pevent: the handle to the pevent
+ * @id: the id of the event to register
+ * @sys_name: the system name the event belongs to
+ * @event_name: the name of the event
+ * @func: the function to call to parse the event information
+ * @context: the data to be passed to @func
+ *
+ * This function allows a developer to override the parsing of
+ * a given event. If for some reason the default print format
+ * is not sufficient, this function will register a function
+ * for an event to be used to parse the data instead.
+ *
+ * If @id is >= 0, then it is used to find the event.
+ * else @sys_name and @event_name are used.
+ */
+int pevent_register_event_handler(struct pevent *pevent,
+                                 int id, char *sys_name, char *event_name,
+                                 pevent_event_handler_func func,
+                                 void *context)
+{
+       struct event_format *event;
+       struct event_handler *handle;
+
+       if (id >= 0) {
+               /* search by id */
+               event = pevent_find_event(pevent, id);
+               if (!event)
+                       goto not_found;
+               if (event_name && (strcmp(event_name, event->name) != 0))
+                       goto not_found;
+               if (sys_name && (strcmp(sys_name, event->system) != 0))
+                       goto not_found;
+       } else {
+               event = pevent_find_event_by_name(pevent, sys_name, event_name);
+               if (!event)
+                       goto not_found;
+       }
+
+       pr_stat("overriding event (%d) %s:%s with new print handler",
+               event->id, event->system, event->name);
+
+       event->handler = func;
+       event->context = context;
+       return 0;
+
+ not_found:
+       /* Save for later use. */
+       handle = malloc_or_die(sizeof(*handle));
+       memset(handle, 0, sizeof(*handle));
+       handle->id = id;
+       if (event_name)
+               handle->event_name = strdup(event_name);
+       if (sys_name)
+               handle->sys_name = strdup(sys_name);
+
+       if ((event_name && !handle->event_name) ||
+           (sys_name && !handle->sys_name)) {
+               die("Failed to allocate event/sys name");
+       }
+
+       handle->func = func;
+       handle->next = pevent->handlers;
+       pevent->handlers = handle;
+       handle->context = context;
+
+       return -1;
+}
+
+/**
+ * pevent_alloc - create a pevent handle
+ */
+struct pevent *pevent_alloc(void)
+{
+       struct pevent *pevent;
+
+       pevent = malloc(sizeof(*pevent));
+       if (!pevent)
+               return NULL;
+       memset(pevent, 0, sizeof(*pevent));
+       pevent->ref_count = 1;
+
+       return pevent;
+}
+
+void pevent_ref(struct pevent *pevent)
+{
+       pevent->ref_count++;
+}
+
+static void free_format_fields(struct format_field *field)
+{
+       struct format_field *next;
+
+       while (field) {
+               next = field->next;
+               free(field->type);
+               free(field->name);
+               free(field);
+               field = next;
+       }
+}
+
+static void free_formats(struct format *format)
+{
+       free_format_fields(format->common_fields);
+       free_format_fields(format->fields);
+}
+
+static void free_event(struct event_format *event)
+{
+       free(event->name);
+       free(event->system);
+
+       free_formats(&event->format);
+
+       free(event->print_fmt.format);
+       free_args(event->print_fmt.args);
+
+       free(event);
+}
+
+/**
+ * pevent_free - free a pevent handle
+ * @pevent: the pevent handle to free
+ */
+void pevent_free(struct pevent *pevent)
+{
+       struct cmdline_list *cmdlist, *cmdnext;
+       struct func_list *funclist, *funcnext;
+       struct printk_list *printklist, *printknext;
+       struct pevent_function_handler *func_handler;
+       struct event_handler *handle;
+       int i;
+
+       if (!pevent)
+               return;
+
+       cmdlist = pevent->cmdlist;
+       funclist = pevent->funclist;
+       printklist = pevent->printklist;
+
+       pevent->ref_count--;
+       if (pevent->ref_count)
+               return;
+
+       if (pevent->cmdlines) {
+               for (i = 0; i < pevent->cmdline_count; i++)
+                       free(pevent->cmdlines[i].comm);
+               free(pevent->cmdlines);
+       }
+
+       while (cmdlist) {
+               cmdnext = cmdlist->next;
+               free(cmdlist->comm);
+               free(cmdlist);
+               cmdlist = cmdnext;
+       }
+
+       if (pevent->func_map) {
+               for (i = 0; i < pevent->func_count; i++) {
+                       free(pevent->func_map[i].func);
+                       free(pevent->func_map[i].mod);
+               }
+               free(pevent->func_map);
+       }
+
+       while (funclist) {
+               funcnext = funclist->next;
+               free(funclist->func);
+               free(funclist->mod);
+               free(funclist);
+               funclist = funcnext;
+       }
+
+       while (pevent->func_handlers) {
+               func_handler = pevent->func_handlers;
+               pevent->func_handlers = func_handler->next;
+               free_func_handle(func_handler);
+       }
+
+       if (pevent->printk_map) {
+               for (i = 0; i < pevent->printk_count; i++)
+                       free(pevent->printk_map[i].printk);
+               free(pevent->printk_map);
+       }
+
+       while (printklist) {
+               printknext = printklist->next;
+               free(printklist->printk);
+               free(printklist);
+               printklist = printknext;
+       }
+
+       for (i = 0; i < pevent->nr_events; i++)
+               free_event(pevent->events[i]);
+
+       while (pevent->handlers) {
+               handle = pevent->handlers;
+               pevent->handlers = handle->next;
+               free_handler(handle);
+       }
+
+       free(pevent->events);
+       free(pevent->sort_events);
+
+       free(pevent);
+}
+
+void pevent_unref(struct pevent *pevent)
+{
+       pevent_free(pevent);
+}
diff --git a/traceevent/event-parse.h b/traceevent/event-parse.h
new file mode 100644 (file)
index 0000000..1a486ae
--- /dev/null
@@ -0,0 +1,811 @@
+/*
+ * Copyright (C) 2009, 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License (not later!)
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+#ifndef _PARSE_EVENTS_H
+#define _PARSE_EVENTS_H
+
+#include <stdarg.h>
+#include <regex.h>
+
+#ifndef __unused
+#define __unused __attribute__ ((unused))
+#endif
+
+/* ----------------------- trace_seq ----------------------- */
+
+
+#ifndef TRACE_SEQ_BUF_SIZE
+#define TRACE_SEQ_BUF_SIZE 4096
+#endif
+
+#ifndef DEBUG_RECORD
+#define DEBUG_RECORD 0
+#endif
+
+struct pevent_record {
+       unsigned long long      ts;
+       unsigned long long      offset;
+       long long               missed_events;  /* buffer dropped events before */
+       int                     record_size;    /* size of binary record */
+       int                     size;           /* size of data */
+       void                    *data;
+       int                     cpu;
+       int                     ref_count;
+       int                     locked;         /* Do not free, even if ref_count is zero */
+       void                    *p_private;
+#if DEBUG_RECORD
+       struct pevent_record    *prev;
+       struct pevent_record    *next;
+       long                    alloc_addr;
+#endif
+};
+
+/*
+ * Trace sequences are used to allow a function to call several other functions
+ * to create a string of data to use (up to a max of PAGE_SIZE).
+ */
+
+struct trace_seq {
+       char                    *buffer;
+       unsigned int            buffer_size;
+       unsigned int            len;
+       unsigned int            readpos;
+};
+
+void trace_seq_init(struct trace_seq *s);
+void trace_seq_destroy(struct trace_seq *s);
+
+extern int trace_seq_printf(struct trace_seq *s, const char *fmt, ...)
+       __attribute__ ((format (printf, 2, 3)));
+extern int trace_seq_vprintf(struct trace_seq *s, const char *fmt, va_list args)
+       __attribute__ ((format (printf, 2, 0)));
+
+extern int trace_seq_puts(struct trace_seq *s, const char *str);
+extern int trace_seq_putc(struct trace_seq *s, unsigned char c);
+
+extern void trace_seq_terminate(struct trace_seq *s);
+
+extern int trace_seq_do_printf(struct trace_seq *s);
+
+
+/* ----------------------- pevent ----------------------- */
+
+struct pevent;
+struct event_format;
+
+typedef int (*pevent_event_handler_func)(struct trace_seq *s,
+                                        struct pevent_record *record,
+                                        struct event_format *event,
+                                        void *context);
+
+typedef int (*pevent_plugin_load_func)(struct pevent *pevent);
+typedef int (*pevent_plugin_unload_func)(void);
+
+struct plugin_option {
+       struct plugin_option            *next;
+       void                            *handle;
+       char                            *file;
+       char                            *name;
+       char                            *plugin_alias;
+       char                            *description;
+       char                            *value;
+       void                            *p_private;
+       int                             set;
+};
+
+/*
+ * Plugin hooks that can be called:
+ *
+ * PEVENT_PLUGIN_LOADER:  (required)
+ *   The function name to initialized the plugin.
+ *
+ *   int PEVENT_PLUGIN_LOADER(struct pevent *pevent)
+ *
+ * PEVENT_PLUGIN_UNLOADER:  (optional)
+ *   The function called just before unloading
+ *
+ *   int PEVENT_PLUGIN_UNLOADER(void)
+ *
+ * PEVENT_PLUGIN_OPTIONS:  (optional)
+ *   Plugin options that can be set before loading
+ *
+ *   struct plugin_option PEVENT_PLUGIN_OPTIONS[] = {
+ *     {
+ *             .name = "option-name",
+ *             .plugin_alias = "overide-file-name", (optional)
+ *             .description = "description of option to show users",
+ *     },
+ *     {
+ *             .name = NULL,
+ *     },
+ *   };
+ *
+ *   Array must end with .name = NULL;
+ *
+ *
+ *   .plugin_alias is used to give a shorter name to access
+ *   the vairable. Useful if a plugin handles more than one event.
+ *
+ * PEVENT_PLUGIN_ALIAS: (optional)
+ *   The name to use for finding options (uses filename if not defined)
+ */
+#define PEVENT_PLUGIN_LOADER pevent_plugin_loader
+#define PEVENT_PLUGIN_UNLOADER pevent_plugin_unloader
+#define PEVENT_PLUGIN_OPTIONS pevent_plugin_options
+#define PEVENT_PLUGIN_ALIAS pevent_plugin_alias
+#define _MAKE_STR(x)   #x
+#define MAKE_STR(x)    _MAKE_STR(x)
+#define PEVENT_PLUGIN_LOADER_NAME MAKE_STR(PEVENT_PLUGIN_LOADER)
+#define PEVENT_PLUGIN_UNLOADER_NAME MAKE_STR(PEVENT_PLUGIN_UNLOADER)
+#define PEVENT_PLUGIN_OPTIONS_NAME MAKE_STR(PEVENT_PLUGIN_OPTIONS)
+#define PEVENT_PLUGIN_ALIAS_NAME MAKE_STR(PEVENT_PLUGIN_ALIAS)
+
+#define NSECS_PER_SEC          1000000000ULL
+#define NSECS_PER_USEC         1000ULL
+
+enum format_flags {
+       FIELD_IS_ARRAY          = 1,
+       FIELD_IS_POINTER        = 2,
+       FIELD_IS_SIGNED         = 4,
+       FIELD_IS_STRING         = 8,
+       FIELD_IS_DYNAMIC        = 16,
+       FIELD_IS_LONG           = 32,
+       FIELD_IS_FLAG           = 64,
+       FIELD_IS_SYMBOLIC       = 128,
+};
+
+struct format_field {
+       struct format_field     *next;
+       struct event_format     *event;
+       char                    *type;
+       char                    *name;
+       int                     offset;
+       int                     size;
+       unsigned int            arraylen;
+       unsigned int            elementsize;
+       unsigned long           flags;
+};
+
+struct format {
+       int                     nr_common;
+       int                     nr_fields;
+       struct format_field     *common_fields;
+       struct format_field     *fields;
+};
+
+struct print_arg_atom {
+       char                    *atom;
+};
+
+struct print_arg_string {
+       char                    *string;
+       int                     offset;
+};
+
+struct print_arg_field {
+       char                    *name;
+       struct format_field     *field;
+};
+
+struct print_flag_sym {
+       struct print_flag_sym   *next;
+       char                    *value;
+       char                    *str;
+};
+
+struct print_arg_typecast {
+       char                    *type;
+       struct print_arg        *item;
+};
+
+struct print_arg_flags {
+       struct print_arg        *field;
+       char                    *delim;
+       struct print_flag_sym   *flags;
+};
+
+struct print_arg_symbol {
+       struct print_arg        *field;
+       struct print_flag_sym   *symbols;
+};
+
+struct print_arg_hex {
+       struct print_arg        *field;
+       struct print_arg        *size;
+};
+
+struct print_arg_dynarray {
+       struct format_field     *field;
+       struct print_arg        *index;
+};
+
+struct print_arg;
+
+struct print_arg_op {
+       char                    *op;
+       int                     prio;
+       struct print_arg        *left;
+       struct print_arg        *right;
+};
+
+struct pevent_function_handler;
+
+struct print_arg_func {
+       struct pevent_function_handler  *func;
+       struct print_arg                *args;
+};
+
+enum print_arg_type {
+       PRINT_NULL,
+       PRINT_ATOM,
+       PRINT_FIELD,
+       PRINT_FLAGS,
+       PRINT_SYMBOL,
+       PRINT_HEX,
+       PRINT_TYPE,
+       PRINT_STRING,
+       PRINT_BSTRING,
+       PRINT_DYNAMIC_ARRAY,
+       PRINT_OP,
+       PRINT_FUNC,
+};
+
+struct print_arg {
+       struct print_arg                *next;
+       enum print_arg_type             type;
+       union {
+               struct print_arg_atom           atom;
+               struct print_arg_field          field;
+               struct print_arg_typecast       typecast;
+               struct print_arg_flags          flags;
+               struct print_arg_symbol         symbol;
+               struct print_arg_hex            hex;
+               struct print_arg_func           func;
+               struct print_arg_string         string;
+               struct print_arg_op             op;
+               struct print_arg_dynarray       dynarray;
+       };
+};
+
+struct print_fmt {
+       char                    *format;
+       struct print_arg        *args;
+};
+
+struct event_format {
+       struct pevent           *pevent;
+       char                    *name;
+       int                     id;
+       int                     flags;
+       struct format           format;
+       struct print_fmt        print_fmt;
+       char                    *system;
+       pevent_event_handler_func handler;
+       void                    *context;
+};
+
+enum {
+       EVENT_FL_ISFTRACE       = 0x01,
+       EVENT_FL_ISPRINT        = 0x02,
+       EVENT_FL_ISBPRINT       = 0x04,
+       EVENT_FL_ISFUNCENT      = 0x10,
+       EVENT_FL_ISFUNCRET      = 0x20,
+
+       EVENT_FL_FAILED         = 0x80000000
+};
+
+enum event_sort_type {
+       EVENT_SORT_ID,
+       EVENT_SORT_NAME,
+       EVENT_SORT_SYSTEM,
+};
+
+enum event_type {
+       EVENT_ERROR,
+       EVENT_NONE,
+       EVENT_SPACE,
+       EVENT_NEWLINE,
+       EVENT_OP,
+       EVENT_DELIM,
+       EVENT_ITEM,
+       EVENT_DQUOTE,
+       EVENT_SQUOTE,
+};
+
+typedef unsigned long long (*pevent_func_handler)(struct trace_seq *s,
+                                            unsigned long long *args);
+
+enum pevent_func_arg_type {
+       PEVENT_FUNC_ARG_VOID,
+       PEVENT_FUNC_ARG_INT,
+       PEVENT_FUNC_ARG_LONG,
+       PEVENT_FUNC_ARG_STRING,
+       PEVENT_FUNC_ARG_PTR,
+       PEVENT_FUNC_ARG_MAX_TYPES
+};
+
+enum pevent_flag {
+       PEVENT_NSEC_OUTPUT              = 1,    /* output in NSECS */
+};
+
+struct cmdline;
+struct cmdline_list;
+struct func_map;
+struct func_list;
+struct event_handler;
+
+struct pevent {
+       int ref_count;
+
+       int header_page_ts_offset;
+       int header_page_ts_size;
+       int header_page_size_offset;
+       int header_page_size_size;
+       int header_page_data_offset;
+       int header_page_data_size;
+       int header_page_overwrite;
+
+       int file_bigendian;
+       int host_bigendian;
+
+       int latency_format;
+
+       int old_format;
+
+       int cpus;
+       int long_size;
+
+       struct cmdline *cmdlines;
+       struct cmdline_list *cmdlist;
+       int cmdline_count;
+
+       struct func_map *func_map;
+       struct func_list *funclist;
+       unsigned int func_count;
+
+       struct printk_map *printk_map;
+       struct printk_list *printklist;
+       unsigned int printk_count;
+
+
+       struct event_format **events;
+       int nr_events;
+       struct event_format **sort_events;
+       enum event_sort_type last_type;
+
+       int type_offset;
+       int type_size;
+
+       int pid_offset;
+       int pid_size;
+
+       int pc_offset;
+       int pc_size;
+
+       int flags_offset;
+       int flags_size;
+
+       int ld_offset;
+       int ld_size;
+
+       int print_raw;
+
+       int test_filters;
+
+       int flags;
+
+       struct format_field *bprint_ip_field;
+       struct format_field *bprint_fmt_field;
+       struct format_field *bprint_buf_field;
+
+       struct event_handler *handlers;
+       struct pevent_function_handler *func_handlers;
+
+       /* cache */
+       struct event_format *last_event;
+};
+
+static inline void pevent_set_flag(struct pevent *pevent, int flag)
+{
+       pevent->flags |= flag;
+}
+
+static inline unsigned short
+__data2host2(struct pevent *pevent, unsigned short data)
+{
+       unsigned short swap;
+
+       if (pevent->host_bigendian == pevent->file_bigendian)
+               return data;
+
+       swap = ((data & 0xffULL) << 8) |
+               ((data & (0xffULL << 8)) >> 8);
+
+       return swap;
+}
+
+static inline unsigned int
+__data2host4(struct pevent *pevent, unsigned int data)
+{
+       unsigned int swap;
+
+       if (pevent->host_bigendian == pevent->file_bigendian)
+               return data;
+
+       swap = ((data & 0xffULL) << 24) |
+               ((data & (0xffULL << 8)) << 8) |
+               ((data & (0xffULL << 16)) >> 8) |
+               ((data & (0xffULL << 24)) >> 24);
+
+       return swap;
+}
+
+static inline unsigned long long
+__data2host8(struct pevent *pevent, unsigned long long data)
+{
+       unsigned long long swap;
+
+       if (pevent->host_bigendian == pevent->file_bigendian)
+               return data;
+
+       swap = ((data & 0xffULL) << 56) |
+               ((data & (0xffULL << 8)) << 40) |
+               ((data & (0xffULL << 16)) << 24) |
+               ((data & (0xffULL << 24)) << 8) |
+               ((data & (0xffULL << 32)) >> 8) |
+               ((data & (0xffULL << 40)) >> 24) |
+               ((data & (0xffULL << 48)) >> 40) |
+               ((data & (0xffULL << 56)) >> 56);
+
+       return swap;
+}
+
+#define data2host2(pevent, ptr)                __data2host2(pevent, *(unsigned short *)(ptr))
+#define data2host4(pevent, ptr)                __data2host4(pevent, *(unsigned int *)(ptr))
+#define data2host8(pevent, ptr)                                        \
+({                                                             \
+       unsigned long long __val;                               \
+                                                               \
+       memcpy(&__val, (ptr), sizeof(unsigned long long));      \
+       __data2host8(pevent, __val);                            \
+})
+
+/* taken from kernel/trace/trace.h */
+enum trace_flag_type {
+       TRACE_FLAG_IRQS_OFF             = 0x01,
+       TRACE_FLAG_IRQS_NOSUPPORT       = 0x02,
+       TRACE_FLAG_NEED_RESCHED         = 0x04,
+       TRACE_FLAG_HARDIRQ              = 0x08,
+       TRACE_FLAG_SOFTIRQ              = 0x10,
+};
+
+int pevent_register_comm(struct pevent *pevent, const char *comm, int pid);
+int pevent_register_function(struct pevent *pevent, char *name,
+                            unsigned long long addr, char *mod);
+int pevent_register_print_string(struct pevent *pevent, char *fmt,
+                                unsigned long long addr);
+int pevent_pid_is_registered(struct pevent *pevent, int pid);
+
+void pevent_print_event(struct pevent *pevent, struct trace_seq *s,
+                       struct pevent_record *record);
+
+int pevent_parse_header_page(struct pevent *pevent, char *buf, unsigned long size,
+                            int long_size);
+
+int pevent_parse_event(struct pevent *pevent, const char *buf,
+                      unsigned long size, const char *sys);
+
+void *pevent_get_field_raw(struct trace_seq *s, struct event_format *event,
+                          const char *name, struct pevent_record *record,
+                          int *len, int err);
+
+int pevent_get_field_val(struct trace_seq *s, struct event_format *event,
+                        const char *name, struct pevent_record *record,
+                        unsigned long long *val, int err);
+int pevent_get_common_field_val(struct trace_seq *s, struct event_format *event,
+                               const char *name, struct pevent_record *record,
+                               unsigned long long *val, int err);
+int pevent_get_any_field_val(struct trace_seq *s, struct event_format *event,
+                            const char *name, struct pevent_record *record,
+                            unsigned long long *val, int err);
+
+int pevent_print_num_field(struct trace_seq *s, const char *fmt,
+                          struct event_format *event, const char *name,
+                          struct pevent_record *record, int err);
+
+int pevent_register_event_handler(struct pevent *pevent, int id, char *sys_name, char *event_name,
+                                 pevent_event_handler_func func, void *context);
+int pevent_register_print_function(struct pevent *pevent,
+                                  pevent_func_handler func,
+                                  enum pevent_func_arg_type ret_type,
+                                  char *name, ...);
+
+struct format_field *pevent_find_common_field(struct event_format *event, const char *name);
+struct format_field *pevent_find_field(struct event_format *event, const char *name);
+struct format_field *pevent_find_any_field(struct event_format *event, const char *name);
+
+const char *pevent_find_function(struct pevent *pevent, unsigned long long addr);
+unsigned long long
+pevent_find_function_address(struct pevent *pevent, unsigned long long addr);
+unsigned long long pevent_read_number(struct pevent *pevent, const void *ptr, int size);
+int pevent_read_number_field(struct format_field *field, const void *data,
+                            unsigned long long *value);
+
+struct event_format *pevent_find_event(struct pevent *pevent, int id);
+
+struct event_format *
+pevent_find_event_by_name(struct pevent *pevent, const char *sys, const char *name);
+
+void pevent_data_lat_fmt(struct pevent *pevent,
+                        struct trace_seq *s, struct pevent_record *record);
+int pevent_data_type(struct pevent *pevent, struct pevent_record *rec);
+struct event_format *pevent_data_event_from_type(struct pevent *pevent, int type);
+int pevent_data_pid(struct pevent *pevent, struct pevent_record *rec);
+const char *pevent_data_comm_from_pid(struct pevent *pevent, int pid);
+void pevent_event_info(struct trace_seq *s, struct event_format *event,
+                      struct pevent_record *record);
+
+struct event_format **pevent_list_events(struct pevent *pevent, enum event_sort_type);
+struct format_field **pevent_event_common_fields(struct event_format *event);
+struct format_field **pevent_event_fields(struct event_format *event);
+
+static inline int pevent_get_cpus(struct pevent *pevent)
+{
+       return pevent->cpus;
+}
+
+static inline void pevent_set_cpus(struct pevent *pevent, int cpus)
+{
+       pevent->cpus = cpus;
+}
+
+static inline int pevent_get_long_size(struct pevent *pevent)
+{
+       return pevent->long_size;
+}
+
+static inline void pevent_set_long_size(struct pevent *pevent, int long_size)
+{
+       pevent->long_size = long_size;
+}
+
+static inline int pevent_is_file_bigendian(struct pevent *pevent)
+{
+       return pevent->file_bigendian;
+}
+
+static inline void pevent_set_file_bigendian(struct pevent *pevent, int endian)
+{
+       pevent->file_bigendian = endian;
+}
+
+static inline int pevent_is_host_bigendian(struct pevent *pevent)
+{
+       return pevent->host_bigendian;
+}
+
+static inline void pevent_set_host_bigendian(struct pevent *pevent, int endian)
+{
+       pevent->host_bigendian = endian;
+}
+
+static inline int pevent_is_latency_format(struct pevent *pevent)
+{
+       return pevent->latency_format;
+}
+
+static inline void pevent_set_latency_format(struct pevent *pevent, int lat)
+{
+       pevent->latency_format = lat;
+}
+
+struct pevent *pevent_alloc(void);
+void pevent_free(struct pevent *pevent);
+void pevent_ref(struct pevent *pevent);
+void pevent_unref(struct pevent *pevent);
+
+/* access to the internal parser */
+void pevent_buffer_init(const char *buf, unsigned long long size);
+enum event_type pevent_read_token(char **tok);
+void pevent_free_token(char *token);
+int pevent_peek_char(void);
+const char *pevent_get_input_buf(void);
+unsigned long long pevent_get_input_buf_ptr(void);
+
+/* for debugging */
+void pevent_print_funcs(struct pevent *pevent);
+void pevent_print_printk(struct pevent *pevent);
+
+/* ----------------------- filtering ----------------------- */
+
+enum filter_boolean_type {
+       FILTER_FALSE,
+       FILTER_TRUE,
+};
+
+enum filter_op_type {
+       FILTER_OP_AND = 1,
+       FILTER_OP_OR,
+       FILTER_OP_NOT,
+};
+
+enum filter_cmp_type {
+       FILTER_CMP_NONE,
+       FILTER_CMP_EQ,
+       FILTER_CMP_NE,
+       FILTER_CMP_GT,
+       FILTER_CMP_LT,
+       FILTER_CMP_GE,
+       FILTER_CMP_LE,
+       FILTER_CMP_MATCH,
+       FILTER_CMP_NOT_MATCH,
+       FILTER_CMP_REGEX,
+       FILTER_CMP_NOT_REGEX,
+};
+
+enum filter_exp_type {
+       FILTER_EXP_NONE,
+       FILTER_EXP_ADD,
+       FILTER_EXP_SUB,
+       FILTER_EXP_MUL,
+       FILTER_EXP_DIV,
+       FILTER_EXP_MOD,
+       FILTER_EXP_RSHIFT,
+       FILTER_EXP_LSHIFT,
+       FILTER_EXP_AND,
+       FILTER_EXP_OR,
+       FILTER_EXP_XOR,
+       FILTER_EXP_NOT,
+};
+
+enum filter_arg_type {
+       FILTER_ARG_NONE,
+       FILTER_ARG_BOOLEAN,
+       FILTER_ARG_VALUE,
+       FILTER_ARG_FIELD,
+       FILTER_ARG_EXP,
+       FILTER_ARG_OP,
+       FILTER_ARG_NUM,
+       FILTER_ARG_STR,
+};
+
+enum filter_value_type {
+       FILTER_NUMBER,
+       FILTER_STRING,
+       FILTER_CHAR
+};
+
+struct fliter_arg;
+
+struct filter_arg_boolean {
+       enum filter_boolean_type        value;
+};
+
+struct filter_arg_field {
+       struct format_field     *field;
+};
+
+struct filter_arg_value {
+       enum filter_value_type  type;
+       union {
+               char                    *str;
+               unsigned long long      val;
+       };
+};
+
+struct filter_arg_op {
+       enum filter_op_type     type;
+       struct filter_arg       *left;
+       struct filter_arg       *right;
+};
+
+struct filter_arg_exp {
+       enum filter_exp_type    type;
+       struct filter_arg       *left;
+       struct filter_arg       *right;
+};
+
+struct filter_arg_num {
+       enum filter_cmp_type    type;
+       struct filter_arg       *left;
+       struct filter_arg       *right;
+};
+
+struct filter_arg_str {
+       enum filter_cmp_type    type;
+       struct format_field     *field;
+       char                    *val;
+       char                    *buffer;
+       regex_t                 reg;
+};
+
+struct filter_arg {
+       enum filter_arg_type    type;
+       union {
+               struct filter_arg_boolean       boolean;
+               struct filter_arg_field         field;
+               struct filter_arg_value         value;
+               struct filter_arg_op            op;
+               struct filter_arg_exp           exp;
+               struct filter_arg_num           num;
+               struct filter_arg_str           str;
+       };
+};
+
+struct filter_type {
+       int                     event_id;
+       struct event_format     *event;
+       struct filter_arg       *filter;
+};
+
+struct event_filter {
+       struct pevent           *pevent;
+       int                     filters;
+       struct filter_type      *event_filters;
+};
+
+struct event_filter *pevent_filter_alloc(struct pevent *pevent);
+
+#define FILTER_NONE            -2
+#define FILTER_NOEXIST         -1
+#define FILTER_MISS            0
+#define FILTER_MATCH           1
+
+enum filter_trivial_type {
+       FILTER_TRIVIAL_FALSE,
+       FILTER_TRIVIAL_TRUE,
+       FILTER_TRIVIAL_BOTH,
+};
+
+int pevent_filter_add_filter_str(struct event_filter *filter,
+                                const char *filter_str,
+                                char **error_str);
+
+
+int pevent_filter_match(struct event_filter *filter,
+                       struct pevent_record *record);
+
+int pevent_event_filtered(struct event_filter *filter,
+                         int event_id);
+
+void pevent_filter_reset(struct event_filter *filter);
+
+void pevent_filter_clear_trivial(struct event_filter *filter,
+                                enum filter_trivial_type type);
+
+void pevent_filter_free(struct event_filter *filter);
+
+char *pevent_filter_make_string(struct event_filter *filter, int event_id);
+
+int pevent_filter_remove_event(struct event_filter *filter,
+                              int event_id);
+
+int pevent_filter_event_has_trivial(struct event_filter *filter,
+                                   int event_id,
+                                   enum filter_trivial_type type);
+
+int pevent_filter_copy(struct event_filter *dest, struct event_filter *source);
+
+int pevent_update_trivial(struct event_filter *dest, struct event_filter *source,
+                         enum filter_trivial_type type);
+
+int pevent_filter_compare(struct event_filter *filter1, struct event_filter *filter2);
+
+#endif /* _PARSE_EVENTS_H */
diff --git a/traceevent/event-utils.h b/traceevent/event-utils.h
new file mode 100644 (file)
index 0000000..0829638
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License (not later!)
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+#ifndef __UTIL_H
+#define __UTIL_H
+
+#include <ctype.h>
+
+/* Can be overridden */
+void die(const char *fmt, ...);
+void *malloc_or_die(unsigned int size);
+void warning(const char *fmt, ...);
+void pr_stat(const char *fmt, ...);
+void vpr_stat(const char *fmt, va_list ap);
+
+/* Always available */
+void __die(const char *fmt, ...);
+void __warning(const char *fmt, ...);
+void __pr_stat(const char *fmt, ...);
+
+void __vdie(const char *fmt, ...);
+void __vwarning(const char *fmt, ...);
+void __vpr_stat(const char *fmt, ...);
+
+static inline char *strim(char *string)
+{
+       char *ret;
+
+       if (!string)
+               return NULL;
+       while (*string) {
+               if (!isspace(*string))
+                       break;
+               string++;
+       }
+       ret = string;
+
+       string = ret + strlen(ret) - 1;
+       while (string > ret) {
+               if (!isspace(*string))
+                       break;
+               string--;
+       }
+       string[1] = 0;
+
+       return ret;
+}
+
+static inline int has_text(const char *text)
+{
+       if (!text)
+               return 0;
+
+       while (*text) {
+               if (!isspace(*text))
+                       return 1;
+               text++;
+       }
+
+       return 0;
+}
+
+#endif
diff --git a/traceevent/parse-filter.c b/traceevent/parse-filter.c
new file mode 100644 (file)
index 0000000..ad17855
--- /dev/null
@@ -0,0 +1,2289 @@
+/*
+ * Copyright (C) 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License (not later!)
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <sys/types.h>
+
+#include "event-parse.h"
+#include "event-utils.h"
+
+#define COMM "COMM"
+
+static struct format_field comm = {
+       .name = "COMM",
+};
+
+struct event_list {
+       struct event_list       *next;
+       struct event_format     *event;
+};
+
+#define MAX_ERR_STR_SIZE 256
+
+static void show_error(char **error_str, const char *fmt, ...)
+{
+       unsigned long long index;
+       const char *input;
+       char *error;
+       va_list ap;
+       int len;
+       int i;
+
+       if (!error_str)
+               return;
+
+       input = pevent_get_input_buf();
+       index = pevent_get_input_buf_ptr();
+       len = input ? strlen(input) : 0;
+
+       error = malloc_or_die(MAX_ERR_STR_SIZE + (len*2) + 3);
+
+       if (len) {
+               strcpy(error, input);
+               error[len] = '\n';
+               for (i = 1; i < len && i < index; i++)
+                       error[len+i] = ' ';
+               error[len + i] = '^';
+               error[len + i + 1] = '\n';
+               len += i+2;
+       }
+
+       va_start(ap, fmt);
+       vsnprintf(error + len, MAX_ERR_STR_SIZE, fmt, ap);
+       va_end(ap);
+
+       *error_str = error;
+}
+
+static void free_token(char *token)
+{
+       pevent_free_token(token);
+}
+
+static enum event_type read_token(char **tok)
+{
+       enum event_type type;
+       char *token = NULL;
+
+       do {
+               free_token(token);
+               type = pevent_read_token(&token);
+       } while (type == EVENT_NEWLINE || type == EVENT_SPACE);
+
+       /* If token is = or ! check to see if the next char is ~ */
+       if (token &&
+           (strcmp(token, "=") == 0 || strcmp(token, "!") == 0) &&
+           pevent_peek_char() == '~') {
+               /* append it */
+               *tok = malloc_or_die(3);
+               sprintf(*tok, "%c%c", *token, '~');
+               free_token(token);
+               /* Now remove the '~' from the buffer */
+               pevent_read_token(&token);
+               free_token(token);
+       } else
+               *tok = token;
+
+       return type;
+}
+
+static int filter_cmp(const void *a, const void *b)
+{
+       const struct filter_type *ea = a;
+       const struct filter_type *eb = b;
+
+       if (ea->event_id < eb->event_id)
+               return -1;
+
+       if (ea->event_id > eb->event_id)
+               return 1;
+
+       return 0;
+}
+
+static struct filter_type *
+find_filter_type(struct event_filter *filter, int id)
+{
+       struct filter_type *filter_type;
+       struct filter_type key;
+
+       key.event_id = id;
+
+       filter_type = bsearch(&key, filter->event_filters,
+                             filter->filters,
+                             sizeof(*filter->event_filters),
+                             filter_cmp);
+
+       return filter_type;
+}
+
+static struct filter_type *
+add_filter_type(struct event_filter *filter, int id)
+{
+       struct filter_type *filter_type;
+       int i;
+
+       filter_type = find_filter_type(filter, id);
+       if (filter_type)
+               return filter_type;
+
+       filter->event_filters = realloc(filter->event_filters,
+                                       sizeof(*filter->event_filters) *
+                                       (filter->filters + 1));
+       if (!filter->event_filters)
+               die("Could not allocate filter");
+
+       for (i = 0; i < filter->filters; i++) {
+               if (filter->event_filters[i].event_id > id)
+                       break;
+       }
+
+       if (i < filter->filters)
+               memmove(&filter->event_filters[i+1],
+                       &filter->event_filters[i],
+                       sizeof(*filter->event_filters) *
+                       (filter->filters - i));
+
+       filter_type = &filter->event_filters[i];
+       filter_type->event_id = id;
+       filter_type->event = pevent_find_event(filter->pevent, id);
+       filter_type->filter = NULL;
+
+       filter->filters++;
+
+       return filter_type;
+}
+
+/**
+ * pevent_filter_alloc - create a new event filter
+ * @pevent: The pevent that this filter is associated with
+ */
+struct event_filter *pevent_filter_alloc(struct pevent *pevent)
+{
+       struct event_filter *filter;
+
+       filter = malloc_or_die(sizeof(*filter));
+       memset(filter, 0, sizeof(*filter));
+       filter->pevent = pevent;
+       pevent_ref(pevent);
+
+       return filter;
+}
+
+static struct filter_arg *allocate_arg(void)
+{
+       struct filter_arg *arg;
+
+       arg = malloc_or_die(sizeof(*arg));
+       memset(arg, 0, sizeof(*arg));
+
+       return arg;
+}
+
+static void free_arg(struct filter_arg *arg)
+{
+       if (!arg)
+               return;
+
+       switch (arg->type) {
+       case FILTER_ARG_NONE:
+       case FILTER_ARG_BOOLEAN:
+       case FILTER_ARG_NUM:
+               break;
+
+       case FILTER_ARG_STR:
+               free(arg->str.val);
+               regfree(&arg->str.reg);
+               free(arg->str.buffer);
+               break;
+
+       case FILTER_ARG_OP:
+               free_arg(arg->op.left);
+               free_arg(arg->op.right);
+       default:
+               break;
+       }
+
+       free(arg);
+}
+
+static void add_event(struct event_list **events,
+                     struct event_format *event)
+{
+       struct event_list *list;
+
+       list = malloc_or_die(sizeof(*list));
+       list->next = *events;
+       *events = list;
+       list->event = event;
+}
+
+static int event_match(struct event_format *event,
+                      regex_t *sreg, regex_t *ereg)
+{
+       if (sreg) {
+               return !regexec(sreg, event->system, 0, NULL, 0) &&
+                       !regexec(ereg, event->name, 0, NULL, 0);
+       }
+
+       return !regexec(ereg, event->system, 0, NULL, 0) ||
+               !regexec(ereg, event->name, 0, NULL, 0);
+}
+
+static int
+find_event(struct pevent *pevent, struct event_list **events,
+          char *sys_name, char *event_name)
+{
+       struct event_format *event;
+       regex_t ereg;
+       regex_t sreg;
+       int match = 0;
+       char *reg;
+       int ret;
+       int i;
+
+       if (!event_name) {
+               /* if no name is given, then swap sys and name */
+               event_name = sys_name;
+               sys_name = NULL;
+       }
+
+       reg = malloc_or_die(strlen(event_name) + 3);
+       sprintf(reg, "^%s$", event_name);
+
+       ret = regcomp(&ereg, reg, REG_ICASE|REG_NOSUB);
+       free(reg);
+
+       if (ret)
+               return -1;
+
+       if (sys_name) {
+               reg = malloc_or_die(strlen(sys_name) + 3);
+               sprintf(reg, "^%s$", sys_name);
+               ret = regcomp(&sreg, reg, REG_ICASE|REG_NOSUB);
+               free(reg);
+               if (ret) {
+                       regfree(&ereg);
+                       return -1;
+               }
+       }
+
+       for (i = 0; i < pevent->nr_events; i++) {
+               event = pevent->events[i];
+               if (event_match(event, sys_name ? &sreg : NULL, &ereg)) {
+                       match = 1;
+                       add_event(events, event);
+               }
+       }
+
+       regfree(&ereg);
+       if (sys_name)
+               regfree(&sreg);
+
+       if (!match)
+               return -1;
+
+       return 0;
+}
+
+static void free_events(struct event_list *events)
+{
+       struct event_list *event;
+
+       while (events) {
+               event = events;
+               events = events->next;
+               free(event);
+       }
+}
+
+static struct filter_arg *
+create_arg_item(struct event_format *event, const char *token,
+               enum event_type type, char **error_str)
+{
+       struct format_field *field;
+       struct filter_arg *arg;
+
+       arg = allocate_arg();
+
+       switch (type) {
+
+       case EVENT_SQUOTE:
+       case EVENT_DQUOTE:
+               arg->type = FILTER_ARG_VALUE;
+               arg->value.type =
+                       type == EVENT_DQUOTE ? FILTER_STRING : FILTER_CHAR;
+               arg->value.str = strdup(token);
+               if (!arg->value.str)
+                       die("malloc string");
+               break;
+       case EVENT_ITEM:
+               /* if it is a number, then convert it */
+               if (isdigit(token[0])) {
+                       arg->type = FILTER_ARG_VALUE;
+                       arg->value.type = FILTER_NUMBER;
+                       arg->value.val = strtoull(token, NULL, 0);
+                       break;
+               }
+               /* Consider this a field */
+               field = pevent_find_any_field(event, token);
+               if (!field) {
+                       if (strcmp(token, COMM) != 0) {
+                               /* not a field, Make it false */
+                               arg->type = FILTER_ARG_BOOLEAN;
+                               arg->boolean.value = FILTER_FALSE;
+                               break;
+                       }
+                       /* If token is 'COMM' then it is special */
+                       field = &comm;
+               }
+               arg->type = FILTER_ARG_FIELD;
+               arg->field.field = field;
+               break;
+       default:
+               free_arg(arg);
+               show_error(error_str, "expected a value but found %s",
+                          token);
+               return NULL;
+       }
+       return arg;
+}
+
+static struct filter_arg *
+create_arg_op(enum filter_op_type btype)
+{
+       struct filter_arg *arg;
+
+       arg = allocate_arg();
+       arg->type = FILTER_ARG_OP;
+       arg->op.type = btype;
+
+       return arg;
+}
+
+static struct filter_arg *
+create_arg_exp(enum filter_exp_type etype)
+{
+       struct filter_arg *arg;
+
+       arg = allocate_arg();
+       arg->type = FILTER_ARG_EXP;
+       arg->op.type = etype;
+
+       return arg;
+}
+
+static struct filter_arg *
+create_arg_cmp(enum filter_exp_type etype)
+{
+       struct filter_arg *arg;
+
+       arg = allocate_arg();
+       /* Use NUM and change if necessary */
+       arg->type = FILTER_ARG_NUM;
+       arg->op.type = etype;
+
+       return arg;
+}
+
+static int add_right(struct filter_arg *op, struct filter_arg *arg,
+                    char **error_str)
+{
+       struct filter_arg *left;
+       char *str;
+       int op_type;
+       int ret;
+
+       switch (op->type) {
+       case FILTER_ARG_EXP:
+               if (op->exp.right)
+                       goto out_fail;
+               op->exp.right = arg;
+               break;
+
+       case FILTER_ARG_OP:
+               if (op->op.right)
+                       goto out_fail;
+               op->op.right = arg;
+               break;
+
+       case FILTER_ARG_NUM:
+               if (op->op.right)
+                       goto out_fail;
+               /*
+                * The arg must be num, str, or field
+                */
+               switch (arg->type) {
+               case FILTER_ARG_VALUE:
+               case FILTER_ARG_FIELD:
+                       break;
+               default:
+                       show_error(error_str,
+                                  "Illegal rvalue");
+                       return -1;
+               }
+
+               /*
+                * Depending on the type, we may need to
+                * convert this to a string or regex.
+                */
+               switch (arg->value.type) {
+               case FILTER_CHAR:
+                       /*
+                        * A char should be converted to number if
+                        * the string is 1 byte, and the compare
+                        * is not a REGEX.
+                        */
+                       if (strlen(arg->value.str) == 1 &&
+                           op->num.type != FILTER_CMP_REGEX &&
+                           op->num.type != FILTER_CMP_NOT_REGEX) {
+                               arg->value.type = FILTER_NUMBER;
+                               goto do_int;
+                       }
+                       /* fall through */
+               case FILTER_STRING:
+
+                       /* convert op to a string arg */
+                       op_type = op->num.type;
+                       left = op->num.left;
+                       str = arg->value.str;
+
+                       /* reset the op for the new field */
+                       memset(op, 0, sizeof(*op));
+
+                       /*
+                        * If left arg was a field not found then
+                        * NULL the entire op.
+                        */
+                       if (left->type == FILTER_ARG_BOOLEAN) {
+                               free_arg(left);
+                               free_arg(arg);
+                               op->type = FILTER_ARG_BOOLEAN;
+                               op->boolean.value = FILTER_FALSE;
+                               break;
+                       }
+
+                       /* Left arg must be a field */
+                       if (left->type != FILTER_ARG_FIELD) {
+                               show_error(error_str,
+                                          "Illegal lvalue for string comparison");
+                               return -1;
+                       }
+
+                       /* Make sure this is a valid string compare */
+                       switch (op_type) {
+                       case FILTER_CMP_EQ:
+                               op_type = FILTER_CMP_MATCH;
+                               break;
+                       case FILTER_CMP_NE:
+                               op_type = FILTER_CMP_NOT_MATCH;
+                               break;
+
+                       case FILTER_CMP_REGEX:
+                       case FILTER_CMP_NOT_REGEX:
+                               ret = regcomp(&op->str.reg, str, REG_ICASE|REG_NOSUB);
+                               if (ret) {
+                                       show_error(error_str,
+                                                  "RegEx '%s' did not compute",
+                                                  str);
+                                       return -1;
+                               }
+                               break;
+                       default:
+                               show_error(error_str,
+                                          "Illegal comparison for string");
+                               return -1;
+                       }
+
+                       op->type = FILTER_ARG_STR;
+                       op->str.type = op_type;
+                       op->str.field = left->field.field;
+                       op->str.val = strdup(str);
+                       if (!op->str.val)
+                               die("malloc string");
+                       /*
+                        * Need a buffer to copy data for tests
+                        */
+                       op->str.buffer = malloc_or_die(op->str.field->size + 1);
+                       /* Null terminate this buffer */
+                       op->str.buffer[op->str.field->size] = 0;
+
+                       /* We no longer have left or right args */
+                       free_arg(arg);
+                       free_arg(left);
+
+                       break;
+
+               case FILTER_NUMBER:
+
+ do_int:
+                       switch (op->num.type) {
+                       case FILTER_CMP_REGEX:
+                       case FILTER_CMP_NOT_REGEX:
+                               show_error(error_str,
+                                          "Op not allowed with integers");
+                               return -1;
+
+                       default:
+                               break;
+                       }
+
+                       /* numeric compare */
+                       op->num.right = arg;
+                       break;
+               default:
+                       goto out_fail;
+               }
+               break;
+       default:
+               goto out_fail;
+       }
+
+       return 0;
+
+ out_fail:
+       show_error(error_str,
+                  "Syntax error");
+       return -1;
+}
+
+static struct filter_arg *
+rotate_op_right(struct filter_arg *a, struct filter_arg *b)
+{
+       struct filter_arg *arg;
+
+       arg = a->op.right;
+       a->op.right = b;
+       return arg;
+}
+
+static int add_left(struct filter_arg *op, struct filter_arg *arg)
+{
+       switch (op->type) {
+       case FILTER_ARG_EXP:
+               if (arg->type == FILTER_ARG_OP)
+                       arg = rotate_op_right(arg, op);
+               op->exp.left = arg;
+               break;
+
+       case FILTER_ARG_OP:
+               op->op.left = arg;
+               break;
+       case FILTER_ARG_NUM:
+               if (arg->type == FILTER_ARG_OP)
+                       arg = rotate_op_right(arg, op);
+
+               /* left arg of compares must be a field */
+               if (arg->type != FILTER_ARG_FIELD &&
+                   arg->type != FILTER_ARG_BOOLEAN)
+                       return -1;
+               op->num.left = arg;
+               break;
+       default:
+               return -1;
+       }
+       return 0;
+}
+
+enum op_type {
+       OP_NONE,
+       OP_BOOL,
+       OP_NOT,
+       OP_EXP,
+       OP_CMP,
+};
+
+static enum op_type process_op(const char *token,
+                              enum filter_op_type *btype,
+                              enum filter_cmp_type *ctype,
+                              enum filter_exp_type *etype)
+{
+       *btype = FILTER_OP_NOT;
+       *etype = FILTER_EXP_NONE;
+       *ctype = FILTER_CMP_NONE;
+
+       if (strcmp(token, "&&") == 0)
+               *btype = FILTER_OP_AND;
+       else if (strcmp(token, "||") == 0)
+               *btype = FILTER_OP_OR;
+       else if (strcmp(token, "!") == 0)
+               return OP_NOT;
+
+       if (*btype != FILTER_OP_NOT)
+               return OP_BOOL;
+
+       /* Check for value expressions */
+       if (strcmp(token, "+") == 0) {
+               *etype = FILTER_EXP_ADD;
+       } else if (strcmp(token, "-") == 0) {
+               *etype = FILTER_EXP_SUB;
+       } else if (strcmp(token, "*") == 0) {
+               *etype = FILTER_EXP_MUL;
+       } else if (strcmp(token, "/") == 0) {
+               *etype = FILTER_EXP_DIV;
+       } else if (strcmp(token, "%") == 0) {
+               *etype = FILTER_EXP_MOD;
+       } else if (strcmp(token, ">>") == 0) {
+               *etype = FILTER_EXP_RSHIFT;
+       } else if (strcmp(token, "<<") == 0) {
+               *etype = FILTER_EXP_LSHIFT;
+       } else if (strcmp(token, "&") == 0) {
+               *etype = FILTER_EXP_AND;
+       } else if (strcmp(token, "|") == 0) {
+               *etype = FILTER_EXP_OR;
+       } else if (strcmp(token, "^") == 0) {
+               *etype = FILTER_EXP_XOR;
+       } else if (strcmp(token, "~") == 0)
+               *etype = FILTER_EXP_NOT;
+
+       if (*etype != FILTER_EXP_NONE)
+               return OP_EXP;
+
+       /* Check for compares */
+       if (strcmp(token, "==") == 0)
+               *ctype = FILTER_CMP_EQ;
+       else if (strcmp(token, "!=") == 0)
+               *ctype = FILTER_CMP_NE;
+       else if (strcmp(token, "<") == 0)
+               *ctype = FILTER_CMP_LT;
+       else if (strcmp(token, ">") == 0)
+               *ctype = FILTER_CMP_GT;
+       else if (strcmp(token, "<=") == 0)
+               *ctype = FILTER_CMP_LE;
+       else if (strcmp(token, ">=") == 0)
+               *ctype = FILTER_CMP_GE;
+       else if (strcmp(token, "=~") == 0)
+               *ctype = FILTER_CMP_REGEX;
+       else if (strcmp(token, "!~") == 0)
+               *ctype = FILTER_CMP_NOT_REGEX;
+       else
+               return OP_NONE;
+
+       return OP_CMP;
+}
+
+static int check_op_done(struct filter_arg *arg)
+{
+       switch (arg->type) {
+       case FILTER_ARG_EXP:
+               return arg->exp.right != NULL;
+
+       case FILTER_ARG_OP:
+               return arg->op.right != NULL;
+
+       case FILTER_ARG_NUM:
+               return arg->num.right != NULL;
+
+       case FILTER_ARG_STR:
+               /* A string conversion is always done */
+               return 1;
+
+       case FILTER_ARG_BOOLEAN:
+               /* field not found, is ok */
+               return 1;
+
+       default:
+               return 0;
+       }
+}
+
+enum filter_vals {
+       FILTER_VAL_NORM,
+       FILTER_VAL_FALSE,
+       FILTER_VAL_TRUE,
+};
+
+void reparent_op_arg(struct filter_arg *parent, struct filter_arg *old_child,
+                 struct filter_arg *arg)
+{
+       struct filter_arg *other_child;
+       struct filter_arg **ptr;
+
+       if (parent->type != FILTER_ARG_OP &&
+           arg->type != FILTER_ARG_OP)
+               die("can not reparent other than OP");
+
+       /* Get the sibling */
+       if (old_child->op.right == arg) {
+               ptr = &old_child->op.right;
+               other_child = old_child->op.left;
+       } else if (old_child->op.left == arg) {
+               ptr = &old_child->op.left;
+               other_child = old_child->op.right;
+       } else
+               die("Error in reparent op, find other child");
+
+       /* Detach arg from old_child */
+       *ptr = NULL;
+
+       /* Check for root */
+       if (parent == old_child) {
+               free_arg(other_child);
+               *parent = *arg;
+               /* Free arg without recussion */
+               free(arg);
+               return;
+       }
+
+       if (parent->op.right == old_child)
+               ptr = &parent->op.right;
+       else if (parent->op.left == old_child)
+               ptr = &parent->op.left;
+       else
+               die("Error in reparent op");
+       *ptr = arg;
+
+       free_arg(old_child);
+}
+
+enum filter_vals test_arg(struct filter_arg *parent, struct filter_arg *arg)
+{
+       enum filter_vals lval, rval;
+
+       switch (arg->type) {
+
+               /* bad case */
+       case FILTER_ARG_BOOLEAN:
+               return FILTER_VAL_FALSE + arg->boolean.value;
+
+               /* good cases: */
+       case FILTER_ARG_STR:
+       case FILTER_ARG_VALUE:
+       case FILTER_ARG_FIELD:
+               return FILTER_VAL_NORM;
+
+       case FILTER_ARG_EXP:
+               lval = test_arg(arg, arg->exp.left);
+               if (lval != FILTER_VAL_NORM)
+                       return lval;
+               rval = test_arg(arg, arg->exp.right);
+               if (rval != FILTER_VAL_NORM)
+                       return rval;
+               return FILTER_VAL_NORM;
+
+       case FILTER_ARG_NUM:
+               lval = test_arg(arg, arg->num.left);
+               if (lval != FILTER_VAL_NORM)
+                       return lval;
+               rval = test_arg(arg, arg->num.right);
+               if (rval != FILTER_VAL_NORM)
+                       return rval;
+               return FILTER_VAL_NORM;
+
+       case FILTER_ARG_OP:
+               if (arg->op.type != FILTER_OP_NOT) {
+                       lval = test_arg(arg, arg->op.left);
+                       switch (lval) {
+                       case FILTER_VAL_NORM:
+                               break;
+                       case FILTER_VAL_TRUE:
+                               if (arg->op.type == FILTER_OP_OR)
+                                       return FILTER_VAL_TRUE;
+                               rval = test_arg(arg, arg->op.right);
+                               if (rval != FILTER_VAL_NORM)
+                                       return rval;
+
+                               reparent_op_arg(parent, arg, arg->op.right);
+                               return FILTER_VAL_NORM;
+
+                       case FILTER_VAL_FALSE:
+                               if (arg->op.type == FILTER_OP_AND)
+                                       return FILTER_VAL_FALSE;
+                               rval = test_arg(arg, arg->op.right);
+                               if (rval != FILTER_VAL_NORM)
+                                       return rval;
+
+                               reparent_op_arg(parent, arg, arg->op.right);
+                               return FILTER_VAL_NORM;
+                       }
+               }
+
+               rval = test_arg(arg, arg->op.right);
+               switch (rval) {
+               case FILTER_VAL_NORM:
+                       break;
+               case FILTER_VAL_TRUE:
+                       if (arg->op.type == FILTER_OP_OR)
+                               return FILTER_VAL_TRUE;
+                       if (arg->op.type == FILTER_OP_NOT)
+                               return FILTER_VAL_FALSE;
+
+                       reparent_op_arg(parent, arg, arg->op.left);
+                       return FILTER_VAL_NORM;
+
+               case FILTER_VAL_FALSE:
+                       if (arg->op.type == FILTER_OP_AND)
+                               return FILTER_VAL_FALSE;
+                       if (arg->op.type == FILTER_OP_NOT)
+                               return FILTER_VAL_TRUE;
+
+                       reparent_op_arg(parent, arg, arg->op.left);
+                       return FILTER_VAL_NORM;
+               }
+
+               return FILTER_VAL_NORM;
+       default:
+               die("bad arg in filter tree");
+       }
+       return FILTER_VAL_NORM;
+}
+
+/* Remove any unknown event fields */
+static struct filter_arg *collapse_tree(struct filter_arg *arg)
+{
+       enum filter_vals ret;
+
+       ret = test_arg(arg, arg);
+       switch (ret) {
+       case FILTER_VAL_NORM:
+               return arg;
+
+       case FILTER_VAL_TRUE:
+       case FILTER_VAL_FALSE:
+               free_arg(arg);
+               arg = allocate_arg();
+               arg->type = FILTER_ARG_BOOLEAN;
+               arg->boolean.value = ret == FILTER_VAL_TRUE;
+       }
+
+       return arg;
+}
+
+static int
+process_filter(struct event_format *event, struct filter_arg **parg,
+              char **error_str, int not)
+{
+       enum event_type type;
+       char *token = NULL;
+       struct filter_arg *current_op = NULL;
+       struct filter_arg *current_exp = NULL;
+       struct filter_arg *left_item = NULL;
+       struct filter_arg *arg = NULL;
+       enum op_type op_type;
+       enum filter_op_type btype;
+       enum filter_exp_type etype;
+       enum filter_cmp_type ctype;
+       int ret;
+
+       *parg = NULL;
+
+       do {
+               free(token);
+               type = read_token(&token);
+               switch (type) {
+               case EVENT_SQUOTE:
+               case EVENT_DQUOTE:
+               case EVENT_ITEM:
+                       arg = create_arg_item(event, token, type, error_str);
+                       if (!arg)
+                               goto fail;
+                       if (!left_item)
+                               left_item = arg;
+                       else if (current_exp) {
+                               ret = add_right(current_exp, arg, error_str);
+                               if (ret < 0)
+                                       goto fail;
+                               left_item = NULL;
+                               /* Not's only one one expression */
+                               if (not) {
+                                       arg = NULL;
+                                       if (current_op)
+                                               goto fail_print;
+                                       free(token);
+                                       *parg = current_exp;
+                                       return 0;
+                               }
+                       } else
+                               goto fail_print;
+                       arg = NULL;
+                       break;
+
+               case EVENT_DELIM:
+                       if (*token == ',') {
+                               show_error(error_str,
+                                          "Illegal token ','");
+                               goto fail;
+                       }
+
+                       if (*token == '(') {
+                               if (left_item) {
+                                       show_error(error_str,
+                                                  "Open paren can not come after item");
+                                       goto fail;
+                               }
+                               if (current_exp) {
+                                       show_error(error_str,
+                                                  "Open paren can not come after expression");
+                                       goto fail;
+                               }
+
+                               ret = process_filter(event, &arg, error_str, 0);
+                               if (ret != 1) {
+                                       if (ret == 0)
+                                               show_error(error_str,
+                                                          "Unbalanced number of '('");
+                                       goto fail;
+                               }
+                               ret = 0;
+
+                               /* A not wants just one expression */
+                               if (not) {
+                                       if (current_op)
+                                               goto fail_print;
+                                       *parg = arg;
+                                       return 0;
+                               }
+
+                               if (current_op)
+                                       ret = add_right(current_op, arg, error_str);
+                               else
+                                       current_exp = arg;
+
+                               if (ret < 0)
+                                       goto fail;
+
+                       } else { /* ')' */
+                               if (!current_op && !current_exp)
+                                       goto fail_print;
+
+                               /* Make sure everything is finished at this level */
+                               if (current_exp && !check_op_done(current_exp))
+                                       goto fail_print;
+                               if (current_op && !check_op_done(current_op))
+                                       goto fail_print;
+
+                               if (current_op)
+                                       *parg = current_op;
+                               else
+                                       *parg = current_exp;
+                               return 1;
+                       }
+                       break;
+
+               case EVENT_OP:
+                       op_type = process_op(token, &btype, &ctype, &etype);
+
+                       /* All expect a left arg except for NOT */
+                       switch (op_type) {
+                       case OP_BOOL:
+                               /* Logic ops need a left expression */
+                               if (!current_exp && !current_op)
+                                       goto fail_print;
+                               /* fall through */
+                       case OP_NOT:
+                               /* logic only processes ops and exp */
+                               if (left_item)
+                                       goto fail_print;
+                               break;
+                       case OP_EXP:
+                       case OP_CMP:
+                               if (!left_item)
+                                       goto fail_print;
+                               break;
+                       case OP_NONE:
+                               show_error(error_str,
+                                          "Unknown op token %s", token);
+                               goto fail;
+                       }
+
+                       ret = 0;
+                       switch (op_type) {
+                       case OP_BOOL:
+                               arg = create_arg_op(btype);
+                               if (current_op)
+                                       ret = add_left(arg, current_op);
+                               else
+                                       ret = add_left(arg, current_exp);
+                               current_op = arg;
+                               current_exp = NULL;
+                               break;
+
+                       case OP_NOT:
+                               arg = create_arg_op(btype);
+                               if (current_op)
+                                       ret = add_right(current_op, arg, error_str);
+                               if (ret < 0)
+                                       goto fail;
+                               current_exp = arg;
+                               ret = process_filter(event, &arg, error_str, 1);
+                               if (ret < 0)
+                                       goto fail;
+                               ret = add_right(current_exp, arg, error_str);
+                               if (ret < 0)
+                                       goto fail;
+                               break;
+
+                       case OP_EXP:
+                       case OP_CMP:
+                               if (op_type == OP_EXP)
+                                       arg = create_arg_exp(etype);
+                               else
+                                       arg = create_arg_cmp(ctype);
+
+                               if (current_op)
+                                       ret = add_right(current_op, arg, error_str);
+                               if (ret < 0)
+                                       goto fail;
+                               ret = add_left(arg, left_item);
+                               if (ret < 0) {
+                                       arg = NULL;
+                                       goto fail_print;
+                               }
+                               current_exp = arg;
+                               break;
+                       default:
+                               break;
+                       }
+                       arg = NULL;
+                       if (ret < 0)
+                               goto fail_print;
+                       break;
+               case EVENT_NONE:
+                       break;
+               default:
+                       goto fail_print;
+               }
+       } while (type != EVENT_NONE);
+
+       if (!current_op && !current_exp)
+               goto fail_print;
+
+       if (!current_op)
+               current_op = current_exp;
+
+       current_op = collapse_tree(current_op);
+
+       *parg = current_op;
+
+       return 0;
+
+ fail_print:
+       show_error(error_str, "Syntax error");
+ fail:
+       free_arg(current_op);
+       free_arg(current_exp);
+       free_arg(arg);
+       free(token);
+       return -1;
+}
+
+static int
+process_event(struct event_format *event, const char *filter_str,
+             struct filter_arg **parg, char **error_str)
+{
+       int ret;
+
+       pevent_buffer_init(filter_str, strlen(filter_str));
+
+       ret = process_filter(event, parg, error_str, 0);
+       if (ret == 1) {
+               show_error(error_str,
+                          "Unbalanced number of ')'");
+               return -1;
+       }
+       if (ret < 0)
+               return ret;
+
+       /* If parg is NULL, then make it into FALSE */
+       if (!*parg) {
+               *parg = allocate_arg();
+               (*parg)->type = FILTER_ARG_BOOLEAN;
+               (*parg)->boolean.value = FILTER_FALSE;
+       }
+
+       return 0;
+}
+
+static int filter_event(struct event_filter *filter,
+                       struct event_format *event,
+                       const char *filter_str, char **error_str)
+{
+       struct filter_type *filter_type;
+       struct filter_arg *arg;
+       int ret;
+
+       if (filter_str) {
+               ret = process_event(event, filter_str, &arg, error_str);
+               if (ret < 0)
+                       return ret;
+
+       } else {
+               /* just add a TRUE arg */
+               arg = allocate_arg();
+               arg->type = FILTER_ARG_BOOLEAN;
+               arg->boolean.value = FILTER_TRUE;
+       }
+
+       filter_type = add_filter_type(filter, event->id);
+       if (filter_type->filter)
+               free_arg(filter_type->filter);
+       filter_type->filter = arg;
+
+       return 0;
+}
+
+/**
+ * pevent_filter_add_filter_str - add a new filter
+ * @filter: the event filter to add to
+ * @filter_str: the filter string that contains the filter
+ * @error_str: string containing reason for failed filter
+ *
+ * Returns 0 if the filter was successfully added
+ *   -1 if there was an error.
+ *
+ * On error, if @error_str points to a string pointer,
+ * it is set to the reason that the filter failed.
+ * This string must be freed with "free".
+ */
+int pevent_filter_add_filter_str(struct event_filter *filter,
+                                const char *filter_str,
+                                char **error_str)
+{
+       struct pevent *pevent = filter->pevent;
+       struct event_list *event;
+       struct event_list *events = NULL;
+       const char *filter_start;
+       const char *next_event;
+       char *this_event;
+       char *event_name = NULL;
+       char *sys_name = NULL;
+       char *sp;
+       int rtn = 0;
+       int len;
+       int ret;
+
+       /* clear buffer to reset show error */
+       pevent_buffer_init("", 0);
+
+       if (error_str)
+               *error_str = NULL;
+
+       filter_start = strchr(filter_str, ':');
+       if (filter_start)
+               len = filter_start - filter_str;
+       else
+               len = strlen(filter_str);
+
+
+       do {
+               next_event = strchr(filter_str, ',');
+               if (next_event &&
+                   (!filter_start || next_event < filter_start))
+                       len = next_event - filter_str;
+               else if (filter_start)
+                       len = filter_start - filter_str;
+               else
+                       len = strlen(filter_str);
+
+               this_event = malloc_or_die(len + 1);
+               memcpy(this_event, filter_str, len);
+               this_event[len] = 0;
+
+               if (next_event)
+                       next_event++;
+
+               filter_str = next_event;
+
+               sys_name = strtok_r(this_event, "/", &sp);
+               event_name = strtok_r(NULL, "/", &sp);
+
+               if (!sys_name) {
+                       show_error(error_str, "No filter found");
+                       /* This can only happen when events is NULL, but still */
+                       free_events(events);
+                       free(this_event);
+                       return -1;
+               }
+
+               /* Find this event */
+               ret = find_event(pevent, &events, strim(sys_name), strim(event_name));
+               if (ret < 0) {
+                       if (event_name)
+                               show_error(error_str,
+                                          "No event found under '%s.%s'",
+                                          sys_name, event_name);
+                       else
+                               show_error(error_str,
+                                          "No event found under '%s'",
+                                          sys_name);
+                       free_events(events);
+                       free(this_event);
+                       return -1;
+               }
+               free(this_event);
+       } while (filter_str);
+
+       /* Skip the ':' */
+       if (filter_start)
+               filter_start++;
+
+       /* filter starts here */
+       for (event = events; event; event = event->next) {
+               ret = filter_event(filter, event->event, filter_start,
+                                  error_str);
+               /* Failures are returned if a parse error happened */
+               if (ret < 0)
+                       rtn = ret;
+
+               if (ret >= 0 && pevent->test_filters) {
+                       char *test;
+                       test = pevent_filter_make_string(filter, event->event->id);
+                       printf(" '%s: %s'\n", event->event->name, test);
+                       free(test);
+               }
+       }
+
+       free_events(events);
+
+       if (rtn >= 0 && pevent->test_filters)
+               exit(0);
+
+       return rtn;
+}
+
+static void free_filter_type(struct filter_type *filter_type)
+{
+       free_arg(filter_type->filter);
+}
+
+/**
+ * pevent_filter_remove_event - remove a filter for an event
+ * @filter: the event filter to remove from
+ * @event_id: the event to remove a filter for
+ *
+ * Removes the filter saved for an event defined by @event_id
+ * from the @filter.
+ *
+ * Returns 1: if an event was removed
+ *   0: if the event was not found
+ */
+int pevent_filter_remove_event(struct event_filter *filter,
+                              int event_id)
+{
+       struct filter_type *filter_type;
+       unsigned long len;
+
+       if (!filter->filters)
+               return 0;
+
+       filter_type = find_filter_type(filter, event_id);
+
+       if (!filter_type)
+               return 0;
+
+       free_filter_type(filter_type);
+
+       /* The filter_type points into the event_filters array */
+       len = (unsigned long)(filter->event_filters + filter->filters) -
+               (unsigned long)(filter_type + 1);
+
+       memmove(filter_type, filter_type + 1, len);
+       filter->filters--;
+
+       memset(&filter->event_filters[filter->filters], 0,
+              sizeof(*filter_type));
+
+       return 1;
+}
+
+/**
+ * pevent_filter_reset - clear all filters in a filter
+ * @filter: the event filter to reset
+ *
+ * Removes all filters from a filter and resets it.
+ */
+void pevent_filter_reset(struct event_filter *filter)
+{
+       int i;
+
+       for (i = 0; i < filter->filters; i++)
+               free_filter_type(&filter->event_filters[i]);
+
+       free(filter->event_filters);
+       filter->filters = 0;
+       filter->event_filters = NULL;
+}
+
+void pevent_filter_free(struct event_filter *filter)
+{
+       pevent_unref(filter->pevent);
+
+       pevent_filter_reset(filter);
+
+       free(filter);
+}
+
+static char *arg_to_str(struct event_filter *filter, struct filter_arg *arg);
+
+static int copy_filter_type(struct event_filter *filter,
+                            struct event_filter *source,
+                            struct filter_type *filter_type)
+{
+       struct filter_arg *arg;
+       struct event_format *event;
+       const char *sys;
+       const char *name;
+       char *str;
+
+       /* Can't assume that the pevent's are the same */
+       sys = filter_type->event->system;
+       name = filter_type->event->name;
+       event = pevent_find_event_by_name(filter->pevent, sys, name);
+       if (!event)
+               return -1;
+
+       str = arg_to_str(source, filter_type->filter);
+       if (!str)
+               return -1;
+
+       if (strcmp(str, "TRUE") == 0 || strcmp(str, "FALSE") == 0) {
+               /* Add trivial event */
+               arg = allocate_arg();
+               arg->type = FILTER_ARG_BOOLEAN;
+               if (strcmp(str, "TRUE") == 0)
+                       arg->boolean.value = 1;
+               else
+                       arg->boolean.value = 0;
+
+               filter_type = add_filter_type(filter, event->id);
+               filter_type->filter = arg;
+
+               free(str);
+               return 0;
+       }
+
+       filter_event(filter, event, str, NULL);
+       free(str);
+
+       return 0;
+}
+
+/**
+ * pevent_filter_copy - copy a filter using another filter
+ * @dest - the filter to copy to
+ * @source - the filter to copy from
+ *
+ * Returns 0 on success and -1 if not all filters were copied
+ */
+int pevent_filter_copy(struct event_filter *dest, struct event_filter *source)
+{
+       int ret = 0;
+       int i;
+
+       pevent_filter_reset(dest);
+
+       for (i = 0; i < source->filters; i++) {
+               if (copy_filter_type(dest, source, &source->event_filters[i]))
+                       ret = -1;
+       }
+       return ret;
+}
+
+
+/**
+ * pevent_update_trivial - update the trivial filters with the given filter
+ * @dest - the filter to update
+ * @source - the filter as the source of the update
+ * @type - the type of trivial filter to update.
+ *
+ * Scan dest for trivial events matching @type to replace with the source.
+ *
+ * Returns 0 on success and -1 if there was a problem updating, but
+ *   events may have still been updated on error.
+ */
+int pevent_update_trivial(struct event_filter *dest, struct event_filter *source,
+                         enum filter_trivial_type type)
+{
+       struct pevent *src_pevent;
+       struct pevent *dest_pevent;
+       struct event_format *event;
+       struct filter_type *filter_type;
+       struct filter_arg *arg;
+       char *str;
+       int i;
+
+       src_pevent = source->pevent;
+       dest_pevent = dest->pevent;
+
+       /* Do nothing if either of the filters has nothing to filter */
+       if (!dest->filters || !source->filters)
+               return 0;
+
+       for (i = 0; i < dest->filters; i++) {
+               filter_type = &dest->event_filters[i];
+               arg = filter_type->filter;
+               if (arg->type != FILTER_ARG_BOOLEAN)
+                       continue;
+               if ((arg->boolean.value && type == FILTER_TRIVIAL_FALSE) ||
+                   (!arg->boolean.value && type == FILTER_TRIVIAL_TRUE))
+                       continue;
+
+               event = filter_type->event;
+
+               if (src_pevent != dest_pevent) {
+                       /* do a look up */
+                       event = pevent_find_event_by_name(src_pevent,
+                                                         event->system,
+                                                         event->name);
+                       if (!event)
+                               return -1;
+               }
+
+               str = pevent_filter_make_string(source, event->id);
+               if (!str)
+                       continue;
+
+               /* Don't bother if the filter is trivial too */
+               if (strcmp(str, "TRUE") != 0 && strcmp(str, "FALSE") != 0)
+                       filter_event(dest, event, str, NULL);
+               free(str);
+       }
+       return 0;
+}
+
+/**
+ * pevent_filter_clear_trivial - clear TRUE and FALSE filters
+ * @filter: the filter to remove trivial filters from
+ * @type: remove only true, false, or both
+ *
+ * Removes filters that only contain a TRUE or FALES boolean arg.
+ */
+void pevent_filter_clear_trivial(struct event_filter *filter,
+                                enum filter_trivial_type type)
+{
+       struct filter_type *filter_type;
+       int count = 0;
+       int *ids = NULL;
+       int i;
+
+       if (!filter->filters)
+               return;
+
+       /*
+        * Two steps, first get all ids with trivial filters.
+        *  then remove those ids.
+        */
+       for (i = 0; i < filter->filters; i++) {
+               filter_type = &filter->event_filters[i];
+               if (filter_type->filter->type != FILTER_ARG_BOOLEAN)
+                       continue;
+               switch (type) {
+               case FILTER_TRIVIAL_FALSE:
+                       if (filter_type->filter->boolean.value)
+                               continue;
+               case FILTER_TRIVIAL_TRUE:
+                       if (!filter_type->filter->boolean.value)
+                               continue;
+               default:
+                       break;
+               }
+
+               ids = realloc(ids, sizeof(*ids) * (count + 1));
+               if (!ids)
+                       die("Can't allocate ids");
+               ids[count++] = filter_type->event_id;
+       }
+
+       if (!count)
+               return;
+
+       for (i = 0; i < count; i++)
+               pevent_filter_remove_event(filter, ids[i]);
+
+       free(ids);
+}
+
+/**
+ * pevent_filter_event_has_trivial - return true event contains trivial filter
+ * @filter: the filter with the information
+ * @event_id: the id of the event to test
+ * @type: trivial type to test for (TRUE, FALSE, EITHER)
+ *
+ * Returns 1 if the event contains a matching trivial type
+ *  otherwise 0.
+ */
+int pevent_filter_event_has_trivial(struct event_filter *filter,
+                                   int event_id,
+                                   enum filter_trivial_type type)
+{
+       struct filter_type *filter_type;
+
+       if (!filter->filters)
+               return 0;
+
+       filter_type = find_filter_type(filter, event_id);
+
+       if (!filter_type)
+               return 0;
+
+       if (filter_type->filter->type != FILTER_ARG_BOOLEAN)
+               return 0;
+
+       switch (type) {
+       case FILTER_TRIVIAL_FALSE:
+               return !filter_type->filter->boolean.value;
+
+       case FILTER_TRIVIAL_TRUE:
+               return filter_type->filter->boolean.value;
+       default:
+               return 1;
+       }
+}
+
+static int test_filter(struct event_format *event,
+                      struct filter_arg *arg, struct pevent_record *record);
+
+static const char *
+get_comm(struct event_format *event, struct pevent_record *record)
+{
+       const char *comm;
+       int pid;
+
+       pid = pevent_data_pid(event->pevent, record);
+       comm = pevent_data_comm_from_pid(event->pevent, pid);
+       return comm;
+}
+
+static unsigned long long
+get_value(struct event_format *event,
+         struct format_field *field, struct pevent_record *record)
+{
+       unsigned long long val;
+
+       /* Handle our dummy "comm" field */
+       if (field == &comm) {
+               const char *name;
+
+               name = get_comm(event, record);
+               return (unsigned long)name;
+       }
+
+       pevent_read_number_field(field, record->data, &val);
+
+       if (!(field->flags & FIELD_IS_SIGNED))
+               return val;
+
+       switch (field->size) {
+       case 1:
+               return (char)val;
+       case 2:
+               return (short)val;
+       case 4:
+               return (int)val;
+       case 8:
+               return (long long)val;
+       }
+       return val;
+}
+
+static unsigned long long
+get_arg_value(struct event_format *event, struct filter_arg *arg, struct pevent_record *record);
+
+static unsigned long long
+get_exp_value(struct event_format *event, struct filter_arg *arg, struct pevent_record *record)
+{
+       unsigned long long lval, rval;
+
+       lval = get_arg_value(event, arg->exp.left, record);
+       rval = get_arg_value(event, arg->exp.right, record);
+
+       switch (arg->exp.type) {
+       case FILTER_EXP_ADD:
+               return lval + rval;
+
+       case FILTER_EXP_SUB:
+               return lval - rval;
+
+       case FILTER_EXP_MUL:
+               return lval * rval;
+
+       case FILTER_EXP_DIV:
+               return lval / rval;
+
+       case FILTER_EXP_MOD:
+               return lval % rval;
+
+       case FILTER_EXP_RSHIFT:
+               return lval >> rval;
+
+       case FILTER_EXP_LSHIFT:
+               return lval << rval;
+
+       case FILTER_EXP_AND:
+               return lval & rval;
+
+       case FILTER_EXP_OR:
+               return lval | rval;
+
+       case FILTER_EXP_XOR:
+               return lval ^ rval;
+
+       case FILTER_EXP_NOT:
+       default:
+               die("error in exp");
+       }
+       return 0;
+}
+
+static unsigned long long
+get_arg_value(struct event_format *event, struct filter_arg *arg, struct pevent_record *record)
+{
+       switch (arg->type) {
+       case FILTER_ARG_FIELD:
+               return get_value(event, arg->field.field, record);
+
+       case FILTER_ARG_VALUE:
+               if (arg->value.type != FILTER_NUMBER)
+                       die("must have number field!");
+               return arg->value.val;
+
+       case FILTER_ARG_EXP:
+               return get_exp_value(event, arg, record);
+
+       default:
+               die("oops in filter");
+       }
+       return 0;
+}
+
+static int test_num(struct event_format *event,
+                   struct filter_arg *arg, struct pevent_record *record)
+{
+       unsigned long long lval, rval;
+
+       lval = get_arg_value(event, arg->num.left, record);
+       rval = get_arg_value(event, arg->num.right, record);
+
+       switch (arg->num.type) {
+       case FILTER_CMP_EQ:
+               return lval == rval;
+
+       case FILTER_CMP_NE:
+               return lval != rval;
+
+       case FILTER_CMP_GT:
+               return lval > rval;
+
+       case FILTER_CMP_LT:
+               return lval < rval;
+
+       case FILTER_CMP_GE:
+               return lval >= rval;
+
+       case FILTER_CMP_LE:
+               return lval <= rval;
+
+       default:
+               /* ?? */
+               return 0;
+       }
+}
+
+static const char *get_field_str(struct filter_arg *arg, struct pevent_record *record)
+{
+       struct event_format *event;
+       struct pevent *pevent;
+       unsigned long long addr;
+       const char *val = NULL;
+       char hex[64];
+
+       /* If the field is not a string convert it */
+       if (arg->str.field->flags & FIELD_IS_STRING) {
+               val = record->data + arg->str.field->offset;
+
+               /*
+                * We need to copy the data since we can't be sure the field
+                * is null terminated.
+                */
+               if (*(val + arg->str.field->size - 1)) {
+                       /* copy it */
+                       memcpy(arg->str.buffer, val, arg->str.field->size);
+                       /* the buffer is already NULL terminated */
+                       val = arg->str.buffer;
+               }
+
+       } else {
+               event = arg->str.field->event;
+               pevent = event->pevent;
+               addr = get_value(event, arg->str.field, record);
+
+               if (arg->str.field->flags & (FIELD_IS_POINTER | FIELD_IS_LONG))
+                       /* convert to a kernel symbol */
+                       val = pevent_find_function(pevent, addr);
+
+               if (val == NULL) {
+                       /* just use the hex of the string name */
+                       snprintf(hex, 64, "0x%llx", addr);
+                       val = hex;
+               }
+       }
+
+       return val;
+}
+
+static int test_str(struct event_format *event,
+                   struct filter_arg *arg, struct pevent_record *record)
+{
+       const char *val;
+
+       if (arg->str.field == &comm)
+               val = get_comm(event, record);
+       else
+               val = get_field_str(arg, record);
+
+       switch (arg->str.type) {
+       case FILTER_CMP_MATCH:
+               return strcmp(val, arg->str.val) == 0;
+
+       case FILTER_CMP_NOT_MATCH:
+               return strcmp(val, arg->str.val) != 0;
+
+       case FILTER_CMP_REGEX:
+               /* Returns zero on match */
+               return !regexec(&arg->str.reg, val, 0, NULL, 0);
+
+       case FILTER_CMP_NOT_REGEX:
+               return regexec(&arg->str.reg, val, 0, NULL, 0);
+
+       default:
+               /* ?? */
+               return 0;
+       }
+}
+
+static int test_op(struct event_format *event,
+                  struct filter_arg *arg, struct pevent_record *record)
+{
+       switch (arg->op.type) {
+       case FILTER_OP_AND:
+               return test_filter(event, arg->op.left, record) &&
+                       test_filter(event, arg->op.right, record);
+
+       case FILTER_OP_OR:
+               return test_filter(event, arg->op.left, record) ||
+                       test_filter(event, arg->op.right, record);
+
+       case FILTER_OP_NOT:
+               return !test_filter(event, arg->op.right, record);
+
+       default:
+               /* ?? */
+               return 0;
+       }
+}
+
+static int test_filter(struct event_format *event,
+                      struct filter_arg *arg, struct pevent_record *record)
+{
+       switch (arg->type) {
+       case FILTER_ARG_BOOLEAN:
+               /* easy case */
+               return arg->boolean.value;
+
+       case FILTER_ARG_OP:
+               return test_op(event, arg, record);
+
+       case FILTER_ARG_NUM:
+               return test_num(event, arg, record);
+
+       case FILTER_ARG_STR:
+               return test_str(event, arg, record);
+
+       case FILTER_ARG_EXP:
+       case FILTER_ARG_VALUE:
+       case FILTER_ARG_FIELD:
+               /*
+                * Expressions, fields and values evaluate
+                * to true if they return non zero
+                */
+               return !!get_arg_value(event, arg, record);
+
+       default:
+               die("oops!");
+               /* ?? */
+               return 0;
+       }
+}
+
+/**
+ * pevent_event_filtered - return true if event has filter
+ * @filter: filter struct with filter information
+ * @event_id: event id to test if filter exists
+ *
+ * Returns 1 if filter found for @event_id
+ *   otherwise 0;
+ */
+int pevent_event_filtered(struct event_filter *filter,
+                         int event_id)
+{
+       struct filter_type *filter_type;
+
+       if (!filter->filters)
+               return 0;
+
+       filter_type = find_filter_type(filter, event_id);
+
+       return filter_type ? 1 : 0;
+}
+
+/**
+ * pevent_filter_match - test if a record matches a filter
+ * @filter: filter struct with filter information
+ * @record: the record to test against the filter
+ *
+ * Returns:
+ *  1 - filter found for event and @record matches
+ *  0 - filter found for event and @record does not match
+ * -1 - no filter found for @record's event
+ * -2 - if no filters exist
+ */
+int pevent_filter_match(struct event_filter *filter,
+                       struct pevent_record *record)
+{
+       struct pevent *pevent = filter->pevent;
+       struct filter_type *filter_type;
+       int event_id;
+
+       if (!filter->filters)
+               return FILTER_NONE;
+
+       event_id = pevent_data_type(pevent, record);
+
+       filter_type = find_filter_type(filter, event_id);
+
+       if (!filter_type)
+               return FILTER_NOEXIST;
+
+       return test_filter(filter_type->event, filter_type->filter, record) ?
+               FILTER_MATCH : FILTER_MISS;
+}
+
+static char *op_to_str(struct event_filter *filter, struct filter_arg *arg)
+{
+       char *str = NULL;
+       char *left = NULL;
+       char *right = NULL;
+       char *op = NULL;
+       int left_val = -1;
+       int right_val = -1;
+       int val;
+       int len;
+
+       switch (arg->op.type) {
+       case FILTER_OP_AND:
+               op = "&&";
+               /* fall through */
+       case FILTER_OP_OR:
+               if (!op)
+                       op = "||";
+
+               left = arg_to_str(filter, arg->op.left);
+               right = arg_to_str(filter, arg->op.right);
+               if (!left || !right)
+                       break;
+
+               /* Try to consolidate boolean values */
+               if (strcmp(left, "TRUE") == 0)
+                       left_val = 1;
+               else if (strcmp(left, "FALSE") == 0)
+                       left_val = 0;
+
+               if (strcmp(right, "TRUE") == 0)
+                       right_val = 1;
+               else if (strcmp(right, "FALSE") == 0)
+                       right_val = 0;
+
+               if (left_val >= 0) {
+                       if ((arg->op.type == FILTER_OP_AND && !left_val) ||
+                           (arg->op.type == FILTER_OP_OR && left_val)) {
+                               /* Just return left value */
+                               str = left;
+                               left = NULL;
+                               break;
+                       }
+                       if (right_val >= 0) {
+                               /* just evaluate this. */
+                               val = 0;
+                               switch (arg->op.type) {
+                               case FILTER_OP_AND:
+                                       val = left_val && right_val;
+                                       break;
+                               case FILTER_OP_OR:
+                                       val = left_val || right_val;
+                                       break;
+                               default:
+                                       break;
+                               }
+                               str = malloc_or_die(6);
+                               if (val)
+                                       strcpy(str, "TRUE");
+                               else
+                                       strcpy(str, "FALSE");
+                               break;
+                       }
+               }
+               if (right_val >= 0) {
+                       if ((arg->op.type == FILTER_OP_AND && !right_val) ||
+                           (arg->op.type == FILTER_OP_OR && right_val)) {
+                               /* Just return right value */
+                               str = right;
+                               right = NULL;
+                               break;
+                       }
+                       /* The right value is meaningless */
+                       str = left;
+                       left = NULL;
+                       break;
+               }
+
+               len = strlen(left) + strlen(right) + strlen(op) + 10;
+               str = malloc_or_die(len);
+               snprintf(str, len, "(%s) %s (%s)",
+                        left, op, right);
+               break;
+
+       case FILTER_OP_NOT:
+               op = "!";
+               right = arg_to_str(filter, arg->op.right);
+               if (!right)
+                       break;
+
+               /* See if we can consolidate */
+               if (strcmp(right, "TRUE") == 0)
+                       right_val = 1;
+               else if (strcmp(right, "FALSE") == 0)
+                       right_val = 0;
+               if (right_val >= 0) {
+                       /* just return the opposite */
+                       str = malloc_or_die(6);
+                       if (right_val)
+                               strcpy(str, "FALSE");
+                       else
+                               strcpy(str, "TRUE");
+                       break;
+               }
+               len = strlen(right) + strlen(op) + 3;
+               str = malloc_or_die(len);
+               snprintf(str, len, "%s(%s)", op, right);
+               break;
+
+       default:
+               /* ?? */
+               break;
+       }
+       free(left);
+       free(right);
+       return str;
+}
+
+static char *val_to_str(struct event_filter *filter, struct filter_arg *arg)
+{
+       char *str;
+
+       str = malloc_or_die(30);
+
+       snprintf(str, 30, "%lld", arg->value.val);
+
+       return str;
+}
+
+static char *field_to_str(struct event_filter *filter, struct filter_arg *arg)
+{
+       return strdup(arg->field.field->name);
+}
+
+static char *exp_to_str(struct event_filter *filter, struct filter_arg *arg)
+{
+       char *lstr;
+       char *rstr;
+       char *op;
+       char *str = NULL;
+       int len;
+
+       lstr = arg_to_str(filter, arg->exp.left);
+       rstr = arg_to_str(filter, arg->exp.right);
+       if (!lstr || !rstr)
+               goto out;
+
+       switch (arg->exp.type) {
+       case FILTER_EXP_ADD:
+               op = "+";
+               break;
+       case FILTER_EXP_SUB:
+               op = "-";
+               break;
+       case FILTER_EXP_MUL:
+               op = "*";
+               break;
+       case FILTER_EXP_DIV:
+               op = "/";
+               break;
+       case FILTER_EXP_MOD:
+               op = "%";
+               break;
+       case FILTER_EXP_RSHIFT:
+               op = ">>";
+               break;
+       case FILTER_EXP_LSHIFT:
+               op = "<<";
+               break;
+       case FILTER_EXP_AND:
+               op = "&";
+               break;
+       case FILTER_EXP_OR:
+               op = "|";
+               break;
+       case FILTER_EXP_XOR:
+               op = "^";
+               break;
+       default:
+               die("oops in exp");
+       }
+
+       len = strlen(op) + strlen(lstr) + strlen(rstr) + 4;
+       str = malloc_or_die(len);
+       snprintf(str, len, "%s %s %s", lstr, op, rstr);
+out:
+       free(lstr);
+       free(rstr);
+
+       return str;
+}
+
+static char *num_to_str(struct event_filter *filter, struct filter_arg *arg)
+{
+       char *lstr;
+       char *rstr;
+       char *str = NULL;
+       char *op = NULL;
+       int len;
+
+       lstr = arg_to_str(filter, arg->num.left);
+       rstr = arg_to_str(filter, arg->num.right);
+       if (!lstr || !rstr)
+               goto out;
+
+       switch (arg->num.type) {
+       case FILTER_CMP_EQ:
+               op = "==";
+               /* fall through */
+       case FILTER_CMP_NE:
+               if (!op)
+                       op = "!=";
+               /* fall through */
+       case FILTER_CMP_GT:
+               if (!op)
+                       op = ">";
+               /* fall through */
+       case FILTER_CMP_LT:
+               if (!op)
+                       op = "<";
+               /* fall through */
+       case FILTER_CMP_GE:
+               if (!op)
+                       op = ">=";
+               /* fall through */
+       case FILTER_CMP_LE:
+               if (!op)
+                       op = "<=";
+
+               len = strlen(lstr) + strlen(op) + strlen(rstr) + 4;
+               str = malloc_or_die(len);
+               sprintf(str, "%s %s %s", lstr, op, rstr);
+
+               break;
+
+       default:
+               /* ?? */
+               break;
+       }
+
+out:
+       free(lstr);
+       free(rstr);
+       return str;
+}
+
+static char *str_to_str(struct event_filter *filter, struct filter_arg *arg)
+{
+       char *str = NULL;
+       char *op = NULL;
+       int len;
+
+       switch (arg->str.type) {
+       case FILTER_CMP_MATCH:
+               op = "==";
+               /* fall through */
+       case FILTER_CMP_NOT_MATCH:
+               if (!op)
+                       op = "!=";
+               /* fall through */
+       case FILTER_CMP_REGEX:
+               if (!op)
+                       op = "=~";
+               /* fall through */
+       case FILTER_CMP_NOT_REGEX:
+               if (!op)
+                       op = "!~";
+
+               len = strlen(arg->str.field->name) + strlen(op) +
+                       strlen(arg->str.val) + 6;
+               str = malloc_or_die(len);
+               snprintf(str, len, "%s %s \"%s\"",
+                        arg->str.field->name,
+                        op, arg->str.val);
+               break;
+
+       default:
+               /* ?? */
+               break;
+       }
+       return str;
+}
+
+static char *arg_to_str(struct event_filter *filter, struct filter_arg *arg)
+{
+       char *str;
+
+       switch (arg->type) {
+       case FILTER_ARG_BOOLEAN:
+               str = malloc_or_die(6);
+               if (arg->boolean.value)
+                       strcpy(str, "TRUE");
+               else
+                       strcpy(str, "FALSE");
+               return str;
+
+       case FILTER_ARG_OP:
+               return op_to_str(filter, arg);
+
+       case FILTER_ARG_NUM:
+               return num_to_str(filter, arg);
+
+       case FILTER_ARG_STR:
+               return str_to_str(filter, arg);
+
+       case FILTER_ARG_VALUE:
+               return val_to_str(filter, arg);
+
+       case FILTER_ARG_FIELD:
+               return field_to_str(filter, arg);
+
+       case FILTER_ARG_EXP:
+               return exp_to_str(filter, arg);
+
+       default:
+               /* ?? */
+               return NULL;
+       }
+
+}
+
+/**
+ * pevent_filter_make_string - return a string showing the filter
+ * @filter: filter struct with filter information
+ * @event_id: the event id to return the filter string with
+ *
+ * Returns a string that displays the filter contents.
+ *  This string must be freed with free(str).
+ *  NULL is returned if no filter is found.
+ */
+char *
+pevent_filter_make_string(struct event_filter *filter, int event_id)
+{
+       struct filter_type *filter_type;
+
+       if (!filter->filters)
+               return NULL;
+
+       filter_type = find_filter_type(filter, event_id);
+
+       if (!filter_type)
+               return NULL;
+
+       return arg_to_str(filter, filter_type->filter);
+}
+
+/**
+ * pevent_filter_compare - compare two filters and return if they are the same
+ * @filter1: Filter to compare with @filter2
+ * @filter2: Filter to compare with @filter1
+ *
+ * Returns:
+ *  1 if the two filters hold the same content.
+ *  0 if they do not.
+ */
+int pevent_filter_compare(struct event_filter *filter1, struct event_filter *filter2)
+{
+       struct filter_type *filter_type1;
+       struct filter_type *filter_type2;
+       char *str1, *str2;
+       int result;
+       int i;
+
+       /* Do the easy checks first */
+       if (filter1->filters != filter2->filters)
+               return 0;
+       if (!filter1->filters && !filter2->filters)
+               return 1;
+
+       /*
+        * Now take a look at each of the events to see if they have the same
+        * filters to them.
+        */
+       for (i = 0; i < filter1->filters; i++) {
+               filter_type1 = &filter1->event_filters[i];
+               filter_type2 = find_filter_type(filter2, filter_type1->event_id);
+               if (!filter_type2)
+                       break;
+               if (filter_type1->filter->type != filter_type2->filter->type)
+                       break;
+               switch (filter_type1->filter->type) {
+               case FILTER_TRIVIAL_FALSE:
+               case FILTER_TRIVIAL_TRUE:
+                       /* trivial types just need the type compared */
+                       continue;
+               default:
+                       break;
+               }
+               /* The best way to compare complex filters is with strings */
+               str1 = arg_to_str(filter1, filter_type1->filter);
+               str2 = arg_to_str(filter2, filter_type2->filter);
+               if (str1 && str2)
+                       result = strcmp(str1, str2) != 0;
+               else
+                       /* bail out if allocation fails */
+                       result = 1;
+
+               free(str1);
+               free(str2);
+               if (result)
+                       break;
+       }
+
+       if (i < filter1->filters)
+               return 0;
+       return 1;
+}
+
diff --git a/traceevent/parse-utils.c b/traceevent/parse-utils.c
new file mode 100644 (file)
index 0000000..f023a13
--- /dev/null
@@ -0,0 +1,110 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <errno.h>
+
+#define __weak __attribute__((weak))
+
+void __vdie(const char *fmt, va_list ap)
+{
+       int ret = errno;
+
+       if (errno)
+               perror("trace-cmd");
+       else
+               ret = -1;
+
+       fprintf(stderr, "  ");
+       vfprintf(stderr, fmt, ap);
+
+       fprintf(stderr, "\n");
+       exit(ret);
+}
+
+void __die(const char *fmt, ...)
+{
+       va_list ap;
+
+       va_start(ap, fmt);
+       __vdie(fmt, ap);
+       va_end(ap);
+}
+
+void __weak die(const char *fmt, ...)
+{
+       va_list ap;
+
+       va_start(ap, fmt);
+       __vdie(fmt, ap);
+       va_end(ap);
+}
+
+void __vwarning(const char *fmt, va_list ap)
+{
+       if (errno)
+               perror("trace-cmd");
+       errno = 0;
+
+       fprintf(stderr, "  ");
+       vfprintf(stderr, fmt, ap);
+
+       fprintf(stderr, "\n");
+}
+
+void __warning(const char *fmt, ...)
+{
+       va_list ap;
+
+       va_start(ap, fmt);
+       __vwarning(fmt, ap);
+       va_end(ap);
+}
+
+void __weak warning(const char *fmt, ...)
+{
+       va_list ap;
+
+       va_start(ap, fmt);
+       __vwarning(fmt, ap);
+       va_end(ap);
+}
+
+void __vpr_stat(const char *fmt, va_list ap)
+{
+       vprintf(fmt, ap);
+       printf("\n");
+}
+
+void __pr_stat(const char *fmt, ...)
+{
+       va_list ap;
+
+       va_start(ap, fmt);
+       __vpr_stat(fmt, ap);
+       va_end(ap);
+}
+
+void __weak vpr_stat(const char *fmt, va_list ap)
+{
+       __vpr_stat(fmt, ap);
+}
+
+void __weak pr_stat(const char *fmt, ...)
+{
+       va_list ap;
+
+       va_start(ap, fmt);
+       __vpr_stat(fmt, ap);
+       va_end(ap);
+}
+
+void __weak *malloc_or_die(unsigned int size)
+{
+       void *data;
+
+       data = malloc(size);
+       if (!data)
+               die("malloc");
+       return data;
+}
diff --git a/traceevent/trace-seq.c b/traceevent/trace-seq.c
new file mode 100644 (file)
index 0000000..b1ccc92
--- /dev/null
@@ -0,0 +1,200 @@
+/*
+ * Copyright (C) 2009 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License (not later!)
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+
+#include "event-parse.h"
+#include "event-utils.h"
+
+/*
+ * The TRACE_SEQ_POISON is to catch the use of using
+ * a trace_seq structure after it was destroyed.
+ */
+#define TRACE_SEQ_POISON       ((void *)0xdeadbeef)
+#define TRACE_SEQ_CHECK(s)                                             \
+do {                                                                   \
+       if ((s)->buffer == TRACE_SEQ_POISON)                    \
+               die("Usage of trace_seq after it was destroyed");       \
+} while (0)
+
+/**
+ * trace_seq_init - initialize the trace_seq structure
+ * @s: a pointer to the trace_seq structure to initialize
+ */
+void trace_seq_init(struct trace_seq *s)
+{
+       s->len = 0;
+       s->readpos = 0;
+       s->buffer_size = TRACE_SEQ_BUF_SIZE;
+       s->buffer = malloc_or_die(s->buffer_size);
+}
+
+/**
+ * trace_seq_destroy - free up memory of a trace_seq
+ * @s: a pointer to the trace_seq to free the buffer
+ *
+ * Only frees the buffer, not the trace_seq struct itself.
+ */
+void trace_seq_destroy(struct trace_seq *s)
+{
+       if (!s)
+               return;
+       TRACE_SEQ_CHECK(s);
+       free(s->buffer);
+       s->buffer = TRACE_SEQ_POISON;
+}
+
+static void expand_buffer(struct trace_seq *s)
+{
+       s->buffer_size += TRACE_SEQ_BUF_SIZE;
+       s->buffer = realloc(s->buffer, s->buffer_size);
+       if (!s->buffer)
+               die("Can't allocate trace_seq buffer memory");
+}
+
+/**
+ * trace_seq_printf - sequence printing of trace information
+ * @s: trace sequence descriptor
+ * @fmt: printf format string
+ *
+ * It returns 0 if the trace oversizes the buffer's free
+ * space, 1 otherwise.
+ *
+ * The tracer may use either sequence operations or its own
+ * copy to user routines. To simplify formating of a trace
+ * trace_seq_printf is used to store strings into a special
+ * buffer (@s). Then the output may be either used by
+ * the sequencer or pulled into another buffer.
+ */
+int
+trace_seq_printf(struct trace_seq *s, const char *fmt, ...)
+{
+       va_list ap;
+       int len;
+       int ret;
+
+       TRACE_SEQ_CHECK(s);
+
+ try_again:
+       len = (s->buffer_size - 1) - s->len;
+
+       va_start(ap, fmt);
+       ret = vsnprintf(s->buffer + s->len, len, fmt, ap);
+       va_end(ap);
+
+       if (ret >= len) {
+               expand_buffer(s);
+               goto try_again;
+       }
+
+       s->len += ret;
+
+       return 1;
+}
+
+/**
+ * trace_seq_vprintf - sequence printing of trace information
+ * @s: trace sequence descriptor
+ * @fmt: printf format string
+ *
+ * The tracer may use either sequence operations or its own
+ * copy to user routines. To simplify formating of a trace
+ * trace_seq_printf is used to store strings into a special
+ * buffer (@s). Then the output may be either used by
+ * the sequencer or pulled into another buffer.
+ */
+int
+trace_seq_vprintf(struct trace_seq *s, const char *fmt, va_list args)
+{
+       int len;
+       int ret;
+
+       TRACE_SEQ_CHECK(s);
+
+ try_again:
+       len = (s->buffer_size - 1) - s->len;
+
+       ret = vsnprintf(s->buffer + s->len, len, fmt, args);
+
+       if (ret >= len) {
+               expand_buffer(s);
+               goto try_again;
+       }
+
+       s->len += ret;
+
+       return len;
+}
+
+/**
+ * trace_seq_puts - trace sequence printing of simple string
+ * @s: trace sequence descriptor
+ * @str: simple string to record
+ *
+ * The tracer may use either the sequence operations or its own
+ * copy to user routines. This function records a simple string
+ * into a special buffer (@s) for later retrieval by a sequencer
+ * or other mechanism.
+ */
+int trace_seq_puts(struct trace_seq *s, const char *str)
+{
+       int len;
+
+       TRACE_SEQ_CHECK(s);
+
+       len = strlen(str);
+
+       while (len > ((s->buffer_size - 1) - s->len))
+               expand_buffer(s);
+
+       memcpy(s->buffer + s->len, str, len);
+       s->len += len;
+
+       return len;
+}
+
+int trace_seq_putc(struct trace_seq *s, unsigned char c)
+{
+       TRACE_SEQ_CHECK(s);
+
+       while (s->len >= (s->buffer_size - 1))
+               expand_buffer(s);
+
+       s->buffer[s->len++] = c;
+
+       return 1;
+}
+
+void trace_seq_terminate(struct trace_seq *s)
+{
+       TRACE_SEQ_CHECK(s);
+
+       /* There's always one character left on the buffer */
+       s->buffer[s->len] = 0;
+}
+
+int trace_seq_do_printf(struct trace_seq *s)
+{
+       TRACE_SEQ_CHECK(s);
+       return printf("%.*s", s->len, s->buffer);
+}