一、        主机驱动与外设驱动分离

        Linux中的SPI、I2c、USB等子系统都利用了典型的把主机驱动和外设驱动分离的想法,让主机端负责产生总线上的传输波形,而外设端只是通过标准的API来让主机端以适当的波形访问自身。因此这里涉及了4个软件模块:

        1)主机端的驱动。根据具体的I2c、SPI、USB等控制器的硬件的手册,操作具体的i2c、SPI、USB等控制器,产生总线的各种波形。

        2)连接主机和外设的纽带。外设不直接调用主机端的驱动来产生波形,而是调一个标准的API。由这个标准的API把这个波形的传输请求间接“转发”给具体的主机端驱动。当然,在这里,最好把关于波形的描述也以某种数据结构标准化。

        3)外设端的驱动。外设接在I2c、SPI、USB这样的总线上,但是它们本身可以是触摸屏、网卡、声卡或者任意一种类型的设备。我们在相关的i2c_driver、spi_driver、usb_driver这种xxx_driver的probe()函数中注册具体的类型。当这些外设要去i2c、spi、usb等去访问它的时候,它调用“连接主机和外设的纽带”模块的标准API。

        4)板级逻辑。板级逻辑用来描述主机和外设是如何互联,它相当于一个“路由表”。假设板子上有多个SPI控制器和多个SPI外设,那究竟谁接在谁上面?管理互联关系,既不是主机端的责任,也不是外设端的责任,这属于板级逻辑的责任。这部分通常在arch/arm/mach-xx或者arch/arm/boot/dts下面。

        什么叫良好的软件设计?一言以蔽之,让正确的代码出现在正确的位置。不要在错误的时间、错误的地点,编写一段错位的代码。在LKML中,关于代码出现在错误的位置,常见的台词是代码“out of place”。

        

