0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

virtIO中有兩種方式控制前后端的notify

Linux閱碼場 ? 來源:未知 ? 作者:李倩 ? 2018-07-06 15:18 ? 次閱讀

本來這是在前端驅(qū)動(dòng)后期分析的,但是這部分內(nèi)容比較多,且分析了后端notify前端的機(jī)制,所以還是單獨(dú)拿出一節(jié)分析比較好!

還是拿網(wǎng)絡(luò)驅(qū)動(dòng)部分做案例,網(wǎng)絡(luò)驅(qū)動(dòng)部分有兩個(gè)隊(duì)列,(忽略控制隊(duì)列):接收隊(duì)列和發(fā)送隊(duì)列;每個(gè)隊(duì)列都對應(yīng)一個(gè)virtqueue,兩個(gè)隊(duì)列之間是互不影響的。

前后端利用virtqueue的方式如下圖所示:

這里再詳細(xì)的描述下,當(dāng)兩個(gè)queue都需要客戶機(jī)填充buffer,ReceiveQueue需要客戶機(jī) driver提前填充分配好的空buffer,然后記錄到availRing,并在恰當(dāng)?shù)臅r(shí)機(jī)通知后端,當(dāng)外部網(wǎng)絡(luò)有數(shù)據(jù)包到達(dá)時(shí),qemu后端就從availRing 中獲取一個(gè)buffer,然后填充數(shù)據(jù),完事后記錄buffer head index到usedRing.最后在恰當(dāng)?shù)臅r(shí)機(jī)通知客戶機(jī)(向客戶機(jī)注入中斷),客戶機(jī)接收到信號(hào)便知道有數(shù)據(jù)包到達(dá),這里只需要從usedRing 中獲取到index,然后取data數(shù)組的第i個(gè)元素即可。因?yàn)樵诳蛻魴C(jī)填充buffer的時(shí)候把邏輯buffer的指針保存在data數(shù)組中。

而SendQueue同樣需要客戶機(jī)去填充,只不過這里是當(dāng)客戶機(jī)需要發(fā)送數(shù)據(jù)包時(shí),把數(shù)據(jù)包構(gòu)造成邏輯buffer,然后填充到send Queue,并在恰當(dāng)?shù)臅r(shí)機(jī)通知后端,qemu后端收到通知就知道那個(gè)隊(duì)列有請求到達(dá),如果當(dāng)前沒有處理其他數(shù)據(jù)包就著手處理這個(gè)數(shù)據(jù)包。具體就同樣是從AvailRing中取出buffer head index,然后從描述符表中g(shù)et到buffer,這時(shí)就需要從buffer中copy數(shù)據(jù)了,因?yàn)橐褦?shù)據(jù)包從host發(fā)送出去,然后更新usedRing。最后同樣要在恰當(dāng)?shù)臅r(shí)機(jī)通知客戶機(jī)。注意這里客戶機(jī)同樣需要從usedRing 中g(shù)et index,但是這里主要是用于delay notify,因?yàn)閿?shù)據(jù)包由客戶機(jī)構(gòu)造,其占用的buffer并不能重復(fù)使用,只是每次有數(shù)據(jù)包就把其構(gòu)造成buffer而已。

以上便是基本的使用sendqueue和receive的原理,但是還有一點(diǎn)上面我沒有提到,就是通知的那個(gè)恰當(dāng)?shù)臅r(shí)機(jī),那么這個(gè)恰當(dāng)?shù)膶?shí)際究竟是什么時(shí)候呢??在virtIO中有兩種方式控制前后端的notify.

1、flags字段

2、事件觸發(fā)

1、在vring_avail和vring_used的flags字段,控制前后端的通信。vring_used中的flags用于通知driver端,當(dāng)add一個(gè)buffer的時(shí)候不用notify后端。而vring_avail中的flags用于通知qemu端,當(dāng)消費(fèi)一個(gè)buffer的時(shí)候不用interrupt 客戶機(jī)。

2、在virtIO中又加入了另一種機(jī)制,需要由driver和qemu自己判斷是否需要通知,也就是設(shè)置一個(gè)限額,當(dāng)一端添加buffer或者消費(fèi)buffer的數(shù)量達(dá)到指定數(shù)目,就觸發(fā)事件,從而發(fā)生notify或者interrupt。在有這種機(jī)制的情況下就忽略了前面所說的flags。

這里我們以receiveQueue為例,分析下前后端的delay notify機(jī)制。

在front driver端:

