]> granicus.if.org Git - sysstat/commitdiff
Added CPU average clock frequency statistics to sar and sadc.
authorSebastien Godard <sysstat@orange.fr>
Sun, 24 Oct 2010 15:39:20 +0000 (17:39 +0200)
committerSebastien Godard <sysstat@orange.fr>
Sun, 24 Oct 2010 15:39:20 +0000 (17:39 +0200)
This patch adds a new option to sar (-m FREQ) that displays
the following field: wghMHz.
For this option to work, the cpufreq-stats driver must be compiled
in the kernel, as we need to read the "time-in-state" file in /sys.
sadc and sadf have also been updated to take into account this new field.
DTD and XSD documents have been updated.
The sar manual page has been updated.

Mail from Zhen Zhang (08/09/2010) <furykerry@gmail.com>
Hi ,

The current stable and development systat collect cpu frequency data
from /proc/cpuinfo, but currently cpuinfo "cpu Mhz" field report the
instant cpu frequency . From a system administrator point of view
however ,the preferred metric is  the average cpu frequency at
reporting interval . The average frequency can be obtain from
/sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state.

Will  the sysstat switch to average cpu frequency at next development version?

Thanks

Mail from Zhen Zhang (11/09/2010) <furykerry@gmail.com>
I want to measure the average cpu frequency of a machine which
probably is capable of dynamic adjusting frequency (DVFS). The average
of cpu frequency is an important metric to evaluate the power
consumption of a machine, and how hard the machine is working to serve
the requests. DVFS capability is starting to get wide adoption in the
server domain e.g. in recent Xeon.

The /proc/cpuinfo interface only record the instant cpu frequency
,however linux kernel or user frequncy governor can adjust cpu
frequency frequently , e.g. for default ondemand governor the
frequency is 10ms . Such interval is way to small comparing to usual
sysstat interval e.g 5min. So an accumulated value is needed .

cpufreq-stats  is a driver ( It seems had entered into kernel 2.6.11,
and its document is available at kernel 2.6.12,
http://lxr.linux.no/#linux+v2.6.12/Documentation/cpu-freq/cpufreq-stats.txt).
For recent ubuntu , cpufreq-stats and cpufreq driver is built into
kernel. The average frequency can be fetch as follow

:/sys/devices/system/cpu/cpu0/cpufreq/stats$ cat time_in_state
2001000 60803
2000000 5734
1600000 5996
1200000 8819
800000 205211

each line define a pair of frequency and its accumulated ticks since
reboot. sysstat can sample it and take the difference as the
accumulated ticks at the sampling interval , and calculated weighted
average cpu frequency.

The  cpufreq-stats do have some pitfall  which is addressed in patch
https://patchwork.kernel.org/patch/72488/).

Nevertheless its current form is already quite useful, I suggest
sysstat to utilize if available , and fall back to /proc/cpuinfo if
not.

Hopes to hear good news:)

thanks

19 files changed:
CHANGES
CREDITS
activity.c
common.h
man/sar.in
nls/sysstat.pot
pr_stats.c
pr_stats.h
prf_stats.c
prf_stats.h
rd_stats.c
rd_stats.h
sa.h
sa_common.c
sa_wrap.c
sadc.c
sar.c
xml/sysstat.dtd
xml/sysstat.xsd

diff --git a/CHANGES b/CHANGES
index 84280f4987a4019a4c9ba665a3730e427bf968c1..23866d8fd4a2861b5d59bffca33e7edcf4a02656 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -6,7 +6,8 @@ xxxx/xx/xx: Version 9.1.6 - Sebastien Godard (sysstat <at> orange.fr)
        * Added a new magical value for each activity in file.
          A format change can now hit only one activity instead of
          the whole file.
-       * Added hugepages utilization statistics to sar.
+       * Added CPU average clock frequency statistics to sar and sadc.
+       * Added hugepages utilization statistics to sar and sadc.
        * [Ivana Varekova]: Moved manual pages to $prefix/share/man
          instead of $prefix/man.
        * [Ivana Varekova]: Fixed configure's --disable-man-group option.
@@ -15,6 +16,7 @@ xxxx/xx/xx: Version 9.1.6 - Sebastien Godard (sysstat <at> orange.fr)
        * sar manual page updated.
        * DTD and XSD documents updated.
        * Made sysstat git aware.
+       * CREDITS file updated.
 
 2010/09/12: Version 9.1.5 - Sebastien Godard (sysstat <at> orange.fr)
        * Added voltage inputs statistics to sar and sadc.
diff --git a/CREDITS b/CREDITS
index 37a20d0dd296542b81f9b8e43ad8ce1c60dc250d..07cd3597a7f470cf5ffbdee6c8b1791c44e1e254 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -210,6 +210,7 @@ I would also thank the following people for their hints or bug reports
        Urban Widmark <urban@sve[...].se>
        Yu Yongcong <yuyc@cn.[...].com>
        Peter Zaitsev <pz@spy[...].ru>
+       Zhen Zhang <furykerry@gma[...].com>
 
 --     
 Sebastien Godard (sysstat <at> orange.fr) is the author and the current
