【Nova】nova-scheduler过滤称重

2023-05-16

在上一篇“ nova-scheduler调度过程分析”中,对过滤称重的过程一笔带过了,这篇着重介绍一下。

首先,我们声明一下host为主机,node为节点,在OpenStack中一个host可以运行多个node或者nova-compute服务。

第一步,过滤filter,通过HostManager的get_filtered_hosts实现:

选取Icehouse版本支持的部分主机过滤器进行简要说明:

RetryFilter -> 如果主机已经尝试被调度了,那么过滤不通过

AvailabilityZoneFilter -> 我们可以根据物理位置对主机划分“可用域”, 如果创建虚拟机实例时指定了availability_zone,而主机又不在

        该availability_zone中,那么过滤不通过

RamFilter -> 如果主机的可用内存不足以提供虚拟机实例需要的内存,那么过滤不通过

ComputeFilter -> 如果主机的计算服务被禁用掉或者down掉(一定时间内没有收到心跳包), 那么过滤不通过

ComputeCapabilitiesFilter -> 创建虚拟机实例时可以指定一些额外的要求,如果主机的能力不满足这些要求,那么过滤不通过

ImagePropertiesFilter -> 我们可以给镜像创建属性,譬如在镜像属性指定架构、hypervisor和虚拟机模式,如果主机不支持这些属性的虚拟机,那么过滤不通过

ServerGroupAntiAffinityFilter、ServerGroupAffinityFilter ->给定一个实例组,那么可以获取运行实例成员的主机集合,如果主机

       在/不在这个主机集合里,那么过滤不通过


# nova-scheduler默认的过滤器列表
cfg.ListOpt('scheduler_default_filters',
            default=[
              'RetryFilter',
              'AvailabilityZoneFilter',
              'RamFilter',
              'ComputeFilter',
              'ComputeCapabilitiesFilter',
              'ImagePropertiesFilter',
              'ServerGroupAntiAffinityFilter',
              'ServerGroupAffinityFilter',
              ],
            help='Which filter class names to use for filtering hosts '
                  'when not specified in the request.'),


# 过滤器基类
class BaseFilter(object):

    def _filter_one(self, obj, filter_properties):
        return True

    def filter_all(self, filter_obj_list, filter_properties):
        for obj in filter_obj_list:
            if self._filter_one(obj, filter_properties):
                yield obj

    run_filter_once_per_request = False
    # 我们可以一次创建多个同类型的实例, 每个实例我们都需要对主机进行一次过滤称重操作,
    # 有些过滤器类只需要在针对第一个实例的过滤过程中运行一次即可, 之后的实例就不再运行
    def run_filter_for_index(self, index):
        if self.run_filter_once_per_request and index > 0:
            return False
        else:
            return True


# 主机过滤器基类
class BaseHostFilter(filters.BaseFilter):
    def _filter_one(self, obj, filter_properties):
        return self.host_passes(obj, filter_properties)

    def host_passes(self, host_state, filter_properties):
        raise NotImplementedError()
        

# 举例: 磁盘过滤器
class DiskFilter(filters.BaseHostFilter):

    def host_passes(self, host_state, filter_properties):

        # 求出创建虚拟机实例所需的磁盘大小
        instance_type = filter_properties.get('instance_type')
        requested_disk = (1024 * (instance_type['root_gb'] +
                                 instance_type['ephemeral_gb']) +
                         instance_type['swap'])

        # 主机的当前可用磁盘大小
        free_disk_mb = host_state.free_disk_mb
        # 主机的总物理磁盘大小
        total_usable_disk_mb = host_state.total_usable_disk_gb * 1024

        # disk_allocation_ratio是总虚拟机实例磁盘/物理磁盘的比率, 默认是1.0;
        # 我们创建一个硬盘大小为60GB的虚拟机实例, 它并不会立刻占用60GB的物理磁盘;
        # 因此, 我们可能在1000GB的物理硬盘上, 创建30个硬盘大小为60GB的虚拟机实例,
        # 这完全是可以的, 只是存在磁盘爆满的情况; 所以这个disk_allocation_ratio我们
        # 可以根据具体应用场景酌情设置高一些
        disk_mb_limit = total_usable_disk_mb * CONF.disk_allocation_ratio
        # 当前已使用硬盘大小
        used_disk_mb = total_usable_disk_mb - free_disk_mb
        # 可用虚拟机实例磁盘大小
        usable_disk_mb = disk_mb_limit - used_disk_mb

        # 当可用虚拟机实例磁盘<创建虚拟机实例所需的磁盘大小时, 我们认为不能让实例落在该主机上
        if not usable_disk_mb >= requested_disk:
            LOG.debug(_("%(host_state)s does not have %(requested_disk)s MB "
                    "usable disk, it only has %(usable_disk_mb)s MB usable "
                    "disk."), {'host_state': host_state,
                               'requested_disk': requested_disk,
                               'usable_disk_mb': usable_disk_mb})
            return False

        # 更新主机的状态信息
        disk_gb_limit = disk_mb_limit / 1024
        host_state.limits['disk_gb'] = disk_gb_limit
        return True


