~n-muench/ubuntu/oneiric/open-vm-tools/open-vm-tools.fix-836277

« back to all changes in this revision

Viewing changes to lib/user/utilPosix.c

  • Committer: Bazaar Package Importer
  • Author(s): Daniel Baumann
  • Date: 2009-07-30 12:56:49 UTC
  • mfrom: (1.1.6 upstream)
  • Revision ID: james.westby@ubuntu.com-20090730125649-97sfj5li8axiseoo
Tags: 2009.07.22-179896-2
* Temporarily building without dumbnet, the recently uploaded
  new dumbnet upstream version broke down (Closes: #539006).
* Using more common name to store local debian additions.

Show diffs side-by-side

added added

removed removed

Lines of Context:
34
34
#include <unistd.h>
35
35
#include <errno.h>
36
36
#include <dirent.h>
 
37
#include <ctype.h>
37
38
 
38
39
#if !__FreeBSD__ && !sun
39
40
#   include <pwd.h>
57
58
#include "unicodeOperations.h"
58
59
#include "err.h"
59
60
#include "posix.h"
 
61
#include "vmstdio.h"
 
62
 
 
63
#define LOGLEVEL_MODULE util
 
64
#include "loglevel_user.h"
 
65
#define LGPFX "UtilPosix:"
60
66
 
61
67
 
62
68
/* For Util_GetProcessName() */
83
89
#   endif
84
90
#endif
85
91
 
 
92
#if defined(VMX86_STATS) && defined(__linux__) && !defined(VMX86_SERVER)
 
93
#define SYS_CSTATE_DIR  "/sys/devices/system/cpu"
 
94
#define PROC_CSTATE_DIR "/proc/acpi/processor"
 
95
#define MAX_C_STATES    8
 
96
#define FREQ_ACPI       3.579545
 
97
#endif
86
98
 
87
99
 
88
100
#if !__FreeBSD__ && !sun
667
679
 
668
680
   fd = Posix_Open(fileName, O_RDONLY);
669
681
   if (fd < 0) {
670
 
      Log("Util_GetProcessName: Error: cannot open %s\n", fileName);
 
682
      Log("%s: Error: cannot open %s\n", __FUNCTION__, fileName);
 
683
 
671
684
      return FALSE;
672
685
   }
673
686
 
677
690
#else
678
691
   if (nread < 0) {
679
692
#endif
680
 
      Log("Util_GetProcessName: Error: could not read %s\n", fileName);
 
693
      Log("%s: Error: could not read %s\n", __FUNCTION__, fileName);
681
694
      close(fd);
 
695
 
682
696
      return FALSE;
683
697
   }
684
698
 
694
708
    * contains a format modifier to ensure psinfo is not overrun.
695
709
    */
696
710
   if (sscanf(buf, PRE PSINFOFMT POST, psinfo) != 1) {
697
 
      Log("Util_GetProcessName: Error, could not parse contents of %s\n", fileName);
 
711
      Log("%s: Error, could not parse contents of %s\n", __FUNCTION__,
 
712
          fileName);
698
713
      return FALSE;
699
714
   }
700
715
 
705
720
 
706
721
   psnameLen = strlen(psname);
707
722
   if (psnameLen + 1 > bufOutSize) {
708
 
      Log("Util_GetProcessName: Error, process name (%"FMTSZ"u bytes) is larger "
709
 
          "than output buffer\n", psnameLen);
 
723
      Log("%s: Error, process name (%"FMTSZ"u bytes) is larger "
 
724
          "than output buffer\n", __FUNCTION__, psnameLen);
 
725
 
710
726
      return FALSE;
711
727
   }
712
728
 
714
730
   return TRUE;
715
731
}
716
732
#endif
 
733
 
 
734
#if defined(VMX86_STATS)
 
735
#if defined(__linux__) && !defined(VMX86_SERVER)
 
