Skip to content
Permalink
Browse files

add setuptutils minimum to requirements (required for python 3.5)

variable array length fixes for MSVC compilers
change gcc shell calls to distutils calls for compilation
  • Loading branch information
micooke committed Nov 22, 2019
1 parent 3a7a00c commit dbba49081ba0b891826b7e1b165462513c0bc6b3
Showing with 88 additions and 63 deletions.
  1. +21 −17 emlearn/common.py
  2. +4 −2 emlearn/eml_bayes.h
  3. +2 −0 emlearn/eml_benchmark.h
  4. +4 −1 examples/digits.py
  5. +1 −0 requirements.dev.txt
  6. +20 −18 test/bench.c
  7. +24 −18 test/test_benchmark.py
  8. +12 −7 test/test_window_function.py
@@ -1,28 +1,38 @@

import os
import os.path
import sys
import subprocess
import platform
from distutils.ccompiler import new_compiler

def get_include_dir():
return os.path.join(os.path.dirname(__file__))


def build_classifier(cmodel, name, temp_dir, include_dir, func=None, compiler=None, test_function=None):
def build_classifier(cmodel, name, temp_dir, include_dir, func=None, test_function=None):
if not os.path.exists(temp_dir):
os.makedirs(temp_dir)

if compiler is None:
compiler = 'gcc'

if test_function is None:
test_function = 'eml_test_read_csv'

# create a new compiler object
# force re-compilation even if object files exist (required)
cc = new_compiler(force=1)

tree_name = name
def_file_name = name+'.h'
def_file = os.path.join(temp_dir, def_file_name)
code_file = os.path.join(temp_dir, name+'.c')
bin_path = os.path.join(temp_dir, name)
output_filename = cc.executable_filename(name)
bin_path = os.path.join(temp_dir, output_filename)
include_dirs = [temp_dir, include_dir]
if sys.platform.startswith('win'): # Windows
libraries = None
cc_args = None
else : # MacOS and Linux should be the same
libraries = ["m"] # math library / libm
cc_args = ["-std=c99"]

