Пример #1
0
void
mono_thread_pool_init ()
{
	gint threads_per_cpu = 1;
	gint thread_count;
	gint cpu_count = mono_cpu_count ();
	int result;

	if (tp_inited == 2)
		return;

	result = InterlockedCompareExchange (&tp_inited, 1, 0);
	if (result == 1) {
		while (1) {
			SleepEx (1, FALSE);
			if (tp_inited == 2)
				return;
		}
	}

	MONO_GC_REGISTER_ROOT_FIXED (socket_io_data.sock_to_state);
	InitializeCriticalSection (&socket_io_data.io_lock);
	if (g_getenv ("MONO_THREADS_PER_CPU") != NULL) {
		threads_per_cpu = atoi (g_getenv ("MONO_THREADS_PER_CPU"));
		if (threads_per_cpu < 1)
			threads_per_cpu = 1;
	}

	thread_count = MIN (cpu_count * threads_per_cpu, 100 * cpu_count);
	threadpool_init (&async_tp, thread_count, MAX (100 * cpu_count, thread_count), async_invoke_thread);
	threadpool_init (&async_io_tp, cpu_count * 2, cpu_count * 4, async_invoke_thread);
	async_io_tp.is_io = TRUE;

	async_call_klass = mono_class_from_name (mono_defaults.corlib, "System", "MonoAsyncCall");
	g_assert (async_call_klass);

	InitializeCriticalSection (&wsqs_lock);
	wsqs = g_ptr_array_sized_new (MAX (100 * cpu_count, thread_count));
	mono_wsq_init ();

#ifndef DISABLE_PERFCOUNTERS
	async_tp.pc_nitems = init_perf_counter ("Mono Threadpool", "Work Items Added");
	g_assert (async_tp.pc_nitems);

	async_io_tp.pc_nitems = init_perf_counter ("Mono Threadpool", "IO Work Items Added");
	g_assert (async_io_tp.pc_nitems);

	async_tp.pc_nthreads = init_perf_counter ("Mono Threadpool", "# of Threads");
	g_assert (async_tp.pc_nthreads);

	async_io_tp.pc_nthreads = init_perf_counter ("Mono Threadpool", "# of IO Threads");
	g_assert (async_io_tp.pc_nthreads);
#endif
	tp_inited = 2;
#ifdef DEBUG
	signal (SIGALRM, signal_handler);
	alarm (2);
#endif
}
Пример #2
0
gint32
mono_cpu_usage (MonoCpuUsageState *prev)
{
	gint32 cpu_usage = 0;
	gint64 cpu_total_time;
	gint64 cpu_busy_time;

#ifndef HOST_WIN32
	struct rusage resource_usage;
	gint64 current_time;
	gint64 kernel_time;
	gint64 user_time;

	if (getrusage (RUSAGE_SELF, &resource_usage) == -1) {
		g_error ("getrusage() failed, errno is %d (%s)\n", errno, strerror (errno));
		return -1;
	}

	current_time = mono_100ns_ticks ();
	kernel_time = resource_usage.ru_stime.tv_sec * 1000 * 1000 * 10 + resource_usage.ru_stime.tv_usec * 10;
	user_time = resource_usage.ru_utime.tv_sec * 1000 * 1000 * 10 + resource_usage.ru_utime.tv_usec * 10;

	cpu_busy_time = (user_time - (prev ? prev->user_time : 0)) + (kernel_time - (prev ? prev->kernel_time : 0));
	cpu_total_time = (current_time - (prev ? prev->current_time : 0)) * mono_cpu_count ();

	if (prev) {
		prev->kernel_time = kernel_time;
		prev->user_time = user_time;
		prev->current_time = current_time;
	}
#else
	guint64 idle_time;
	guint64 kernel_time;
	guint64 user_time;

	if (!GetSystemTimes ((FILETIME*) &idle_time, (FILETIME*) &kernel_time, (FILETIME*) &user_time)) {
		g_error ("GetSystemTimes() failed, error code is %d\n", GetLastError ());
		return -1;
	}

	cpu_total_time = (gint64)((user_time - (prev ? prev->user_time : 0)) + (kernel_time - (prev ? prev->kernel_time : 0)));
	cpu_busy_time = (gint64)(cpu_total_time - (idle_time - (prev ? prev->idle_time : 0)));

	if (prev) {
		prev->idle_time = idle_time;
		prev->kernel_time = kernel_time;
		prev->user_time = user_time;
	}
#endif

	if (cpu_total_time > 0 && cpu_busy_time > 0)
		cpu_usage = (gint32)(cpu_busy_time * 100 / cpu_total_time);

	g_assert (cpu_usage >= 0);
	g_assert (cpu_usage <= 100);

	return cpu_usage;
}
Пример #3
0
static void
get_cpu_times (int cpu_id, gint64 *user, gint64 *systemt, gint64 *irq, gint64 *sirq, gint64 *idle)
{
	char buf [256];
	char *s;
	int hz = get_user_hz ();
	guint64	user_ticks = 0, nice_ticks = 0, system_ticks = 0, idle_ticks = 0, irq_ticks = 0, sirq_ticks = 0;
	FILE *f = fopen ("/proc/stat", "r");
	if (!f)
		return;
	if (cpu_id < 0)
		hz *= mono_cpu_count ();
	while ((s = fgets (buf, sizeof (buf), f))) {
		char *data = NULL;
		if (cpu_id < 0 && strncmp (s, "cpu", 3) == 0 && g_ascii_isspace (s [3])) {
			data = s + 4;
		} else if (cpu_id >= 0 && strncmp (s, "cpu", 3) == 0 && strtol (s + 3, &data, 10) == cpu_id) {
			if (data == s + 3)
				continue;
			data++;
		} else {
			continue;
		}
		
		user_ticks = strtoull (data, &data, 10);
		nice_ticks = strtoull (data, &data, 10);
		system_ticks = strtoull (data, &data, 10);
		idle_ticks = strtoull (data, &data, 10);
		/* iowait_ticks = strtoull (data, &data, 10); */
		irq_ticks = strtoull (data, &data, 10);
		sirq_ticks = strtoull (data, &data, 10);
		break;
	}
	fclose (f);

	if (user)
		*user = (user_ticks + nice_ticks) * 10000000 / hz;
	if (systemt)
		*systemt = (system_ticks) * 10000000 / hz;
	if (irq)
		*irq = (irq_ticks) * 10000000 / hz;
	if (sirq)
		*sirq = (sirq_ticks) * 10000000 / hz;
	if (idle)
		*idle = (idle_ticks) * 10000000 / hz;
}
gint32
mono_cpu_usage (MonoCpuUsageState *prev)
{
	gint32 cpu_usage = 0;
	gint64 cpu_total_time;
	gint64 cpu_busy_time;
	guint64 idle_time;
	guint64 kernel_time;
	guint64 user_time;
	guint64 current_time;
	guint64 creation_time;
	guint64 exit_time;

	GetSystemTimeAsFileTime ((FILETIME*)&current_time);
	if (!GetProcessTimes (GetCurrentProcess (), (FILETIME*)&creation_time, (FILETIME*)&exit_time, (FILETIME*)&kernel_time, (FILETIME*)&user_time)) {
		g_error ("GetProcessTimes() failed, error code is %d\n", GetLastError ());
		return -1;
	}

	// GetProcessTimes user_time is a sum of user time spend by all threads in the process.
	// This means that the total user time can be more than real time. In order to adjust for this
	// the total available time that we can be scheduled depends on the number of available cores.
	// For example, having 2 threads running 100% on a 2 core system for 100 ms will return a user_time of 200ms
	// but the current_time - creation_time will only be 100ms but by adjusting the available time based on number of
	// of availalbe cores will gives use the total load of the process.
	guint64 total_available_time = (current_time - creation_time) * mono_cpu_count ();

	idle_time = total_available_time - (kernel_time + user_time);

	cpu_total_time = (gint64)((idle_time - (prev ? prev->idle_time : 0)) + (user_time - (prev ? prev->user_time : 0)) + (kernel_time - (prev ? prev->kernel_time : 0)));
	cpu_busy_time = (gint64)(cpu_total_time - (idle_time - (prev ? prev->idle_time : 0)));

	if (prev) {
		prev->idle_time = idle_time;
		prev->kernel_time = kernel_time;
		prev->user_time = user_time;
	}

	if (cpu_total_time > 0 && cpu_busy_time > 0)
		cpu_usage = (gint32)(cpu_busy_time * 100 / cpu_total_time);

	return cpu_usage;
}
Пример #5
0
MonoBoolean
ves_icall_System_Threading_ThreadPool_SetMaxThreads (gint workerThreads, gint completionPortThreads)
{
	gint min_threads;
	gint min_io_threads;
	gint cpu_count;

	cpu_count = mono_cpu_count ();
	min_threads = async_tp.min_threads;
	if (workerThreads < min_threads || workerThreads < cpu_count)
		return FALSE;

	/* We don't really have the concept of completion ports. Do we care here? */
	min_io_threads = async_io_tp.min_threads;
	if (completionPortThreads < min_io_threads || completionPortThreads < cpu_count)
		return FALSE;

	InterlockedExchange (&async_tp.max_threads, workerThreads);
	InterlockedExchange (&async_io_tp.max_threads, completionPortThreads);
	return TRUE;
}
Пример #6
0
static void
ensure_initialized (gboolean *enable_worker_tracking)
{
	ThreadPoolHillClimbing *hc;
	const char *threads_per_cpu_env;
	gint threads_per_cpu;
	gint threads_count;

	if (enable_worker_tracking) {
		// TODO implement some kind of switch to have the possibily to use it
		*enable_worker_tracking = FALSE;
	}

	if (status >= STATUS_INITIALIZED)
		return;
	if (status == STATUS_INITIALIZING || InterlockedCompareExchange (&status, STATUS_INITIALIZING, STATUS_NOT_INITIALIZED) != STATUS_NOT_INITIALIZED) {
		while (status == STATUS_INITIALIZING)
			mono_thread_info_yield ();
		g_assert (status >= STATUS_INITIALIZED);
		return;
	}

	g_assert (!threadpool);
	threadpool = g_new0 (ThreadPool, 1);
	g_assert (threadpool);

	threadpool->domains = g_ptr_array_new ();
	mono_mutex_init_recursive (&threadpool->domains_lock);

	threadpool->parked_threads = g_ptr_array_new ();
	mono_mutex_init (&threadpool->parked_threads_lock);

	threadpool->working_threads = g_ptr_array_new ();
	mono_mutex_init (&threadpool->working_threads_lock);

	threadpool->heuristic_adjustment_interval = 10;
	mono_mutex_init (&threadpool->heuristic_lock);

	mono_rand_open ();

	hc = &threadpool->heuristic_hill_climbing;

	hc->wave_period = HILL_CLIMBING_WAVE_PERIOD;
	hc->max_thread_wave_magnitude = HILL_CLIMBING_MAX_WAVE_MAGNITUDE;
	hc->thread_magnitude_multiplier = (gdouble) HILL_CLIMBING_WAVE_MAGNITUDE_MULTIPLIER;
	hc->samples_to_measure = hc->wave_period * HILL_CLIMBING_WAVE_HISTORY_SIZE;
	hc->target_throughput_ratio = (gdouble) HILL_CLIMBING_BIAS;
	hc->target_signal_to_noise_ratio = (gdouble) HILL_CLIMBING_TARGET_SIGNAL_TO_NOISE_RATIO;
	hc->max_change_per_second = (gdouble) HILL_CLIMBING_MAX_CHANGE_PER_SECOND;
	hc->max_change_per_sample = (gdouble) HILL_CLIMBING_MAX_CHANGE_PER_SAMPLE;
	hc->sample_interval_low = HILL_CLIMBING_SAMPLE_INTERVAL_LOW;
	hc->sample_interval_high = HILL_CLIMBING_SAMPLE_INTERVAL_HIGH;
	hc->throughput_error_smoothing_factor = (gdouble) HILL_CLIMBING_ERROR_SMOOTHING_FACTOR;
	hc->gain_exponent = (gdouble) HILL_CLIMBING_GAIN_EXPONENT;
	hc->max_sample_error = (gdouble) HILL_CLIMBING_MAX_SAMPLE_ERROR_PERCENT;
	hc->current_control_setting = 0;
	hc->total_samples = 0;
	hc->last_thread_count = 0;
	hc->average_throughput_noise = 0;
	hc->elapsed_since_last_change = 0;
	hc->accumulated_completion_count = 0;
	hc->accumulated_sample_duration = 0;
	hc->samples = g_new0 (gdouble, hc->samples_to_measure);
	hc->thread_counts = g_new0 (gdouble, hc->samples_to_measure);
	hc->random_interval_generator = rand_create ();
	hc->current_sample_interval = rand_next (&hc->random_interval_generator, hc->sample_interval_low, hc->sample_interval_high);

	if (!(threads_per_cpu_env = g_getenv ("MONO_THREADS_PER_CPU")))
		threads_per_cpu = 1;
	else
		threads_per_cpu = CLAMP (atoi (threads_per_cpu_env), 1, 50);

	threads_count = mono_cpu_count () * threads_per_cpu;

	threadpool->limit_worker_min = threadpool->limit_io_min = threads_count;
	threadpool->limit_worker_max = threadpool->limit_io_max = threads_count * 100;

	threadpool->counters._.max_working = threadpool->limit_worker_min;

	threadpool->cpu_usage_state = g_new0 (MonoCpuUsageState, 1);

	threadpool->suspended = FALSE;

	status = STATUS_INITIALIZED;
}
Пример #7
0
void
mono_threadpool_worker_init (MonoThreadPoolWorkerCallback callback)
{
	ThreadPoolHillClimbing *hc;
	const char *threads_per_cpu_env;
	gint threads_per_cpu;
	gint threads_count;

	mono_refcount_init (&worker, destroy);

	worker.callback = callback;

	mono_coop_mutex_init (&worker.parked_threads_lock);
	worker.parked_threads_count = 0;
	mono_coop_cond_init (&worker.parked_threads_cond);

	worker.worker_creation_current_second = -1;
	mono_coop_mutex_init (&worker.worker_creation_lock);

	worker.heuristic_adjustment_interval = 10;
	mono_coop_mutex_init (&worker.heuristic_lock);

	mono_rand_open ();

	hc = &worker.heuristic_hill_climbing;

	hc->wave_period = HILL_CLIMBING_WAVE_PERIOD;
	hc->max_thread_wave_magnitude = HILL_CLIMBING_MAX_WAVE_MAGNITUDE;
	hc->thread_magnitude_multiplier = (gdouble) HILL_CLIMBING_WAVE_MAGNITUDE_MULTIPLIER;
	hc->samples_to_measure = hc->wave_period * HILL_CLIMBING_WAVE_HISTORY_SIZE;
	hc->target_throughput_ratio = (gdouble) HILL_CLIMBING_BIAS;
	hc->target_signal_to_noise_ratio = (gdouble) HILL_CLIMBING_TARGET_SIGNAL_TO_NOISE_RATIO;
	hc->max_change_per_second = (gdouble) HILL_CLIMBING_MAX_CHANGE_PER_SECOND;
	hc->max_change_per_sample = (gdouble) HILL_CLIMBING_MAX_CHANGE_PER_SAMPLE;
	hc->sample_interval_low = HILL_CLIMBING_SAMPLE_INTERVAL_LOW;
	hc->sample_interval_high = HILL_CLIMBING_SAMPLE_INTERVAL_HIGH;
	hc->throughput_error_smoothing_factor = (gdouble) HILL_CLIMBING_ERROR_SMOOTHING_FACTOR;
	hc->gain_exponent = (gdouble) HILL_CLIMBING_GAIN_EXPONENT;
	hc->max_sample_error = (gdouble) HILL_CLIMBING_MAX_SAMPLE_ERROR_PERCENT;
	hc->current_control_setting = 0;
	hc->total_samples = 0;
	hc->last_thread_count = 0;
	hc->average_throughput_noise = 0;
	hc->elapsed_since_last_change = 0;
	hc->accumulated_completion_count = 0;
	hc->accumulated_sample_duration = 0;
	hc->samples = g_new0 (gdouble, hc->samples_to_measure);
	hc->thread_counts = g_new0 (gdouble, hc->samples_to_measure);
	hc->random_interval_generator = rand_create ();
	hc->current_sample_interval = rand_next (&hc->random_interval_generator, hc->sample_interval_low, hc->sample_interval_high);

	if (!(threads_per_cpu_env = g_getenv ("MONO_THREADS_PER_CPU")))
		threads_per_cpu = 1;
	else
		threads_per_cpu = CLAMP (atoi (threads_per_cpu_env), 1, 50);

	threads_count = mono_cpu_count () * threads_per_cpu;

	worker.limit_worker_min = threads_count;

#if defined (PLATFORM_ANDROID) || defined (HOST_IOS)
	worker.limit_worker_max = CLAMP (threads_count * 100, MIN (threads_count, 200), MAX (threads_count, 200));
#else
	worker.limit_worker_max = threads_count * 100;
#endif

	worker.counters._.max_working = worker.limit_worker_min;

	worker.cpu_usage_state = g_new0 (MonoCpuUsageState, 1);

	worker.suspended = FALSE;

	worker.monitor_status = MONITOR_STATUS_NOT_RUNNING;
}