* Copyright (c) 2025 Huawei Technologies Co., Ltd.
* This program is free software, you can redistribute it and/or modify it under the terms and conditions of
* CANN Open Software License Agreement Version 2.0 (the "License").
* Please refer to the License for details. You may not use this file except in compliance with the License.
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
* See LICENSE in the root of the software repository for the full text of the License.
*/
#ifndef UT_TEST
#include <stdlib.h>
#include "ascend_hal.h"
#include "securec.h"
#include "prof_common.h"
#include "prof_adapt.h"
#include "prof_buff.h"
#define PROF_DATA_HEAD_RSV_LENGTH 1021
struct prof_data_head {
uint32_t read_ptr;
uint32_t write_ptr;
uint32_t data_buf_len;
uint32_t rsv[PROF_DATA_HEAD_RSV_LENGTH];
};
drvError_t prof_buff_init(uint32_t chan_id, uint8_t **buff)
{
uint8_t *buff_addr = NULL;
struct prof_data_head *data_head = NULL;
uint32_t buff_len = 0x400000;
size_t alignment = 0x1000;
int ret;
if (chan_id == CHANNEL_AICPU) {
buff_len = 0x800000;
}
ret = posix_memalign((void**)&buff_addr, alignment, buff_len);
if (ret != 0) {
PROF_ERR("Failed to alloc mem. (chan_id=%u, ret=%d)\n", chan_id, ret);
return DRV_ERROR_MALLOC_FAIL;
}
(void)memset_s(buff_addr, buff_len, 0, buff_len);
data_head = (struct prof_data_head *)buff_addr;
data_head->write_ptr = 0;
data_head->read_ptr = 0;
data_head->data_buf_len = buff_len - (uint32_t)sizeof(struct prof_data_head);
*buff = buff_addr;
return DRV_ERROR_NONE;
}
void prof_buff_uninit(uint8_t **buff)
{
if (*buff != NULL) {
free(*buff);
*buff = NULL;
}
}
drvError_t prof_buff_write(uint8_t *buff, void *data, uint32_t data_len)
{
struct prof_data_head *data_head = (struct prof_data_head *)buff;
uint8_t *dest_base = NULL, *src_base = NULL;
uint32_t dest_len, src_len;
int ret;
dest_base = (uint8_t *)data_head + sizeof(struct prof_data_head) + data_head->write_ptr;
dest_len = data_head->data_buf_len - data_head->write_ptr;
src_base = data;
src_len = data_len;
if (dest_len < src_len) {
ret = memcpy_s(dest_base, dest_len, src_base, dest_len);
if (ret != 0) {
PROF_ERR("Failed to copy. (ret=%d, dest_len=%u, src_len=%u)\n", ret, dest_len, src_len);
return DRV_ERROR_MEMORY_OPT_FAIL;
}
src_base += dest_len;
src_len -= dest_len;
ATOMIC_SET(&data_head->write_ptr, 0);
dest_base = (uint8_t *)data_head + sizeof(struct prof_data_head);
dest_len = data_head->data_buf_len;
}
ret = memcpy_s(dest_base, dest_len, src_base, src_len);
if (ret != 0) {
PROF_ERR("Failed to copy. (ret=%d, dest_len=%u, src_len=%u)\n", ret, dest_len, src_len);
return DRV_ERROR_MEMORY_OPT_FAIL;
}
ATOMIC_SET(&data_head->write_ptr, (data_head->write_ptr + src_len) % data_head->data_buf_len);
return DRV_ERROR_NONE;
}
STATIC drvError_t prof_buff_copy(struct prof_data_head *data_head, char *out_buf, uint32_t buf_size,
uint32_t data_len)
{
uint8_t *data_base = NULL;
int ret;
data_base = (uint8_t *)data_head + sizeof(struct prof_data_head) + data_head->read_ptr;
ret = memcpy_s(out_buf, buf_size, data_base, data_len);
if (ret != 0) {
PROF_ERR("Failed to copy. (ret=%d, buf_size=%u, data_len=%u)\n", ret, buf_size, data_len);
return DRV_ERROR_MEMORY_OPT_FAIL;
}
ATOMIC_SET(&data_head->read_ptr, (data_head->read_ptr + data_len) % data_head->data_buf_len);
return DRV_ERROR_NONE;
}
int prof_buff_read(uint8_t *buff, char *out_buf, uint32_t buf_size)
{
struct prof_data_head *data_head = (struct prof_data_head *)buff;
uint32_t data_len, copied_len;
drvError_t ret;
if (data_head->read_ptr == data_head->write_ptr) {
return 0;
}
if (data_head->read_ptr < data_head->write_ptr) {
data_len = data_head->write_ptr - data_head->read_ptr;
data_len = (data_len > buf_size) ? buf_size : data_len;
ret = prof_buff_copy(data_head, out_buf, buf_size, data_len);
if (ret != DRV_ERROR_NONE) {
return PROF_ERROR;
}
return (int)data_len;
}
data_len = data_head->data_buf_len - data_head->read_ptr;
data_len = (data_len > buf_size) ? buf_size : data_len;
ret = prof_buff_copy(data_head, out_buf, buf_size, data_len);
if (ret != DRV_ERROR_NONE) {
return PROF_ERROR;
}
if ((data_len >= buf_size) || (data_head->write_ptr == 0)) {
return (int)data_len;
}
copied_len = data_len;
data_len = data_head->write_ptr;
data_len = ((data_len + copied_len) > buf_size) ? (buf_size - copied_len) : data_len;
ret = prof_buff_copy(data_head, out_buf + copied_len, buf_size - copied_len, data_len);
if (ret != DRV_ERROR_NONE) {
return (int)copied_len;
}
return (int)(data_len + copied_len);
}
uint32_t prof_buff_get_data_len(uint8_t *buff)
{
struct prof_data_head *data_head = (struct prof_data_head *)buff;
uint32_t write_ptr = data_head->write_ptr;
uint32_t read_ptr = data_head->read_ptr;
if (write_ptr >= read_ptr) {
return (write_ptr - read_ptr);
}
return (data_head->data_buf_len - read_ptr + write_ptr);
}
uint32_t prof_buff_get_avail_len(uint8_t *buff)
{
struct prof_data_head *data_head = (struct prof_data_head *)buff;
return (data_head->data_buf_len - prof_buff_get_data_len(buff) - 1);
}
void *prof_buff_get_buf_addr(uint8_t *buff)
{
return (void *)(buff + sizeof(struct prof_data_head));
}
uint32_t prof_buff_get_buf_size(uint8_t *buff)
{
struct prof_data_head *data_head = (struct prof_data_head *)buff;
return data_head->data_buf_len;
}
void *prof_buff_get_readptr_addr(uint8_t *buff)
{
struct prof_data_head *data_head = (struct prof_data_head *)buff;
return (void *)&data_head->read_ptr;
}
uint32_t prof_buff_get_readptr_size(uint8_t *buff)
{
struct prof_data_head *data_head = (struct prof_data_head *)buff;
return sizeof(data_head->read_ptr);
}
uint32_t prof_buff_get_writeptr(uint8_t *buff)
{
struct prof_data_head *data_head = (struct prof_data_head *)buff;
return data_head->write_ptr;
}
void prof_buff_update_writeptr(uint8_t *buff, uint32_t write_ptr)
{
struct prof_data_head *data_head = (struct prof_data_head *)buff;
ATOMIC_SET(&data_head->write_ptr, write_ptr);
}
void prof_buff_wait_read_empty(uint8_t *buff, uint32_t dev_id, uint32_t chan_id)
{
struct prof_adapt_core_notifier *notifier = prof_adapt_get_notifier();
uint32_t data_len, wait_num = 0;
data_len = prof_buff_get_data_len(buff);
if (data_len == 0) {
return;
}
notifier->poll_report(dev_id, chan_id);
while ((data_len != 0) && (wait_num < 1000)) {
(void)usleep(1000);
wait_num++;
data_len = prof_buff_get_data_len(buff);
}
if (data_len != 0) {
PROF_RUN_INFO("Waiting for read timeout. (dev_id=%u, chan_id=%u, data_len=%u, wait_num=%u)\n",
dev_id, chan_id, data_len, wait_num);
return;
}
PROF_INFO("Read completed. (dev_id=%u, chan_id=%u, wait_num=%u)\n", dev_id, chan_id, wait_num);
}
#else
int prof_buff_ut_test(void)
{
return 0;
}
#endif