736
/*
 
737
 *----------------------------------------------------------------------------
 
738
 *
 
739
 * UtilAllocCStArrays --
 
740
 *
 
741
 *      (Re-)Allocate data arrays for UtilReadSysCStRes and UtilReadProcCStRes.
 
742
 *
 
743
 * Results:
 
744
 *      TRUE if successful.
 
745
 *
 
746
 * Side effects:
 
747
 *      None.
 
748
 *
 
749
 *----------------------------------------------------------------------------
 
750
 */
 
751
 
 
752
static Bool
 
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
 
759
{
 
760
   free(*transitns);
 
761
   free(*residency);
 
762
   free(*transTime);
 
763
   free(*residTime);
 
764
 
 
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);
 
769
 
 
770
   if (!*transitns || !*residency || !*transTime || !*residTime) {
 
771
      free(*transitns);
 
772
      free(*residency);
 
773
      free(*transTime);
 
774
      free(*residTime);
 
775
      Warning("%s: Cannot allocate memory for C-state queries\n", __FUNCTION__);
 
776
      return FALSE;
 
777
   }
 
778
 
 
779
   return TRUE;
 
780
}
 
781
 
 
782
 
 
783
/*
 
784
 *----------------------------------------------------------------------------
 
785
 *
 
786
 * UtilReadSysCStRes --
 
787
 * UtilReadProcCStRes --
 
788
 *
 
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
 
793
 *      parameters.
 
794
 *
 
795
 * Results:
 
796
 *      TRUE if successful.
 
797
 *
 
798
 * Side effects:
 
799
 *      None.
 
800
 *
 
801
 *----------------------------------------------------------------------------
 
802
 */
 
803
 
 
804
static Bool
 
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
 
812
{
 
813
   struct dirent *cpuEntry;
 
814
   DIR *cpuDir;
 
815
   struct dirent *cstateEntry;
 
816
   char pathname[PATH_MAX + 1];
 
817
   uint32 cpu = 0;
 
818
   uint32 cl = 0;
 
819
 
 
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])) {
 
824
         cpu++;
 
825
         if (cl != 0) {         /* already found the number of c states */
 
826
            continue;
 
827
         }
 
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__));
 
831
            return FALSE;
 
832
         }
 
833
         cpuDir = Posix_OpenDir(pathname);
 
834
         if (cpuDir != NULL) {
 
835
            uint32 cnum;
 
836
 
 
837
            while ((cstateEntry = readdir(cpuDir))) {
 
838
               if (Str_Strncasecmp(cstateEntry->d_name, "state", 5) == 0 &&
 
839
                   sscanf(cstateEntry->d_name + 5, "%u", &cnum) == 1 &&
 
840
                   cnum > cl) {
 
841
                  cl = cnum;    /* state0 will be ignored */
 
842
               }
 
843
            }
 
844
            closedir(cpuDir);
 
845
         }
 
846
      }
 
847
   }
 
848
   if (cpu == 0 || cl == 0) {
 
849
      return FALSE;
 
850
   }
 
851
 
 
852
   if (*numCpus != cpu || *numCStates != cl) {
 
853
      if (!UtilAllocCStArrays(cpu, cl, transitns, residency, transTime,
 
854
                              residTime)) {
 
855
         return FALSE;
 
856
      }
 
857
      *numCpus = cpu;
 
858
      *numCStates = cl;
 
859
   }
 
860
 
 
861
   rewinddir(dir);
 
862
   cpu = 0;
 
