Fetcher

linux_proc

Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231
// -*- C++ -*-
//
// Package:     Services
// Class  :     ProcInfoFetcher
//
// Implementation:
//     [Notes on implementation]
//
// Original Author:  Chris Jones
//         Created:  Sun May  6 11:14:31 CDT 2012
//

// system include files

// user include files

#include <cstring>
#include <cassert>
#include <iostream>
#ifdef __linux__
#include <malloc.h>
#endif
#include <sstream>
//#include <stdio.h>
#include <string>

#include <fcntl.h>
#include <unistd.h>

#include "FWCore/Services/plugins/ProcInfoFetcher.h"
#include "FWCore/Utilities/interface/EDMException.h"
#include "FWCore/Utilities/interface/get_underlying_safe.h"
#include "FWCore/MessageLogger/interface/MessageLogger.h"

//
// constants, enums and typedefs
//

//
// static data member definitions
//

namespace {
  struct linux_proc {
    int pid;  // %d
    std::string comm;
    char state;                    // %c
    int ppid;                      // %d
    int pgrp;                      // %d
    int session;                   // %d
    int tty;                       // %d
    int tpgid;                     // %d
    unsigned int flags;            // %u [before linux 2.6 %lu]
    unsigned long minflt;          // %lu
    unsigned long cminflt;         // %lu
    unsigned long majflt;          // %lu
    unsigned long cmajflt;         // %lu
    unsigned long utime;           // %lu
    unsigned long stime;           // %lu
    long cutime;                   // %ld
    long cstime;                   // %ld
    long priority;                 // %ld
    long nice;                     // %ld
    long num_threads;              // %ld
    long itrealvalue;              // %ld
    unsigned long long starttime;  // %llu [before linux 2.6 %d]
    unsigned long vsize;           // %lu
    long rss;                      // %ld
    unsigned long rlim;            // %lu
    unsigned long startcode;       // %lu
    unsigned long endcode;         // %lu
    unsigned long startstack;      // %lu
    unsigned long kstkesp;         // %lu
    unsigned long kstkeip;         // %lu
    unsigned long signal;          // %lu
    unsigned long blocked;         // %lu
    unsigned long sigignore;       // %lu
    unsigned long sigcatch;        // %lu
    unsigned long wchan;           // %lu
  };

  class Fetcher {
  public:
    friend Fetcher& operator>>(Fetcher&, int&);
    friend Fetcher& operator>>(Fetcher&, long&);
    friend Fetcher& operator>>(Fetcher&, unsigned int&);
    friend Fetcher& operator>>(Fetcher&, unsigned long&);
    friend Fetcher& operator>>(Fetcher&, unsigned long long&);
    friend Fetcher& operator>>(Fetcher&, char&);
    friend Fetcher& operator>>(Fetcher&, std::string&);

    explicit Fetcher(char* buffer) : buffer_(buffer), save_(nullptr), delims_(" \t\n\f\v\r") {}

  private:
    int getInt() {
      const char* t = getItem();
      //std::cout <<"int '"<<t <<"'"<<std::endl;
      return std::stoi(t);
    }
    long getLong() {
      const char* t = getItem();
      //std::cout <<"long '"<<t <<"'"<<std::endl;
      return std::stol(t);
    }
    unsigned int getUInt() {
      const char* t = getItem();
      //std::cout <<"uint '"<<t <<"'"<<std::endl;
      return std::stoul(t);
    }
    unsigned long getULong() {
      const char* t = getItem();
      //std::cout <<"ulong '"<<t <<"'"<<std::endl;
      return std::stoul(t);
    }
    unsigned long long getULongLong() {
      const char* t = getItem();
      //std::cout <<"ulong '"<<t <<"'"<<std::endl;
      return std::stoull(t);
    }
    char getChar() { return *getItem(); }
    std::string getString() { return std::string(getItem()); }
    char* getItem() {
      char* item = strtok_r(buffer_, delims_, &save());
      assert(item);
      buffer_ = nullptr;  // Null for subsequent strtok_r calls.
      return item;
    }

