Wakeup Source框架設計與實現

Wakeup Source 為系統組件提供了投票機制,以便低功耗子系統判斷當前是否可以進入休眠。

Wakeup Source(后簡稱:WS) 模塊可與內核中的其他模塊或者上層服務交互,并最終體現在對睡眠鎖的控制上。

通用低功耗軟件棧.png

1. 模塊功能說明

WS的處理邏輯基本上是圍繞?combined_event_count?變量展開的,這個變量高16位記錄系統已處理的所有的喚醒事件總數,低16位記錄在處理中的喚醒事件總數。每次持鎖時,處理中的喚醒事件記錄(低16位)會加1;每次釋放鎖時,處理中的喚醒事件記錄(低16位)會減1,同時已處理的喚醒事件記錄(高16位)會加1。

對于每次系統能否進入休眠,通過判斷是否有正在處理中的喚醒事件(低16位)來決定。該模塊實現主要的功能:

  • 持鎖和釋放鎖

  • 注冊和注銷鎖

  • 查詢激活狀態鎖個數

2. 主要數據結構

2.1 wakeup_source 結構體

@include/linux/pm_wakeup.h
/*** struct wakeup_source - Representation of wakeup sources** @name: Name of the wakeup source* @id: Wakeup source id* @entry: Wakeup source list entry* @lock: Wakeup source lock* @wakeirq: Optional device specific wakeirq* @timer: Wakeup timer list* @timer_expires: Wakeup timer expiration* @total_time: Total time this wakeup source has been active.* @max_time: Maximum time this wakeup source has been continuously active.* @last_time: Monotonic clock when the wakeup source's was touched last time.* @prevent_sleep_time: Total time this source has been preventing autosleep.* @event_count: Number of signaled wakeup events.* @active_count: Number of times the wakeup source was activated.* @relax_count: Number of times the wakeup source was deactivated.* @expire_count: Number of times the wakeup source's timeout has expired.* @wakeup_count: Number of times the wakeup source might abort suspend.* @dev: Struct device for sysfs statistics about the wakeup source.* @active: Status of the wakeup source.* @autosleep_enabled: Autosleep is active, so update @prevent_sleep_time.*/
struct wakeup_source {const char 		*name; //ws 名稱int			id;  //WS系統給本ws分配的IDstruct list_head	entry; //用于把本ws節點維護到WS系統的全局鏈表中spinlock_t		lock;struct wake_irq		*wakeirq; //與本ws節點綁定的喚醒中斷相關的結構體,用戶可自行把指定中斷與ws綁定struct timer_list	timer; //超時鎖使用,如定義本ws為超時鎖,指定在一定時間后釋放鎖unsigned long		timer_expires;//超時鎖超時時間ktime_t total_time; //本ws激活的總時長ktime_t max_time;   //在ws激活歷史中,最長一次的激活時間ktime_t last_time;  //最后一次訪問本ws的時間ktime_t start_prevent_time; //本ws最近一次阻止autosleep進入休眠的時間戳ktime_t prevent_sleep_time; //因本ws導致的阻止autosleep進入休眠的總時間unsigned long		event_count; //事件次數,本ws被持鎖(不考慮是否已持鎖),則加1并作記錄unsigned long		active_count;//激活次數,本ws僅在首次持鎖(激活)時加1(已持鎖則不加1,鎖釋放后再次持鎖則加1)unsigned long		relax_count; //釋放次數,與 active_count 相對unsigned long		expire_count; //超時鎖超時次數unsigned long		wakeup_count; //與event_count一樣,但受events_check_enabled 使能標記控制struct device		*dev; //與本ws綁定的設備bool			active:1; //標記是否處于激活狀態bool			autosleep_enabled:1; //標記是否使能autosleep
};

2.2 核心變量

2.2.1 combined_event_count 變量

