00001 #include "IgTools/IgProf/src/IgProf.h"
00002 #include "IgTools/IgProf/src/IgProfTrace.h"
00003 #include "IgTools/IgHook/interface/IgHook.h"
00004 #include "IgTools/IgHook/interface/IgHookTrace.h"
00005 #include <cstdlib>
00006 #include <cstring>
00007 #include <cstdio>
00008 #include <cerrno>
00009 #include <sys/socket.h>
00010 #include <pthread.h>
00011
00012
00013
00014 IGPROF_DUAL_HOOK(3, int, doopen, _main, _libc,
00015 (const char *fn, int flags, int mode), (fn, flags, mode),
00016 "open", 0, "libc.so.6")
00017 IGPROF_DUAL_HOOK(3, int, doopen64, _main, _libc,
00018 (const char *fn, int flags, int mode), (fn, flags, mode),
00019 "__open64", 0, "libc.so.6")
00020 IGPROF_DUAL_HOOK(1, int, doclose, _main, _libc,
00021 (int fd), (fd),
00022 "close", 0, "libc.so.6")
00023 IGPROF_DUAL_HOOK(1, int, dodup, _main, _libc,
00024 (int fd), (fd),
00025 "dup", 0, "libc.so.6")
00026 IGPROF_DUAL_HOOK(2, int, dodup2, _main, _libc,
00027 (int fd, int newfd), (fd, newfd),
00028 "dup2", 0, "libc.so.6")
00029 IGPROF_DUAL_HOOK(3, int, dosocket, _main, _libc,
00030 (int domain, int type, int proto), (domain, type, proto),
00031 "socket", 0, "libc.so.6")
00032 IGPROF_DUAL_HOOK(3, int, doaccept, _main, _libc,
00033 (int fd, sockaddr *addr, socklen_t *len), (fd, addr, len),
00034 "accept", 0, "libc.so.6")
00035
00036
00037 static IgProfTrace::CounterDef s_ct_used = { "FD_USED", IgProfTrace::TICK, -1 };
00038 static IgProfTrace::CounterDef s_ct_live = { "FD_LIVE", IgProfTrace::TICK_PEAK, -1 };
00039 static bool s_count_used = 0;
00040 static bool s_count_live = 0;
00041 static bool s_initialized = false;
00042 static int s_moduleid = -1;
00043
00045 static void __attribute__((noinline))
00046 add (int fd)
00047 {
00048 IgProfTrace *buf = IgProf::buffer(s_moduleid);
00049 if (! buf)
00050 return;
00051
00052 void *addresses[IgProfTrace::MAX_DEPTH];
00053 int depth = IgHookTrace::stacktrace(addresses, IgProfTrace::MAX_DEPTH);
00054 IgProfTrace::Record entries [2];
00055 int nentries = 0;
00056
00057 if (s_count_used)
00058 {
00059 entries[nentries].type = IgProfTrace::COUNT;
00060 entries[nentries].def = &s_ct_used;
00061 entries[nentries].amount = 1;
00062 entries[nentries].ticks = 1;
00063 nentries++;
00064 }
00065
00066 if (s_count_live)
00067 {
00068 entries[nentries].type = IgProfTrace::COUNT | IgProfTrace::ACQUIRE;
00069 entries[nentries].def = &s_ct_live;
00070 entries[nentries].amount = 1;
00071 entries[nentries].ticks = 1;
00072 entries[nentries].resource = fd;
00073 nentries++;
00074 }
00075
00076
00077 buf->push(addresses+4, depth-5, entries, nentries);
00078 }
00079
00083 static void
00084 remove (int fd)
00085 {
00086 if (s_count_live)
00087 {
00088 IgProfTrace *buf = IgProf::buffer(s_moduleid);
00089 if (! buf)
00090 return;
00091
00092 IgProfTrace::Record entry
00093 = { IgProfTrace::RELEASE, &s_ct_live, 0, 0, fd };
00094 buf->push(0, 0, &entry, 1);
00095 }
00096 }
00097
00098
00101 static void
00102 initialize(void)
00103 {
00104 if (s_initialized) return;
00105 s_initialized = true;
00106
00107 const char *options = IgProf::options();
00108 bool enable = false;
00109 bool opts = false;
00110
00111 while (options && *options)
00112 {
00113 while (*options == ' ' || *options == ',')
00114 ++options;
00115
00116 if (! strncmp(options, "fd", 2))
00117 {
00118 enable = true;
00119 options += 2;
00120 while (*options)
00121 {
00122 if (! strncmp(options, ":used", 5))
00123 {
00124 s_count_used = 1;
00125 options += 5;
00126 opts = true;
00127 }
00128 else if (! strncmp(options, ":live", 5))
00129 {
00130 s_count_live = 1;
00131 options += 5;
00132 opts = true;
00133 }
00134 else if (! strncmp(options, ":all", 4))
00135 {
00136 s_count_used = 1;
00137 s_count_live = 1;
00138 options += 4;
00139 opts = true;
00140 }
00141 else
00142 break;
00143 }
00144 }
00145 else
00146 options++;
00147
00148 while (*options && *options != ',' && *options != ' ')
00149 options++;
00150 }
00151
00152 if (! enable)
00153 return;
00154
00155 if (! IgProf::initialize(&s_moduleid, 0, false))
00156 return;
00157
00158 IgProf::disable(true);
00159 if (!opts)
00160 {
00161 IgProf::debug("FD: defaulting to total descriptor counting\n");
00162 s_count_used = 1;
00163 }
00164 else
00165 {
00166 if (s_count_used)
00167 IgProf::debug("FD: enabling usage counting\n");
00168 if (s_count_live)
00169 IgProf::debug("FD: enabling live counting\n");
00170 }
00171
00172
00173 IgHook::hook(doopen_hook_main.raw);
00174 IgHook::hook(doopen64_hook_main.raw);
00175 IgHook::hook(doclose_hook_main.raw);
00176 IgHook::hook(dodup_hook_main.raw);
00177 IgHook::hook(dodup2_hook_main.raw);
00178 IgHook::hook(dosocket_hook_main.raw);
00179 IgHook::hook(doaccept_hook_main.raw);
00180 #if __linux
00181 if (doopen_hook_main.raw.chain) IgHook::hook(doopen_hook_libc.raw);
00182 if (doopen64_hook_main.raw.chain) IgHook::hook(doopen64_hook_libc.raw);
00183 if (doclose_hook_main.raw.chain) IgHook::hook(doclose_hook_libc.raw);
00184 if (dodup_hook_main.raw.chain) IgHook::hook(dodup_hook_libc.raw);
00185 if (dodup2_hook_main.raw.chain) IgHook::hook(dodup2_hook_libc.raw);
00186 if (dosocket_hook_main.raw.chain) IgHook::hook(dosocket_hook_libc.raw);
00187 if (doaccept_hook_main.raw.chain) IgHook::hook(doaccept_hook_libc.raw);
00188 #endif
00189 IgProf::debug("File descriptor profiler enabled\n");
00190 IgProf::enable(true);
00191 }
00192
00193
00194
00195 static int
00196 doopen(IgHook::SafeData<igprof_doopen_t> &hook, const char *fn, int flags, int mode)
00197 {
00198 bool enabled = IgProf::disable(false);
00199 int result = (*hook.chain)(fn, flags, mode);
00200 int err = errno;
00201
00202 if (enabled && result != -1)
00203 add(result);
00204
00205 errno = err;
00206 IgProf::enable(false);
00207 return result;
00208 }
00209
00210 static int
00211 doopen64(IgHook::SafeData<igprof_doopen64_t> &hook, const char *fn, int flags, int mode)
00212 {
00213 bool enabled = IgProf::disable(false);
00214 int result = (*hook.chain)(fn, flags, mode);
00215 int err = errno;
00216
00217 if (enabled && result != -1)
00218 add(result);
00219
00220 errno = err;
00221 IgProf::enable(false);
00222 return result;
00223 }
00224
00225 static int
00226 doclose(IgHook::SafeData<igprof_doclose_t> &hook, int fd)
00227 {
00228 IgProf::disable(false);
00229 int result = (*hook.chain)(fd);
00230 int err = errno;
00231
00232 if (result != -1)
00233 remove(fd);
00234
00235 errno = err;
00236 IgProf::enable(false);
00237 return result;
00238 }
00239
00240
00241 static int
00242 dodup(IgHook::SafeData<igprof_dodup_t> &hook, int fd)
00243 {
00244 bool enabled = IgProf::disable(false);
00245 int result = (*hook.chain)(fd);
00246 int err = errno;
00247
00248 if (enabled && result != -1)
00249 add(result);
00250
00251 errno = err;
00252 IgProf::enable(false);
00253 return result;
00254 }
00255
00256 static int
00257 dodup2(IgHook::SafeData<igprof_dodup2_t> &hook, int fd, int newfd)
00258 {
00259 bool enabled = IgProf::disable(false);
00260 int result = (*hook.chain)(fd, newfd);
00261 int err = errno;
00262
00263 if (result != -1)
00264 {
00265 remove(fd);
00266 if (enabled)
00267 add(newfd);
00268 }
00269
00270 errno = err;
00271 IgProf::enable(false);
00272 return result;
00273 }
00274
00275 static int
00276 dosocket(IgHook::SafeData<igprof_dosocket_t> &hook, int domain, int type, int proto)
00277 {
00278 bool enabled = IgProf::disable(false);
00279 int result = (*hook.chain)(domain, type, proto);
00280 int err = errno;
00281
00282 if (enabled && result != -1)
00283 add(result);
00284
00285 errno = err;
00286 IgProf::enable(false);
00287 return result;
00288 }
00289
00290 static int
00291 doaccept(IgHook::SafeData<igprof_doaccept_t> &hook,
00292 int fd, struct sockaddr *addr, socklen_t *len)
00293 {
00294 bool enabled = IgProf::disable(false);
00295 int result = (*hook.chain)(fd, addr, len);
00296 int err = errno;
00297
00298 if (enabled && result != -1)
00299 add(result);
00300
00301 errno = err;
00302 IgProf::enable(false);
00303 return result;
00304 }
00305
00306
00307 static bool autoboot = (initialize(), true);