    char const* save() const { return get_underlying_safe(save_); }
    char*& save() { return get_underlying_safe(save_); }

    edm::propagate_const<char*> buffer_;
    edm::propagate_const<char*> save_;
    char const* const delims_;
  };

  Fetcher& operator>>(Fetcher& iFetch, int& oValue) {
    oValue = iFetch.getInt();
    return iFetch;
  }
  Fetcher& operator>>(Fetcher& iFetch, long& oValue) {
    oValue = iFetch.getLong();
    return iFetch;
  }
  Fetcher& operator>>(Fetcher& iFetch, unsigned int& oValue) {
    oValue = iFetch.getUInt();
    return iFetch;
  }
  Fetcher& operator>>(Fetcher& iFetch, unsigned long& oValue) {
    oValue = iFetch.getULong();
    return iFetch;
  }
  Fetcher& operator>>(Fetcher& iFetch, unsigned long long& oValue) {
    oValue = iFetch.getULongLong();
    return iFetch;
  }
  Fetcher& operator>>(Fetcher& iFetch, char& oValue) {
    oValue = iFetch.getChar();
    return iFetch;
  }
  Fetcher& operator>>(Fetcher& iFetch, std::string& oValue) {
    oValue = iFetch.getString();
    return iFetch;
  }
}  // namespace

namespace edm {
  namespace service {

    ProcInfoFetcher::ProcInfoFetcher() : pg_size_(sysconf(_SC_PAGESIZE)) {
#ifdef __linux__
      std::ostringstream ost;
      ost << "/proc/" << getpid() << "/stat";

      if ((fd_ = open(ost.str().c_str(), O_RDONLY)) < 0) {
        throw Exception(errors::Configuration) << "Failed to open " << ost.str() << std::endl;
      }
#endif
    }
    ProcInfoFetcher::~ProcInfoFetcher() {
#ifdef LINUX
      close(fd_);
#endif
    }
    ProcInfo ProcInfoFetcher::fetch() const {
      ProcInfo ret;

#ifdef __linux__
      double pr_size = 0.0, pr_rssize = 0.0;

      linux_proc pinfo;
      int cnt;

      lseek(fd_, 0, SEEK_SET);

      if ((cnt = read(fd_, buf_, sizeof(buf_) - 1)) < 0) {
        perror("Read of Proc file failed:");
        return ProcInfo();
      }

      if (cnt > 0) {
        buf_[cnt] = '\0';

        try {
          Fetcher fetcher(buf_);
          fetcher >> pinfo.pid >> pinfo.comm >> pinfo.state >> pinfo.ppid >> pinfo.pgrp >> pinfo.session >> pinfo.tty >>
              pinfo.tpgid >> pinfo.flags >> pinfo.minflt >> pinfo.cminflt >> pinfo.majflt >> pinfo.cmajflt >>
              pinfo.utime >> pinfo.stime >> pinfo.cutime >> pinfo.cstime >> pinfo.priority >> pinfo.nice >>
              pinfo.num_threads >> pinfo.itrealvalue >> pinfo.starttime >> pinfo.vsize >> pinfo.rss >> pinfo.rlim >>
              pinfo.startcode >> pinfo.endcode >> pinfo.startstack >> pinfo.kstkesp >> pinfo.kstkeip >> pinfo.signal >>
              pinfo.blocked >> pinfo.sigignore >> pinfo.sigcatch >> pinfo.wchan;
        } catch (const std::exception& iE) {
          LogWarning("ProcInfoFetcher") << "Parsing of Prof file failed:" << iE.what() << std::endl;
          return ProcInfo();
        }

        // resident set size in pages
        pr_size = (double)pinfo.vsize;
        pr_rssize = (double)pinfo.rss;

        ret.vsize = pr_size / (1024.0 * 1024.0);
        ret.rss = (pr_rssize * pg_size_) / (1024.0 * 1024.0);
      }
#else
      ret.vsize = 0;
      ret.rss = 0;
#endif
      return ret;
    }
  }  // namespace service
}  // namespace edm