class BaseFilterHandler(loadables.BaseLoader):

    def get_filtered_objects(self, filter_classes, objs,
            filter_properties, index=0):
        list_objs = list(objs)
        LOG.debug(_("Starting with %d host(s)"), len(list_objs))
        for filter_cls in filter_classes:
            cls_name = filter_cls.__name__
            # 创建过滤器类实例
            filter = filter_cls()

            # 判断该过滤器在当前index下是否需要运行
            if filter.run_filter_for_index(index):
                # 对每个list_obj进行_filter_one过滤, _filter_one实际会调用host_passes进行真正的过滤操作
                # 因此, 每个过滤器类只需要继承BaseHostFilter类并实现host_passes方法即可,
                # 这里会返回一个生成器对象
                objs = filter.filter_all(list_objs,
                                               filter_properties)
                if objs is None:
                    LOG.debug(_("Filter %(cls_name)s says to stop filtering"),
                          {'cls_name': cls_name})
                    return
                list_objs = list(objs)
                if not list_objs:
                    # 如果在该过滤器运行之后,没有list_obj通过过滤, 
                    # 那么就不需要运行剩余的过滤器了
                    LOG.info(_("Filter %s returned 0 hosts"), cls_name)
                    break
                LOG.debug(_("Filter %(cls_name)s returned "
                            "%(obj_len)d host(s)"),
                          {'cls_name': cls_name, 'obj_len': len(list_objs)})
        # 返回最终通过所有过滤的list_obj
        return list_objs


