Skip to content

Commit

Permalink
Benchmark code.
Browse files Browse the repository at this point in the history
Signed-off-by: Rule Timothy (VM/EMT3) <Timothy.Rule@de.bosch.com>
  • Loading branch information
timrulebosch committed Apr 29, 2024
1 parent 9472f17 commit cff79ae
Show file tree
Hide file tree
Showing 5 changed files with 365 additions and 0 deletions.
65 changes: 65 additions & 0 deletions extra/benchmark/Taskfile.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@

version: '3'

vars:
GO_BUILDER_IMAGE: golang:bullseye
GCC_BUILDER_IMAGE: golang:bullseye

tasks:

benchmark-tools:
run: when_changed
dir: '{{.USER_WORKING_DIR}}'
cmds:
- mkdir -p build
- docker run --rm -v $(pwd):/tmp -w /tmp {{.GO_BUILDER_IMAGE}} go build -o build/benchmark-gen benchmark-gen.go
sources:
- benchmark-gen.go
generates:
- build/benchmark-gen

benchmark-gen:
run: always
deps:
- benchmark-tools
dir: '{{.USER_WORKING_DIR}}'
vars:
SIGNALCOUNT: '{{.SIGNALCOUNT | default 2}}'
cmds:
- mkdir -p build
- build/benchmark-gen --signals {{.SIGNALCOUNT}}
sources:
- build/benchmark-gen
- template/network_ct_front.tmpl
- template/network_ct_body.tmpl
generates:
- build/network_ct.c

benchmark-build:
run: always
dir: '{{.USER_WORKING_DIR}}'
vars:
SIGNALCOUNT: '{{.SIGNALCOUNT | default 2}}'
cmds:
- docker run --rm -v $(pwd):/tmp -w /tmp {{.GCC_BUILDER_IMAGE}}
gcc -shared -o build/network_ct.so -Wall -fpic build/network_ct.c
- docker run --rm -v $(pwd):/tmp -w /tmp {{.GCC_BUILDER_IMAGE}}
gcc -o build/bench_net -Wall bench_net.c -ldl
sources:
- build/network_ct.c
- bench_net.c
generates:
- build/network_ct.so
- build/bench_net

benchmark:
run: always
dir: '{{.USER_WORKING_DIR}}'
vars:
SIGNALCOUNT: '{{.SIGNALCOUNT | default 1000}}'
cmds:
- task: benchmark-gen
vars: { SIGNALCOUNT: '{{.SIGNALCOUNT}}' }
- task: benchmark-build
- ls -R build/
- build/bench_net {{.SIGNALCOUNT}}
181 changes: 181 additions & 0 deletions extra/benchmark/bench_net_ct.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@

#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <dlfcn.h>
#include <time.h>
#include <unistd.h>


struct timespec get_timespec_now(void)
{
struct timespec ts = {};
clock_gettime(CLOCK_MONOTONIC, &ts);
return ts;
}


uint64_t get_elapsedtime_ns(struct timespec ref)
{
struct timespec now = get_timespec_now();
if (ref.tv_sec == now.tv_sec) {
return now.tv_nsec - ref.tv_nsec;
} else {
return ((now.tv_sec - ref.tv_sec) * 1000000000) +
(now.tv_nsec - ref.tv_nsec);
}
}

double ns_to_us_to_sec(uint64_t t_ns)
{
uint32_t t_us = t_ns / 1000;
return t_us / 1000000.0;
}

typedef int (*PackFunc)(uint8_t*, const void*, size_t);
typedef int (*UnpackFunc)(void*, const uint8_t*, size_t);
typedef bool (*RangeFunc)(uint8_t value);
typedef double (*DecodeFunc)(uint8_t value);
typedef uint8_t (*EncodeFunc)(double signal);


typedef struct signal_t {
int count;
PackFunc pack_func;
UnpackFunc unpack_func;
RangeFunc range_func;
DecodeFunc decode_func;
EncodeFunc encode_func;

uint8_t buffer[8];
uint8_t pack[16];
} signal_t;


void* _get_func_handle(void* handle, const char* fmt, int index)
{
char b[1000];
snprintf(b, 1000, fmt, index);
// printf(" loading function : %s\n", b);
void* func = dlsym(handle, b);
if (func == NULL) {
printf("Could not load function from library! (%s)", dlerror());
exit(1);
}
return func;
}


void run_bench_ct(double* signals, signal_t* st, int count, int steps)
{
struct timespec _ts = get_timespec_now();

for (int step = 0; step < steps; step++) {
for (int i = 0; i < count; i++) {
// Encode
double original = signals[i];
double value = original + 1;
// printf(" signal[%d] val=%f (orig=%f) .. ", i, value, original);
if (value > 100) value = 0.0;
st[i].buffer[0] = st[i].encode_func(value);
st[i].pack_func(st[i].pack, st[i].buffer, 8);
// Decode
st[i].buffer[0] = 0;
st[i].unpack_func(st[i].buffer, st[i].pack, 8);
if (st[i].range_func(st[i].buffer[0])) {
value = st[i].decode_func(st[i].buffer[0]);
} else {
value = value + 1;
// printf(" .. out of range .. ");
}
// printf("val=%f (orig=%f)\n", value, original);
signals[i] = value;
}
}

uint64_t time_ns = get_elapsedtime_ns(_ts);
printf("CANtools: Time %.9f (steps=%d, signals=%d)\n",
ns_to_us_to_sec(time_ns), steps, count);
}


