734
#if defined(VMX86_STATS)
735
#if defined(__linux__) && !defined(VMX86_SERVER)
737
*----------------------------------------------------------------------------
739
* UtilAllocCStArrays --
741
* (Re-)Allocate data arrays for UtilReadSysCStRes and UtilReadProcCStRes.
744
* TRUE if successful.
749
*----------------------------------------------------------------------------
753
UtilAllocCStArrays(uint32 ncpus, // IN
754
uint32 nstates, // IN
755
uint64 **transitns, // OUT
756
uint64 **residency, // OUT
757
uint64 **transTime, // OUT
758
uint64 **residTime) // OUT
765
*transitns = calloc(nstates * ncpus, sizeof **transitns);
766
*residency = calloc(nstates * ncpus, sizeof **residency);
767
*transTime = calloc(ncpus, sizeof **transTime);
768
*residTime = calloc(ncpus, sizeof **residTime);
770
if (!*transitns || !*residency || !*transTime || !*residTime) {
775
Warning("%s: Cannot allocate memory for C-state queries\n", __FUNCTION__);
784
*----------------------------------------------------------------------------
786
* UtilReadSysCStRes --
787
* UtilReadProcCStRes --
789
* Read the C-state residency statistics under /sys and /proc
790
* respectively. UtilReadSysCStRes should take precedence over
791
* UtilReadProcCStRes as /proc/acpi is getting replaced by sysfs
792
* in newer kernels. See Util_QueryCStResidency for description of
796
* TRUE if successful.
801
*----------------------------------------------------------------------------
805
UtilReadSysCStRes(DIR *dir, // IN
806
uint32 *numCpus, // IN/OUT
807
uint32 *numCStates, // IN/OUT
808
uint64 **transitns, // OUT
809
uint64 **residency, // OUT
810
uint64 **transTime, // OUT
811
uint64 **residTime) // OUT
813
struct dirent *cpuEntry;
815
struct dirent *cstateEntry;
816
char pathname[PATH_MAX + 1];
820
/* Determine the number of cpus and c-states. */
821
while ((cpuEntry = readdir(dir))) {
822
if (Str_Strncasecmp(cpuEntry->d_name, "cpu", 3) == 0 &&
823
isdigit(cpuEntry->d_name[3])) {
825
if (cl != 0) { /* already found the number of c states */
828
if (Str_Snprintf(pathname, sizeof pathname,
829
SYS_CSTATE_DIR"/%s/cpuidle", cpuEntry->d_name) <= 0) {
830
LOG(0, ("%s: Str_Snprintf failed\n", __FUNCTION__));
833
cpuDir = Posix_OpenDir(pathname);
834
if (cpuDir != NULL) {
837
while ((cstateEntry = readdir(cpuDir))) {
838
if (Str_Strncasecmp(cstateEntry->d_name, "state", 5) == 0 &&
839
sscanf(cstateEntry->d_name + 5, "%u", &cnum) == 1 &&
841
cl = cnum; /* state0 will be ignored */
848
if (cpu == 0 || cl == 0) {
852
if (*numCpus != cpu || *numCStates != cl) {
853
if (!UtilAllocCStArrays(cpu, cl, transitns, residency, transTime,
863
while ((cpuEntry = readdir(dir))) {
867
if (Str_Strncasecmp(cpuEntry->d_name, "cpu", 3) != 0 ||
868
!isdigit(cpuEntry->d_name[3])) {
871
pathlen = Str_Snprintf(pathname, sizeof pathname,
872
SYS_CSTATE_DIR"/%s/cpuidle", cpuEntry->d_name);
874
LOG(0, ("%s: Str_Snprintf for '%s/cpuidle' failed\n", __FUNCTION__,
878
cpuDir = Posix_OpenDir(pathname);
879
if (cpuDir == NULL) {
880
LOG(0, ("%s: Failed to open directory %s\n", __FUNCTION__, pathname));
885
* Under the "cpuidle" directory, there is one "stateX" directory for
886
* each C-state. We ignore "state0", i.e. C0, which is the running state.
887
* Under each "stateX" directory, there is a "usage" file which contains
888
* the number of entries into that state, and a "time" file which
889
* contains the total residency in that state.
892
while ((cstateEntry = readdir(cpuDir))) {
897
if (Str_Strncasecmp(cstateEntry->d_name, "state", 5) != 0) {
900
if (sscanf(cstateEntry->d_name + 5, "%u", &cl) != 1 || cl == 0) {
903
cl--; /* ignoring state0 -- cl == 0 -> state1 */
904
index = *numCStates * cpu + cl;
906
if (Str_Snprintf(pathname + pathlen, sizeof pathname - pathlen,
907
"/%s/usage", cstateEntry->d_name) <= 0) {
908
LOG(0, ("%s: Str_Snprintf for 'usage' failed\n", __FUNCTION__));
912
statsFile = Posix_Fopen(pathname, "r");
913
if (statsFile == NULL) {
916
result = fscanf(statsFile, "%"FMT64"u", &(*transitns)[index]);
922
if (Str_Snprintf(pathname + pathlen, sizeof pathname - pathlen,
923
"/%s/time", cstateEntry->d_name) <= 0) {
924
LOG(0, ("%s: Str_Snprintf for 'time' failed\n", __FUNCTION__));
928
statsFile = Posix_Fopen(pathname, "r");
929
if (statsFile == NULL) {
932
result = fscanf(statsFile, "%"FMT64"u", &(*residency)[index]);
940
timeUS = Hostinfo_SystemTimerUS();
942
LOG(0, ("%s: Hostinfo_SystemTimerUS() failed\n", __FUNCTION__));
945
(*transTime)[cpu] = timeUS;
946
(*residTime)[cpu] = timeUS;
955
UtilReadProcCStRes(DIR *dir, // IN
956
uint32 *numCpus, // IN/OUT
957
uint32 *numCStates, // IN/OUT
958
uint64 **transitns, // OUT
959
uint64 **residency, // OUT
960
uint64 **transTime, // OUT
961
uint64 **residTime) // OUT
963
struct dirent *cpuEntry;
966
/* Determine the number of cpus. */
967
while ((cpuEntry = readdir(dir))) {
968
if (cpuEntry->d_name[0] != '.') {
976
if (*numCpus != cpu) {
978
* We do not know the number of C-states supported until we read the
979
* file, so we allocate for MAX_C_STATES and determine *numCStates later.
982
if (!UtilAllocCStArrays(cpu, MAX_C_STATES, transitns, residency,
983
transTime, residTime)) {
992
while ((cpuEntry = readdir(dir))) {
993
char pathname[PATH_MAX + 1];
1000
if (cpuEntry->d_name[0] == '.') {
1003
if (Str_Snprintf(pathname, sizeof pathname, PROC_CSTATE_DIR"/%s/power",
1004
cpuEntry->d_name) <= 0) {
1005
LOG(0, ("%s: Str_Snprintf for '%s/power' failed\n", __FUNCTION__,
1009
powerFile = Posix_Fopen(pathname, "r");
1010
if (powerFile == NULL) {
1015
while (StdIO_ReadNextLine(powerFile, &line, 0, &lineSize)
1018
uint32 index = *numCStates * cpu + cl;
1020
if ((ptr = Str_Strnstr(line, "usage[", lineSize))) {
1021
sscanf(ptr + 6, "%"FMT64"u]", &(*transitns)[index]);
1022
if ((ptr = Str_Strnstr(line, "duration[", lineSize))) {
1023
sscanf(ptr + 9, "%"FMT64"u]", &(*residency)[index]);
1031
timeUS = Hostinfo_SystemTimerUS();
1033
LOG(0, ("%s: Hostinfo_SystemTimerUS() failed\n", __FUNCTION__));
1036
(*transTime)[cpu] = timeUS;
1037
(*residTime)[cpu] = (uint64)((double)timeUS * FREQ_ACPI);
1038
if (*numCStates == 0) {
1043
return cpu > 0 && *numCStates > 0;
1048
*----------------------------------------------------------------------------
1050
* Util_QueryCStResidency --
1052
* Query CPU's C-state residency statistics exposed by the host OS.
1053
* On Linux, this is done via either the sysfs or /proc/acpi interface.
1055
* The parameters transitns, residency, transTime and residTime are
1056
* pointers to uint64 arrays, whose dimensions are specified by
1057
* *numCpus and/or *numCStates:
1058
* transitns -- number of trasitions into each c-state for each CPU
1059
* residency -- time in each c-state for each CPU (in some opaque unit)
1060
* transTime -- timestamp (microseconds) for transitns data, per CPU
1061
* residTime -- timestamp for residency data, per CPU (in same unit as
1064
* If the dimensions specified are too small, the arrays are freed
1065
* and new memory allocated.
1068
* TRUE if successful.
1073
*----------------------------------------------------------------------------
1077
Util_QueryCStResidency(uint32 *numCpus, // IN/OUT
1078
uint32 *numCStates, // IN/OUT
1079
uint64 **transitns, // OUT
1080
uint64 **residency, // OUT
1081
uint64 **transTime, // OUT
1082
uint64 **residTime) // OUT
1087
dir = Posix_OpenDir(SYS_CSTATE_DIR);
1089
ret = UtilReadSysCStRes(dir, numCpus, numCStates, transitns, residency,
1090
transTime, residTime);
1095
dir = Posix_OpenDir(PROC_CSTATE_DIR);
1097
ret = UtilReadProcCStRes(dir, numCpus, numCStates, transitns,
1098
residency, transTime, residTime);
1106
#else // #if defined(__linux__) && !defined(VMX86_SERVER)
1109
Util_QueryCStResidency(uint32 *numCpus, // IN/OUT
1110
uint32 *numCStates, // IN/OUT
1111
uint64 **transitns, // OUT
1112
uint64 **residency, // OUT
1113
uint64 **transTime, // OUT
1114
uint64 **residTime) // OUT
1119
#endif // #if defined(VMX86_STATS)