6

Is there a way to get this information from the /proc directory? I want to be able to get how long each process has been running on seconds.

EDIT: I needed to do this from C++. Sorry for the confusion.

kmdent
  • 1,577
  • 16
  • 32

7 Answers7

8

Okay guys, so after reading the top command's source code, I figured out a non-hacky way of getting the start time of a process. The formula that they use is:

Process_Time = (current_time - boot_time) - (process_start_time)/HZ.

(You have to divide by HZ because process_start_time is in jiffies)

Obtaining these values:

  • current_time - You can get this from the C command gettimeofday().
  • boot_time - This value is located in /proc/uptime. This file contains two numbers: the uptime of the system (seconds), and the amount of time spent in idle process (seconds). Take the first.
  • process_start_time - This value is located in /proc/[PID]/stat. The time difference (in jiffies) between system boot and when the process started. (The 22nd value in the file if you split on whitespace).

The code (Sorry, I sometimes mix c and c++):

  int fd;
  char buff[128];
  char *p;
  unsigned long uptime;
  struct timeval tv;
  static time_t boottime;


  if ((fd = open("/proc/uptime", 0)) != -1)
  {
    if (read(fd, buff, sizeof(buff)) > 0)
    {
      uptime = strtoul(buff, &p, 10);
      gettimeofday(&tv, 0);
      boottime = tv.tv_sec - uptime;

    }
    close(fd);
  }


ifstream procFile;
procFile.open("/proc/[INSERT PID HERE]/stat");

char str[255];
procFile.getline(str, 255);  // delim defaults to '\n'


vector<string> tmp;
istringstream iss(str);
copy(istream_iterator<string>(iss),
     istream_iterator<string>(),
     back_inserter<vector<string> >(tmp));

process_time = (now - boottime) - (atof(tmp.at(21).c_str()))/HZ;

Happy Coding!

Brad Mace
  • 27,194
  • 17
  • 102
  • 148
