Merge branch 'feat/add_mutex' into 'master'

Feat/add mutex

See merge request speech-recognition-framework/esp-sr!29
This commit is contained in:
Sun Xiang Yu 2023-03-21 00:28:57 +08:00
commit a4f3332561
21 changed files with 16864 additions and 49 deletions

View File

@ -1,8 +1,13 @@
# Change log for esp-sr # Change log for esp-sr
## Unreleased ## Unreleased
## 1.2.1
- Fix bugs in model loader
- Read all parameters sequentially, which reduces about 5x in model loading time. - Read all parameters sequentially, which reduces about 5x in model loading time.
- Use esp_partition_mmap to replace spiffs file system, which further reduces about 3x in model loading time - Use esp_partition_mmap to replace spiffs file system, which further reduces about 3x in model loading time
- Add WakeNet API unity test
- Add MultiNet API unity test
## 1.2.0 ## 1.2.0
- ESP-DSP dependency is now installed from the component registry - ESP-DSP dependency is now installed from the component registry

View File

@ -1,4 +1,4 @@
version: "1.2.0" version: "1.2.1"
description: esp_sr provides basic algorithms for Speech Recognition applications description: esp_sr provides basic algorithms for Speech Recognition applications
url: https://github.com/espressif/esp-sr url: https://github.com/espressif/esp-sr
dependencies: dependencies:

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -2,6 +2,7 @@ import io
import os import os
import argparse import argparse
import shutil import shutil
import math
from pack_model import pack_models from pack_model import pack_models
def calculate_total_size(folder_path): def calculate_total_size(folder_path):
@ -64,23 +65,25 @@ def copy_multinet_from_sdkconfig(model_path, sdkconfig_path, target_path):
models_string += label models_string += label
models = [] models = []
if "CONFIG_SR_MN_CN_MULTINET3_SINGLE_RECOGNITION" in models_string and len(models) < 2: if "CONFIG_SR_MN_CN_MULTINET3_SINGLE_RECOGNITION" in models_string:
models.append('mn3_cn') models.append('mn3_cn')
elif "CONFIG_SR_MN_CN_MULTINET4_5_SINGLE_RECOGNITION_QUANT8" in models_string: elif "CONFIG_SR_MN_CN_MULTINET4_5_SINGLE_RECOGNITION_QUANT8" in models_string:
models.append('mn4q8_cn') models.append('mn4q8_cn')
elif "CONFIG_SR_MN_CN_MULTINET4_5_SINGLE_RECOGNITION" in models_string and len(models) < 2: elif "CONFIG_SR_MN_CN_MULTINET4_5_SINGLE_RECOGNITION" in models_string:
models.append('mn4_cn') models.append('mn4_cn')
elif "CONFIG_SR_MN_CN_MULTINET5_RECOGNITION_QUANT8" in models_string and len(models) < 2: elif "CONFIG_SR_MN_CN_MULTINET5_RECOGNITION_QUANT8" in models_string:
models.append('mn5q8_cn') models.append('mn5q8_cn')
elif "CONFIG_SR_MN_EN_MULTINET5_SINGLE_RECOGNITION_QUANT8" in models_string and len(models) < 2: elif "CONFIG_SR_MN_CN_MULTINET6_QUANT" in models_string:
models.append('mn5q8_en')
elif "CONFIG_SR_MN_EN_MULTINET5_SINGLE_RECOGNITION" in models_string and len(models) < 2:
models.append('mn5_en')
elif "CONFIG_SR_MN_EN_MULTINET6_QUANT" in models_string and len(models) < 2:
models.append('mn6_en')
elif "CONFIG_SR_MN_CN_MULTINET6_QUANT" in models_string and len(models) < 2:
models.append('mn6_cn') models.append('mn6_cn')
if "CONFIG_SR_MN_EN_MULTINET5_SINGLE_RECOGNITION_QUANT8" in models_string:
models.append('mn5q8_en')
elif "CONFIG_SR_MN_EN_MULTINET5_SINGLE_RECOGNITION" in models_string:
models.append('mn5_en')
elif "CONFIG_SR_MN_EN_MULTINET6_QUANT" in models_string:
models.append('mn6_en')
if "MULTINET6" in models_string: if "MULTINET6" in models_string:
models.append('fst') models.append('fst')
@ -116,6 +119,7 @@ if __name__ == '__main__':
sdkconfig_path = args.project_path + '/sdkconfig' sdkconfig_path = args.project_path + '/sdkconfig'
model_path = args.model_path + '/model' model_path = args.model_path + '/model'
target_path = args.build_path + '/srmodels' target_path = args.build_path + '/srmodels'
image_file = "srmodels.bin"
if os.path.exists(target_path): if os.path.exists(target_path):
shutil.rmtree(target_path) shutil.rmtree(target_path)
@ -123,6 +127,7 @@ if __name__ == '__main__':
copy_multinet_from_sdkconfig(model_path, sdkconfig_path, target_path) copy_multinet_from_sdkconfig(model_path, sdkconfig_path, target_path)
copy_wakenet_from_sdkconfig(model_path, sdkconfig_path, target_path) copy_wakenet_from_sdkconfig(model_path, sdkconfig_path, target_path)
total_size = calculate_total_size(target_path) pack_models(target_path, image_file)
pack_models(target_path, "srmodels.bin") total_size = os.path.getsize(os.path.join(target_path, image_file))
print("Recommended model partition size: ", str(int((total_size / 1024 + 900) / 4 ) * 4) + 'KB') recommended_size = int(math.ceil(total_size/1024))
print("Recommended model partition size: %dK" % (recommended_size))