static atomic_t combined_event_count = ATOMIC_INIT(0);該變量是1個組合計數變量,高16位記錄喚醒事件的總數,低16位記錄正在處理中的喚醒事件的總數。系統根據低16位(正在處理中的喚醒事件)來判斷是否可以進入休眠。

2.2.2 wakeup_sources 變量

static LIST_HEAD(wakeup_sources);所有通過調用?wakeup_source_register()注冊的ws全部維護在此鏈表中,以便系統進行維護。

2.3 主要函數分析

Wakeup Source 對外提供的主要接口:

  • wakeup_source_register()wakeup_source_unregister()分別用于注冊與注銷一個ws

  • __pm_stay_awake()__pm_relax(),針對ws類型對象提供持鎖與釋放鎖接口

  • (device_set_wakeup_capable()+device_wakeup_enable()/device_wakeup_disable()/device_set_wakeup_enable())/device_init_wakeup()給設備配置是否支持喚醒以及注冊/注銷ws的接口

  • pm_stay_awake()pm_relax(),針對device類型對象提供持鎖與釋放鎖接口

2.3.1 wakeup_source_register()/wakeup_source_unregister() 接口

wakeup_source_register()函數為dev設備創建ws,并將創建的ws添加到全局鏈表wakeup_sources中,方便后續維護,并在sysfs系統中創建節點/sys/class/wakeup/wakeup<id>/,便于獲取ws相關信息。

@drivers/base/power/wakeup.c
/*** wakeup_source_register - Create wakeup source and add it to the list.* @dev: Device this wakeup source is associated with (or NULL if virtual).* @name: Name of the wakeup source to register.*/
struct wakeup_source *wakeup_source_register(struct device *dev,const char *name)
{struct wakeup_source *ws;int ret;ws = wakeup_source_create(name); //分配內存,設置ws的name和idif (ws) {if (!dev || device_is_registered(dev)) {//在sysfs下為該ws創建dev, /sys/class/wakeup/wakeup<id>/ret = wakeup_source_sysfs_add(dev, ws);if (ret) {wakeup_source_free(ws);return NULL;}}wakeup_source_add(ws); //設置超時回調函數并將ws添加到wakeup_sources鏈表}return ws;
}
@drivers/base/power/wakeup_stats.c
static struct device *wakeup_source_device_create(struct device *parent,struct wakeup_source *ws)
{struct device *dev = NULL;int retval = -ENODEV;dev = kzalloc(sizeof(*dev), GFP_KERNEL);device_initialize(dev);dev->devt = MKDEV(0, 0);dev->class = wakeup_class; //ws dev掛于wakeup類dev->parent = parent;dev->groups = wakeup_source_groups;dev->release = device_create_release;dev_set_drvdata(dev, ws);device_set_pm_not_required(dev);retval = kobject_set_name(&dev->kobj, "wakeup%d", ws->id);retval = device_add(dev);return dev;
}
//ws dev存在的屬性: /sys/class/wakeup/wakeup<id>/
static struct attribute *wakeup_source_attrs[] = {&dev_attr_name.attr, //RO, ws 名稱&dev_attr_active_count.attr, //RO, 激活次數&dev_attr_event_count.attr, //RO, 持鎖次數&dev_attr_wakeup_count.attr, //RO, 同event_count,但受events_check_enabled使能標記&dev_attr_expire_count.attr, //RO, 超時次數&dev_attr_active_time_ms.attr, //RO, 如當前處于激活狀態,顯示已激活時間&dev_attr_total_time_ms.attr, //RO, 總激活時間&dev_attr_max_time_ms.attr, //RO, 最長激活時間&dev_attr_last_change_ms.attr, //RO, 最近一次激活時的時間戳&dev_attr_prevent_suspend_time_ms.attr, //RO, 阻止autosleep進入休眠的總時間NULL,
};
ATTRIBUTE_GROUPS(wakeup_source);

wakeup_source_unregister()?接口刪除了已注冊的ws,移除了sysfs系統中的節點并釋放占用的系統資源。

