gl_runtime.cc (6634B)
1 // 2 // Copyright (c) 2016, 2017 Kyle Milz <kyle@0x30.net> 3 // 4 // Permission to use, copy, modify, and distribute this software for any 5 // purpose with or without fee is hereby granted, provided that the above 6 // copyright notice and this permission notice appear in all copies. 7 // 8 // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 // 16 #include <sys/stat.h> 17 18 #include <cassert> // assert 19 #include <cstdlib> // std::getenv 20 #include <cstring> // std::memcpy, std::strncmp 21 #include <csignal> // kill 22 #include <err.h> 23 #include <fstream> // std::ifstream 24 #include <iostream> // std::cerr 25 #include <sstream> // std::stringstream 26 27 #include "citrun.h" // struct citrun_node 28 #include "gl_runtime.h" // citrun::gl_transunit, citrun::gl_procfile 29 30 31 // 32 // Take a pointer to a shared memory region and map data structures on top. 33 // Automatically increments the pointer once we know how big this region is. 34 // 35 citrun::gl_transunit::gl_transunit(citrun::mem &m_mem, citrun::gl_font &font, 36 glyphy_point_t &draw_pos) : 37 m_node(static_cast<struct citrun_node *>(m_mem.get_ptr())), 38 m_data((unsigned long long *)(m_node + 1)), 39 m_data_buffer(m_node->size) 40 { 41 unsigned int size; 42 43 // Total size is node size plus live execution data size. 44 size = sizeof(struct citrun_node); 45 size += m_node->size * sizeof(unsigned long long); 46 m_mem.increment(size); 47 48 m_glbuffer.move_to(&draw_pos); 49 50 std::stringstream tu_info; 51 tu_info << "Source file: " << m_node->comp_file_path << std::endl; 52 tu_info << "Lines of code: " << m_node->size << std::endl; 53 m_glbuffer.add_text(tu_info.str().c_str(), font, 2); 54 55 glyphy_point_t cur_pos; 56 m_glbuffer.current_point(&cur_pos); 57 cur_pos.x = draw_pos.x; 58 m_glbuffer.move_to(&cur_pos); 59 60 std::ifstream file_stream(m_node->abs_file_path); 61 if (file_stream.is_open() == 0) { 62 std::cerr << "ifstream.open: " << m_node->abs_file_path << std::endl; 63 return; 64 } 65 66 std::string line; 67 unsigned int i; 68 for (i = 1; std::getline(file_stream, line); ++i) { 69 m_glbuffer.add_text(line.c_str(), font, 1); 70 71 m_glbuffer.current_point(&cur_pos); 72 cur_pos.x = draw_pos.x; 73 m_glbuffer.move_to(&cur_pos); 74 } 75 76 if (i != m_node->size) 77 std::cerr << m_node->abs_file_path << " size mismatch: " 78 << i << " vs " << m_node->size << std::endl; 79 } 80 81 // 82 // Returns number of lines that citrun_inst processed (whole source file 83 // ideally) 84 // 85 unsigned int 86 citrun::gl_transunit::num_lines() const 87 { 88 return m_node->size; 89 } 90 91 // 92 // Returns the source file path as it was passed to the compiler. 93 // 94 std::string 95 citrun::gl_transunit::comp_file_path() const 96 { 97 return std::string(m_node->comp_file_path); 98 } 99 100 glyphy_extents_t 101 citrun::gl_transunit::get_extents() 102 { 103 glyphy_extents_t extents; 104 m_glbuffer.extents(NULL, &extents); 105 106 return extents; 107 } 108 109 // 110 // Copy live executions to secondary buffer. Used for computing deltas later. 111 // 112 void 113 citrun::gl_transunit::save_executions() 114 { 115 std::memcpy(&m_data_buffer[0], m_data, m_node->size * sizeof(unsigned long long)); 116 } 117 118 void 119 citrun::gl_transunit::display() 120 { 121 m_glbuffer.draw(); 122 } 123 124 // 125 // citrun::gl_procfile 126 // 127 // Take a filesystem path and memory map its contents. Map at least a header 128 // structure on top of it. 129 // 130 citrun::gl_procfile::gl_procfile(std::string const &path, citrun::gl_font &font, double const &x_off) : 131 m_mem(path) 132 { 133 // Header is always at offset 0. 134 m_header = static_cast<struct citrun_header *>(m_mem.get_ptr()); 135 m_mem.increment(sizeof(struct citrun_header)); 136 137 assert(std::strncmp(m_header->magic, "ctrn", 4) == 0); 138 assert(m_header->major == citrun_major); 139 140 glyphy_point_t orig_pos = { x_off, 0 }; 141 m_glbuffer.move_to(&orig_pos); 142 143 std::stringstream maj; 144 maj << "Name: '" << m_header->progname << "'" << std::endl; 145 maj << "Translation Units: " << m_header->units << std::endl; 146 maj << "Lines of code: " << m_header->loc << std::endl; 147 m_glbuffer.add_text(maj.str().c_str(), font, 3); 148 149 std::stringstream min; 150 min << "Working directory: " << m_header->cwd << std::endl; 151 min << "Instrumented with: v" << m_header->major << "." << m_header->minor << std::endl; 152 m_glbuffer.add_text(min.str().c_str(), font, 2); 153 154 glyphy_point_t draw_pos; 155 m_glbuffer.current_point(&draw_pos); 156 157 while (!m_mem.at_end()) { 158 m_tus.emplace_back(m_mem, font, draw_pos); 159 draw_pos.x += 80; 160 } 161 162 // Make sure internal increment in TranslationUnit works as intended. 163 assert(m_mem.at_end_exactly()); 164 } 165 166 // 167 // Checks if the pid given by the runtime is alive. Prone to race conditions. 168 // 169 bool 170 citrun::gl_procfile::is_alive() const 171 { 172 return kill(m_header->pids[0], 0) == 0; 173 } 174 175 const citrun::gl_transunit * 176 citrun::gl_procfile::find_tu(std::string const &srcname) const 177 { 178 for (auto &i : m_tus) 179 if (srcname == i.comp_file_path()) 180 return &i; 181 return NULL; 182 } 183 184 void 185 citrun::gl_procfile::display() 186 { 187 m_glbuffer.draw(); 188 189 for (auto &t : m_tus) 190 t.display(); 191 } 192 193 glyphy_extents_t 194 citrun::gl_procfile::get_extents() 195 { 196 glyphy_extents_t extents; 197 m_glbuffer.extents(NULL, &extents); 198 199 for (auto &i : m_tus) { 200 glyphy_extents_t t = i.get_extents(); 201 extents.max_x = std::max(extents.max_x, t.max_x); 202 extents.max_y = std::max(extents.max_y, t.max_y); 203 extents.min_x = std::min(extents.min_x, t.min_x); 204 extents.min_y = std::min(extents.min_y, t.min_y); 205 } 206 207 return extents; 208 } 209 210 211 // 212 // citrun::process_dir 213 // 214 citrun::process_dir::process_dir() 215 { 216 if ((m_procdir = std::getenv("CITRUN_PROCDIR")) == NULL) 217 m_procdir = "/tmp/citrun/"; 218 219 if ((m_dirp = opendir(m_procdir)) == NULL) { 220 if (errno != ENOENT) 221 err(1, "opendir '%s'", m_procdir); 222 223 // Create if there was no such file or directory. 224 mkdir(m_procdir, S_IRWXU); 225 if ((m_dirp = opendir(m_procdir)) == NULL) 226 err(1, "opendir '%s'", m_procdir); 227 } 228 } 229 230 std::vector<std::string> 231 citrun::process_dir::scan() 232 { 233 std::vector<std::string> new_files; 234 struct dirent *dp; 235 236 rewinddir(m_dirp); 237 while ((dp = readdir(m_dirp)) != NULL) { 238 239 if (std::strcmp(dp->d_name, ".") == 0 || 240 std::strcmp(dp->d_name, "..") == 0) 241 continue; 242 243 std::string p(m_procdir); 244 p.append(dp->d_name); 245 246 if (m_known_files.find(p) != m_known_files.end()) 247 // We already know this file. 248 continue; 249 250 m_known_files.insert(p); 251 new_files.push_back(p); 252 } 253 254 return new_files; 255 }