citrun

watch C/C++ source code execute
Log | Files | Refs | LICENSE

commit adae8b96bef786868c54f441f82e9f77320cce93
parent 7c72a249aa0ae8e452852e223e0cab463974945c
Author: Kyle Milz <kyle@0x30.net>
Date:   Fri,  9 Dec 2016 00:19:05 -0700

src: sync process file with runtime

Diffstat:
Msrc/gl_main.cc | 18+++++++++---------
Msrc/process_file.cc | 214++++++++++++++++++++++++++++++++++++++++++++-----------------------------------
Msrc/process_file.h | 83+++++++++++++++++++++++++++++++++++--------------------------------------------
3 files changed, 165 insertions(+), 150 deletions(-)

diff --git a/src/gl_main.cc b/src/gl_main.cc @@ -83,11 +83,11 @@ add_new_process(std::string const &file_name) demo_buffer_clear(buffer); std::stringstream ss; - ss << "program name:\t" << pfile->m_progname << std::endl; + ss << "program name:\t" << pfile->progname() << std::endl; ss << "trnsltn units:\t" << pfile->m_tus.size() << std::endl; - ss << "process id:\t" << pfile->m_pid << std::endl; - ss << "parent pid:\t" << pfile->m_ppid << std::endl; - ss << "process group:\t" << pfile->m_pgrp << std::endl; + ss << "process id:\t" << pfile->getpid() << std::endl; + ss << "parent pid:\t" << pfile->getppid() << std::endl; + ss << "process group:\t" << pfile->getpgrp() << std::endl; glyphy_point_t cur_pos = { 0, 0 }; demo_buffer_move_to(buffer, &cur_pos); @@ -98,7 +98,7 @@ add_new_process(std::string const &file_name) cur_pos.x = 0; for (auto &t : pfile->m_tus) { - demo_buffer_add_text(buffer, t.comp_file_path.c_str(), font, 1); + demo_buffer_add_text(buffer, t.comp_file_path().c_str(), font, 1); } } @@ -112,15 +112,15 @@ next_frame(View *vu) delete new_files; for (auto &rp : drawables) { - rp.read_executions(); + // rp.read_executions(); //glyphy_point_t tmp; for (auto &t : rp.m_tus) { //size_t bytes_total = t.num_lines * sizeof(uint64_t); - for (unsigned int i = 0; i < t.num_lines; i++) { - if (t.exec_counts[i] == 0) - continue; + for (unsigned int i = 0; i < t.num_lines(); i++) { + //if (t.exec_counts[i] == 0) + // continue; // demo_buffer_add_text(buffer, ">>", font, 1); } diff --git a/src/process_file.cc b/src/process_file.cc @@ -18,138 +18,144 @@ #include <cassert> #include <csignal> // kill +#include <cstring> // strncmp #include <err.h> #include <fcntl.h> // O_RDONLY #include <fstream> +#include <iostream> #include <stdlib.h> // getenv +#include <string.h> // memcpy #include <unistd.h> // getpagesize #include "process_file.h" +#include "rt.h" // struct citrun_{node,header} #include "version.h" // citrun_major -ProcessFile::ProcessFile(std::string const &path) : - m_path(path), - m_fd(0), - m_mem(NULL), - m_pos(0), - m_tus_with_execs(0), - m_program_loc(0) +// +// Take a pointer to a shared memory region and map data structures on top. +// Automatically increments the pointer once we know how big this region is. +// +TranslationUnit::TranslationUnit(void* &mem) : + m_node(static_cast<struct citrun_node *>(mem)), + m_data((unsigned long long *)(m_node + 1)), + m_data_buffer(new uint64_t[m_node->size]()) { - if ((m_fd = open(m_path.c_str(), O_RDONLY, S_IRUSR | S_IWUSR)) < 0) - err(1, "open"); - - struct stat sb; - fstat(m_fd, &sb); - - if (sb.st_size > 1024 * 1024 * 1024) - errx(1, "shared memory too large: %lli", sb.st_size); - - m_mem = (uint8_t *)mmap(NULL, sb.st_size, PROT_READ, MAP_SHARED, m_fd, 0); - if (m_mem == MAP_FAILED) - err(1, "mmap"); - - m_size = sb.st_size; - - std::string magic; - assert(sizeof(pid_t) == 4); - - shm_read_magic(magic); - assert(magic == "citrun"); - shm_read_all(&m_major); - assert(m_major == citrun_major); - shm_read_all(&m_minor); - shm_read_all(&m_pid); - shm_read_all(&m_ppid); - shm_read_all(&m_pgrp); - shm_read_string(m_progname); - shm_read_string(m_cwd); - shm_next_page(); - - while (shm_at_end() == false) { - TranslationUnit t; + unsigned int size, page_mask; - shm_read_all(&t.num_lines); + // Total size is node size plus live execution data size. + size = sizeof(struct citrun_node); + size += m_node->size * sizeof(unsigned long long); - shm_read_string(t.comp_file_path); - shm_read_string(t.abs_file_path); + // Increment passed in pointer to next page. + page_mask = getpagesize() - 1; + mem = (char *)mem + ((size + page_mask) & ~page_mask); - t.exec_counts = (uint64_t *)shm_get_block(t.num_lines * 8); - t.exec_counts_last = new uint64_t[t.num_lines](); - - t.source.resize(t.num_lines); - m_program_loc += t.num_lines; - read_source(t); + read_source(); +} - m_tus.push_back(t); +// +// Returns number of lines that citrun-inst processed (whole source file +// ideally) +// +unsigned int +TranslationUnit::num_lines() const +{ + return m_node->size; +} - shm_next_page(); - } +// +// Returns the source file path as it was passed to the compiler. +// +std::string +TranslationUnit::comp_file_path() const +{ + return std::string(m_node->comp_file_path); } +// +// Try and read the contents of the on disk source file using the absolute path +// provided by clang/llvm. +// void -ProcessFile::read_source(struct TranslationUnit &t) +TranslationUnit::read_source() { - std::ifstream file_stream(t.abs_file_path); + std::ifstream file_stream(m_node->abs_file_path); if (file_stream.is_open() == 0) { - warnx("ifstream.open(%s)", t.abs_file_path.c_str()); + warnx("ifstream.open(%s)", m_node->abs_file_path); return; } - for (auto &l : t.source) - std::getline(file_stream, l); + std::string line; + while (std::getline(file_stream, line)) + m_source.push_back(line); } +// +// Copy live executions to secondary buffer. Used for computing deltas later. +// void -ProcessFile::shm_next_page() +TranslationUnit::save_executions() { - int page_size = getpagesize(); - m_pos += page_size - (m_pos % page_size); + memcpy(m_data_buffer, m_data, m_node->size * sizeof(unsigned long long)); } -void -ProcessFile::shm_read_magic(std::string &magic) + +// +// Take a filesystem path and memory map its contents. Map at least a header +// structure on top of it. +// +ProcessFile::ProcessFile(std::string const &path) : + m_path(path), + m_fd(0), + m_tus_with_execs(0), + m_program_loc(0) { - magic.resize(6); + struct stat sb; + void *mem, *end; - memcpy(&magic[0], m_mem + m_pos, 6); - m_pos += 6; -} + if ((m_fd = open(m_path.c_str(), O_RDONLY, S_IRUSR | S_IWUSR)) < 0) + err(1, "open"); -void -ProcessFile::shm_read_string(std::string &str) -{ - uint16_t len; + if (fstat(m_fd, &sb) < 0) + err(1, "fstat"); - memcpy(&len, m_mem + m_pos, sizeof(len)); - m_pos += sizeof(len); + if (sb.st_size > 1024 * 1024 * 1024) + errx(1, "shared memory too large: %lli", sb.st_size); - str.resize(len); - memcpy(&str[0], m_mem + m_pos, len); - m_pos += len; -} + m_size = sb.st_size; -void * -ProcessFile::shm_get_block(size_t inc) -{ - void *block = m_mem + m_pos; - m_pos += inc; + mem = mmap(NULL, sb.st_size, PROT_READ, MAP_SHARED, m_fd, 0); + if (mem == MAP_FAILED) + err(1, "mmap"); - return block; -} -bool -ProcessFile::shm_at_end() -{ - assert(m_pos <= m_size); - return (m_pos == m_size ? true : false); + // Header is always at offset 0 and always one page long. + m_header = static_cast<struct citrun_header *>(mem); + + end = (char *)mem + m_size; + mem = (char *)mem + getpagesize(); + + assert(std::strncmp(m_header->magic, "ctrn", 4) == 0); + assert(m_header->major == citrun_major); + + while (mem < end) + m_tus.push_back(TranslationUnit(mem)); + // Make sure internal increment in TranslationUnit works as intended. + assert(mem == end); + + for (auto &t : m_tus) + m_program_loc += t.num_lines(); } +// +// Checks if the pid given by the runtime is alive. Prone to race conditions. +// bool ProcessFile::is_alive() const { - if (kill(m_pid, 0) == 0) + if (kill(m_header->pids[0], 0) == 0) return 1; return 0; } @@ -158,19 +164,37 @@ const TranslationUnit * ProcessFile::find_tu(std::string const &srcname) const { for (auto &i : m_tus) - if (srcname == i.comp_file_path) + if (srcname == i.comp_file_path()) return &i; return NULL; } -void -ProcessFile::save_executions() +// +// Return program the runtime is/was running within. +// +std::string +ProcessFile::progname() const { - for (auto &t : m_tus) - memcpy(t.exec_counts_last, t.exec_counts, t.num_lines * 8); + return std::string(m_header->progname); } -void -ProcessFile::read_executions() +// +// Return the pid, ppid, pgrp the runtime is/was running within. +// +int +ProcessFile::getpid() const +{ + return m_header->pids[0]; +} + +int +ProcessFile::getppid() const +{ + return m_header->pids[1]; +} + +int +ProcessFile::getpgrp() const { + return m_header->pids[2]; } diff --git a/src/process_file.h b/src/process_file.h @@ -1,58 +1,49 @@ #include <string> -#include <string.h> // memcpy #include <vector> -struct TranslationUnit { - std::vector<std::string> source; - std::string comp_file_path; - std::string abs_file_path; - uint64_t *exec_counts; - uint64_t *exec_counts_last; - uint32_t num_lines; - uint8_t has_execs; +// +// Owns a few pages of shared memory that are created by a running instrumented +// translation unit. +// +class TranslationUnit +{ + struct citrun_node *m_node; + uint64_t *m_data; + uint64_t *m_data_buffer; + + std::vector<std::string> m_source; + +public: + TranslationUnit(void* &); + + std::string comp_file_path() const; + unsigned int num_lines() const; + void read_source(); + void save_executions(); }; -class ProcessFile { -private: - void read_source(struct TranslationUnit &); - - template<typename T> - void shm_read_all(T *buf) - { - memcpy(buf, m_mem + m_pos, sizeof(T)); - m_pos += sizeof(T); - }; - - void shm_next_page(); - void shm_read_string(std::string &); - void shm_read_magic(std::string &); - void *shm_get_block(size_t); - bool shm_at_end(); - - std::string m_path; - int m_fd; - uint8_t *m_mem; - size_t m_pos; - size_t m_size; +// +// Owns an executing/executed instrumented processes shared memory file. +// +class ProcessFile +{ + struct citrun_header *m_header; + std::string m_path; + int m_fd; + size_t m_size; + int m_tus_with_execs; + unsigned int m_program_loc; public: ProcessFile(std::string const &); - const TranslationUnit *find_tu(std::string const &) const; - bool is_alive() const; - void read_executions(); - void save_executions(); - - uint8_t m_major; - uint8_t m_minor; - std::string m_progname; - std::string m_cwd; - uint32_t m_pid; - uint32_t m_ppid; - uint32_t m_pgrp; - std::vector<TranslationUnit> m_tus; - int m_tus_with_execs; + const TranslationUnit *find_tu(std::string const &) const; + bool is_alive() const; + std::string progname() const; + int getpid() const; + int getppid() const; + int getpgrp() const; - uint32_t m_program_loc; + std::vector<TranslationUnit> m_tus; };