# CoreMark measures only the processor core, and its run rules decide if the number counts

> CoreMark is the EEMBC benchmark for comparing processors, designed so that a score means the same thing on a microcontroller and on a desktop CPU. The rules are strict: a run under ten seconds is not reportable, only the porting layer may be changed, and results carry the compiler flags they were built with. It is a small C codebase with a Makefile and a set of porting files.

**eembc/coremark** — CoreMark® is an industry-standard benchmark that measures the performance of central processing units (CPU) and embedded microcrontrollers (MCU).

- Repository: https://github.com/eembc/coremark
- Stars: 1,274 · Forks: 422
- Language: C
- License: NOASSERTION
- Published: 2026-10-19 · Updated: 2026-10-19 · Language: en
- Canonical page: https://hysenlabs.com/projects/eembc-coremark

## The benchmark is narrow on purpose

CoreMark's stated primary goals are simplicity and providing a method for testing only a processor's core features. That second phrase is the design brief, and it explains both what the benchmark is good at and what it will never tell you.

The project describes itself as an industry-standard benchmark that measures the performance of central processing units and embedded microcontrollers. It comes from the Embedded Microprocessor Benchmark Consortium, and the README points at eembc.org for the organisation's broader embedded benchmark suites, and at CoreMark-PRO for a more compute-intensive version that uses larger datasets and execution loops taken from common applications.

So the scope is the processor core. The workloads are list handling, matrix manipulation and state management, in the source files core_list_join.c, core_matrix.c and core_state.c, with core_util.c and core_main.c as the framework around them. There is no I/O, no memory bandwidth test, no floating point emphasis, and no application level behaviour.

That narrowness is the feature for the embedded case, where there is no realistic application to benchmark against and the question is instead how fast the core executes. It is also the reason a CoreMark number is not a general purpose CPU ranking, and the reporting rules in the README are written to keep that comparison honest.

## Only the porting layer may change, and make check proves it

The constraint that defines the whole benchmark is the set of files a porter is allowed to touch. The core sources are core_list_join.c, core_main.c, core_matrix.c, core_state.c and core_util.c, and the porting layer is core_portme.c, core_portme.h and core_portme.mak inside a platform directory.

The NOT ALLOWED list in the run rules has exactly one item: changing of source file other than core_portme*, with the note to use make check to validate. The check target tests the MD5 of sources that may not be modified, and the repository ships coremark.md5 for that purpose. That is a stronger guarantee than a guideline, because a porter cannot quietly optimise the matrix code and still call the result CoreMark.

What a porter may change is listed just as precisely: the number of iterations, the toolchain and build, load and run options, the method of acquiring a data memory block, the method of acquiring seed values, the implementation in core_portme.c, the configuration values in core_portme.h, and core_portme.mak. The intent is that the port adapts the benchmark to the platform while the workload and the algorithm stay comparable.

The alternative to a port directory is a barebones port. For microcontrollers and embedded processor systems without an OS, the README points at barebones_porting.md, and there is a barebones/ directory in the repository alongside ready made ports for linux, macos, cygwin, freebsd, posix, rtems, simple and zephyr.

## A score is only reportable if the run rules were followed

The run rules section is the most useful part of the README for anyone reading a published CoreMark number, because it defines what disqualifies it.

The benchmark has to run for at least ten seconds, and the README says results are only valid for reporting if that was the case. Validation must succeed for two seed sets, 0,0,0x66 and 0x3415,0x3415,0x66, with a buffer size of 2000 bytes total. If the target does not accept command line arguments, both runs have to be built explicitly.

```bash
% make XCFLAGS="-DPERFORMANCE_RUN=1" REBUILD=1 run1.log
% make XCFLAGS="-DVALIDATION_RUN=1" REBUILD=1 run2.log
```

Profile guided optimization has its own rule: the profile must be generated with seeds of 8,8,8 and a buffer size of 1200 bytes total, using a third run target.

```bash
% make XCFLAGS="-DTOTAL_DATA_SIZE=1200 -DPROFILE_RUN=1" REBUILD=1 run3.log
```

Two further rules are about the build rather than the run. All source files must be compiled with the same flags, and the data type sizes must match exactly in bits, with ee_u8 an unsigned 8-bit type, ee_s16 a signed 16-bit type, ee_u16 unsigned 16-bit, ee_s32 signed 32-bit and ee_u32 unsigned 32-bit. The reason is obvious once stated: the algorithms and their iteration counts are chosen so the work is the same only if the types are the same size.

The consequence for a reader of published results is that a CoreMark score without the compiler flags attached is close to meaningless, which is why the reporting syntax demands them.

## Building on a Linux host is one make command

On a typical Linux system, the README says to type make, and that is the whole build. The Makefile picks the port directory automatically from the uname output, choosing cygwin, macos, freebsd or linux accordingly, and it errors out with PLEASE define PORT_DIR if it cannot detect a platform, for example with make PORT_DIR=simple.

The default target is run, and the results land in files. The README says full results are available in run1.log and run2.log, and that the CoreMark result can be found in run1.log. The make targets listed in the README map directly onto the phases: run creates run1.log and run2.log, run1.log runs the benchmark with performance parameters, run2.log with validation parameters, run3.log with profile generation parameters, compile compiles the benchmark executable, link links it, check tests the MD5 of the sources that may not be modified, and clean removes temporary files.

The iteration count is a make variable. By default the benchmark runs between ten and one hundred seconds, and ITERATIONS=N overrides that.

```bash
% make ITERATIONS=10
```