index 23293da29785544c7af460d170e3aa3ebdb517fc..ac852c0e78a5a7946ce88874a95cdae103808113 100644 (file)
@@ -1006,7 +1006,7 @@ struct activity pwr_temp_act = {
 /* Voltage inputs */
 struct activity pwr_in_act = {
        .id             = A_PWR_IN,
-       .options        = AO_CLOSE_MARKUP,
+       .options        = AO_NULL,
        .magic          = ACTIVITY_MAGIC_BASE,
 #ifdef SOURCE_SADC
        .f_count        = wrap_get_in_nr,
@@ -1061,6 +1061,36 @@ struct activity huge_act = {
        .bitmap         = NULL
 };
 
+/* CPU weighted frequency */
+struct activity pwr_wghfreq_act = {
+       .id             = A_PWR_WGHFREQ,
+       .options        = AO_CLOSE_MARKUP,
+       .magic          = ACTIVITY_MAGIC_BASE,
+#ifdef SOURCE_SADC
+       .f_count        = wrap_get_cpu_nr,
+       .f_count2       = wrap_get_freq_nr,
+       .f_read         = wrap_read_time_in_state,
+#endif
+#ifdef SOURCE_SAR
+       .f_print        = print_pwr_wghfreq_stats,
+       .f_print_avg    = print_pwr_wghfreq_stats,
+#endif
+#ifdef SOURCE_SADF
+       .f_render       = render_pwr_wghfreq_stats,
+       .f_xml_print    = xml_print_pwr_wghfreq_stats,
+       .hdr_line       = "CPU;wghMHz",
+       .name           = "A_PWR_WGHFREQ",
+#endif
+       .nr             = -1,
+       .nr2            = 1,
+       .fsize          = STATS_PWR_WGHFREQ_SIZE,
+       .msize          = STATS_PWR_WGHFREQ_SIZE,
+       .opt_flags      = 0,
+       .buf            = {NULL, NULL, NULL},
+       .bitmap         = &cpu_bitmap
+};
+
+
 /*
  * Array of activities.
  */
@@ -1098,5 +1128,6 @@ struct activity *act[NR_ACT] = {
        &pwr_fan_act,
        &pwr_temp_act,
        &pwr_in_act,
-       &huge_act
+       &huge_act,
+       &pwr_wghfreq_act
 };
index f206e5f75fe0a260e450df689b1592f2a92e8a3e..4d2651e1bf22b1d0acf241ed85ea2cdd4cd6994c 100644 (file)
--- a/common.h
+++ b/common.h
 #define K_UTC  "UTC"
 
 /* Files */
-#define STAT           "/proc/stat"
-#define UPTIME         "/proc/uptime"
-#define PPARTITIONS    "/proc/partitions"
-#define DISKSTATS      "/proc/diskstats"
-#define INTERRUPTS     "/proc/interrupts"
-#define MEMINFO                "/proc/meminfo"
-#define SYSFS_BLOCK    "/sys/block"
-#define SYSFS_DEVCPU   "/sys/devices/system/cpu"
-#define S_STAT         "stat"
-#define DEVMAP_DIR     "/dev/mapper"
+#define STAT                   "/proc/stat"
+#define UPTIME                 "/proc/uptime"
+#define PPARTITIONS            "/proc/partitions"
+#define DISKSTATS              "/proc/diskstats"
+#define INTERRUPTS             "/proc/interrupts"
+#define MEMINFO                        "/proc/meminfo"
+#define SYSFS_BLOCK            "/sys/block"
+#define SYSFS_DEVCPU           "/sys/devices/system/cpu"
+#define SYSFS_TIME_IN_STATE    "cpufreq/stats/time_in_state"
+#define S_STAT                 "stat"
+#define DEVMAP_DIR             "/dev/mapper"
 
 #define MAX_FILE_LEN   256
 #define MAX_PF_NAME    1024
index 06643bf3d5d335b77107b5b5888b911823b3a05f..c648f8cdeb8726df7af08073fca55d25c23a69c9 100644 (file)
@@ -1,4 +1,4 @@
-.TH SAR 1 "SEPTEMBER 2010" Linux "Linux User's Manual" -*- nroff -*-
+.TH SAR 1 "OCTOBER 2010" Linux "Linux User's Manual" -*- nroff -*-
 .SH NAME
 sar \- Collect, report, or save system activity information.
 .SH SYNOPSIS
@@ -374,19 +374,20 @@ Note that these statistics depend on sadc option "-S POWER" to be collected.
 Possible keywords are
 .BR CPU ,
 .BR FAN ,
+.BR FREQ ,
 .BR IN
 and
 .BR TEMP .
 
 With the
 .B CPU
-keyword, statistics about CPU clock frequency are reported.
+keyword, statistics about CPU are reported.
 The following value is displayed:
 
 .B MHz
 .RS
 .RS
-CPU clock frequency in MHz.
+Instantaneous CPU clock frequency in MHz.
 .RE
 
 With the
@@ -410,6 +411,18 @@ and its low limit (fan_min).
 Sensor device name.
 .RE
 
+With the
+.B FREQ
+keyword, statistics about CPU clock frequency are reported.
+The following value is displayed:
+
+.B wghMHz
+.RS
+Weighted average CPU clock frequency in MHz.
+Note that the cpufreq-stats driver must be compiled in the
+kernel for this option to work.
+.RE
+
 With the
 .B IN
 keyword, statistics about voltage inputs are reported.
index 0693f33a3b88d7e0665e226ba2471136da98600d..9a22880a026740e4d8a3ec5b1ed9fdfe65f2dcd5 100644 (file)
@@ -8,7 +8,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: sysstat <at> orange.fr\n"
-"POT-Creation-Date: 2010-09-18 15:03+0200\n"
+"POT-Creation-Date: 2010-10-23 15:32+0200\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"
@@ -34,8 +34,8 @@ msgstr ""
 msgid "sysstat version %s\n"
 msgstr ""
 
-#: ioconf.c:490 rd_stats.c:72 rd_stats.c:1848 sa_common.c:1052 sadc.c:593
-#: sadc.c:602 sadc.c:662
+#: ioconf.c:490 rd_stats.c:72 rd_stats.c:2145 sa_common.c:1057 sadc.c:607
+#: sadc.c:616 sadc.c:676
 #, c-format
 msgid "Cannot open %s: %s\n"
 msgstr ""
@@ -69,7 +69,7 @@ msgid ""
 "ALL } ] [ -V ]\n"
 msgstr ""
 
-#: mpstat.c:530 pidstat.c:1806 sar.c:361
+#: mpstat.c:530 pidstat.c:1806 sar.c:362
 msgid "Average:"
 msgstr ""
 
@@ -87,12 +87,12 @@ msgid ""
 "[ -p { <pid> [,...] | SELF | ALL } ] [ -T { TASK | CHILD | ALL } ]\n"
 msgstr ""
 
-#: pidstat.c:199 sar.c:979
+#: pidstat.c:199 sar.c:989
 #, c-format
 msgid "Requested activities not available\n"
 msgstr ""
 
-#: rd_stats.c:1894
+#: rd_stats.c:2191
 #, c-format
 msgid "Cannot handle so many processors!\n"
 msgstr ""
@@ -123,7 +123,7 @@ msgid ""
 "Current sysstat version can no longer read the format of this file (%#x)\n"
 msgstr ""
 
-#: sa_common.c:1135
+#: sa_common.c:1164
 #, c-format
 msgid "Requested activities not available in file %s\n"
 msgstr ""
@@ -141,17 +141,17 @@ msgid ""
 "[ -S { INT | DISK | IPV6 | POWER | SNMP | XDISK | ALL | XALL } ]\n"
 msgstr ""
 
-#: sadc.c:206
+#: sadc.c:207
 #, c-format
 msgid "Cannot write data to system activity file: %s\n"
 msgstr ""
 
-#: sadc.c:480
+#: sadc.c:494
 #, c-format
 msgid "Cannot write system activity file header: %s\n"
 msgstr ""
 
-#: sadc.c:756
+#: sadc.c:775
 #, c-format
 msgid "Cannot append data to that file (%s)\n"
 msgstr ""
@@ -190,6 +190,11 @@ msgstr ""
 msgid "List of activities:\n"
 msgstr ""
 
+#: sadf.c:638
+#, c-format
+msgid "\t[Unknown activity format]"
+msgstr ""
+
 #: sar.c:104
 #, c-format
 msgid ""
@@ -240,13 +245,14 @@ msgid ""
 "\t-m { <keyword> [,...] | ALL }\n"
 "\t\tPower management statistics\n"
 "\t\tKeywords are:\n"
-"\t\tCPU\tCPU clock frequency\n"
+"\t\tCPU\tCPU instantaneous clock frequency\n"
 "\t\tFAN\tFans speed\n"
+"\t\tFREQ\tCPU average clock frequency\n"
 "\t\tIN\tVoltage inputs\n"
 "\t\tTEMP\tDevices temperature\n"
 msgstr ""
 
-#: sar.c:140
+#: sar.c:141
 #, c-format
 msgid ""
 "\t-n { <keyword> [,...] | ALL }\n"
@@ -272,84 +278,84 @@ msgid ""
 "\t\tUDP6\tUDP traffic\t(v6)\n"
 msgstr ""
 
-#: sar.c:161
+#: sar.c:162
 #, c-format
 msgid "\t-q\tQueue length and load average statistics\n"
 msgstr ""
 
-#: sar.c:162
+#: sar.c:163
 #, c-format
 msgid "\t-r\tMemory utilization statistics\n"
 msgstr ""
 
-#: sar.c:163
+#: sar.c:164
 #, c-format
 msgid "\t-R\tMemory statistics\n"
 msgstr ""
 
-#: sar.c:164
+#: sar.c:165
 #, c-format
 msgid "\t-S\tSwap space utilization statistics\n"
 msgstr ""
 
-#: sar.c:165
+#: sar.c:166
 #, c-format
 msgid ""
 "\t-u [ ALL ]\n"
 "\t\tCPU utilization statistics\n"
 msgstr ""
 
-#: sar.c:167
+#: sar.c:168
 #, c-format
 msgid "\t-v\tKernel table statistics\n"
 msgstr ""
 
-#: sar.c:168
+#: sar.c:169
 #, c-format
 msgid "\t-w\tTask creation and system switching statistics\n"
 msgstr ""
 
-#: sar.c:169
+#: sar.c:170
 #, c-format
 msgid "\t-W\tSwapping statistics\n"
 msgstr ""
 
-#: sar.c:170
+#: sar.c:171
 #, c-format
 msgid "\t-y\tTTY device statistics\n"
 msgstr ""
 
-#: sar.c:213
+#: sar.c:214
 #, c-format
 msgid "End of data collecting unexpected\n"
 msgstr ""
 
-#: sar.c:781
+#: sar.c:783
 #, c-format
 msgid "Invalid data format\n"
 msgstr ""
 
-#: sar.c:785
+#: sar.c:787
 #, c-format
 msgid "Using a wrong data collector from a different sysstat version\n"
 msgstr ""
 
-#: sar.c:805
+#: sar.c:811
 #, c-format
 msgid "Inconsistent input data\n"
 msgstr ""
 
-#: sar.c:1226
+#: sar.c:1236
 #, c-format
 msgid "-f and -o options are mutually exclusive\n"
 msgstr ""
 
-#: sar.c:1232
+#: sar.c:1242
 #, c-format
 msgid "Not reading from a system activity file (use -f option)\n"
 msgstr ""
 
-#: sar.c:1333
+#: sar.c:1343
 #, c-format
 msgid "Cannot find the data collector (%s)\n"
 msgstr ""
index 285055b5e51157adcce44c63bc97f940ce70dcea..6438ab32d9968e35a6b580bc73faaa7830fd0fd1 100644 (file)
@@ -2217,3 +2217,81 @@ __print_funct_t print_avg_huge_stats(struct activity *a, int prev, int curr,
 {
        stub_print_huge_stats(a, prev, curr, itv, TRUE);
 }
+
+/*
+ ***************************************************************************
+ * Display CPU weighted frequency statistics. This function is used to
+ * display instantaneous and average statistics.
+ *
+ * IN:
+ * @a          Activity structure with statistics.
+ * @prev       Index in array where stats used as reference are.
+ * @curr       Index in array for current sample statistics.
+ * @dispavg    True if displaying average statistics.
+ ***************************************************************************
+ */
+void print_pwr_wghfreq_stats(struct activity *a, int prev, int curr,
+                            unsigned long long itv)
+{
+       int i, k;
+       struct stats_pwr_wghfreq *spc, *spp, *spc_k, *spp_k;
+       unsigned long long tis, tisfreq;
+
+       if (dis) {
+               printf("\n%-11s     CPU    wghMHz\n",
+                      timestamp[!curr]);
+       }
+
+       for (i = 0; (i < a->nr) && (i < a->bitmap->b_size + 1); i++) {
+
+               /*
+                * The size of a->buf[...] CPU structure may be different from the default
+                * sizeof(struct stats_pwr_wghfreq) value if data have been read from a file!
+                * That's why we don't use a syntax like:
+                * spc = (struct stats_pwr_wghfreq *) a->buf[...] + i;
+                */
+               spc = (struct stats_pwr_wghfreq *) ((char *) a->buf[curr] + i * a->msize * a->nr2);
+               spp = (struct stats_pwr_wghfreq *) ((char *) a->buf[prev] + i * a->msize * a->nr2);
+
+               /*
+                * Note: a->nr is in [1, NR_CPUS + 1].
+                * Bitmap size is provided for (NR_CPUS + 1) CPUs.
+                * Anyway, NR_CPUS may vary between the version of sysstat
+                * used by sadc to create a file, and the version of sysstat
+                * used by sar to read it...
+                */
+
+               /* Should current CPU (including CPU "all") be displayed? */
+               if (a->bitmap->b_array[i >> 3] & (1 << (i & 0x07))) {
+
+                       /* Yes: Display it */
+                       printf("%-11s", timestamp[curr]);
+
+                       if (!i) {
+                               /* This is CPU "all" */
+                               printf("     all");
+                       }
+                       else {
+                               printf("     %3d", i - 1);
+                       }
+
+                       tisfreq = 0;
+                       tis = 0;
+
+                       for (k = 0; k < a->nr2; k++) {
+
+                               spc_k = (struct stats_pwr_wghfreq *) ((char *) spc + k * a->msize);
+                               if (!spc_k->freq)
+                                       break;
+                               spp_k = (struct stats_pwr_wghfreq *) ((char *) spp + k * a->msize);
+
+                               tisfreq += (spc_k->freq / 1000) *
+                                          (spc_k->time_in_state - spp_k->time_in_state);
+                               tis     += (spc_k->time_in_state - spp_k->time_in_state);
+                       }
+
+                       /* Display weighted frequency for current CPU */
+                       printf(" %9.2f\n", tis ? ((double) tisfreq) / tis : 0.0);
+               }
+       }
+}
index f847ee02298a8bf769e35117d513d7b46fbe4e87..f126c8154e7fa22025e5d73a8933b21f95ad0519 100644 (file)
@@ -84,6 +84,8 @@ extern __print_funct_t print_pwr_in_stats
        (struct activity *, int, int, unsigned long long);
 extern __print_funct_t print_huge_stats
        (struct activity *, int, int, unsigned long long);
+extern __print_funct_t print_pwr_wghfreq_stats
+       (struct activity *, int, int, unsigned long long);
 
 /* Functions used to display average statistics */
 extern __print_funct_t print_avg_memory_stats
index 59dbf68891dcbdcfab5136c3ca62816c8db1fce0..e79fb306be31f9d1448eb5101233ac954ec7b22a 100644 (file)
@@ -2396,6 +2396,70 @@ __print_funct_t render_huge_stats(struct activity *a, int isdb, char *pre,
               0.0);
 }
 
+/*
+ ***************************************************************************
+ * Display weighted CPU frequency statistics in selected format.
+ *
+ * IN:
+ * @a          Activity structure with statistics.
+ * @isdb       Flag, true if db printing, false if ppc printing.
+ * @pre                Prefix string for output entries
+ * @curr       Index in array for current sample statistics.
+ * @itv                Interval of time in jiffies.
+ ***************************************************************************
+ */
+__print_funct_t render_pwr_wghfreq_stats(struct activity *a, int isdb, char *pre,
+                                        int curr, unsigned long long itv)
+{
+       int i, k;
+       struct stats_pwr_wghfreq *spc, *spp, *spc_k, *spp_k;
+       unsigned long long tis, tisfreq;
+       int pt_newlin
+               = (DISPLAY_HORIZONTALLY(flags) ? PT_NOFLAG : PT_NEWLIN);
+
+       for (i = 0; (i < a->nr) && (i < a->bitmap->b_size + 1); i++) {
+
+               spc = (struct stats_pwr_wghfreq *) ((char *) a->buf[curr]  + i * a->msize * a->nr2);
+               spp = (struct stats_pwr_wghfreq *) ((char *) a->buf[!curr] + i * a->msize * a->nr2);
+
+               /* Should current CPU (including CPU "all") be displayed? */
+               if (a->bitmap->b_array[i >> 3] & (1 << (i & 0x07))) {
+
+                       /* Yes... */
+                       tisfreq = 0;
+                       tis = 0;
+
+                       for (k = 0; k < a->nr2; k++) {
+
+                               spc_k = (struct stats_pwr_wghfreq *) ((char *) spc + k * a->msize);
+                               if (!spc_k->freq)
+                                       break;
+                               spp_k = (struct stats_pwr_wghfreq *) ((char *) spp + k * a->msize);
+
+                               tisfreq += (spc_k->freq / 1000) *
+                                          (spc_k->time_in_state - spp_k->time_in_state);
+                               tis     += (spc_k->time_in_state - spp_k->time_in_state);
+                       }
+                       
+                       if (!i) {
+                               /* This is CPU "all" */
+                               render(isdb, pre, pt_newlin,
+                                      "all\twghMHz",
+                                      "-1", NULL,
+                                      NOVAL,
+                                      tis ? ((double) tisfreq) / tis : 0.0);
+                       }
+                       else {
+                               render(isdb, pre, pt_newlin,
+                                      "cpu%d\twghMHz",
+                                      "%d", cons(iv, i - 1, NOVAL),
+                                      NOVAL,
+                                      tis ? ((double) tisfreq) / tis : 0.0);
+                       }
+               }
+       }
+}
+
 /*
  ***************************************************************************
  * Print tabulations
@@ -4230,3 +4294,78 @@ __print_funct_t xml_print_huge_stats(struct activity *a, int curr, int tab,
 
        xprintf(tab, "</hugepages>");
 }
+
+/*
+ ***************************************************************************
+ * Display weighted CPU frequency statistics in XML.
+ *
+ * IN:
+ * @a          Activity structure with statistics.
+ * @curr       Index in array for current sample statistics.
+ * @tab                Indentation in XML output.
+ * @itv                Interval of time in jiffies.
+ ***************************************************************************
+ */
+__print_funct_t xml_print_pwr_wghfreq_stats(struct activity *a, int curr, int tab,
+                                           unsigned long long itv)
+{
+       int i, k;
+       struct stats_pwr_wghfreq *spc, *spp, *spc_k, *spp_k;
+       unsigned long long tis, tisfreq;
+       char cpuno[8];
+
+       if (!IS_SELECTED(a->options) || (a->nr <= 0))
+               goto close_xml_markup;
+
+       xml_markup_power_management(tab, OPEN_XML_MARKUP);
+       tab++;
+
+       xprintf(tab++, "<cpu-weighted-frequency unit=\"MHz\">");
+
+       for (i = 0; (i < a->nr) && (i < a->bitmap->b_size + 1); i++) {
+
+               spc = (struct stats_pwr_wghfreq *) ((char *) a->buf[curr]  + i * a->msize * a->nr2);
+               spp = (struct stats_pwr_wghfreq *) ((char *) a->buf[!curr] + i * a->msize * a->nr2);
+
+               /* Should current CPU (including CPU "all") be displayed? */
+               if (a->bitmap->b_array[i >> 3] & (1 << (i & 0x07))) {
+
+                       /* Yes... */
+                       tisfreq = 0;
+                       tis = 0;
+
+                       for (k = 0; k < a->nr2; k++) {
+
+                               spc_k = (struct stats_pwr_wghfreq *) ((char *) spc + k * a->msize);
+                               if (!spc_k->freq)
+                                       break;
+                               spp_k = (struct stats_pwr_wghfreq *) ((char *) spp + k * a->msize);
+
+                               tisfreq += (spc_k->freq / 1000) *
+                                          (spc_k->time_in_state - spp_k->time_in_state);
+                               tis     += (spc_k->time_in_state - spp_k->time_in_state);
+                       }
+
+                       if (!i) {
+                               /* This is CPU "all" */
+                               strcpy(cpuno, "all");
+                       }
+                       else {
+                               sprintf(cpuno, "%d", i - 1);
+                       }
+
+                       xprintf(tab, "<cpuwfreq number=\"%s\" "
+                               "weighted-frequency=\"%.2f\"/>",
+                               cpuno,
+                               tis ? ((double) tisfreq) / tis : 0.0);
+               }
+       }
+
+       xprintf(--tab, "</cpu-weighted-frequency>");
+       tab--;
+
+close_xml_markup:
+       if (CLOSE_MARKUP(a->options)) {
+               xml_markup_power_management(tab, CLOSE_XML_MARKUP);
+       }
+}
index 71dde5726423cacddc730ef74d8a9226816c8348..8117bff3a8fc834d3246d7efd929f7e5e5f79bfa 100644 (file)
@@ -111,6 +111,8 @@ extern __print_funct_t render_pwr_in_stats
        (struct activity *, int, char *, int, unsigned long long);
 extern __print_funct_t render_huge_stats
        (struct activity *, int, char *, int, unsigned long long);
+extern __print_funct_t render_pwr_wghfreq_stats
+       (struct activity *, int, char *, int, unsigned long long);
 
 /* Functions used to display statistics in XML */
 extern void xprintf
@@ -183,5 +185,7 @@ extern __print_funct_t xml_print_pwr_in_stats
        (struct activity *, int, int, unsigned long long);
 extern __print_funct_t xml_print_huge_stats
        (struct activity *, int, int, unsigned long long);
+extern __print_funct_t xml_print_pwr_wghfreq_stats
+       (struct activity *, int, int, unsigned long long);
 
 #endif /* _PRF_STATS_H */
index bf70da3ab486bac679930864ecb0c87367fcd002..59f90aa8d23a63fc12e14c0b35718ed3c56190e9 100644 (file)
@@ -1571,6 +1571,319 @@ void read_net_udp6(struct stats_net_udp6 *st_net_udp6)
        fclose(fp);
 }
 
+/*
+ ***************************************************************************
+ * Read CPU frequency statistics.
+ *
+ * IN:
+ * @st_pwr_cpufreq     Structure where stats will be saved.
+ * @nbr                        Total number of CPU (including cpu "all").
+ *
+ * OUT:
+ * @st_pwr_cpufreq     Structure with statistics.
+ ***************************************************************************
+ */
+void read_cpuinfo(struct stats_pwr_cpufreq *st_pwr_cpufreq, int nbr)
+{
+       FILE *fp;
+       struct stats_pwr_cpufreq *st_pwr_cpufreq_i;
+       char line[1024];
+       int proc_nb = 0, nr = 0;
+       unsigned int ifreq, dfreq;
+       
+       if ((fp = fopen(CPUINFO, "r")) == NULL)
+               return;
+       
+       st_pwr_cpufreq->cpufreq = 0;
+       
+       while (fgets(line, 1024, fp) != NULL) {
+               
+               if (!strncmp(line, "processor\t", 10)) {
+                       sscanf(strchr(line, ':') + 1, "%d", &proc_nb);
+               }
+               
+               else if (!strncmp(line, "cpu MHz\t", 8)) {
+                       sscanf(strchr(line, ':') + 1, "%u.%u", &ifreq, &dfreq);
+                       
+                       if (proc_nb < (nbr - 1)) {                      /* FIXME: quelle reaction pour un kernel non SMP 1 proc? */
+                               /* Save current CPU frequency */
+                               st_pwr_cpufreq_i = st_pwr_cpufreq + proc_nb + 1;
+                               st_pwr_cpufreq_i->cpufreq = ifreq * 100 + dfreq / 10;
+                               
+                               /* Also save it to compute an average CPU frequency */
+                               st_pwr_cpufreq->cpufreq += st_pwr_cpufreq_i->cpufreq;
+                               nr++;
+                       }
+               }
+       }
+       
+       fclose(fp);
+       
+       if (nr) {
+               /* Compute average CPU frequency for this machine */
+               st_pwr_cpufreq->cpufreq /= nr;
+       }
+}
+
+/*
+ ***************************************************************************
+ * Read fan statistics.
+ *
+ * IN:
+ * @st_pwr_fan Structure where stats will be saved.
+ * @nbr                Total number of fans.
+ *
+ * OUT:
+ * @st_pwr_fan Structure with statistics.
+ ***************************************************************************
+ */
+void read_fan(struct stats_pwr_fan *st_pwr_fan, int nbr)
+{
+#ifdef HAVE_SENSORS
+       int count = 0;
+       const sensors_chip_name *chip;
+       const sensors_feature *feature;
+       const sensors_subfeature *sub;
+       struct stats_pwr_fan *st_pwr_fan_i;
+       int chip_nr = 0;
+       int i, j;
+
+       memset(st_pwr_fan, 0, STATS_PWR_FAN_SIZE);
+       int err = 0;
+
+       while ((chip = sensors_get_detected_chips(NULL, &chip_nr))) {
+               i = 0;
+               while ((feature = sensors_get_features(chip, &i))) {
+                       if ((feature->type == SENSORS_FEATURE_FAN) && (count < nbr)) {
+                               j = 0;
+                               st_pwr_fan_i = st_pwr_fan + count;
+                               sensors_snprintf_chip_name(st_pwr_fan_i->device, MAX_SENSORS_DEV_LEN, chip);
+                               
+                               while ((sub = sensors_get_all_subfeatures(chip, feature, &j))) {
+                                       if ((sub->type == SENSORS_SUBFEATURE_FAN_INPUT) &&
+                                           (sub->flags & SENSORS_MODE_R)) {
+                                               if ((err = sensors_get_value(chip, sub->number, &st_pwr_fan_i->rpm))) {
+                                                       st_pwr_fan_i->rpm = 0;
+                                               }
+                                       }
+                                       else if ((sub->type == SENSORS_SUBFEATURE_FAN_MIN)) {
+                                               if ((err = sensors_get_value(chip, sub->number, &st_pwr_fan_i->rpm_min))) {
+                                                       st_pwr_fan_i->rpm_min = 0;
+                                               }
+                                       }
+                               }
+                               count++;
+                       }
+               }
+       }
+#endif /* HAVE_SENSORS */
+}
+
+/*
+ ***************************************************************************
+ * Read device temperature statistics.
+ *
+ * IN:
+ * @st_pwr_temp        Structure where stats will be saved.
+ * @nbr                Total number of fans.
+ *
+ * OUT:
+ * @st_pwr_temp        Structure with statistics.
+ ***************************************************************************
+ */
+void read_temp(struct stats_pwr_temp *st_pwr_temp, int nbr)
+{
+#ifdef HAVE_SENSORS
+       int count = 0;
+       const sensors_chip_name *chip;
+       const sensors_feature *feature;
+       const sensors_subfeature *sub;
+       struct stats_pwr_temp *st_pwr_temp_i;
+       int chip_nr = 0;
+       int i, j;
+
+       memset(st_pwr_temp, 0, STATS_PWR_TEMP_SIZE);
+       int err = 0;
+
+       while ((chip = sensors_get_detected_chips(NULL, &chip_nr))) {
+               i = 0;
+               while ((feature = sensors_get_features(chip, &i))) {
+                       if ((feature->type == SENSORS_FEATURE_TEMP) && (count < nbr)) {
+                               j = 0;
+                               st_pwr_temp_i = st_pwr_temp + count;
+                               sensors_snprintf_chip_name(st_pwr_temp_i->device, MAX_SENSORS_DEV_LEN, chip);
+                               
+                               while ((sub = sensors_get_all_subfeatures(chip, feature, &j))) {
+                                       if ((sub->type == SENSORS_SUBFEATURE_TEMP_INPUT) &&
+                                               (sub->flags & SENSORS_MODE_R)) {
+                                               if ((err = sensors_get_value(chip, sub->number, &st_pwr_temp_i->temp))) {
+                                                       st_pwr_temp_i->temp = 0;
+                                               }
+                                       }
+                                       else if ((sub->type == SENSORS_SUBFEATURE_TEMP_MIN)) {
+                                               if ((err = sensors_get_value(chip, sub->number, &st_pwr_temp_i->temp_min))) {
+                                                       st_pwr_temp_i->temp_min = 0;
+                                               }
+                                       }
+                                       else if ((sub->type == SENSORS_SUBFEATURE_TEMP_MAX)) {
+                                               if ((err = sensors_get_value(chip, sub->number, &st_pwr_temp_i->temp_max))) {
+                                                       st_pwr_temp_i->temp_max = 0;
+                                               }
+                                       }
+                               }
+                               count++;
+                       }
+               }
+       }
+#endif /* HAVE_SENSORS */
+}
+
+/*
+ ***************************************************************************
+ * Read voltage inputs statistics.
+ *
+ * IN:
+ * @st_pwr_in  Structure where stats will be saved.
+ * @nbr                Total number of voltage inputs.
+ *
+ * OUT:
+ * @st_pwr_in  Structure with statistics.
+ ***************************************************************************
+ */
+void read_in(struct stats_pwr_in *st_pwr_in, int nbr)
+{
+#ifdef HAVE_SENSORS
+       int count = 0;
+       const sensors_chip_name *chip;
+       const sensors_feature *feature;
+       const sensors_subfeature *sub;
+       struct stats_pwr_in *st_pwr_in_i;
+       int chip_nr = 0;
+       int i, j;
+
+       memset(st_pwr_in, 0, STATS_PWR_IN_SIZE);
+       int err = 0;
+
+       while ((chip = sensors_get_detected_chips(NULL, &chip_nr))) {
+               i = 0;
+               while ((feature = sensors_get_features(chip, &i))) {
+                       if ((feature->type == SENSORS_FEATURE_IN) && (count < nbr)) {
+                               j = 0;
+                               st_pwr_in_i = st_pwr_in + count;
+                               sensors_snprintf_chip_name(st_pwr_in_i->device, MAX_SENSORS_DEV_LEN, chip);
+
+                               while ((sub = sensors_get_all_subfeatures(chip, feature, &j))) {
+                                       if ((sub->type == SENSORS_SUBFEATURE_IN_INPUT) &&
+                                               (sub->flags & SENSORS_MODE_R)) {
+                                               if ((err = sensors_get_value(chip, sub->number, &st_pwr_in_i->in))) {
+                                                       st_pwr_in_i->in = 0;
+                                               }
+                                       }
+                                       else if ((sub->type == SENSORS_SUBFEATURE_IN_MIN)) {
+                                               if ((err = sensors_get_value(chip, sub->number, &st_pwr_in_i->in_min))) {
+                                                       st_pwr_in_i->in_min = 0;
+                                               }
+                                       }
+                                       else if ((sub->type == SENSORS_SUBFEATURE_IN_MAX)) {
+                                               if ((err = sensors_get_value(chip, sub->number, &st_pwr_in_i->in_max))) {
+                                                       st_pwr_in_i->in_max = 0;
+                                               }
+                                       }
+                               }
+                               count++;
+                       }
+               }
+       }
+#endif /* HAVE_SENSORS */
+}
+
+/*
+ ***************************************************************************
+ * Read hugepages statistics from /proc/meminfo.
+ *
+ * IN:
+ * @st_huge    Structure where stats will be saved.
+ *
+ * OUT:
+ * @st_huge    Structure with statistics.
+ ***************************************************************************
+ */
+void read_meminfo_huge(struct stats_huge *st_huge)
+{
+       FILE *fp;
+       char line[128];
+       unsigned long szhkb = 0;
+
+       if ((fp = fopen(MEMINFO, "r")) == NULL)
+               return;
+
+       while (fgets(line, 128, fp) != NULL) {
+
+               if (!strncmp(line, "HugePages_Total:", 16)) {
+                       /* Read the total number of huge pages */
+                       sscanf(line + 16, "%lu", &st_huge->tlhkb);
+               }
+               else if (!strncmp(line, "HugePages_Free:", 15)) {
+                       /* Read the number of free huge pages */
+                       sscanf(line + 15, "%lu", &st_huge->frhkb);
+               }
+               else if (!strncmp(line, "Hugepagesize:", 13)) {
+                       /* Read the default size of a huge page in kB */
+                       sscanf(line + 13, "%lu", &szhkb);
+               }
+       }
+
+       fclose(fp);
+
+       /* We want huge pages stats in kB and not expressed in a number of pages */
+       st_huge->tlhkb *= szhkb;
+       st_huge->frhkb *= szhkb;
+}
+
+/*
+ ***************************************************************************
+ * Read CPU average frequencies statistics.
+ *
+ * IN:
+ * @st_pwr_wghfreq     Structure where stats will be saved.
+ * @cpu_nr             CPU number for which time_in_state date will be read.
+ * @nbr                        Total number of states (frequencies).
+ *
+ * OUT:
+ * @st_pwr_wghfreq     Structure with statistics.
+ ***************************************************************************
+ */
+void read_time_in_state(struct stats_pwr_wghfreq *st_pwr_wghfreq, int cpu_nr, int nbr)
+{
+       FILE *fp;
+       struct stats_pwr_wghfreq *st_pwr_wghfreq_j;
+       char filename[MAX_PF_NAME];
+       char line[128];
+       int j = 0;
+       unsigned long freq;
+       unsigned long long time_in_state;
+
+       snprintf(filename, MAX_PF_NAME, "%s/cpu%d/%s",
+                SYSFS_DEVCPU, cpu_nr, SYSFS_TIME_IN_STATE);
+       if ((fp = fopen(filename, "r")) == NULL)
+               return;
+
+       while (fgets(line, 128, fp) != NULL) {
+
+               sscanf(line, "%lu %llu", &freq, &time_in_state);
+
+               if (j < nbr) {
+                       /* Save current frequency and time */
+                       st_pwr_wghfreq_j = st_pwr_wghfreq + j;
+                       st_pwr_wghfreq_j->freq = freq;
+                       st_pwr_wghfreq_j->time_in_state = time_in_state;
+                       j++;
+               }
+       }
+
+       fclose(fp);
+}
+
 /*
  ***************************************************************************
  * Read machine uptime, independently of the number of processors.
@@ -1592,7 +1905,8 @@ void read_uptime(unsigned long long *uptime)
                return;
 
        sscanf(line, "%lu.%lu", &up_sec, &up_cent);
-       *uptime = (unsigned long long) up_sec * HZ + (unsigned long long) up_cent * HZ / 100;
+       *uptime = (unsigned long long) up_sec * HZ +
+                 (unsigned long long) up_cent * HZ / 100;
 
        fclose(fp);
 
@@ -1615,11 +1929,11 @@ int get_irq_nr(void)
 
        if ((fp = fopen(STAT, "r")) == NULL)
                return 0;
-       
+
        while (fgets(line, 8192, fp) != NULL) {
 
                if (!strncmp(line, "intr ", 5)) {
-                       
+
                        while (pos < strlen(line)) {
                                in++;
                                pos += strcspn(line + pos + 1, " ") + 1;
@@ -1628,7 +1942,7 @@ int get_irq_nr(void)
        }
 
        fclose(fp);
-       
+
        return in;
 }
 
@@ -1758,7 +2072,7 @@ int get_diskstats_dev_nr(int count_part, int only_used_dev)
 int get_disk_nr(unsigned int f)
 {
        int disk_nr;
-       
+
        /*
         * Partitions are taken into account by sar -d only with
         * kernels 2.6.25 and later.
@@ -1917,7 +2231,7 @@ int get_irqcpu_nr(char *file, int max_nr_irqcpu, int cpu_nr)
        }
 
        fclose(fp);
-       
+
        if (line) {
                free(line);
        }
@@ -1925,60 +2239,6 @@ int get_irqcpu_nr(char *file, int max_nr_irqcpu, int cpu_nr)
        return irq;
 }
 
-/*
- ***************************************************************************
- * Read CPU frequency statistics.
- *
- * IN:
- * @st_pwr_cpufreq     Structure where stats will be saved.
- * @nbr                        Total number of CPU (including cpu "all").
- *
- * OUT:
- * @st_pwr_cpufreq     Structure with statistics.
- ***************************************************************************
- */
-void read_cpuinfo(struct stats_pwr_cpufreq *st_pwr_cpufreq, int nbr)
-{
-       FILE *fp;
-       struct stats_pwr_cpufreq *st_pwr_cpufreq_i;
-       char line[1024];
-       int proc_nb = 0, nr = 0;
-       unsigned int ifreq, dfreq;
-       
-       if ((fp = fopen(CPUINFO, "r")) == NULL)
-               return;
-       
-       st_pwr_cpufreq->cpufreq = 0;
-       
-       while (fgets(line, 1024, fp) != NULL) {
-               
-               if (!strncmp(line, "processor\t", 10)) {
-                       sscanf(strchr(line, ':') + 1, "%d", &proc_nb);
-               }
-               
-               else if (!strncmp(line, "cpu MHz\t", 8)) {
-                       sscanf(strchr(line, ':') + 1, "%u.%u", &ifreq, &dfreq);
-                       
-                       if (proc_nb < (nbr - 1)) {
-                               /* Save current CPU frequency */
-                               st_pwr_cpufreq_i = st_pwr_cpufreq + proc_nb + 1;
-                               st_pwr_cpufreq_i->cpufreq = ifreq * 100 + dfreq / 10;
-                               
-                               /* Also save it to compute an average CPU frequency */
-                               st_pwr_cpufreq->cpufreq += st_pwr_cpufreq_i->cpufreq;
-                               nr++;
-                       }
-               }
-       }
-       
-       fclose(fp);
-       
-       if (nr) {
-               /* Compute average CPU frequency for this machine */
-               st_pwr_cpufreq->cpufreq /= nr;
-       }
-}
-
 #ifdef HAVE_SENSORS
 /*
  ***************************************************************************
@@ -2028,60 +2288,6 @@ int get_fan_nr(void)
 #endif /* HAVE_SENSORS */
 }
 
