Blame src/vma/dev/ring_allocation_logic.cpp

Packit Service aa3af4
/*
Packit Service aa3af4
 * Copyright (c) 2001-2020 Mellanox Technologies, Ltd. All rights reserved.
Packit Service aa3af4
 *
Packit Service aa3af4
 * This software is available to you under a choice of one of two
Packit Service aa3af4
 * licenses.  You may choose to be licensed under the terms of the GNU
Packit Service aa3af4
 * General Public License (GPL) Version 2, available from the file
Packit Service aa3af4
 * COPYING in the main directory of this source tree, or the
Packit Service aa3af4
 * BSD license below:
Packit Service aa3af4
 *
Packit Service aa3af4
 *     Redistribution and use in source and binary forms, with or
Packit Service aa3af4
 *     without modification, are permitted provided that the following
Packit Service aa3af4
 *     conditions are met:
Packit Service aa3af4
 *
Packit Service aa3af4
 *      - Redistributions of source code must retain the above
Packit Service aa3af4
 *        copyright notice, this list of conditions and the following
Packit Service aa3af4
 *        disclaimer.
Packit Service aa3af4
 *
Packit Service aa3af4
 *      - Redistributions in binary form must reproduce the above
Packit Service aa3af4
 *        copyright notice, this list of conditions and the following
Packit Service aa3af4
 *        disclaimer in the documentation and/or other materials
Packit Service aa3af4
 *        provided with the distribution.
Packit Service aa3af4
 *
Packit Service aa3af4
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
Packit Service aa3af4
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
Packit Service aa3af4
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
Packit Service aa3af4
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
Packit Service aa3af4
 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
Packit Service aa3af4
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
Packit Service aa3af4
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
Packit Service aa3af4
 * SOFTWARE.
Packit Service aa3af4
 */
Packit Service aa3af4
Packit Service aa3af4
Packit Service aa3af4
#include <dev/ring_profile.h>
Packit Service aa3af4
#include "vma/dev/ring_allocation_logic.h"
Packit Service aa3af4
Packit Service aa3af4
Packit Service aa3af4
#define MODULE_NAME 		"ral"
Packit Service aa3af4
Packit Service aa3af4
#undef  MODULE_HDR_INFO
Packit Service aa3af4
#define MODULE_HDR_INFO 	MODULE_NAME "%s:%d:%s() "
Packit Service aa3af4
#undef	__INFO__
Packit Service aa3af4
#define __INFO__		m_tostr.c_str()
Packit Service aa3af4
Packit Service aa3af4
#define ral_logpanic		__log_info_panic
Packit Service aa3af4
#define ral_logerr		__log_info_err
Packit Service aa3af4
#define ral_logwarn		__log_info_warn
Packit Service aa3af4
#define ral_loginfo		__log_info_info
Packit Service aa3af4
#define ral_logdbg		__log_info_dbg
Packit Service aa3af4
#define ral_logfunc		__log_info_func
Packit Service aa3af4
#define ral_logfuncall		__log_info_funcall
Packit Service aa3af4
Packit Service aa3af4
ring_allocation_logic::ring_allocation_logic():m_ring_migration_ratio(0),
Packit Service aa3af4
						m_source(-1),
Packit Service aa3af4
						m_migration_try_count(0),
Packit Service aa3af4
						m_migration_candidate(0),
Packit Service aa3af4
						m_active(true),
Packit Service aa3af4
						m_res_key() {}
Packit Service aa3af4
Packit Service aa3af4
ring_allocation_logic::ring_allocation_logic(ring_logic_t allocation_logic,
Packit Service aa3af4
					     int ring_migration_ratio, source_t source,
Packit Service aa3af4
					     resource_allocation_key &ring_profile):
Packit Service aa3af4
	m_tostr("base"), m_ring_migration_ratio(ring_migration_ratio),
Packit Service aa3af4
	m_source(source), m_migration_try_count(ring_migration_ratio)