The README recommends pinning the iteration count in certain situations, naming a simulator, measuring power or energy, and a case where timing cannot be restarted. That is the mechanism for running the benchmark on hardware where the usual self timing does not apply, and it is also where the accuracy of the result depends on the harness rather than on the core.

Two more flags exist for edge cases. XCFLAGS adds compiler flags from the command line, and CORE_DEBUG is defined to compile for a debug run if you get an incorrect CRC. REBUILD forces a rebuild of the executable, which is what the run rules above rely on when switching between a performance and a validation build.

## Parallel runs and targets without a command line

Two features take CoreMark beyond a single core, and both are implemented in the porting layer rather than in the benchmark core.

The first is parallel execution. XCFLAGS=-DMULTITHREAD=N sets the number of threads to run in parallel, and several implementations are available, or you can implement your own in core_portme.c. The README gives the POSIX threads variant and the fork variant.

```bash
% make XCFLAGS="-DMULTITHREAD=4 -DUSE_PTHREAD -pthread"
% make XCFLAGS="-DMULTITHREAD=4 -DUSE_FORK"
```

There is a practical warning attached: linking may fail on the pthread build if the linker does not add the pthread library automatically, showing undefined reference errors, in which case you add -pthread to the LFLAGS_END parameter in core_portme.mak for your platform.

The second feature is for targets that do not use malloc and do not support command line arguments. In that case the buffer size for the algorithms must be defined through the compiler define TOTAL_DATA_SIZE, which must be set to 2000 bytes for standard runs, and MAIN_HAS_NOARGC tells the build that main takes no arguments.

```bash
% make XCFLAGS="-DTOTAL_DATA_SIZE=6000 -DMAIN_HAS_NOARGC=1"
```

The example in the README uses 6000, and the comment notes that a different value is a reasonable default when testing different configurations. This is also the path a barebones microcontroller takes, where the whole benchmark is compiled with the toolchain for the target and run on the device.

## The reporting syntax is what makes two numbers comparable

The README gives the syntax for reporting a result on a data sheet.

CoreMark 1.0: N / C [/ P] [/ M]

N is the number of iterations per second with seeds 0,0,0x66 and size 2000. C is the compiler version and flags. P covers parameters such as data and code allocation specifics, and it may be omitted if all data was allocated on the heap in RAM, but it may not be omitted when reporting CoreMark per MHz. M describes the type of parallel execution, if used, and the number of contexts, and it may be omitted if parallel execution was not used.

The example given is CoreMark 1.0: 128 / GCC 4.1.2 -O2 -fprofile-use, which shows the shape of a real entry: a number, a compiler and a flag set, and nothing else because the data was on the heap and no parallel execution was involved.

The two optional fields are where a number quietly becomes incomparable. The P field exists because where the data lives changes the result, and the M field exists because a four core score and a one core score are not the same measurement. A score that omits the parallel context count is the easiest way to make a number look better than it is.

Results can also be submitted on the web, through the submission page at eembc.org, after registering an account. The licence is a custom one that GitHub does not classify, with the file at LICENSE.md, while the Makefile header in the repository carries the Apache License 2.0 text with a 2018 EEMBC copyright. The last push was on 2026-10-17, and the only listed release is the v1.01 tag from 2009, which is consistent with a benchmark whose rules have to stay fixed for its scores to remain comparable.

## Conclusion

CoreMark is the right tool when you need a single comparable number for a processor, especially an embedded one where nothing else is available. It is the wrong tool for ranking general purpose CPUs on real workloads, since it deliberately exercises only core features and the rules forbid changing the algorithms. Verify first that you can satisfy the run rules before quoting a score, in particular the ten second minimum and the two validation seeds, and record the compiler version and flags, because the reporting syntax requires them and a score without them is not comparable.

## FAQ

### How do I build and run CoreMark?

On a typical Linux system, type make. The Makefile selects the port directory from the platform name, and the default target writes the results to run1.log and run2.log, with the CoreMark result in run1.log. The README also lists a manual gcc command for systems without make.

### What are the rules for a CoreMark result to be valid?

The benchmark has to run for at least ten seconds, validation must succeed for the seeds 0,0,0x66 and 0x3415,0x3415,0x66 with a total buffer size of 2000 bytes, all source files must be compiled with the same flags, and the data type sizes must match the required bit widths.

### Which files am I allowed to modify when porting CoreMark?

Only the porting layer, meaning core_portme.c, core_portme.h and core_portme.mak, along with settings such as the iteration count, toolchain options, memory allocation method and seed acquisition. Changing any other source file is not allowed, and the make check target validates that with MD5 checks.

### How do I run CoreMark on multiple cores?

Use the compiler flag MULTITHREAD=N with the number of threads, either with the POSIX threads implementation, XCFLAGS="-DMULTITHREAD=4 -DUSE_PTHREAD -pthread", or with forking, XCFLAGS="-DMULTITHREAD=4 -DUSE_FORK". Several implementations are provided, and you can write your own in core_portme.c.

### How should a CoreMark result be reported?

The syntax is CoreMark 1.0 : N / C [/ P] [/ M], where N is iterations per second, C the compiler version and flags, P the data and code allocation parameters, which may not be omitted when reporting CoreMark per MHz, and M the type of parallel execution and number of contexts.

## Sources

- [eembc/coremark on GitHub](https://github.com/eembc/coremark)
- [Issues](https://github.com/eembc/coremark/issues)
- [README](https://github.com/eembc/coremark/blob/main/README.md)
- [Releases](https://github.com/eembc/coremark/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/eembc-coremark