@drivers/base/power/wakeup.c
void wakeup_source_unregister(struct wakeup_source *ws)
{if (ws) {wakeup_source_remove(ws); //從wakeup_sources隊列移除并刪除其定時器if (ws->dev)wakeup_source_sysfs_remove(ws);//移除該ws在sysfs系統中的信息wakeup_source_destroy(ws);}
}
void wakeup_source_destroy(struct wakeup_source *ws)
{__pm_relax(ws); //釋放該wswakeup_source_record(ws);//如果該ws被持鎖過,則將其記錄疊加到deleted_ws這個ws上wakeup_source_free(ws);//釋放內存資源
}static struct wakeup_source deleted_ws = {//用于保存已移除ws的記錄.name = "deleted",.lock =  __SPIN_LOCK_UNLOCKED(deleted_ws.lock),
};static void wakeup_source_record(struct wakeup_source *ws)
{unsigned long flags;spin_lock_irqsave(&deleted_ws.lock, flags);if (ws->event_count) {//如果該ws被持鎖過,則將記錄都疊加到deleted_ws這個ws上deleted_ws.total_time =ktime_add(deleted_ws.total_time, ws->total_time);deleted_ws.prevent_sleep_time =ktime_add(deleted_ws.prevent_sleep_time,ws->prevent_sleep_time);deleted_ws.max_time =ktime_compare(deleted_ws.max_time, ws->max_time) > 0 ?deleted_ws.max_time : ws->max_time;deleted_ws.event_count += ws->event_count;deleted_ws.active_count += ws->active_count;deleted_ws.relax_count += ws->relax_count;deleted_ws.expire_count += ws->expire_count;deleted_ws.wakeup_count += ws->wakeup_count;}spin_unlock_irqrestore(&deleted_ws.lock, flags);
}

2.3.2 __pm_stay_awake()/__pm_relax() 接口

__pm_stay_awake()?用于上鎖ws來阻止系統休眠。

@drivers/base/power/wakeup.c
void __pm_stay_awake(struct wakeup_source *ws)
{unsigned long flags;if (!ws)return;spin_lock_irqsave(&ws->lock, flags);wakeup_source_report_event(ws, false);//紀錄該ws的信息del_timer(&ws->timer);ws->timer_expires = 0;spin_unlock_irqrestore(&ws->lock, flags);
}
static void wakeup_source_report_event(struct wakeup_source *ws, bool hard)
{ws->event_count++;  //持鎖次數加1/* This is racy, but the counter is approximate anyway. */if (events_check_enabled)ws->wakeup_count++;if (!ws->active) //ws還未激活情況下,激活wswakeup_source_activate(ws);if (hard)  //如果需要,可以強制阻止系統休眠pm_system_wakeup();
}
static void wakeup_source_activate(struct wakeup_source *ws)
{unsigned int cec;if (WARN_ONCE(wakeup_source_not_registered(ws),"unregistered wakeup source\n"))return;ws->active = true;ws->active_count++;  //激活次數加1ws->last_time = ktime_get(); //紀錄最后操作該鎖的時間戳if (ws->autosleep_enabled) //如果autosleep已使能,則記錄該ws阻止休眠時時間戳ws->start_prevent_time = ws->last_time;/* Increment the counter of events in progress. */cec = atomic_inc_return(&combined_event_count); //combined_event_count低16位加1trace_wakeup_source_activate(ws->name, cec);
}

__pm_relax()?用于將持有的睡眠鎖釋放掉,并在檢測到combined_event_count低16位為0(表示當前沒有在處理的ws)時會觸發wakeup_count_wait_queue等待隊列運行,如果工作隊列滿足睡眠條件,則繼續進入睡眠流程,該機制是通過pm_get_wakeup_count()接口與autosleep配合使用的

@drivers/base/power/wakeup.c
void __pm_relax(struct wakeup_source *ws)
{unsigned long flags;if (!ws)return;spin_lock_irqsave(&ws->lock, flags);if (ws->active) //如果ws已激活,則去激活該wswakeup_source_deactivate(ws);spin_unlock_irqrestore(&ws->lock, flags);
}static void wakeup_source_deactivate(struct wakeup_source *ws)
{unsigned int cnt, inpr, cec;ktime_t duration;ktime_t now;ws->relax_count++; //釋放次數加1/** __pm_relax() may be called directly or from a timer function.* If it is called directly right after the timer function has been* started, but before the timer function calls __pm_relax(), it is* possible that __pm_stay_awake() will be called in the meantime and* will set ws->active.  Then, ws->active may be cleared immediately* by the __pm_relax() called from the timer function, but in such a* case ws->relax_count will be different from ws->active_count.*/if (ws->relax_count != ws->active_count) {ws->relax_count--; //未解決定時鎖與主動調用釋放鎖并發操作時出現沖突做的處理return;}ws->active = false;now = ktime_get();duration = ktime_sub(now, ws->last_time);ws->total_time = ktime_add(ws->total_time, duration); //疊加總的持鎖時間if (ktime_to_ns(duration) > ktime_to_ns(ws->max_time))ws->max_time = duration;  //更新最長持鎖時間ws->last_time = now; //紀錄最后操作該鎖的時間戳del_timer(&ws->timer);ws->timer_expires = 0;if (ws->autosleep_enabled)//如果autosleep已使能,更新該ws阻止系統休眠的時長update_prevent_sleep_time(ws, now);/** Increment the counter of registered wakeup events and decrement the* couter of wakeup events in progress simultaneously.*/cec = atomic_add_return(MAX_IN_PROGRESS, &combined_event_count);//combined_event_count高16位加1trace_wakeup_source_deactivate(ws->name, cec);split_counters(&cnt, &inpr);//拆分出combined_event_count高16位和低16位if (!inpr && waitqueue_active(&wakeup_count_wait_queue))//如果該ws已經無正在處理的喚醒事件,則通知PM corewake_up(&wakeup_count_wait_queue);
}

注:同個ws連續使用多次__pm_stay_awake()__pm_relax()只會增加/減少一次combined_event_count低16位(表示正在處理中的事件總數),只要__pm_relax()被調用就會釋放鎖。

2.3.3?pm_get_wakeup_count()接口

該函數主要是獲取已處理的wakeup event數量(combined_event_count高16位)與正在處理的wakeup event數量是否為0(combined_event_count低16位)。

bool pm_get_wakeup_count(unsigned int *count, bool block)
{unsigned int cnt, inpr;if (block) { DEFINE_WAIT(wait); //定義名為wait的等待隊列入口for (;;) {prepare_to_wait(&wakeup_count_wait_queue, &wait,TASK_INTERRUPTIBLE); //準備 wakeup_count_wait_queue 等待隊列split_counters(&cnt, &inpr);if (inpr == 0 || signal_pending(current))break;pm_print_active_wakeup_sources();schedule(); //調度到其他線程}//__pm_relax() 里wake_up(&wakeup_count_wait_queue);會觸發調度到此處finish_wait(&wakeup_count_wait_queue, &wait);}split_counters(&cnt, &inpr);*count = cnt;return !inpr; //返回0表示有待處理事件,返回1表示無待處理事件
}

1.如果入參block為0,則僅僅對入參count賦值當前已處理的wakeup event總數,并返回當前是否有待處理wakeup event(返回0表示有待處理事件,返回1表示無待處理事件)。2.如果入參block為1,則需要一直等到待處理事件為0(combined_event_count低16位為0)或者當前掛起進程有事件需要處理時才退出。該處理分支的wait等待隊列會在__pm_relax()滿足睡眠條件時觸發調度運行,即finish_wait().

2.3.4 pm_wakeup_pending() 接口

該函數的功能是確認當前是否滿足休眠條件,返回true表示可以休眠,false表示不可休眠。

bool pm_wakeup_pending(void)
{unsigned long flags;bool ret = false;raw_spin_lock_irqsave(&events_lock, flags);if (events_check_enabled) {unsigned int cnt, inpr;split_counters(&cnt, &inpr);ret = (cnt != saved_count || inpr > 0);events_check_enabled = !ret;}raw_spin_unlock_irqrestore(&events_lock, flags);if (ret) {pm_pr_dbg("Wakeup pending, aborting suspend\n");pm_print_active_wakeup_sources();}return ret || atomic_read(&pm_abort_suspend) > 0;
}

判斷允許休眠的依據:1.已處理的wakeup event數量與已記錄的數量(saved_count)一致,且2.待處理的wakeup event數量為0,且3.原子量pm_abort_suspend為0(該值大于0表示睡眠流程中出現了喚醒中斷或事件,喚醒事件通過調用pm_system_wakeup()來給pm_abort_suspend加1操作。)

2.3.5 device與wakeup_source關聯處理的接口

kernel抽象出的device數據結構存放著power manager相關的信息,其中就存放著wakeup source數據結構,如下:

//代碼格式錯誤,僅為呈現數據結構,請忽略格式。
struct device {// @power:	For device power management.struct dev_pm_info	power {unsigned int		can_wakeup:1; //需置1才允許使用wakeup sourcestruct wakeup_source	*wakeup; };
};

wakeup source框架中為此提供了大量相關的接口直接操作某個dev的ws,接口如下:

  • int device_wakeup_enable(struct device *dev):注冊設備的wakeup source1.以dev名注冊個ws,并指定該ws dev的parent為當前dev2.將注冊的ws關聯到dev->power.wakeup,如果存在wakeirq,也會一起綁定到該ws上。

  • int device_wakeup_disable(struct device *dev):注銷設備的wakeup source1.取消已注冊的ws與dev->power.wakeup的關聯2.注銷ws

  • void device_set_wakeup_capable(struct device *dev, bool capable):設置設備是否支持wakeup source1.設置dev->power.can_wakeup2.如果設備支持wakeup,則為其創建屬性文件(位于/sys/devices/<dev_name>/power/下);如果設備不支持wakeup,則不會移除相關屬性文件。

static struct attribute *wakeup_attrs[] = {
#ifdef CONFIG_PM_SLEEP&dev_attr_wakeup.attr, //RW,可寫入enabled/disabled動態配置是否支持wakeup&dev_attr_wakeup_count.attr, //RO, 讀取該dev ws的wakeup_count&dev_attr_wakeup_active_count.attr, //RO, 讀取該dev ws的active_count&dev_attr_wakeup_abort_count.attr, //RO, 讀取該dev ws的wakeup_count&dev_attr_wakeup_expire_count.attr, //RO, 讀取該dev ws的expire_count&dev_attr_wakeup_active.attr, //RO, 讀取該dev ws的active狀態&dev_attr_wakeup_total_time_ms.attr, //RO, 讀取該dev ws的total_time&dev_attr_wakeup_max_time_ms.attr, //RO, 讀取該dev ws的max_time&dev_attr_wakeup_last_time_ms.attr, //RO, 讀取該dev ws的last_time
#ifdef CONFIG_PM_AUTOSLEEP&dev_attr_wakeup_prevent_sleep_time_ms.attr, //RO, 讀取該dev ws的prevent_sleep_time
#endif
#endifNULL,
};

  • int device_init_wakeup(struct device *dev, bool enable):一步到位直接配置是否支持wakeup并且注冊/注銷ws

int device_init_wakeup(struct device *dev, bool enable)
{int ret = 0;if (enable) {device_set_wakeup_capable(dev, true);ret = device_wakeup_enable(dev);} else {device_wakeup_disable(dev);device_set_wakeup_capable(dev, false); }return ret;
}

  • int device_set_wakeup_enable(struct device *dev, bool enable):設置設備是否能通過ws喚醒系統,注冊/注銷ws

int device_set_wakeup_enable(struct device *dev, bool enable)
{return enable ? device_wakeup_enable(dev) : device_wakeup_disable(dev);
}

  • void pm_stay_awake(struct device *dev):持鎖設備的ws,不讓設備休眠,實際是調用__pm_stay_awake(dev->power.wakeup);實現

  • void pm_relax(struct device *dev):釋放設備的ws,允許設備休眠,實際是調用__pm_relax(dev->power.wakeup);實現

總結:1.device_set_wakeup_capable()?用于設置是否支持wakeup,并提供屬性節點,便于調試2.device_wakeup_enable()/device_wakeup_disable()/device_set_wakeup_enable()主要是注冊/注銷設備ws,需在device_set_wakeup_capable()enabled的前提下才能使用。3.device_init_wakeup()?通常使用在默認支持wakeup的device上,在probe/remove時分別enable/disable。4.pm_stay_awake()/pm_relax()主要是持有/釋放ws鎖,阻止/允許系統休眠

3. 主要工作時序

1)device或者其他需要上鎖的模塊調用device_init_wakeup()/wakeup_source_register()來注冊ws2)在處理業務時,為了防止系統進入睡眠流程,設備或模塊可以通過調用pm_stay_awake()/__pm_stay_awake()來持鎖ws阻止休眠3)當業務處理完成后,設備或模塊可以調用pm_relax()/__pm_relax()來釋放ws允許系統休眠4)在__pm_relax()釋放鎖時,會檢查當前是否有正在處理的持鎖事件,如果沒有,則觸發wakeup_count_wait_queue5)wakeup_count_wait_queue所在的pm_get_wakeup_count()接口會返回到autosleep的工作隊列中繼續走休眠流程