kmdent
  • 1,577
  • 16
  • 32
  • Thank you for the snippet. While implementing my own version, I realized that there is no need to grab the current time. The formula is simply up_time - process_start_time / HZ. – user1995488 Sep 02 '20 at 18:40
  • I have seen on a PaaS called codeanywhere that the boottime counts in millions, but the /proc/uptime or CLOCK_MONOTONIC is the proper uptime. This will give you bad results. To get the uptime in integer use sysinfo, to get uptime in floating point, you have to read /proc/uptime (file handling is a little bit more overhead) – 15 Volts Jan 30 '21 at 07:09
  • In case if anyone wants to use this idea, please refer [this](https://rextester.com/JLA60581) – P0W Jan 28 '22 at 10:40
3

You can do stat /proc/{processid} to see the creation time at the shell.

EDIT: fstat on that folder should give you what you want (the creation time).

Femi
  • 64,273
  • 8
  • 118
  • 148
  • Good Call. Didn't think to check when the folder was created. Thanks! – kmdent Jun 29 '11 at 00:06
  • I don't think it gives you folder creation time. It gives you change time, modify time, and access time. None of which are give you the time the folder was created. – kmdent Jun 29 '11 at 16:59
  • @kmdent: by default you don't get the creation time because not all filesystems support it, but see http://stackoverflow.com/questions/5929419/how-to-get-file-creation-date-in-linux for a potential solution that does give you creation time. – Femi Jun 29 '11 at 18:20
1

Let's break down what you're trying to do:

  1. Get the time the file was modified.
  2. Convert the time into Unix time.
  3. Subtract the two times.

So, in order to get the current time, we can run:

#include <cstdio>
#include <cstdlib>
char *command;
int process_number = 1; // init process.
SYSTEM ("mkfifo time_pipe");
sprintf (command, "stat /proc/%d -printf="%%X" > time_pipe", process_number); // get the command to run.
// since this directory is created once it starts, we know it is the start time (about)
// note the %%, which means to print a literal %
SYSTEM (command); // run the command.

Now, the next step is parsing it to Unix time -- but we don't have to! The %X specifier actually converts it to Unix Time. So next step would be to (a) get the current time (b) subtract the times:

timeval cur_time;
double current_time, time_passed;
char read_time[11]; // 32 bit overflows = only 11 digits.
FILE *ourpipe;
gettimeofday(&cur_time, NULL);
current_time = cur_time.tv_sec + (cur_time.tv_usec * 1000000.0);
// usec stands for mu second, i.e., a millionth of a second. I wasn't there when they named this stuff.
ourpipe = fopen ("time_pipe", "rb"); 
fread(read_time, sizeof (char), 10, ourpipe);
time_passed = current_time - atoi (read_time);
fclose (ourpipe);

So yeah, that's pretty much it. The pipe is needed to get the input from one to the other.

Arka
  • 837
  • 4
  • 8
  • Modify time is different from creation time. Stat gives modify time, access time, and change time.This wont actually give you the process creation time. Do you agree? – kmdent Jun 29 '11 at 17:03
  • @kmdent Yes, you seem to be right. I suppose the alternative would be: `ps -eo pid,etime` (to return the pid's elapsed time). I'll update my post accordingly. – Arka Jun 29 '11 at 17:28
0

Old topic this, but since I was working on the same issues, I thought I might post my response. Perhaps it would be useful for someone else. Note, this code should not be used in a serious production environment, but as a quick and dirty way to get what the OP is looking for, I think this would be sufficient. Note that this code is the same code as OP posted in response to his own question, but it is modified to be able to be directly compiled when you copy it from stackexchange, his code was not directly able to compile.

This code compile, and I've added a few extra functions.

Instructions: Start any program, then do a 'ps aux | programname' to get its pid. It's the second column from the left. Now input that number to pid in the main function and compile the program. Now, when running the program, the output will be something like:

Lapsed: days: 0 , hours: 0 , min: 5 , seconds: 58

//Original code credit by kmdent.
//http://stackoverflow.com/questions/6514378/how-do-you-get-how-long-a-process-has-been-running
#include <iostream>
#include <iterator>
#include <sstream>
#include <fstream>
#include <vector>
#include <cstring>
#include <cerrno>
#include <ctime>
#include <cstdio>
#include <fcntl.h>
#include <sys/time.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdlib.h>
#include <string>
#include "/usr/include/x86_64-linux-gnu/sys/param.h"

using namespace std;


template <class T>
inline std::string to_string (const T& t)
{
    std::stringstream ss;
    ss << t;
    return ss.str();
}

//Return the number of seconds a process has been running.
long lapsed(string pid) {

    int fd;
    char buff[128];
    char *p;
    unsigned long uptime;
    struct timeval tv;
    static time_t boottime;


    if ((fd = open("/proc/uptime", 0)) != -1) {
    if (read(fd, buff, sizeof(buff)) > 0) {
      uptime = strtoul(buff, &p, 10);
      gettimeofday(&tv, 0);
      boottime = tv.tv_sec - uptime;
    }
        close(fd);
    }

    ifstream procFile;
    string f = "/proc/"+pid+"/stat";
    procFile.open(f.c_str());

    char str[255];
    procFile.getline(str, 255);  // delim defaults to '\n'

    vector<string> tmp;
    istringstream iss(str);
    copy(istream_iterator<string>(iss),
         istream_iterator<string>(),
         back_inserter<vector<string> >(tmp));

    std::time_t now = std::time(0);
    std::time_t lapsed = ((now - boottime) - (atof(tmp.at(21).c_str()))/HZ);
    return lapsed;

}

string human_readable_lapsed(long input_seconds) {
    //Credit: http://www.cplusplus.com/forum/beginner/14357/
     long days = input_seconds / 60 / 60 / 24;
     int hours = (input_seconds / 60 / 60) % 24;
     int minutes = (input_seconds / 60) % 60;
     int seconds = input_seconds % 60;

     return "days: " + to_string(days) + " , hours: " + to_string(hours) + " , min: " + to_string(minutes) + " , seconds: " + to_string(seconds);
}

int main(int argc, char* argv[])
{
    //Pid to get total running time for.
    string pid = "13875";
    std::cout << "Lapsed: " << human_readable_lapsed(lapsed(pid)) << std::endl;
    return 0;
}
NordicViking
  • 131
  • 4
0

The time command will give you that info:

> man 1 time

Command-line arguments will make it return

%S     Total number of CPU-seconds that the  process  spent  in  kernel mode.
%U     Total number of CPU-seconds that the process spent in user mode.
%P     Percentage of the CPU that this job got

You can call system( char *command ) to execute the command from your prog.

Pete Wilson
  • 8,610
  • 6
  • 39
  • 51
0

/proc/{processid} # Good idea!

But why not just read /proc/{processid}/stat, and simply get whatever statistics you want?

from "man proc":

...
       stat   kernel/system statistics

          cpu  3357 0 4313 1362393
                 The number of jiffies (1/100ths of a second)
                 that the system spent in user mode, user
                 mode with low priority (nice), system mode,
                 and the idle task, respectively.  The last
                 value should be 100 times the second entry
                 in the uptime pseudo-file.

          disk 0 0 0 0
                 The four disk entries are not implemented at
                 this time.  I'm not even sure what this
                 should be, since kernel statistics on other
                 machines usually track both transfer rate
                 and I/Os per second and this only allows for
                 one field per drive.

...

paulsm4
  • 114,292
  • 17
  • 138
  • 190
0

This is how I implemented it in C++ with Qt: https://github.com/carlonluca/procweb/blob/756cc3607250057520bc107cb612b2b1d40d1cd0/procweb-qt/pwsampler.cpp#L141.

  1. Read file /proc/<pid>/stat.
  2. Take the value at index 21.
  3. Read system uptime [1].
  4. Read clock ticks per second with sysconf(_SC_CLK_TCK).
  5. Compute uptime - startTime.
qint64 startTime = 0;
if (procStatValues.size() > 21)
    if (long int clockTick = sysconf(_SC_CLK_TCK))
        startTime = qRound64(lqt::string_to_uint64(procStatValues[21], 0)/static_cast<double>(clockTick))*1000;

[1]

std::optional<quint64> PWSampler::readSysUptimeMillis()
{
    QFile f(QSL("/proc/uptime"));
    if (!f.open(QIODevice::ReadOnly)) {
        qWarning() << "Could not open /proc/uptime";
        return std::nullopt;
    }

    QString s = f.readAll();
    QStringList tokens = s.split(' ');
    if (tokens.size() != 2) {
        qWarning() << "Cannot parse /proc/uptime content";
        return std::nullopt;
    }

    double uptimeSecs = lqt::string_to_float(tokens[0], -1);
    if (uptimeSecs < 0) {
        qWarning() << "Cannot parse /proc/uptime content";
        return std::nullopt;
    }

    return qRound64(uptimeSecs*1000);
}
Luca Carlon
  • 9,546
  • 13
  • 59
  • 91