客戶機(jī)driver通過NAPI接收數(shù)據(jù)時(shí),會(huì)在可用buffer不足的時(shí)候調(diào)用函數(shù)添加,具體就是try_fill_recv:

至于添加的是哪種類型的buffer,我們這里并不關(guān)心,循環(huán)結(jié)束就調(diào)用virtqueue_kick(rq->vq)函數(shù),此時(shí)參數(shù)是接收隊(duì)列的virtqueue,

接下來就調(diào)用到了virtqueue_kick_prepare函數(shù),該函數(shù)判斷當(dāng)前應(yīng)不應(yīng)該通知后端。先看下函數(shù)的代碼:

這里面涉及到幾個(gè)變量,old是add_sg之前的avail.idx,而new是當(dāng)前的avail.idx,還有一個(gè)是vring_avail_event(&vq->vring),看具體的實(shí)現(xiàn):

可以看到這里是VRingUsed中的ring數(shù)組最后一項(xiàng)的值,該值在后端驅(qū)動(dòng)從virtqueue中pop一個(gè)elem之前設(shè)置成相應(yīng)隊(duì)列的下一個(gè)將要使用的index,即last_avail_index。

看下vring_need_event函數(shù):

前后端通過對比(__u16)(new_idx - event_idx - 1) < (__u16)(new_idx - old)來判斷是否需要notify后端,這在數(shù)據(jù)量比較大的時(shí)候顯得很實(shí)用。在初始狀態(tài)下,即在qemu一個(gè)buffer還沒有使用的情況下,event_idx必然是0,那么此時(shí)這里的判斷肯定為真,所以notify后端。后端收到通知就從virtqueue中pop buffer,同時(shí)在此之前需要設(shè)置event_idx,代碼見qemu virtio.c的virtqueue_pop函數(shù):

如果是初始化狀態(tài),即當(dāng)前是首次執(zhí)行virtqueue_pop函數(shù),last_avail_idx=0,在++后就成了1,然后設(shè)置此值到UsedRing.ring[]數(shù)組的最后一項(xiàng):

設(shè)置成功后就執(zhí)行pop之后的處理,寫入數(shù)據(jù)完成后,調(diào)用后端的virtio_notify(vdev, q->rx_vq)函數(shù)。該函數(shù)執(zhí)行前同樣需要判斷是否需要notify,具體函數(shù)為virtio_should_notify

該函數(shù)邏輯和前端driver總的判斷函數(shù)大致類似,但是還是有些不同,首先,如果隊(duì)列為空即當(dāng)前沒有可用buffer了,那么必然會(huì)notify前端;

接著判斷是否支持這樣事件觸發(fā)式的方式即VIRTIO_RING_F_EVENT_IDX,如果不支持,就通過flags字段來判斷。而如果支持,就通過事件觸發(fā)來通知。

這里有兩個(gè)條件:第一個(gè)是v = vq->signalled_used_valid和vring_need_event(vring_get_used_event(vq), new, old)

v = vq->signalled_used_valid在初始化的時(shí)候被設(shè)置成false,表示還沒有向前端做任何通知,而后再每次的virtio_should_notify中就會(huì)設(shè)置成true,并更新vq->signalled_used = vq->used_idx;所以如果是首次嘗試通知前端,則總能成功,否則需要判斷vring_need_event(vring_get_used_event(vq), new, old),該函數(shù)具體是根前面邏輯是一樣的,正如前面所說,這是第一次嘗試通知,所以總能成功。而vring_get_used_event(vq)是VRingAvail.ring[]數(shù)組的最后一項(xiàng)的值,該值在客戶機(jī)driver中被設(shè)置

在次回到linux driver中,就會(huì)從usedRing中取buffer,同樣每取出一個(gè)buffer就會(huì)設(shè)置used_event,代碼見virtio_ring.c的virtqueue_get_buf函數(shù),設(shè)置的值是vq->last_used_idx,記錄客戶機(jī)處理位置。

