Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move examples to tests as performance testing #13

Merged
merged 4 commits into from
Apr 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ run-test:

## test Run tests (e.g., make test ARCH=generic)
test:
@$(eval TECH_FILTER := $(if $(TECH),$(shell echo $(TECH) | tr ',' '|'),.*)) # Convert TECH to regex filter
@$(eval TECH_FILTER := $(if $(TECH),$(shell echo $(TECH) | tr ',' '|'),.*))
@$(eval TESTS := $(shell find tests/arch/$(ARCH) -type f -name 'main.c' | grep -E "$(TECH_FILTER)" | sed 's|/main.c||' | sed 's|tests/||'))
@for test in $(TESTS); do \
$(MAKE) run-test ARCH=$(ARCH) TECH=$(TECH) TEST=$$test || exit 1; \
Expand All @@ -50,7 +50,7 @@ build-example:

## build-examples Build examples (e.g., make build-examples ARCH=generic)
build-examples:
@$(eval TECH_FILTER := $(if $(TECH),$(shell echo $(TECH) | tr ',' '|'),.*)) # Convert TECH to regex filter
@$(eval TECH_FILTER := $(if $(TECH),$(shell echo $(TECH) | tr ',' '|'),.*))
@$(eval EXAMPLES := $(shell find examples/arch/$(ARCH) -type f -name 'main.c' | grep -E "$(TECH_FILTER)" | sed 's|/main.c||' | sed 's|examples/||'))
@for example in $(EXAMPLES); do \
$(MAKE) build-example ARCH=$(ARCH) TECH=$(TECH) EXAMPLE=$$example || exit 1; \
Expand All @@ -64,7 +64,7 @@ run-example:

# run-examples Run examples (e.g., make run-examples ARCH=generic)
run-examples:
@$(eval TECH_FILTER := $(if $(TECH),$(shell echo $(TECH) | tr ',' '|'),.*)) # Convert TECH to regex filter
@$(eval TECH_FILTER := $(if $(TECH),$(shell echo $(TECH) | tr ',' '|'),.*))
@$(eval EXAMPLES := $(shell find examples/arch/$(ARCH) -type f -name 'main.c' | grep -E "$(TECH_FILTER)" | sed 's|/main.c||' | sed 's|examples/||'))
@for example in $(EXAMPLES); do \
$(MAKE) run-example ARCH=$(ARCH) TECH=$(TECH) EXAMPLE=$$example || exit 1; \
Expand Down
37 changes: 0 additions & 37 deletions examples/arch/arm/cmsis-dsp/neuron/main.c

This file was deleted.

37 changes: 0 additions & 37 deletions examples/arch/arm/neon/neuron/main.c

This file was deleted.

32 changes: 0 additions & 32 deletions examples/arch/generic/neuron/main.c

This file was deleted.

9 changes: 9 additions & 0 deletions include/nn_test.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#ifndef NN_TEST_H
#define NN_TEST_H

#include <time.h>

// nn_timespec_diff_ns returns the difference between two timespec structs in nanoseconds.
long long nn_timespec_diff_ns(struct timespec *start, struct timespec *end);

#endif // NN_TEST_H
8 changes: 8 additions & 0 deletions src/nn_test.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#define _POSIX_C_SOURCE 199309L
#include "nn_test.h"
#include <time.h>