-/*
- ***************************************************************************
- * Read fan statistics.
- *
- * IN:
- * @st_pwr_fan Structure where stats will be saved.
- * @nbr                Total number of fans.
- *
- * OUT:
- * @st_pwr_fan Structure with statistics.
- ***************************************************************************
- */
-void read_fan(struct stats_pwr_fan *st_pwr_fan, int nbr)
-{
-#ifdef HAVE_SENSORS
-       int count = 0;
-       const sensors_chip_name *chip;
-       const sensors_feature *feature;
-       const sensors_subfeature *sub;
-       struct stats_pwr_fan *st_pwr_fan_i;
-       int chip_nr = 0;
-       int i, j;
-
-       memset(st_pwr_fan, 0, STATS_PWR_FAN_SIZE);
-       int err = 0;
-
-       while ((chip = sensors_get_detected_chips(NULL, &chip_nr))) {
-               i = 0;
-               while ((feature = sensors_get_features(chip, &i))) {
-                       if ((feature->type == SENSORS_FEATURE_FAN) && (count < nbr)) {
-                               j = 0;
-                               st_pwr_fan_i = st_pwr_fan + count;
-                               sensors_snprintf_chip_name(st_pwr_fan_i->device, MAX_SENSORS_DEV_LEN, chip);
-                               
-                               while ((sub = sensors_get_all_subfeatures(chip, feature, &j))) {
-                                       if ((sub->type == SENSORS_SUBFEATURE_FAN_INPUT) &&
-                                           (sub->flags & SENSORS_MODE_R)) {
-                                               if ((err = sensors_get_value(chip, sub->number, &st_pwr_fan_i->rpm))) {
-                                                       st_pwr_fan_i->rpm = 0;
-                                               }
-                                       }
-                                       else if ((sub->type == SENSORS_SUBFEATURE_FAN_MIN)) {
-                                               if ((err = sensors_get_value(chip, sub->number, &st_pwr_fan_i->rpm_min))) {
-                                                       st_pwr_fan_i->rpm_min = 0;
-                                               }
-                                       }
-                               }
-                               count++;
-                       }
-               }
-       }
-#endif /* HAVE_SENSORS */
-}
-
 /*
  ***************************************************************************
  * Count the number of temperature sensors on the machine.
@@ -2100,65 +2306,6 @@ int get_temp_nr(void)
 
 }
 
-/*
- ***************************************************************************
- * Read device temperature statistics.
- *
- * IN:
- * @st_pwr_temp        Structure where stats will be saved.
- * @nbr                Total number of fans.
- *
- * OUT:
- * @st_pwr_temp        Structure with statistics.
- ***************************************************************************
- */
-void read_temp(struct stats_pwr_temp *st_pwr_temp, int nbr)
-{
-#ifdef HAVE_SENSORS
-       int count = 0;
-       const sensors_chip_name *chip;
-       const sensors_feature *feature;
-       const sensors_subfeature *sub;
-       struct stats_pwr_temp *st_pwr_temp_i;
-       int chip_nr = 0;
-       int i, j;
-
-       memset(st_pwr_temp, 0, STATS_PWR_TEMP_SIZE);
-       int err = 0;
-
-       while ((chip = sensors_get_detected_chips(NULL, &chip_nr))) {
-               i = 0;
-               while ((feature = sensors_get_features(chip, &i))) {
-                       if ((feature->type == SENSORS_FEATURE_TEMP) && (count < nbr)) {
-                               j = 0;
-                               st_pwr_temp_i = st_pwr_temp + count;
-                               sensors_snprintf_chip_name(st_pwr_temp_i->device, MAX_SENSORS_DEV_LEN, chip);
-                               
-                               while ((sub = sensors_get_all_subfeatures(chip, feature, &j))) {
-                                       if ((sub->type == SENSORS_SUBFEATURE_TEMP_INPUT) &&
-                                               (sub->flags & SENSORS_MODE_R)) {
-                                               if ((err = sensors_get_value(chip, sub->number, &st_pwr_temp_i->temp))) {
-                                                       st_pwr_temp_i->temp = 0;
-                                               }
-                                       }
-                                       else if ((sub->type == SENSORS_SUBFEATURE_TEMP_MIN)) {
-                                               if ((err = sensors_get_value(chip, sub->number, &st_pwr_temp_i->temp_min))) {
-                                                       st_pwr_temp_i->temp_min = 0;
-                                               }
-                                       }
-                                       else if ((sub->type == SENSORS_SUBFEATURE_TEMP_MAX)) {
-                                               if ((err = sensors_get_value(chip, sub->number, &st_pwr_temp_i->temp_max))) {
-                                                       st_pwr_temp_i->temp_max = 0;
-                                               }
-                                       }
-                               }
-                               count++;
-                       }
-               }
-       }
-#endif /* HAVE_SENSORS */
-}
-
 /*
  ***************************************************************************
  * Count the number of voltage inputs on the machine.
@@ -2179,102 +2326,29 @@ int get_in_nr(void)
 
 /*
  ***************************************************************************
- * Read voltage inputs statistics.
- *
- * IN:
- * @st_pwr_in  Structure where stats will be saved.
- * @nbr                Total number of voltage inputs.
- *
- * OUT:
- * @st_pwr_in  Structure with statistics.
- ***************************************************************************
- */
-void read_in(struct stats_pwr_in *st_pwr_in, int nbr)
-{
-#ifdef HAVE_SENSORS
-       int count = 0;
-       const sensors_chip_name *chip;
-       const sensors_feature *feature;
-       const sensors_subfeature *sub;
-       struct stats_pwr_in *st_pwr_in_i;
-       int chip_nr = 0;
-       int i, j;
-
-       memset(st_pwr_in, 0, STATS_PWR_IN_SIZE);
-       int err = 0;
-
-       while ((chip = sensors_get_detected_chips(NULL, &chip_nr))) {
-               i = 0;
-               while ((feature = sensors_get_features(chip, &i))) {
-                       if ((feature->type == SENSORS_FEATURE_IN) && (count < nbr)) {
-                               j = 0;
-                               st_pwr_in_i = st_pwr_in + count;
-                               sensors_snprintf_chip_name(st_pwr_in_i->device, MAX_SENSORS_DEV_LEN, chip);
-
-                               while ((sub = sensors_get_all_subfeatures(chip, feature, &j))) {
-                                       if ((sub->type == SENSORS_SUBFEATURE_IN_INPUT) &&
-                                               (sub->flags & SENSORS_MODE_R)) {
-                                               if ((err = sensors_get_value(chip, sub->number, &st_pwr_in_i->in))) {
-                                                       st_pwr_in_i->in = 0;
-                                               }
-                                       }
-                                       else if ((sub->type == SENSORS_SUBFEATURE_IN_MIN)) {
-                                               if ((err = sensors_get_value(chip, sub->number, &st_pwr_in_i->in_min))) {
-                                                       st_pwr_in_i->in_min = 0;
-                                               }
-                                       }
-                                       else if ((sub->type == SENSORS_SUBFEATURE_IN_MAX)) {
-                                               if ((err = sensors_get_value(chip, sub->number, &st_pwr_in_i->in_max))) {
-                                                       st_pwr_in_i->in_max = 0;
-                                               }
-                                       }
-                               }
-                               count++;
-                       }
-               }
-       }
-#endif /* HAVE_SENSORS */
-}
-
-/*
- ***************************************************************************
- * Read hugepages statistics from /proc/meminfo.
- *
- * IN:
- * @st_huge    Structure where stats will be saved.
+ * Count number of possible frequencies for CPU#0.
  *
- * OUT:
- * @st_huge    Structure with statistics.
+ * RETURNS:
+ * Number of frequencies.
  ***************************************************************************
  */
