/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ /* auto generate by HHB_VERSION "2.0.21" */ #include #include #include #include #include #include #include #include #include #include #include "process_linker_types.h" #include "io.h" #include "shl_ref.h" #include "process.h" #include "video_mem.h" #include "detect.h" #include "output_120_out0_nchw_1_2_7668_1.h" #define MODULE_NAME "npu_sink_test" #define MIN(x, y) ((x) < (y) ? (x) : (y)) #define FILE_LENGTH 1028 #define SHAPE_LENGHT 128 #ifndef NULL #define NULL ((void *)0) #endif #define NUM_OF_BUFFERS 5 #define errExit(msg) do { perror(msg); exit(EXIT_FAILURE); \ } while (0) void *csinn_(char *params); void csinn_run(void *data0, void *td); void *csinn_nbg(const char *nbg_file_name); #define OUT_SIZE1 (1*7668) #define OUT_SIZE2 (1917*21) int input_size[] = {1 * 3 * 304 * 304, }; int output_size[] = {OUT_SIZE1, OUT_SIZE1 * 2, 1 * OUT_SIZE2, }; const char model_name[] = "network"; #define R_MEAN 127.5 #define G_MEAN 127.5 #define B_MEAN 127.5 #define SCALE (1.0/127.5) float mean[] = {B_MEAN, G_MEAN, R_MEAN}; const char class_name[][FILE_LENGTH] = { "background", "aeroplane", "bicycle", "bird", "boat", "bottle", "bus", "car", "cat", "chair", "cow", "diningtable", "dog", "horse", "motorbike", "person", "pottedplant", "sheep", "sofa", "train", "tvmonitor" }; const char shm_sink_name[] = "/ispnpu"; const char shm_src_name[] = "/npu_g2d"; #define BASE_MEMORY 0xD8000000 typedef struct _ServerParams { char *plinkname; int count; int frames; } ServerParams; typedef struct _PlinkChannel { PlinkChannelID id; PlinkHandle plink; PlinkPacket pkt; int sendid; int backid; int exit; int available_bufs; } PlinkChannel; typedef struct _FeatureBuffer { unsigned int bus_address; void *virtual_address; unsigned int size; } FeatureBuffer; void parseParams(int argc, char **argv, ServerParams *params) { int i = 1; memset(params, 0, sizeof(*params)); params->plinkname = "/tmp/plink_npu_featuremap.test"; params->frames = 3; while (i < argc) { if (argv[i][0] != '-' || strlen(argv[i]) < 2) { i++; continue; } if (argv[i][1] == 'l') { if (++i < argc) { params->plinkname = argv[i++]; } } else if (argv[i][1] == 'n') { if (++i < argc) { params->frames = atoi(argv[i++]); } } }; } int checkParams(ServerParams *params) { if (params->plinkname == NULL) return -1; return 0; } void printUsage(char *name) { printf("usage: %s [options]\n" "\n" " Available options:\n" " -l plink file name (default: /tmp/plink.test)\n" " -i input YUV file name (mandatory)\n" " -f input color format (default: 2)\n" " 2 - I420\n" " 3 - NV12\n" " -w video width (mandatory)\n" " -h video height (mandatory)\n" " -s video buffer stride (default: video width)\n" " -n number of frames to send (default: 10)\n" "\n", name); } int getBufferSize(ServerParams *params) { return sizeof(PlinkObjectDetect); } void constructFeatureInfo(PlinkObjectInfo *info, ServerParams *params, unsigned int bus_address, int face_cnt, int id) { info->header.type = PLINK_TYPE_OBJECT; info->header.size = DATA_SIZE(*info); info->header.id = id + 1; info->bus_address = bus_address; info->object_cnt = face_cnt; } int getBufferCount(PlinkPacket *pkt) { int ret = 0; for (int i = 0; i < pkt->num; i++) { PlinkDescHdr *hdr = (PlinkDescHdr *)(pkt->list[i]); if (hdr->type == PLINK_TYPE_MESSAGE) { int *data = (int *)(pkt->list[i] + DATA_HEADER_SIZE); if (*data == PLINK_EXIT_CODE) { ret |= 0x80000000; // set bit 31 to 1 to indicate 'exit' } else if (*data >= 0) ret++; } } return ret; } void retreiveSentBuffers(PlinkHandle plink, PlinkChannel *channel) { PlinkStatus sts = PLINK_STATUS_OK; while (channel->available_bufs < NUM_OF_BUFFERS) { do { sts = PLINK_recv(plink, channel->id, &channel->pkt); int count = getBufferCount(&channel->pkt); if (count > 0) { channel->available_bufs += count; } } while (sts == PLINK_STATUS_MORE_DATA); } } void AllocateBuffers(FeatureBuffer featurebuffers[NUM_OF_BUFFERS], unsigned int size, int fd_mem) { unsigned int bus_address = BASE_MEMORY; unsigned int buffer_size = (size + 0xFFF) & ~0xFFF; for (int i = 0; i < NUM_OF_BUFFERS; i++) { featurebuffers[i].virtual_address = mmap(0, buffer_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd_mem, bus_address); printf("mmap %p from %x with size %d\n", featurebuffers[i].virtual_address, bus_address, size); featurebuffers[i].bus_address = bus_address; featurebuffers[i].size = buffer_size; bus_address += buffer_size; } } void FreeBuffers(FeatureBuffer featurebuffers[NUM_OF_BUFFERS], unsigned int size, int fd_mem) { for (int i = 0; i < NUM_OF_BUFFERS; i++) { munmap(featurebuffers[i].virtual_address, featurebuffers[i].size); } } static void print_tensor_info(struct csinn_tensor *t) { printf("\n=== tensor info ===\n"); printf("shape: "); for (int j = 0; j < t->dim_count; j++) { printf("%d ", t->dim[j]); } printf("\n"); if (t->dtype == CSINN_DTYPE_UINT8) { printf("scale: %f\n", t->qinfo->scale); printf("zero point: %d\n", t->qinfo->zero_point); } printf("data pointer: %p\n", t->data); } /* * Postprocess function */ static void postprocess(void *sess, const char *filename_prefix, BBoxOut *out, int *num) { int output_num, input_num; struct csinn_tensor *input = csinn_alloc_tensor(NULL); struct csinn_tensor *output = csinn_alloc_tensor(NULL); //input_num = csinn_get_input_number(sess); //for (int i = 0; i < input_num; i++) { // input->data = NULL; // csinn_get_input(i, input, sess); // //print_tensor_info(input); // struct csi_tensor *finput = shl_ref_tensor_transform_f32(input); // char filename[FILE_LENGTH] = {0}; // char shape[SHAPE_LENGHT] = {0}; // shape2string(input->dim, input->dim_count, shape, SHAPE_LENGHT); // snprintf(filename, FILE_LENGTH, "%s_input%u_%s.txt", filename_prefix, i, shape); // int input_size = csi_tensor_size(input); //printf("input_size: %d\n", input_size); //save_data_to_file(filename, (float*)finput->data, input_size); //} float *location = (float*)malloc(OUT_SIZE1*sizeof(float)); float *confidence = (float*)malloc(OUT_SIZE2*sizeof(float)); output_num = csinn_get_output_number(sess); for (int i = 0; i < output_num; i++) { output->data = NULL; csinn_get_output(i, output, sess); //print_tensor_info(output); struct csinn_tensor *foutput = shl_ref_tensor_transform_f32(output); //shl_show_top5(foutput, sess); //char filename[FILE_LENGTH] = {0}; //char shape[SHAPE_LENGHT] = {0}; //shape2string(output->dim, output->dim_count, shape, SHAPE_LENGHT); //snprintf(filename, FILE_LENGTH, "%s_output%u_%s.txt", filename_prefix, i, shape); //int output_size = csinn_tensor_size(foutput); //save_data_to_file(filename, (float*)foutput->data, output_size); if (i == 0) memcpy(location, (float *)foutput->data, OUT_SIZE1*sizeof(float)); if (i == 1) memcpy(confidence, (float *)foutput->data, OUT_SIZE2*sizeof(float)); shl_ref_tensor_transform_free_f32(foutput); } //BBoxOut out[100]; BBox gbboxes[num_prior]; *num = ssdforward(location, confidence, priorbox, gbboxes, out); free(location); free(confidence); printf("%d\n", *num); for (int i = 0; i < *num; i++) { fprintf(stderr, "%d, label=%s, score=%f, x1=%f, y1=%f, x2=%f, y2=%f\n", out[i].label, class_name[out[i].label], out[i].score, out[i].xmin, out[i].ymin, out[i].xmax, out[i].ymax); } csinn_free_tensor(input); csinn_free_tensor(output); } void *create_graph(char *params_path) { void *ret; int binary_size; char *params = get_binary_from_file(params_path, &binary_size); if (params == NULL) { return NULL; } char *suffix = params_path + (strlen(params_path) - 7); if (strcmp(suffix, ".params") == 0) { // create general graph ret = csinn_(params); free(params); return ret; } suffix = params_path + (strlen(params_path) - 3); if (strcmp(suffix, ".bm") == 0) { struct shl_bm_sections *section = (struct shl_bm_sections *)(params + 4128); if (section->graph_offset) { ret = csinn_import_binary_model(params); free(params); return ret; } else { ret = csinn_(params + section->params_offset * 4096); free(params); return ret; } } else { free(params); return NULL; } } bool is_looping = true; int main(int argc, char **argv) { char **data_path = NULL; char *params_path = NULL; int input_num = 1; int output_num = 3; int input_group_num = 1; int index = 0; int export_index = 0; PlinkStatus sts = PLINK_STATUS_OK; PlinkPacket sendpkt, recvpkt; PlinkMsg msg; PlinkHandle plink_npu_sink = NULL; ServerParams params; VmemParams vmem_params; void *vmem = NULL; PlinkChannel channel[2]; PlinkObjectInfo feat_map; FILE *fp = NULL; int exitcode = 0; int i; if (argc < (2 + input_num)) { printf("Please set valide args: ./model.elf model.params " "[tensor1/image1 ...] [tensor2/image2 ...]\n"); return -1; } else { if (argc == 3 && get_file_type(argv[2]) == FILE_TXT) { data_path = read_string_from_file(argv[2], &input_group_num); input_group_num /= input_num; } else { data_path = argv + 2; input_group_num = (argc - 2) / input_num; } } parseParams(argc, argv, ¶ms); if (checkParams(¶ms) != 0) { printUsage(argv[0]); return 0; } void *sess = create_graph(argv[1]); uint8_t *input[input_num]; float *finput[input_num]; char filename_prefix[FILE_LENGTH] = {0}; void *input_aligned[input_num]; for (i = 0; i < input_num; i++) { input_aligned[i] = shl_mem_alloc_aligned(input_size[i], 0); } uint64_t start_time, end_time; uint64_t _start_time, _end_time; //int frames = argc > 1 ? atoi(argv[1]) : 1000; int frames = 1000; //char *dumpname = argc > 2 ? argv[2] : NULL; char *dumpname = NULL; if (dumpname != NULL) { fp = fopen(dumpname, "wb"); if (fp == NULL) errExit("fopen"); } if (VMEM_create(&vmem) != VMEM_STATUS_OK) errExit("Failed to create VMEM."); int fd_mem = open("/dev/mem", O_RDWR | O_SYNC); if (fd_mem == -1) { printf("ERROR: failed to open: %s\n", "/dev/mem"); return -1; } int fd_src_mem = open("/dev/mem", O_RDWR | O_SYNC); if (fd_src_mem < 0) { printf("%s: failed to open /dev/mem", MODULE_NAME); return -1; } BBoxOut out[100]; int out_num = 0; if (PLINK_create(&plink_npu_sink, "/tmp/plink_npu_rgb.test", PLINK_MODE_CLIENT) != PLINK_STATUS_OK) errExit("Failed to create PLINK."); if (PLINK_connect(plink_npu_sink, NULL) != PLINK_STATUS_OK) errExit("Failed to connect to server."); int frmcnt = 0; // while loop to receive shm picture do { sts = PLINK_recv(plink_npu_sink, 0, &recvpkt); memset(&vmem_params, 0, sizeof(vmem_params)); if (recvpkt.fd != PLINK_INVALID_FD) { // dmabuf fd vmem_params.fd = recvpkt.fd; if (VMEM_import(vmem, &vmem_params) != VMEM_STATUS_OK) errExit("Failed to import fd."); printf("%s: recvpkt.fd<%d> phy<0x%lx>\n", MODULE_NAME, vmem_params.fd, vmem_params.phy_address); } for (i = 0; i < recvpkt.num; i++) { PlinkDescHdr *hdr = (PlinkDescHdr *)(recvpkt.list[i]); if (hdr->type == PLINK_TYPE_2D_RGB) { uint8_t *vaddr = 0; PlinkRGBInfo *pic = (PlinkRGBInfo *)(recvpkt.list[i]); printf("[CLIENT] Received frame %d 0x%010llx: %dx%d, stride = %d\n", pic->header.id, pic->bus_address_b, pic->img_width, pic->img_height, pic->stride_b); int size_stride = 3 * pic->stride_b * pic->stride_b; if (recvpkt.fd == PLINK_INVALID_FD) { // physical address vaddr = (uint8_t *) mmap(0, size_stride, PROT_READ | PROT_WRITE, MAP_SHARED, fd_mem, pic->bus_address_b); } // return the buffer to source msg.header.type = PLINK_TYPE_MESSAGE; msg.header.size = DATA_SIZE(PlinkMsg); msg.msg = hdr->id; sendpkt.list[0] = &msg; sendpkt.num = 1; sendpkt.fd = PLINK_INVALID_FD; if (PLINK_send(plink_npu_sink, 0, &sendpkt) == PLINK_STATUS_ERROR) errExit("Failed to send data."); _start_time = shl_get_timespec(); if (recvpkt.fd == PLINK_INVALID_FD) { // physical address csinn_run(vaddr, sess); } else { csinn_run(&vmem_params.fd, sess); } _end_time = shl_get_timespec(); printf("Run graph execution time: %.5fms, FPS=%.2f\n", ((float)(_end_time-_start_time))/1000000, 1000000000.0/((float)(_end_time-_start_time))); //snprintf(filename_prefix, FILE_LENGTH, "%s", basename(data_path[i * input_num])); _start_time = shl_get_timespec(); postprocess(sess, filename_prefix, out, &out_num); _end_time = shl_get_timespec(); printf("postProcess execution time: %.5fms\n", ((float)(_end_time-_start_time))/1000000); if (recvpkt.fd == PLINK_INVALID_FD) // physical address munmap(vaddr, size_stride); } else if (hdr->type == PLINK_TYPE_MESSAGE) { PlinkMsg *msg = (PlinkMsg *)(recvpkt.list[i]); if (msg->msg == PLINK_EXIT_CODE) { exitcode = 1; printf("Exit\n"); break; } } } if (recvpkt.fd != PLINK_INVALID_FD) { // dmabuf fd if (VMEM_release(vmem, &vmem_params) != VMEM_STATUS_OK) errExit("Failed to release buffer."); close(recvpkt.fd); } frmcnt++; #if 0 if (frmcnt >= frames) { msg.header.type = PLINK_TYPE_MESSAGE; msg.header.size = DATA_SIZE(PlinkMsg); msg.msg = PLINK_EXIT_CODE; sendpkt.list[0] = &msg; sendpkt.num = 1; sendpkt.fd = PLINK_INVALID_FD; if (PLINK_send(plink_npu_sink, 0, &sendpkt) == PLINK_STATUS_ERROR) errExit("Failed to send data."); break; } #endif } while (exitcode == 0); cleanup: sleep(1); // Sleep one second to make sure server is ready for exit PLINK_close(plink_npu_sink, 0); if (fp != NULL) fclose(fp); for (i = 0; i < input_num; i++) { shl_mem_free(input_aligned[i]); } csinn_session_deinit(sess); csinn_free_session(sess); return 0; }