到目前為止,基本一次完整的交互已經(jīng)完成了,但是由于是初次交互,前后端的delay機(jī)制都沒起作用,判斷條件中使用到的event_idx已經(jīng)更新了,假如說首次add 8個(gè)buffer,然后通知了后端,并且后端使用了三個(gè)buffer并首次notify前端,此時(shí) 后端向第4個(gè)buffer中寫數(shù)據(jù),last_avail_idx=4(從0開始),那么used_event=4,此時(shí)前端發(fā)現(xiàn)可用buffer不足,需要添加,那么本次添加了5個(gè),即new=8+5=13,old=8,new-old=5,而此時(shí)new-used_event-1=8,條件不滿足,所以此時(shí)前端driver添加的buffer就不用notify后端。而話說這段時(shí)間后端又處理好了第二個(gè)數(shù)據(jù)包,使用了3個(gè)buffer。但不幸,前端還在處理第二個(gè)buffer,即last_used_idx=2,則used_event=2;對于后端來講new-old=3,new-used_event-1=3,條件不滿足,所以也不用通知。這樣delay notify的機(jī)制便顯示出效果了。筆者認(rèn)為這其實(shí)本質(zhì)上就是一場速度的對決,為了保證公平,即使一方處理快,也不能任意向另一端發(fā)送數(shù)據(jù),只能待對方處理的差不多了你才能發(fā),這樣發(fā)送一方可以歇歇,而接受一方也不會(huì)因?yàn)樘幚聿患岸鴣G棄,從而造成浪費(fèi)!哈哈,真是無規(guī)矩不成方圓!

具體通知方式:

前面已經(jīng)提到前端或者后端完成某個(gè)操作需要通知另一端的時(shí)候需要某種notify機(jī)制。這個(gè)notify機(jī)制是啥呢?這里分為兩個(gè)方向

1、guest->host

前面也已經(jīng)介紹,當(dāng)前端想通知后端時(shí),會(huì)調(diào)用virtqueue_kick函數(shù),繼而調(diào)用virtqueue_notify,對應(yīng)virtqueue結(jié)構(gòu)中的notify函數(shù),在初始化的時(shí)候被初始化成vp_notify(virtio_pci.c中),看下該函數(shù)的實(shí)現(xiàn)

可以看到這里僅僅是吧vq的index編號(hào)寫入到設(shè)備的IO地址空間中,實(shí)際上就是設(shè)備對應(yīng)的PCI配置空間中VIRTIO_PCI_QUEUE_NOTIFY位置。這里執(zhí)行IO操作會(huì)引發(fā)VM-exit,繼而退出到KVM->qemu中處理。看下后端驅(qū)動(dòng)的處理方式。在qemu代碼中virtio-pci.c文件中有函數(shù)virtio_ioport_write專門處理前端驅(qū)動(dòng)的IO寫操作,看

這里首先判斷隊(duì)列號(hào)是否在合法范圍內(nèi),然后調(diào)用virtio_queue_notify函數(shù),而最終會(huì)調(diào)用到virtio_queue_notify_vq,該函數(shù)其實(shí)僅僅調(diào)用了VirtQueue結(jié)構(gòu)中綁定的處理函數(shù)handle_output,該函數(shù)根據(jù)不同的設(shè)備有不同的實(shí)現(xiàn),比如網(wǎng)卡有網(wǎng)卡的實(shí)現(xiàn),而塊設(shè)備有塊設(shè)備的實(shí)現(xiàn)。以網(wǎng)卡為例看看創(chuàng)建VirtQueue的時(shí)候給綁定的是哪個(gè)函數(shù)。在virtio-net,c中的virtio_net_init,可以看到這里給接收隊(duì)列綁定的是virtio_net_handle_rx,而給發(fā)送隊(duì)列綁定的是virtio_net_handle_tx_bh或者virtio_net_handle_tx_timer。而對于塊設(shè)備則對應(yīng)的是virtio_blk_handle_output函數(shù)。

2、host->guest

host通知guest當(dāng)然是通過注入中斷的方式,首先調(diào)用的是virtio_notify,繼而調(diào)用virtio_notify_vector并把中斷向量作為參數(shù)傳遞進(jìn)去。這里就調(diào)用了設(shè)備關(guān)聯(lián)的notify函數(shù),具體實(shí)現(xiàn)為virtio_pci_notify函數(shù),常規(guī)中斷(非MSI)會(huì)調(diào)用qemu_set_irq,在8259a中斷控制器的情況下回調(diào)用kvm_pic_set_irq,然后到了kvm_set_irq,這里就會(huì)通過kvm_vm_ioctl和KVM交互,接口為KVM_IRQ_LINE,通知KVM對guest進(jìn)行中斷的注入。KVm里的kvm_vm_ioctl函數(shù)會(huì)對此調(diào)用進(jìn)行處理,具體就是調(diào)用kvm_vm_ioctl_irq_line,之后就調(diào)用kvm_set_irq函數(shù)進(jìn)行注入了。之后的流程參看中斷虛擬化部分。

