#define _POSIX_C_SOURCE 200809L #include "xtc/xtc_engine.h" #include #include #include #include #include #include static double now(void) { struct timespec t; if (clock_gettime(CLOCK_MONOTONIC,&t)) abort(); return (double)t.tv_sec+(double)t.tv_nsec/1e9; } static double cpu_now(void) { struct timespec t; if (clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&t)) abort(); return (double)t.tv_sec+(double)t.tv_nsec/1e9; } static int compare(const void *a,const void *b) { double x = *(const double *)a,y = *(const double *)b; return x < y ? -1 : x > y; } static size_t number(const char *s,size_t maximum) { char *end; unsigned long n; errno = 0; n = strtoul(s,&end,10); if (errno || !s[0] || *end || n < 1 || n > maximum) return 0; return (size_t)n; } int main(int argc,char **argv) { size_t nodes,channels,rate,frames,blocks,i,j,id = 0,previous = 0; xtc_graph *g = NULL; xtc_plan *p = NULL; float *in = NULL,*left = NULL,*right = NULL; double *times = NULL,begin,compile,total = 0,cpu_begin,cpu; size_t misses = 0; struct rusage usage; int status = 1; if (argc != 6) return 1; nodes = number(argv[1],256); channels = number(argv[2],2); rate = number(argv[3],768000); frames = number(argv[4],65536); blocks = number(argv[5],100000); if (nodes < 2 || !channels || !rate || !frames || !blocks) return 1; in = calloc(frames,sizeof(float)); left = calloc(frames,sizeof(float)); right = calloc(frames,sizeof(float)); times = calloc(blocks,sizeof(double)); if (!in || !left || !right || !times || xtc_graph_create(nodes,&g) != XTC_OK) goto done; for (i = 0; i < nodes; ++i) { xtc_result r = i+1 == nodes ? xtc_graph_add_output(g,&id) : i+2 == nodes ? xtc_graph_add_meter(g,&id) : xtc_graph_add_gain(g,.999f,&id); if (r != XTC_OK || (i && xtc_graph_connect(g,previous,id) != XTC_OK)) goto done; previous = id; } begin = now(); if (xtc_graph_compile(g,(double)rate,frames,&p) != XTC_OK) goto done; compile = now()-begin; for (i = 0; i < frames; ++i) in[i] = (float)sin((double)i*.1)*.1f; /* Warm caches outside the sample, then measure only the process call. */ for (i = 0; i < 20; ++i) if (xtc_plan_process_stereo(p,in,NULL,NULL,NULL,NULL,left,channels == 2 ? right : NULL,frames) != XTC_OK) goto done; cpu_begin = cpu_now(); for (i = 0; i < blocks; ++i) { begin = now(); if (xtc_plan_process_stereo(p,in,NULL,NULL,NULL,NULL,left,channels == 2 ? right : NULL,frames) != XTC_OK) goto done; times[i] = now()-begin; total += times[i]; if (times[i] > (double)frames/(double)rate) ++misses; for (j = 0; j < frames; ++j) if (!isfinite(left[j]) || (channels == 2 && !isfinite(right[j]))) goto done; } cpu = cpu_now()-cpu_begin; if (getrusage(RUSAGE_SELF,&usage)) goto done; qsort(times,blocks,sizeof(double),compare); printf("{\"nodes\":%zu,\"channels\":%zu,\"rate\":%zu,\"frames\":%zu,\"blocks\":%zu," "\"compile_ms\":%.6f,\"mean_us\":%.6f,\"p99_us\":%.6f,\"max_us\":%.6f,\"deadline_us\":%.6f," "\"load\":%.6f,\"graph_buffer_bytes\":%zu,\"deadline_misses\":%zu,\"process_cpu_ms\":%.6f,\"peak_rss_kib\":%ld}\n",nodes,channels,rate,frames,blocks,compile*1e3,total/(double)blocks*1e6, times[blocks*99/100]*1e6,times[blocks-1]*1e6,(double)frames/(double)rate*1e6, total/(double)blocks/((double)frames/(double)rate),nodes*frames*2*sizeof(float),misses,cpu*1e3,usage.ru_maxrss); status = 0; done: free(in); free(left); free(right); free(times); xtc_plan_destroy(p); xtc_graph_destroy(g); return status; }