Packit Service aa3af4
{
Packit Service aa3af4
	if (ring_profile.get_ring_alloc_logic() == RING_LOGIC_PER_INTERFACE &&
Packit Service aa3af4
	    ring_profile.get_ring_profile_key() < START_RING_INDEX) {
Packit Service aa3af4
		ring_profile.set_ring_alloc_logic(allocation_logic);
Packit Service aa3af4
	}
Packit Service aa3af4
	m_res_key = resource_allocation_key(ring_profile);
Packit Service aa3af4
	m_migration_candidate = 0;
Packit Service aa3af4
	m_res_key.set_user_id_key(calc_res_key_by_logic());
Packit Service aa3af4
Packit Service aa3af4
	m_active = true;
Packit Service aa3af4
}
Packit Service aa3af4
Packit Service aa3af4
/**
Packit Service aa3af4
 *
Packit Service aa3af4
 * @return the key that is part of a unique id in rings map
Packit Service aa3af4
 */
Packit Service aa3af4
uint64_t ring_allocation_logic::calc_res_key_by_logic()
Packit Service aa3af4
{
Packit Service aa3af4
	uint64_t res_key = 0;
Packit Service aa3af4
	switch (m_res_key.get_ring_alloc_logic()) {
Packit Service aa3af4
	case RING_LOGIC_PER_INTERFACE:
Packit Service aa3af4
		res_key = 0;
Packit Service aa3af4
		if (safe_mce_sys().tcp_ctl_thread > CTL_THREAD_DISABLE)
Packit Service aa3af4
			res_key = 1;
Packit Service aa3af4
		break;
Packit Service aa3af4
	case RING_LOGIC_PER_IP:
Packit Service aa3af4
		res_key = m_source.m_ip;
Packit Service aa3af4
		break;
Packit Service aa3af4
	case RING_LOGIC_PER_SOCKET:
Packit Service aa3af4
		res_key = m_source.m_fd;
Packit Service aa3af4
		break;
Packit Service aa3af4
	case RING_LOGIC_PER_USER_ID:
Packit Service aa3af4
		res_key = m_res_key.get_user_id_key();
Packit Service aa3af4
		break;
Packit Service aa3af4
	case RING_LOGIC_PER_THREAD:
Packit Service aa3af4
		res_key = pthread_self();
Packit Service aa3af4
		break;
Packit Service aa3af4
	case RING_LOGIC_PER_CORE:
Packit Service aa3af4
	case RING_LOGIC_PER_CORE_ATTACH_THREADS:
Packit Service aa3af4
		res_key = sched_getcpu();
Packit Service aa3af4
		break;
Packit Service aa3af4
	BULLSEYE_EXCLUDE_BLOCK_START
Packit Service aa3af4
	default:
Packit Service aa3af4
		//not suppose to get here
Packit Service aa3af4
		ral_logdbg("non-valid ring logic = %d", m_res_key.get_ring_alloc_logic());
Packit Service aa3af4
		break;
Packit Service aa3af4
	BULLSEYE_EXCLUDE_BLOCK_END
Packit Service aa3af4
	}
Packit Service aa3af4
	return res_key;
Packit Service aa3af4
}
Packit Service aa3af4
Packit Service aa3af4
resource_allocation_key* ring_allocation_logic::create_new_key(in_addr_t addr, int suggested_cpu /* = NO_CPU */)
Packit Service aa3af4
{
Packit Service aa3af4
	if (m_res_key.get_ring_alloc_logic() == RING_LOGIC_PER_CORE_ATTACH_THREADS) {
Packit Service aa3af4
		pthread_t tid = pthread_self();
Packit Service aa3af4
		int cpu = g_cpu_manager.reserve_cpu_for_thread(tid, suggested_cpu);
Packit Service aa3af4
		if (cpu >= 0) {
Packit Service aa3af4
			m_res_key.set_user_id_key(cpu);
Packit Service aa3af4
			return &m_res_key;
Packit Service aa3af4
		}
Packit Service aa3af4
	}
Packit Service aa3af4
Packit Service aa3af4
	if (m_res_key.get_ring_alloc_logic() == RING_LOGIC_PER_IP) {
Packit Service aa3af4
		m_source.m_ip = addr;
Packit Service aa3af4
	}
Packit Service aa3af4
Packit Service aa3af4
	m_res_key.set_user_id_key(calc_res_key_by_logic());
Packit Service aa3af4
	return &m_res_key;
Packit Service aa3af4
}
Packit Service aa3af4
Packit Service aa3af4
/*
Packit Service aa3af4
 * return true if ring migration is recommended.
Packit Service aa3af4
 */