共享內(nèi)存

前面提到,在guest通知host的時(shí)候,是把隊(duì)列的索引寫入到了配置空間的VIRTIO_PCI_QUEUE_NOTIFY字段,但是僅僅一個(gè)索引是怎么找到指定的隊(duì)列,且數(shù)據(jù)時(shí)什么時(shí)候到達(dá)后端的呢?這就用到了共享內(nèi)存。我們知道的是前后端的確通過共享內(nèi)存的方式傳遞數(shù)據(jù),但是數(shù)據(jù)的地址是怎么傳遞到后端的,這是個(gè)問題。本小節(jié)主要分析下這個(gè)問題。

為了便于理解我們先闡述其原理,然后結(jié)合代碼看具體的實(shí)現(xiàn)。實(shí)際上前后端在初始化后就共享了一段連續(xù)的內(nèi)存區(qū),注意這里是物理上連續(xù)的內(nèi)存區(qū)(GPA),由客戶機(jī)內(nèi)部初始化隊(duì)列的時(shí)候分配,所以這里就是需要和伙伴系統(tǒng)交互。這段內(nèi)存區(qū)的結(jié)構(gòu)如下圖所示

對于vring了解的朋友應(yīng)該很熟悉這個(gè)結(jié)構(gòu),沒錯(cuò),這就是通過vring管理的結(jié)構(gòu),換句話說,前后端直接共享的其實(shí)是vring。也就是說針對同一個(gè)隊(duì)列(比如網(wǎng)卡的發(fā)送隊(duì)列),前后端已經(jīng)形成一種協(xié)議,通過這段內(nèi)存區(qū)交換數(shù)據(jù)的地址信息。在把數(shù)據(jù)的地址信息寫入到desc數(shù)組中后,僅僅需要通知另一端,另一端就知道從哪里取出數(shù)據(jù)。當(dāng)然還是通過desc數(shù)組。具體數(shù)據(jù)的傳遞過程參見其他小結(jié)。因此在初始化階段,前端分配好內(nèi)存區(qū),并初始化好前端的vring后,就把內(nèi)存區(qū)的信息傳遞到后端,后端也利用這個(gè)內(nèi)存區(qū)的信息初始化隊(duì)列相關(guān)的vring。這樣vring就在前后端保持了一致。原理就是如此,下面看具體初始化代碼:

前端:

virtnet_probe->init_vqs->virtnet_find_vqs->vi->vdev->config->find_vqs(vp_find_vqs)->vp_try_to_find_vqs->setup_vq,在setup_vp中通過IO端口和后端交互完成前面我們說的協(xié)議??聪略摵瘮?shù)

注意協(xié)商的步驟,首先通過VIRTIO_PCI_QUEUE_SEL標(biāo)記本次操作的隊(duì)列索引,因?yàn)槊總€(gè)隊(duì)列都有自己的vring,即需要自己的共享內(nèi)存區(qū)。然后檢查隊(duì)列是否可用,這是通過VIRTIO_PCI_QUEUE_NUM,如果返回的結(jié)果是0,則表示沒有隊(duì)列可用,則返回錯(cuò)誤。接著通過VIRTIO_PCI_QUEUE_PFN檢查是否已經(jīng)激活,如果已經(jīng)激活,同樣返回錯(cuò)誤。這些檢查通過就可以予以初始化了,具體先分配一個(gè)中間結(jié)構(gòu)virtio_pci_vq_info,這不是重點(diǎn),后面通過alloc_pages_exact向伙伴系統(tǒng)分配了不小于size的連續(xù)物理內(nèi)存,等會(huì)我們再說size的問題,然后把這塊物理頁框號(hào)(GPA>>VIRTIO_PCI_QUEUE_ADDR_SHIFT)寫入到VIRTIO_PCI_QUEUE_PFN,這樣后端就會(huì)得到這塊內(nèi)存區(qū)的信息。然后我們先看下前端利用這塊內(nèi)存區(qū)做了什么?看下面的vring_new_virtqueue函數(shù),該函數(shù)中調(diào)用vring_init來初始化vring

這個(gè)函數(shù)正好體現(xiàn)了我們前面那個(gè)結(jié)構(gòu)圖。這樣前端vring就初始化好了。對隊(duì)列填充數(shù)據(jù)時(shí)就是根據(jù)這個(gè)vring填充信息。

后端(qemu端)

主要操作都在virtio_ioport_write中,我們只關(guān)注三個(gè)case

