void count_memory(aClient *cptr, char *nick, int debug) { extern aChannel *channel; extern aClass *classes; extern aConfItem *conf; extern int _HASHSIZE, _CHANNELHASHSIZE; Reg aClient *acptr; Reg Link *link; Reg aChannel *chptr; Reg aConfItem *aconf; Reg aClass *cltmp; int lc = 0, d_lc = 0, /* local clients */ ch = 0, d_ch = 0, /* channels */ lcc = 0, d_lcc = 0, /* local client conf links */ rc = 0, d_rc = 0, /* remote clients */ us = 0, d_us = 0, /* user structs */ chu = 0, d_chu = 0, /* channel users */ chi = 0, d_chi = 0, /* channel invites */ chb = 0, d_chb = 0, /* channel bans */ chh = 0, d_chh = 0, /* channel in history */ wwu = 0, d_wwu = 0, /* whowas users */ cl = 0, d_cl = 0, /* classes */ co = 0, d_co = 0; /* conf lines */ int usi = 0, d_usi = 0, /* users invited */ usc = 0, d_usc = 0, /* users in channels */ aw = 0, d_aw = 0, /* aways set */ wwa = 0, d_wwa = 0, /* whowas aways */ wwuw = 0, d_wwuw = 0; /* whowas uwas */ u_long chm = 0, d_chm = 0, /* memory used by channels */ chhm = 0, d_chhm = 0, /* memory used by channel in history */ chbm = 0, d_chbm = 0, /* memory used by channel bans */ lcm = 0, d_lcm = 0, /* memory used by local clients */ rcm = 0, d_rcm = 0, /* memory used by remote clients */ awm = 0, d_awm = 0, /* memory used by aways */ wwam = 0, d_wwam = 0, /* whowas away memory used */ wwm = 0, d_wwm = 0, /* whowas array memory used */ dm = 0, d_dm = 0, /* delay array memory used */ com = 0, d_com = 0, /* memory used by conf lines */ db = 0, d_db = 0, /* memory used by dbufs */ rm = 0, d_rm = 0, /* res memory used */ totcl = 0, d_totcl = 0, totch = 0, d_totch = 0, totww = 0, d_totww = 0, tot = 0, d_tot = 0; time_t start = 0; if (debug) { start = time(NULL); count_whowas_memory(&d_wwu, &d_wwa, &d_wwam, &d_wwuw); d_wwm = sizeof(aName) * ww_size; d_dm = sizeof(aLock) * lk_size; } wwu = istat.is_wwusers; wwa = istat.is_wwaways; wwam = istat.is_wwawaysmem; wwuw = istat.is_wwuwas; wwm = sizeof(aName) * ww_size; dm = sizeof(aLock) * lk_size; /*lc = istat.is_unknown + istat.is_myclnt + istat.is_serv;*/ lc = istat.is_localc; lcc = istat.is_conflink; rc = istat.is_remc; us = istat.is_users; usi = istat.is_useri; usc = istat.is_userc; aw = istat.is_away; awm = istat.is_awaymem; if (debug) { for (acptr = client; acptr; acptr = acptr->next) { if (MyConnect(acptr)) { d_lc++; for (link = acptr->confs; link; link=link->next) { d_lcc++; } } else { d_rc++; } if (acptr->user) { invLink *ilink; d_us++; for (ilink = acptr->user->invited; ilink; ilink = ilink->next) { d_usi++; } d_usc += acptr->user->joined; if (acptr->user->away) { d_aw++; d_awm += (strlen(acptr->user->away)+1); } } } } lcm = lc * CLIENT_LOCAL_SIZE; rcm = rc * CLIENT_REMOTE_SIZE; d_lcm = d_lc * CLIENT_LOCAL_SIZE; d_rcm = d_rc * CLIENT_REMOTE_SIZE; ch = istat.is_chan; chm = istat.is_chanmem; chh = istat.is_hchan; chhm = istat.is_hchanmem; chi = istat.is_invite; chb = istat.is_bans; chbm = istat.is_banmem + chb * sizeof(Link); chu = istat.is_chanusers; if (debug) { for (chptr = channel; chptr; chptr = chptr->nextch) { if (chptr->users == 0) { d_chh++; d_chhm+=strlen(chptr->chname)+sizeof(aChannel); } else { d_ch++; d_chm += (strlen(chptr->chname) + sizeof(aChannel)); } for (link = chptr->members; link; link = link->next) { d_chu++; } for (link = chptr->invites; link; link = link->next) { d_chi++; } for (link = chptr->mlist; link; link = link->next) { d_chb++; d_chbm += strlen(link->value.cp) + 1; } } d_chbm += d_chb * sizeof(Link); } co = istat.is_conf; com = istat.is_confmem; cl = istat.is_class; if (debug) { for (aconf = conf; aconf; aconf = aconf->next) { d_co++; d_com += aconf->host ? strlen(aconf->host)+1 : 0; d_com += aconf->passwd ? strlen(aconf->passwd)+1 : 0; d_com += aconf->name ? strlen(aconf->name)+1 : 0; d_com += aconf->ping ? sizeof(*aconf->ping) : 0; d_com += sizeof(aConfItem); } for (cltmp = classes; cltmp; cltmp = cltmp->next) { d_cl++; } } if (debug) sendto_one(cptr, ":%s %d %s :Request processed in %u seconds", me.name, RPL_STATSDEBUG, nick, time(NULL) - start); sendto_one(cptr, ":%s %d %s :Client Local %d(%lu) Remote %d(%lu) Auth %d(%lu)", me.name, RPL_STATSDEBUG, nick, lc, lcm, rc, rcm, istat.is_auth, istat.is_authmem); if (debug && (lc != d_lc || lcm != d_lcm || rc != d_rc || rcm != d_rcm)) { sendto_one(cptr, ":%s %d %s :Client Local %d(%lu) Remote %d(%lu) [REAL]", me.name, RPL_STATSDEBUG, nick, d_lc, d_lcm, d_rc, d_rcm); } sendto_one(cptr, ":%s %d %s :Users %d in/visible %d/%d(%lu) Invites %d(%lu)", me.name, RPL_STATSDEBUG, nick, us, istat.is_user[1], istat.is_user[0], us*sizeof(anUser), usi, usi*sizeof(Link)); if (debug && (us != d_us || usi != d_usi)) { sendto_one(cptr, ":%s %d %s :Users %d(%lu) Invites %d(%lu) [REAL]", me.name, RPL_STATSDEBUG, nick, d_us, d_us*sizeof(anUser), d_usi, d_usi * sizeof(Link)); } sendto_one(cptr, ":%s %d %s :User channels %d(%lu) Aways %d(%lu)", me.name, RPL_STATSDEBUG, nick, usc, usc*sizeof(Link), aw, awm); if (debug && (usc != d_usc || aw != d_aw || awm != d_awm)) { sendto_one(cptr, ":%s %d %s :User channels %d(%lu) Aways %d(%lu) [REAL]", me.name, RPL_STATSDEBUG, nick, d_usc, d_usc*sizeof(Link), d_aw, d_awm); } sendto_one(cptr, ":%s %d %s :Attached confs %d(%lu)", me.name, RPL_STATSDEBUG, nick, lcc, lcc*sizeof(Link)); if (debug && lcc != d_lcc) { sendto_one(cptr, ":%s %d %s :Attached confs %d(%lu) [REAL]", me.name, RPL_STATSDEBUG, nick, d_lcc, d_lcc*sizeof(Link)); } totcl = lcm + rcm + us*sizeof(anUser) + usc*sizeof(Link) + awm; totcl += lcc*sizeof(Link) + usi*sizeof(Link); d_totcl = d_lcm + d_rcm + d_us*sizeof(anUser) + d_usc*sizeof(Link); d_totcl += d_awm + d_lcc*sizeof(Link) + d_usi*sizeof(Link); sendto_one(cptr, ":%s %d %s :Conflines %d(%lu)", me.name, RPL_STATSDEBUG, nick, co, com); if (debug && (co != d_co || com != d_com)) { sendto_one(cptr, ":%s %d %s :Conflines %d(%lu) [REAL]", me.name, RPL_STATSDEBUG, nick, d_co, d_com); } sendto_one(cptr, ":%s %d %s :Classes %d(%lu)", me.name, RPL_STATSDEBUG, nick, cl, cl*sizeof(aClass)); if (debug && cl != d_cl) { sendto_one(cptr, ":%s %d %s :Classes %d(%lu) [REAL]", me.name, RPL_STATSDEBUG, nick, d_cl, d_cl*sizeof(aClass)); } sendto_one(cptr, ":%s %d %s :Channels %d(%lu) Modes %d(%lu) History %d(%lu) Cache %d(%lu)", me.name, RPL_STATSDEBUG, nick, ch, chm, chb, chbm, chh, chhm, istat.is_cchan, istat.is_cchanmem); if (debug && (ch != d_ch || chm != d_chm || chb != d_chb || chbm != d_chbm || chh != d_chh || chhm != d_chhm)) { sendto_one(cptr, ":%s %d %s :Channels %d(%lu) Modes %d(%lu) History %d(%lu) [REAL]", me.name, RPL_STATSDEBUG, nick, d_ch, d_chm, d_chb, d_chbm, d_chh, d_chhm); } sendto_one(cptr, ":%s %d %s :Channel members %d(%lu) invite %d(%lu)", me.name, RPL_STATSDEBUG, nick, chu, chu*sizeof(Link), chi, chi*sizeof(Link)); if (debug && (chu != d_chu || chi != d_chi)) { sendto_one(cptr, ":%s %d %s :Channel members %d(%lu) invite %d(%lu) " "[REAL]", me.name, RPL_STATSDEBUG, nick, d_chu, d_chu*sizeof(Link), d_chi, d_chi*sizeof(Link)); } totch = chm + chhm + chbm + chu*sizeof(Link) + chi*sizeof(Link); d_totch = d_chm + d_chhm + d_chbm + d_chu*sizeof(Link) + d_chi*sizeof(Link); sendto_one(cptr, ":%s %d %s :Whowas users %d(%lu) away %d(%lu) links %d(%lu)", me.name, RPL_STATSDEBUG, nick, wwu, wwu*sizeof(anUser), wwa, wwam, wwuw, wwuw*sizeof(Link)); if (debug && (wwu != d_wwu || wwa != d_wwa || wwam != d_wwam || wwuw != d_wwuw)) { sendto_one(cptr, ":%s %d %s :Whowas users %d(%lu) away %d(%lu) " "links %d(%lu) [REAL]", me.name, RPL_STATSDEBUG, nick, d_wwu, d_wwu*sizeof(anUser), d_wwa, d_wwam, d_wwuw, d_wwuw*sizeof(Link)); } sendto_one(cptr, ":%s %d %s :Whowas array %d(%lu) Delay array %d(%lu)", me.name, RPL_STATSDEBUG, nick, ww_size, wwm, lk_size, dm); if (debug && (wwm != d_wwm || dm != d_dm)) { sendto_one(cptr, ":%s %d %s :Whowas array %d(%lu) Delay array %d(%lu) " "[REAL]", me.name, RPL_STATSDEBUG, nick, ww_size, d_wwm, lk_size, d_dm); } totww = wwu*sizeof(anUser) + wwam + wwm; d_totww = d_wwu*sizeof(anUser) + d_wwam + d_wwm; sendto_one(cptr, ":%s %d %s :Hash: client %d(%lu) chan %d(%lu)", me.name, RPL_STATSDEBUG, nick, _HASHSIZE, sizeof(aHashEntry) * _HASHSIZE, _CHANNELHASHSIZE, sizeof(aHashEntry) * _CHANNELHASHSIZE); d_db = db = istat.is_dbufnow * sizeof(dbufbuf); db = istat.is_dbufnow * sizeof(dbufbuf); sendto_one(cptr, ":%s %d %s :Dbuf blocks %lu(%lu) (> %lu [%lu]) (%lu < %lu) " "[%lu]", me.name, RPL_STATSDEBUG, nick, istat.is_dbufnow, db, istat.is_dbuf, (u_int) (((u_int)BUFFERPOOL) / ((u_int)sizeof(dbufbuf))), istat.is_dbufuse, istat.is_dbufmax, istat.is_dbufmore); d_rm = rm = cres_mem(cptr, nick); tot = totww + totch + totcl + com + cl*sizeof(aClass) + db + rm; tot += sizeof(aHashEntry) * _HASHSIZE; tot += sizeof(aHashEntry) * _CHANNELHASHSIZE; d_tot = d_totww + d_totch + d_totcl + d_com + d_cl*sizeof(aClass); d_tot += d_db + d_rm; d_tot += sizeof(aHashEntry) * _HASHSIZE; d_tot += sizeof(aHashEntry) * _CHANNELHASHSIZE; sendto_one(cptr, ":%s %d %s :Total: ww %lu ch %lu cl %lu co %lu db %lu", me.name, RPL_STATSDEBUG, nick, totww, totch, totcl, com,db); if (debug && tot != d_tot) { sendto_one(cptr, ":%s %d %s :Total: ww %lu ch %lu cl %lu co %lu " "db %lu [REAL]", me.name, RPL_STATSDEBUG, nick, d_totww, d_totch, d_totcl, d_com, d_db); sendto_one(cptr, ":%s %d %s :TOTAL: %lu [REAL]", me.name, RPL_STATSDEBUG, nick, d_tot); } sendto_one(cptr, ":%s %d %s :TOTAL: %d sbrk(0)-etext: %u", me.name, RPL_STATSDEBUG, nick, tot, (u_long)sbrk((size_t)0)-(u_long)sbrk0); return; }
/** Report memory usage statistics to a client. * @param cptr Client to send data to. * @param sd StatDesc that generated the stats request (ignored). * @param param Extra parameter from user (ignored). */ void count_memory(struct Client *cptr, const struct StatDesc *sd, char *param) { struct Client *acptr; struct Invite *inv; struct SLink *link; struct Ban *ban; struct Channel *chptr; struct ConfItem *aconf; const struct ConnectionClass* cltmp; struct Membership* member; int acc = 0, /* accounts */ c = 0, /* clients */ cn = 0, /* connections */ ch = 0, /* channels */ lcc = 0, /* local client conf links */ chb = 0, /* channel bans */ wwu = 0, /* whowas users */ cl = 0, /* classes */ co = 0, /* conf lines */ listeners = 0, /* listeners */ memberships = 0; /* channel memberships */ int usi = 0, /* users invited */ aw = 0, /* aways set */ wwa = 0, /* whowas aways */ gl = 0, /* glines */ ju = 0; /* jupes */ size_t chm = 0, /* memory used by channels */ chbm = 0, /* memory used by channel bans */ cm = 0, /* memory used by clients */ cnm = 0, /* memory used by connections */ us = 0, /* user structs */ usm = 0, /* memory used by user structs */ awm = 0, /* memory used by aways */ wwam = 0, /* whowas away memory used */ wwm = 0, /* whowas array memory used */ wt = 0, /* watch entrys */ wtm = 0, /* memory used by watchs */ #if defined(DDB) dbs = 0, /* keys of database */ dbm = 0, /* memory used by DDB */ #endif glm = 0, /* memory used by glines */ jum = 0, /* memory used by jupes */ com = 0, /* memory used by conf lines */ dbufs_allocated = 0, /* memory used by dbufs */ dbufs_used = 0, /* memory used by dbufs */ msg_allocated = 0, /* memory used by struct Msg */ msgbuf_allocated = 0, /* memory used by struct MsgBuf */ listenersm = 0, /* memory used by listetners */ rm = 0, /* res memory used */ totcl = 0, totch = 0, totww = 0, tot = 0; count_whowas_memory(&wwu, &wwm, &wwa, &wwam); wwm += sizeof(struct Whowas) * feature_uint(FEAT_NICKNAMEHISTORYLENGTH); wwm += sizeof(struct Whowas *) * WW_MAX; for (acptr = GlobalClientList; acptr; acptr = cli_next(acptr)) { c++; if (MyConnect(acptr)) { cn++; for (link = cli_confs(acptr); link; link = link->next) lcc++; } if (cli_user(acptr)) { for (inv = cli_user(acptr)->invited; inv; inv = inv->next_user) usi++; for (member = cli_user(acptr)->channel; member; member = member->next_channel) ++memberships; if (cli_user(acptr)->away) { aw++; awm += (strlen(cli_user(acptr)->away) + 1); } } #if defined(UNDERNET) if (IsAccount(acptr)) acc++; #endif } cm = c * sizeof(struct Client); cnm = cn * sizeof(struct Connection); user_count_memory(&us, &usm); for (chptr = GlobalChannelList; chptr; chptr = chptr->next) { ch++; chm += (strlen(chptr->chname) + sizeof(struct Channel)); for (ban = chptr->banlist; ban; ban = ban->next) { chb++; chbm += strlen(ban->who) + strlen(ban->banstr) + 2 + sizeof(*ban); } } for (aconf = GlobalConfList; aconf; aconf = aconf->next) { co++; com += aconf->host ? strlen(aconf->host) + 1 : 0; com += aconf->passwd ? strlen(aconf->passwd) + 1 : 0; com += aconf->name ? strlen(aconf->name) + 1 : 0; com += sizeof(struct ConfItem); } for (cltmp = get_class_list(); cltmp; cltmp = cltmp->next) cl++; #if defined(USE_SSL) send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, ":Clients %d(%zu) Connections %d(%zu) SSL %d", c, cm, cn, cnm, ssl_count()); #else send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, ":Clients %d(%zu) Connections %d(%zu)", c, cm, cn, cnm); #endif send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, ":Users %zu(%zu) Accounts %d(%zu) Invites %d(%zu)", us, usm, acc, acc * (ACCOUNTLEN + 1), usi, usi * sizeof(struct Invite)); send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, ":User channels %d(%zu) Aways %d(%zu)", memberships, memberships * sizeof(struct Membership), aw, awm); totcl = cm + cnm + us * sizeof(struct User) + memberships * sizeof(struct Membership) + awm; totcl += lcc * sizeof(struct SLink) + usi * sizeof(struct SLink); send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, ":Conflines %d(%zu) Attached %d(%zu) Classes %d(%zu)", co, com, lcc, lcc * sizeof(struct SLink), cl, cl * sizeof(struct ConnectionClass)); send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, ":Channels %d(%zu) Bans %d(%zu)", ch, chm, chb, chbm); send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, ":Channel Members %d(%zu)", memberships, memberships * sizeof(struct Membership)); totch = chm + chbm; send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, ":Whowas Users %d(%zu) Away %d(%zu) Array %u(%zu)", wwu, wwu * sizeof(struct User), wwa, wwam, feature_uint(FEAT_NICKNAMEHISTORYLENGTH), wwm); totww = wwu * sizeof(struct User) + wwam + wwm; watch_count_memory(&wt, &wtm); send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, ":Watchs %d(%zu)", wt, wtm); motd_memory_count(cptr); gl = gline_memory_count(&glm); ju = jupe_memory_count(&jum); send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, ":Glines %d(%zu) Jupes %d(%zu)", gl, glm, ju, jum); send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, ":Hash: client %d(%zu), chan is the same", HASHSIZE, sizeof(void *) * HASHSIZE); count_listener_memory(&listeners, &listenersm); send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, ":Listeners allocated %d(%zu)", listeners, listenersm); #if defined(DDB) ddb_count_memory(&dbs, &dbm); send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, ":DDB keys allocated %d(%zu)", dbs, dbm); #endif /* * NOTE: this count will be accurate only for the exact instant that this * message is being sent, so the count is affected by the dbufs that * are being used to send this message out. If this is not desired, move * the dbuf_count_memory call to a place before we start sending messages * and cache DBufAllocCount and DBufUsedCount in variables until they * are sent. */ dbuf_count_memory(&dbufs_allocated, &dbufs_used); send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, ":DBufs allocated %u(%zu) used %u(%zu)", DBufAllocCount, dbufs_allocated, DBufUsedCount, dbufs_used); /* The DBuf caveats now count for this, but this routine now sends * replies all on its own. */ msgq_count_memory(cptr, &msg_allocated, &msgbuf_allocated); rm = cres_mem(cptr); tot = totww + totch + totcl + com + cl * sizeof(struct ConnectionClass) + dbufs_allocated + msg_allocated + msgbuf_allocated + rm; tot += sizeof(void *) * HASHSIZE * 3; #if defined(MDEBUG) send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, ":Allocations: %zu(%zu)", fda_get_block_count(), fda_get_byte_count()); #endif send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, ":Total: ww %zu ch %zu cl %zu co %zu db %zu ms %zu mb %zu", totww, totch, totcl, com, dbufs_allocated, msg_allocated, msgbuf_allocated); }