openpilot is an open source driver assistance system. openpilot performs the functions of Automated Lane Centering and Adaptive Cruise Control for over 200 supported car makes and models.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

245 lines
7.5 KiB

#include <cstdio>
#include <cstdlib>
#include <climits>
#include <cassert>
#include <unistd.h>
#include <dirent.h>
#include <vector>
#include <string>
#include <memory>
#include <utility>
#include <sstream>
#include <fstream>
#include <algorithm>
#include <functional>
#include <unordered_map>
#include <zmq.h>
#include <capnp/serialize.h>
#include "cereal/gen/cpp/log.capnp.h"
#include "common/timing.h"
#include "common/utilpp.h"
namespace {
struct ProcCache {
std::string name;
std::vector<std::string> cmdline;
std::string exe;
};
}
int main() {
int err;
void *context = zmq_ctx_new();
void *publisher = zmq_socket(context, ZMQ_PUB);
err = zmq_bind(publisher, "tcp://*:8031");
assert(err == 0);
double jiffy = sysconf(_SC_CLK_TCK);
size_t page_size = sysconf(_SC_PAGE_SIZE);
std::unordered_map<pid_t, ProcCache> proc_cache;
while (1) {
capnp::MallocMessageBuilder msg;
cereal::Event::Builder event = msg.initRoot<cereal::Event>();
event.setLogMonoTime(nanos_since_boot());
auto procLog = event.initProcLog();
auto orphanage = msg.getOrphanage();
// stat
{
std::vector<capnp::Orphan<cereal::ProcLog::CPUTimes>> otimes;
std::ifstream sstat("/proc/stat");
std::string stat_line;
while (std::getline(sstat, stat_line)) {
if (util::starts_with(stat_line, "cpu ")) {
// cpu total
} else if (util::starts_with(stat_line, "cpu")) {
// specific cpu
int id;
unsigned long utime, ntime, stime, itime;
unsigned long iowtime, irqtime, sirqtime;
int count = sscanf(stat_line.data(), "cpu%d %lu %lu %lu %lu %lu %lu %lu",
&id, &utime, &ntime, &stime, &itime, &iowtime, &irqtime, &sirqtime);
auto ltimeo = orphanage.newOrphan<cereal::ProcLog::CPUTimes>();
auto ltime = ltimeo.get();
ltime.setCpuNum(id);
ltime.setUser(utime / jiffy);
ltime.setNice(ntime / jiffy);
ltime.setSystem(stime / jiffy);
ltime.setIdle(itime / jiffy);
ltime.setIowait(iowtime / jiffy);
ltime.setIrq(irqtime / jiffy);
ltime.setSoftirq(irqtime / jiffy);
otimes.push_back(std::move(ltimeo));
} else {
break;
}
}
auto ltimes = procLog.initCpuTimes(otimes.size());
for (size_t i = 0; i < otimes.size(); i++) {
ltimes.adoptWithCaveats(i, std::move(otimes[i]));
}
}
// meminfo
{
auto mem = procLog.initMem();
std::ifstream smem("/proc/meminfo");
std::string mem_line;
uint64_t mem_total = 0, mem_free = 0, mem_available = 0, mem_buffers = 0;
uint64_t mem_cached = 0, mem_active = 0, mem_inactive = 0, mem_shared = 0;
while (std::getline(smem, mem_line)) {
if (util::starts_with(mem_line, "MemTotal:")) sscanf(mem_line.data(), "MemTotal: %lu kB", &mem_total);
else if (util::starts_with(mem_line, "MemFree:")) sscanf(mem_line.data(), "MemFree: %lu kB", &mem_free);
else if (util::starts_with(mem_line, "MemAvailable:")) sscanf(mem_line.data(), "MemAvailable: %lu kB", &mem_available);
else if (util::starts_with(mem_line, "Buffers:")) sscanf(mem_line.data(), "Buffers: %lu kB", &mem_buffers);
else if (util::starts_with(mem_line, "Cached:")) sscanf(mem_line.data(), "Cached: %lu kB", &mem_cached);
else if (util::starts_with(mem_line, "Active:")) sscanf(mem_line.data(), "Active: %lu kB", &mem_active);
else if (util::starts_with(mem_line, "Inactive:")) sscanf(mem_line.data(), "Inactive: %lu kB", &mem_inactive);
else if (util::starts_with(mem_line, "Shmem:")) sscanf(mem_line.data(), "Shmem: %lu kB", &mem_shared);
}
mem.setTotal(mem_total * 1024);
mem.setFree(mem_free * 1024);
mem.setAvailable(mem_available * 1024);
mem.setBuffers(mem_buffers * 1024);
mem.setCached(mem_cached * 1024);
mem.setActive(mem_active * 1024);
mem.setInactive(mem_inactive * 1024);
mem.setShared(mem_shared * 1024);
}
// processes
{
std::vector<capnp::Orphan<cereal::ProcLog::Process>> oprocs;
struct dirent *de = NULL;
DIR *d = opendir("/proc");
assert(d);
while ((de = readdir(d))) {
if (!isdigit(de->d_name[0])) continue;
pid_t pid = atoi(de->d_name);
auto lproco = orphanage.newOrphan<cereal::ProcLog::Process>();
auto lproc = lproco.get();
lproc.setPid(pid);
char tcomm[PATH_MAX] = {0};
{
std::string stat = util::read_file(util::string_format("/proc/%d/stat", pid));
char state;
int ppid;
unsigned long utime, stime;
long cutime, cstime, priority, nice, num_threads;
unsigned long long starttime;
unsigned long vms, rss;
int processor;
int count = sscanf(stat.data(),
"%*d (%1024[^)]) %c %d %*d %*d %*d %*d %*d %*d %*d %*d %*d "
"%lu %lu %ld %ld %ld %ld %ld %*d %lld "
"%lu %lu %*d %*d %*d %*d %*d %*d %*d "
"%*d %*d %*d %*d %*d %*d %*d %d",
tcomm, &state, &ppid,
&utime, &stime, &cutime, &cstime, &priority, &nice, &num_threads, &starttime,
&vms, &rss, &processor);
if (count != 14) continue;
lproc.setState(state);
lproc.setPpid(ppid);
lproc.setCpuUser(utime / jiffy);
lproc.setCpuSystem(stime / jiffy);
lproc.setCpuChildrenUser(cutime / jiffy);
lproc.setCpuChildrenSystem(cstime / jiffy);
lproc.setPriority(priority);
lproc.setNice(nice);
lproc.setNumThreads(num_threads);
lproc.setStartTime(starttime / jiffy);
lproc.setMemVms(vms);
lproc.setMemRss((uint64_t)rss * page_size);
lproc.setProcessor(processor);
}
std::string name(tcomm);
lproc.setName(name);
// populate other things from cache
auto cache_it = proc_cache.find(pid);
ProcCache cache;
if (cache_it != proc_cache.end()) {
cache = cache_it->second;
}
if (cache_it == proc_cache.end() || cache.name != name) {
cache = (ProcCache){
.name = name,
.exe = util::readlink(util::string_format("/proc/%d/exe", pid)),
};
// null-delimited cmdline arguments to vector
std::string cmdline_s = util::read_file(util::string_format("/proc/%d/cmdline", pid));
const char* cmdline_p = cmdline_s.c_str();
const char* cmdline_ep = cmdline_p + cmdline_s.size();
// strip trailing null bytes
while ((cmdline_ep-1) > cmdline_p && *(cmdline_ep-1) == 0) {
cmdline_ep--;
}
while (cmdline_p < cmdline_ep) {
std::string arg(cmdline_p);
cache.cmdline.push_back(arg);
cmdline_p += arg.size() + 1;
}
proc_cache[pid] = cache;
}
auto lcmdline = lproc.initCmdline(cache.cmdline.size());
for (size_t i = 0; i < lcmdline.size(); i++) {
lcmdline.set(i, cache.cmdline[i]);
}
lproc.setExe(cache.exe);
oprocs.push_back(std::move(lproco));
}
closedir(d);
auto lprocs = procLog.initProcs(oprocs.size());
for (size_t i = 0; i < oprocs.size(); i++) {
lprocs.adoptWithCaveats(i, std::move(oprocs[i]));
}
}
auto words = capnp::messageToFlatArray(msg);
auto bytes = words.asBytes();
zmq_send(publisher, bytes.begin(), bytes.size(), 0);
usleep(2000000); // 2 secs
}
return 0;
}