NOTE: Fracture was built to provide a very basic API which allowed you to utilize multi-cpu / multi-core architectures prior to the inclusion of better libraries in the JDK with the same goal. Unless you are using a rather old JDK, I suggest using the Fork Join and concurrency features built into modern JDKs.


Fracture is a Java library which simplifies multi-core development. Currently, this library is very simple, providing a single public class (com.kccoder.fracture.Fracture) which contains the static methods needed to transform your single-core loops into multi-core loops with minimal effort. Future releases will provide solutions for more complex situations as well as reveal the objects present 'under-the-hood' to enable custom solutions.

Usage

To use Fracture simply replace a cpu intensive loop with the appropriate Fracture method call. For example:
for(DifferentialEquation deq : equations) {
  solve(deq);
}
becomes
Fracture.forEach(equations, new IProcessor<DifferentialEquation>() {
  public void processElement(DifferentialEquation deq) {
    solve(deq);
  }
});

It should be noted that there is overhead associated with using Fracture (synchronization and coordination). So, if solve() executes very quickly or total loop execution is very quick, you will experience very little gain in performance (you might even experience a degradation). However, for sufficiently lengthy tasks, you should experience a sizable increase in performance. Further examples are included in the distribution (package com.kccoder.fracture.example).

Performance Measurement

The utility class com.kccoder.fracture.util.MethodTimer is provided to help you quantify performance gains (or losses) exhibited with Fracture's use. For example:
public static void main(String[] args) {
  MethodTimer.compareMethods(MandelbrodtExample.class, "normalWay", "fractureWay");
}

public static void normalWay() {
  for(int x = 0; x < 1280; x++) {
    mandelbrot(x);
  }
}

public static void fractureWay() {
  Fracture.forEach(0, 1280, 1, new IProcessor<Integer>() {
    public void processElement(Integer x) {
      mandelbrot(x);
    }
  });
}
produces on a Core2Duo MacBook:
Method [com.kccoder.fracture.example.MandelbrodtExample.normalWay] took [12390] millis to complete
Method [com.kccoder.fracture.example.MandelbrodtExample.fractureWay] took [6445] millis to complete
fractureWay executed [1.9224204809930179] times faster than normalWay
produces on a 8x2.8Ghz Mac Pro:
Method [com.kccoder.fracture.example.MandelbrodtExample.normalWay] took [8627] millis to complete
Method [com.kccoder.fracture.example.MandelbrodtExample.fractureWay] took [1213] millis to complete
fractureWay executed [7.112118713932399] times faster than normalWay

Core Mode

By default Fracture uses all available cores; however, you can configure Fracture to use fewer cores by setting the CoreMode via Fracture.setCoreMode(). The modes available are pretty self explanatory. Future releases will provide more sophisticated (and granular) configuration options.

Thread Safety

It should be noted that objects referenced by your IProcessor must be thread-safe. So, if you are putting/getting things into/out-of a Map, you need to either synchronize on that Map or use a Thread-Safe version (checkout the sycnrhonizedX methods in java.util.Collections).

Loop Iteration Independence

In addition to thread saftey, you will also need to be sure that the successful processing of loop iteration X is not dependent on X-1. For example the below cannot be simply migrated to Fracture as each loop iteration is dependent on previous iterations:
int fibonacci = 0;
int t = 1;
for(int n = 0; n < 10; n++) {
  fibonacci = fibonacci + t;
  t = fibonacci - t;
}

Releases

Fracture Release 0.2 -
This release focuses on reducing synchronization overhead for data sets which allow for random access, the addition of rudimentary JUnit test cases and a few refactorings.

Fracture Release 0.1 -
This is the initial release of Fracture.

Feedback

Feedback is appreciated and can be directed to csshelton [at] gmail [dot] com.