Changeset 487 for trunk/lib/Stats.cc
- Timestamp:
- Oct 14, 2007, 12:20:17 AM (15 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/lib/Stats.cc
r483 r487 51 51 52 52 Stats::Stats(const std::string& path) 53 : valid_(true) 53 54 { 54 55 // Make sure latest revision is set properly … … 59 60 60 61 61 std::vector<u_int> Stats::accumulated(const Map_& map) const 62 { 63 // sum of all users 64 std::vector<u_int> sum(revision_+1); 65 sum=std::accumulate(map.begin(), map.end(), sum, 66 PairValuePlus<std::string,u_int>()); 67 68 // calculate accumulated sum 69 std::vector<u_int> accum(sum.size()); 70 std::partial_sum(sum.begin(),sum.end(),accum.begin()); 71 assert(sum.size()==accum.size()); 72 return accum; 73 } 74 75 std::vector<u_int> Stats::accumulated(const Map_& map, 76 const std::string& user) const 77 { 78 if (!map.count(user)) 79 return std::vector<u_int>(last_changed_rev_,0); 80 std::vector<u_int> vec=(map.find(user))->second; 81 82 // static_cast to remove annoying compiler warning 83 if (vec.size() < static_cast<size_t>(revision_+1)) 84 vec.insert(vec.end(), revision_+1-vec.size(), 0); 85 86 std::vector<u_int> accum(vec.size()); 87 std::partial_sum(vec.begin(),vec.end(),accum.begin()); 88 return accum; 89 } 90 91 void Stats::add(const std::string& user, const u_int& rev, 92 const Parser::line_type& lt) 93 { 94 assert(user.size()); 95 authors_.insert(user); 96 97 std::vector<u_int>* total = &(total_[user]); 98 assert(total); 99 if (total->size() < rev+1){ 100 total->reserve(revision_ + 1); 101 total->insert(total->end(), rev - total->size(), 0); 102 total->push_back(1); 62 Stats::~Stats(void) 63 { 64 } 65 66 67 void Stats::base_add(v_map::const_iterator first1, 68 v_map::const_iterator last1, v_map& map) 69 { 70 v_map::iterator first2(map.begin()); 71 v_map::key_compare compare; 72 while ( first1 != last1) { 73 // key of first1 less than key of first2 74 if (first2==map.end() || compare(first1->first,first2->first)) { 75 first2 = map.insert(first2, *first1); 76 ++first1; 77 } 78 // key of first2 less than key of first1 79 else if ( compare(first2->first, first1->first)) { 80 ++first2; 81 } 82 // keys are equivalent 83 else { 84 VectorPlus<v_map::mapped_type::value_type> vp; 85 first2->second = vp(first1->second, first2->second); 86 ++first1; 87 ++first2; 88 } 103 89 } 104 else 105 ++(*total)[rev]; 106 107 std::vector<u_int>* code = &(code_[user]); 108 assert(code); 109 if (code->size() < rev+1){ 110 code->reserve(revision_ + 1); 111 code->insert(code->end(), rev - code->size(), 0); 112 if (lt == Parser::code) 113 code->push_back(1); 114 else 115 code->push_back(0); 116 } 117 else if (lt == Parser::code) 118 ++(*code)[rev]; 119 120 std::vector<u_int>* comments = &(comments_[user]); 121 assert(comments); 122 if (comments->size() < rev+1){ 123 comments->reserve(revision_ + 1); 124 comments->insert(comments->end(), rev - comments->size(), 0); 125 if (lt == Parser::comment) 126 comments->push_back(1); 127 else 128 comments->push_back(0); 129 } 130 else if (lt == Parser::comment) 131 ++(*comments)[rev]; 132 133 std::vector<u_int>* empty = &(empty_[user]); 134 assert(empty); 135 if (empty->size() < rev+1){ 136 empty->reserve(revision_ + 1); 137 empty->insert(empty->end(), rev - empty->size(), 0); 138 if (lt == Parser::empty) 139 empty->push_back(1); 140 else 141 empty->push_back(0); 142 } 143 else if (lt == Parser::empty) 144 ++(*empty)[rev]; 145 } 146 90 } 91 92 93 void Stats::add_author(std::string name) 94 { 95 authors_.insert(name); 96 } 97 98 99 void Stats::add_authors(std::set<std::string>::const_iterator first, 100 std::set<std::string>::const_iterator last) 101 { 102 authors_.insert(first, last); 103 } 104 105 106 const std::set<std::string>& Stats::authors(void) const 107 { 108 return authors_; 109 } 110 111 112 void Stats::base_add(const Stats& rhs) 113 { 114 revision_ = std::max(revision_, rhs.revision_); 115 last_changed_rev_ = std::max(last_changed_rev_, rhs.last_changed_rev_); 116 add_authors(rhs.authors().begin(), rhs.authors().end()); 117 valid_ &= rhs.valid(); 118 // if cache not valid no need to update it 119 if (valid()) { 120 base_add(rhs.code_.begin(), rhs.code_.end(), code_); 121 base_add(rhs.comments_.begin(), rhs.comments_.end(), comments_); 122 base_add(rhs.other_.begin(), rhs.other_.end(), other_); 123 base_add(rhs.total_.begin(), rhs.total_.end(), total_); 124 } 125 } 126 127 128 u_int Stats::code(const std::string& user) const 129 { 130 return get_vector(code_, "all").back(); 131 } 132 133 134 u_int Stats::comments(const std::string& user) const 135 { 136 return get_vector(comments_, "all").back(); 137 } 138 139 140 u_int Stats::empty(const std::string& user) const 141 { 142 return get_vector(other_, "all").back(); 143 } 144 145 146 const std::vector<u_int>& Stats::get_vector(const v_map& m, 147 std::string user) const 148 { 149 // Peter, we should avoid calling this function prior all 150 // statistics are calculated. If, for some reason, this is not 151 // possible call update_stats() first, however, that function is 152 // not const so some redesign is needed (e.g. making cache mutable 153 // or making them pointers) 154 assert(valid() && "trying to access invalid cache of statistics"); 155 v_map::const_iterator iter(m.find(std::string(user))); 156 if (iter==m.end()) 157 throw std::runtime_error(user+std::string(" not found i Stats")); 158 return iter->second; 159 } 147 160 148 161 bool Stats::load_cache(std::istream& is) 149 162 { 163 150 164 svn_revnum_t rev; 151 165 is >> rev; … … 163 177 authors_.insert(str); 164 178 } 165 getline(is, str); 166 if (str!=code_cache()){ 167 return false; 168 } 169 load(is, code_); 170 getline(is, str); 171 getline(is, str); 172 if (str!=comments_cache()){ 173 return false; 174 } 175 load(is, comments_); 176 getline(is, str); 177 getline(is, str); 178 if (str!=empty_cache()){ 179 return false; 180 } 181 load(is, empty_); 182 getline(is, str); 183 getline(is, str); 184 if (str!=total_cache()){ 185 return false; 186 } 187 load(is, total_); 188 getline(is,str); 189 getline(is,str); 190 return str==end_of_cache(); 191 } 192 193 194 void Stats::load(std::istream& is, Map_& m) 195 { 196 m.clear(); 197 while (m.size() < authors_.size() && is.good()) { 198 std::string name; 199 std::getline(is, name); 200 assert(name.size()); 201 std::vector<u_int>& vec=m[name]; 202 size_t revs=0; 203 is >> revs; 204 vec.reserve(revs); 205 while (vec.size() < revs) { 206 u_int tmp; 207 is >> tmp; 208 vec.push_back(tmp); 209 } 210 } 179 return do_load_cache(is); 180 } 181 182 183 svn_revnum_t Stats::last_changed_rev(void) const 184 { 185 return last_changed_rev_; 186 } 187 188 189 u_int Stats::lines(const std::string& user) const 190 { 191 assert(valid()); return get_vector(total_, "all").back(); 211 192 } 212 193 … … 214 195 void Stats::parse(const std::string& path) 215 196 { 216 Parser parser(path); 217 std::vector<Parser::line_type>::const_iterator count=parser.type().begin(); 218 219 SVNblame svn_blame(path); 220 while (svn_blame.valid()) { 221 add(svn_blame.author(), svn_blame.revision(), *count); 222 svn_blame.next_line(); 223 ++count; 224 } 225 226 } 227 197 valid_=false; 198 // First we let inherited class do parsing 199 do_parse(path); 200 // then we fill up with statistics 201 202 update_stats(); 203 } 228 204 229 205 std::string Stats::plot(const std::string& filename, 230 206 const std::string& linetype) const 231 207 { 232 plot_init(filename); 233 GnuplotFE* gp=GnuplotFE::instance(); 234 const Map_* stat=NULL; 235 if (linetype=="total") 236 stat = &total_; 237 else if (linetype=="code") 238 stat = &code_; 239 else if (linetype=="comments") 240 stat = &comments_; 241 else if (linetype=="empty") 242 stat = &empty_; 243 assert(stat); 244 std::vector<u_int> total=accumulated(*stat); 245 double yrange_max=1.03*total.back()+1; 246 gp->yrange(yrange_max); 247 248 typedef std::vector<std::pair<std::string, std::vector<u_int> > > vec_type; 249 vec_type author_cont; 250 author_cont.reserve(stat->size()); 251 for (MapConstIter_ i= stat->begin(); i != stat->end(); ++i) { 252 author_cont.push_back(std::make_pair(i->first, 253 accumulated(*stat,i->first))); 254 } 255 256 LessReversed<std::vector<u_int> > lr; 257 PairSecondCompare<std::string, std::vector<u_int>, 258 LessReversed<std::vector<u_int> > > compare(lr); 259 std::sort(author_cont.begin(), author_cont.end(), compare); 260 261 size_t plotno=author_cont.size(); 262 std::stringstream ss; 263 vec_type::iterator end(author_cont.end()); 264 for (vec_type::iterator i(author_cont.begin()); i!=end; ++i) { 265 ss.str(""); 266 ss << "set key height " << 2*plotno; 267 gp->command(ss.str()); 268 ss.str(""); 269 ss << i->second.back() << " " << i->first; 270 gp->yrange(yrange_max); 271 gp->linetitle(ss.str()); 272 ss.str(""); 273 ss << "steps " << --plotno+2; 274 gp->linestyle(ss.str()); 275 gp->plot(i->second); 276 } 277 ss.str(""); 278 ss << total.back() << " total"; 279 gp->command("set key height 0"); 280 gp->linetitle(ss.str()); 281 gp->linestyle("steps 1"); 282 gp->plot(total); 283 284 gp->command("unset multiplot"); 285 gp->yrange(); 286 287 return filename; 208 return do_plot(filename, linetype); 288 209 } 289 210 … … 304 225 void Stats::plot_summary(const std::string& filename) const 305 226 { 227 assert(valid()); 306 228 plot_init(filename); 307 229 GnuplotFE* gp=GnuplotFE::instance(); 308 std::vector<u_int> total =accumulated(total_);230 std::vector<u_int> total = get_vector(total_, "all"); 309 231 double yrange_max=1.03*total.back()+1; 310 232 gp->yrange(yrange_max); … … 312 234 313 235 ss.str(""); 314 std::vector<u_int> x =accumulated(code_);236 std::vector<u_int> x(get_vector(code_, "all")); 315 237 ss << x.back() << " code"; 316 238 gp->command("set key height 2"); … … 320 242 321 243 ss.str(""); 322 x =accumulated(comments_);244 x = get_vector(code_, "all"); 323 245 ss << x.back() << " comment"; 324 246 gp->command("set key height 4"); … … 328 250 329 251 ss.str(""); 330 x =accumulated(empty_);252 x = get_vector(code_, "all"); 331 253 ss << x.back() << " other"; 332 254 gp->command("set key height 6"); … … 354 276 std::copy(authors_.begin(), authors_.end(), 355 277 std::ostream_iterator<std::string>(os, "\n")); 356 os << code_cache() << "\n"; 357 print(os, code_); 358 os << "\n" << comments_cache() << "\n"; 359 print(os, comments_); 360 os << "\n" << empty_cache() << "\n"; 361 print(os, empty_); 362 os << "\n" << total_cache() << "\n"; 363 print(os, total_); 364 os << "\n" << end_of_cache() << "\n"; 365 } 366 367 368 void Stats::print(std::ostream& os, const Map_& m) const 369 { 370 for (MapConstIter_ i(m.begin()); i!=m.end(); ++i){ 371 os << i->first << "\n"; 372 os << i->second.size() << " "; 373 std::copy(i->second.begin(), i->second.end(), 374 std::ostream_iterator<u_int>(os, " ")); 278 do_print(os); 279 } 280 281 282 void Stats::reset(void) 283 { 284 do_reset(); 285 } 286 287 288 void Stats::update_stats(void) 289 { 290 for (std::set<std::string>::const_iterator iter(authors_.begin()); 291 iter!=authors_.end(); ++iter) { 292 std::vector<u_int> code(vector("code", *iter)); 293 code_[*iter] = code; 294 std::vector<u_int> comments(vector("comments", *iter)); 295 comments_[*iter] = comments; 296 std::vector<u_int> other(vector("other", *iter)); 297 other_[*iter] = other; 298 VectorPlus<u_int> vp; 299 total_[*iter] = vp(vp(code, comments),other); 375 300 } 376 } 377 378 379 Stats& Stats::operator+=(const Stats& other) 380 { 381 for (MapConstIter_ o_i= other.code_.begin(); 382 o_i != other.code_.end(); ++o_i) 383 { 384 std::pair<MapIter_,bool> result = code_.insert(*o_i); 385 if (!result.second) 386 code_[(*(result.first)).first] = 387 VectorPlus<u_int>()( (*(result.first)).second, (*o_i).second ); 388 389 } 390 391 for (MapConstIter_ o_i= other.comments_.begin(); 392 o_i != other.comments_.end(); ++o_i) 393 { 394 std::pair<MapIter_,bool> result = comments_.insert(*o_i); 395 if (!result.second) 396 comments_[(*(result.first)).first] = 397 VectorPlus<u_int>()( (*(result.first)).second, (*o_i).second ); 398 399 } 400 401 for (MapConstIter_ o_i= other.empty_.begin(); 402 o_i != other.empty_.end(); ++o_i) 403 { 404 std::pair<MapIter_,bool> result = empty_.insert(*o_i); 405 if (!result.second) 406 empty_[(*(result.first)).first] = 407 VectorPlus<u_int>()( (*(result.first)).second, (*o_i).second ); 408 409 } 410 411 for (MapConstIter_ o_i= other.total_.begin(); 412 o_i != other.total_.end(); ++o_i) 413 { 414 std::pair<MapIter_,bool> result = total_.insert(*o_i); 415 if (!result.second) 416 total_[(*(result.first)).first] = 417 VectorPlus<u_int>()( (*(result.first)).second, (*o_i).second ); 418 419 } 420 421 if (!other.authors().empty()) 422 authors_.insert(other.authors().begin(), other.authors().end()); 423 return *this; 424 } 301 std::vector<u_int> init(revision()+1); 302 code_["all"]=std::accumulate(code_.begin(), code_.end(), init, 303 PairValuePlus<std::string,u_int>()); 304 comments_["all"]=std::accumulate(comments_.begin(), comments_.end(), init, 305 PairValuePlus<std::string,u_int>()); 306 other_["all"]=std::accumulate(other_.begin(), other_.end(), init, 307 PairValuePlus<std::string,u_int>()); 308 VectorPlus<u_int> vp; 309 total_["all"] = vp(vp(code_["all"], comments_["all"]), other_["all"]); 310 valid_=true; 311 } 312 425 313 426 314 }} // end of namespace svndigest and namespace theplu
Note: See TracChangeset
for help on using the changeset viewer.