#include #include #include #include #include #include #include #include #include "unix_lock.h" #include "StatMgr.h" #if HAS_ATOMIC8 int64_t CStatItem::dummy; #else uint32_t CStatItemU32::dummy; int32_t CStatItemS32::dummy; CStatItemObject CStatItem::dummy; #endif int64_t CStatSampleObject::dummyCnt[2]; const TStatInfo CStatSampleObject::dummyInfo = { 0, 0, SA_SAMPLE, 0 }; CStatSampleObject CStatSample::dummy; int64_t CStatSampleObject::count(unsigned int n) { P a(this); if(n > info->cnt) return 0; return cnt[n]; } int64_t CStatSampleObject::sum(void) { P a(this); return cnt[0]; } int64_t CStatSampleObject::average(int64_t o) { P a(this); return cnt[1] ? cnt[0]/cnt[1] : o; } void CStatSampleObject::push(int64_t v) { P a(this); cnt[0] += v; cnt[1] ++; for(unsigned int n = 0; ncnt; n++) if(v >= info->vptr[n]) cnt[2+n]++; } void CStatSampleObject::output(int64_t *v) { P a(this); memcpy(v, cnt, (2+16)*sizeof(int64_t)); memset(cnt, 0, (2+16)*sizeof(int64_t)); } CStatManager::CStatManager() { header = NULL; indexsize = 0; memset(fmap, 0, sizeof(fmap)); info = NULL; numinfo = 0; lockdev = 0; lockino = 0; lockfd = -1; } CStatManager::~CStatManager() { if(header) { for(unsigned int i=0; idatasize); munmap(header, indexsize); } if(info) delete []info; if(lockfd >= 0) close(lockfd); } int CStatManager::InitStatInfo(const char *name, const char *indexfile, int isc) { P __a(this); int fd; fd = open(indexfile, O_RDWR); if( fd < 0 ) { snprintf(szErrMsg, sizeof(szErrMsg), "cannot open index file"); return -1; } struct stat st; if(fstat(fd, &st) != 0) { snprintf(szErrMsg, sizeof(szErrMsg), "fstat() failed on index file"); close(fd); return -2; } lockdev = st.st_dev; lockino = st.st_ino; if(isc==1) { if(Lock("serv") < 0) { snprintf(szErrMsg, sizeof(szErrMsg), "stat data locked by other process"); close(fd); return -2; } } indexsize = lseek(fd, 0L, SEEK_END); if(indexsize < sizeof(TStatHeader) + sizeof(TStatInfo)) { // file too short close(fd); snprintf(szErrMsg, sizeof(szErrMsg), "index file too short"); return -1; } header = (TStatHeader *)mmap(NULL, indexsize, PROT_READ, MAP_SHARED, fd, 0); close(fd); if(header == MAP_FAILED) { header = NULL; snprintf(szErrMsg, sizeof(szErrMsg), "mmap index file failed"); return -2; } if(header->signature != *(unsigned int *)"sTaT") { snprintf(szErrMsg, sizeof(szErrMsg), "bad index file signature"); return -1; } if(header->version != 1) { snprintf(szErrMsg, sizeof(szErrMsg), "bad index file version"); return -1; } if(indexsize < header->indexsize) { // file too short snprintf(szErrMsg, sizeof(szErrMsg), "index file too short"); return -1; } if(header->indexsize > (4<<20)) { // data too large snprintf(szErrMsg, sizeof(szErrMsg), "index size too large"); return -1; } if(header->datasize > (1<<20)) { // data too large snprintf(szErrMsg, sizeof(szErrMsg), "data size too large"); return -1; } if(strncmp(name, header->name, sizeof(header->name)) != 0) { // name mismatch snprintf(szErrMsg, sizeof(szErrMsg), "stat name mismatch"); return -1; } if(header->numinfo==0) { snprintf(szErrMsg, sizeof(szErrMsg), "No Stat ID defined"); return -1; } numinfo = header->numinfo; info = new CStatInfo[numinfo]; TStatInfo *si = header->first(); for(unsigned int i=0; inext()) { if(si->next() > header->last()) { snprintf(szErrMsg, sizeof(szErrMsg), "index info exceed EOF"); return -1; } if(si->off+si->datasize() > header->datasize) { snprintf(szErrMsg, sizeof(szErrMsg), "data offset exceed EOF"); return -1; } // first 16 bytes reserved by header if(si->off < 16) { snprintf(szErrMsg, sizeof(szErrMsg), "data offset < 16"); return -1; } if(si->cnt + si->cnt1 > 16) { snprintf(szErrMsg, sizeof(szErrMsg), "too many base value"); return -1; } info[i].owner = this; info[i].si = si; idmap[si->id] = &info[i]; } mprotect(header, indexsize, PROT_READ); char buf[strlen(indexfile)+10]; strncpy(buf,indexfile, strlen(indexfile)+10); char *p = strrchr(buf, '.'); if(p==NULL) p = buf + strlen(buf); fmap[SC_CUR] = (char *)mapfile(NULL, header->datasize); strncpy(p, ".10s", 5); fmap[SC_10S] = (char *)mapfile(buf, header->datasize); strncpy(p, ".10m", 5); fmap[SC_10M] = (char *)mapfile(buf, header->datasize); strncpy(p, ".all", 5); fmap[SC_ALL] = (char *)mapfile(buf, header->datasize); at_cur(2*8) = header->createtime; if(isc==0) { int n; do { n = 0; for(unsigned int i=0; icnt + info[i].si->cnt1; if(cnt==0) continue; info[i].expr = InitExpr(cnt, info[i].si->vptr); if(info[i].expr) { expr.push_back(&info[i]); n++; } } } while(n>0); at_cur(3*8) = time(NULL); // startup time atomic_t *a0 = (atomic_t *)&at_cur(0); int v = atomic_add_return(1, a0); atomic_set(a0+1, v); } return 0; } static const TStatDefinition SysStatDefinition[] = { { STAT_CREATE_TIME, "statinfo create time", SA_CONST, SU_DATETIME }, { STAT_STARTUP_TIME, "startup time" , SA_CONST, SU_DATETIME }, { STAT_CHECKPOINT_TIME, "checkpoint time", SA_CONST, SU_DATETIME }, }; #define NSYSID (sizeof(SysStatDefinition)/sizeof(TStatDefinition)) int CStatManager::CreateStatIndex( const char *name, const char *indexfile, const TStatDefinition *statdef, char *szErrMsg, int iErrLen ) { if(access(indexfile, F_OK)==0) { snprintf(szErrMsg, iErrLen, "index file already exists"); return -1; } int numinfo = NSYSID; int indexsize = sizeof(TStatHeader)+sizeof(TStatInfo)*NSYSID; int datasize = 16 + sizeof(int64_t)*NSYSID; unsigned int i; for(i=0; statdef[i].id; i++) { if(statdef[i].cnt+statdef[i].cnt1 > 16) { snprintf(szErrMsg, iErrLen, "too many argument counts"); return -1; } numinfo++; indexsize += sizeof(TStatInfo); switch(statdef[i].type) { case SA_SAMPLE: indexsize += 16 * sizeof(int64_t); datasize += 18 * sizeof(int64_t); break; case SA_EXPR: indexsize += (statdef[i].cnt+statdef[i].cnt1) * sizeof(int64_t); default: datasize += sizeof(int64_t); } } if(indexsize > (4<<20)) { snprintf(szErrMsg, iErrLen, "index file size too large"); return -1; } if(datasize > (1<<20)) { snprintf(szErrMsg, iErrLen, "data file size too large"); return -1; } TStatHeader *header = (TStatHeader *)mapfile(indexfile, indexsize); if (header == NULL) { snprintf(szErrMsg, iErrLen, "map stat file error"); return -1; } header->signature = *(int *)"sTaT"; header->version = 1; header->numinfo = numinfo; header->indexsize = indexsize; header->datasize = datasize; strncpy(header->name, name, sizeof(header->name)); TStatInfo *si = header->first(); unsigned int off = 16; for(i=0; inext()) { si->id = SysStatDefinition[i].id; si->type = SysStatDefinition[i].type; si->unit = SysStatDefinition[i].unit; si->off = off; si->cnt = 0; si->cnt1 = 0; strncpy(si->name, SysStatDefinition[i].name, sizeof(si->name)); off += si->datasize(); } for(i=0; statdef[i].id; i++, si=si->next()) { si->id = statdef[i].id; si->type = statdef[i].type; si->unit = statdef[i].unit; si->off = off; si->cnt = 0; si->cnt1 = 0; strncpy(si->name, statdef[i].name, sizeof(si->name)); off += si->datasize(); if(si->issample()) { unsigned char &j = si->cnt; for(j=0; j<16 && statdef[i].arg[j]; j++) si->vptr[j] = statdef[i].arg[j]; } else if(si->isexpr()) { si->cnt = statdef[i].cnt; si->cnt1 = statdef[i].cnt1; for(int j=0; jcnt+si->cnt1; j++) si->vptr[j] = statdef[i].arg[j]; } } header->createtime = time(NULL); // create time munmap(header, indexsize); char buf[strlen(indexfile)+10]; strncpy(buf, indexfile, strlen(indexfile)+10); char *p = strrchr(buf, '.'); if(p==NULL) p = buf + strlen(buf); strncpy(p, ".dat", 5); unlink(buf); strncpy(p, ".10s", 5); unlink(buf); strncpy(p, ".10m", 5); unlink(buf); strncpy(p, ".all", 5); unlink(buf); return 0; } void *CStatManager::mapfile(const char *fn, int size) { int fd = open(fn, O_RDWR|O_CREAT, 0666); void *map = NULL; if(fd >= 0) { if(size > 0) ftruncate(fd, size); else size = lseek(fd, 0L, SEEK_END); if(size > 0) map = mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); close(fd); } else if(size > 0) { map = mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0); } if(map == MAP_FAILED) { map = NULL; } return map; } #if HAS_ATOMIC8 CStatItem CStatManager::GetItem(unsigned int id) { //P __a(this); CStatInfo *i = idmap[id]; if(i==NULL || i->issample()) { CStatItem v; return v; } return (CStatItem)&at_cur(i->offset()); } CStatItem CStatManager::Get10sItem(unsigned int id) { CStatInfo *i = idmap[id]; if(i==NULL || i->issample()) { CStatItem v; return v; } return (CStatItem)&at_10s(i->offset()); } #else CStatItemS32 CStatManager::GetItemS32(unsigned int id) { P __a(this); CStatInfo *i = idmap[id]; if(i==NULL || i->issample() || !i->istype(1)) { CStatItemS32 v; return v; } i->ltype = 1; return (CStatItemS32)(int32_t *)&at_cur(i->offset()); } CStatItemU32 CStatManager::GetItemU32(unsigned int id) { P __a(this); CStatInfo *i = idmap[id]; if(i==NULL || i->issample() || i->istype(2)) { CStatItemU32 v; return v; } i->ltype = 2; return (CStatItemU32)(uint32_t *)&at_cur(i->offset()); } CStatItem CStatManager::GetItem(unsigned int id) { P __a(this); CStatInfo *i = idmap[id]; if(i==NULL || i->issample() || !i->istype(3)) { CStatItem v; return v; } i->ltype = 3; if(i->vobj == NULL) i->vobj = new CStatItemObject(&at_cur(i->offset())); return CStatItem(i->vobj); } CStatItem CStatManager::Get10sItem(unsigned int id) { P __a(this); CStatInfo *i = idmap[id]; if(i==NULL || i->issample() || !i->istype(3)) { CStatItem v; return v; } i->ltype = 3; if(i->vobj == NULL) i->vobj = new CStatItemObject(&at_10s(i->offset())); return CStatItem(i->vobj); } #endif int64_t CStatManager::Get10SItemValue(unsigned int id) { P __a(this); int64_t ddwValue = 0; CStatInfo *i = idmap[id]; if(i==NULL || i->issample() ) { return ddwValue; } ddwValue = at_10s(i->offset()); return ddwValue; } CStatSample CStatManager::GetSample(unsigned int id) { P __a(this); CStatInfo *i = idmap[id]; if(i==NULL || !i->issample()) { CStatSample v; return v; } if(i->sobj == NULL) i->sobj = new CStatSampleObject(i->si, &at_cur(i->offset())); CStatSample v(i->sobj); return v; } int CStatManager::SetCountBase(unsigned int id, const int64_t *v, int c) { if(c < 0) c = 0; else if(c > 16) c = 16; P __a(this); CStatInfo *i = idmap[id]; if(i==NULL || !i->issample()) return -1; mprotect(header, indexsize, PROT_READ|PROT_WRITE); if(c > 0) memcpy(i->si->vptr, v, sizeof(int64_t)*c); i->si->cnt = c; mprotect(header, indexsize, PROT_READ); return c; } int CStatManager::GetCountBase(unsigned int id, int64_t *v) { P __a(this); CStatInfo *i = idmap[id]; if(i==NULL || !i->issample()) return -1; if(i->si->cnt > 0) memcpy(v, i->si->vptr, sizeof(int64_t)*i->si->cnt); return i->si->cnt; } int64_t call_imm(CStatManager::CStatExpr *info, const char *map) { return info->val; } int64_t call_id(CStatManager::CStatExpr *info, const char *map) { return *(const int64_t *)(map+info->off0); } int64_t call_negative(CStatManager::CStatExpr *info, const char *map) { return - *(const int64_t *)(map+info->off0); } int64_t call_shift_1(CStatManager::CStatExpr *info, const char *map) { return *(const int64_t *)(map+info->off0) << 1; } int64_t call_shift_2(CStatManager::CStatExpr *info, const char *map) { return *(const int64_t *)(map+info->off0) << 2; } int64_t call_shift_3(CStatManager::CStatExpr *info, const char *map) { return *(const int64_t *)(map+info->off0) << 3; } int64_t call_shift_4(CStatManager::CStatExpr *info, const char *map) { return *(const int64_t *)(map+info->off0) << 4; } int64_t call_id_multi(CStatManager::CStatExpr *info, const char *map) { return *(const int64_t *)(map+info->off0) * info->val; } int64_t call_id_multi2(CStatManager::CStatExpr *info, const char *map) { return *(const int64_t *)(map+info->off0) * *(const int64_t *)(map+info->off1); } CStatManager::CStatExpr *CStatManager::InitExpr(unsigned int cnt, int64_t *arg) { CStatInfo *info; CStatExpr *expr = new CStatExpr[cnt]; int val, id; int sub; for(unsigned int i=0; i> 32; id = arg[i] & 0xFFFFFFFF; if(id==0) { expr[i].val = val; expr[i].off0 = 0; expr[i].off1 = 0; expr[i].call = &call_imm; } else if((id&0x80000000)==0) { expr[i].val = val; sub = id % 20; id /= 20; info = idmap[id]; if(info==NULL || (sub>0 && !info->issample())) { goto bad; } // not yet initialized if(info->isexpr() && info->expr==NULL) goto bad; expr[i].off0 = info->offset()+ sub * sizeof(int64_t); expr[i].off1 = 0; switch(val) { case -1: expr[i].call = &call_negative; break; case 0: expr[i].call = &call_imm; break; case 1: expr[i].call = &call_id; break; case 2: expr[i].call = &call_shift_1; break; case 4: expr[i].call = &call_shift_2; break; case 8: expr[i].call = &call_shift_3; break; case 16: expr[i].call = &call_shift_4; break; default: expr[i].call = &call_id_multi; break; } } else { expr[i].val = 0; id &= 0x7FFFFFFF; sub = id % 20; id /= 20; info = idmap[id]; if(info==NULL || (sub>0 && !info->issample())) { goto bad; } // not yet initialized if(info->isexpr() && info->expr==NULL) goto bad; expr[i].off0 = info->offset()+ sub * sizeof(int64_t); id = val & 0x7FFFFFFF; sub = id % 20; id /= 20; info = idmap[id]; if(info==NULL || (sub>0 && !info->issample())) { goto bad; } // not yet initialized if(info->isexpr() && info->expr==NULL) goto bad; expr[i].off1 = info->offset()+ sub * sizeof(int64_t); expr[i].call = &call_id_multi2; } } return expr; bad: delete []expr; return NULL; } int64_t CStatManager::CalcExpr(const char *map, unsigned int cnt, CStatExpr *expr) { int64_t v = 0; for(unsigned int i=0; i>6; } static inline void ltrend(int64_t &m, int64_t s) { m = (m*255+s)>>8; } void CStatManager::RunJobOnce(void) { atomic_t *a0 = (atomic_t *)&at_cur(0); int a0v = atomic_add_return(1, a0); at_cur(4*8) = time(NULL); // checkpoint time for(unsigned i=0; ioutput(&at_10s(off)); } else { memcpy(&at_10s(off), &at_cur(off), 18*sizeof(int64_t)); memset(&at_cur(off), 0, 18*sizeof(int64_t)); } for(unsigned n=0; n<18; n++) { // count all at_all(off, n) += at_10s(off, n); // 10m trend(at_10m(off, n), at_10s(off, n)); } break; case SA_COUNT: #if !HAS_ATOMIC8 if(info[i].ltype==1) { CStatItemS32 vi((int32_t *)&at_cur(off)); at_10s(off) = vi.clear(); } else #else { CStatItem vi(&at_cur(off)); at_10s(off) = vi.clear(); } #endif // count all at_all(off) += at_10s(off); // 10m trend(at_10m(off), at_10s(off)); break; case SA_VALUE: #if !HAS_ATOMIC8 if(info[i].ltype==1) { CStatItemS32 vi((int32_t *)&at_cur(off)); at_10s(off) = vi.get(); } else #else { CStatItem vi(&at_cur(off)); at_10s(off) = vi.get(); } #endif // 10m trend(at_10m(off), at_10s(off)); ltrend(at_all(off), at_10m(off)); break; case SA_CONST: at_10s(off) = at_cur(off); at_10m(off) = at_cur(off); at_all(off) = at_cur(off); break; } } // calculate expression for(unsigned i=0; icnt1==0) { at_10s(off) = CalcExpr(fmap[SC_10S], e.si->cnt, e.expr); at_all(off) = CalcExpr(fmap[SC_ALL], e.si->cnt, e.expr); } else { div = CalcExpr(fmap[SC_10S], e.si->cnt1, e.expr+e.si->cnt); if(div != 0) { sum = CalcExpr(fmap[SC_10S], e.si->cnt, e.expr); at_10s(off) = sum/div; } div = CalcExpr(fmap[SC_ALL], e.si->cnt1, e.expr+e.si->cnt); if(div != 0) { sum = CalcExpr(fmap[SC_ALL], e.si->cnt, e.expr); at_all(off) = sum/div; } } trend(at_10m(off), at_10s(off)); } atomic_set(a0+1, a0v); } int CStatManager::Lock(const char *type) { if(lockfd >= 0) return 0; lockfd = UnixSocketLock("tlock-stat-%s-%llu-%llu", type, (long long)lockdev, (long long)lockino); return lockfd >= 0 ? 0 : -1; } void CStatManager::clear(void) { for(unsigned i=0; i