可以看到在VIRTIO_PCI_QUEUE_SEL時(shí)候,僅僅是標(biāo)記了下設(shè)備中的queue_sel表示當(dāng)前操作的隊(duì)列索引。下面在通過VIRTIO_PCI_QUEUE_PFN傳遞地址的時(shí)候,調(diào)用virtio_queue_set_addr設(shè)置后端相關(guān)隊(duì)列的vring該函數(shù)實(shí)現(xiàn)較簡單

看到這里有么有很面熟,沒錯(cuò),這個(gè)函數(shù)和前端初始化vring的函數(shù)很是類似,這樣前后端的vring就同步起來了……

而在guest通知后端的時(shí)候,通過VIRTIO_PCI_QUEUE_NOTIFY接口,該函數(shù)調(diào)用了virtio_queue_notify_vq繼而調(diào)用 vq->handle_output……就這樣,后端就得到通知著手處理了!

后記:

到此,virtIO部分已經(jīng)分析的差不多了,分析期間真實(shí)感覺到了自己知識(shí)的匱乏,其間多次向開發(fā)者求助,并均得到認(rèn)真回復(fù),在此在此感謝這些優(yōu)秀的開發(fā)者。有時(shí)候看內(nèi)核代碼就感覺工程師和硬件在干仗,站在工程師的角度,需要盡其所能榨取硬件的性能。大到實(shí)現(xiàn)算法的優(yōu)化,小到分析程序執(zhí)行流的概率,從而針對編譯做優(yōu)化。站在硬件的角度,你處理不好,我就不給你工作。而從這方面,工程師自然是完勝,并且還在不遺余力的朝著勝利的另一個(gè)境界挺近,即征服硬件!哈哈,不過誰都知道,這是一場沒有勝負(fù)的戰(zhàn)爭,工程師自然優(yōu)秀,但是,因?yàn)楣こ處焹?nèi)部的競爭,這樣戰(zhàn)斗將永無休止??!唉,瞎扯淡了,各位朋友,下篇文章見!

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報(bào)投訴
  • 信號(hào)
    +關(guān)注

    關(guān)注

    11

    文章

    2791

    瀏覽量

    76764
  • 網(wǎng)絡(luò)
    +關(guān)注

    關(guān)注

    14

    文章

    7565

    瀏覽量

    88788
  • 數(shù)據(jù)包
    +關(guān)注

    關(guān)注

    0

    文章

    261

    瀏覽量

    24393

原文標(biāo)題:virtIO前后端notify機(jī)制詳解