// nn_timespec_diff_ns returns the difference between two timespec structs in nanoseconds.
long long nn_timespec_diff_ns(struct timespec *start, struct timespec *end) {
return (end->tv_sec - start->tv_sec) * 1000000000LL + (end->tv_nsec - start->tv_nsec);
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,22 @@
#include "nn_app.h"
#include "nn_config.h"
#include "nn_dot_product.h"
#include "nn_test.h"
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

// timespec_diff_ns returns the difference between two timespec structs in nanoseconds.
static long long timespec_diff_ns(struct timespec *start, struct timespec *end) {
return (end->tv_sec - start->tv_sec) * 1000000000LL + (end->tv_nsec - start->tv_nsec);
}

int main(int argc, char *argv[]) {
nn_init_app(argc, argv);

if (!nn_cmsis_dsp_available()) {
printf("dot_product (CMSIS): ARM CMSIS-DSP not available\n");
printf("ARM CMSIS-DSP not available\n");
}

// Init vars
const int n_runs = 1000;
const int n_vectors = 100000;
long long total_time = 0;
struct timespec start, end;
float *a = malloc(n_vectors * sizeof(float));
float *b = malloc(n_vectors * sizeof(float));
Expand All @@ -30,15 +27,14 @@ int main(int argc, char *argv[]) {
b[i] = (float)rand() / (float)RAND_MAX;
}

// Benchmark CMSIS implementation
long long total_time_cmsis = 0;
// Benchmark
for (int i = 0; i < n_runs; ++i) {
clock_gettime(CLOCK_MONOTONIC, &start);
nn_dot_product_cmsis(a, b, n_vectors);
clock_gettime(CLOCK_MONOTONIC, &end);
total_time_cmsis += timespec_diff_ns(&start, &end);
total_time += nn_timespec_diff_ns(&start, &end);
}
printf("dot_product (CMSIS): n_vectors=%d n_runs=%d total_time_ns=%lld avg_time_ns=%lld\n", n_vectors, n_runs, total_time_cmsis, total_time_cmsis / n_runs / n_vectors);
printf("avg_time_ns=%lld total_time_ms=%lld info=nn_dot_product_cmsis\n", total_time / n_runs, total_time / 1000000);

return 0;
}
52 changes: 52 additions & 0 deletions tests/arch/arm/cmsis-dsp/neuron_perf/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
#define _POSIX_C_SOURCE 199309L
#include "arch/arm/cmsis-dsp/nn_dot_product.h"
#include "nn_activation.h"
#include "nn_app.h"
#include "nn_config.h"
#include "nn_neuron.h"
#include "nn_test.h"
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[]) {
nn_init_app(argc, argv);

if (!nn_cmsis_dsp_available()) {
printf("ARM CMSIS-DSP not available\n");
}

// Init vars
NNNeuron neuron;
NNError error;
size_t input_size = 3;
float weights[NEURON_MAX_WEIGHTS] = {0.2f, 0.8f, -0.5f};
float bias = 2.0f;
const int n_runs = 1000;
const int n_inputs = n_runs * input_size;
long long total_time = 0;
struct timespec start, end;
float *inputs = malloc(n_inputs * sizeof(float));
for (int i = 0; i < n_inputs; ++i) {
inputs[i] = (float)rand() / (float)RAND_MAX;
}

if (!nn_neuron_init(&neuron, weights, input_size, bias, nn_activation_func_identity, nn_dot_product_cmsis, &error)) {
printf("error: %s\n", error.message);
return 1;
}

// Benchmark
for (int i = 0; i < n_runs; ++i) {
clock_gettime(CLOCK_MONOTONIC, &start);
nn_neuron_compute(&neuron, inputs + i * input_size, &error);
clock_gettime(CLOCK_MONOTONIC, &end);
total_time += nn_timespec_diff_ns(&start, &end);
}
if (error.code != NN_ERROR_NONE) {
printf("error: %s\n", error.message);
return 1;
}
printf("avg_time_ns=%lld total_time_ms=%lld info=nn_neuron_compute\n", total_time / n_runs, total_time / 1000000);

return 0;
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,23 @@
#include "arch/arm/neon/nn_dot_product.h"
#include "nn_app.h"
#include "nn_config.h"
#include "nn_test.h"
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

// timespec_diff_ns returns the difference between two timespec structs in nanoseconds.
static long long timespec_diff_ns(struct timespec *start, struct timespec *end) {
return (end->tv_sec - start->tv_sec) * 1000000000LL + (end->tv_nsec - start->tv_nsec);
}

int main(int argc, char *argv[]) {
nn_init_app(argc, argv);

if (!nn_neon_available()) {
printf("dot_product (NEON): ARM NEON not available\n");
printf("ARM NEON not available\n");
return 1;
}

// Init vars
const int n_runs = 1000;
const int n_vectors = 100000;
long long total_time = 0;
struct timespec start, end;
float *a = malloc(n_vectors * sizeof(float));
float *b = malloc(n_vectors * sizeof(float));
Expand All @@ -29,15 +27,14 @@ int main(int argc, char *argv[]) {
b[i] = (float)rand() / (float)RAND_MAX;
}

// Benchmark NEON implementation
long long total_time_neon = 0;
// Benchmark
for (int i = 0; i < n_runs; ++i) {
clock_gettime(CLOCK_MONOTONIC, &start);
nn_dot_product_neon(a, b, n_vectors);
clock_gettime(CLOCK_MONOTONIC, &end);
total_time_neon += timespec_diff_ns(&start, &end);
total_time += nn_timespec_diff_ns(&start, &end);
}
printf("dot_product (NEON): n_vectors=%d n_runs=%d total_time_ns=%lld avg_time_ns=%lld\n", n_vectors, n_runs, total_time_neon, total_time_neon / n_runs / n_vectors);
printf("avg_time_ns=%lld total_time_ms=%lld info=nn_dot_product_neon\n", total_time / n_runs, total_time / 1000000);

return 0;
}
53 changes: 53 additions & 0 deletions tests/arch/arm/neon/neuron_perf/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
#define _POSIX_C_SOURCE 199309L
#include "arch/arm/neon/nn_dot_product.h"
#include "nn_activation.h"
#include "nn_app.h"
#include "nn_config.h"
#include "nn_neuron.h"
#include "nn_test.h"
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[]) {
nn_init_app(argc, argv);

if (!nn_neon_available()) {
printf("ARM NEON not available\n");
return 1;
}

// Init vars
NNNeuron neuron;
NNError error;
size_t input_size = 3;
float weights[NEURON_MAX_WEIGHTS] = {0.2f, 0.8f, -0.5f};
float bias = 2.0f;
const int n_runs = 1000;
const int n_inputs = n_runs * input_size;
long long total_time = 0;
struct timespec start, end;
float *inputs = malloc(n_inputs * sizeof(float));
for (int i = 0; i < n_inputs; ++i) {
inputs[i] = (float)rand() / (float)RAND_MAX;
}

if (!nn_neuron_init(&neuron, weights, input_size, bias, nn_activation_func_identity, nn_dot_product_neon, &error)) {
printf("error: %s\n", error.message);
return 1;
}

// Benchmark
for (int i = 0; i < n_runs; ++i) {
clock_gettime(CLOCK_MONOTONIC, &start);
nn_neuron_compute(&neuron, inputs + i * input_size, &error);
clock_gettime(CLOCK_MONOTONIC, &end);
total_time += nn_timespec_diff_ns(&start, &end);
}
if (error.code != NN_ERROR_NONE) {
printf("error: %s\n", error.message);
return 1;
}
printf("avg_time_ns=%lld total_time_ms=%lld info=nn_neuron_compute\n", total_time / n_runs, total_time / 1000000);

return 0;
}
Loading
Loading