image

4. 調試節點

  1. 獲取所有wakeup source信息節點:cat /d/wakeup_sources列出所有wakeup_source當前的信息,包括:name,active_count,event_count,wakeup_count,expire_count,active_since,total_time,max_time,last_change,prevent_suspend_time。注:代碼實現在@drivers/base/power/wakeup.c

  2. 從wakeup類下獲取某個ws的信息:/sys/class/wakeup/wakeup<id>/wakeup類下匯總了所有已注冊的ws,該節點下存在屬性:name, active_count, event_count, wakeup_count,expire_count, active_time_ms, total_time_ms, max_time_ms, last_change_ms, prevent_suspend_time_ms。注:代碼實現在@drivers/base/power/wakeup_stats.c

  3. 從device節點下獲取該設備的ws信息:/sys/devices/<dev_name>/power/該節點存在如下屬性信息:wakeup(是否支持喚醒),wakeup_count, wakeup_active_count, wakeup_abort_count, wakeup_expire_count, wakeup_active, wakeup_total_time_ms, max_time_ms, last_time_ms, prevent_sleep_time_ms。注:代碼實現在@drivers/base/power/sysfs.c

注:本文是基于內核kernel-5.10展開。上述分析基于32位系統,若是64位系統,則combined_event_count會被拆分成2個32位分別來紀錄喚醒事件的總數和正在處理中的喚醒事件的總數