-void read_meminfo_huge(struct stats_huge *st_huge)
+int get_freq_nr(void)
 {
        FILE *fp;
+       char filename[MAX_PF_NAME];
        char line[128];
-       unsigned long szhkb = 0;
+       int freq = 0;
 
-       if ((fp = fopen(MEMINFO, "r")) == NULL)
-               return;
+       snprintf(filename, MAX_PF_NAME, "%s/cpu0/%s",
+                SYSFS_DEVCPU, SYSFS_TIME_IN_STATE);
+       if ((fp = fopen(filename, "r")) == NULL)
+               return 0;       /* No time_in_state file for CPU#0 */
 
        while (fgets(line, 128, fp) != NULL) {
-
-               if (!strncmp(line, "HugePages_Total:", 16)) {
-                       /* Read the total number of huge pages */
-                       sscanf(line + 16, "%lu", &st_huge->tlhkb);
-               }
-               else if (!strncmp(line, "HugePages_Free:", 15)) {
-                       /* Read the number of free huge pages */
-                       sscanf(line + 15, "%lu", &st_huge->frhkb);
-               }
-               else if (!strncmp(line, "Hugepagesize:", 13)) {
-                       /* Read the default size of a huge page in kB */
-                       sscanf(line + 13, "%lu", &szhkb);
-               }
+               freq++;
        }
 
        fclose(fp);
 
-       /* We want huge pages stats in kB and not expressed in a number of pages */
-       st_huge->tlhkb *= szhkb;
-       st_huge->frhkb *= szhkb;
+       return freq;
 }