Packit Service aa3af4
bool ring_allocation_logic::should_migrate_ring()
Packit Service aa3af4
{
Packit Service aa3af4
	ral_logfuncall("currently accessed from thread=%lu, cpu=%d", pthread_self(), sched_getcpu());
Packit Service aa3af4
Packit Service aa3af4
	if (false == m_active) {
Packit Service aa3af4
		return false;
Packit Service aa3af4
	}
Packit Service aa3af4
Packit Service aa3af4
	int count_max = m_ring_migration_ratio;
Packit Service aa3af4
	if (m_migration_candidate) {
Packit Service aa3af4
		count_max = CANDIDATE_STABILITY_ROUNDS;
Packit Service aa3af4
		uint64_t new_id = calc_res_key_by_logic();
Packit Service aa3af4
		if (m_migration_candidate != new_id) {
Packit Service aa3af4
			m_migration_candidate = 0;
Packit Service aa3af4
			m_migration_try_count = 0;
Packit Service aa3af4
			return false;
Packit Service aa3af4
		}
Packit Service aa3af4
	}
Packit Service aa3af4
Packit Service aa3af4
Packit Service aa3af4
	if (m_migration_try_count < count_max) {
Packit Service aa3af4
		m_migration_try_count++;
Packit Service aa3af4
		return false;
Packit Service aa3af4
	} else {
Packit Service aa3af4
		m_migration_try_count = 0;
Packit Service aa3af4
	}
Packit Service aa3af4
Packit Service aa3af4
	if (!m_migration_candidate) {
Packit Service aa3af4
		// save current used allocation key
Packit Service aa3af4
		// no need to save profile, and allocation logic
Packit Service aa3af4
		uint64_t curr_id = m_res_key.get_user_id_key();
Packit Service aa3af4
		// calc new key
Packit Service aa3af4
		uint64_t new_id = calc_res_key_by_logic();
Packit Service aa3af4
		if (new_id == curr_id || g_n_internal_thread_id == curr_id) {
Packit Service aa3af4
			return false;
Packit Service aa3af4
		}
Packit Service aa3af4
		m_migration_candidate = new_id;
Packit Service aa3af4
		return false;
Packit Service aa3af4
	}
Packit Service aa3af4
Packit Service aa3af4
	ral_logdbg("migrating from ring of id=%s to ring of id=%lu",
Packit Service aa3af4
		   m_res_key.to_str(), m_migration_candidate);
Packit Service aa3af4
	m_migration_candidate = 0;
Packit Service aa3af4
Packit Service aa3af4
	return true;
Packit Service aa3af4
}
Packit Service aa3af4
Packit Service aa3af4
cpu_manager g_cpu_manager;
Packit Service aa3af4
__thread int g_n_thread_cpu_core = NO_CPU;
Packit Service aa3af4
Packit Service aa3af4
cpu_manager::cpu_manager()
Packit Service aa3af4
{
Packit Service aa3af4
	reset();
Packit Service aa3af4
}
Packit Service aa3af4
Packit Service aa3af4
void cpu_manager::reset()
Packit Service aa3af4
{
Packit Service aa3af4
	memset(m_cpu_thread_count, 0, sizeof(m_cpu_thread_count));
Packit Service aa3af4
}
Packit Service aa3af4
Packit Service aa3af4
int cpu_manager::reserve_cpu_for_thread(pthread_t tid, int suggested_cpu /* = NO_CPU */)
Packit Service aa3af4
{
Packit Service aa3af4
	lock();
Packit Service aa3af4
	int cpu = g_n_thread_cpu_core;
Packit Service aa3af4
	if (cpu != NO_CPU) { //already reserved
Packit Service aa3af4
		unlock();
Packit Service aa3af4
		return cpu;
Packit Service aa3af4
	}
Packit Service aa3af4
Packit Service aa3af4
	cpu_set_t cpu_set;
Packit Service aa3af4
	CPU_ZERO(&cpu_set);
Packit Service aa3af4
Packit Service aa3af4
	int ret = pthread_getaffinity_np(tid, sizeof(cpu_set_t), &cpu_set);
Packit Service aa3af4
	if (ret) {
Packit Service aa3af4
		unlock();
Packit Service aa3af4
		__log_err("pthread_getaffinity_np failed for tid=%lu, ret=%d (errno=%d %m)", tid, ret, errno);
Packit Service aa3af4
		return -1;
Packit Service aa3af4
	}
Packit Service aa3af4
Packit Service aa3af4
	int avail_cpus = CPU_COUNT(&cpu_set);
Packit Service aa3af4
	if (avail_cpus == 0) {
Packit Service aa3af4
		unlock();
Packit Service aa3af4
		__log_err("no cpu available for tid=%lu", tid);
Packit Service aa3af4
		return -1;
Packit Service aa3af4
	}
Packit Service aa3af4
Packit Service aa3af4
	if (avail_cpus == 1) { //already attached
Packit Service aa3af4
		for (cpu = 0; cpu < MAX_CPU && !CPU_ISSET(cpu, &cpu_set); cpu++) {}
Packit Service aa3af4
	} else { //need to choose one cpu to attach to
Packit Service aa3af4
		int min_cpu_count = -1;
Packit Service aa3af4
		for (int i = 0, j = 0; i < MAX_CPU && j < avail_cpus; i++) {
Packit Service aa3af4
			if (!CPU_ISSET(i, &cpu_set)) continue;
Packit Service aa3af4
			j++;
Packit Service aa3af4
			if (min_cpu_count < 0 || m_cpu_thread_count[i] < min_cpu_count) {
Packit Service aa3af4
				min_cpu_count = m_cpu_thread_count[i];
Packit Service aa3af4
				cpu = i;
Packit Service aa3af4
			}
Packit Service aa3af4
		}
Packit Service aa3af4
		if (suggested_cpu >= 0
Packit Service aa3af4
			&& CPU_ISSET(suggested_cpu, &cpu_set)
Packit Service aa3af4
			&& m_cpu_thread_count[suggested_cpu] <= min_cpu_count + 1 ) {
Packit Service aa3af4
			cpu = suggested_cpu;
Packit Service aa3af4
		}
Packit Service aa3af4
		CPU_ZERO(&cpu_set);
Packit Service aa3af4
		CPU_SET(cpu, &cpu_set);
Packit Service aa3af4
		__log_dbg("attach tid=%lu running on cpu=%d to cpu=%d", tid, sched_getcpu(), cpu);
Packit Service aa3af4
		ret = pthread_setaffinity_np(tid, sizeof(cpu_set_t), &cpu_set);
Packit Service aa3af4
		if (ret) {
Packit Service aa3af4
			unlock();
Packit Service aa3af4
			__log_err("pthread_setaffinity_np failed for tid=%lu to cpu=%d, ret=%d (errno=%d %m)", tid, cpu, ret, errno);
Packit Service aa3af4
			return -1;
Packit Service aa3af4
		}
Packit Service aa3af4
	}
Packit Service aa3af4
Packit Service aa3af4
	g_n_thread_cpu_core = cpu;
Packit Service aa3af4
	if (cpu > NO_CPU && cpu < MAX_CPU)
Packit Service aa3af4
		m_cpu_thread_count[cpu]++;
Packit Service aa3af4
	unlock();
Packit Service aa3af4
	return cpu;
Packit Service aa3af4
}