class HostManager(object):

    # 返回filter_cls_names指定的过滤器列表
    def _choose_host_filters(self, filter_cls_names):
        if filter_cls_names is None:
        # 如果filter_cls_names未空,那么就返回配置选项scheduler_default_filters中指定的过滤器列表
            filter_cls_names = CONF.scheduler_default_filters
        if not isinstance(filter_cls_names, (list, tuple)):
            filter_cls_names = [filter_cls_names]
        # 返回所有可用的过滤器名称和对应的过滤器类
        # 过滤器采用了插件模式,我们可以自定义过滤器,只需要将文件放入nova/scheduler/filters下面,
        # 那么就可以通过配置选项scheduler_default_filters来使用其中的过滤器
        # 每当nova-scheduler开始运行, 它就会自动在该目录下加载过滤器
        cls_map = dict((cls.__name__, cls) for cls in self.filter_classes)
        
        # 我们可能会因为手误配置了不存在的调度器名, 那么下面就是对要使用的过滤器进行验证,
        # 以杜绝这种错误的发生
        good_filters = []
        bad_filters = []
        for filter_name in filter_cls_names:
            if filter_name not in cls_map:
                bad_filters.append(filter_name)
                continue
            good_filters.append(cls_map[filter_name])
        if bad_filters:
            msg = ", ".join(bad_filters)
            # 如果要使用的调度器不存在,就抛出异常
            raise exception.SchedulerHostFilterNotFound(filter_name=msg)
        # 返回要使用的过滤器类
        return good_filters

    # 对参数hosts中的所有主机进行过滤,返回通过所有过滤条件的主机
    def get_filtered_hosts(self, hosts, filter_properties,
            filter_class_names=None, index=0):

        # 从host_map中去除hostname在hosts_to_ignore中的主机
        def _strip_ignore_hosts(host_map, hosts_to_ignore):
            ignored_hosts = []
            for host in hosts_to_ignore:
                for (hostname, nodename) in host_map.keys():
                    if host == hostname:
                        del host_map[(hostname, nodename)]
                        ignored_hosts.append(host)
            ignored_hosts_str = ', '.join(ignored_hosts)
            msg = _('Host filter ignoring hosts: %s')
            LOG.audit(msg % ignored_hosts_str)

        # 从host_map中去除hostname不在hosts_to_force中的主机
        def _match_forced_hosts(host_map, hosts_to_force):
            forced_hosts = []
            for (hostname, nodename) in host_map.keys():
                if hostname not in hosts_to_force:
                    del host_map[(hostname, nodename)]
                else:
                    forced_hosts.append(hostname)
            if host_map:
                forced_hosts_str = ', '.join(forced_hosts)
                msg = _('Host filter forcing available hosts to %s')
            else:
                forced_hosts_str = ', '.join(hosts_to_force)
                msg = _("No hosts matched due to not matching "
                        "'force_hosts' value of '%s'")
            LOG.audit(msg % forced_hosts_str)

        # 从host_map中去除nodenames不在nodes_to_force中的主机
        def _match_forced_nodes(host_map, nodes_to_force):
            forced_nodes = []
            for (hostname, nodename) in host_map.keys():
                if nodename not in nodes_to_force:
                    del host_map[(hostname, nodename)]
                else:
                    forced_nodes.append(nodename)
            if host_map:
                forced_nodes_str = ', '.join(forced_nodes)
                msg = _('Host filter forcing available nodes to %s')
            else:
                forced_nodes_str = ', '.join(nodes_to_force)
                msg = _("No nodes matched due to not matching "
                        "'force_nodes' value of '%s'")
            LOG.audit(msg % forced_nodes_str)

        # 获取filter_class_names指定的过滤器类列表
        filter_classes = self._choose_host_filters(filter_class_names)
        ignore_hosts = filter_properties.get('ignore_hosts', [])
        force_hosts = filter_properties.get('force_hosts', [])
        force_nodes = filter_properties.get('force_nodes', [])

        if ignore_hosts or force_hosts or force_nodes:
            # 我们不能假设host是唯一的,因为一个host可能运行多个nodes
            name_to_cls_map = dict([((x.host, x.nodename), x) for x in hosts])
            if ignore_hosts:
                # 从name_to_cls_map中去除hostname在ignore_hosts中的host
                _strip_ignore_hosts(name_to_cls_map, ignore_hosts)
                if not name_to_cls_map:
                    return []

            if force_hosts:
                # 从name_to_cls_map中去除hostname不在force_hosts中的host
                _match_forced_hosts(name_to_cls_map, force_hosts)
            if force_nodes:
                # # 从name_to_cls_map中去除nodename不在force_nodes中的host
                _match_forced_nodes(name_to_cls_map, force_nodes)
            if force_hosts or force_nodes:
                # 当我们强制了虚拟机要落在哪些host或node上, 就可以跳过过滤过程
                if name_to_cls_map:
                    return name_to_cls_map.values()
            hosts = name_to_cls_map.itervalues()
        
        # 对hosts使用filter_classes中的过滤器进行过滤, 返回通过过滤的主机列表
        return self.filter_handler.get_filtered_objects(filter_classes,
                hosts, filter_properties, index)


第二步,称重weigh,通过HostManager的get_weighed_hosts实现, 为什么要称重呢?我们可能有多个主机通过过滤filter,那我们怎么决定实例落在哪个主机上了,这就是称重的作用,帮助我们对这些主机进行排序, 以选取出相对最优的主机。

Icehouse版本支持的称重器就以下2种:

RAMWeigher -> 内存称重器, 可用内存越多,重量越重

MetricsWeigher -> 指标称重器, 可以通过配置的形式指定主机的多种指标和比率, 将这些指标结合起来进行称重

我曾经因为需要, 自己写过VCPU称重器,方法很简单,但是对于权重的选择要把握好

# 称重目标类
class WeighedObject(object):

    def __init__(self, obj, weight):
        self.obj = obj
        self.weight = weight

    def __repr__(self):
        return "<WeighedObject '%s': %s>" % (self.obj, self.weight)