文章轉載自:Jayfan_Ma

原文鏈接:https://www.cnblogs.com/jiafan-ma/p/18200874

體驗地址:引邁 - JNPF快速開發平臺_低代碼開發平臺_零代碼開發平臺_流程設計器_表單引擎_工作流引擎_軟件架構

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/24045.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/24045.shtml
英文地址,請注明出處:http://en.pswp.cn/web/24045.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

后端進階-分庫分表

文章目錄 為什么需要分庫為什么需要分表 什么時候需要分庫分表只需要分庫只需要分表 分庫分表解決方案垂直分庫水平分庫垂直分表水平分表 分庫分表常用算法范圍算法hash分片查表分片 分庫分表模式客戶端模式代理模式 今天跟著訓練營學習了分庫分表&#xff0c;整理了學習筆記。…

機器學習模型進行預測和回測

這段代碼是為了并行地處理多個 CSV 文件&#xff0c;并使用機器學習模型進行預測和回測。主要涉及以下步驟&#xff1a; 初始化環境與設置&#xff1a; 引入必要的庫&#xff0c;如 ray 用于并行計算&#xff0c;pandas 用于數據處理&#xff0c;tqdm 用于進度條顯示等。設置一…

golang 不用sleep如何實現實現每隔指定時間執行一次for循環?