index 559c82b4ac4f82270d9f673d2c965a21677485c6..c3585722e767b78a91886116804eb9f21cb4b86b 100644 (file)
@@ -524,6 +524,18 @@ struct stats_huge {
 
 #define STATS_HUGE_SIZE        (sizeof(struct stats_memory))
 
+/*
+ * Structure for weighted CPU frequency statistics.
+ * In activity buffer: First structure is for global CPU utilisation ("all").
+ * Following structures are for each individual CPU (0, 1, etc.)
+ */
+struct stats_pwr_wghfreq {
+       unsigned long long      time_in_state   __attribute__ ((aligned (16)));
+       unsigned long           freq            __attribute__ ((aligned (16)));
+};
+
+#define STATS_PWR_WGHFREQ_SIZE (sizeof(struct stats_pwr_wghfreq))
+
 /*
  ***************************************************************************
  * Prototypes for functions used to read system statistics
@@ -601,6 +613,8 @@ extern void
        read_in(struct stats_pwr_in *, int);
 extern void
        read_meminfo_huge(struct stats_huge *);
+extern void
+       read_time_in_state(struct stats_pwr_wghfreq *, int, int);
 
 /*
  ***************************************************************************
@@ -628,5 +642,7 @@ extern int
        get_temp_nr(void);
 extern int
        get_in_nr(void);
+extern int
+       get_freq_nr(void);
 
 #endif /* _RD_STATS_H */
diff --git a/sa.h b/sa.h
index ec51d9ed3c4749154f72780ee96c96446e833c94..cde99aee4dc7b53ebdf22c1c3fccb8408f85aa98 100644 (file)
--- a/sa.h
+++ b/sa.h
@@ -17,7 +17,7 @@
  */
 
 /* Number of activities */
-#define NR_ACT 34
+#define NR_ACT 35
 
 /* Activities */
 #define A_CPU          1
@@ -54,6 +54,7 @@
 #define A_PWR_TEMP     32
 #define A_PWR_IN       33
 #define A_HUGE         34
+#define A_PWR_WGHFREQ  35
 
 
 /* Macro used to flag an activity that should be collected */
 #define K_FAN          "FAN"
 #define K_TEMP         "TEMP"
 #define K_IN           "IN"
+#define K_FREQ         "FREQ"
 
 /* sadc program */
 #define SADC           "sadc"
 #define NR_IFACE_PREALLOC      2
 #define NR_SERIAL_PREALLOC     2
 #define NR_DISK_PREALLOC       3
+#define NR_FREQ_PREALLOC       0
 
 #define UTSNAME_LEN            65
 #define TIMESTAMP_LEN          16
@@ -663,6 +666,8 @@ extern __nr_t
        wrap_get_temp_nr(struct activity *);
 extern __nr_t
        wrap_get_in_nr(struct activity *);
+extern __nr_t
+       wrap_get_freq_nr(struct activity *);
 
 /* Functions used to read activities statistics */
 extern __read_funct_t
@@ -733,6 +738,8 @@ extern __read_funct_t
        wrap_read_in(struct activity *);
 extern __read_funct_t
        wrap_read_meminfo_huge(struct activity *);
+extern __read_funct_t
+       wrap_read_time_in_state(struct activity *);
 
 /* Other functions */
 extern void
index 72eff3cbced5c5362b378d3f59264fe087d089d5..09ef7852592811ee918c1fc964a4a50e4f0c12da 100644 (file)
@@ -1341,11 +1341,15 @@ int parse_sar_m_opt(char *argv[], int *opt, struct activity *act[])
                else if (!strcmp(t, K_TEMP)) {
                        SELECT_ACTIVITY(A_PWR_TEMP);
                }
+               else if (!strcmp(t, K_FREQ)) {
+                       SELECT_ACTIVITY(A_PWR_WGHFREQ);
+               }
                else if (!strcmp(t, K_ALL)) {
                        SELECT_ACTIVITY(A_PWR_CPUFREQ);
                        SELECT_ACTIVITY(A_PWR_FAN);
                        SELECT_ACTIVITY(A_PWR_IN);
                        SELECT_ACTIVITY(A_PWR_TEMP);
+                       SELECT_ACTIVITY(A_PWR_WGHFREQ);
                }
                else
                        return 1;
index 8b758e358439d7059f4a5e08a6cb130a22c45add..93f834dfe3da97e8d3659d76c534a3fa79893559 100644 (file)
--- a/sa_wrap.c
+++ b/sa_wrap.c
 extern unsigned int flags;
 extern struct record_header record_hdr;
 
-/*
- ***************************************************************************
- * Count number of interrupts that are in /proc/stat file.
- * Truncate the number of different individual interrupts to NR_IRQS.
- *
- * IN:
- * @a  Activity structure.
- *
- * RETURNS:
- * Number of interrupts, including total number of interrupts.
- * Value in [0, NR_IRQS + 1].
- ***************************************************************************
- */
-__nr_t wrap_get_irq_nr(struct activity *a)
-{
-       __nr_t n;
-
-       if ((n = get_irq_nr()) > (a->bitmap->b_size + 1)) {
-               n = a->bitmap->b_size + 1;
-       }
-       
-       return n;
-}
-
-/*
- ***************************************************************************
- * Find number of serial lines that support tx/rx accounting
- * in /proc/tty/driver/serial file.
- *
- * IN:
- * @a  Activity structure.
- *
- * RETURNS:
- * Number of serial lines supporting tx/rx accouting + a pre-allocation
- * constant.
- ***************************************************************************
- */
-__nr_t wrap_get_serial_nr(struct activity *a)
-{
-       __nr_t n = 0;
-       
-       if ((n = get_serial_nr()) > 0)
-               return n + NR_SERIAL_PREALLOC;
-       
-       return 0;
-}
-
-/*
- ***************************************************************************
- * Find number of interfaces (network devices) that are in /proc/net/dev
- * file.
- *
- * IN:
- * @a  Activity structure.
- *
- * RETURNS:
- * Number of network interfaces + a pre-allocation constant.
- ***************************************************************************
- */
-__nr_t wrap_get_iface_nr(struct activity *a)
-{
-       __nr_t n = 0;
-       
-       if ((n = get_iface_nr()) > 0)
-               return n + NR_IFACE_PREALLOC;
-       
-       return 0;
-}
-
-/*
- ***************************************************************************
- * Compute number of CPU structures to allocate.
- *
- * IN:
- * @a  Activity structure.
- *
- * RETURNS:
- * Number of structures (value in [1, NR_CPUS + 1]).
- * 1 means that there is only one proc and non SMP kernel.
- * 2 means one proc and SMP kernel.
- * Etc.
- ***************************************************************************
- */
-__nr_t wrap_get_cpu_nr(struct activity *a)
-{
-       return (get_cpu_nr(a->bitmap->b_size) + 1);
-}
-
-/*
- ***************************************************************************
- * Get number of devices in /proc/diskstats.
- * Always done, since disk stats must be read at least for sar -b
- * if not for sar -d.
- *
- * IN:
- * @a  Activity structure.
- *
- * RETURNS:
- * Number of devices + a pre-allocation constant.
- ***************************************************************************
- */
-__nr_t wrap_get_disk_nr(struct activity *a)
-{
-       __nr_t n = 0;
-       unsigned int f = COLLECT_PARTITIONS(a->opt_flags);
-       
-       if ((n = get_disk_nr(f)) > 0)
-               return n + NR_DISK_PREALLOC;
-       
-       return 0;
-}
-
 /*
  ***************************************************************************
  * Read CPU statistics.
@@ -797,22 +685,6 @@ __read_funct_t wrap_read_cpuinfo(struct activity *a)
        return;
 }
 
-/*
- ***************************************************************************
- * Get number of fan structures to allocate.
- *
- * IN:
- * @a  Activity structure.
- *
- * RETURNS:
- * Number of structures.
- ***************************************************************************
- */
-__nr_t wrap_get_fan_nr(struct activity *a)
-{
-       return (get_fan_nr());
-}
-
 /*
  ***************************************************************************
  * Read fan statistics.
@@ -837,23 +709,29 @@ __read_funct_t wrap_read_fan(struct activity *a)
 
 /*
  ***************************************************************************
- * Get number of temp structures to allocate.
+ * Read temperature statistics.
  *
  * IN:
  * @a  Activity structure.
  *
- * RETURNS:
- * Number of structures.
+ * OUT:
+ * @a  Activity structure with statistics.
  ***************************************************************************
  */
-__nr_t wrap_get_temp_nr(struct activity *a)
+__read_funct_t wrap_read_temp(struct activity *a)
 {
-       return (get_temp_nr());
+       struct stats_pwr_temp *st_pwr_temp
+               = (struct stats_pwr_temp *) a->_buf0;
+
+       /* Read temperature stats */
+       read_temp(st_pwr_temp, a->nr);
+
+       return;
 }
 
 /*
  ***************************************************************************
- * Read temperature statistics.
+ * Read voltage input statistics.
  *
  * IN:
  * @a  Activity structure.
@@ -862,13 +740,13 @@ __nr_t wrap_get_temp_nr(struct activity *a)
  * @a  Activity structure with statistics.
  ***************************************************************************
  */
-__read_funct_t wrap_read_temp(struct activity *a)
+__read_funct_t wrap_read_in(struct activity *a)
 {
-       struct stats_pwr_temp *st_pwr_temp
-               = (struct stats_pwr_temp *) a->_buf0;
+       struct stats_pwr_in *st_pwr_in
+               = (struct stats_pwr_in *) a->_buf0;
 
-       /* Read temperature stats */
-       read_temp(st_pwr_temp, a->nr);
+       /* Read voltage input stats */
+       read_in(st_pwr_in, a->nr);
 
        return;
 }
@@ -895,6 +773,201 @@ __read_funct_t wrap_read_meminfo_huge(struct activity *a)
        return;
 }
 
