Esempio n. 1
0
/**
 * 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);
}