# Trivial program that reads values on stdin, and returns classifications on stdout
code = """
@@ -43,16 +53,11 @@ def build_classifier(cmodel, name, temp_dir, include_dir, func=None, compiler=No

with open(code_file, 'w') as f:
f.write(code)
objects = cc.compile(sources=[code_file],
extra_preargs=cc_args, include_dirs=include_dirs)

args = [
compiler,
'-std=c99',
code_file, '-o', bin_path,
'-I{}'.format(include_dir),
'-I{}'.format(temp_dir),
'-lm',
]
subprocess.check_call(' '.join(args), shell=True)
cc.link("executable", objects, output_filename=output_filename,
output_dir=temp_dir, libraries=libraries)

return bin_path

@@ -76,9 +81,8 @@ def run_classifier(bin_path, data):

return classes


class CompiledClassifier():
def __init__(self, cmodel, name, call=None, include_dir=None, temp_dir='tmp/', test_function=None):
def __init__(self, cmodel, name, call=None, include_dir=None, temp_dir='tmp', test_function=None):
if include_dir == None:
include_dir = get_include_dir()
self.bin_path = build_classifier(cmodel, name,
@@ -5,6 +5,9 @@
#include "eml_common.h"
#include "eml_fixedpoint.h"

#ifndef EML_MAX_CLASSES
#define EML_MAX_CLASSES 10
#endif

typedef struct _EmlBayesSummary {
eml_q16_t mean;
@@ -94,8 +97,7 @@ eml_bayes_predict(EmlBayesModel *model, const float values[], int32_t values_len
EML_PRECONDITION(values, -EmlUninitialized);
EML_PRECONDITION(model->n_classes >= 2, -EmlUninitialized);

const int MAX_CLASSES = 10;
eml_q16_t class_probabilities[MAX_CLASSES];
eml_q16_t class_probabilities[EML_MAX_CLASSES];

for (int class_idx = 0; class_idx<model->n_classes; class_idx++) {

@@ -6,7 +6,9 @@

#if defined (__unix__) || (defined (__APPLE__) && defined (__MACH__))
// Unix-like system
#ifndef _POSIX_C_SOURCE
#define _POSIX_C_SOURCE 199309L
#endif
#define EML_HAVE_SYS_TIME 1
#endif

@@ -5,6 +5,7 @@
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
from sklearn import metrics, datasets
import serial.tools.list_ports as port_list

rnd = 11
digits = datasets.load_digits()
@@ -32,7 +33,9 @@

print('Wrote C code to', filename)

port = '/dev/ttyUSB0'
assert len(port_list.comports()) > 0, "No serial ports available"

port = port_list.comports()[0].device # grab the first serial port
print('Classify on microcontroller via', port)
import serial
device = serial.Serial(port=port, baudrate=115200, timeout=0.1)
@@ -1,3 +1,4 @@
setuptools>=41.0.0
pytest-cov>=2.5.1
scipy>=1.0.0
scikit-learn>=0.19.1
@@ -4,31 +4,33 @@

#include <stdio.h>

#ifndef EML_N_FFT
#define EML_N_FFT 1024
#define EML_N_REPS 1000
#define EML_FRAME_LENGTH 1024
#define EML_N_FFT_TABLE (EML_N_FFT/2)
#endif

EmlError
bench_melspec()
{
const int n_fft = 1024;
const int n_reps = 1000;
const EmlAudioMel mel = { 64, 0, 20000, n_fft, 44100 };
float times[n_reps];

const int frame_length = 1024;
const EmlAudioMel mel = { 64, 0, 20000, EML_N_FFT, 44100 };
float times[EML_N_REPS];

float input_data[frame_length];
float temp_data[frame_length];
eml_benchmark_fill(input_data, frame_length);
float input_data[EML_FRAME_LENGTH];
float temp_data[EML_FRAME_LENGTH];
eml_benchmark_fill(input_data, EML_FRAME_LENGTH);

const int n_fft_table = n_fft/2;
float fft_sin[n_fft_table];
float fft_cos[n_fft_table];
EmlFFT fft = { n_fft_table, fft_sin, fft_cos };
EML_CHECK_ERROR(eml_fft_fill(fft, n_fft));
float fft_sin[EML_N_FFT_TABLE];
float fft_cos[EML_N_FFT_TABLE];
EmlFFT fft = { EML_N_FFT_TABLE, fft_sin, fft_cos };
EML_CHECK_ERROR(eml_fft_fill(fft, EML_N_FFT));

eml_benchmark_melspectrogram(mel, fft, input_data, temp_data, n_reps, times);
EmlVector t = { times, n_reps };
eml_benchmark_melspectrogram(mel, fft, input_data, temp_data, EML_N_REPS, times);
EmlVector t = { times, EML_N_REPS };

const float mean = eml_vector_mean(t);
printf("melspec;%d;%f\n", n_reps, mean);
printf("melspec;%d;%f\n", EML_N_REPS, mean);
return EmlOk;
}

@@ -44,4 +46,4 @@ int main() {

const EmlError e = bench_all();
return -(int)e;
}
}
@@ -5,27 +5,33 @@

import pandas

def compile_program(input, out):
args = [
'gcc',
input,
'-o', out,
'-std=c99',
'-O3',
'-g',
'-fno-omit-frame-pointer',
'-lm',
'-Wall',
'-Werror',
'-I./emlearn',
]
subprocess.check_call(' '.join(args), shell=True)
import sys
from distutils.ccompiler import new_compiler

def test_bench_melspec():
testdir = os.path.dirname(__file__)
# create a new compiler object
# force re-compilation even if object files exist (required)
cc = new_compiler(force=1)
output_filename = cc.executable_filename('bench')

testdir = os.path.abspath(os.path.dirname(__file__))
code = os.path.join(testdir, 'bench.c')
prog = os.path.join(testdir, 'bench')
compile_program(code, prog)
prog = os.path.join(testdir, output_filename)
print(prog)
include_dirs=["emlearn"]

if sys.platform.startswith('win'): # Windows
# disable warnings: C5045-QSpectre, C4996-unsafe function/var
cc_args = ["/Ox","/Oy-","/Wall","/WX","/wd5045","wd4996"]
libraries = None
else : # MacOS and Linux should be the same
cc_args = ["-O3","-fno-omit-frame-pointer","-Wall","-Werror"]
libraries = ["m"] # math library / libm

objects = cc.compile(sources=[code], include_dirs=include_dirs,
debug=1, extra_preargs=cc_args)
cc.link("executable", objects, output_filename=output_filename,
debug=1, libraries=libraries, output_dir=testdir)
out = subprocess.check_output([prog]).decode('utf-8')

df = pandas.read_csv(io.StringIO(out), sep=';')
@@ -4,9 +4,9 @@
import json

import numpy
from distutils.ccompiler import new_compiler

examples_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), '../examples'))

examples_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), '..','examples'))

def run_window_function(options):
path = os.path.join(examples_dir, 'window-function.py')
@@ -42,8 +42,11 @@ def run_extract(include, name, length, workdir):
print_json(arr, length);
}}
"""

prog_path = os.path.join(workdir, 'test_' + name)
# create a new compiler object
# force re-compilation even if object files exist (required)
cc = new_compiler(force=1)
output_filename = cc.executable_filename('test_' + name)
prog_path = os.path.join(workdir, output_filename)
code_path = prog_path + '.c'

params = dict(include=include, name=name, length=length)
@@ -52,10 +55,12 @@ def run_extract(include, name, length, workdir):
f.write(prog)

# compile
args = ['gcc', '-std=c99', code_path, '-o', prog_path]
subprocess.check_call(' '.join(args), shell=True)
objects = cc.compile([code_path])
cc.link("executable", objects, output_filename=output_filename,
output_dir=workdir)

stdout = subprocess.check_output([prog_path])

arr = json.loads(stdout)
return arr

@@ -84,7 +89,7 @@ def window_function_test(file_path, args):

def test_window_function_hann():

file_path = 'tests/out/window_func.h'
file_path = os.path.join('tests','out','window_func.h')
args = dict(
window='hann',
length=512,

0 comments on commit dbba490

Please sign in to comment.
You can’t perform that action at this time.