Initial commit: Loongson FPGA SoC project for 2026 CIC-IEC
This commit is contained in:
14
sdk/software/examples/c_prg/inner_product/Makefile
Normal file
14
sdk/software/examples/c_prg/inner_product/Makefile
Normal file
@@ -0,0 +1,14 @@
|
||||
TARGET = inner_product
|
||||
|
||||
CFLAGS += -O3 -g
|
||||
|
||||
#根据SIMU宏选择串口波特率,0:FPGA上板;1:仿真
|
||||
CFLAGS += -DSIMU=0
|
||||
|
||||
C_SRCS := $(wildcard ./*.c )
|
||||
|
||||
OBJDIR = obj
|
||||
COMMON_DIR = ../../../bsp
|
||||
GCC_DIR=../../../../toolchains/loongson-gnu-toolchain-8.3-x86_64-loongarch32r-linux-gnusf-v2.0
|
||||
PICOLIBC_DIR=../../../../toolchains/picolibc
|
||||
include ../../../bsp/common.mk
|
||||
446
sdk/software/examples/c_prg/inner_product/inner_product.c
Normal file
446
sdk/software/examples/c_prg/inner_product/inner_product.c
Normal file
@@ -0,0 +1,446 @@
|
||||
/*
|
||||
Copyright 2008 Adobe Systems Incorporated
|
||||
Copyright 2018-2019 Chris Cox
|
||||
Distributed under the MIT License (see accompanying file LICENSE_1_0_0.txt
|
||||
or a copy at http://stlab.adobe.com/licenses.html )
|
||||
|
||||
|
||||
Goal: Test performance of various idioms for calculating the inner product of two sequences.
|
||||
|
||||
NOTE: Inner products are common in mathematical and geometry processing applications,
|
||||
plus some audio and image processing.
|
||||
|
||||
|
||||
Assumptions:
|
||||
1) The compiler will optimize inner product operations.
|
||||
|
||||
2) The compiler may recognize ineffecient inner product idioms
|
||||
and substitute efficient methods when it can.
|
||||
NOTE: the best method is highly dependent on the data types and CPU architecture
|
||||
|
||||
3) std::inner_product will be well optimized for all types and containers.
|
||||
|
||||
|
||||
*/
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
#include <time.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
/******************************************************************************/
|
||||
/******************************************************************************/
|
||||
//BSP板级支持包所需全局变量
|
||||
unsigned long UART_BASE = 0xbfe001e0; //UART16550的虚地址
|
||||
unsigned long CONFREG_UART_BASE = 0xbfafff10; //CONFREG模拟UART的虚地址
|
||||
unsigned long CONFREG_TIMER_BASE = 0xbfafe000; //CONFREG计数器的虚地址
|
||||
unsigned long CONFREG_CLOCKS_PER_SEC = 100000000L; //CONFREG时钟频率
|
||||
unsigned long CORE_CLOCKS_PER_SEC = 33000000L; //处理器核时钟频率
|
||||
|
||||
clock_t start_time, end_time;
|
||||
|
||||
// this constant may need to be adjusted to give reasonable minimum times
|
||||
// For best results, times should be about 1.0 seconds for the minimum test run
|
||||
int iterations = 5;
|
||||
|
||||
|
||||
// 8000 items, or between 8 and 64k of data
|
||||
// this is intended to remain within the L2 cache of most common CPUs
|
||||
const int SIZE = 8000;
|
||||
|
||||
|
||||
// initial value for filling our arrays, may be changed from the command line
|
||||
int32_t init_value_8 = 3;
|
||||
int32_t init_value_16 = 211;
|
||||
int32_t init_value_32 = 1065;
|
||||
float init_value_f16 = 5.0;
|
||||
double init_value_f32 = 365.0;
|
||||
|
||||
/******************************************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
void fill_8(int8_t * first, int8_t * last, int8_t value) {
|
||||
while (first != last) *first++ = (int8_t)(value);
|
||||
}
|
||||
|
||||
void fill_u8(uint8_t * first, uint8_t * last, uint8_t value) {
|
||||
while (first != last) *first++ = (uint8_t)(value);
|
||||
}
|
||||
|
||||
void fill_16(int16_t * first, int16_t * last, int16_t value) {
|
||||
while (first != last) *first++ = (int16_t)(value);
|
||||
}
|
||||
|
||||
void fill_u16(uint16_t * first, uint16_t * last, uint16_t value) {
|
||||
while (first != last) *first++ = (uint16_t)(value);
|
||||
}
|
||||
|
||||
void fill_32(int32_t * first, int32_t * last, int32_t value) {
|
||||
while (first != last) *first++ = (int32_t)(value);
|
||||
}
|
||||
|
||||
void fill_u32(uint32_t * first, uint32_t * last, uint32_t value) {
|
||||
while (first != last) *first++ = (uint32_t)(value);
|
||||
}
|
||||
|
||||
void fill_f16(float * first, float * last, float value) {
|
||||
while (first != last) *first++ = (float)(value);
|
||||
}
|
||||
|
||||
void fill_f32(double * first, double * last, double value) {
|
||||
while (first != last) *first++ = (double)(value);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/******************************************************************************/
|
||||
// a trivial for loop
|
||||
|
||||
void test_inner_product_8( const int8_t* first, const int8_t* second, const size_t count, const char *label) {
|
||||
|
||||
start_time = clock();
|
||||
|
||||
for(int i = 0; i < iterations; ++i) {
|
||||
|
||||
int8_t sum = 0 ;
|
||||
for (size_t j = 0; j < count; ++j) {
|
||||
sum += first[j] * second[j];
|
||||
}
|
||||
|
||||
//check_sum( sum, label );
|
||||
int8_t target = (int8_t)(init_value_8)*(int8_t)(init_value_8)*SIZE;
|
||||
if ( abs( sum - target ) > (int8_t)(1.0e-6) )
|
||||
printf("test %s failed\n", label);
|
||||
}
|
||||
|
||||
// need the labels to remain valid until we print the summary
|
||||
end_time = clock();
|
||||
|
||||
double time_cost = (end_time - start_time)/ (double)(CLOCKS_PER_SEC);
|
||||
printf("CLOCKS_PER_SEC=%d\n",CLOCKS_PER_SEC);
|
||||
printf("\"%s, %lu items\" %f sec\n",
|
||||
label,
|
||||
count,
|
||||
time_cost);
|
||||
}
|
||||
|
||||
void test_inner_product_u8( const uint8_t* first, const uint8_t* second, const size_t count, const char *label) {
|
||||
|
||||
start_time = clock();
|
||||
|
||||
for(int i = 0; i < iterations; ++i) {
|
||||
|
||||
uint8_t sum = 0 ;
|
||||
for (size_t j = 0; j < count; ++j) {
|
||||
sum += first[j] * second[j];
|
||||
}
|
||||
|
||||
//check_sum( sum, label );
|
||||
uint8_t target = (uint8_t)(init_value_8)*(uint8_t)(init_value_8)*SIZE;
|
||||
if ( ( sum - target ) > (uint8_t)(1.0e-6) )
|
||||
printf("test %s failed\n", label);
|
||||
}
|
||||
|
||||
// need the labels to remain valid until we print the summary
|
||||
end_time = clock();
|
||||
|
||||
double time_cost = (end_time - start_time)/ (double)(CLOCKS_PER_SEC);
|
||||
printf("\"%s, %lu items\" %f sec\n",
|
||||
label,
|
||||
count,
|
||||
time_cost);
|
||||
}
|
||||
|
||||
void test_inner_product_16( const int16_t* first, const int16_t* second, const size_t count, const char *label) {
|
||||
|
||||
start_time = clock();
|
||||
|
||||
for(int i = 0; i < iterations; ++i) {
|
||||
|
||||
int16_t sum = 0 ;
|
||||
for (size_t j = 0; j < count; ++j) {
|
||||
sum += first[j] * second[j];
|
||||
}
|
||||
|
||||
//check_sum( sum, label );
|
||||
int16_t target = (int16_t)(init_value_16)*(int16_t)(init_value_16)*SIZE;
|
||||
if ( abs( sum - target ) > (int16_t)(1.0e-6) )
|
||||
printf("test %s failed\n", label);
|
||||
}
|
||||
|
||||
// need the labels to remain valid until we print the summary
|
||||
end_time = clock();
|
||||
|
||||
double time_cost = (end_time - start_time)/ (double)(CLOCKS_PER_SEC);
|
||||
printf("\"%s, %lu items\" %f sec\n",
|
||||
label,
|
||||
count,
|
||||
time_cost);
|
||||
}
|
||||
|
||||
void test_inner_product_u16( const uint16_t* first, const uint16_t* second, const size_t count, const char *label) {
|
||||
|
||||
start_time = clock();
|
||||
|
||||
for(int i = 0; i < iterations; ++i) {
|
||||
|
||||
uint16_t sum = 0 ;
|
||||
for (size_t j = 0; j < count; ++j) {
|
||||
sum += first[j] * second[j];
|
||||
}
|
||||
|
||||
//check_sum( sum, label );
|
||||
uint16_t target = (uint16_t)(init_value_16)*(uint16_t)(init_value_16)*SIZE;
|
||||
if ( ( sum - target ) > (uint16_t)(1.0e-6) )
|
||||
printf("test %s failed\n", label);
|
||||
}
|
||||
|
||||
// need the labels to remain valid until we print the summary
|
||||
end_time = clock();
|
||||
|
||||
double time_cost = (end_time - start_time)/ (double)(CLOCKS_PER_SEC);
|
||||
printf("\"%s, %lu items\" %f sec\n",
|
||||
label,
|
||||
count,
|
||||
time_cost);
|
||||
}
|
||||
|
||||
void test_inner_product_32( const int32_t* first, const int32_t* second, const size_t count, const char *label) {
|
||||
|
||||
start_time = clock();
|
||||
|
||||
for(int i = 0; i < iterations; ++i) {
|
||||
|
||||
int32_t sum = 0 ;
|
||||
for (size_t j = 0; j < count; ++j) {
|
||||
sum += first[j] * second[j];
|
||||
}
|
||||
|
||||
//check_sum( sum, label );
|
||||
int32_t target = (int32_t)(init_value_32)*(int32_t)(init_value_32)*SIZE;
|
||||
if ( abs( sum - target ) > (int32_t)(1.0e-6) )
|
||||
printf("test %s failed\n", label);
|
||||
}
|
||||
|
||||
// need the labels to remain valid until we print the summary
|
||||
end_time = clock();
|
||||
|
||||
double time_cost = (end_time - start_time)/ (double)(CLOCKS_PER_SEC);
|
||||
printf("\"%s, %lu items\" %f sec\n",
|
||||
label,
|
||||
count,
|
||||
time_cost);
|
||||
}
|
||||
|
||||
void test_inner_product_u32( const uint32_t* first, const uint32_t* second, const size_t count, const char *label) {
|
||||
|
||||
start_time = clock();
|
||||
|
||||
for(int i = 0; i < iterations; ++i) {
|
||||
|
||||
uint32_t sum = 0 ;
|
||||
for (size_t j = 0; j < count; ++j) {
|
||||
sum += first[j] * second[j];
|
||||
}
|
||||
|
||||
//check_sum( sum, label );
|
||||
uint32_t target = (uint32_t)(init_value_32)*(uint32_t)(init_value_32)*SIZE;
|
||||
if ( ( sum - target ) > (uint32_t)(1.0e-6) )
|
||||
printf("test %s failed\n", label);
|
||||
}
|
||||
|
||||
// need the labels to remain valid until we print the summary
|
||||
end_time = clock();
|
||||
|
||||
double time_cost = (end_time - start_time)/ (double)(CLOCKS_PER_SEC);
|
||||
printf("\"%s, %lu items\" %f sec\n",
|
||||
label,
|
||||
count,
|
||||
time_cost);
|
||||
}
|
||||
|
||||
void test_inner_product_f16( const float* first, const float* second, const size_t count, const char *label) {
|
||||
|
||||
start_time = clock();
|
||||
|
||||
for(int i = 0; i < iterations; ++i) {
|
||||
|
||||
float sum = 0 ;
|
||||
for (size_t j = 0; j < count; ++j) {
|
||||
sum += first[j] * second[j];
|
||||
}
|
||||
|
||||
//check_sum( sum, label );
|
||||
float target = (float)(init_value_f16)*(float)(init_value_f16)*SIZE;
|
||||
if ( fabs( sum - target ) > (float)(1.0e-6) )
|
||||
printf("test %s failed\n", label);
|
||||
}
|
||||
|
||||
// need the labels to remain valid until we print the summary
|
||||
end_time = clock();
|
||||
|
||||
double time_cost = (end_time - start_time)/ (double)(CLOCKS_PER_SEC);
|
||||
printf("\"%s, %lu items\" %f sec\n",
|
||||
label,
|
||||
count,
|
||||
time_cost);
|
||||
}
|
||||
|
||||
void test_inner_product_f32( const double* first, const double* second, const size_t count, const char *label) {
|
||||
|
||||
start_time = clock();
|
||||
|
||||
for(int i = 0; i < iterations; ++i) {
|
||||
|
||||
double sum = 0 ;
|
||||
for (size_t j = 0; j < count; ++j) {
|
||||
sum += first[j] * second[j];
|
||||
}
|
||||
|
||||
//check_sum( sum, label );
|
||||
double target = (double)(init_value_f32)*(double)(init_value_f32)*SIZE;
|
||||
if ( fabs( sum - target ) > (double)(1.0e-6) )
|
||||
printf("test %s failed\n", label);
|
||||
}
|
||||
|
||||
// need the labels to remain valid until we print the summary
|
||||
end_time = clock();
|
||||
|
||||
double time_cost = (end_time - start_time)/ (double)(CLOCKS_PER_SEC);
|
||||
printf("\"%s, %lu items\" %f sec\n",
|
||||
label,
|
||||
count,
|
||||
time_cost);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
// NOTE - can't make generic template template argument without C++17
|
||||
// I would like to have TestOneFunction to handle all the types and if's, but need to use different types with it inside
|
||||
// see sum_sequence.cpp
|
||||
|
||||
|
||||
void TestOneType_8()
|
||||
{
|
||||
int8_t data[SIZE];
|
||||
int8_t dataB[SIZE];
|
||||
|
||||
fill_8(data, data+SIZE, (int8_t)(init_value_8));
|
||||
fill_8(dataB, dataB+SIZE, (int8_t)(init_value_8));
|
||||
|
||||
test_inner_product_8( data, dataB, SIZE, "int_8 inner_product1 to int_8");
|
||||
}
|
||||
|
||||
void TestOneType_u8()
|
||||
{
|
||||
uint8_t data[SIZE];
|
||||
uint8_t dataB[SIZE];
|
||||
|
||||
fill_u8(data, data+SIZE, (uint8_t)(init_value_8));
|
||||
fill_u8(dataB, dataB+SIZE, (uint8_t)(init_value_8));
|
||||
|
||||
test_inner_product_u8( data, dataB, SIZE, "uint_8 inner_product1 to uint_8");
|
||||
}
|
||||
|
||||
|
||||
void TestOneType_16()
|
||||
{
|
||||
int16_t data[SIZE];
|
||||
int16_t dataB[SIZE];
|
||||
|
||||
fill_16(data, data+SIZE, (int16_t)(init_value_16));
|
||||
fill_16(dataB, dataB+SIZE, (int16_t)(init_value_16));
|
||||
|
||||
test_inner_product_16( data, dataB, SIZE, "int_16 inner_product1 to int_16");
|
||||
}
|
||||
|
||||
void TestOneType_u16()
|
||||
{
|
||||
uint16_t data[SIZE];
|
||||
uint16_t dataB[SIZE];
|
||||
|
||||
fill_u16(data, data+SIZE, (uint16_t)(init_value_16));
|
||||
fill_u16(dataB, dataB+SIZE, (uint16_t)(init_value_16));
|
||||
|
||||
test_inner_product_u16( data, dataB, SIZE, "uint_16 inner_product1 to uint_16");
|
||||
}
|
||||
|
||||
void TestOneType_32()
|
||||
{
|
||||
int32_t data[SIZE];
|
||||
int32_t dataB[SIZE];
|
||||
|
||||
fill_32(data, data+SIZE, (int32_t)(init_value_32));
|
||||
fill_32(dataB, dataB+SIZE, (int32_t)(init_value_32));
|
||||
|
||||
test_inner_product_32( data, dataB, SIZE, "int_32 inner_product1 to int_32");
|
||||
}
|
||||
|
||||
void TestOneType_u32()
|
||||
{
|
||||
uint32_t data[SIZE];
|
||||
uint32_t dataB[SIZE];
|
||||
|
||||
fill_u32(data, data+SIZE, (uint32_t)(init_value_32));
|
||||
fill_u32(dataB, dataB+SIZE, (uint32_t)(init_value_32));
|
||||
|
||||
test_inner_product_u32( data, dataB, SIZE, "uint_32 inner_product1 to uint_32");
|
||||
}
|
||||
|
||||
void TestOneType_f16()
|
||||
{
|
||||
float data[SIZE];
|
||||
float dataB[SIZE];
|
||||
|
||||
fill_f16(data, data+SIZE, (float)(init_value_f16));
|
||||
fill_f16(dataB, dataB+SIZE, (float)(init_value_f16));
|
||||
|
||||
test_inner_product_f16( data, dataB, SIZE, "float inner_product1 to float");
|
||||
}
|
||||
|
||||
void TestOneType_f32()
|
||||
{
|
||||
double data[SIZE];
|
||||
double dataB[SIZE];
|
||||
|
||||
fill_f32(data, data+SIZE, (double)(init_value_f32));
|
||||
fill_f32(dataB, dataB+SIZE, (double)(init_value_f32));
|
||||
|
||||
test_inner_product_f32( data, dataB, SIZE, "double inner_product1 to double");
|
||||
}
|
||||
/******************************************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
|
||||
// output command for documentation:
|
||||
int i;
|
||||
// for (i = 0; i < argc; ++i)
|
||||
// printf("%s ", argv[i] );
|
||||
// printf("\n");
|
||||
|
||||
if (argc > 1) iterations = atoi(argv[1]);
|
||||
// if (argc > 2) init_value = (int32_t) atoi(argv[2]);
|
||||
|
||||
|
||||
TestOneType_8();
|
||||
TestOneType_u8();
|
||||
TestOneType_16();
|
||||
TestOneType_u16();
|
||||
TestOneType_32();
|
||||
TestOneType_u32();
|
||||
|
||||
TestOneType_f16();
|
||||
TestOneType_f32();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// the end
|
||||
/******************************************************************************/
|
||||
/******************************************************************************/
|
||||
Reference in New Issue
Block a user