文章出處:【微信號(hào):LinuxDev,微信公眾號(hào):Linux閱碼場】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    virtio I/O通信流程及設(shè)備框架的實(shí)現(xiàn)

    virtio 是一通用的半虛擬化的 I/O 通信協(xié)議,提供了一套前后端 I/O 通信的的框架協(xié)議和編程接口。根據(jù)該協(xié)議實(shí)現(xiàn)的設(shè)備通過前后端的配合,相比全模擬設(shè)備可以大幅減少陷入陷出以
    的頭像 發(fā)表于 03-10 13:37 ?6534次閱讀

    兩種采樣方式

    兩種采樣方式.....................................
    發(fā)表于 08-08 15:04

    請問小車轉(zhuǎn)向兩種方式有什么優(yōu)缺點(diǎn)?

    我知道的小車轉(zhuǎn)向常見的有兩種方式,一是通過舵機(jī)控制轉(zhuǎn)向,另一是通過控制
    發(fā)表于 05-21 02:37

    jqgrid前后端交互實(shí)例分享

    [溫習(xí)]jqgrid 前后端交互實(shí)例
    發(fā)表于 06-10 17:30

    SQL語言的兩種使用方式

    SQL語言的兩種使用方式在終端交互方式下使用,稱為交互式SQL嵌入在高級(jí)語言的程序中使用,稱為嵌入式SQL―高級(jí)語言如C、Java等,稱為宿主語言嵌入式SQL的實(shí)現(xiàn)方式源程序(用主語言
    發(fā)表于 12-20 06:51

    電力操作電源兩種控制方式的比較

    電力操作電源兩種控制方式的比較   1引言 開關(guān)電源是一個(gè)閉環(huán)的自動(dòng)控制系統(tǒng),開關(guān)電源的控制環(huán)節(jié)的設(shè)計(jì)是其設(shè)計(jì)
    發(fā)表于 07-10 08:43 ?1395次閱讀
    電力操作電源<b class='flag-5'>兩種</b><b class='flag-5'>控制</b><b class='flag-5'>方式</b>的比較

    逆變器的兩種電流型控制方式

    逆變器的兩種電流型控制方式 摘要:研究分析了逆變器的兩種雙環(huán)瞬時(shí)反饋控制方式
    發(fā)表于 07-10 11:21 ?4004次閱讀
    逆變器的<b class='flag-5'>兩種</b>電流型<b class='flag-5'>控制</b><b class='flag-5'>方式</b>

    Wincc如何與PLC進(jìn)行通訊兩種常用的方式介紹

    西門子WINCC與SiemensPLC通訊連接有多種方式,下面介紹兩種常用的通訊方式。
    的頭像 發(fā)表于 02-17 09:27 ?3w次閱讀
    Wincc如何與PLC進(jìn)行通訊<b class='flag-5'>兩種</b>常用的<b class='flag-5'>方式</b>介紹

    單片機(jī)常用的兩種延時(shí)控制方式

    單片機(jī)中常用的延時(shí)控制方式兩種。一是采用編程的方式達(dá)到延時(shí)的目的,另一方法則是通過單片機(jī)中
    發(fā)表于 07-17 10:22 ?6053次閱讀
    單片機(jī)常用的<b class='flag-5'>兩種</b>延時(shí)<b class='flag-5'>控制</b><b class='flag-5'>方式</b>

    MATLAB/simulink中兩種實(shí)現(xiàn)建模方式的優(yōu)勢

    導(dǎo)讀:本期文章主要介紹在MATLAB/simulink中建模時(shí)的兩種不同實(shí)現(xiàn)方式,一是直接用現(xiàn)成的文件庫中的模塊進(jìn)行搭建,一是用Sfunction代碼實(shí)現(xiàn)。接下來以電壓型磁鏈觀測器
    的頭像 發(fā)表于 09-15 10:10 ?5052次閱讀

    詳解PMSM中常用的兩種坐標(biāo)變換

    期介紹了Clarke的Park變化的基本原理,但是經(jīng)過這兩種變換后會(huì)存在兩種系數(shù),相信大家都很迷惑,這是什么原因? 主要原因是存在兩種遵循的方式
    的頭像 發(fā)表于 01-19 15:52 ?2473次閱讀
    詳解PMSM中常用的<b class='flag-5'>兩種</b>坐標(biāo)變換

    星三角的兩種控制方式

    今天給大家展示一下星三角的兩種控制控制方式的電路圖,PLC 控制方式以三菱PLC 為例
    發(fā)表于 05-05 15:53 ?664次閱讀
    星三角的<b class='flag-5'>兩種</b><b class='flag-5'>控制</b><b class='flag-5'>方式</b>

    springboot前后端交互流程

    Spring Boot 是一個(gè)用于構(gòu)建 Java 企業(yè)級(jí)應(yīng)用程序的開源框架,它提供了一簡化的開發(fā)方式,使得開發(fā)人員可以更加便捷地創(chuàng)建獨(dú)立的、可執(zhí)行的 Spring 應(yīng)用程序。在使用 Spring
    的頭像 發(fā)表于 11-22 16:00 ?2127次閱讀

    Linux應(yīng)用層控制外設(shè)的兩種不同的方式

    眾所周知,linux下一切皆文件,那么應(yīng)用層如何控制硬件層,同樣是通過 文件I/O的方式來實(shí)現(xiàn)的,那么應(yīng)用層控制硬件層通常有兩種方式。
    的頭像 發(fā)表于 10-05 19:03 ?516次閱讀
    Linux應(yīng)用層<b class='flag-5'>控制</b>外設(shè)的<b class='flag-5'>兩種</b>不同的<b class='flag-5'>方式</b>

    eBPF技術(shù)實(shí)踐之virtio-net網(wǎng)卡隊(duì)列可觀測

    時(shí),這一路徑難以進(jìn)行觀測。一些復(fù)雜的網(wǎng)絡(luò)抖動(dòng)問題很可能是由于網(wǎng)卡隊(duì)列不正常工作引起的。為了解決這類問題,我們基于eBPF技術(shù)擴(kuò)展了網(wǎng)卡隊(duì)列的可觀測能力,使得virtio網(wǎng)卡前后端的定界問題不再困擾。 virtio-net
    的頭像 發(fā)表于 11-14 11:18 ?207次閱讀
    eBPF技術(shù)實(shí)踐之<b class='flag-5'>virtio</b>-net網(wǎng)卡隊(duì)列可觀測