From: Gonzalo A. <ga...@us...> - 2007-03-12 19:18:51
|
Update of /cvsroot/mod-c/ehtml/src In directory sc8-pr-cvs7.sourceforge.net:/tmp/cvs-serv10474/src Modified Files: Makefile.am Profiling.cpp Added Files: ehtml_prof_util.cpp Log Message: Implemented a profiling information persistent storage. ehmlt_prof_util merges profiling information and generates profiling reports (plain old text so far). Index: Makefile.am =================================================================== RCS file: /cvsroot/mod-c/ehtml/src/Makefile.am,v retrieving revision 1.13 retrieving revision 1.14 diff -C2 -d -r1.13 -r1.14 *** Makefile.am 12 Oct 2006 18:30:33 -0000 1.13 --- Makefile.am 12 Mar 2007 19:18:46 -0000 1.14 *************** *** 13,17 **** lib_LTLIBRARIES = libehtml.la libsession.la libdisksession.la libsessionid.la ! bin_PROGRAMS = mod_c_dss noinst_PROGRAMS = testCommon --- 13,17 ---- lib_LTLIBRARIES = libehtml.la libsession.la libdisksession.la libsessionid.la ! bin_PROGRAMS = mod_c_dss ehtml_prof_util noinst_PROGRAMS = testCommon *************** *** 43,46 **** --- 43,48 ---- mod_c_dss_CXXFLAGS = $(INCLUDE_DIRS) + ehtml_prof_util_SOURCES = ehtml_prof_util.cpp + LIBSESS_SOURCES = DefaultSessionAddress.cpp LIBSESS_SOURCES += DefaultSessionDriver.cpp --- NEW FILE: ehtml_prof_util.cpp --- // // Authors: // Gonzalo Arana (gon...@gm...) // // (C) 2006 Gonzalo Arana // // // This source code is licenced under The MIT License: // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the // "Software"), to deal in the Software without restriction, including // without limitation the rights to use, copy, modify, merge, publish, // distribute, sublicense, and/or sell copies of the Software, and to // permit persons to whom the Software is furnished to do so, subject to // the following conditions: // // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // #include "Profiling.h" #include <fstream> #include <iostream> #include <iomanip> #include <assert.h> #include <map> #include <set> using namespace std; struct prof { prof(): accum(0), self(0), ncalls(0) { ; } prof& operator += (const prof& p); ~prof() { ; } hrtime_t accum; hrtime_t self; int64_t ncalls; }; prof& prof::operator += (const prof& p) { accum += p.accum; self += p.self; ncalls += p.ncalls; return *this; } map<string,prof> stats; const char* USAGE = "ehtml_prof_util -m result_file file [file [file ...] ]\n" " Merges EHTML profiling information found in files and directories\n" " specified as arguments\n" "\n" "ehtml_prof_util -r result_file [sort_column]" " Generates a report to stdout sorted by sort_column.\n" " sort_column must be 4 chars, and it must be a combination of these:\n" " 'a': accumulated time.\n" " 'n': number of calls.\n" " 's': self accumulated time.\n" " 'l': location (dictionary sorted).\n" "\n" ; size_t max_loc_len = 0; static void read_profiles(const char* files[]) { static char line[8192]; for (int i = 0; files[i]; ++i) { ifstream in(files[i]); if (!in.good()) { cerr << "Error: could not open file \"" << files[i] << "\": " << strerror(errno) << "\n"; continue; } hrtime_t values[3]; char types[3]; static char location[512]; prof p; while (in.getline(line, sizeof(line)-1).good()) { line[sizeof(line)-1] = '\0'; if (sscanf(line, "%s %c%llu %c%llu %c%llu", location, &types[0], &values[0], &types[1], &values[1], &types[2], &values[2]) != 7) { cerr << "Invalid line \"" << line << "\"\n"; exit(1); } for (int i = 0; i < 3; ++i) switch (types[i]) { case 'a': p.accum = values[i]; break; case 's': p.self = values[i]; break; case 'n': p.ncalls = values[i]; break; default: cerr << "Unknown field type '" << types[i] << "'\n"; break; } stats[location] += p; size_t loc_len = strlen(location); if (loc_len > max_loc_len) max_loc_len = loc_len; } } } static void save_profile(const char* out) { ofstream o(out); if (!o.good()) { cerr << "Error opening \"" << out << "\": " << strerror(errno) << "\n"; exit(2); } for (map<string,prof>::iterator i = stats.begin(); i != stats.end(); ++i) { o << i->first << "\t" << 'a' << i->second.accum << "\t" << 's' << i->second.self << "\t" << 'n' << i->second.ncalls << "\n"; } o.close(); } static void merge(const char* argv[]) { read_profiles(argv); save_profile(argv[0]); for (int i = 1; argv[i]; ++i) unlink(argv[i]); } struct profloc { profloc(const prof& _p, const string& l): p(_p), loc(l) { ; } profloc(const profloc& p): p(p.p), loc(p.loc) { ; } prof p; string loc; }; #define hrtime_cmp(x,y) ((x) < (y) ? 1 : ((x) == (y) ? 0 : -1)) struct profloc_cmp { static char cmp_order[4]; int cmp(const profloc& p1, const profloc& p2, char c) const { switch (c) { case 'a': return hrtime_cmp(p1.p.accum, p2.p.accum); case 's': return hrtime_cmp(p1.p.self, p2.p.self); case 'n': return p2.p.ncalls - p1.p.ncalls; case 'l': return strcmp(p1.loc.c_str(), p2.loc.c_str()); } assert(0); } bool operator() (const profloc& p1, const profloc& p2) const { int dev; for (int i = 0; i < 4; ++i) { dev = cmp(p1,p2,cmp_order[i]); if (dev) break; } return dev < 0; } }; char profloc_cmp::cmp_order[4] = {'s', 'a', 'n', 'l'}; static void report(const char* file, const char* sort) { const char* profiles[2]; profiles[0] = file; profiles[1] = NULL; read_profiles(profiles); if (sort == NULL) sort = "sanl"; strncpy(profloc_cmp::cmp_order, sort, 4); set<profloc, profloc_cmp> ordered; for (map<string,prof>::iterator iprof = stats.begin(); iprof != stats.end(); ++iprof) { ordered.insert(profloc(iprof->second,iprof->first)); } for (set<profloc>::iterator iprof = ordered.begin(); iprof != ordered.end(); ++iprof) { cout << setw(max_loc_len) << left << iprof->loc << setw(22) << right << iprof->p.accum << setw(22) << right << iprof->p.self << setw(12) << right << iprof->p.ncalls << endl; } } int main(int argc, const char* argv[]) { if (argc <= 2) { puts(USAGE); return 1; } if (!strcmp(argv[1], "-m")) merge(argv+2); else if (!strcmp(argv[1], "-r")) report(argv[2], argv[3]); return 0; } Index: Profiling.cpp =================================================================== RCS file: /cvsroot/mod-c/ehtml/src/Profiling.cpp,v retrieving revision 1.7 retrieving revision 1.8 diff -C2 -d -r1.7 -r1.8 *** Profiling.cpp 8 Mar 2007 17:42:00 -0000 1.7 --- Profiling.cpp 12 Mar 2007 19:18:46 -0000 1.8 *************** *** 29,32 **** --- 29,34 ---- #include "Profiling.h" + #include <sys/time.h> + #include <time.h> #include <string.h> *************** *** 106,107 **** --- 108,129 ---- } + void saveProfile() { + void* cb = NULL; + struct runspec spec; + char file[48]; + struct timeval now; + gettimeofday(&now, NULL); + snprintf(file, sizeof(file), "/tmp/ehtml_profile.%d.%lu.%lu", + getpid(), now.tv_sec, now.tv_usec); + FILE* f = fopen(file, "at"); + while (profile_tick(&cb, &spec), cb != NULL) + fprintf(f, "%s@%s:%d\ta%llu\ts%llu\tn%llu\n", + spec.name, spec.file, spec.line, + spec.accum, spec.self, spec.ncalls); + fclose(f); + char file1[53]; + snprintf(file1, sizeof(file1), "%s.done", file); + rename(file, file1); + unlink(file); + } + |