二、        linux SPI主机和设备驱动

        在linux中,用代码的spi_maste结构体来描述一个spi主机控制器驱动,其主要成员是主机控制器的序号(系统中可能存在多个SPI主机控制器)、片选数量、SPI模式、时钟设置用到的和数据传输用到的函数等。

        

 521 struct spi_controller {522     struct device   dev;523 524     struct list_head list;525 526     /*527      * Other than negative (== assign one dynamically), bus_num is fully528      * board-specific. Usually that simplifies to being SoC-specific.529      * example: one SoC has three SPI controllers, numbered 0..2,530      * and one board's schematics might show it using SPI-2. Software531      * would normally use bus_num=2 for that controller.532      */533     s16         bus_num;534 535     /*536      * Chipselects will be integral to many controllers; some others537      * might use board-specific GPIOs.538      */539     u16         num_chipselect;540 541     /* Some SPI controllers pose alignment requirements on DMAable542      * buffers; let protocol drivers know about these requirements.543      */544     u16         dma_alignment;545 546     /* spi_device.mode flags understood by this controller driver */547     u32         mode_bits;548 549     /* spi_device.mode flags override flags for this controller */550     u32         buswidth_override_bits;551 552     /* Bitmask of supported bits_per_word for transfers */553     u32         bits_per_word_mask;554 #define SPI_BPW_MASK(bits) BIT((bits) - 1)555 #define SPI_BPW_RANGE_MASK(min, max) GENMASK((max) - 1, (min) - 1)556 557     /* Limits on transfer speed */558     u32         min_speed_hz;559     u32         max_speed_hz;560 561     /* Other constraints relevant to this driver */562     u16         flags;563 #define SPI_CONTROLLER_HALF_DUPLEX  BIT(0)  /* Can't do full duplex */564 #define SPI_CONTROLLER_NO_RX        BIT(1)  /* Can't do buffer read */565 #define SPI_CONTROLLER_NO_TX        BIT(2)  /* Can't do buffer write */566 #define SPI_CONTROLLER_MUST_RX      BIT(3)  /* Requires rx */567 #define SPI_CONTROLLER_MUST_TX      BIT(4)  /* Requires tx */568 #define SPI_CONTROLLER_GPIO_SS      BIT(5)  /* GPIO CS must select slave */569 #define SPI_CONTROLLER_SUSPENDED    BIT(6)  /* Currently suspended */570 571     /* Flag indicating if the allocation of this struct is devres-managed */572     bool            devm_allocated;573 574     union {575         /* Flag indicating this is an SPI slave controller */576         bool            slave;577         /* Flag indicating this is an SPI target controller */578         bool            target;579     };580 581     /*582      * On some hardware transfer / message size may be constrained583      * the limit may depend on device transfer settings.584      */585     size_t (*max_transfer_size)(struct spi_device *spi);586     size_t (*max_message_size)(struct spi_device *spi);587 588     /* I/O mutex */589     struct mutex        io_mutex;590 591     /* Used to avoid adding the same CS twice */592     struct mutex        add_lock;593 594     /* Lock and mutex for SPI bus locking */595     spinlock_t      bus_lock_spinlock;596     struct mutex        bus_lock_mutex;597 598     /* Flag indicating that the SPI bus is locked for exclusive use */599     bool            bus_lock_flag;600 601     /*602      * Setup mode and clock, etc (SPI driver may call many times).603      *604      * IMPORTANT:  this may be called when transfers to another605      * device are active.  DO NOT UPDATE SHARED REGISTERS in ways606      * which could break those transfers.607      */608     int         (*setup)(struct spi_device *spi);609 610     /*611      * set_cs_timing() method is for SPI controllers that supports612      * configuring CS timing.613      *614      * This hook allows SPI client drivers to request SPI controllers615      * to configure specific CS timing through spi_set_cs_timing() after616      * spi_setup().617      */618     int (*set_cs_timing)(struct spi_device *spi);619 620     /*621      * Bidirectional bulk transfers622      *623      * + The transfer() method may not sleep; its main role is624      *   just to add the message to the queue.625      * + For now there's no remove-from-queue operation, or626      *   any other request management627      * + To a given spi_device, message queueing is pure FIFO628      *629      * + The controller's main job is to process its message queue,630      *   selecting a chip (for masters), then transferring data631      * + If there are multiple spi_device children, the i/o queue632      *   arbitration algorithm is unspecified (round robin, FIFO,633      *   priority, reservations, preemption, etc)634      *635      * + Chipselect stays active during the entire message636      *   (unless modified by spi_transfer.cs_change != 0).637      * + The message transfers use clock and SPI mode parameters638      *   previously established by setup() for this device639      */640     int         (*transfer)(struct spi_device *spi,641                         struct spi_message *mesg);642 643     /* Called on release() to free memory provided by spi_controller */644     void            (*cleanup)(struct spi_device *spi);645 646     /*647      * Used to enable core support for DMA handling, if can_dma()648      * exists and returns true then the transfer will be mapped649      * prior to transfer_one() being called.  The driver should650      * not modify or store xfer and dma_tx and dma_rx must be set651      * while the device is prepared.652      */653     bool            (*can_dma)(struct spi_controller *ctlr,654                        struct spi_device *spi,655                        struct spi_transfer *xfer);656     struct device *dma_map_dev;657     struct device *cur_rx_dma_dev;658     struct device *cur_tx_dma_dev;659 660     /*661      * These hooks are for drivers that want to use the generic662      * controller transfer queueing mechanism. If these are used, the663      * transfer() function above must NOT be specified by the driver.664      * Over time we expect SPI drivers to be phased over to this API.665      */666     bool                queued;667     struct kthread_worker       *kworker;668     struct kthread_work     pump_messages;669     spinlock_t          queue_lock;670     struct list_head        queue;671     struct spi_message      *cur_msg;672     struct completion               cur_msg_completion;673     bool                cur_msg_incomplete;674     bool                cur_msg_need_completion;675     bool                busy;676     bool                running;677     bool                rt;678     bool                auto_runtime_pm;679     bool                cur_msg_mapped;680     char                last_cs;681     bool                last_cs_mode_high;682     bool                            fallback;683     struct completion               xfer_completion;684     size_t              max_dma_len;685 686     int (*prepare_transfer_hardware)(struct spi_controller *ctlr);687     int (*transfer_one_message)(struct spi_controller *ctlr,688                     struct spi_message *mesg);689     int (*unprepare_transfer_hardware)(struct spi_controller *ctlr);690     int (*prepare_message)(struct spi_controller *ctlr,691                    struct spi_message *message);692     int (*unprepare_message)(struct spi_controller *ctlr,693                  struct spi_message *message);694     union {695         int (*slave_abort)(struct spi_controller *ctlr);696         int (*target_abort)(struct spi_controller *ctlr);697     };698 699     /*700      * These hooks are for drivers that use a generic implementation701      * of transfer_one_message() provided by the core.702      */703     void (*set_cs)(struct spi_device *spi, bool enable);704     int (*transfer_one)(struct spi_controller *ctlr, struct spi_device *spi,705                 struct spi_transfer *transfer);706     void (*handle_err)(struct spi_controller *ctlr,707                struct spi_message *message);708 709     /* Optimized handlers for SPI memory-like operations. */710     const struct spi_controller_mem_ops *mem_ops;711     const struct spi_controller_mem_caps *mem_caps;712 713     /* GPIO chip select */714     struct gpio_desc    **cs_gpiods;715     bool            use_gpio_descriptors;716     s8          unused_native_cs;717     s8          max_native_cs;718 719     /* Statistics */720     struct spi_statistics __percpu  *pcpu_statistics;721 722     /* DMA channels for use with core dmaengine helpers */723     struct dma_chan     *dma_tx;724     struct dma_chan     *dma_rx;725 726     /* Dummy data for full duplex devices */727     void            *dummy_rx;728     void            *dummy_tx;729 730     int (*fw_translate_cs)(struct spi_controller *ctlr, unsigned cs);731 732     /*733      * Driver sets this field to indicate it is able to snapshot SPI734      * transfers (needed e.g. for reading the time of POSIX clocks)735      */736     bool            ptp_sts_supported;737 738     /* Interrupt enable state during PTP system timestamping */739     unsigned long       irq_flags;740 741     /* Flag for enabling opportunistic skipping of the queue in spi_sync */742     bool            queue_empty;743     bool            must_async;744 };

        分配、注册和注销SPI主机的API由SPI核心提供:

     

        在linux中,用代码清单的spi_driver结构体来描述一个SPI外设驱动,这个外设驱动可以认为是spi_master的客户端驱动。

 325 struct spi_driver {326     const struct spi_device_id *id_table;327     int         (*probe)(struct spi_device *spi);328     void            (*remove)(struct spi_device *spi);329     void            (*shutdown)(struct spi_device *spi);330     struct device_driver    driver;331 };

        可以看出,spi_driver结构体和platform_driver结构体有极大的相似性,都有probe()、remove()、suspend()、resume()这样都接口和device_driver都实例。这几乎是一切客户端驱动常模板。 

        在SPI外设驱动中,当通过SPI总线进行数据传输都时候,使用了一套与CPU无关的统一的接口。这套接口的第1个关键数据结构就是spi_transfer,它用于描述SPI传输,如下所示:

1030 struct spi_transfer {
1031     /*
1032      * It's okay if tx_buf == rx_buf (right?).
1033      * For MicroWire, one buffer must be NULL.
1034      * Buffers must work with dma_*map_single() calls, unless
1035      * spi_message.is_dma_mapped reports a pre-existing mapping.
1036      */
1037     const void  *tx_buf;
1038     void        *rx_buf;
1039     unsigned    len;
1040 
1041 #define SPI_TRANS_FAIL_NO_START BIT(0)
1042     u16     error;
1043 
1044     dma_addr_t  tx_dma;
1045     dma_addr_t  rx_dma;
1046     struct sg_table tx_sg;
1047     struct sg_table rx_sg;
1048 
1049     unsigned    dummy_data:1;
1050     unsigned    cs_off:1;
1051     unsigned    cs_change:1;
1052     unsigned    tx_nbits:3;
1053     unsigned    rx_nbits:3;
1054     unsigned    timestamped:1;
1055 #define SPI_NBITS_SINGLE    0x01 /* 1-bit transfer */
1056 #define SPI_NBITS_DUAL      0x02 /* 2-bit transfer */
1057 #define SPI_NBITS_QUAD      0x04 /* 4-bit transfer */
1058     u8      bits_per_word;
1059     struct spi_delay    delay;
1060     struct spi_delay    cs_change_delay;
1061     struct spi_delay    word_delay;
1062     u32     speed_hz;
1063 
1064     u32     effective_speed_hz;
1065 
1066     unsigned int    ptp_sts_word_pre;
1067     unsigned int    ptp_sts_word_post;
1068 
1069     struct ptp_system_timestamp *ptp_sts;
1070 
1071     struct list_head transfer_list;
1072 };

        而一次完整的SPI传输流程可能不是只包含spi_transfer,它可能包含一个或多个spi_transfer,这些spi_transfer最终通过spi_message组织在一起。

1107 struct spi_message {
1108     struct list_head    transfers;
1109 
1110     struct spi_device   *spi;
1111 
1112     unsigned        is_dma_mapped:1;
1113 
1114     /* spi_prepare_message() was called for this message */
1115     bool            prepared;
1116 
1117     /*
1118      * REVISIT: we might want a flag affecting the behavior of the
1119      * last transfer ... allowing things like "read 16 bit length L"
1120      * immediately followed by "read L bytes".  Basically imposing
1121      * a specific message scheduling algorithm.
1122      *
1123      * Some controller drivers (message-at-a-time queue processing)
1124      * could provide that as their default scheduling algorithm.  But
1125      * others (with multi-message pipelines) could need a flag to
1126      * tell them about such special cases.
1127      */
1128 
1129     /* Completion is reported through a callback */
1130     int         status;
1131     void            (*complete)(void *context);
1132     void            *context;
1133     unsigned        frame_length;
1134     unsigned        actual_length;
1135 
1136     /*
1137      * For optional use by whatever driver currently owns the
1138      * spi_message ...  between calls to spi_async and then later
1139      * complete(), that's the spi_controller controller driver.
1140      */
1141     struct list_head    queue;
1142     void            *state;
1143 
1144     /* List of spi_res resources when the SPI message is processed */
1145     struct list_head        resources;
1146 
1147     /* For embedding transfers into the memory of the message */
1148     struct spi_transfer t[];
1149 };

        通过spi_message_init()可以初始化spi_message,而将spi_transfer添加到spi_message队列的方法则是:

     

        发起一次spi_message的传输有同步和异步两种方式,使用同步API时,会阻塞等待这个消息被处理完。同步操作时使用的API是:
 

        使用异步API时,不会阻塞等待这个消息被处理完,但是可以在spi_message的complete字段挂接一个回调函数,当消息被处理完成后,该函数会被调用。在异步操作时使用的API是:

       

        下图是非常典型的初始化spi_transfer、spi_message并进行spi数据传输的例子,同时spi_write()、spi_read()也是spi核心层的两个通用快捷API,在SPI外设驱动中可以直接调用它们进行简单的纯写和纯读操作。

         

        SPI主机控制器驱动位于driver/spi/,这些驱动的主体是实现了spi_master的transfer()、transfer_one()、setup()这样的成员函数,当然,也可能是实现spi_bitbang的txrx_bufs()、setup_transfer()、chipselect()这样的成员函数。 下图SPI主机端驱动完成的波形传输

摘取了./drivers/spi/spi-pl022.c的部分代码。

1576 static int pl022_transfer_one_message(struct spi_controller *host,
1577                       struct spi_message *msg)
1578 {
1579     struct pl022 *pl022 = spi_controller_get_devdata(host);
1580 
1581     /* Initial message state */
1582     pl022->cur_msg = msg;
1583     msg->state = STATE_START;
1584 
1585     pl022->cur_transfer = list_entry(msg->transfers.next,
1586                      struct spi_transfer, transfer_list);
1587 
1588     /* Setup the SPI using the per chip configuration */
1589     pl022->cur_chip = spi_get_ctldata(msg->spi);
1590     pl022->cur_cs = spi_get_chipselect(msg->spi, 0);
1591     /* This is always available but may be set to -ENOENT */
1592     pl022->cur_gpiod = spi_get_csgpiod(msg->spi, 0);
1593 
1594     restore_state(pl022);
1595     flush(pl022);
1596 
1597     if (pl022->cur_chip->xfer_type == POLLING_TRANSFER)
1598         do_polling_transfer(pl022);
1599     else
1600         do_interrupt_dma_transfer(pl022);
1601 
1602     return 0;
1603 }1840 static int pl022_setup(struct spi_device *spi)
1841 {
1842     struct pl022_config_chip const *chip_info;
1843     struct pl022_config_chip chip_info_dt;
1844     struct chip_data *chip;
1845     struct ssp_clock_params clk_freq = { .cpsdvsr = 0, .scr = 0};
1846     int status = 0;
1847     struct pl022 *pl022 = spi_controller_get_devdata(spi->controller);
1848     unsigned int bits = spi->bits_per_word;
1849     u32 tmp;
1850     struct device_node *np = spi->dev.of_node;
..........
..........
2027     /* Stuff that is common for all versions */
2028     if (spi->mode & SPI_CPOL)
2029         tmp = SSP_CLK_POL_IDLE_HIGH;
2030     else
2031         tmp = SSP_CLK_POL_IDLE_LOW;
2032     SSP_WRITE_BITS(chip->cr0, tmp, SSP_CR0_MASK_SPO, 6);
2033 
2034     if (spi->mode & SPI_CPHA)
2035         tmp = SSP_CLK_SECOND_EDGE;
2036     else
2037         tmp = SSP_CLK_FIRST_EDGE;
2038     SSP_WRITE_BITS(chip->cr0, tmp, SSP_CR0_MASK_SPH, 7);
2039 
2040     SSP_WRITE_BITS(chip->cr0, clk_freq.scr, SSP_CR0_MASK_SCR, 8);
...........
...........
2057  err_config_params:
2058     spi_set_ctldata(spi, NULL);
2059     kfree(chip);
2060     return status;
2061 }2101 static int pl022_probe(struct amba_device *adev, const struct amba_id *id)
2102 {
2103     struct device *dev = &adev->dev;
2104     struct pl022_ssp_controller *platform_info =
2105             dev_get_platdata(&adev->dev);
2106     struct spi_controller *host;
2107     struct pl022 *pl022 = NULL; /*Data for this driver */
2108     int status = 0;
..........
..........
2133     /*
2134      * Bus Number Which has been Assigned to this SSP controller
2135      * on this board
2136      */
2137     host->bus_num = platform_info->bus_id;
2138     host->cleanup = pl022_cleanup;
2139     host->setup = pl022_setup;
2140     host->auto_runtime_pm = true;
2141     host->transfer_one_message = pl022_transfer_one_message;
2142     host->unprepare_transfer_hardware = pl022_unprepare_transfer_hardware;
2143     host->rt = platform_info->rt;
2144     host->dev.of_node = dev->of_node;
2145     host->use_gpio_descriptors = true;
2146 
2147     /*
..........
..........
2239  err_spi_register:
2240     if (platform_info->enable_dma)
2241         pl022_dma_remove(pl022);
2242  err_no_irq:
2243     clk_disable_unprepare(pl022->clk);
2244  err_no_clk_en:
2245  err_no_clk:
2246  err_no_ioremap:
2247     amba_release_regions(adev);
2248  err_no_ioregion:
2249     spi_controller_put(host);
2250     return status;
2251 }

        SPI外设驱动遍布内核的drivers、sound的各个子目录之下,SPI只是一种总线,spi_driver的作用只是将SPI外设挂接在该总线上,因此在spi_driver的probe()函数中,将注册SPI外设本身所属设备驱动的类型。

        和platform_driver对应一个platform_device一样,spi_driver也对应一个spi_device,platform_device需要在BSP的板文件中添加板信息数据,而spi_device也同样需要。spi_device的板信息用spi_board_info结构体描述,该结构体记录着spi外设使用的主机控制器序号、片选序号、数据比特率、SPI传输模式(即CPOL、CPHA)等。诺基亚770上的两个SPI设备的板信息数据如下图所示,位于板文件的arch/arm/mach-omap1/board-nokia770.c中。

151 static struct spi_board_info nokia770_spi_board_info[] __initdata = {
152     [0] = {
153         .modalias       = "lcd_mipid",
154         .bus_num        = 2,
155         .chip_select    = 3,
156         .max_speed_hz   = 12000000,
157         .platform_data  = &nokia770_mipid_platform_data,
158         .swnode         = &nokia770_mipid_swnode,
159     },
160     [1] = {
161         .modalias       = "ads7846",
162         .bus_num        = 2,
163         .chip_select    = 0,
164         .max_speed_hz   = 2500000,
165         .swnode         = &nokia770_ads7846_swnode,
166     },
167 };

        在linux启动过程中,在机器的init_machine()函数中,会通过如下语句注册这些spi_board_info:

        这一点和启动时通过platform_add_device()添加platform_device非常相似。

        ARM Linux 3.x之后的内核在改为设备树,不再需要在arch/arm/mach-xxx中编码SPI的板级信息了。而倾向于在SPI控制器节点下填写子节点,如下图通过设备树添加SPI外设。

        

         

        

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/news/918778.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/918778.shtml
英文地址,请注明出处:http://en.pswp.cn/news/918778.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何生成.patch?

文章目录 ​​方法 1:使用 `git format-patch`(推荐)​ ​​步骤​​ ​方法 2:使用 `diff`命令(适用于非 Git 项目)​ ​​方法 3:使用 `git diff`(生成未提交的变更)​ ​方法 4:使用 `quilt`(适用于大量补丁管理) ​如何提交补丁给上游项目?​ ​总结​​ 在 L…

【计算机网络 | 第6篇】计算机体系结构与参考模型

文章目录计算机体系结构与参考模型分层思想🍂常见的3种模型(网络体系结构)🐦‍🔥TCP/IP体系结构各层包含的主要协议🥝每层所解决的主要问题🤔层次间的交互规则🥝实体与对等实体协议服…

Autoware Universe 感知模块详解 | 第一节 感性认识多源传感器标定

传感器与感知模块 在基于规则的自动驾驶系统中,感知模块,承担着理解车体周围环境信息的重要职责。它通过融合多种传感器数据,与定位模块共同为规划与控制模块提供准确、系统化的输入信息。正如人可以通过眼睛观察周围的环境(盲人也…

docker搭建java运行环境(java或者springboot)

目录1. 创建测试代码2. 编译打包3. 代码环境运行使用普通运行方式使用docker挂载项目(长期运行)1. 创建 Dockerfile2. 构建并后台运行使用docker swram实现零停机更新(推荐)1. 初始化swarm2. 创建 Dockerfile3. 使用Dockerfile 构…

哈希表特性与unordered_map/unordered_set实现分析

目录 一、哈希表核心特性总结 1.开放地址法 2.链地址法 二、unordered_map/unordered_set实现要点分析 1. 哈希表核心实现(HashTable2.h) (1) 哈希函数处理 (2) 链地址法实现 (3) 迭代器设计 (4) hashtable设计 2. unordered_map实现要点 3. unordered_map实现要点 一…

生产环境sudo配置详细指南

目录 1. 语法格式 2. 配置示例 3. 使用 /etc/sudoers.d/ 目录管理(推荐) 4. 基础配置:用户权限管理 4.1 ​​添加用户到sudo组 ​​4.2 验证用户组信息 5. sudo日志配置 5.1 修改sudoers配置文件 5.2 创建日志目录与权限设置 6. Su…

CSS动态视口单位:彻底解决移动端适配顽疾,告别布局跳动

你是否曾被这些问题困扰: 移动端页面滚动时,地址栏收缩导致页面高度突变,元素错位?100vh在移动设备上实际高度超出可视区域?全屏弹窗底部总被浏览器UI遮挡? 这些痛点背后都是传统视口单位的局限——无法响应…

【P27 4-8】OpenCV Python——Mat类、深拷贝(clone、copyTo、copy)、浅拷贝,原理讲解与示例代码

P27 4-8 1 Mat结构体2 深拷贝VS浅拷贝3 代码示例1 Mat结构体 2 深拷贝VS浅拷贝 只拷贝了头部,header,,但是data部分是共用的,速度非常快; 缺点,任意一个修改,另一个data跟着变,这就是…

容器运行时支持GPU,并使用1panel安装ollama

前言 安装Docker请看之前博文:Docker实战中1panel方式安装Docker。 安装 NVIDIA 容器工具包 https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/install-guide.html 安装 先决条件 阅读有关平台支持的部分。为您的 Linux 发行版安装…

高并发内存池 性能瓶颈分析与基数树优化(9)

文章目录前言一、性能瓶颈分析操作步骤及其环境配置分析性能瓶颈二、基数树优化单层基数树二层基数树三层基数树三、使用基数树来优化代码总结前言 到了最后一篇喽,嘻嘻!   终于是要告一段落了,接下来我们将学什么呢,再说吧&…

C#面试题及详细答案120道(01-10)-- 基础语法与数据类型

《前后端面试题》专栏集合了前后端各个知识模块的面试题,包括html,javascript,css,vue,react,java,Openlayers,leaflet,cesium,mapboxGL,threejs&…

机器翻译:回译与低资源优化详解

文章目录一、机器翻译的瓶颈二、回译(Back-Translation)2.1 什么是回译?2.2 为什么回译有效?2.3 回译的缺点与挑战三、低资源优化详解3.1 数据层面策略3.2 模型层面策略3.3 架构层面策略四、回译与低资源优化对比4.1 回译与低资源…

leetcode-python-344反转字符串

题目: 编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 s 的形式给出。 不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。 示例 1: 输入:s [“h”,“…

【Python】新手入门:什么是python字符编码?python标识符?什么是pyhon保留字?

🌈 个人主页:(时光煮雨) 🔥 高质量专栏:vulnhub靶机渗透测试 👈 希望得到您的订阅和支持~ 💡 创作高质量博文(平均质量分95+),分享更多关于网络安全、Python领域的优质内容!(希望得到您的关注~) 🌵文章目录🌵 前言 💡一、编码 📝二、标识符 🎯三、Py…

为什么要使用消息队列呢?

消息队列(Message Queue,MQ)在分布式系统中扮演着 ​异步通信枢纽​ 的角色,其核心价值在于解决系统间的解耦、流量削峰、异步处理等关键问题。以下是它的核心价值及典型应用场景:⚙️ 一、核心价值:解决什…

ROS机器人云实践案例博客建议和范文-AI版本

海报图AI图1AI图2zhangrelay的博客以技术深度、跨界思考和社会洞察为特色,内容兼具实用性与前瞻性,但部分观点存在争议,需结合具体主题辩证看待。以下从内容特色、技术深度、社会洞察、争议点四个维度展开分析:一、内容特色&#…

UE小:编辑器模式下「窗口/鼠标不在焦点」时仍保持高帧率

要在UE编辑器模式下「窗口/鼠标不在焦点」时仍保持高帧率,可按下面做法: 关闭编辑器的后台降频选项:在 Edit -> Editor Preferences -> General -> Performance 中取消勾选 “Use Less CPU when in Background”。

VS2022 + Qt 5.15.2+Occ开发环境搭建流程

Visual Studio 2022 Qt 5.15.2 图形处理开发环境搭建流程 1. 安装 Visual Studio 2022 下载安装程序:Visual Studio 官网选择工作负载: ✔️ “使用C的桌面开发”✔️ “通用Windows平台开发”(可选) 安装组件: ✔️…

多任务并发:进程管理的核心奥秘

多任务(并发):让系统具备同时处理多个任务的能力1. 多进程2. 多线程3. 进程间通信一、进程的基本概念1. 什么是进程?正在运行的程序,其运行过程中需要消耗内存和CPU。进程的特点:动态性:进程是程…

高效TypeScript开发:VSCode终极配置指南

⚙️ VSCode TypeScript 专属效率设置大全 (纯 settings.json 配置) // .vscode/settings.json {/* 🔍 引用与类型追踪 */"typescript.referencesCodeLens.enabled": true, // 显示引用计数(点击查看所有引用处)"typescript.implementationsCod…