├── CoreMark.ino ├── README.md ├── core_list_join.c ├── core_main.c ├── core_matrix.c ├── core_portme.c ├── core_portme.h ├── core_state.c ├── core_util.c └── coremark.h /CoreMark.ino: -------------------------------------------------------------------------------- 1 | // CoreMark Benchmark for Arduino compatible boards 2 | // original CoreMark code: https://github.com/eembc/coremark 3 | 4 | #include 5 | 6 | // A way to call the C-only coremark function from Arduino's C++ environment 7 | extern "C" int coremark_main(void); 8 | 9 | void setup() 10 | { 11 | Serial.begin(9600); 12 | while (!Serial) ; // wait for Arduino Serial Monitor 13 | delay(500); 14 | Serial.println("CoreMark Performance Benchmark"); 15 | Serial.println(); 16 | Serial.println("CoreMark measures how quickly your processor can manage linked"); 17 | Serial.println("lists, compute matrix multiply, and execute state machine code."); 18 | Serial.println(); 19 | Serial.println("Iterations/Sec is the main benchmark result, higher numbers are better"); 20 | Serial.println("Running.... (usually requires 12 to 20 seconds)"); 21 | Serial.println(); 22 | delay(250); 23 | coremark_main(); // Run the benchmark :-) 24 | } 25 | 26 | void loop() 27 | { 28 | } 29 | 30 | // CoreMark calls this function to print results. 31 | extern "C" int ee_printf(const char *format, ...) 32 | { 33 | va_list args; 34 | va_start(args, format); 35 | for (; *format; format++) { 36 | if (*format == '%') { 37 | bool islong = false; 38 | format++; 39 | if (*format == '%') { Serial.print(*format); continue; } 40 | if (*format == '-') format++; // ignore size 41 | while (*format >= '0' && *format <= '9') format++; // ignore size 42 | if (*format == 'l') { islong = true; format++; } 43 | if (*format == '\0') break; 44 | if (*format == 's') { 45 | Serial.print((char *)va_arg(args, int)); 46 | } else if (*format == 'f') { 47 | Serial.print(va_arg(args, double)); 48 | } else if (*format == 'd') { 49 | if (islong) Serial.print(va_arg(args, long)); 50 | else Serial.print(va_arg(args, int)); 51 | } else if (*format == 'u') { 52 | if (islong) Serial.print(va_arg(args, unsigned long)); 53 | else Serial.print(va_arg(args, unsigned int)); 54 | } else if (*format == 'x') { 55 | if (islong) Serial.print(va_arg(args, unsigned long), HEX); 56 | else Serial.print(va_arg(args, unsigned int), HEX); 57 | } else if (*format == 'c' ) { 58 | Serial.print(va_arg(args, int)); 59 | } 60 | } else { 61 | if (*format == '\n') Serial.print('\r'); 62 | Serial.print(*format); 63 | } 64 | } 65 | va_end(args); 66 | return 1; 67 | } 68 | 69 | // CoreMark calls this function to measure elapsed time 70 | extern "C" uint32_t Arduino_millis(void) 71 | { 72 | return millis(); 73 | } 74 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CoreMark - CPU Performance Benchmark 2 | 3 | Measures the number for times per second your processor can perform a 4 | variety of common tasks: linked list management, matrix multiply, and 5 | executing state machines. 6 | 7 | | Board | CoreMark | 8 | | ---------------------- | :------: | 9 | | Teensy 4.0 | 2313.57 | 10 | | Adafruit Metro M4 (200MHz overclock, 'dragons' optimization) | 536.35 | 11 | | Adafruit Metro M4 (180MHz overclock, faster optimizations) | 458.19 | 12 | | Teensy 3.6 | 440.72 | 13 | | Sparkfun ESP32 Thing | 351.33 | 14 | | Adafruit HUZZAH 32 | 351.35 | 15 | | Teensy 3.5 | 265.50 | 16 | | Teensy 3.2 (96MHz overclock, faster optimizations) | 218.26 | 17 | | Adafruit Metro M4 (120MHz, smaller code) | 214.85 | 18 | | Teensy 3.2 (72MHz) | 168.62 | 19 | | Teensy 3.2 (72MHz, smaller code) | 126.76 | 20 | | Arduino Due | 94.95 | 21 | | Arduino Zero | 56.86 | 22 | | Arduino Nano Every | 8.20 | 23 | | Arduino Mega | 7.03 | 24 | 25 | (larger numbers are better) 26 | 27 | -------------------------------------------------------------------------------- /core_list_join.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2018 Embedded Microprocessor Benchmark Consortium (EEMBC) 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | 16 | Original Author: Shay Gal-on 17 | */ 18 | 19 | #include "coremark.h" 20 | /* 21 | Topic: Description 22 | Benchmark using a linked list. 23 | 24 | Linked list is a common data structure used in many applications. 25 | 26 | For our purposes, this will excercise the memory units of the processor. 27 | In particular, usage of the list pointers to find and alter data. 28 | 29 | We are not using Malloc since some platforms do not support this library. 30 | 31 | Instead, the memory block being passed in is used to create a list, 32 | and the benchmark takes care not to add more items then can be 33 | accomodated by the memory block. The porting layer will make sure 34 | that we have a valid memory block. 35 | 36 | All operations are done in place, without using any extra memory. 37 | 38 | The list itself contains list pointers and pointers to data items. 39 | Data items contain the following: 40 | 41 | idx - An index that captures the initial order of the list. 42 | data - Variable data initialized based on the input parameters. The 16b are divided as follows: 43 | o Upper 8b are backup of original data. 44 | o Bit 7 indicates if the lower 7 bits are to be used as is or calculated. 45 | o Bits 0-2 indicate type of operation to perform to get a 7b value. 46 | o Bits 3-6 provide input for the operation. 47 | 48 | */ 49 | 50 | /* local functions */ 51 | 52 | list_head *core_list_find(list_head *list,list_data *info); 53 | list_head *core_list_reverse(list_head *list); 54 | list_head *core_list_remove(list_head *item); 55 | list_head *core_list_undo_remove(list_head *item_removed, list_head *item_modified); 56 | list_head *core_list_insert_new(list_head *insert_point 57 | , list_data *info, list_head **memblock, list_data **datablock 58 | , list_head *memblock_end, list_data *datablock_end); 59 | typedef ee_s32(*list_cmp)(list_data *a, list_data *b, core_results *res); 60 | list_head *core_list_mergesort(list_head *list, list_cmp cmp, core_results *res); 61 | 62 | ee_s16 calc_func(ee_s16 *pdata, core_results *res) { 63 | ee_s16 data=*pdata; 64 | ee_s16 retval; 65 | ee_u8 optype=(data>>7) & 1; /* bit 7 indicates if the function result has been cached */ 66 | if (optype) /* if cached, use cache */ 67 | return (data & 0x007f); 68 | else { /* otherwise calculate and cache the result */ 69 | ee_s16 flag=data & 0x7; /* bits 0-2 is type of function to perform */ 70 | ee_s16 dtype=((data>>3) & 0xf); /* bits 3-6 is specific data for the operation */ 71 | dtype |= dtype << 4; /* replicate the lower 4 bits to get an 8b value */ 72 | switch (flag) { 73 | case 0: 74 | if (dtype<0x22) /* set min period for bit corruption */ 75 | dtype=0x22; 76 | retval=core_bench_state(res->size,res->memblock[3],res->seed1,res->seed2,dtype,res->crc); 77 | if (res->crcstate==0) 78 | res->crcstate=retval; 79 | break; 80 | case 1: 81 | retval=core_bench_matrix(&(res->mat),dtype,res->crc); 82 | if (res->crcmatrix==0) 83 | res->crcmatrix=retval; 84 | break; 85 | default: 86 | retval=data; 87 | break; 88 | } 89 | res->crc=crcu16(retval,res->crc); 90 | retval &= 0x007f; 91 | *pdata = (data & 0xff00) | 0x0080 | retval; /* cache the result */ 92 | return retval; 93 | } 94 | } 95 | /* Function: cmp_complex 96 | Compare the data item in a list cell. 97 | 98 | Can be used by mergesort. 99 | */ 100 | ee_s32 cmp_complex(list_data *a, list_data *b, core_results *res) { 101 | ee_s16 val1=calc_func(&(a->data16),res); 102 | ee_s16 val2=calc_func(&(b->data16),res); 103 | return val1 - val2; 104 | } 105 | 106 | /* Function: cmp_idx 107 | Compare the idx item in a list cell, and regen the data. 108 | 109 | Can be used by mergesort. 110 | */ 111 | ee_s32 cmp_idx(list_data *a, list_data *b, core_results *res) { 112 | if (res==NULL) { 113 | a->data16 = (a->data16 & 0xff00) | (0x00ff & (a->data16>>8)); 114 | b->data16 = (b->data16 & 0xff00) | (0x00ff & (b->data16>>8)); 115 | } 116 | return a->idx - b->idx; 117 | } 118 | 119 | void copy_info(list_data *to,list_data *from) { 120 | to->data16=from->data16; 121 | to->idx=from->idx; 122 | } 123 | 124 | /* Benchmark for linked list: 125 | - Try to find multiple data items. 126 | - List sort 127 | - Operate on data from list (crc) 128 | - Single remove/reinsert 129 | * At the end of this function, the list is back to original state 130 | */ 131 | ee_u16 core_bench_list(core_results *res, ee_s16 finder_idx) { 132 | ee_u16 retval=0; 133 | ee_u16 found=0,missed=0; 134 | list_head *list=res->list; 135 | ee_s16 find_num=res->seed3; 136 | list_head *this_find; 137 | list_head *finder, *remover; 138 | list_data info; 139 | ee_s16 i; 140 | 141 | info.idx=finder_idx; 142 | /* find values in the list, and change the list each time (reverse and cache if value found) */ 143 | for (i=0; inext->info->data16 >> 8) & 1; 150 | } 151 | else { 152 | found++; 153 | if (this_find->info->data16 & 0x1) /* use found value */ 154 | retval+=(this_find->info->data16 >> 9) & 1; 155 | /* and cache next item at the head of the list (if any) */ 156 | if (this_find->next != NULL) { 157 | finder = this_find->next; 158 | this_find->next = finder->next; 159 | finder->next=list->next; 160 | list->next=finder; 161 | } 162 | } 163 | if (info.idx>=0) 164 | info.idx++; 165 | #if CORE_DEBUG 166 | ee_printf("List find %d: [%d,%d,%d]\n",i,retval,missed,found); 167 | #endif 168 | } 169 | retval+=found*4-missed; 170 | /* sort the list by data content and remove one item*/ 171 | if (finder_idx>0) 172 | list=core_list_mergesort(list,cmp_complex,res); 173 | remover=core_list_remove(list->next); 174 | /* CRC data content of list from location of index N forward, and then undo remove */ 175 | finder=core_list_find(list,&info); 176 | if (!finder) 177 | finder=list->next; 178 | while (finder) { 179 | retval=crc16(list->info->data16,retval); 180 | finder=finder->next; 181 | } 182 | #if CORE_DEBUG 183 | ee_printf("List sort 1: %04x\n",retval); 184 | #endif 185 | remover=core_list_undo_remove(remover,list->next); 186 | /* sort the list by index, in effect returning the list to original state */ 187 | list=core_list_mergesort(list,cmp_idx,NULL); 188 | /* CRC data content of list */ 189 | finder=list->next; 190 | while (finder) { 191 | retval=crc16(list->info->data16,retval); 192 | finder=finder->next; 193 | } 194 | #if CORE_DEBUG 195 | ee_printf("List sort 2: %04x\n",retval); 196 | #endif 197 | return retval; 198 | } 199 | /* Function: core_list_init 200 | Initialize list with data. 201 | 202 | Parameters: 203 | blksize - Size of memory to be initialized. 204 | memblock - Pointer to memory block. 205 | seed - Actual values chosen depend on the seed parameter. 206 | The seed parameter MUST be supplied from a source that cannot be determined at compile time 207 | 208 | Returns: 209 | Pointer to the head of the list. 210 | 211 | */ 212 | list_head *core_list_init(ee_u32 blksize, list_head *memblock, ee_s16 seed) { 213 | /* calculated pointers for the list */ 214 | ee_u32 per_item=16+sizeof(struct list_data_s); 215 | ee_u32 size=(blksize/per_item)-2; /* to accomodate systems with 64b pointers, and make sure same code is executed, set max list elements */ 216 | list_head *memblock_end=memblock+size; 217 | list_data *datablock=(list_data *)(memblock_end); 218 | list_data *datablock_end=datablock+size; 219 | /* some useful variables */ 220 | ee_u32 i; 221 | list_head *finder,*list=memblock; 222 | list_data info; 223 | 224 | /* create a fake items for the list head and tail */ 225 | list->next=NULL; 226 | list->info=datablock; 227 | list->info->idx=0x0000; 228 | list->info->data16=(ee_s16)0x8080; 229 | memblock++; 230 | datablock++; 231 | info.idx=0x7fff; 232 | info.data16=(ee_s16)0xffff; 233 | core_list_insert_new(list,&info,&memblock,&datablock,memblock_end,datablock_end); 234 | 235 | /* then insert size items */ 236 | for (i=0; inext; 244 | i=1; 245 | while (finder->next!=NULL) { 246 | if (iinfo->idx=i++; 248 | else { 249 | ee_u16 pat=(ee_u16)(i++ ^ seed); /* get a pseudo random number */ 250 | finder->info->idx=0x3fff & (((i & 0x07) << 8) | pat); /* make sure the mixed items end up after the ones in sequence */ 251 | } 252 | finder=finder->next; 253 | } 254 | list = core_list_mergesort(list,cmp_idx,NULL); 255 | #if CORE_DEBUG 256 | ee_printf("Initialized list:\n"); 257 | finder=list; 258 | while (finder) { 259 | ee_printf("[%04x,%04x]",finder->info->idx,(ee_u16)finder->info->data16); 260 | finder=finder->next; 261 | } 262 | ee_printf("\n"); 263 | #endif 264 | return list; 265 | } 266 | 267 | /* Function: core_list_insert 268 | Insert an item to the list 269 | 270 | Parameters: 271 | insert_point - where to insert the item. 272 | info - data for the cell. 273 | memblock - pointer for the list header 274 | datablock - pointer for the list data 275 | memblock_end - end of region for list headers 276 | datablock_end - end of region for list data 277 | 278 | Returns: 279 | Pointer to new item. 280 | */ 281 | list_head *core_list_insert_new(list_head *insert_point, list_data *info, list_head **memblock, list_data **datablock 282 | , list_head *memblock_end, list_data *datablock_end) { 283 | list_head *newitem; 284 | 285 | if ((*memblock+1) >= memblock_end) 286 | return NULL; 287 | if ((*datablock+1) >= datablock_end) 288 | return NULL; 289 | 290 | newitem=*memblock; 291 | (*memblock)++; 292 | newitem->next=insert_point->next; 293 | insert_point->next=newitem; 294 | 295 | newitem->info=*datablock; 296 | (*datablock)++; 297 | copy_info(newitem->info,info); 298 | 299 | return newitem; 300 | } 301 | 302 | /* Function: core_list_remove 303 | Remove an item from the list. 304 | 305 | Operation: 306 | For a singly linked list, remove by copying the data from the next item 307 | over to the current cell, and unlinking the next item. 308 | 309 | Note: 310 | since there is always a fake item at the end of the list, no need to check for NULL. 311 | 312 | Returns: 313 | Removed item. 314 | */ 315 | list_head *core_list_remove(list_head *item) { 316 | list_data *tmp; 317 | list_head *ret=item->next; 318 | /* swap data pointers */ 319 | tmp=item->info; 320 | item->info=ret->info; 321 | ret->info=tmp; 322 | /* and eliminate item */ 323 | item->next=item->next->next; 324 | ret->next=NULL; 325 | return ret; 326 | } 327 | 328 | /* Function: core_list_undo_remove 329 | Undo a remove operation. 330 | 331 | Operation: 332 | Since we want each iteration of the benchmark to be exactly the same, 333 | we need to be able to undo a remove. 334 | Link the removed item back into the list, and switch the info items. 335 | 336 | Parameters: 337 | item_removed - Return value from the 338 | item_modified - List item that was modified during 339 | 340 | Returns: 341 | The item that was linked back to the list. 342 | 343 | */ 344 | list_head *core_list_undo_remove(list_head *item_removed, list_head *item_modified) { 345 | list_data *tmp; 346 | /* swap data pointers */ 347 | tmp=item_removed->info; 348 | item_removed->info=item_modified->info; 349 | item_modified->info=tmp; 350 | /* and insert item */ 351 | item_removed->next=item_modified->next; 352 | item_modified->next=item_removed; 353 | return item_removed; 354 | } 355 | 356 | /* Function: core_list_find 357 | Find an item in the list 358 | 359 | Operation: 360 | Find an item by idx (if not 0) or specific data value 361 | 362 | Parameters: 363 | list - list head 364 | info - idx or data to find 365 | 366 | Returns: 367 | Found item, or NULL if not found. 368 | */ 369 | list_head *core_list_find(list_head *list,list_data *info) { 370 | if (info->idx>=0) { 371 | while (list && (list->info->idx != info->idx)) 372 | list=list->next; 373 | return list; 374 | } else { 375 | while (list && ((list->info->data16 & 0xff) != info->data16)) 376 | list=list->next; 377 | return list; 378 | } 379 | } 380 | /* Function: core_list_reverse 381 | Reverse a list 382 | 383 | Operation: 384 | Rearrange the pointers so the list is reversed. 385 | 386 | Parameters: 387 | list - list head 388 | info - idx or data to find 389 | 390 | Returns: 391 | Found item, or NULL if not found. 392 | */ 393 | 394 | list_head *core_list_reverse(list_head *list) { 395 | list_head *next=NULL, *tmp; 396 | while (list) { 397 | tmp=list->next; 398 | list->next=next; 399 | next=list; 400 | list=tmp; 401 | } 402 | return next; 403 | } 404 | /* Function: core_list_mergesort 405 | Sort the list in place without recursion. 406 | 407 | Description: 408 | Use mergesort, as for linked list this is a realistic solution. 409 | Also, since this is aimed at embedded, care was taken to use iterative rather then recursive algorithm. 410 | The sort can either return the list to original order (by idx) , 411 | or use the data item to invoke other other algorithms and change the order of the list. 412 | 413 | Parameters: 414 | list - list to be sorted. 415 | cmp - cmp function to use 416 | 417 | Returns: 418 | New head of the list. 419 | 420 | Note: 421 | We have a special header for the list that will always be first, 422 | but the algorithm could theoretically modify where the list starts. 423 | 424 | */ 425 | list_head *core_list_mergesort(list_head *list, list_cmp cmp, core_results *res) { 426 | list_head *p, *q, *e, *tail; 427 | ee_s32 insize, nmerges, psize, qsize, i; 428 | 429 | insize = 1; 430 | 431 | while (1) { 432 | p = list; 433 | list = NULL; 434 | tail = NULL; 435 | 436 | nmerges = 0; /* count number of merges we do in this pass */ 437 | 438 | while (p) { 439 | nmerges++; /* there exists a merge to be done */ 440 | /* step `insize' places along from p */ 441 | q = p; 442 | psize = 0; 443 | for (i = 0; i < insize; i++) { 444 | psize++; 445 | q = q->next; 446 | if (!q) break; 447 | } 448 | 449 | /* if q hasn't fallen off end, we have two lists to merge */ 450 | qsize = insize; 451 | 452 | /* now we have two lists; merge them */ 453 | while (psize > 0 || (qsize > 0 && q)) { 454 | 455 | /* decide whether next element of merge comes from p or q */ 456 | if (psize == 0) { 457 | /* p is empty; e must come from q. */ 458 | e = q; q = q->next; qsize--; 459 | } else if (qsize == 0 || !q) { 460 | /* q is empty; e must come from p. */ 461 | e = p; p = p->next; psize--; 462 | } else if (cmp(p->info,q->info,res) <= 0) { 463 | /* First element of p is lower (or same); e must come from p. */ 464 | e = p; p = p->next; psize--; 465 | } else { 466 | /* First element of q is lower; e must come from q. */ 467 | e = q; q = q->next; qsize--; 468 | } 469 | 470 | /* add the next element to the merged list */ 471 | if (tail) { 472 | tail->next = e; 473 | } else { 474 | list = e; 475 | } 476 | tail = e; 477 | } 478 | 479 | /* now p has stepped `insize' places along, and q has too */ 480 | p = q; 481 | } 482 | 483 | tail->next = NULL; 484 | 485 | /* If we have done only one merge, we're finished. */ 486 | if (nmerges <= 1) /* allow for nmerges==0, the empty list case */ 487 | return list; 488 | 489 | /* Otherwise repeat, merging lists twice the size */ 490 | insize *= 2; 491 | } 492 | #if COMPILER_REQUIRES_SORT_RETURN 493 | return list; 494 | #endif 495 | } 496 | -------------------------------------------------------------------------------- /core_main.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2018 Embedded Microprocessor Benchmark Consortium (EEMBC) 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | 16 | Original Author: Shay Gal-on 17 | */ 18 | 19 | /* File: core_main.c 20 | This file contains the framework to acquire a block of memory, seed initial parameters, tun t he benchmark and report the results. 21 | */ 22 | #include "coremark.h" 23 | 24 | /* Function: iterate 25 | Run the benchmark for a specified number of iterations. 26 | 27 | Operation: 28 | For each type of benchmarked algorithm: 29 | a - Initialize the data block for the algorithm. 30 | b - Execute the algorithm N times. 31 | 32 | Returns: 33 | NULL. 34 | */ 35 | static ee_u16 list_known_crc[] = {(ee_u16)0xd4b0,(ee_u16)0x3340,(ee_u16)0x6a79,(ee_u16)0xe714,(ee_u16)0xe3c1}; 36 | static ee_u16 matrix_known_crc[] = {(ee_u16)0xbe52,(ee_u16)0x1199,(ee_u16)0x5608,(ee_u16)0x1fd7,(ee_u16)0x0747}; 37 | static ee_u16 state_known_crc[] = {(ee_u16)0x5e47,(ee_u16)0x39bf,(ee_u16)0xe5a4,(ee_u16)0x8e3a,(ee_u16)0x8d84}; 38 | void *iterate(void *pres) { 39 | ee_u32 i; 40 | ee_u16 crc; 41 | core_results *res=(core_results *)pres; 42 | ee_u32 iterations=res->iterations; 43 | res->crc=0; 44 | res->crclist=0; 45 | res->crcmatrix=0; 46 | res->crcstate=0; 47 | 48 | for (i=0; icrc=crcu16(crc,res->crc); 51 | crc=core_bench_list(res,-1); 52 | res->crc=crcu16(crc,res->crc); 53 | if (i==0) res->crclist=res->crc; 54 | } 55 | return NULL; 56 | } 57 | 58 | #if (SEED_METHOD==SEED_ARG) 59 | ee_s32 get_seed_args(int i, int argc, char *argv[]); 60 | #define get_seed(x) (ee_s16)get_seed_args(x,argc,argv) 61 | #define get_seed_32(x) get_seed_args(x,argc,argv) 62 | #else /* via function or volatile */ 63 | ee_s32 get_seed_32(int i); 64 | #define get_seed(x) (ee_s16)get_seed_32(x) 65 | #endif 66 | 67 | #if (MEM_METHOD==MEM_STATIC) 68 | ee_u8 static_memblk[TOTAL_DATA_SIZE]; 69 | #endif 70 | char *mem_name[3] = {"Static","Heap","Stack"}; 71 | /* Function: main 72 | Main entry routine for the benchmark. 73 | This function is responsible for the following steps: 74 | 75 | 1 - Initialize input seeds from a source that cannot be determined at compile time. 76 | 2 - Initialize memory block for use. 77 | 3 - Run and time the benchmark. 78 | 4 - Report results, testing the validity of the output if the seeds are known. 79 | 80 | Arguments: 81 | 1 - first seed : Any value 82 | 2 - second seed : Must be identical to first for iterations to be identical 83 | 3 - third seed : Any value, should be at least an order of magnitude less then the input size, but bigger then 32. 84 | 4 - Iterations : Special, if set to 0, iterations will be automatically determined such that the benchmark will run between 10 to 100 secs 85 | 86 | */ 87 | 88 | #if MAIN_HAS_NOARGC 89 | MAIN_RETURN_TYPE main(void) { 90 | int argc=0; 91 | char *argv[1]; 92 | #else 93 | MAIN_RETURN_TYPE main(int argc, char *argv[]) { 94 | #endif 95 | ee_u16 i,j=0,num_algorithms=0; 96 | ee_s16 known_id=-1,total_errors=0; 97 | ee_u16 seedcrc=0; 98 | CORE_TICKS total_time; 99 | core_results results[MULTITHREAD]; 100 | #if (MEM_METHOD==MEM_STACK) 101 | ee_u8 stack_memblock[TOTAL_DATA_SIZE*MULTITHREAD]; 102 | #endif 103 | /* first call any initializations needed */ 104 | portable_init(&(results[0].port), &argc, argv); 105 | /* First some checks to make sure benchmark will run ok */ 106 | if (sizeof(struct list_head_s)>128) { 107 | ee_printf("list_head structure too big for comparable data!\n"); 108 | return MAIN_RETURN_VAL; 109 | } 110 | results[0].seed1=get_seed(1); 111 | results[0].seed2=get_seed(2); 112 | results[0].seed3=get_seed(3); 113 | results[0].iterations=get_seed_32(4); 114 | #if CORE_DEBUG 115 | results[0].iterations=1; 116 | #endif 117 | results[0].execs=get_seed_32(5); 118 | if (results[0].execs==0) { /* if not supplied, execute all algorithms */ 119 | results[0].execs=ALL_ALGORITHMS_MASK; 120 | } 121 | /* put in some default values based on one seed only for easy testing */ 122 | if ((results[0].seed1==0) && (results[0].seed2==0) && (results[0].seed3==0)) { /* validation run */ 123 | results[0].seed1=0; 124 | results[0].seed2=0; 125 | results[0].seed3=0x66; 126 | } 127 | if ((results[0].seed1==1) && (results[0].seed2==0) && (results[0].seed3==0)) { /* perfromance run */ 128 | results[0].seed1=0x3415; 129 | results[0].seed2=0x3415; 130 | results[0].seed3=0x66; 131 | } 132 | #if (MEM_METHOD==MEM_STATIC) 133 | results[0].memblock[0]=(void *)static_memblk; 134 | results[0].size=TOTAL_DATA_SIZE; 135 | results[0].err=0; 136 | #if (MULTITHREAD>1) 137 | #error "Cannot use a static data area with multiple contexts!" 138 | #endif 139 | #elif (MEM_METHOD==MEM_MALLOC) 140 | for (i=0 ; i1) 217 | if (default_num_contexts>MULTITHREAD) { 218 | default_num_contexts=MULTITHREAD; 219 | } 220 | for (i=0 ; i=0) { 265 | for (i=0 ; i 0) 292 | ee_printf("Iterations/Sec : %f\n",default_num_contexts*results[0].iterations/time_in_secs(total_time)); 293 | #else 294 | ee_printf("Total time (secs): %d\n",time_in_secs(total_time)); 295 | if (time_in_secs(total_time) > 0) 296 | ee_printf("Iterations/Sec : %d\n",default_num_contexts*results[0].iterations/time_in_secs(total_time)); 297 | #endif 298 | if (time_in_secs(total_time) < 10) { 299 | ee_printf("ERROR! Must execute for at least 10 secs for a valid result!\n"); 300 | total_errors++; 301 | } 302 | 303 | ee_printf("Iterations : %lu\n", (long unsigned) default_num_contexts*results[0].iterations); 304 | ee_printf("Compiler version : %s\n",COMPILER_VERSION); 305 | ee_printf("Compiler flags : %s\n",COMPILER_FLAGS); 306 | #if (MULTITHREAD>1) 307 | ee_printf("Parallel %s : %d\n",PARALLEL_METHOD,default_num_contexts); 308 | #endif 309 | ee_printf("Memory location : %s\n",MEM_LOCATION); 310 | /* output for verification */ 311 | ee_printf("seedcrc : 0x%04x\n",seedcrc); 312 | if (results[0].execs & ID_LIST) 313 | for (i=0 ; i1) 335 | ee_printf(" / %d:%s",default_num_contexts,PARALLEL_METHOD); 336 | #endif 337 | ee_printf("\n"); 338 | } 339 | #endif 340 | } 341 | if (total_errors>0) 342 | ee_printf("Errors detected\n"); 343 | if (total_errors<0) 344 | ee_printf("Cannot validate operation for these seed values, please compare with results on a known platform.\n"); 345 | 346 | #if (MEM_METHOD==MEM_MALLOC) 347 | for (i=0 ; i>(from)) & (~(0xffffffff << (to)))) 48 | 49 | #if CORE_DEBUG 50 | void printmat(MATDAT *A, ee_u32 N, char *name) { 51 | ee_u32 i,j; 52 | ee_printf("Matrix %s [%dx%d]:\n",name,N,N); 53 | for (i=0; i N times, 79 | changing the matrix values slightly by a constant amount each time. 80 | */ 81 | ee_u16 core_bench_matrix(mat_params *p, ee_s16 seed, ee_u16 crc) { 82 | ee_u32 N=p->N; 83 | MATRES *C=p->C; 84 | MATDAT *A=p->A; 85 | MATDAT *B=p->B; 86 | MATDAT val=(MATDAT)seed; 87 | 88 | crc=crc16(matrix_test(N,C,A,B,val),crc); 89 | 90 | return crc; 91 | } 92 | 93 | /* Function: matrix_test 94 | Perform matrix manipulation. 95 | 96 | Parameters: 97 | N - Dimensions of the matrix. 98 | C - memory for result matrix. 99 | A - input matrix 100 | B - operator matrix (not changed during operations) 101 | 102 | Returns: 103 | A CRC value that captures all results calculated in the function. 104 | In particular, crc of the value calculated on the result matrix 105 | after each step by . 106 | 107 | Operation: 108 | 109 | 1 - Add a constant value to all elements of a matrix. 110 | 2 - Multiply a matrix by a constant. 111 | 3 - Multiply a matrix by a vector. 112 | 4 - Multiply a matrix by a matrix. 113 | 5 - Add a constant value to all elements of a matrix. 114 | 115 | After the last step, matrix A is back to original contents. 116 | */ 117 | ee_s16 matrix_test(ee_u32 N, MATRES *C, MATDAT *A, MATDAT *B, MATDAT val) { 118 | ee_u16 crc=0; 119 | MATDAT clipval=matrix_big(val); 120 | 121 | matrix_add_const(N,A,val); /* make sure data changes */ 122 | #if CORE_DEBUG 123 | printmat(A,N,"matrix_add_const"); 124 | #endif 125 | matrix_mul_const(N,C,A,val); 126 | crc=crc16(matrix_sum(N,C,clipval),crc); 127 | #if CORE_DEBUG 128 | printmatC(C,N,"matrix_mul_const"); 129 | #endif 130 | matrix_mul_vect(N,C,A,B); 131 | crc=crc16(matrix_sum(N,C,clipval),crc); 132 | #if CORE_DEBUG 133 | printmatC(C,N,"matrix_mul_vect"); 134 | #endif 135 | matrix_mul_matrix(N,C,A,B); 136 | crc=crc16(matrix_sum(N,C,clipval),crc); 137 | #if CORE_DEBUG 138 | printmatC(C,N,"matrix_mul_matrix"); 139 | #endif 140 | matrix_mul_matrix_bitextract(N,C,A,B); 141 | crc=crc16(matrix_sum(N,C,clipval),crc); 142 | #if CORE_DEBUG 143 | printmatC(C,N,"matrix_mul_matrix_bitextract"); 144 | #endif 145 | 146 | matrix_add_const(N,A,-val); /* return matrix to initial value */ 147 | return crc; 148 | } 149 | 150 | /* Function : matrix_init 151 | Initialize the memory block for matrix benchmarking. 152 | 153 | Parameters: 154 | blksize - Size of memory to be initialized. 155 | memblk - Pointer to memory block. 156 | seed - Actual values chosen depend on the seed parameter. 157 | p - pointers to containing initialized matrixes. 158 | 159 | Returns: 160 | Matrix dimensions. 161 | 162 | Note: 163 | The seed parameter MUST be supplied from a source that cannot be determined at compile time 164 | */ 165 | ee_u32 core_init_matrix(ee_u32 blksize, void *memblk, ee_s32 seed, mat_params *p) { 166 | ee_u32 N=0; 167 | MATDAT *A; 168 | MATDAT *B; 169 | ee_s32 order=1; 170 | MATDAT val; 171 | ee_u32 i=0,j=0; 172 | if (seed==0) 173 | seed=1; 174 | while (jA=A; 196 | p->B=B; 197 | p->C=(MATRES *)align_mem(B+N*N); 198 | p->N=N; 199 | #if CORE_DEBUG 200 | printmat(A,N,"A"); 201 | printmat(B,N,"B"); 202 | #endif 203 | return N; 204 | } 205 | 206 | /* Function: matrix_sum 207 | Calculate a function that depends on the values of elements in the matrix. 208 | 209 | For each element, accumulate into a temporary variable. 210 | 211 | As long as this value is under the parameter clipval, 212 | add 1 to the result if the element is bigger then the previous. 213 | 214 | Otherwise, reset the accumulator and add 10 to the result. 215 | */ 216 | ee_s16 matrix_sum(ee_u32 N, MATRES *C, MATDAT clipval) { 217 | MATRES tmp=0,prev=0,cur=0; 218 | ee_s16 ret=0; 219 | ee_u32 i,j; 220 | for (i=0; iclipval) { 225 | ret+=10; 226 | tmp=0; 227 | } else { 228 | ret += (cur>prev) ? 1 : 0; 229 | } 230 | prev=cur; 231 | } 232 | } 233 | return ret; 234 | } 235 | 236 | /* Function: matrix_mul_const 237 | Multiply a matrix by a constant. 238 | This could be used as a scaler for instance. 239 | */ 240 | void matrix_mul_const(ee_u32 N, MATRES *C, MATDAT *A, MATDAT val) { 241 | ee_u32 i,j; 242 | for (i=0; i. 89 | This methodology is taken to accomodate any hardware or simulated platform. 90 | The sample implementation returns millisecs by default, 91 | and the resolution is controlled by 92 | */ 93 | CORE_TICKS get_time(void) { 94 | CORE_TICKS elapsed=(CORE_TICKS)(MYTIMEDIFF(stop_time_val, start_time_val)); 95 | return elapsed; 96 | } 97 | /* Function : time_in_secs 98 | Convert the value returned by get_time to seconds. 99 | 100 | The type is used to accomodate systems with no support for floating point. 101 | Default implementation implemented by the EE_TICKS_PER_SEC macro above. 102 | */ 103 | secs_ret time_in_secs(CORE_TICKS ticks) { 104 | secs_ret retval=((secs_ret)ticks) / (secs_ret)EE_TICKS_PER_SEC; 105 | return retval; 106 | } 107 | 108 | ee_u32 default_num_contexts=1; 109 | 110 | /* Function : portable_init 111 | Target specific initialization code 112 | Test for some common mistakes. 113 | */ 114 | void portable_init(core_portable *p, int *argc, char *argv[]) 115 | { 116 | // Serial.begin(9600); 117 | // #error "Call board initialization routines in portable init (if needed), in particular initialize UART!\n" 118 | if (sizeof(ee_ptr_int) != sizeof(ee_u8 *)) { 119 | ee_printf("ERROR! Please define ee_ptr_int to a type that holds a pointer!\n"); 120 | } 121 | if (sizeof(ee_u32) != 4) { 122 | ee_printf("ERROR! Please define ee_u32 to a 32b unsigned type!\n"); 123 | } 124 | p->portable_id=1; 125 | } 126 | /* Function : portable_fini 127 | Target specific final code 128 | */ 129 | void portable_fini(core_portable *p) 130 | { 131 | p->portable_id=0; 132 | } 133 | 134 | 135 | -------------------------------------------------------------------------------- /core_portme.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | // a minor hack to rename the main function, so we can call it from C++ 5 | #define main(ignore) coremark_main(void) 6 | 7 | #define FLAGS_STR "(flags unknown)" 8 | 9 | #define PERFORMANCE_RUN 1 10 | 11 | // 0 means auto-detect number of iterations for 10 second test 12 | #define ITERATIONS 0 13 | 14 | /* 15 | Copyright 2018 Embedded Microprocessor Benchmark Consortium (EEMBC) 16 | 17 | Licensed under the Apache License, Version 2.0 (the "License"); 18 | you may not use this file except in compliance with the License. 19 | You may obtain a copy of the License at 20 | 21 | http://www.apache.org/licenses/LICENSE-2.0 22 | 23 | Unless required by applicable law or agreed to in writing, software 24 | distributed under the License is distributed on an "AS IS" BASIS, 25 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 26 | See the License for the specific language governing permissions and 27 | limitations under the License. 28 | 29 | Original Author: Shay Gal-on 30 | */ 31 | /* Topic : Description 32 | This file contains configuration constants required to execute on different platforms 33 | */ 34 | #ifndef CORE_PORTME_H 35 | #define CORE_PORTME_H 36 | /************************/ 37 | /* Data types and settings */ 38 | /************************/ 39 | /* Configuration : HAS_FLOAT 40 | Define to 1 if the platform supports floating point. 41 | */ 42 | #ifndef HAS_FLOAT 43 | #define HAS_FLOAT 1 44 | #endif 45 | /* Configuration : HAS_TIME_H 46 | Define to 1 if platform has the time.h header file, 47 | and implementation of functions thereof. 48 | */ 49 | #ifndef HAS_TIME_H 50 | #define HAS_TIME_H 0 51 | #endif 52 | /* Configuration : USE_CLOCK 53 | Define to 1 if platform has the time.h header file, 54 | and implementation of functions thereof. 55 | */ 56 | #ifndef USE_CLOCK 57 | #define USE_CLOCK 0 58 | #endif 59 | /* Configuration : HAS_STDIO 60 | Define to 1 if the platform has stdio.h. 61 | */ 62 | #ifndef HAS_STDIO 63 | #define HAS_STDIO 1 64 | #endif 65 | /* Configuration : HAS_PRINTF 66 | Define to 1 if the platform has stdio.h and implements the printf function. 67 | */ 68 | #ifndef HAS_PRINTF 69 | #define HAS_PRINTF 0 70 | #endif 71 | 72 | 73 | /* Definitions : COMPILER_VERSION, COMPILER_FLAGS, MEM_LOCATION 74 | Initialize these strings per platform 75 | */ 76 | #ifndef COMPILER_VERSION 77 | #ifdef __GNUC__ 78 | #define COMPILER_VERSION "GCC"__VERSION__ 79 | #else 80 | #define COMPILER_VERSION "Please put compiler version here (e.g. gcc 4.1)" 81 | #endif 82 | #endif 83 | #ifndef COMPILER_FLAGS 84 | #define COMPILER_FLAGS FLAGS_STR /* "Please put compiler flags here (e.g. -o3)" */ 85 | #endif 86 | #ifndef MEM_LOCATION 87 | #define MEM_LOCATION "STACK" 88 | #endif 89 | 90 | /* Data Types : 91 | To avoid compiler issues, define the data types that need ot be used for 8b, 16b and 32b in . 92 | 93 | *Imprtant* : 94 | ee_ptr_int needs to be the data type used to hold pointers, otherwise coremark may fail!!! 95 | */ 96 | typedef int16_t ee_s16; 97 | typedef uint16_t ee_u16; 98 | typedef int32_t ee_s32; 99 | typedef double ee_f32; 100 | typedef uint8_t ee_u8; 101 | typedef uint32_t ee_u32; 102 | typedef uintptr_t ee_ptr_int; 103 | typedef size_t ee_size_t; 104 | #define NULL ((void *)0) 105 | /* align_mem : 106 | This macro is used to align an offset to point to a 32b value. It is used in the Matrix algorithm to initialize the input memory blocks. 107 | */ 108 | #define align_mem(x) (void *)(4 + (((ee_ptr_int)(x) - 1) & ~3)) 109 | 110 | /* Configuration : CORE_TICKS 111 | Define type of return from the timing functions. 112 | */ 113 | #define CORETIMETYPE ee_u32 114 | typedef ee_u32 CORE_TICKS; 115 | 116 | /* Configuration : SEED_METHOD 117 | Defines method to get seed values that cannot be computed at compile time. 118 | 119 | Valid values : 120 | SEED_ARG - from command line. 121 | SEED_FUNC - from a system function. 122 | SEED_VOLATILE - from volatile variables. 123 | */ 124 | #ifndef SEED_METHOD 125 | #define SEED_METHOD SEED_VOLATILE 126 | #endif 127 | 128 | /* Configuration : MEM_METHOD 129 | Defines method to get a block of memry. 130 | 131 | Valid values : 132 | MEM_MALLOC - for platforms that implement malloc and have malloc.h. 133 | MEM_STATIC - to use a static memory array. 134 | MEM_STACK - to allocate the data block on the stack (NYI). 135 | */ 136 | #ifndef MEM_METHOD 137 | #define MEM_METHOD MEM_STACK 138 | #endif 139 | 140 | /* Configuration : MULTITHREAD 141 | Define for parallel execution 142 | 143 | Valid values : 144 | 1 - only one context (default). 145 | N>1 - will execute N copies in parallel. 146 | 147 | Note : 148 | If this flag is defined to more then 1, an implementation for launching parallel contexts must be defined. 149 | 150 | Two sample implementations are provided. Use or to enable them. 151 | 152 | It is valid to have a different implementation of and in , 153 | to fit a particular architecture. 154 | */ 155 | #ifndef MULTITHREAD 156 | #define MULTITHREAD 1 157 | #define USE_PTHREAD 0 158 | #define USE_FORK 0 159 | #define USE_SOCKET 0 160 | #endif 161 | 162 | /* Configuration : MAIN_HAS_NOARGC 163 | Needed if platform does not support getting arguments to main. 164 | 165 | Valid values : 166 | 0 - argc/argv to main is supported 167 | 1 - argc/argv to main is not supported 168 | 169 | Note : 170 | This flag only matters if MULTITHREAD has been defined to a value greater then 1. 171 | */ 172 | #ifndef MAIN_HAS_NOARGC 173 | #define MAIN_HAS_NOARGC 1 174 | #endif 175 | 176 | /* Configuration : MAIN_HAS_NORETURN 177 | Needed if platform does not support returning a value from main. 178 | 179 | Valid values : 180 | 0 - main returns an int, and return value will be 0. 181 | 1 - platform does not support returning a value from main 182 | */ 183 | #ifndef MAIN_HAS_NORETURN 184 | #define MAIN_HAS_NORETURN 0 185 | #endif 186 | 187 | /* Variable : default_num_contexts 188 | Not used for this simple port, must cintain the value 1. 189 | */ 190 | extern ee_u32 default_num_contexts; 191 | 192 | typedef struct CORE_PORTABLE_S { 193 | ee_u8 portable_id; 194 | } core_portable; 195 | 196 | /* target specific init/fini */ 197 | void portable_init(core_portable *p, int *argc, char *argv[]); 198 | void portable_fini(core_portable *p); 199 | 200 | #if !defined(PROFILE_RUN) && !defined(PERFORMANCE_RUN) && !defined(VALIDATION_RUN) 201 | #if (TOTAL_DATA_SIZE==1200) 202 | #define PROFILE_RUN 1 203 | #elif (TOTAL_DATA_SIZE==2000) 204 | #define PERFORMANCE_RUN 1 205 | #else 206 | #define VALIDATION_RUN 1 207 | #endif 208 | #endif 209 | 210 | int ee_printf(const char *fmt, ...); 211 | 212 | #endif /* CORE_PORTME_H */ 213 | -------------------------------------------------------------------------------- /core_state.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2018 Embedded Microprocessor Benchmark Consortium (EEMBC) 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | 16 | Original Author: Shay Gal-on 17 | */ 18 | 19 | #include "coremark.h" 20 | /* local functions */ 21 | enum CORE_STATE core_state_transition( ee_u8 **instr , ee_u32 *transition_count); 22 | 23 | /* 24 | Topic: Description 25 | Simple state machines like this one are used in many embedded products. 26 | 27 | For more complex state machines, sometimes a state transition table implementation is used instead, 28 | trading speed of direct coding for ease of maintenance. 29 | 30 | Since the main goal of using a state machine in CoreMark is to excercise the switch/if behaviour, 31 | we are using a small moore machine. 32 | 33 | In particular, this machine tests type of string input, 34 | trying to determine whether the input is a number or something else. 35 | (see core_state.png). 36 | */ 37 | 38 | /* Function: core_bench_state 39 | Benchmark function 40 | 41 | Go over the input twice, once direct, and once after introducing some corruption. 42 | */ 43 | ee_u16 core_bench_state(ee_u32 blksize, ee_u8 *memblock, 44 | ee_s16 seed1, ee_s16 seed2, ee_s16 step, ee_u16 crc) 45 | { 46 | ee_u32 final_counts[NUM_CORE_STATES]; 47 | ee_u32 track_counts[NUM_CORE_STATES]; 48 | ee_u8 *p=memblock; 49 | ee_u32 i; 50 | 51 | 52 | #if CORE_DEBUG 53 | ee_printf("State Bench: %d,%d,%d,%04x\n",seed1,seed2,step,crc); 54 | #endif 55 | for (i=0; i0) { 127 | for(i=0;i>3) & 0x3]; 138 | next=4; 139 | break; 140 | case 3: /* float */ 141 | case 4: /* float */ 142 | buf=floatpat[(seed>>3) & 0x3]; 143 | next=8; 144 | break; 145 | case 5: /* scientific */ 146 | case 6: /* scientific */ 147 | buf=scipat[(seed>>3) & 0x3]; 148 | next=8; 149 | break; 150 | case 7: /* invalid */ 151 | buf=errpat[(seed>>3) & 0x3]; 152 | next=8; 153 | break; 154 | default: /* Never happen, just to make some compilers happy */ 155 | break; 156 | } 157 | } 158 | size++; 159 | while (total='0') & (c<='9')) ? 1 : 0; 171 | return retval; 172 | } 173 | 174 | /* Function: core_state_transition 175 | Actual state machine. 176 | 177 | The state machine will continue scanning until either: 178 | 1 - an invalid input is detcted. 179 | 2 - a valid number has been detected. 180 | 181 | The input pointer is updated to point to the end of the token, and the end state is returned (either specific format determined or invalid). 182 | */ 183 | 184 | enum CORE_STATE core_state_transition( ee_u8 **instr , ee_u32 *transition_count) { 185 | ee_u8 *str=*instr; 186 | ee_u8 NEXT_SYMBOL; 187 | enum CORE_STATE state=CORE_START; 188 | for( ; *str && state != CORE_INVALID; str++ ) { 189 | NEXT_SYMBOL = *str; 190 | if (NEXT_SYMBOL==',') /* end of this input */ { 191 | str++; 192 | break; 193 | } 194 | switch(state) { 195 | case CORE_START: 196 | if(ee_isdigit(NEXT_SYMBOL)) { 197 | state = CORE_INT; 198 | } 199 | else if( NEXT_SYMBOL == '+' || NEXT_SYMBOL == '-' ) { 200 | state = CORE_S1; 201 | } 202 | else if( NEXT_SYMBOL == '.' ) { 203 | state = CORE_FLOAT; 204 | } 205 | else { 206 | state = CORE_INVALID; 207 | transition_count[CORE_INVALID]++; 208 | } 209 | transition_count[CORE_START]++; 210 | break; 211 | case CORE_S1: 212 | if(ee_isdigit(NEXT_SYMBOL)) { 213 | state = CORE_INT; 214 | transition_count[CORE_S1]++; 215 | } 216 | else if( NEXT_SYMBOL == '.' ) { 217 | state = CORE_FLOAT; 218 | transition_count[CORE_S1]++; 219 | } 220 | else { 221 | state = CORE_INVALID; 222 | transition_count[CORE_S1]++; 223 | } 224 | break; 225 | case CORE_INT: 226 | if( NEXT_SYMBOL == '.' ) { 227 | state = CORE_FLOAT; 228 | transition_count[CORE_INT]++; 229 | } 230 | else if(!ee_isdigit(NEXT_SYMBOL)) { 231 | state = CORE_INVALID; 232 | transition_count[CORE_INT]++; 233 | } 234 | break; 235 | case CORE_FLOAT: 236 | if( NEXT_SYMBOL == 'E' || NEXT_SYMBOL == 'e' ) { 237 | state = CORE_S2; 238 | transition_count[CORE_FLOAT]++; 239 | } 240 | else if(!ee_isdigit(NEXT_SYMBOL)) { 241 | state = CORE_INVALID; 242 | transition_count[CORE_FLOAT]++; 243 | } 244 | break; 245 | case CORE_S2: 246 | if( NEXT_SYMBOL == '+' || NEXT_SYMBOL == '-' ) { 247 | state = CORE_EXPONENT; 248 | transition_count[CORE_S2]++; 249 | } 250 | else { 251 | state = CORE_INVALID; 252 | transition_count[CORE_S2]++; 253 | } 254 | break; 255 | case CORE_EXPONENT: 256 | if(ee_isdigit(NEXT_SYMBOL)) { 257 | state = CORE_SCIENTIFIC; 258 | transition_count[CORE_EXPONENT]++; 259 | } 260 | else { 261 | state = CORE_INVALID; 262 | transition_count[CORE_EXPONENT]++; 263 | } 264 | break; 265 | case CORE_SCIENTIFIC: 266 | if(!ee_isdigit(NEXT_SYMBOL)) { 267 | state = CORE_INVALID; 268 | transition_count[CORE_INVALID]++; 269 | } 270 | break; 271 | default: 272 | break; 273 | } 274 | } 275 | *instr=str; 276 | return state; 277 | } 278 | -------------------------------------------------------------------------------- /core_util.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2018 Embedded Microprocessor Benchmark Consortium (EEMBC) 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | 16 | Original Author: Shay Gal-on 17 | */ 18 | 19 | #include "coremark.h" 20 | /* Function: get_seed 21 | Get a values that cannot be determined at compile time. 22 | 23 | Since different embedded systems and compilers are used, 3 different methods are provided: 24 | 1 - Using a volatile variable. This method is only valid if the compiler is forced to generate code that 25 | reads the value of a volatile variable from memory at run time. 26 | Please note, if using this method, you would need to modify core_portme.c to generate training profile. 27 | 2 - Command line arguments. This is the preferred method if command line arguments are supported. 28 | 3 - System function. If none of the first 2 methods is available on the platform, 29 | a system function which is not a stub can be used. 30 | 31 | e.g. read the value on GPIO pins connected to switches, or invoke special simulator functions. 32 | */ 33 | #if (SEED_METHOD==SEED_VOLATILE) 34 | extern volatile ee_s32 seed1_volatile; 35 | extern volatile ee_s32 seed2_volatile; 36 | extern volatile ee_s32 seed3_volatile; 37 | extern volatile ee_s32 seed4_volatile; 38 | extern volatile ee_s32 seed5_volatile; 39 | ee_s32 get_seed_32(int i) { 40 | ee_s32 retval; 41 | switch (i) { 42 | case 1: 43 | retval=seed1_volatile; 44 | break; 45 | case 2: 46 | retval=seed2_volatile; 47 | break; 48 | case 3: 49 | retval=seed3_volatile; 50 | break; 51 | case 4: 52 | retval=seed4_volatile; 53 | break; 54 | case 5: 55 | retval=seed5_volatile; 56 | break; 57 | default: 58 | retval=0; 59 | break; 60 | } 61 | return retval; 62 | } 63 | #elif (SEED_METHOD==SEED_ARG) 64 | ee_s32 parseval(char *valstring) { 65 | ee_s32 retval=0; 66 | ee_s32 neg=1; 67 | int hexmode=0; 68 | if (*valstring == '-') { 69 | neg=-1; 70 | valstring++; 71 | } 72 | if ((valstring[0] == '0') && (valstring[1] == 'x')) { 73 | hexmode=1; 74 | valstring+=2; 75 | } 76 | /* first look for digits */ 77 | if (hexmode) { 78 | while (((*valstring >= '0') && (*valstring <= '9')) || ((*valstring >= 'a') && (*valstring <= 'f'))) { 79 | ee_s32 digit=*valstring-'0'; 80 | if (digit>9) 81 | digit=10+*valstring-'a'; 82 | retval*=16; 83 | retval+=digit; 84 | valstring++; 85 | } 86 | } else { 87 | while ((*valstring >= '0') && (*valstring <= '9')) { 88 | ee_s32 digit=*valstring-'0'; 89 | retval*=10; 90 | retval+=digit; 91 | valstring++; 92 | } 93 | } 94 | /* now add qualifiers */ 95 | if (*valstring=='K') 96 | retval*=1024; 97 | if (*valstring=='M') 98 | retval*=1024*1024; 99 | 100 | retval*=neg; 101 | return retval; 102 | } 103 | 104 | ee_s32 get_seed_args(int i, int argc, char *argv[]) { 105 | if (argc>i) 106 | return parseval(argv[i]); 107 | return 0; 108 | } 109 | 110 | #elif (SEED_METHOD==SEED_FUNC) 111 | /* If using OS based function, you must define and implement the functions below in core_portme.h and core_portme.c ! */ 112 | ee_s32 get_seed_32(int i) { 113 | ee_s32 retval; 114 | switch (i) { 115 | case 1: 116 | retval=portme_sys1(); 117 | break; 118 | case 2: 119 | retval=portme_sys2(); 120 | break; 121 | case 3: 122 | retval=portme_sys3(); 123 | break; 124 | case 4: 125 | retval=portme_sys4(); 126 | break; 127 | case 5: 128 | retval=portme_sys5(); 129 | break; 130 | default: 131 | retval=0; 132 | break; 133 | } 134 | return retval; 135 | } 136 | #endif 137 | 138 | /* Function: crc* 139 | Service functions to calculate 16b CRC code. 140 | 141 | */ 142 | ee_u16 crcu8(ee_u8 data, ee_u16 crc ) 143 | { 144 | ee_u8 i=0,x16=0,carry=0; 145 | 146 | for (i = 0; i < 8; i++) 147 | { 148 | x16 = (ee_u8)((data & 1) ^ ((ee_u8)crc & 1)); 149 | data >>= 1; 150 | 151 | if (x16 == 1) 152 | { 153 | crc ^= 0x4002; 154 | carry = 1; 155 | } 156 | else 157 | carry = 0; 158 | crc >>= 1; 159 | if (carry) 160 | crc |= 0x8000; 161 | else 162 | crc &= 0x7fff; 163 | } 164 | return crc; 165 | } 166 | ee_u16 crcu16(ee_u16 newval, ee_u16 crc) { 167 | crc=crcu8( (ee_u8) (newval) ,crc); 168 | crc=crcu8( (ee_u8) ((newval)>>8) ,crc); 169 | return crc; 170 | } 171 | ee_u16 crcu32(ee_u32 newval, ee_u16 crc) { 172 | crc=crc16((ee_s16) newval ,crc); 173 | crc=crc16((ee_s16) (newval>>16) ,crc); 174 | return crc; 175 | } 176 | ee_u16 crc16(ee_s16 newval, ee_u16 crc) { 177 | return crcu16((ee_u16)newval, crc); 178 | } 179 | 180 | ee_u8 check_data_types() { 181 | ee_u8 retval=0; 182 | if (sizeof(ee_u8) != 1) { 183 | ee_printf("ERROR: ee_u8 is not an 8b datatype!\n"); 184 | retval++; 185 | } 186 | if (sizeof(ee_u16) != 2) { 187 | ee_printf("ERROR: ee_u16 is not a 16b datatype!\n"); 188 | retval++; 189 | } 190 | if (sizeof(ee_s16) != 2) { 191 | ee_printf("ERROR: ee_s16 is not a 16b datatype!\n"); 192 | retval++; 193 | } 194 | if (sizeof(ee_s32) != 4) { 195 | ee_printf("ERROR: ee_s32 is not a 32b datatype!\n"); 196 | retval++; 197 | } 198 | if (sizeof(ee_u32) != 4) { 199 | ee_printf("ERROR: ee_u32 is not a 32b datatype!\n"); 200 | retval++; 201 | } 202 | if (sizeof(ee_ptr_int) != sizeof(int *)) { 203 | ee_printf("ERROR: ee_ptr_int is not a datatype that holds an int pointer!\n"); 204 | retval++; 205 | } 206 | if (retval>0) { 207 | ee_printf("ERROR: Please modify the datatypes in core_portme.h!\n"); 208 | } 209 | return retval; 210 | } 211 | -------------------------------------------------------------------------------- /coremark.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2018 Embedded Microprocessor Benchmark Consortium (EEMBC) 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | 16 | Original Author: Shay Gal-on 17 | */ 18 | 19 | /* Topic: Description 20 | This file contains declarations of the various benchmark functions. 21 | */ 22 | 23 | /* Configuration: TOTAL_DATA_SIZE 24 | Define total size for data algorithms will operate on 25 | */ 26 | #ifndef TOTAL_DATA_SIZE 27 | #define TOTAL_DATA_SIZE 2*1000 28 | #endif 29 | 30 | #define SEED_ARG 0 31 | #define SEED_FUNC 1 32 | #define SEED_VOLATILE 2 33 | 34 | #define MEM_STATIC 0 35 | #define MEM_MALLOC 1 36 | #define MEM_STACK 2 37 | 38 | #include "core_portme.h" 39 | 40 | #if HAS_STDIO 41 | #include 42 | #endif 43 | #if HAS_PRINTF 44 | #define ee_printf printf 45 | #endif 46 | 47 | /* Actual benchmark execution in iterate */ 48 | void *iterate(void *pres); 49 | 50 | /* Typedef: secs_ret 51 | For machines that have floating point support, get number of seconds as a double. 52 | Otherwise an unsigned int. 53 | */ 54 | #if HAS_FLOAT 55 | typedef double secs_ret; 56 | #else 57 | typedef ee_u32 secs_ret; 58 | #endif 59 | 60 | #if MAIN_HAS_NORETURN 61 | #define MAIN_RETURN_VAL 62 | #define MAIN_RETURN_TYPE void 63 | #else 64 | #define MAIN_RETURN_VAL 0 65 | #define MAIN_RETURN_TYPE int 66 | #endif 67 | 68 | void start_time(void); 69 | void stop_time(void); 70 | CORE_TICKS get_time(void); 71 | secs_ret time_in_secs(CORE_TICKS ticks); 72 | 73 | /* Misc useful functions */ 74 | ee_u16 crcu8(ee_u8 data, ee_u16 crc); 75 | ee_u16 crc16(ee_s16 newval, ee_u16 crc); 76 | ee_u16 crcu16(ee_u16 newval, ee_u16 crc); 77 | ee_u16 crcu32(ee_u32 newval, ee_u16 crc); 78 | ee_u8 check_data_types(); 79 | void *portable_malloc(ee_size_t size); 80 | void portable_free(void *p); 81 | ee_s32 parseval(char *valstring); 82 | 83 | /* Algorithm IDS */ 84 | #define ID_LIST (1<<0) 85 | #define ID_MATRIX (1<<1) 86 | #define ID_STATE (1<<2) 87 | #define ALL_ALGORITHMS_MASK (ID_LIST|ID_MATRIX|ID_STATE) 88 | #define NUM_ALGORITHMS 3 89 | 90 | /* list data structures */ 91 | typedef struct list_data_s { 92 | ee_s16 data16; 93 | ee_s16 idx; 94 | } list_data; 95 | 96 | typedef struct list_head_s { 97 | struct list_head_s *next; 98 | struct list_data_s *info; 99 | } list_head; 100 | 101 | 102 | /*matrix benchmark related stuff */ 103 | #define MATDAT_INT 1 104 | #if MATDAT_INT 105 | typedef ee_s16 MATDAT; 106 | typedef ee_s32 MATRES; 107 | #else 108 | typedef ee_f16 MATDAT; 109 | typedef ee_f32 MATRES; 110 | #endif 111 | 112 | typedef struct MAT_PARAMS_S { 113 | int N; 114 | MATDAT *A; 115 | MATDAT *B; 116 | MATRES *C; 117 | } mat_params; 118 | 119 | /* state machine related stuff */ 120 | /* List of all the possible states for the FSM */ 121 | typedef enum CORE_STATE { 122 | CORE_START=0, 123 | CORE_INVALID, 124 | CORE_S1, 125 | CORE_S2, 126 | CORE_INT, 127 | CORE_FLOAT, 128 | CORE_EXPONENT, 129 | CORE_SCIENTIFIC, 130 | NUM_CORE_STATES 131 | } core_state_e ; 132 | 133 | 134 | /* Helper structure to hold results */ 135 | typedef struct RESULTS_S { 136 | /* inputs */ 137 | ee_s16 seed1; /* Initializing seed */ 138 | ee_s16 seed2; /* Initializing seed */ 139 | ee_s16 seed3; /* Initializing seed */ 140 | void *memblock[4]; /* Pointer to safe memory location */ 141 | ee_u32 size; /* Size of the data */ 142 | ee_u32 iterations; /* Number of iterations to execute */ 143 | ee_u32 execs; /* Bitmask of operations to execute */ 144 | struct list_head_s *list; 145 | mat_params mat; 146 | /* outputs */ 147 | ee_u16 crc; 148 | ee_u16 crclist; 149 | ee_u16 crcmatrix; 150 | ee_u16 crcstate; 151 | ee_s16 err; 152 | /* ultithread specific */ 153 | core_portable port; 154 | } core_results; 155 | 156 | /* Multicore execution handling */ 157 | #if (MULTITHREAD>1) 158 | ee_u8 core_start_parallel(core_results *res); 159 | ee_u8 core_stop_parallel(core_results *res); 160 | #endif 161 | 162 | /* list benchmark functions */ 163 | list_head *core_list_init(ee_u32 blksize, list_head *memblock, ee_s16 seed); 164 | ee_u16 core_bench_list(core_results *res, ee_s16 finder_idx); 165 | 166 | /* state benchmark functions */ 167 | void core_init_state(ee_u32 size, ee_s16 seed, ee_u8 *p); 168 | ee_u16 core_bench_state(ee_u32 blksize, ee_u8 *memblock, 169 | ee_s16 seed1, ee_s16 seed2, ee_s16 step, ee_u16 crc); 170 | 171 | /* matrix benchmark functions */ 172 | ee_u32 core_init_matrix(ee_u32 blksize, void *memblk, ee_s32 seed, mat_params *p); 173 | ee_u16 core_bench_matrix(mat_params *p, ee_s16 seed, ee_u16 crc); 174 | 175 | --------------------------------------------------------------------------------