~siborgium/prelockdpp

6cfa14c90ff51537bddaf5ec6a635cf62fc4bec7 — Sergey Smirnykh 2 years ago 846bf17
Efficient get_uptime
1 files changed, 56 insertions(+), 0 deletions(-)

M main.cpp
M main.cpp => main.cpp +56 -0
@@ 1,5 1,6 @@
#include <iostream>
#include <fstream>
#include <limits>
#include <charconv>
#include <string>
#include <string_view>


@@ 9,9 10,11 @@
#include <cstring>

#include <dirent.h>
#include <fcntl.h>
#include <sys/epoll.h>
#include <sys/mman.h>
#include <sys/signalfd.h>
#include <sys/stat.h>
#include <sys/timerfd.h>
#include <sys/types.h>
#include <signal.h>


@@ 68,6 71,7 @@ struct sc_info {
struct base_fd {
    int fd;

    base_fd(int fd): fd{ fd } {}
    base_fd() = default;
    base_fd(base_fd&&) = delete;
    base_fd(const base_fd&) = delete;


@@ 143,6 147,56 @@ struct context {
            throw std::runtime_error{ concat("mlockall failed ", errno_) };
        }
    }
    auto get_uptime() {
        // FIXME: proper open, avoid streams
        int fd = open("/proc/uptime", O_RDONLY);
        if (fd == -1) {
            throw errno_exception("open(/proc/uptime) failed", errno);
        }
        base_fd guard { fd };

        // see /fs/proc/uptime.c
        // time is encoded as %lu.%2lu ...
        constexpr auto max_len = std::numeric_limits<unsigned long>::digits10 + 2;
        constexpr auto buf_size = max_len * 2 + 4;
        char buffer[buf_size]; // two full lu's + a digit + some extra just in case
        ssize_t total = 0;
        while (total < buf_size) {
            auto r = read(fd, buffer + total, buf_size - total);
            if (r < 0) {
                throw errno_exception("read(/proc/uptime) failed", errno);
            }
            if (!r) {
                break;
            }
            total += r;
        }

        auto from_chars = [&](auto begin, auto end, auto& out) {
            if (auto [_, ec] = std::from_chars(begin, end, out); ec != std::errc()) {
                throw std::runtime_error{ "Failed to read /proc/uptime value" };
            }
        };

        if (total > 0) {
            auto begin = buffer;
            auto end = begin + total;

            auto end1 = std::find(begin, end, '.');
            if (end1 == end) {
                throw std::logic_error{ "Unexpected /proc/uptime fmt" };
            }

            unsigned long sec, nsec;
            from_chars(begin, end1, sec);
            from_chars(end1 + 1, end, nsec);
            timespec uptime;
            uptime.tv_sec = sec;
            uptime.tv_nsec = nsec;
            return uptime;
        }
        throw std::logic_error{ "read(/proc/uptime) was empty" };
    }
    auto const& get_pid_list() {
        pids.clear();



@@ 185,9 239,11 @@ struct context {
        if (clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &p0)) {
            throw errno_exception("clock_gettime(PROCESS_CPUTIME) failed", errno);
        }
        auto uptime = get_uptime();
        for (auto&& pid: get_pid_list()) {
            std::cout << pid << '\n';
        }
        std::cout << "Uptime: " << uptime.tv_sec << '.' << uptime.tv_nsec << '\n';

    }
};