今天介紹的是在go語言里面不用time.Sleep&#xff0c; 使用for range 定時器管道 來實現按照我們指定的時間間隔來執行for循環, 即&#xff1a; for range ticker.C { } 這樣就實現了for每隔指定時間執行一次&#xff0c;除非管道被關閉&#xff0c;否則for而且會一直柱塞當前線…

淺說線性DP(下)

聲明 最近博主身體不適&#xff0c;更新較慢&#xff0c;請大家體諒體諒 最大上升子序列 【題目描述】 一個數的序列 你的任務&#xff0c;就是對于給定的序列&#xff0c;求出最大上升子序列和。注意&#xff0c;最長的上升子序列的和不一定是最大的&#xff0c;比如序列(1…

03-3.3.1 棧在括號匹配中的應用

&#x1f44b; Hi, I’m Beast Cheng&#x1f440; I’m interested in photography, hiking, landscape…&#x1f331; I’m currently learning python, javascript, kotlin…&#x1f4eb; How to reach me --> 458290771qq.com 喜歡《數據結構》部分筆記的小伙伴可以訂…

echarts的使用

一 echarts的使用 引入 echarts.js 文件 <script src"https://cdn.jsdelivr.net/npm/echarts/dist/echarts.min.js"></script> 準備一個呈現圖表的盒子 <div class"container"><div class"t_header"><span>端午…