# 称重器抽象基类
@six.add_metaclass(abc.ABCMeta)
class BaseWeigher(object):
    minval = None
    maxval = None

    def weight_multiplier(self):
        return 1.0

    @abc.abstractmethod
    def _weigh_object(self, obj, weight_properties):

    def weigh_objects(self, weighed_obj_list, weight_properties):
        weights = []
        for obj in weighed_obj_list:
            # 对obj.obj进行称重
            weight = self._weigh_object(obj.obj, weight_properties)
            
            # 记录和更新重量的最大最小值, 方便进行归一化
            if self.minval is None:
                self.minval = weight
            if self.maxval is None:
                self.maxval = weight

            if weight < self.minval:
                self.minval = weight
            elif weight > self.maxval:
                self.maxval = weight

            weights.append(weight)

        return weights


# 举例: 内存称重器
# 每个称重器只要实现_weigh_object即可, weight_multiplier可根据情况进行覆盖
class RAMWeigher(weights.BaseHostWeigher):
    minval = 0

    def weight_multiplier(self):
        # 返回配置的内存称重权重, 默认为1.0
        return CONF.ram_weight_multiplier

    def _weigh_object(self, host_state, weight_properties):
        # 返回主机的可用内存大小, 内存越大, 优先级越高;
        # 如果我们希望越小优先级越高, 可通过乘以-1实现
        return host_state.free_ram_mb


# 称重处理器基类
class BaseWeightHandler(loadables.BaseLoader):
    object_class = WeighedObject

    def get_weighed_objects(self, weigher_classes, obj_list,
            weighing_properties):

        if not obj_list:
            return []

        # 将要称重的object封装进WeighedObject里, weight为0.0 
        weighed_objs = [self.object_class(obj, 0.0) for obj in obj_list]
        for weigher_cls in weigher_classes:
            # 实例化称重器
            weigher = weigher_cls()
            # 对weighed_objs逐个进行称重, 并返回weights列表
            weights = weigher.weigh_objects(weighed_objs, weighing_properties)

            # 对weights进行归一化, 让每个weight处于[0.0,1.0]之间
            # 为什么要这样做呢?我们不能让称重元素的重量过多的影响称重结果;
            # 假设我们要对主机的内存、硬盘进行称重, 一般主机的内存会比硬盘小很多, 譬如内存为128GB, 硬盘为2048GB;
            # 如果我们不进行归一化, 由于硬盘和内存的大小相差较大, 导致内存的称重对称重结果影响微乎其微, 甚至毫无作用;
            # 我们可以通过归一化抹平不同称重元素之间的差异性, 而通过权重来指定它们的重要性
            weights = normalize(weights,
                                minval=weigher.minval,
                                maxval=weigher.maxval)

            for i, weight in enumerate(weights):
                obj = weighed_objs[i]
                # 更新obj的重量
                # weight_multiplier方法返回的是该称重器的权重
                # 我们可以根据实际需要, 为不同称重器指定不同的权重, 一般来说相对重要的称重器权重更高
                obj.weight += weigher.weight_multiplier() * weight

        # 对称重目标列表按照重量的大小进行降序排列
        # 在OpenStack中重量越大, 意味着主机的优先级越高
        return sorted(weighed_objs, key=lambda x: x.weight, reverse=True)


# 主机称重处理器
class HostWeightHandler(weights.BaseWeightHandler):
    object_class = WeighedHost

    def __init__(self):
        super(HostWeightHandler, self).__init__(BaseHostWeigher)


class HostManager(object):

    def __init__(self):
        ...
        # 创建主机称重处理器实例
        self.weight_handler = weights.HostWeightHandler()
        # 同过滤器一样, 称重器也是采用了插件模式, 我们可以自定义称重器,只需要将文件放入nova/scheduler/weights下面;
        # 这里用于获取和加载该目录下的称重器类
        self.weight_classes = self.weight_handler.get_matching_classes(
                CONF.scheduler_weight_classes)

    def get_weighed_hosts(self, hosts, weight_properties):
        # 这里调用的是BaseWeightHandler中的get_weighed_objects方法;
        # 对hosts使用weight_classes中的称重器进行称重, 返回称重后的有序主机列表
        return self.weight_handler.get_weighed_objects(self.weight_classes,
                hosts, weight_properties)