863
   while ((cpuEntry = readdir(dir))) {
 
864
      int pathlen;
 
865
      VmTimeType timeUS;
 
866
 
 
867
      if (Str_Strncasecmp(cpuEntry->d_name, "cpu", 3) != 0 ||
 
868
          !isdigit(cpuEntry->d_name[3])) {
 
869
         continue;
 
870
      }
 
871
      pathlen = Str_Snprintf(pathname, sizeof pathname,
 
872
                             SYS_CSTATE_DIR"/%s/cpuidle", cpuEntry->d_name);
 
873
      if (pathlen <= 0) {
 
874
         LOG(0, ("%s: Str_Snprintf for '%s/cpuidle' failed\n", __FUNCTION__,
 
875
                 cpuEntry->d_name));
 
876
         return FALSE;
 
877
      }
 
878
      cpuDir = Posix_OpenDir(pathname);
 
879
      if (cpuDir == NULL) {
 
880
         LOG(0, ("%s: Failed to open directory %s\n", __FUNCTION__, pathname));
 
881
         continue;
 
882
      }
 
883
 
 
884
      /*
 
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.
 
890
       */
 
891
 
 
892
      while ((cstateEntry = readdir(cpuDir))) {
 
893
         FILE *statsFile;
 
894
         int result;
 
895
         uint32 index;
 
896
 
 
897
         if (Str_Strncasecmp(cstateEntry->d_name, "state", 5) != 0) {
 
898
            continue;
 
899
         }
 
900
         if (sscanf(cstateEntry->d_name + 5, "%u", &cl) != 1 || cl == 0) {
 
901
            continue;
 
902
         }
 
903
         cl--;          /* ignoring state0 -- cl == 0 -> state1 */
 
904
         index = *numCStates * cpu + cl;
 
905
 
 
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__));
 
909
            closedir(cpuDir);
 
910
            return FALSE;
 
911
         }
 
912
         statsFile = Posix_Fopen(pathname, "r");
 
913
         if (statsFile == NULL) {
 
914
            continue;
 
915
         }
 
916
         result = fscanf(statsFile, "%"FMT64"u", &(*transitns)[index]);
 
917
         fclose(statsFile);
 
918
         if (result <= 0) {
 
919
            continue;
 
920
         }
 
921
 
 
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__));
 
925
            closedir(cpuDir);
 
926
            return FALSE;
 
927
         }
 
928
         statsFile = Posix_Fopen(pathname, "r");
 
929
         if (statsFile == NULL) {
 
930
            continue;
 
931
         }
 
932
         result = fscanf(statsFile, "%"FMT64"u", &(*residency)[index]);
 
933
         fclose(statsFile);
 
934
         if (result <= 0) {
 
935
            continue;
 
936
         }
 
937
      }
 
938
      closedir(cpuDir);
 
939
 
 
940
      timeUS = Hostinfo_SystemTimerUS();
 
941
      if (timeUS <= 0) {
 
942
         LOG(0, ("%s: Hostinfo_SystemTimerUS() failed\n", __FUNCTION__));
 
943
         return FALSE;
 
944
      }
 
945
      (*transTime)[cpu] = timeUS;
 
946
      (*residTime)[cpu] = timeUS;
 
947
      cpu++;
 
948
   }
 
949
 
 
950
   return cpu > 0;
 
951
}
 
952
 
 
953
 
 
954
static Bool
 
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
 
962
{
 
963
   struct dirent *cpuEntry;
 
964
   uint32 cpu = 0;
 
965
 
 
966
   /* Determine the number of cpus. */
 
967
   while ((cpuEntry = readdir(dir))) {
 
968
      if (cpuEntry->d_name[0] != '.') {
 
969
         cpu++;
 
970
      }
 
971
   }
 
972
   if (cpu == 0) {
 
973
      return FALSE;
 
974
   }
 
975
 
 
976
   if (*numCpus != cpu) {
 
977
      /*
 
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.
 
980
       */
 
981
 
 
982
      if (!UtilAllocCStArrays(cpu, MAX_C_STATES, transitns, residency,
 
983
                              transTime, residTime)) {
 
984
         return FALSE;
 
985
      }
 
986
      *numCpus = cpu;
 
987
      *numCStates = 0;
 
988
   }
 
989
 
 
990
   rewinddir(dir);
 
991
   cpu = 0;
 
992
   while ((cpuEntry = readdir(dir))) {
 
993
      char pathname[PATH_MAX + 1];
 
994
      char *line;
 
995
      size_t lineSize;
 
996
      FILE *powerFile;
 
997
      uint32 cl;
 
998
      VmTimeType timeUS;
 
999
 
 
1000
      if (cpuEntry->d_name[0] == '.') {
 
1001
         continue;
 
1002
      }
 
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__,
 
1006
                 cpuEntry->d_name));
 