+/*
+ ***************************************************************************
+ * Read weighted CPU frequency statistics.
+ *
+ * IN:
+ * @a  Activity structure.
+ *
+ * OUT:
+ * @a  Activity structure with statistics.
+ ***************************************************************************
+ */
+__read_funct_t wrap_read_time_in_state(struct activity *a)
+{
+       __nr_t  cpu = 0;
+       int j;
+       struct stats_pwr_wghfreq *st_pwr_wghfreq
+               = (struct stats_pwr_wghfreq *) a->_buf0;
+       struct stats_pwr_wghfreq *st_pwr_wghfreq_i, *st_pwr_wghfreq_j, *st_pwr_wghfreq_all_j;
+
+       while (cpu < (a->nr - 1)) {
+               /* Read current CPU time-in-state data */
+               st_pwr_wghfreq_i = st_pwr_wghfreq + (cpu + 1) * a->nr2;
+               read_time_in_state(st_pwr_wghfreq_i, cpu, a->nr2);
+
+               /* Also save data for CPU 'all' */
+               for (j = 0; j < a->nr2; j++) {
+                       st_pwr_wghfreq_j     = st_pwr_wghfreq_i + j;    /* CPU #cpu, state #j */
+                       st_pwr_wghfreq_all_j = st_pwr_wghfreq   + j;    /* CPU #all, state #j */
+                       if (!cpu) {
+                               /* Assume that possible frequencies are the same for all CPUs */
+                               st_pwr_wghfreq_all_j->freq = st_pwr_wghfreq_j->freq;
+                       }
+                       st_pwr_wghfreq_all_j->time_in_state += st_pwr_wghfreq_j->time_in_state;
+               }
+               cpu++;
+       }
+
+       /* Special processing for non SMP kernels: Only CPU 'all' is available */
+       if (a->nr == 1) {
+               read_time_in_state(st_pwr_wghfreq, 0, a->nr2);
+       }
+       else {
+               for (j = 0; j < a->nr2; j++) {
+                       st_pwr_wghfreq_all_j = st_pwr_wghfreq + j;      /* CPU #all, state #j */
+                       st_pwr_wghfreq_all_j->time_in_state /= (a->nr - 1);
+               }
+       }
+
+       return;
+}
+
+/*
+ ***************************************************************************
+ * Count number of interrupts that are in /proc/stat file.
+ * Truncate the number of different individual interrupts to NR_IRQS.
+ *
+ * IN:
+ * @a  Activity structure.
+ *
+ * RETURNS:
+ * Number of interrupts, including total number of interrupts.
+ * Value in [0, NR_IRQS + 1].
+ ***************************************************************************
+ */
+__nr_t wrap_get_irq_nr(struct activity *a)
+{
+       __nr_t n;
+
+       if ((n = get_irq_nr()) > (a->bitmap->b_size + 1)) {
+               n = a->bitmap->b_size + 1;
+       }
+
+       return n;
+}
+
+/*
+ ***************************************************************************
+ * Find number of serial lines that support tx/rx accounting
+ * in /proc/tty/driver/serial file.
+ *
+ * IN:
+ * @a  Activity structure.
+ *
+ * RETURNS:
+ * Number of serial lines supporting tx/rx accouting + a pre-allocation
+ * constant.
+ ***************************************************************************
+ */
+__nr_t wrap_get_serial_nr(struct activity *a)
+{
+       __nr_t n = 0;
+
+       if ((n = get_serial_nr()) > 0)
+               return n + NR_SERIAL_PREALLOC;
+
+       return 0;
+}
+
+/*
+ ***************************************************************************
+ * Find number of interfaces (network devices) that are in /proc/net/dev
+ * file.
+ *
+ * IN:
+ * @a  Activity structure.
+ *
+ * RETURNS:
+ * Number of network interfaces + a pre-allocation constant.
+ ***************************************************************************
+ */
+__nr_t wrap_get_iface_nr(struct activity *a)
+{
+       __nr_t n = 0;
+
+       if ((n = get_iface_nr()) > 0)
+               return n + NR_IFACE_PREALLOC;
+
+       return 0;
+}
+
+/*
+ ***************************************************************************
+ * Compute number of CPU structures to allocate.
+ *
+ * IN:
+ * @a  Activity structure.
+ *
+ * RETURNS:
+ * Number of structures (value in [1, NR_CPUS + 1]).
+ * 1 means that there is only one proc and non SMP kernel.
+ * 2 means one proc and SMP kernel.
+ * Etc.
+ ***************************************************************************
+ */
+__nr_t wrap_get_cpu_nr(struct activity *a)
+{
+       return (get_cpu_nr(a->bitmap->b_size) + 1);
+}
+
+/*
+ ***************************************************************************
+ * Get number of devices in /proc/diskstats.
+ * Always done, since disk stats must be read at least for sar -b
+ * if not for sar -d.
+ *
+ * IN:
+ * @a  Activity structure.
+ *
+ * RETURNS:
+ * Number of devices + a pre-allocation constant.
+ ***************************************************************************
+ */
+__nr_t wrap_get_disk_nr(struct activity *a)
+{
+       __nr_t n = 0;
+       unsigned int f = COLLECT_PARTITIONS(a->opt_flags);
+
+       if ((n = get_disk_nr(f)) > 0)
+               return n + NR_DISK_PREALLOC;
+
+       return 0;
+}
+
+/*
+ ***************************************************************************
+ * Get number of fan structures to allocate.
+ *
+ * IN:
+ * @a  Activity structure.
+ *
+ * RETURNS:
+ * Number of structures.
+ ***************************************************************************
+ */
+__nr_t wrap_get_fan_nr(struct activity *a)
+{
+       return (get_fan_nr());
+}
+
+/*
+ ***************************************************************************
+ * Get number of temp structures to allocate.
+ *
+ * IN:
+ * @a  Activity structure.
+ *
+ * RETURNS:
+ * Number of structures.
+ ***************************************************************************
+ */
+__nr_t wrap_get_temp_nr(struct activity *a)
+{
+       return (get_temp_nr());
+}
+
 /*
  ***************************************************************************
  * Get number of voltage input structures to allocate.
@@ -913,22 +986,21 @@ __nr_t wrap_get_in_nr(struct activity *a)
 
 /*
  ***************************************************************************
- * Read voltage input statistics.
+ * Count number of possible frequencies for CPU#0.
  *
  * IN:
- * @a  Activity structure.
+ * @a  Activity structure.
  *
- * OUT:
- * @a  Activity structure with statistics.
+ * RETURNS:
+ * Number of CPU frequencies + a pre-allocation constant.
  ***************************************************************************
  */