本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【Nova】nova-scheduler过滤称重 的相关文章

  • VMM插件和OpenStack nova集成(华三CAS插件处理虚拟化流程及源码分析)

    插件组成 华三目前依托OpenStack有以下几个插件 xff1a l openstack cas nova version tar gz 虚拟化 l openstack cas cinder version tar gz 为用户提供统一的
  • OpenStack之Nova(T版)

    目录 一 概述二 Nova系统架构一 API二 Scheduler一 选择计算节点二 调度器类型三 过滤器 三 compute四 conductor五 PlacementAPl六 cell架构 三 部署一 Placement一 创建数据库二
  • 【Nova】nova-scheduler过滤称重

    在上一篇 nova scheduler调度过程分析 中 xff0c 对过滤称重的过程一笔带过了 xff0c 这篇着重介绍一下 首先 xff0c 我们声明一下host为主机 xff0c node为节点 xff0c 在OpenStack中一个h
  • Quartz学习总结之核心接口Scheduler、Job

    参考文章 https www cnblogs com mengrennwpu p 7141986 html 核心接口如下 接口 含义 Scheduler scheduler的主要API接口 Job 任务实现接口 期望调度器能够执行 JobD
  • Nova: 2 Nova源码以及服务路径

    目标 1 弄清楚nova组件通过packstack安装后源码位置 2 确定nova组件服务启动路径 3 确定nova组件配置文件路径 0 whereis nova root localhost www whereis nova nova u
  • 如何在 Android 中设置持久/定期计划?

    如何在每个指定时间 例如每天凌晨 5 点 执行一个操作 可能是一个 Intent 它必须在设备重新启动后保留 类似于 cron 的工作原理 我不确定是否可以使用AlarmManager为此 我可以吗 如果您希望它在设备重新启动后保留 则必须
  • Python 调度程序与循环 + 睡眠

    以下是 蟒蛇计划 from time import time sleep from sched import scheduler def daemon local handler print hi local handler enter 3
  • 气流可以在不重新启动调度程序的情况下加载 dags 文件吗

    就我而言 我在 dags 路径下编写了一个 dag 文件 启动airflow调度程序后 成功加载dag文件 但是 更改 dag 文件后 无法加载 dag 文件 有没有建议加载 dag 文件而不重新启动调度程序 您的 DAG 应根据调度程序心
  • 寻找有限状态机的不同调度算法的比较

    是否有任何好的资源 书籍 网站 可以对没有操作系统的嵌入式系统中的有限状态机 FSM 的不同调度算法进行很好的比较 我正在设计一个简单的嵌入式网络服务器 没有操作系统 我想知道用于安排系统中发生的不同事件的处理的各种方法 例如 如果两个事件
  • 调度周期性任务和时钟漂移

    我想安排一个每隔 X 小时执行一次的定期任务 我有一个用 Java 编写的服务 我正在考虑创建一个长时间运行的后台线程 只要服务启动 它就永远运行 我如何确保我们每 X 小时执行一次任务 我的主机上的时钟漂移是我应该担心的问题吗 我知道如果
  • 对于彩票调度程序来说,比 LCG 更好的(伪)随机数生成器是什么?

    我想设计一个彩票调度程序 我需要一个非常好的 伪 随机数生成器 类似于 LCG 但我想知道是否还有其他更好的选择 我专门寻找用 C 编写的随机生成器 LCG代码 unsigned long lcg rand unsigned long a
  • Flyway clean 不会删除调度程序作业或程序

    我最近在我的开发模式中添加了一个调度程序作业和程序 当我尝试刷新架构时 我做了一个飞行路线clean 然后是飞行路线migrate 我收到以下错误 ERROR Found non empty schema TESTDATA without
  • Linux内核:schedule()在什么进程中运行?

    当您调用系统调用时 例如fork在进程 X 中 内核被认为是在进程上下文中执行 所以 fork可以说是运行在进程X中吧 But if schedule 在同一进程中被调用 并且它不是系统调用 你会说它是作为 X 的一部分运行吗 或者它在交换
  • 具有 REST API 的开源作业调度程序

    是否有任何具有 REST API 的开源作业调度程序可供商业使用 它将支持以下功能 树状作业依赖关系 保持和释放 重新运行失败的步骤 并行性 如有帮助 将不胜感激 注意 我们正在寻找开源替代方案TWS http en wikipedia o
  • sched_getcpu() 相当于 OS X 吗?

    在 OS X 上 有没有办法找出线程正在哪个 CPU 上运行 Linux 的等效函数是调度获取CPU http man7 org linux man pages man3 sched getcpu 3 html 获取当前处理器编号 http
  • 避免 kubernetes 调度程序在 kubernetes 集群的单个节点上运行所有 pod

    我有一个 Kubernetes 集群 有 4 个节点和 1 个主节点 我正在尝试在所有节点中运行 5 个 nginx pod 目前 调度程序有时在一台机器上运行所有 Pod 有时在不同的机器上运行 如果我的节点出现故障并且所有 Pod 都在
  • 任务计划程序 - 在未登录的情况下运行任务时访问非本地驱动器

    我在 win 调度程序中有一个每分钟运行的任务 该任务运行一个 bat 文件 SVN 会更新一系列文件夹 然后执行一个 perl 脚本 该脚本又会运行其他几个脚本 Perl 脚本的输出 日志 按日期 时间标记 被发送到共享驱动器 而不是任务
  • 按一天中的时间自动切换 Windows 10 中的暗/亮模式(无需修改或更改主题!)

    如今大多数设备都允许自动切换暗 亮模式 但 Windows 10 似乎没有这样的功能 有办法做到这一点吗 例如使用任务计划程序 似乎有很多关于如何以编程方式更改窗口 主题 的示例 但没有关于亮 暗模式切换的示例 可以在 设置 颜色 中为 W
  • 非抢占式 最早截止时间优先调度

    我正在开发任务调度程序 我想使用 EDF 调度 我需要安排的任务集仅包含截止日期等于其周期的任务 并且必须定期安排任务 我遇到的问题是任务一旦开始执行就无法中断 我知道 仅当任务抢占式地在单个处理器上调度时 EDF 才是最佳调度算法 因此我
  • 如何使用 Laravel Scheduler 命令将输出重定向到 STDOUT?

    我的调度程序应用程序运行到 Docker 容器中 Laravel 调度程序由主管管理并执行到容器中 我通过以下方式管理输出重定向 http veithen github io 2015 01 08 supervisord redirecti