1007
         return FALSE;
 
1008
      }
 
1009
      powerFile = Posix_Fopen(pathname, "r");
 
1010
      if (powerFile == NULL) {
 
1011
         continue;
 
1012
      }
 
1013
 
 
1014
      cl = 0;
 
1015
      while (StdIO_ReadNextLine(powerFile, &line, 0, &lineSize)
 
1016
             == StdIO_Success) {
 
1017
         char *ptr;
 
1018
         uint32 index = *numCStates * cpu + cl;
 
1019
 
 
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]);
 
1024
               cl++;
 
1025
            }
 
1026
         }
 
1027
         free(line);
 
1028
      }
 
1029
      fclose(powerFile);
 
1030
 
 
1031
      timeUS = Hostinfo_SystemTimerUS();
 
1032
      if (timeUS <= 0) {
 
1033
         LOG(0, ("%s: Hostinfo_SystemTimerUS() failed\n", __FUNCTION__));
 
1034
         return FALSE;
 
1035
      }
 
1036
      (*transTime)[cpu] = timeUS;
 
1037
      (*residTime)[cpu] = (uint64)((double)timeUS * FREQ_ACPI);
 
1038
      if (*numCStates == 0) {
 
1039
         *numCStates = cl;
 
1040
      }
 
1041
      cpu++;
 
1042
   }
 
1043
   return cpu > 0 && *numCStates > 0;
 
1044
}
 
1045
 
 
1046
 
 
1047
/*
 
1048
 *----------------------------------------------------------------------------
 
1049
 *
 
1050
 * Util_QueryCStResidency --
 
1051
 *
 
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.
 
1054
 *
 
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
 
1062
 *                   residency)
 
1063
 *
 
1064
 *      If the dimensions specified are too small, the arrays are freed
 
1065
 *      and new memory allocated.
 
1066
 *
 
1067
 * Results:
 
1068
 *      TRUE if successful.
 
1069
 *
 
1070
 * Side Effects:
 
1071
 *      None.
 
1072
 *
 
1073
 *----------------------------------------------------------------------------
 
1074
 */
 
1075
 
 
1076
Bool
 
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
 
1083
{
 
1084
   DIR *dir;
 
1085
   Bool ret = FALSE;
 
1086
 
 
1087
   dir = Posix_OpenDir(SYS_CSTATE_DIR);
 
1088
   if (dir) {
 
1089
      ret = UtilReadSysCStRes(dir, numCpus, numCStates, transitns, residency,
 
1090
                              transTime, residTime);
 
1091
      closedir(dir);
 
1092
   }
 
1093
 
 
1094
   if (!ret) {
 
1095
      dir = Posix_OpenDir(PROC_CSTATE_DIR);
 
1096
      if (dir) {
 
1097
         ret = UtilReadProcCStRes(dir, numCpus, numCStates, transitns,
 
1098
                                  residency, transTime, residTime);
 
1099
         closedir(dir);
 
1100
      }
 
1101
   }
 
1102
 
 
1103
   return ret;
 
1104
}
 
1105
 
 
1106
#else   // #if defined(__linux__) && !defined(VMX86_SERVER)
 
1107
 
 
1108
Bool
 
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
 
1115
{
 
1116
   return FALSE;
 
1117
}
 
1118
#endif
 
1119
#endif  // #if defined(VMX86_STATS)