Skip to content

Commit b3cee5f

Browse files
authored
feat: Add optimizable function (#204)
1 parent 874ce3d commit b3cee5f

File tree

2 files changed

+94
-0
lines changed

2 files changed

+94
-0
lines changed
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package fr.hammons.slinc.jitc
2+
3+
import java.util.concurrent.atomic.AtomicInteger
4+
import scala.compiletime.codeOf
5+
6+
sealed trait OptimizableFunction[F]:
7+
def apply[O](fn: F => O): O
8+
9+
class UnoptimizedFunction[F](
10+
aotcFn: F,
11+
val originalCode: String,
12+
limit: Int,
13+
updateFn: () => Unit
14+
) extends OptimizableFunction[F]:
15+
val counter: AtomicInteger = AtomicInteger(0)
16+
17+
def getCount() = counter.getOpaque()
18+
19+
def apply[O](fn: F => O): O =
20+
val res = fn(aotcFn)
21+
val currentCount = counter.getOpaque()
22+
if currentCount + 1 >= limit then
23+
counter.setOpaque(currentCount + 1)
24+
updateFn()
25+
res
26+
else
27+
counter.setOpaque(currentCount + 1)
28+
res
29+
30+
object UnoptimizedFunction:
31+
inline def apply[F](
32+
inline aotc: F,
33+
limit: Int,
34+
updateFn: () => Unit
35+
): UnoptimizedFunction[F] =
36+
new UnoptimizedFunction[F](aotc, codeOf(aotc), limit, updateFn)
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package fr.hammons.slinc.jitc
2+
3+
import scala.concurrent.Future
4+
import scala.concurrent.Await
5+
import scala.concurrent.duration.Duration
6+
import scala.concurrent.ExecutionContext.Implicits.global
7+
import munit.ScalaCheckSuite
8+
import org.scalacheck.Prop.*
9+
import org.scalacheck.Gen
10+
11+
class JitSpecification extends ScalaCheckSuite:
12+
test("single-threaded count works"):
13+
var optimizationTriggered = false
14+
val fn = UnoptimizedFunction(
15+
(i: Int) => i,
16+
10,
17+
() => optimizationTriggered = true
18+
)
19+
20+
var i = 0
21+
while i < 10 do
22+
fn(_(6))
23+
i += 1
24+
25+
assertEquals(fn.getCount(), 10)
26+
assert(
27+
optimizationTriggered,
28+
s"Optimization function not run? ${optimizationTriggered} - ${fn.getCount()}"
29+
)
30+
assertNoDiff(
31+
fn.originalCode,
32+
"""|{
33+
| def $anonfun(i: Int): Int = i
34+
| closure($anonfun)
35+
|}
36+
|""".stripMargin
37+
)
38+
39+
property("multi-threaded count works"):
40+
forAll(Gen.choose(0, 100)): (runs: Int) =>
41+
var optimizationTriggered = false
42+
val fn = UnoptimizedFunction(
43+
(i: Int) => i,
44+
10,
45+
() => optimizationTriggered = true
46+
)
47+
48+
val futures: Seq[Future[Unit]] = for
49+
j <- 0 until 5
50+
res = Future(
51+
(0 until runs).foreach(i => fn(_(i * j)))
52+
)
53+
yield res
54+
55+
Await.result(Future.traverse(futures)(identity), Duration.Inf)
56+
57+
assert(fn.getCount() >= runs)
58+
assert(runs < 10 || optimizationTriggered)

0 commit comments

Comments
 (0)