Ejemplo n.º 1
0
void
pgm_messages_init (void)
{
	char *log_mask, *min_log_level;
	size_t len;
	errno_t err;

	if (pgm_atomic_exchange_and_add32 (&messages_ref_count, 1) > 0)
		return;

	pgm_mutex_init (&messages_mutex);

	err = pgm_dupenv_s (&log_mask, &len, "PGM_LOG_MASK");
	if (!err && len > 0) {
		unsigned int value = 0;
		if (1 == pgm_sscanf_s (log_mask, "0x%4x", &value))
			pgm_log_mask = value;
		pgm_free (log_mask);
	}

	err = pgm_dupenv_s (&min_log_level, &len, "PGM_MIN_LOG_LEVEL");
	if (!err && len > 0) {
		switch (min_log_level[0]) {
		case 'D':	pgm_min_log_level = PGM_LOG_LEVEL_DEBUG; break;
		case 'T':	pgm_min_log_level = PGM_LOG_LEVEL_TRACE; break;
		case 'M':	pgm_min_log_level = PGM_LOG_LEVEL_MINOR; break;
		case 'N':	pgm_min_log_level = PGM_LOG_LEVEL_NORMAL; break;
		case 'W':	pgm_min_log_level = PGM_LOG_LEVEL_WARNING; break;
		case 'E':	pgm_min_log_level = PGM_LOG_LEVEL_ERROR; break;
		case 'F':	pgm_min_log_level = PGM_LOG_LEVEL_FATAL; break;
		default: break;
		}
		pgm_free (min_log_level);
	}
}
Ejemplo n.º 2
0
PGM_GNUC_INTERNAL
bool
pgm_time_init (
	pgm_error_t**	error
	)
{
	char	*pgm_timer;
	size_t	 envlen;
	errno_t	 err;

	if (pgm_atomic_exchange_and_add32 (&time_ref_count, 1) > 0)
		return TRUE;

/* user preferred time stamp function */
	err = pgm_dupenv_s (&pgm_timer, &envlen, "PGM_TIMER");
	if (0 != err || 0 == envlen) {
		pgm_timer = pgm_strdup (
/* default time stamp function */
#if defined(_WIN32)
			"MMTIME"
#else
			"GETTIMEOFDAY"
#endif
				);
	}

	pgm_time_since_epoch = pgm_time_conv;

	switch (pgm_timer[0]) {
#ifdef HAVE_FTIME
	case 'F':
		pgm_minor (_("Using ftime() timer."));
		pgm_time_update_now	= pgm_ftime_update;
		break;
#endif
#ifdef HAVE_CLOCK_GETTIME
	case 'C':
		pgm_minor (_("Using clock_gettime() timer."));
		pgm_time_update_now	= pgm_clock_update;
		break;
#endif
#ifdef HAVE_DEV_RTC
	case 'R':
		pgm_minor (_("Using /dev/rtc timer."));
		pgm_time_update_now	= pgm_rtc_update;
		pgm_time_since_epoch	= pgm_time_conv_from_reset;
		break;
#endif
#ifdef HAVE_RDTSC
	case 'T':
		pgm_minor (_("Using TSC timer."));
		pgm_time_update_now	= pgm_tsc_update;
		pgm_time_since_epoch	= pgm_time_conv_from_reset;
		break;
#endif
#ifdef HAVE_DEV_HPET
	case 'H':
		pgm_minor (_("Using HPET timer."));
		pgm_time_update_now	= pgm_hpet_update;
		pgm_time_since_epoch	= pgm_time_conv_from_reset;
		break;
#endif
#ifdef HAVE_GETTIMEOFDAY
	case 'G':
		pgm_minor (_("Using gettimeofday() timer."));
		pgm_time_update_now	= pgm_gettimeofday_update;
		break;
#endif
#ifdef _WIN32
	case 'M':
		pgm_minor (_("Using multi-media timer."));
		pgm_time_update_now	= pgm_mmtime_update;
		pgm_time_since_epoch	= pgm_time_conv_from_reset;
		break;

	case 'Q':
		pgm_minor (_("Using QueryPerformanceCounter() timer."));
		pgm_time_update_now	= pgm_queryperformancecounter_update;
		pgm_time_since_epoch	= pgm_time_conv_from_reset;
		break;
#endif

	default:
		pgm_set_error (error,
			       PGM_ERROR_DOMAIN_TIME,
			       PGM_ERROR_FAILED,
			       _("Unsupported time stamp function: PGM_TIMER=%s"),
			       pgm_timer);
		pgm_free (pgm_timer);
		goto err_cleanup;
	}

/* clean environment copy */
	pgm_free (pgm_timer);

#ifdef HAVE_DEV_RTC
	if (pgm_time_update_now == pgm_rtc_update)
	{
		pgm_error_t* sub_error = NULL;
		if (!pgm_rtc_init (&sub_error)) {
			pgm_propagate_error (error, sub_error);
			goto err_cleanup;
		}
	}
#endif
#ifdef _WIN32
	if (pgm_time_update_now == pgm_queryperformancecounter_update)
	{
/* MSDN statement: The frequency cannot change while the system is running.
 * http://msdn.microsoft.com/en-us/library/ms644905(v=vs.85).aspx
 */
		LARGE_INTEGER frequency;
		if (QueryPerformanceFrequency (&frequency))
		{
			tsc_khz = (uint_fast32_t)(frequency.QuadPart / 1000LL);
			pgm_minor (_("High-resolution performance counter frequency %lld Hz"),
				frequency.QuadPart);
		}
		else
		{
			const DWORD save_errno = GetLastError();
			char winstr[1024];
			pgm_set_error (error,
				       PGM_ERROR_DOMAIN_TIME,
				       PGM_ERROR_FAILED,
				       _("No supported high-resolution performance counter: %s"),
				       pgm_win_strerror (winstr, sizeof (winstr), save_errno));
			goto err_cleanup;
		}
		set_tsc_mul (tsc_khz);
	}
#endif /* _WIN32 */
#ifdef HAVE_RDTSC
	if (pgm_time_update_now == pgm_tsc_update)
	{
		char	*rdtsc_frequency;

#ifdef HAVE_PROC_CPUINFO
/* attempt to parse clock ticks from kernel
 */
		FILE	*fp = fopen ("/proc/cpuinfo", "r");
		if (fp)
		{
			char buffer[1024];
			while (!feof(fp) && fgets (buffer, sizeof(buffer), fp))
			{
				if (strstr (buffer, "cpu MHz")) {
					const char *p = strchr (buffer, ':');
					if (p) tsc_khz = atoi (p + 1) * 1000;
					break;
				}
			}
			fclose (fp);
		}
#elif defined(_WIN32)
/* core frequency HKLM/Hardware/Description/System/CentralProcessor/0/~Mhz
 */
		HKEY hKey;
		if (ERROR_SUCCESS == RegOpenKeyExA (HKEY_LOCAL_MACHINE,
					"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0",
					0,
					KEY_QUERY_VALUE,
					&hKey))
		{
			DWORD dwData = 0;
			DWORD dwDataSize = sizeof (dwData);
			if (ERROR_SUCCESS == RegQueryValueExA (hKey,
						"~MHz",
						NULL,
						NULL,
						(LPBYTE)&dwData,
						&dwDataSize))
			{
				tsc_khz = dwData * 1000;
				pgm_minor (_("Registry reports central processor frequency %u MHz"),
					(unsigned)dwData);
/* dump processor name for comparison aid of obtained frequency */
				char szProcessorBrandString[48];
				dwDataSize = sizeof (szProcessorBrandString);
				if (ERROR_SUCCESS == RegQueryValueExA (hKey,
							"ProcessorNameString",
							NULL,
							NULL,
							(LPBYTE)szProcessorBrandString,
							&dwDataSize))
				{
					pgm_minor (_("Processor Brand String \"%s\""), szProcessorBrandString);
				}
			}
			else
			{
				const DWORD save_errno = GetLastError();
				char winstr[1024];
				pgm_warn (_("Registry query on HKLM\\HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0\\~MHz failed: %s"),
					pgm_win_strerror (winstr, sizeof (winstr), save_errno));
			}
			RegCloseKey (hKey);
		}
#elif defined(__APPLE__)
/* nb: RDTSC is non-functional on Darwin */
		uint64_t cpufrequency;
		size_t len;
		len = sizeof (cpufrequency);
		if (0 == sysctlbyname ("hw.cpufrequency", &cpufrequency, &len, NULL, 0)) {
			tsc_khz = (uint_fast32_t)(cpufrequency / 1000);
		}
#elif defined(__FreeBSD__)
/* frequency in Mhz */
		unsigned long clockrate;
		size_t len;
		len = sizeof (clockrate);
		if (0 == sysctlbyname ("hw.clockrate", &clockrate, &len, NULL, 0)) {
			tsc_khz = (uint_fast32_t)(clockrate * 1000);
		}
#elif defined(KSTAT_DATA_INT32)
/* ref: http://developers.sun.com/solaris/articles/kstatc.html */
		kstat_ctl_t* kc;
		kstat_t* ksp;
		kstat_named_t* kdata;
		if (NULL != (kc = kstat_open()) &&
			NULL != (ksp = kstat_lookup (kc, "cpu_info", -1, NULL)) &&
			KSTAT_TYPE_NAMED == ksp->ks_type &&
			-1 != kstat_read (kc, ksp, NULL) &&
			NULL != (kdata = kstat_data_lookup (ksp, "clock_MHz")) &&
			KSTAT_DATA_INT32 == kdata->data_type)
		{
			tsc_khz = (uint_fast32_t)(kdata->value.i32 * 1000);
			kstat_close (kc);
		}
#endif /* !_WIN32 */

/* e.g. export RDTSC_FREQUENCY=3200.000000
 *
 * Value can be used to override kernel tick rate as well as internal calibration
 */
		err = pgm_dupenv_s (&rdtsc_frequency, &envlen, "RDTSC_FREQUENCY");
		if (0 == err && envlen > 0) {
			tsc_khz = atoi (rdtsc_frequency) * 1000;
			pgm_free (rdtsc_frequency);
		}

#ifndef _WIN32
/* calibrate */
		if (0 >= tsc_khz) {
			pgm_error_t* sub_error = NULL;
			if (!pgm_tsc_init (&sub_error)) {
				pgm_propagate_error (error, sub_error);
				goto err_cleanup;
			}
		}
#endif
		pgm_minor (_("TSC frequency set at %u KHz"), (unsigned)(tsc_khz));
		set_tsc_mul (tsc_khz);
	}
#endif /* HAVE_RDTSC */

#ifdef HAVE_DEV_HPET
	if (pgm_time_update_now == pgm_hpet_update)
	{
		pgm_error_t* sub_error = NULL;
		if (!pgm_hpet_init (&sub_error)) {
			pgm_propagate_error (error, sub_error);
			goto err_cleanup;
		}
	}
#endif

	pgm_time_update_now();

/* calculate relative time offset */
#if defined(HAVE_DEV_RTC) || defined(HAVE_RDTSC) || defined(HAVE_DEV_HPET) || defined(_WIN32)
	if (	0
#	ifdef HAVE_DEV_RTC
		|| pgm_time_update_now == pgm_rtc_update
#	endif
#	ifdef HAVE_RDTSC
		|| pgm_time_update_now == pgm_tsc_update
#	endif
#	ifdef HAVE_DEV_HPET
		|| pgm_time_update_now == pgm_hpet_update
#	endif
#	ifdef _WIN32
		|| pgm_time_update_now == pgm_mmtime_update
		|| pgm_time_update_now == pgm_queryperformancecounter_update
#	endif
	   )
	{
#	if defined( HAVE_GETTIMEOFDAY )
		rel_offset = pgm_gettimeofday_update() - pgm_time_update_now();
#	elif defined( HAVE_FTIME )
		rel_offset = pgm_ftime_update() - pgm_time_update_now();
#	else
#		error "gettimeofday() or ftime() required to calculate counter offset"
#	endif
	}
#else
	rel_offset = 0;
#endif

/* update Windows timer resolution to 1ms */
#ifdef _WIN32
	TIMECAPS tc;
	if (TIMERR_NOERROR == timeGetDevCaps (&tc, sizeof (TIMECAPS)))
	{
		wTimerRes = min (max (tc.wPeriodMin, 1 /* ms */), tc.wPeriodMax);
		timeBeginPeriod (wTimerRes);
		pgm_debug ("Set timer resolution to %ums.", wTimerRes);
	}
	else
	{
		pgm_warn (_("Unable to determine timer device resolution."));
	}
#endif

	return TRUE;
err_cleanup:
	pgm_atomic_dec32 (&time_ref_count);
	return FALSE;
}