Unit Tests
Unit test Guide Find out how to run Junit tests and how to add new tests.
Unit Test Guide
The Unit Test Guide explains the test infrastructure associated with Aparapi, including instructions for executing existing tests adding new test cases. OpenCL™ code generation tests
The initial open source tree includes the codegen subdirectory (test/codegen), which used to validate the Aparapi bytecode to OpenCL™ conversion.
/src/test/java/
com/aparapi/
codegen/
test/
pom.xml
The code generation tests to not require OpenCL™ , AMD APP SDK or a GPU devices to be configured; these tests only validate the creation of valid OpenCL™ code by comparing against predefined expected output.
Running the OpenCL™ code generation JUnit tests
Before executing the code generation tests, build the com.aparapi sub-project and ensure that you have JUnit 4 installed.
Edit the junit.jar property in test/codegen/build.xml to point to your install directory.
<property name="junit.jar" value="C:\JUnit4.9\junit-4.9.jar"/>
Initiate the code generation tests using ant.
C:\> cd tests/codegen
C:\> ant
<failures will be reported here>
C:>
View the HTML version of the JUnit report at junit/html/index.html. On Microsoft Windows® platforms use
C:\> start junit\html\index.html
On Linux® platforms just invoke your browser (Firefox in this case).
firefox junit\html\index.html
Adding a new OpenCL™ code generation test
The test cases for OpenCL™ code generation are not strictly JUnit tests. Instead the codegen Java tree contains a tool (CreateJUnitTests) to create JUnit test cases from specially formatted test source files.
The package com.aparapi.test (codegen/src/java/com/aparapi/test)
contains all of the existing code generation tests.
Here is an example that tests the code generation resulting from a call to Kernel.getPassId(), this is taken from com.aparapi.test.CallGetPassId
package com.aparapi.test;
import com.aparapi.Kernel;
public class CallGetPassId extends Kernel{
public void run() {
int thePassId = getPassId();
}
}
/**{OpenCL{
typedef struct This_s{
int passid;
}This;
int get_pass_id(This *this){
return this->passid;
}
__kernel void run(
int passid
){
This thisStruct;
This* this=&thisStruct;
this->passid = passid;
{
int thePassId = get_pass_id(this);
return;
}
}
}OpenCL}**/
The test source takes the form of a simple class that extends the kernel and a block of OpenCL code between the /{OpenCL{ and }OpenCL}/ markers. The code between these markers is the OpenCL code that we expect Aparapi to produce as a result of converting the run() method to OpenCL.
The code-generating ant build.xml file performs the following steps to generate its report:
- compiles the src/java tree. This compiles all the test cases as well as a few ‘utility’ classes.
- executes the com.aparapi.test.CreateJUnitTests program. This iterates through all of the test source files and converts them to JUnit form. The generated source is written to the src/genjava tree.
- compiles the src/genjava tree to create the required JUnit classes
- initiates the JUnit test phase (result data in junit/data)
- creates the JUnit report (in junit/html/junit from junit/data)
To create a new test case, just add your test case to the codegen/src/java/com/aparapi/test
package (including the expected OpenCL).
Sometimes different javac implementations (such as Oracle and Eclipse) will generate different bytecode for the same source. When Aparapi converts this bytecode it may yield different (but equally acceptable) OpenCL forms. One example of this is the BooleanToggle test:
public class BooleanToggle{
public void run() {
boolean pass = false;
pass = !pass;
}
}
The BooleanToggle test code creates two (slightly different) versions of OpenCL™ (sadly one line different) depending on the javac compiler.
This example shows the ‘toggle’ OpenCL™ created from the bytecode generated by Oracle.
pass = pass==1?0:1;
This example shows the bytecode from Eclipse javac:
pass = pass==0?1:0;
Logically either of the above are correct. However, to accommodate the alternate acceptable forms we need to add two complete /**{OpenCL{ and }OpenCL}**/
sections to the file. If either matches, the test will pass.
Here is the complete BooleanToggle code.
package com.aparapi.test;
public class BooleanToggle{
public void run() {
boolean pass = false;
pass = !pass;
}
}
/**{OpenCL{
typedef struct This_s{
int passid;
}This;
int get_pass_id(This *this){
return this->passid;
}
__kernel void run(
int passid
){
This thisStruct;
This* this=&thisStruct;
this->passid = passid;
{
char pass = 0;
pass = (pass==0)?1:0;
return;
}
}
}OpenCL}**/
/**{OpenCL{
typedef struct This_s{
int passid;
}This;
int get_pass_id(This *this){
return this->passid;
}
__kernel void run(
int passid
){
This thisStruct;
This* this=&thisStruct;
this->passid = passid;
{
char pass = 0;
pass = (pass!=0)?0:1;
return;
}
}
}OpenCL}**/