随机推荐

  • GitLab 使用Tortoisegit询问“git@192.168.1.18‘s password“问题解决

    现象如下 xff1a 使用TortoiseGit去拉本地GitLab上建立的项目时 xff0c 一直提示输入密码 xff08 如下图 xff09 xff0c 这个密码又没有指定用户名 xff0c 就算你输入你用户名的密码也是失败 但是很诡异
  • 二代身份证读写器原理及开发

    身份证读写器的作用就是从身份证中读取身份信息 xff08 例如姓名 民族 身份证号等 xff09 xff0c 然后显示或者传输给其他模块使用 功能框架如下 xff1a 功能框图说明 xff1a 1 业务模块 负责向安全模块发送命令 xff0
  • JLINK V10 V11固件修复

    先去我的资源里面下载bootloader和app固件文件 步骤 xff1a 1 PC上安装JLINK V4 9工具 xff08 貌似不能使用太高版本的工具 xff0c 否则有问题 xff09 2 打开j flash v4 9 xff0c 新
  • ROS | 话题通信的编程实现

    ROS 话题通信的编程实现 1 创建功能包2 节点编程与消息定义2 1 案例说明2 2 话题消息的定义2 3 创建 cpp文件2 4 话题发布者编程2 5 话题订阅者编程 3 配置与编译3 1 在CMaKeLists txt中添加编译选项3
  • Cocos2dx 3.0配置环境

    3 15 cocos2dx 3 0rc0 终于放出来了 在这里不得不吐槽一件事 xff0c 3 0版本从Alpha xff0c 到beta xff0c 再到rc xff0c 三个版本竟然都有各自创建项目的方式 xff0c 这样真的不会被人打
  • linux 开机运行应用程序

    把运行应用程序的脚本放在 etc rc local里面 xff0c 如果没有 etc rc local xff0c 需要执行前面的3条指令新建这个文件 注意执行应用最好要在后台执行 xff08 后面加个 amp xff09 xff0c 否则
  • arm linux游戏手柄(joystick)驱动移植

    在arm linux中移植usb joystick驱动 xff0c 参考了如下经验 xff1a Linux系统中使用Xbox360手柄 知 行 博客园 cnblogs com 使用BlueZ连接蓝牙手柄 Dokin丶的博客 CSDN博客 蓝
  • linux ubuntu下网络调试助手(GUI)工具

    mNetAssist这个工具在ubuntu下可以运行 xff0c 是个带界面的tcp调试工具 1 UDP通讯 xff1b 2 可做 TCP客户端 xff1b 3 可做 TCP服务器 xff1b 4 可以 十六进制 传送接收数据 5 可以传送
  • fft的通俗解释

    FFT是离散傅立叶变换的快速算法 xff0c 可以将一个信号变换 到频域 有些信号在时域上是很难看出什么特征的 xff0c 但是如 果变换到频域之后 xff0c 就很容易看出特征了 这就是很多信号 分析采用FFT变换的原因 另外 xff0c
  • linux 字符驱动完整框架(poll,async,waitqueue,nonblock等)

    一个linux内核驱动的完整框架 xff0c 包含了能遇到的大部分内容 xff0c 例如timer poll async waitqueue nonblock等等 xff0c 不过基本上没啥大用 xff0c 就是用来熟悉基础的 xff0c
  • vscode远程调试Linux CUDA程序

    参考了 xff1a CUDA 01 第一个程序 知乎 zhihu com 1 本地安装插件 xff1a remote ssh xff0c Microsoft C C 43 43 与NVIDIA Nsight Visual Studio Co
  • 移植MQTT-C库(附源码)

    Software mqtt org 中mqtt客户端的c库里面有一个叫MQTT C的库 xff0c 就2个实现文件 xff0c 算比较简单的了 xff0c 实现了基本的mqtt客户端功能 xff0c 移植一下试试 我的移植代码放在我的资源里
  • TCP协议的滑动窗口和流量控制算法(转)

    目录 滑动窗口 流量控制 操作系统缓冲区与滑动窗口的关系 窗口关闭 糊涂窗口综合症 拥塞控制 慢启动 拥塞避免算法 拥塞发生 快速恢复 拥塞算法示意图 引入 窗口概念的原因 我们都知道 TCP 是每发送一个数据 xff0c 都要进行一次确认
  • linux应用中的时间处理

    参考下 xff1a Linux下有关时间的函数 xff1a time times clock gettimeofday等 linux time函数 见牛羊的博客 CSDN博客 下面的代码基本涵盖了获取时间和操作计时的一些函数使用 xff1a
  • 从旋转向量到欧拉角的六种计算方法

    利用SolvePNP解出旋转向量 xff0c 旋转向量通过罗德里格斯公式解出旋转矩阵 xff0c 然后通过下面六种公式计算即可 xff0c 欧拉角有十二种 xff0c 六种是相对于自身参考系 xff0c 六种是相对于惯性参考系 xff0c
  • ROS | 服务通信的编程实现

    ROS 服务通信的编程实现 1 创建功能包2 节点编程与服务数据定义2 1 案例说明2 2 服务数据的定义2 3 创建 cpp文件2 4 客户端编程2 5 服务器编程 3 配置与编译3 1 在CMaKeLists txt中添加编译选项3 2
  • HTTP基础验证

    HTTP 内置基础验证 浏览器收到401状态码响应后 xff0c 弹出要求输入信息的对话框 通过验证则显示内容 xff0c 不通过不显示需要验证身份的内容 1 xff1b 手动HTTP基础验证 xff1a header 39 http 1
  • 位域,段域,联合体,结构体操作寄存器

    include lt stdio h gt typedef int Uint16 struct SCICCR BITS bit description Uint16 SCICHAR 3 2 0 Character length contro
  • C++ 网络编程之使用socket + epoll 模拟http 的请求与响应

    为了更好的理解http协议 xff0c 笔者使用了C 43 43 socket模拟了一个http服务器 xff0c 其中的服务器使用了epoll的方式 xff0c 并针对每一个新的连接开启新线程处理 大致分为三个部分 xff0c 具体代码可
  • 【Nova】nova-scheduler过滤称重

    在上一篇 nova scheduler调度过程分析 中 xff0c 对过滤称重的过程一笔带过了 xff0c 这篇着重介绍一下 首先 xff0c 我们声明一下host为主机 xff0c node为节点 xff0c 在OpenStack中一个h