東方博宜1760 - 整理抽屜

題目描述 期末考試即將來臨&#xff0c;小T由于同時肩負了學習、競賽、班團活動等多方面的任務&#xff0c;一直沒有時間好好整理他的課桌抽屜&#xff0c;為了更好地復習&#xff0c;小T首先要把課桌抽屜里的書分類整理好。 小T的抽屜里堆著 N 本書&#xff0c;每本書的封面上…

智能視頻監控平臺LntonCVS視頻融合共享平臺保障露營安全解決方案

在當今社會&#xff0c;都市生活的快節奏和壓力使得越來越多的人渴望逃離城市的喧囂&#xff0c;尋求一種短暫的慢生活體驗。他們向往在壯麗的山河之間或寧靜的鄉村中露營&#xff0c;享受大自然的寧靜與美好。隨著露營活動的普及&#xff0c;露營地的場景也變得更加豐富多樣&a…

使用python繪制核密度估計圖

使用python繪制核密度估計圖 核密度估計圖介紹效果代碼 核密度估計圖介紹 核密度估計&#xff08;Kernel Density Estimation&#xff0c;KDE&#xff09;是一種用于估計數據概率密度函數的非參數方法。與直方圖不同&#xff0c;KDE 可以生成平滑的密度曲線&#xff0c;更好地…

Mybatis使用緩存的配置總結

1.全局變量配置cacheEnabled&#xff1a; ture&#xff08;默認&#xff09;&#xff1a;開啟二級緩存&#xff0c; false&#xff1a;關閉二級緩存&#xff0c;但一級緩存不受影響 2.映射文件中mapper標簽下&#xff1a; 配置有&#xff1a;開啟二級緩存 沒配置有&#x…

LeetCode62不同路徑

題目描述 一個機器人位于一個 m x n 網格的左上角 &#xff08;起始點在下圖中標記為 “Start” &#xff09;。機器人每次只能向下或者向右移動一步。機器人試圖達到網格的右下角&#xff08;在下圖中標記為 “Finish” &#xff09;。問總共有多少條不同的路徑&#xff1f; …

