diff --git a/src/main/scala/util/package.scala b/src/main/scala/util/package.scala index 832901c67..9c78a97be 100644 --- a/src/main/scala/util/package.scala +++ b/src/main/scala/util/package.scala @@ -1,4 +1,6 @@ import java.io.{File, PrintWriter} +import scala.util.control.NonFatal +import scala.util.{Failure, Success, Try} package object util { def createTempFile(prefix: String, suffix: String): File = { @@ -39,13 +41,18 @@ package object util { same(a, b, msg) } - def withExecutor[T](f: => T): T = { + def withExecutor[T](f: => T): Try[T] = { import opencl.executor._ - Executor.loadLibrary() - Executor.init() - try f - finally Executor.shutdown() + try Success({ + Executor.loadLibrary() + Executor.init() + try f + finally Executor.shutdown() + }) catch { + case e: UnsatisfiedLinkError => Failure(e) + case NonFatal(e) => Failure(e) + } } def printTime[T](msg: String, block: => T): T = { diff --git a/src/test/scala/apps/convolution1D.scala b/src/test/scala/apps/convolution1D.scala index 5c1a2966d..c80d1573f 100644 --- a/src/test/scala/apps/convolution1D.scala +++ b/src/test/scala/apps/convolution1D.scala @@ -102,7 +102,7 @@ class convolution1D extends test_util.Tests { } test("binomialTile compiles to valid OpenCL that passes checks") { - util.withExecutor { + test_util.withExecutor { checkOCL(128, LocalSize(1), GlobalSize(2), binomialTile) // expected to fail: // checkOCL(130, LocalSize(1), GlobalSize(2), binomialTile) @@ -110,7 +110,7 @@ class convolution1D extends test_util.Tests { } test("binomialTileShiftInwardsGP compiles to valid OpenCL that passes checks") { - util.withExecutor { + test_util.withExecutor { checkOCL(128, LocalSize(1), GlobalSize(64), binomialTileShiftInwardsGP) checkOCL(132, LocalSize(1), GlobalSize(64), binomialTileShiftInwardsGP) checkOCL(148, LocalSize(1), GlobalSize(64), binomialTileShiftInwardsGP) @@ -118,7 +118,7 @@ class convolution1D extends test_util.Tests { } test("binomialTileShiftInwardsWLP compiles to valid OpenCL that passes checks") { - util.withExecutor { + test_util.withExecutor { checkOCL(128, LocalSize(16), GlobalSize(128), binomialTileShiftInwardsWLP) checkOCL(132, LocalSize(32), GlobalSize(128), binomialTileShiftInwardsWLP) checkOCL(148, LocalSize(64), GlobalSize(128), binomialTileShiftInwardsWLP) @@ -127,7 +127,7 @@ class convolution1D extends test_util.Tests { // TODO: nat normal form + concat codegen ignore("binomialTileEpilogue compiles to valid OpenCL that passes checks") { - util.withExecutor { + test_util.withExecutor { checkOCL(128, LocalSize(1), GlobalSize(2), binomialTileEpilogue) checkOCL(132, LocalSize(1), GlobalSize(2), binomialTileEpilogue) checkOCL(148, LocalSize(1), GlobalSize(2), binomialTileEpilogue) @@ -136,7 +136,7 @@ class convolution1D extends test_util.Tests { // TODO: codegen + parallelism ignore("binomialTileDep compiles to valid OpenCL that passes checks") { - util.withExecutor { + test_util.withExecutor { checkOCL(128, LocalSize(1), GlobalSize(1), binomialTileDep) checkOCL(132, LocalSize(1), GlobalSize(1), binomialTileDep) checkOCL(148, LocalSize(1), GlobalSize(1), binomialTileDep) diff --git a/src/test/scala/apps/separableConvolution2DCheck.scala b/src/test/scala/apps/separableConvolution2DCheck.scala index 5aa655b34..8ebb77573 100644 --- a/src/test/scala/apps/separableConvolution2DCheck.scala +++ b/src/test/scala/apps/separableConvolution2DCheck.scala @@ -98,13 +98,13 @@ int main(int argc, char** argv) { } test("baseVecU compiles to valid OpenCL that passes checks") { - util.withExecutor { + test_util.withExecutor { checkOCL(LocalSize(1), GlobalSize(1), baseVecU(binomialWeights2d)) } } test("regRotPar compiles to valid OpenCL that passes checks") { - util.withExecutor { + test_util.withExecutor { checkOCL(LocalSize(1), GlobalSize(4), regRotPar(binomialWeightsV)(binomialWeightsH) ) @@ -112,7 +112,7 @@ int main(int argc, char** argv) { } test("scanlinePar compiles to valid OpenCL that passes checks") { - util.withExecutor { + test_util.withExecutor { checkOCL(LocalSize(1), GlobalSize(4), scanlinePar(binomialWeightsV)(binomialWeightsH) ) diff --git a/src/test/scala/apps/stencil.scala b/src/test/scala/apps/stencil.scala index eb965503f..2aeb54886 100644 --- a/src/test/scala/apps/stencil.scala +++ b/src/test/scala/apps/stencil.scala @@ -227,7 +227,9 @@ class stencil extends test_util.Tests { } test("Basic 1D addition stencil") { - BasicStencil1D(1024, 5).run(LocalSize(4), GlobalSize(4)).correctness.check() + test_util.withExecutor { + BasicStencil1D(1024, 5).run(LocalSize(4), GlobalSize(4)).correctness.check() + } } ignore("Partitioned 1D addition stencil, with specialised area handling") { @@ -238,10 +240,12 @@ class stencil extends test_util.Tests { } test("Basic 2D addition stencil") { - BasicStencil2D(256, stencilSize = 11) - .run(LocalSize(2), GlobalSize(4)) - .correctness - .check() + test_util.withExecutor { + BasicStencil2D(256, stencilSize = 11) + .run(LocalSize(2), GlobalSize(4)) + .correctness + .check() + } } ignore("Partitioned 2D addition stencil") { diff --git a/src/test/scala/shine/DPIA/Primitives/Pad.scala b/src/test/scala/shine/DPIA/Primitives/Pad.scala index ca9c7697d..e5f91c0d6 100644 --- a/src/test/scala/shine/DPIA/Primitives/Pad.scala +++ b/src/test/scala/shine/DPIA/Primitives/Pad.scala @@ -102,7 +102,7 @@ class Pad extends test_util.Tests { val f1 = k1.as[ScalaFunction `(` Int `,` Array[Array[Int]] `)=>`Array[Int]] val f2 = k2.as[ScalaFunction `(` Int `,` Array[Array[Int]] `)=>`Array[Int]] - val ((r1, _), (r2, _)) = util.withExecutor { + val ((r1, _), (r2, _)) = test_util.withExecutor { (f1(localSize, globalSize)(N `,` input), f2(localSize, globalSize)(N `,` input)) } diff --git a/src/test/scala/shine/DPIA/Primitives/Scatter.scala b/src/test/scala/shine/DPIA/Primitives/Scatter.scala index 1926a0e60..1616fc445 100644 --- a/src/test/scala/shine/DPIA/Primitives/Scatter.scala +++ b/src/test/scala/shine/DPIA/Primitives/Scatter.scala @@ -28,7 +28,7 @@ class Scatter extends test_util.Tests { val f = k.as[ScalaFunction `(` Array[Int] `)=>` Array[Int]] val input = (1 to N).toArray val expected = input.reverse - val (r, _) = util.withExecutor { + val (r, _) = test_util.withExecutor { f(lS, gS)(input `;`) } util.assertSame(r, expected, "unexpected result") @@ -55,7 +55,7 @@ class Scatter extends test_util.Tests { val f = k.as[ScalaFunction `(` Array[Int] `)=>` Array[Int]] val input = Array.fill(2)((1 to N).toArray) val expected = input(0).reverse - val (r, _) = util.withExecutor { + val (r, _) = test_util.withExecutor { f(lS, gS)(input.flatten `;`) } util.assertSame(r, expected, "unexpected result") diff --git a/src/test/scala/test_util/package.scala b/src/test/scala/test_util/package.scala index 39d84502d..497ba5148 100644 --- a/src/test/scala/test_util/package.scala +++ b/src/test/scala/test_util/package.scala @@ -1,5 +1,7 @@ import opencl.executor.Executor -import org.scalatest.BeforeAndAfter +import org.scalactic.source.Position +import org.scalatest.exceptions.TestCanceledException +import org.scalatest.{BeforeAndAfter, Tag} import org.scalatest.matchers.should.Matchers import org.scalatest.funsuite.AnyFunSuite import org.apache.logging.log4j.scala.Logging @@ -15,13 +17,54 @@ package object test_util { } abstract class TestsWithExecutor extends Tests with BeforeAndAfter { + var openclIsAvailable = true before { - Executor.loadLibrary() - Executor.init() + try { + Executor.loadLibrary() + Executor.init() + } catch { + case _: UnsatisfiedLinkError => + openclIsAvailable = false + } } after { - Executor.shutdown() + try { + Executor.shutdown() + } catch { + case _: UnsatisfiedLinkError => + } + } + + override protected def test(testName: String, testTags: Tag*) + (testFun: => Any) + (implicit pos: Position): Unit = { + super.test(testName, testTags:_*) { + // try to execute test ... + try { + testFun + } catch { + // ... only if execution fails due to a unsatisfied link error we + // enforce the assumption that OpenCL must be available. + case _: UnsatisfiedLinkError => + assume(openclIsAvailable) + } + } + } + } + + def withExecutor[T](f: => T): T = { + import opencl.executor._ + + try { + Executor.loadLibrary() + Executor.init() + try f + finally Executor.shutdown() + } catch { + case e: UnsatisfiedLinkError => + throw new TestCanceledException("OpenCL not available", e, 0) + case e : Throwable => throw e } }