網(wǎng)站是先解析后備案嗎免費投放廣告平臺
自動駕駛的關鍵路徑如下,傳感器的數(shù)據(jù)發(fā)送給感知模塊;感知模塊根據(jù)傳感器數(shù)據(jù)來確定車輛所處的環(huán)境,比如前方有沒有障礙物,是不是和車道線保持著適當?shù)木嚯x等;感知處理之后的數(shù)據(jù)傳遞給規(guī)控模塊,規(guī)控根據(jù)車輛當前所處的環(huán)境來規(guī)劃車輛的路線和加減速等;最后規(guī)控的結果要發(fā)送到底盤/動力來做真正的執(zhí)行。
在自動駕駛的關鍵路徑中,對確定性要求是非常高的,因為車輛是一個安全產品,一旦某個環(huán)節(jié)消耗的時間不符合確定性的要求,那么會造成比較大的影響。比如車輛前方有行人,那么車輛就需要及時剎停,不可延誤。
確定性,考慮的是最惡劣的情況,假如規(guī)控模塊要求,每次處理規(guī)控任務的處理時間不能超過2ms,那么就是要求無論系統(tǒng)運行在什么環(huán)境下,當前系統(tǒng)的負載是怎么樣的,規(guī)控任務的處理時間都不能超過2ms。也就是說如果車輛連續(xù)運行了一周,假如規(guī)控運行的次數(shù)是1000萬次,那么也不允許有一次超過2ms的。
1獲取線程實際消耗的cpu時間
如下代碼,如果要獲取planning函數(shù)執(zhí)行消耗的時間。在相當長的一段時間,都是直接獲取CLOCK_BOOTTIME這種clock id的時間,這種時間都是墻上時間。在很多時候用這種時間來表示任務消耗的也是沒有問題的,但是如果進程中發(fā)生了睡眠,發(fā)生了阻塞,使用這種時間就不準確了,這種時間不能表示任務實際消耗的cpu時間。
通過函數(shù)pthread_getcpuclockid獲取的clock,表示cpu時間,也就是線程實際占用的cpu的時間。
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
#include <pthread.h>void planning() {int counter = 0;for(int i = 0; i < 10000; i++) {counter++;}for (int i = 0; i < 5; i++) {sleep(1);}
}int main() {clockid_t clock_id;struct timespec start_time1;struct timespec end_time1;struct timespec start_time2;struct timespec end_time2;pthread_getcpuclockid(pthread_self(), &clock_id);clock_gettime(clock_id, &start_time1);clock_gettime(CLOCK_BOOTTIME, &start_time2);planning();clock_gettime(clock_id, &end_time1);clock_gettime(CLOCK_BOOTTIME, &end_time2);printf("real time:%ldns\n", (end_time1.tv_sec * 1000 * 1000 * 1000 + end_time1.tv_nsec) - (start_time1.tv_sec * 1000 * 1000 * 1000 + start_time1.tv_nsec));printf("wall time:%ldns\n", (end_time2.tv_sec * 1000 * 1000 * 1000 + end_time2.tv_nsec) - (start_time2.tv_sec * 1000 * 1000 * 1000 + start_time2.tv_nsec));return 0;
}
運行結果如下,cpu clock id顯示的時間是線程實際消耗的時間,是514微秒左右;wall time是5秒。
2獲取線程調度次數(shù)
在linux中進程的status文件中顯示了線程調度的次數(shù)。最后兩行表示線程調度次數(shù),voluntary_ctxt_switches表示線程主動調度的次數(shù),比如當線程睡眠,IO阻塞時,會觸發(fā)線程調度,這時的調度就是自愿調度;nonvoluntary_ctxt_switches表示線程非自愿調度的次數(shù),比如當線程的時間片用完,被調度器強制調度,這種情況就是非自愿調度。
可以通過該文件獲取調度次數(shù),可以在調用planning之前獲取線程的調度次數(shù),返回之后再次獲取調度次數(shù),兩者的調度次數(shù)差就基本上能表示在planning執(zhí)行過程中發(fā)生的調度次數(shù)。這里之所以說是基本上,而不是絕對,因為在獲取調度次數(shù)到planning真正被執(zhí)行,以及planning返回到獲取調度次數(shù)之間,也有可能發(fā)生調度。
root@wangyanlong-virtual-machine:/home/wangyanlong/test# cat /proc/12744/status
Name:?? a.out
Umask:? 0022
State:? S (sleeping)
Tgid:?? 12744
Ngid:?? 0
Pid:??? 12744
PPid:?? 2374
TracerPid:????? 0
Uid:??? 0?????? 0?????? 0?????? 0
Gid:??? 0?????? 0?????? 0?????? 0
FDSize: 256
Groups: 0 999
NStgid: 12744
NSpid:? 12744
NSpgid: 12744
NSsid:? 2294
VmPeak:???? 2712 kB
VmSize:???? 2644 kB
VmLck:???????? 0 kB
VmPin:???????? 0 kB
VmHWM:????? 1024 kB
VmRSS:????? 1024 kB
RssAnon:?????????????? 0 kB
RssFile:??????????? 1024 kB
RssShmem:????????????? 0 kB
VmData:?????? 92 kB
VmStk:?????? 132 kB
VmExe:???????? 4 kB
VmLib:????? 1796 kB
VmPTE:??????? 36 kB
VmSwap:??????? 0 kB
HugetlbPages:????????? 0 kB
CoreDumping:??? 0
THP_enabled:??? 1
Threads:??????? 1
SigQ:?? 0/15188
SigPnd: 0000000000000000
ShdPnd: 0000000000000000
SigBlk: 0000000000000000
SigIgn: 0000000000000000
SigCgt: 0000000000000000
CapInh: 0000000000000000
CapPrm: 000001ffffffffff
CapEff: 000001ffffffffff
CapBnd: 000001ffffffffff
CapAmb: 0000000000000000
NoNewPrivs:???? 0
Seccomp:??????? 0
Seccomp_filters:??????? 0
Speculation_Store_Bypass:?????? thread vulnerable
SpeculationIndirectBranch:????? conditional enabled
Cpus_allowed:?? ffffffff,ffffffff,ffffffff,ffffffff
Cpus_allowed_list:????? 0-127
Mems_allowed:?? 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000001
Mems_allowed_list:????? 0
voluntary_ctxt_switches:??????? 42
nonvoluntary_ctxt_switches:???? 0
root@wangyanlong-virtual-machine:/home/wangyanlong/test#
有時候,當我們統(tǒng)計出來wall time比較大的時候,就說這個任務消耗的時間多,這樣的說服力是比較弱的。這個時候我們就需要獲取線程實際消耗的時間結合調度次數(shù),來進行分析。
(1)如果real time和wall time都比較大,那么說明就是任務執(zhí)行實際消耗的時間長,需要對任務本身的邏輯進行優(yōu)化。
(2)如果real time比較小,wall time比較大,那么可能有兩種情況
①在任務執(zhí)行期間發(fā)生了調度,這個時候就需要通過綁核或者提高線程的優(yōu)先級等方式來保證在任務執(zhí)行期間不會發(fā)生調度。
②任務中存在阻塞的操作,等待一個條件滿足,比如等待一個IO條件,等待一個mutex等,要結合代碼進一步分析。