View File

@ -104,6 +104,7 @@ def pack_models(model_path, out_file="srmodels.bin"):
out_bin += model_bin out_bin += model_bin
assert len(out_bin) == header_len assert len(out_bin) == header_len
if data_bin != None:
out_bin += data_bin out_bin += data_bin
out_file = os.path.join(model_path, out_file) out_file = os.path.join(model_path, out_file)

View File

@ -874,7 +874,9 @@ char *get_id_name_en(int i)
esp_mn_error_t* esp_mn_commands_update_from_sdkconfig(const esp_mn_iface_t *multinet, model_iface_data_t *model_data) esp_mn_error_t* esp_mn_commands_update_from_sdkconfig(const esp_mn_iface_t *multinet, model_iface_data_t *model_data)
{ {
#ifdef CONFIG_SR_MN_CN_MULTINET6_QUANT || CONFIG_SR_MN_EN_MULTINET6_QUANT #ifdef CONFIG_SR_MN_CN_MULTINET6_QUANT
return NULL;
#else if CONFIG_SR_MN_EN_MULTINET6_QUANT
return NULL; return NULL;
#endif #endif

View File

@ -17,8 +17,8 @@ typedef struct
typedef struct typedef struct
{ {
char **model_name; // the name of models, like "wn9_hilexin"(wakenet9, hilexin), "mn5_en"(multinet5, english) char **model_name; // the name of models, like "wn9_hilexin"(wakenet9, hilexin), "mn5_en"(multinet5, english)
char *partition_label; // partition label used to save the files of model esp_partition_t *partition; // partition label used to save the files of model
spi_flash_mmap_handle_t *mmap_handle;// mmap_handle if using esp_partition_mmap else NULL; spi_flash_mmap_handle_t mmap_handle; // mmap_handle if using esp_partition_mmap else NULL;
int num; // the number of models int num; // the number of models
srmodel_data_t **model_data; // the model data , NULL if spiffs format srmodel_data_t **model_data; // the model data , NULL if spiffs format
} srmodel_list_t; } srmodel_list_t;
@ -72,11 +72,11 @@ int esp_srmodel_exists(srmodel_list_t *models, char *model_name);
/** /**
* @brief Initialize and mount SPIFFS filesystem, return all avaliable models in spiffs. * @brief Initialize and mount SPIFFS filesystem, return all avaliable models in spiffs.
* *
* @param partition_label The spiffs label defined in your partition file used to save models. * @param part The spiffs partition.
* *
* @return all avaliable models in spiffs,save as srmodel_list_t. * @return all avaliable models in spiffs,save as srmodel_list_t.
*/ */
srmodel_list_t *srmodel_spiffs_init(const char* partition_label); srmodel_list_t* srmodel_spiffs_init(const esp_partition_t *part);
/** /**
* @brief unregister SPIFFS filesystem and free srmodel_list_t. * @brief unregister SPIFFS filesystem and free srmodel_list_t.

View File

@ -25,11 +25,10 @@ void set_model_base_path(const char *base_path)
static srmodel_list_t* srmodel_list_alloc(void) static srmodel_list_t* srmodel_list_alloc(void)
{ {
srmodel_list_t *models = (srmodel_list_t*) malloc(sizeof(srmodel_list_t)); srmodel_list_t *models = (srmodel_list_t*) malloc(sizeof(srmodel_list_t));
models->mmap_handle = NULL;
models->model_data = NULL; models->model_data = NULL;
models->model_name = NULL; models->model_name = NULL;
models->num = 0; models->num = 0;
models->partition_label = NULL; models->partition = NULL;
return models; return models;
} }
@ -71,7 +70,6 @@ srmodel_list_t *read_models_form_spiffs(esp_vfs_spiffs_conf_t *conf)
return models; return models;
} else { } else {
models->num = model_num; models->num = model_num;
models->partition_label = (char *)conf->partition_label;
models->model_name = malloc(models->num*sizeof(char*)); models->model_name = malloc(models->num*sizeof(char*));
for (int i=0; i<models->num; i++) for (int i=0; i<models->num; i++)
models->model_name[i] = (char*) calloc(MODEL_NAME_MAX_LENGTH, sizeof(char)); models->model_name[i] = (char*) calloc(MODEL_NAME_MAX_LENGTH, sizeof(char));
@ -104,13 +102,13 @@ srmodel_list_t *read_models_form_spiffs(esp_vfs_spiffs_conf_t *conf)
} }
srmodel_list_t* srmodel_spiffs_init(const char *partition_label) srmodel_list_t* srmodel_spiffs_init(const esp_partition_t *part)
{ {
ESP_LOGI(TAG, "\nInitializing models from SPIFFS, partition label: %s\n", partition_label); ESP_LOGI(TAG, "\nInitializing models from SPIFFS, partition label: %s\n", part->label);
esp_vfs_spiffs_conf_t conf = { esp_vfs_spiffs_conf_t conf = {
.base_path = SRMODE_BASE_PATH, .base_path = SRMODE_BASE_PATH,
.partition_label = partition_label, .partition_label = part->label,
.max_files = 5, .max_files = 5,
.format_if_mount_failed = true .format_if_mount_failed = true
}; };
@ -131,7 +129,7 @@ srmodel_list_t* srmodel_spiffs_init(const char *partition_label)
} }
size_t total = 0, used = 0; size_t total = 0, used = 0;
ret = esp_spiffs_info(partition_label, &total, &used); ret = esp_spiffs_info(part->label, &total, &used);
if (ret != ESP_OK) { if (ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to get SPIFFS partition information (%s)\n", esp_err_to_name(ret)); ESP_LOGE(TAG, "Failed to get SPIFFS partition information (%s)\n", esp_err_to_name(ret));
} else { } else {
@ -139,18 +137,20 @@ srmodel_list_t* srmodel_spiffs_init(const char *partition_label)
} }
// Read all model from path // Read all model from path
return read_models_form_spiffs(&conf); srmodel_list_t *models = read_models_form_spiffs(&conf);
models->partition = (esp_partition_t *)part;
return models;
} }
void srmodel_spiffs_deinit(srmodel_list_t *models) void srmodel_spiffs_deinit(srmodel_list_t *models)
{ {
if (models->partition_label != NULL) { if (models->partition != NULL) {
esp_err_t ret = esp_vfs_spiffs_unregister(models->partition_label); esp_err_t ret = esp_vfs_spiffs_unregister(models->partition->label);
if (ret != ESP_OK) { if (ret != ESP_OK) {
ESP_LOGW(TAG, "Already unregistered\n"); ESP_LOGW(TAG, "Already unregistered\n");
} else { } else {
ESP_LOGI(TAG, "%s has been unregistered\n", models->partition_label); ESP_LOGI(TAG, "%s has been unregistered\n", models->partition->label);
} }
} }
@ -236,7 +236,7 @@ static uint32_t read_int32(char *data) {
return value; return value;
} }
srmodel_list_t *srmodel_mmap_init(esp_partition_t *part) srmodel_list_t *srmodel_mmap_init(const esp_partition_t *part)
{ {
if (static_srmodels == NULL) if (static_srmodels == NULL)
static_srmodels = srmodel_list_alloc(); static_srmodels = srmodel_list_alloc();
@ -244,19 +244,18 @@ srmodel_list_t *srmodel_mmap_init(esp_partition_t *part)
return static_srmodels; return static_srmodels;
srmodel_list_t *models = static_srmodels; srmodel_list_t *models = static_srmodels;
void *root = NULL; const void *root;
models->mmap_handle = (spi_flash_mmap_handle_t *)malloc(sizeof(spi_flash_mmap_handle_t)); esp_err_t err=esp_partition_mmap(part, 0, part->size, SPI_FLASH_MMAP_DATA, &root, &models->mmap_handle);
esp_err_t err=esp_partition_mmap(part, 0, part->size, SPI_FLASH_MMAP_DATA, &root, models->mmap_handle);
if (err != ESP_OK) { if (err != ESP_OK) {
ESP_LOGE(TAG, "Can not map %s partition!\n", part->label); ESP_LOGE(TAG, "Can not map %s partition!", part->label);
return NULL; return NULL;
} else { } else {
ESP_LOGI(TAG, "partition %s size: %d by mmap\n", part->label, part->size); ESP_LOGI(TAG, "partition %s size: %d by mmap", part->label, part->size);
} }
models->partition_label = part->label; models->partition = (esp_partition_t *)part;
char *start = root; char *start = (char *)root;
char *data = root; char *data = (char *)root;
int str_len = SRMODEL_STRING_LENGTH; int str_len = SRMODEL_STRING_LENGTH;
int int_len = 4; int int_len = 4;
//read model number //read model number
@ -271,13 +270,12 @@ srmodel_list_t *srmodel_mmap_init(esp_partition_t *part)
models->model_name[i] = (char*)malloc((strlen(data)+1)*sizeof(char)); models->model_name[i] = (char*)malloc((strlen(data)+1)*sizeof(char));
strcpy(models->model_name[i], data); strcpy(models->model_name[i], data);
data += str_len; data += str_len;
printf("%s\n", models->model_name[i]);
//read model number //read model number
int file_num = read_int32(data); int file_num = read_int32(data);
model_data->num = file_num; model_data->num = file_num;
data += int_len; data += int_len;
model_data->files = (char **) malloc(sizeof(char*)*file_num); model_data->files = (char **) malloc(sizeof(char*)*file_num);
model_data->data = (void **) malloc(sizeof(void*)*file_num); model_data->data = (char **) malloc(sizeof(void*)*file_num);
model_data->sizes = (int *) malloc(sizeof(int)*file_num); model_data->sizes = (int *) malloc(sizeof(int)*file_num);
for (int j=0; j<file_num; j++) { for (int j=0; j<file_num; j++) {
@ -322,6 +320,7 @@ void srmodel_mmap_deinit(srmodel_list_t *models)
free(models); free(models);
} }
models = NULL; models = NULL;
static_srmodels = NULL;
} }
#endif #endif
@ -399,7 +398,7 @@ srmodel_list_t* srmodel_sdcard_init(const char *base_path)
return models; return models;
} else { } else {
models->num = model_num; models->num = model_num;
models->partition_label = NULL; models->partition = NULL;
models->model_name = malloc(models->num*sizeof(char*)); models->model_name = malloc(models->num*sizeof(char*));
for (int i=0; i<models->num; i++) for (int i=0; i<models->num; i++)
models->model_name[i] = (char*) calloc(MODEL_NAME_MAX_LENGTH, sizeof(char)); models->model_name[i] = (char*) calloc(MODEL_NAME_MAX_LENGTH, sizeof(char));
@ -463,7 +462,7 @@ srmodel_list_t* esp_srmodel_init(const char* partition_label)
if (part) { if (part) {
return srmodel_mmap_init(part); return srmodel_mmap_init(part);
} else { } else {
ESP_LOGE(TAG, "Can not find %s in partition table\n", partition_label); ESP_LOGE(TAG, "Can not find %s in partition table", partition_label);
} }
return NULL; return NULL;
@ -481,7 +480,7 @@ void esp_srmodel_deinit(srmodel_list_t *models)
#ifdef CONFIG_IDF_TARGET_ESP32 #ifdef CONFIG_IDF_TARGET_ESP32
return srmodel_config_deinit(models); return srmodel_config_deinit(models);
#else #else
return srmodel_spiffs_deinit(models); return srmodel_mmap_deinit(models);
#endif #endif
#else #else

3
test/CMakeLists.txt Normal file
View File

@ -0,0 +1,3 @@
idf_component_register(SRC_DIRS "."
INCLUDE_DIRS "."
REQUIRES cmock esp-sr)

4025
test/alexa.h Normal file

File diff suppressed because it is too large Load Diff

4985
test/dakaidiandeng.h Normal file

File diff suppressed because it is too large Load Diff

7554
test/hilexin.h Normal file

File diff suppressed because it is too large Load Diff

114
test/unity_multinet.c Normal file
View File

@ -0,0 +1,114 @@
/* test_mean.c: Implementation of a testable component.
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include "string.h"
#include <limits.h>
#include "unity.h"
#include "model_path.h"
#include "esp_mn_iface.h"
#include "esp_mn_models.h"
#include "dakaidiandeng.h"
#include "alexa.h"
#include "dl_lib_convq_queue.h"
#include <sys/time.h>
TEST_CASE("multinet create/destroy API & memory leak", "[mn]")
{
vTaskDelay(500 / portTICK_PERIOD_MS);
int start_size = heap_caps_get_free_size(MALLOC_CAP_8BIT);
int start_internal_size = heap_caps_get_free_size(MALLOC_CAP_INTERNAL);
srmodel_list_t *models = esp_srmodel_init("model");
char *model_name = esp_srmodel_filter(models, ESP_MN_PREFIX, NULL);
esp_mn_iface_t *multinet = esp_mn_handle_from_name(model_name);
// test model loading time
struct timeval tv_start, tv_end;
gettimeofday(&tv_start, NULL);
model_iface_data_t *model_data = multinet->create(model_name, 6000);
gettimeofday(&tv_end, NULL);
int tv_ms=(tv_end.tv_sec-tv_start.tv_sec)*1000+(tv_end.tv_usec-tv_start.tv_usec)/1000;
printf("create latency:%d ms\n", tv_ms);
// test model memory concumption
int create_size = start_size - heap_caps_get_free_size(MALLOC_CAP_8BIT);
int create_internal_size = start_internal_size - heap_caps_get_free_size(MALLOC_CAP_INTERNAL);
printf("Internal RAM: %d, PSRAM:%d\n", create_internal_size, create_size-create_internal_size);
multinet->destroy(model_data);
esp_srmodel_deinit(models);
// test memory leak
int first_end_size = heap_caps_get_free_size(MALLOC_CAP_8BIT);
int first_end_internal_size = heap_caps_get_free_size(MALLOC_CAP_INTERNAL);
int last_end_size = first_end_size;
int last_end_internal_size = first_end_internal_size;
int mem_leak = start_size - last_end_size;
printf("create&destroy times:%d, memory leak:%d\n", 1, mem_leak);
for (int i=0; i<5; i++) {
printf("init partition ...\n");
models = esp_srmodel_init("model");
model_name = esp_srmodel_filter(models, ESP_MN_PREFIX, NULL);
multinet = esp_mn_handle_from_name(model_name);
int time_out = 3000+i*2000;
printf("create ..., time out = %d\n", time_out);
model_data = multinet->create(model_name, time_out);
printf("destroy ...\n");
multinet->destroy(model_data);
esp_srmodel_deinit(models);
last_end_size = heap_caps_get_free_size(MALLOC_CAP_8BIT);
last_end_internal_size = heap_caps_get_free_size(MALLOC_CAP_INTERNAL);
mem_leak = start_size - last_end_size;
printf("create&destroy times:%d, memory leak:%d\n", i+2, mem_leak);
}
TEST_ASSERT_EQUAL(true, (mem_leak) < 1000 && last_end_size == first_end_size);
}
TEST_CASE("multinet detect API & cpu loading", "[mn]")
{
vTaskDelay(500 / portTICK_PERIOD_MS);
srmodel_list_t *models = esp_srmodel_init("model");
char *model_name = esp_srmodel_filter(models, ESP_MN_PREFIX, NULL);
esp_mn_iface_t *multinet = esp_mn_handle_from_name(model_name);
model_iface_data_t *model_data = multinet->create(model_name, 6000);
int frequency = multinet->get_samp_rate(model_data);
int audio_chunksize = multinet->get_samp_chunksize(model_data) * sizeof(int16_t);
int16_t *buffer = malloc(audio_chunksize);
int chunks = 0;
struct timeval tv_start, tv_end;
gettimeofday(&tv_start, NULL);
while (1) {
if ((chunks + 1)*audio_chunksize <= sizeof(alexa)) {
memcpy(buffer, alexa + chunks * audio_chunksize, audio_chunksize);
} else {
memset(buffer, 0, audio_chunksize);
}
esp_mn_state_t mn_state = multinet->detect(model_data, buffer);
chunks++;
if (chunks == 64)
break;
}
gettimeofday(&tv_end, NULL);
int tv_ms=(tv_end.tv_sec-tv_start.tv_sec)*1000+(tv_end.tv_usec-tv_start.tv_usec)/1000;
chunks -= 7;
int run_ms = (chunks)*audio_chunksize/sizeof(int16_t)*1000/frequency;
float cpu_loading = tv_ms*100.0/run_ms;
printf("Done! Took %d ms to parse %d ms worth of samples in %d iterations. CPU loading(single core):%.1f%%\n",
tv_ms, run_ms, chunks, cpu_loading);
multinet->destroy(model_data);
esp_srmodel_deinit(models);
TEST_ASSERT_EQUAL(true, (cpu_loading<75 && tv_ms>0));
}

122
test/unity_wakenet.c Normal file
View File

@ -0,0 +1,122 @@
/* test_mean.c: Implementation of a testable component.
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include "string.h"
#include <limits.h>
#include "unity.h"
#include "model_path.h"
#include "esp_wn_iface.h"
#include "esp_wn_models.h"
#include "hilexin.h"
#include "dl_lib_convq_queue.h"
#include <sys/time.h>
TEST_CASE("wakenet create/destroy API & memory leak", "[wn]")
{
vTaskDelay(500 / portTICK_PERIOD_MS);
int start_size = heap_caps_get_free_size(MALLOC_CAP_8BIT);
int start_internal_size = heap_caps_get_free_size(MALLOC_CAP_INTERNAL);
srmodel_list_t *models = esp_srmodel_init("model");
char *model_name = esp_srmodel_filter(models, ESP_WN_PREFIX, NULL);
esp_wn_iface_t *wakenet = esp_wn_handle_from_name(model_name);
// test model loading time
struct timeval tv_start, tv_end;
gettimeofday(&tv_start, NULL);
model_iface_data_t *model_data = wakenet->create(model_name, DET_MODE_3CH_95);
gettimeofday(&tv_end, NULL);
int tv_ms=(tv_end.tv_sec-tv_start.tv_sec)*1000+(tv_end.tv_usec-tv_start.tv_usec)/1000;
printf("create latency:%d ms\n", tv_ms);
// test model memory concumption
int create_size = start_size - heap_caps_get_free_size(MALLOC_CAP_8BIT);
int create_internal_size = start_internal_size - heap_caps_get_free_size(MALLOC_CAP_INTERNAL);
printf("Internal RAM: %d, PSRAM:%d\n", create_internal_size, create_size-create_internal_size);
wakenet->destroy(model_data);
esp_srmodel_deinit(models);
// test memory leak
int first_end_size = heap_caps_get_free_size(MALLOC_CAP_8BIT);
int first_end_internal_size = heap_caps_get_free_size(MALLOC_CAP_INTERNAL);
int last_end_size = first_end_size;
int last_end_internal_size = first_end_internal_size;
int mem_leak = start_size - last_end_size;
printf("create&destroy times:%d, memory leak:%d\n", 1, mem_leak);
for (int i=0; i<6; i++) {
printf("init partition ...\n");
models = esp_srmodel_init("model");
model_name = esp_srmodel_filter(models, ESP_WN_PREFIX, NULL);
wakenet = esp_wn_handle_from_name(model_name);
printf("create ...\n");
// typedef enum {
// DET_MODE_90 = 0, // Normal
// DET_MODE_95 = 1, // Aggressive
// DET_MODE_2CH_90 = 2,
// DET_MODE_2CH_95 = 3,
// DET_MODE_3CH_90 = 4,
// DET_MODE_3CH_95 = 5,
// } det_mode_t;
model_data = wakenet->create(model_name, i);
printf("destroy ...\n");
wakenet->destroy(model_data);
esp_srmodel_deinit(models);
last_end_size = heap_caps_get_free_size(MALLOC_CAP_8BIT);
last_end_internal_size = heap_caps_get_free_size(MALLOC_CAP_INTERNAL);
mem_leak = start_size - last_end_size;
printf("create&destroy times:%d, memory leak:%d\n", i+2, mem_leak);
}
TEST_ASSERT_EQUAL(true, (mem_leak) < 1000 && last_end_size == first_end_size);
}
TEST_CASE("wakenet detect API & cpu loading", "[wn]")
{
vTaskDelay(500 / portTICK_PERIOD_MS);
srmodel_list_t *models = esp_srmodel_init("model");
char *model_name = esp_srmodel_filter(models, ESP_WN_PREFIX, NULL);
esp_wn_iface_t *wakenet = esp_wn_handle_from_name(model_name);
model_iface_data_t *model_data = wakenet->create(model_name, DET_MODE_95);
int frequency = wakenet->get_samp_rate(model_data);
int audio_chunksize = wakenet->get_samp_chunksize(model_data) * sizeof(int16_t);
int16_t *buffer = malloc(audio_chunksize);
int chunks = 0;
int detected = 0;
struct timeval tv_start, tv_end;
gettimeofday(&tv_start, NULL);
while (1) {
if ((chunks + 1)*audio_chunksize <= sizeof(hilexin)) {
memcpy(buffer, hilexin + chunks * audio_chunksize, audio_chunksize);
} else {
memset(buffer, 0, audio_chunksize);
}
int res = wakenet->detect(model_data, buffer);
if (res > 0)
detected = 1;
chunks++;
if (detected == 1)
break;
}
gettimeofday(&tv_end, NULL);
int tv_ms=(tv_end.tv_sec-tv_start.tv_sec)*1000+(tv_end.tv_usec-tv_start.tv_usec)/1000;
int run_ms = (chunks)*audio_chunksize/sizeof(int16_t)*1000/frequency;
float cpu_loading = tv_ms*100.0/run_ms;
printf("Done! Took %d ms to parse %d ms worth of samples in %d iterations. CPU loading(single core):%.1f%%\n",
tv_ms, run_ms, chunks, cpu_loading);
wakenet->destroy(model_data);
esp_srmodel_deinit(models);
TEST_ASSERT_EQUAL(true, (cpu_loading<75 && detected==1));
}