From f35355d4f2dac5c7db0f0354aec27b0c840072ba Mon Sep 17 00:00:00 2001 From: Michel Steuwer Date: Fri, 5 Mar 2021 11:48:27 +0000 Subject: [PATCH 1/4] OpenCL tests will fail gracefully if the OpenCL library can not be loaded. --- src/test/scala/test_util/package.scala | 35 +++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/src/test/scala/test_util/package.scala b/src/test/scala/test_util/package.scala index 259d52254..f6e1e1681 100644 --- a/src/test/scala/test_util/package.scala +++ b/src/test/scala/test_util/package.scala @@ -1,5 +1,6 @@ import opencl.executor.Executor -import org.scalatest.BeforeAndAfter +import org.scalactic.source.Position +import org.scalatest.{BeforeAndAfter, Tag} import org.scalatest.matchers.should.Matchers import org.scalatest.funsuite.AnyFunSuite import util.{AssertSame, Time, TimeSpan} @@ -8,13 +9,39 @@ package object test_util { abstract class Tests extends AnyFunSuite with Matchers 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 _: Throwable => + } + } + + 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) + } + } } } From 3e048f4f57b04ce1d7a7156de0d6a42b7f8f1b46 Mon Sep 17 00:00:00 2001 From: Michel Steuwer Date: Fri, 5 Mar 2021 14:08:52 +0000 Subject: [PATCH 2/4] Adjusted `withExecutor` API as well. --- src/main/scala/util/package.scala | 17 ++++++++++++----- src/test/scala/apps/convolution1D.scala | 10 +++++----- .../apps/separableConvolution2DCheck.scala | 6 +++--- src/test/scala/shine/DPIA/Primitives/Pad.scala | 2 +- .../scala/shine/DPIA/Primitives/Scatter.scala | 4 ++-- src/test/scala/test_util/package.scala | 18 +++++++++++++++++- 6 files changed, 40 insertions(+), 17 deletions(-) diff --git a/src/main/scala/util/package.scala b/src/main/scala/util/package.scala index 2c39c0979..0829bf9d2 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 355946cd9..10356706c 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 67f4d533f..945b70d0b 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/shine/DPIA/Primitives/Pad.scala b/src/test/scala/shine/DPIA/Primitives/Pad.scala index de80eb9df..a04607de2 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 f6e1e1681..e76c7c299 100644 --- a/src/test/scala/test_util/package.scala +++ b/src/test/scala/test_util/package.scala @@ -1,5 +1,6 @@ import opencl.executor.Executor 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 @@ -24,7 +25,7 @@ package object test_util { try { Executor.shutdown() } catch { - case _: Throwable => + case _: UnsatisfiedLinkError => } } @@ -45,6 +46,21 @@ package object test_util { } } + 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 => throw e + } + } + def runsWithSameResult[R, U <: Time.Unit](runs: Seq[(String, (R, TimeSpan[U]))]) (implicit assertSame: AssertSame[R]): Unit = { runs.tail.foreach(r => assertSame(r._2._1, runs.head._2._1, s"${r._1} had a different result")) From afca29848699a4233cbf6b00ee8fd9492f39fe5c Mon Sep 17 00:00:00 2001 From: Michel Steuwer Date: Fri, 5 Mar 2021 14:25:32 +0000 Subject: [PATCH 3/4] Fixed compiler warning. --- src/test/scala/test_util/package.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/scala/test_util/package.scala b/src/test/scala/test_util/package.scala index e76c7c299..737dc00e6 100644 --- a/src/test/scala/test_util/package.scala +++ b/src/test/scala/test_util/package.scala @@ -57,7 +57,7 @@ package object test_util { } catch { case e: UnsatisfiedLinkError => throw new TestCanceledException("OpenCL not available", e, 0) - case e => throw e + case e : Throwable => throw e } } From 5130f3804bd6e1f6bf1d003ce881ccb2873de8d3 Mon Sep 17 00:00:00 2001 From: Michel Steuwer Date: Fri, 5 Mar 2021 15:04:45 +0000 Subject: [PATCH 4/4] Fixed two tests that implicitly relied on OpenCL. --- src/test/scala/apps/stencil.scala | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/test/scala/apps/stencil.scala b/src/test/scala/apps/stencil.scala index f769a9e0b..fcc701d2c 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") {