/** * Updates the cached NIO counters using PDH if the counters were updated * more than a second ago. * Computes the delta between current and last counters, checks for * discontinuities (including determining whether 32 bit counters are being * use - eg for bytes - and have wrapped), accumulates totals, and stores * the latest counter values for delta computation on next invokation. * If 64 bit counters are detected, indicates this by setting * sp->nio->polling_seconds = 0 so that more * frequent polling of counters can be turned off. */ void updateNioCounters(HSP *sp) { // don't do anything if we refreshed the numbers less than a second ago if (sp->nio_last_update == sp->clk) { return; } sp->nio_last_update = sp->clk; // first read all the counters into new_nio if (query == NULL) { PDH_STATUS status = createCounterQuery(); if (status != ERROR_SUCCESS) { query = NULL; myLog(LOG_ERR, "updateNioCounters: creating query failed: 0x%x", status); return; } } PdhCollectQueryData(query); PPDH_RAW_COUNTER_ITEM_W values; uint32_t icount = 0; icount = getRawCounterValues(&bytesIn, &values); if (icount > 0) { for (uint32_t i = 0; i < icount; i++) { SFLHost_nio_counters *newctrs = getNewNIO(sp, values[i].szName); if (newctrs != NULL) { newctrs->bytes_in = values[i].RawValue.FirstValue; //myLog(LOG_INFO, "updateNioCounters: adapter=%S bytesIn=%lu", // values[i].szName, newctrs->bytes_in); } } my_free(values); icount = 0; } icount = getRawCounterValues(&pktsIn, &values); if (icount > 0) { for (uint32_t i = 0; i < icount; i++) { SFLHost_nio_counters *newctrs = getNewNIO(sp, values[i].szName); if(newctrs != NULL) { newctrs->pkts_in = (uint32_t)values[i].RawValue.FirstValue; } } my_free(values); icount = 0; } icount = getRawCounterValues(&errorsIn, &values); if (icount > 0) { for (uint32_t i = 0; i < icount; i++) { SFLHost_nio_counters *newctrs = getNewNIO(sp, values[i].szName); if(newctrs != NULL) { newctrs->errs_in = (uint32_t)values[i].RawValue.FirstValue; } } my_free(values); icount = 0; } icount = getRawCounterValues(&discardsIn, &values); if (icount > 0) { for (uint32_t i = 0; i < icount; i++) { SFLHost_nio_counters *newctrs = getNewNIO(sp, values[i].szName); if (newctrs != NULL) { newctrs->drops_in = (uint32_t)values[i].RawValue.FirstValue; } } my_free(values); icount = 0; } icount = getRawCounterValues(&bytesOut, &values); if (icount > 0) { for (uint32_t i = 0; i < icount; i++) { SFLHost_nio_counters *newctrs = getNewNIO(sp, values[i].szName); if (newctrs != NULL) { newctrs->bytes_out = values[i].RawValue.FirstValue; } } my_free(values); icount = 0; } icount = getRawCounterValues(&pktsOut, &values); if (icount > 0) { for (uint32_t i = 0; i < icount; i++) { SFLHost_nio_counters *newctrs = getNewNIO(sp, values[i].szName); if (newctrs != NULL) { newctrs->pkts_out = (uint32_t)values[i].RawValue.FirstValue; } } my_free(values); icount = 0; } icount = getRawCounterValues(&errorsOut, &values); if (icount > 0) { for (uint32_t i = 0; i < icount; i++) { SFLHost_nio_counters *newctrs = getNewNIO(sp, values[i].szName); if (newctrs != NULL) { newctrs->errs_out = (uint32_t)values[i].RawValue.FirstValue; } } my_free(values); icount = 0; } icount = getRawCounterValues(&discardsOut, &values); if (icount > 0) { for (uint32_t i = 0; i < icount; i++) { SFLHost_nio_counters *newctrs = getNewNIO(sp, values[i].szName); if (newctrs != NULL) { newctrs->drops_out = (uint32_t)values[i].RawValue.FirstValue; } } my_free(values); icount = 0; } // now compute the deltas, sanity check them, accumulate and latch for (uint32_t i = 0; i < sp->adaptorList->num_adaptors; i++) { SFLAdaptor *ad = sp->adaptorList->adaptors[i]; if (ad != NULL) { HSPAdaptorNIO *nio = (HSPAdaptorNIO *)ad->userData; if (nio != NULL) { // have to detect discontinuities here, so use a full // set of latched counters and accumulators. BOOL accumulate = nio->last_update ? TRUE : FALSE; nio->last_update = sp->clk; uint64_t maxDeltaBytes = HSP_MAX_NIO_DELTA64; SFLHost_nio_counters delta; #define NIO_COMPUTE_DELTA(field) delta.field = nio->new_nio.field - nio->last_nio.field NIO_COMPUTE_DELTA(pkts_in); NIO_COMPUTE_DELTA(errs_in); NIO_COMPUTE_DELTA(drops_in); NIO_COMPUTE_DELTA(pkts_out); NIO_COMPUTE_DELTA(errs_out); NIO_COMPUTE_DELTA(drops_out); if (sp->nio_polling_secs == 0) { // 64-bit byte counters NIO_COMPUTE_DELTA(bytes_in); NIO_COMPUTE_DELTA(bytes_out); } else { // for case where byte counters are 32-bit, we need // to use 32-bit unsigned arithmetic to avoid spikes delta.bytes_in = (uint32_t)nio->new_nio.bytes_in - nio->last_bytes_in32; delta.bytes_out = (uint32_t)nio->new_nio.bytes_out - nio->last_bytes_out32; nio->last_bytes_in32 = (uint32_t)nio->new_nio.bytes_in; nio->last_bytes_out32 = (uint32_t)nio->new_nio.bytes_out; maxDeltaBytes = HSP_MAX_NIO_DELTA32; // if we detect that the OS is using 64-bits then we can turn off the faster // NIO polling. This should probably be done based on the kernel version or some // other include-file definition, but it's not expensive to do it here like this: if (nio->new_nio.bytes_in > 0xFFFFFFFF || nio->new_nio.bytes_out > 0xFFFFFFFF) { myLog(LOG_INFO, "detected 64-bit network counters"); sp->nio_polling_secs = 0; } } if (accumulate) { // sanity check in case the counters were reset under out feet. // normally we leave this to the upstream collector, but these // numbers might be getting passed through from the hardware(?) // so we treat them with particular distrust. if (delta.bytes_in > maxDeltaBytes || delta.bytes_out > maxDeltaBytes || delta.pkts_in > HSP_MAX_NIO_DELTA32 || delta.pkts_out > HSP_MAX_NIO_DELTA32) { myLog(LOG_INFO, "detected NIO counter discontinuity"); accumulate = FALSE; } } if (accumulate) { #define NIO_ACCUMULATE(field) nio->nio.field += delta.field NIO_ACCUMULATE(bytes_in); NIO_ACCUMULATE(pkts_in); NIO_ACCUMULATE(errs_in); NIO_ACCUMULATE(drops_in); NIO_ACCUMULATE(bytes_out); NIO_ACCUMULATE(pkts_out); NIO_ACCUMULATE(errs_out); NIO_ACCUMULATE(drops_out); //myLog(LOG_INFO, "accumulated NIO counters (new=%lu old=%lu delta=%lu nio->nio.bytes_in now = %lu)", // nio->new_nio.bytes_in, nio->last_nio.bytes_in, delta.bytes_in, nio->nio.bytes_in); } #define NIO_LATCH(field) nio->last_nio.field = nio->new_nio.field NIO_LATCH(bytes_in); NIO_LATCH(pkts_in); NIO_LATCH(errs_in); NIO_LATCH(drops_in); NIO_LATCH(bytes_out); NIO_LATCH(pkts_out); NIO_LATCH(errs_out); NIO_LATCH(drops_out); } } } }
/* * Uses PDH to obtain the host_cpu counters and populates the * SFLHost_spu_counters stucture. * Uses Processor, System, and Process performance counter objects * for CPU time, interrupts and contexts and registry to obtain CPU speed. */ void readCpuCounters(SFLHost_cpu_counters *cpu) { cpu->load_one = (float)load_1; cpu->load_five = (float)load_5; cpu->load_fifteen = (float)load_15; PDH_HQUERY query; if (PdhOpenQuery(NULL, 0, &query) == ERROR_SUCCESS) { PDH_HCOUNTER userTime, systemTime, idleTime, intrTime, interrupts, contexts, uptime, processes; if (addCounterToQuery(CPU_COUNTER_OBJECT, COUNTER_INSTANCE_TOTAL, CPU_COUNTER_USER, &query, &userTime) == ERROR_SUCCESS && addCounterToQuery(CPU_COUNTER_OBJECT, COUNTER_INSTANCE_TOTAL, CPU_COUNTER_SYSTEM, &query, &systemTime) == ERROR_SUCCESS && addCounterToQuery(CPU_COUNTER_OBJECT, COUNTER_INSTANCE_TOTAL, CPU_COUNTER_IDLE, &query, &idleTime) == ERROR_SUCCESS && addCounterToQuery(CPU_COUNTER_OBJECT, COUNTER_INSTANCE_TOTAL, CPU_COUNTER_INTR, &query, &intrTime) == ERROR_SUCCESS && addCounterToQuery(CPU_COUNTER_OBJECT, COUNTER_INSTANCE_TOTAL, CPU_COUNTER_INTERRUPTS, &query, &interrupts) == ERROR_SUCCESS && addCounterToQuery(SYS_COUNTER_OBJECT, NULL, SYS_COUNTER_CONTEXTS, &query, &contexts) == ERROR_SUCCESS && addCounterToQuery(SYS_COUNTER_OBJECT, NULL, SYS_COUNTER_UPTIME, &query, &uptime) == ERROR_SUCCESS && addCounterToQuery(SYS_COUNTER_OBJECT, NULL, SYS_COUNTER_PROCESSES, &query, &processes) == ERROR_SUCCESS && PdhCollectQueryData(query) == ERROR_SUCCESS) { //CPU time is in 100ns units, divide by 10000 for ms cpu->cpu_user = (uint32_t)(getRawCounterValue(&userTime)/tick_to_ms); cpu->cpu_system = (uint32_t)(getRawCounterValue(&systemTime)/tick_to_ms); cpu->cpu_idle = (uint32_t)(getRawCounterValue(&idleTime)/tick_to_ms); cpu->cpu_intr = (uint32_t)(getRawCounterValue(&intrTime)/tick_to_ms); cpu->interrupts = (uint32_t)getRawCounterValue(&interrupts); cpu->contexts = (uint32_t)getRawCounterValue(&contexts); cpu->uptime = (uint32_t)getCookedCounterValue(&uptime); cpu->proc_total = (uint32_t)getRawCounterValue(&processes); } PdhCloseQuery(query); } if (PdhOpenQuery(NULL, 0, &query) == ERROR_SUCCESS) { PDH_HCOUNTER threads; if (addCounterToQuery(THR_COUNTER_OBJECT, COUNTER_INSTANCE_ALL, THR_COUNTER_STATE, &query, &threads) == ERROR_SUCCESS && PdhCollectQueryData(query) == ERROR_SUCCESS) { PPDH_RAW_COUNTER_ITEM_W values = NULL; uint32_t threadCount = getRawCounterValues(&threads, &values); if (threadCount > 0) { for (uint32_t i = 0; i < threadCount; i++) { if (values[i].RawValue.FirstValue == 2 && wcsncmp(L"Idle", values[i].szName, 4) != 0) { //count the threads that are running (state==2) and are not owned by the idle process. //the name of each thread state counter starts with the process name. cpu->proc_run++; } } my_free(values); } } PdhCloseQuery(query); } cpu->cpu_num = getCpuNum(); DWORD dwRet,cbData = sizeof(DWORD); HKEY hkey; // see http://support.microsoft.com/kb/888282 for ways to determine CPU speed dwRet = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "hardware\\description\\system\\centralprocessor\\0", 0, KEY_QUERY_VALUE, &hkey); if(dwRet == ERROR_SUCCESS) { dwRet = RegQueryValueEx( hkey, "~MHz", NULL, NULL, (LPBYTE) &cpu->cpu_speed, &cbData ); if(dwRet != ERROR_SUCCESS) cpu->cpu_speed = UNKNOWN_GAUGE; RegCloseKey(hkey); } //These have no obvious Windows equivalent cpu->cpu_sintr = UNKNOWN_COUNTER; cpu->cpu_nice = UNKNOWN_COUNTER; cpu->cpu_wio = UNKNOWN_COUNTER; myLog(LOG_INFO, "readCpuCounters:\n\tload_one:\t%f\n\tload_five:\t%f\n\tload_fifteen:\t%f\n" "\tuptime:\t\t%lus\n\tcpu_num:\t%d\n" "\tcpu speed:\t%d MHz\n\tuser:\t\t%lu\n\tsystem:\t\t%lu\n\tidle:\t\t%lu\n\tirq:\t\t%lu\n" "\tcontexts:\t%lu\n\tinterrupts:\t%lu\n" "\tproc_total:\t%lu\n\tproc_run:\t%lu\n", cpu->load_one, cpu->load_five, cpu->load_fifteen, cpu->uptime, cpu->cpu_num, cpu->cpu_speed, cpu->cpu_user,cpu->cpu_system, cpu->cpu_idle, cpu->cpu_intr, cpu->contexts, cpu->interrupts, cpu->proc_total, cpu->proc_run); }