void run_bench_loop(double* signals, signal_t* st, int count, int steps)
{
struct timespec _ts = get_timespec_now();

for (int step = 0; step < steps; step++) {
for (int i = 0; i < count; i++) {
// Encode
double original = signals[i];
double value = original + 1;
if (value > 100) value = 0.0;
st[i].buffer[0] = (uint8_t)(value / 0.5);
// memset(st[i].pack, 0, 8);
st[i].pack[0] |=
(uint8_t)((uint8_t)(st[i].buffer[0] << 1u) & 0x7eu);
// Decode
st[i].buffer[0] = (uint8_t)((uint8_t)(st[i].pack[0] & 0x7eu) >> 1u);
;
if (st[i].buffer[0] <= 200u) {
value = (double)st[i].buffer[0] * 0.5;
} else {
value = value + 1;
// printf(" .. out of range .. ");
}
// printf("val=%f (orig=%f)\n", value, original);
signals[i] = value;
}
}

uint64_t time_ns = get_elapsedtime_ns(_ts);
printf("LOOP: Time %.9f (steps=%d, signals=%d)\n",
ns_to_us_to_sec(time_ns), steps, count);
}


int main(int argc, char** argv)
{
if (argc != 2) {
printf("Incorrect arguments!");
exit(1);
}
int signalCount = argv[1] ? atoi(argv[1]) : 0;
int steps = 10;

printf("Running Network CANtools benchmark\n");
printf("signals : %d\n", signalCount);

void* handle = dlopen("build/network_ct.so", RTLD_NOW | RTLD_GLOBAL);
if (handle == NULL) {
printf("Could not open message library! (%s)", dlerror());
exit(1);
}

printf(" loading signal functions ...\n");
signal_t* signal_table = calloc(signalCount, sizeof(signal_t));
for (int i = 0; i < signalCount; i++) {
signal_table[i].pack_func =
_get_func_handle(handle, "message%d_pack", i);
signal_table[i].unpack_func =
_get_func_handle(handle, "message%d_unpack", i);
signal_table[i].range_func =
_get_func_handle(handle, "message%d_signal_is_in_range", i);
signal_table[i].decode_func =
_get_func_handle(handle, "message%d_signal_decode", i);
signal_table[i].encode_func =
_get_func_handle(handle, "message%d_signal_encode", i);
}

double* signals = calloc(signalCount, sizeof(double));
for (int i = 0; i < signalCount; i++) {
signals[i] = i % 100;
}
printf(" run cantools based benchmark ...\n");
run_bench_ct(signals, signal_table, signalCount, steps);
run_bench_loop(signals, signal_table, signalCount, steps);


exit(0);
}
28 changes: 28 additions & 0 deletions extra/benchmark/benchmark-gen.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package main

import (
"flag"
"fmt"
"os"
"text/template"
)

func main() {
var signalCount = flag.Int("signals", 1, "benchmark N signals")
var netCt = flag.String("net_ct", "network_ct", "generated network (on basis cantools)")
flag.Parse()

fmt.Printf("Generate benchmark code for %d signals ...\n", *signalCount)
file, _ := os.Create(fmt.Sprintf("build/%s.c", *netCt))
defer file.Close()

// Front matter
tmpl := template.Must(template.ParseFiles(fmt.Sprintf("template/%s_front.tmpl", *netCt)))
tmpl.Execute(file, nil)

// Body content
tmpl = template.Must(template.ParseFiles(fmt.Sprintf("template/%s_body.tmpl", *netCt)))
for i := 0; i < *signalCount; i++ {
tmpl.Execute(file, i)
}
}
54 changes: 54 additions & 0 deletions extra/benchmark/template/network_ct_body.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@

int message{{.}}_pack(
uint8_t *dst_p,
const struct message_t *src_p,
size_t size)
{
if (size < 8u) {
return (-EINVAL);
}

memset(&dst_p[0], 0, 8);

dst_p[0] |= pack_left_shift_u8(src_p->radius, 1u, 0x7eu);

return (8);
}

int message{{.}}_unpack(
struct message_t *dst_p,
const uint8_t *src_p,
size_t size)
{
if (size < 8u) {
return (-EINVAL);
}

dst_p->radius = unpack_right_shift_u8(src_p[0], 1u, 0x7eu);

return (0);
}

int message{{.}}_init(struct message_t *msg_p)
{
if (msg_p == NULL) return -1;

memset(msg_p, 0, sizeof(struct message_t));

return 0;
}

uint8_t message{{.}}_signal_encode(double value)
{
return (uint8_t)(value / 0.1);
}

double message{{.}}_signal_decode(uint8_t value)
{
return ((double)value * 0.1);
}

bool message{{.}}_signal_is_in_range(uint8_t value)
{
return (value <= 50u);
}
37 changes: 37 additions & 0 deletions extra/benchmark/template/network_ct_front.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@

#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
#include <string.h>

#ifndef EINVAL
# define EINVAL 22
#endif



struct message_t {
/**
* Range: 0..50 (0..5 m)
* Scale: 0.1
* Offset: 0
*/
uint8_t radius;
};

static inline uint8_t pack_left_shift_u8(
uint8_t value,
uint8_t shift,
uint8_t mask)
{
return (uint8_t)((uint8_t)(value << shift) & mask);
}

static inline uint8_t unpack_right_shift_u8(
uint8_t value,
uint8_t shift,
uint8_t mask)
{
return (uint8_t)((uint8_t)(value & mask) >> shift);
}

0 comments on commit cff79ae

Please sign in to comment.