大模型參加高考,同寫2024年高考作文,及格分(通義千問、Kimi、智譜清言、Gemini Advanced、Claude-3-Sonnet、GPT-4o)

大家好&#xff0c;我是章北海 今天高考&#xff0c;上午的語文結束&#xff0c;市面上又要來一場大模型參考的文章了。 我也湊湊熱鬧&#xff0c;讓通義千問、Kimi、智譜清言一起來寫一下高考作文。 公平起見&#xff0c;不加任何其他prompt&#xff0c;直接把題目甩過去。…

網絡基礎_02

1.ARP協議 地址解析協議&#xff08;Address Resolution Protocol&#xff09; 已知對方的三層ip地址&#xff0c;需要二層mac地址 當一臺設備&#xff08;請求方&#xff09;需要知道某個 IP 地址對應的 MAC 地址時&#xff0c;會使用 ARP封裝一個數據幀。這臺設備的網絡層以…

華為RH2288H V3服務器iBMC的SSL證書續期

本文對華為RH2288H V3服務器iBMC的SSL證書續期&#xff0c;以避名登錄告警提示及主機狀態異常。 一、檢查現網服務器iBMC的SSL證書到期時間 登錄iBMC&#xff0c;點擊配置--SSL證書&#xff0c;如下&#xff1a; 可以看到本服務器SSL證書將于今年7月22日到期。 二、聯系廠家…

【第四節】C/C++數據結構之樹與二叉樹

目錄 一、基本概念與術語 二、樹的ADT 三、二叉樹的定義和術語 四、平衡二叉樹 4.1 解釋 4.2 相關經典操作 4.3 代碼展示 一、基本概念與術語 樹(Tree)是由一個或多個結點組成的有限集合T。其中: 1 有一個特定的結點&#xff0c;稱為該樹的根(root)結點&#xff1b; 2 …

【Linux】進程2——管理概念,進程概念

1.什么是管理&#xff1f; 那在還沒有學習進程之前&#xff0c;就問大家&#xff0c;操作系統是怎么管理進行進程管理的呢&#xff1f; 很簡單&#xff0c;先把進程描述起來&#xff0c;再把進程組織起來&#xff01; 我們拿大學為例子 最典型的管理者——校長最典型的被管理…

來自工業界的知識庫 RAG 服務(三),FinGLM 競賽獲獎項目詳解

背景介紹 前面介紹過工業界的 RAG 服務 QAnything 和 RagFlow 的詳細設計&#xff0c;也介紹過來自學術界的 一些優化手段。 前一陣子剛好看到智譜組織的一個金融大模型比賽 FinGLM&#xff0c;主要做就是 RAG 服務的競賽&#xff0c;深入研究了其中的幾個獲獎作品&#xff…

Pyramid Vision Transformer, PVT(ICCV 2021)原理與代碼解讀

paper&#xff1a;Pyramid Vision Transformer: A Versatile Backbone for Dense Prediction without Convolutions official implementation&#xff1a;GitHub - whai362/PVT: Official implementation of PVT series 存在的問題 現有的 Vision Transformer (ViT) 主要設計…

C++結合ffmpeg獲取聲音的分貝值

提示&#xff1a;文章寫完后&#xff0c;目錄可以自動生成&#xff0c;如何生成可參考右邊的幫助文檔 文章目錄 前言一、分貝是什么&#xff1f;1.功率量2.場量 二、實際操作1.分析wav文件2.讀取麥克風 總結 前言 最近面對一個需求&#xff0c;就是需要傳遞聲音文件到模型里推…

鏈表的回文結構OJ

鏈表的回文結構_牛客題霸_牛客網對于一個鏈表&#xff0c;請設計一個時間復雜度為O(n),額外空間復雜度為O(1)的算法&#xff0c;判斷其是否為。題目來自【牛客題霸】https://www.nowcoder.com/practice/d281619e4b3e4a60a2cc66ea32855bfa?tpId49&&tqId29370&rp1&a…