From: Sebastien Godard Date: Sun, 24 Oct 2010 15:39:20 +0000 (+0200) Subject: Added CPU average clock frequency statistics to sar and sadc. X-Git-Tag: v9.1.6~8 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=5b7479528d59c8ff53a6138db5ae52460b3b60c1;p=sysstat Added CPU average clock frequency statistics to sar and sadc. 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) 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) 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 --- diff --git a/CHANGES b/CHANGES index 84280f4..23866d8 100644 --- a/CHANGES +++ b/CHANGES @@ -6,7 +6,8 @@ xxxx/xx/xx: Version 9.1.6 - Sebastien Godard (sysstat 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 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 orange.fr) * Added voltage inputs statistics to sar and sadc. diff --git a/CREDITS b/CREDITS index 37a20d0..07cd359 100644 --- a/CREDITS +++ b/CREDITS @@ -210,6 +210,7 @@ I would also thank the following people for their hints or bug reports Urban Widmark Yu Yongcong Peter Zaitsev + Zhen Zhang -- Sebastien Godard (sysstat orange.fr) is the author and the current diff --git a/activity.c b/activity.c index 23293da..ac852c0 100644 --- a/activity.c +++ b/activity.c @@ -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 }; diff --git a/common.h b/common.h index f206e5f..4d2651e 100644 --- a/common.h +++ b/common.h @@ -44,16 +44,17 @@ #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 diff --git a/man/sar.in b/man/sar.in index 06643bf..c648f8c 100644 --- a/man/sar.in +++ b/man/sar.in @@ -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. diff --git a/nls/sysstat.pot b/nls/sysstat.pot index 0693f33..9a22880 100644 --- a/nls/sysstat.pot +++ b/nls/sysstat.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: sysstat 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 \n" "Language-Team: LANGUAGE \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 { [,...] | 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 { [,...] | 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 { [,...] | 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 "" diff --git a/pr_stats.c b/pr_stats.c index 285055b..6438ab3 100644 --- a/pr_stats.c +++ b/pr_stats.c @@ -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); + } + } +} diff --git a/pr_stats.h b/pr_stats.h index f847ee0..f126c81 100644 --- a/pr_stats.h +++ b/pr_stats.h @@ -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 diff --git a/prf_stats.c b/prf_stats.c index 59dbf68..e79fb30 100644 --- a/prf_stats.c +++ b/prf_stats.c @@ -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, ""); } + +/* + *************************************************************************** + * 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++, ""); + + 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, "", + cpuno, + tis ? ((double) tisfreq) / tis : 0.0); + } + } + + xprintf(--tab, ""); + tab--; + +close_xml_markup: + if (CLOSE_MARKUP(a->options)) { + xml_markup_power_management(tab, CLOSE_XML_MARKUP); + } +} diff --git a/prf_stats.h b/prf_stats.h index 71dde57..8117bff 100644 --- a/prf_stats.h +++ b/prf_stats.h @@ -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 */ diff --git a/rd_stats.c b/rd_stats.c index bf70da3..59f90aa 100644 --- a/rd_stats.c +++ b/rd_stats.c @@ -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; } diff --git a/rd_stats.h b/rd_stats.h index 559c82b..c358572 100644 --- a/rd_stats.h +++ b/rd_stats.h @@ -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 ec51d9e..cde99ae 100644 --- 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 */ @@ -153,6 +154,7 @@ #define K_FAN "FAN" #define K_TEMP "TEMP" #define K_IN "IN" +#define K_FREQ "FREQ" /* sadc program */ #define SADC "sadc" @@ -172,6 +174,7 @@ #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 diff --git a/sa_common.c b/sa_common.c index 72eff3c..09ef785 100644 --- a/sa_common.c +++ b/sa_common.c @@ -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; diff --git a/sa_wrap.c b/sa_wrap.c index 8b758e3..93f834d 100644 --- a/sa_wrap.c +++ b/sa_wrap.c @@ -25,118 +25,6 @@ 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 0489e12..ad904ae 100644 --- 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 84cc562..c9fc5b6 100644 --- a/sar.c +++ b/sar.c @@ -133,8 +133,9 @@ void display_help(char *progname) fprintf(stderr, _("\t-m { [,...] | 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 { [,...] | ALL }\n" diff --git a/xml/sysstat.dtd b/xml/sysstat.dtd index abab80b..32a6eb3 100644 --- a/xml/sysstat.dtd +++ b/xml/sysstat.dtd @@ -393,7 +393,7 @@ brk CDATA #REQUIRED ovrun CDATA #REQUIRED > - + + + + + + + + + + + + + + @@ -524,6 +533,13 @@ + + + + + + + @@ -649,6 +665,7 @@ +