history.hpp (5080B)
1 /* Relacy Race Detector 2 * Copyright (c) 2008-2013, Dmitry S. Vyukov 3 * All rights reserved. 4 * This software is provided AS-IS with no warranty, either express or implied. 5 * This software is distributed under a license and may not be copied, 6 * modified or distributed except as expressly authorized under the 7 * terms of the license contained in the file LICENSE in this distribution. 8 */ 9 10 #ifndef RL_HISTORY_HPP 11 #define RL_HISTORY_HPP 12 #ifdef _MSC_VER 13 # pragma once 14 #endif 15 16 #include "base.hpp" 17 18 19 namespace rl 20 { 21 22 23 typedef void (*event_output_f)(std::ostream& s, void const* ev); 24 typedef void (*event_dtor_f)(void* ev); 25 26 struct history_entry 27 { 28 thread_id_t thread_index_; 29 debug_info info_; 30 void* ev_; 31 event_output_f output_; 32 event_dtor_f dtor_; 33 34 history_entry(thread_id_t thread_index, debug_info_param info, void* ev, event_output_f output, event_dtor_f dtor) 35 : thread_index_(thread_index) 36 , info_(info) 37 , ev_(ev) 38 , output_(output) 39 , dtor_(dtor) 40 { 41 } 42 }; 43 44 template<typename T> 45 void event_output(std::ostream& s, void const* ev) 46 { 47 static_cast<T const*>(ev)->output(s); 48 } 49 50 template<typename T> 51 void event_dtor(void* ev) 52 { 53 delete static_cast<T*>(ev); 54 } 55 56 57 struct user_event 58 { 59 char const* desc_; 60 61 void output(std::ostream& s) const 62 { 63 s << desc_; 64 } 65 }; 66 67 inline string strip_path(char const* filename) 68 { 69 char const* slash = strrchr(filename, '\\'); 70 if (slash) 71 return slash + 1; 72 else 73 return filename; 74 } 75 76 inline std::ostream& operator << (std::ostream& ss, debug_info_param info) 77 { 78 /* 79 char const* func = info; 80 char const* file = info + strlen(info) + 1; 81 char const* line = file + strlen(file) + 1; 82 */ 83 84 #ifdef RL_MSVC_OUTPUT 85 ss << info.file_ << "(" << info.line_ << ") : "; 86 #else 87 ss << info.func_ << ", " << strip_path(info.file_) << "(" << info.line_ << ")"; 88 #endif 89 return ss; 90 } 91 92 93 94 class history_mgr : nocopy<> 95 { 96 public: 97 history_mgr(std::ostream& stream, thread_id_t thread_count) 98 : thread_count_(thread_count) 99 , out_stream_(stream) 100 { 101 } 102 103 ~history_mgr() 104 { 105 clear(); 106 } 107 108 template<typename event_t> 109 void exec_log(thread_id_t th, debug_info_param info, event_t const& ev, bool output_history) 110 { 111 exec_history_.push_back(history_entry(th, info, new event_t(ev), &event_output<event_t>, &event_dtor<event_t>)); 112 if (output_history) 113 { 114 output(exec_history_.size() - 1); 115 } 116 } 117 118 void print_exec_history(bool output_history) 119 { 120 size_t const buf_size = 4096; 121 char buf [buf_size + 1]; 122 123 size_t const count = exec_history_.size(); 124 if (false == output_history) 125 { 126 sprintf(buf, "execution history (%u):\n", (unsigned)count); 127 out_stream_ << buf; 128 #if defined(_MSC_VER) && defined(RL_MSVC_OUTPUT) 129 OutputDebugStringA(buf); 130 #endif 131 132 for (size_t i = 0; i != count; ++i) 133 { 134 output(i); 135 } 136 } 137 out_stream_ << "\n"; 138 #if defined(_MSC_VER) && defined(RL_MSVC_OUTPUT) 139 OutputDebugStringA("\n"); 140 #endif 141 142 for (thread_id_t th = 0; th != thread_count_; ++th) 143 { 144 sprintf(buf, "thread %u:\n", th); 145 out_stream_ << buf; 146 #if defined(_MSC_VER) && defined(RL_MSVC_OUTPUT) 147 OutputDebugStringA(buf); 148 #endif 149 for (size_t i = 0; i != count; ++i) 150 { 151 if (exec_history_[i].thread_index_ == th) 152 { 153 output(i); 154 } 155 } 156 out_stream_ << "\n"; 157 #if defined(_MSC_VER) && defined(RL_MSVC_OUTPUT) 158 OutputDebugStringA("\n"); 159 #endif 160 } 161 } 162 163 void clear() 164 { 165 for (size_t i = 0; i != exec_history_.size(); ++i) 166 { 167 history_entry const& ent = exec_history_[i]; 168 ent.dtor_(ent.ev_); 169 } 170 exec_history_.clear(); 171 } 172 173 private: 174 vector<history_entry>::type exec_history_; 175 thread_id_t thread_count_; 176 std::ostream& out_stream_; 177 178 void output(size_t i) 179 { 180 std::basic_ostringstream<char, std::char_traits<char>, raw_allocator<char> > stream; 181 182 history_entry const& ent = exec_history_[i]; 183 #ifdef RL_MSVC_OUTPUT 184 { 185 stream << ent.info_ << "[" << i << "] " << ent.thread_index_ << ": "; 186 ent.output_(stream, ent.ev_); 187 stream << std::endl; 188 } 189 #else 190 stream << "[" << (unsigned)i << "] " << ent.thread_index_ << ": "; 191 ent.output_(stream, ent.ev_); 192 stream << ", in " << ent.info_ << std::endl; 193 #endif 194 195 out_stream_ << stream.str(); 196 #if defined(_MSC_VER) && defined(RL_MSVC_OUTPUT) 197 OutputDebugStringA(stream.str().c_str()); 198 #endif 199 } 200 }; 201 202 203 } 204 205 #endif