-__read_funct_t wrap_read_in(struct activity *a)
+__nr_t wrap_get_freq_nr(struct activity *a)
 {
-       struct stats_pwr_in *st_pwr_in
-               = (struct stats_pwr_in *) a->_buf0;
+       __nr_t n = 0;
 
-       /* Read voltage input stats */
-       read_in(st_pwr_in, a->nr);
+       if ((n = get_freq_nr()) > 0)
+               return n + NR_FREQ_PREALLOC;
 
-       return;
+       return 0;
 }
diff --git a/sadc.c b/sadc.c
index 0489e1206aa79d81357b718b5992cad9364b4233..ad904ae335a2faab9bd432876ec3bcb3149c2f65 100644 (file)
--- a/sadc.c
+++ b/sadc.c
@@ -140,6 +140,7 @@ void parse_sadc_S_option(char *argv[], int opt)
                        COLLECT_ACTIVITY(A_PWR_CPUFREQ);
                        COLLECT_ACTIVITY(A_PWR_FAN);
                        COLLECT_ACTIVITY(A_PWR_TEMP);
+                       COLLECT_ACTIVITY(A_PWR_WGHFREQ);
                }
                else if (!strcmp(p, K_ALL) || !strcmp(p, K_XALL)) {
                        /* Select all activities */
diff --git a/sar.c b/sar.c
index 84cc5627529a15390b53f2eac5f9752aa65e0bd1..c9fc5b6701bdcb0ca25fb2f6d107dc10ea176d2f 100644 (file)
--- a/sar.c
+++ b/sar.c
@@ -133,8 +133,9 @@ void display_help(char *progname)
        fprintf(stderr, _("\t-m { <keyword> [,...] | ALL }\n"
                          "\t\tPower management statistics\n"
                          "\t\tKeywords are:\n"
-                         "\t\tCPU\tCPU clock frequency\n"
+                         "\t\tCPU\tCPU instantaneous clock frequency\n"
                          "\t\tFAN\tFans speed\n"
+                         "\t\tFREQ\tCPU average clock frequency\n"
                          "\t\tIN\tVoltage inputs\n"
                          "\t\tTEMP\tDevices temperature\n"));
        fprintf(stderr, _("\t-n { <keyword> [,...] | ALL }\n"
index abab80baa41eae6632e3192394c4e6ed2e74474e..32a6eb3d5c194d55bf8dcf4fc913b33dc453f3c4 100644 (file)
        brk CDATA #REQUIRED
        ovrun CDATA #REQUIRED
 >
-<!ELEMENT power-management (cpu-frequency, fan-speed, temperature, voltage-input)>
+<!ELEMENT power-management (cpu-frequency, fan-speed, temperature, voltage-input, cpu-weighted-frequency,)>
 <!ELEMENT cpu-frequency (cpufreq+)>
 <!ATTLIST cpu-frequency
        unit CDATA #REQUIRED
        number CDATA #REQUIRED
        frequency CDATA #REQUIRED
 >
+<!ELEMENT cpu-weighted-frequency (cpuwfreq+)>
+<!ATTLIST cpu-weighted-frequency
+       unit CDATA #REQUIRED
+>
+<!ELEMENT cpuwfreq EMPTY>
+<!ATTLIST cpuwfreq
+       number CDATA #REQUIRED
+       weighted-frequency CDATA #REQUIRED
+>
 <!ELEMENT fan-speed (fanspd+)>
 <!ATTLIST fan-speed
        unit CDATA #REQUIRED
index 08d76125a754c6e94756b37605490ba61c97393b..201c79e805491da8b0d5b75083cb882e5a0e394f 100644 (file)
        </xs:restriction>
     </xs:simpleType>
 
+    <xs:element name="cpu-weighted-frequency" type="cpu-weighted-frequency-type"></xs:element>
+
+    <xs:complexType name="cpu-weighted-frequency-type">
+       <xs:sequence>
+               <xs:element name="cpuwfreq" type="cpuwfreq-type" minOccurs="1"></xs:element>
+       </xs:sequence>
+       <xs:attribute name="unit" type="frequnit-type"></xs:attribute>
+    </xs:complexType>
+
     <xs:element name="fan-speed" type="fan-speed-type"></xs:element>
 
     <xs:complexType name="fan-speed-type">
        <xs:attribute name="frequency" type="hundredth-type"></xs:attribute>
     </xs:complexType>
 
+    <xs:element name="cpuwfreq" type="cpuwfreq-type"></xs:element>
+
+    <xs:complexType name="cpuwfreq-type">
+       <xs:attribute name="number" type="xs:string"></xs:attribute>
+       <xs:attribute name="weighted-frequency" type="hundredth-type"></xs:attribute>
+    </xs:complexType>
+
     <xs:element name="fan" type="fan-type"></xs:element>
 
     <xs:complexType name="fan-type">
                <xs:element name="fan-speed" type="fan-speed-type"></xs:element>
                <xs:element name="temperature" type="temperature-type"></xs:element>
                <xs:element name="voltage-input" type="voltage-input-type"></xs:element>
+               <xs:element name="cpu-weighted-frequency" type="cpu-weighted-frequency-type"></xs:element>
        </xs:sequence>
     </xs:complexType>