Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update main branch #24

Merged
merged 99 commits into from
Sep 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
99 commits
Select commit Hold shift + click to select a range
049feee
Setup jcstress submodule
DLochmelis33 Oct 9, 2023
1b2645c
Struggling to call kotlin from jcstress maven project
DLochmelis33 Oct 10, 2023
c5160dc
Manually connect and run a test with jcstress
DLochmelis33 Oct 18, 2023
94af8b9
Improve build files
DLochmelis33 Nov 5, 2023
965ed45
Generate wrappers in runtime, call jcstress via ProcessBuilder
DLochmelis33 Nov 5, 2023
10d0996
Add @Outcome annotations, handle single values differently
DLochmelis33 Nov 6, 2023
fc1f253
Use LitmusI..IOutcome in all tests
DLochmelis33 Nov 6, 2023
249ad82
No-op PthreadRunner
DLochmelis33 Nov 14, 2023
afe3771
Working PthreadRunner
DLochmelis33 Nov 14, 2023
243dd50
Support affinity for PthreadRunner
DLochmelis33 Nov 14, 2023
cb772fa
Split starting and joining test threads for async-style actual parall…
DLochmelis33 Nov 15, 2023
9661840
Refactor into a common JVM CLI, currently broken due to a cyclic depe…
DLochmelis33 Nov 21, 2023
e2d1bde
temp
DLochmelis33 Nov 23, 2023
586f237
Improve affinity cinterop with compilerOpts
DLochmelis33 Dec 13, 2023
9798a48
Huge refactor to resolve cyclic dependency + get jcstress to work
DLochmelis33 Jan 22, 2024
a97540d
Refactor tests into separate subproject
DLochmelis33 Jan 22, 2024
7ce3efc
Minor improvements
DLochmelis33 Jan 28, 2024
ee8ed4e
Update README
DLochmelis33 Jan 28, 2024
c214aff
Tiny README fixes
DLochmelis33 Jan 28, 2024
6fbfaeb
Merge branch 'dev-pthread-runner' into dev-jcstress-integration
DLochmelis33 Feb 4, 2024
9888c07
Move state allocation out of runner
DLochmelis33 Feb 5, 2024
0f52f5e
Improve results calculation speed
DLochmelis33 Feb 5, 2024
21c83f5
PR cleanup
DLochmelis33 Feb 5, 2024
ab89911
PR cleanup (part 2)
DLochmelis33 Feb 18, 2024
6d014ca
Merge pull request #9 from JetBrains-Research/dev-jcstress-integration
DLochmelis33 Feb 18, 2024
44bb174
Use LitmusAutoState as both state and outcome, change lists to holder…
DLochmelis33 Feb 18, 2024
c829ecd
Implement CustomList, confirm that it improves performance
DLochmelis33 Feb 19, 2024
d2b4b4a
MR fixes
DLochmelis33 Feb 25, 2024
eb19935
Fix typo in LitmusIIIIState
DLochmelis33 Feb 26, 2024
8944afc
More PR fixes
DLochmelis33 Apr 7, 2024
c60261e
Merge pull request #11 from JetBrains-Research/dev-performance-calcStats
DLochmelis33 Apr 7, 2024
7e7c451
Fix single outcome bug, notice jcstress-interop not working
DLochmelis33 Apr 7, 2024
1a73d1b
Fix jcstress interop
DLochmelis33 Apr 7, 2024
6121e67
Change package to org.jetbrains.litmuskt
DLochmelis33 Apr 14, 2024
8f215a2
Cleanup build files
DLochmelis33 Apr 14, 2024
66ca452
Codegen: skip unnecessary variables
DLochmelis33 Apr 28, 2024
6f4d4f4
Redo codegen + reorganize tests
DLochmelis33 Apr 28, 2024
1797f58
Resolve cherry-pick conflicts
DLochmelis33 May 8, 2024
6bd8439
Parse jcstress HTML output
DLochmelis33 Apr 25, 2024
0da7b20
Late fixes related to changing tests naming + support multiple tests …
DLochmelis33 Apr 28, 2024
a7b37b1
Update README
DLochmelis33 Apr 28, 2024
1882b61
Apply KSP to multiplatform tests
DLochmelis33 May 8, 2024
cc1d05b
Add more AutoOutcome-s (not generated yet)
DLochmelis33 May 8, 2024
1002620
Add word tearing tests
DLochmelis33 May 8, 2024
4718708
Add volatile arrays test + more word tearing
DLochmelis33 May 8, 2024
5bfbcab
rename some tests (give more explicit names)
eupp May 13, 2024
80f482f
move all unsafe publication tests into single file
eupp May 13, 2024
0c5a6dd
minor refactoring in UnsafePublication.kt
eupp May 13, 2024
b463394
move MPNoDRF into `MessagePassing.kt`
eupp May 13, 2024
80a424d
Minor changes
DLochmelis33 May 19, 2024
14f4e63
Rollback README changes
DLochmelis33 May 19, 2024
30d25b3
Abstract pthread away into cinterop to support Macos
DLochmelis33 May 22, 2024
251ac03
Small fix (replace try/catch with runCatching)
DLochmelis33 Jun 5, 2024
4a6b639
Add forgotten @Volatile, delete outdated comments
DLochmelis33 Jun 5, 2024
4d6e3ad
Merge branch 'dev-jcstress-integration' into development
DLochmelis33 Jun 5, 2024
57f72e3
Merge branch 'dev-more-tests' into development
DLochmelis33 Jun 21, 2024
b330c88
Update README
DLochmelis33 Jun 21, 2024
4ccaa7e
Cleanup
DLochmelis33 Jun 26, 2024
93b6898
Merge branch 'dev-testing' into development
DLochmelis33 Jun 26, 2024
f26a460
Abstract workers and pthread into Threadlike
DLochmelis33 Jun 26, 2024
672b984
Return affinity support for pthread
DLochmelis33 Jun 26, 2024
0d2b0e2
Clean up
DLochmelis33 Jun 26, 2024
66edc9e
Delete outdated files
DLochmelis33 Jul 4, 2024
99bb8cd
Minor style fixes
DLochmelis33 Jul 7, 2024
adacd49
Merge pull request #18 from JetBrains-Research/dev-threads
DLochmelis33 Jul 7, 2024
8c799c6
Add basic CI
DLochmelis33 Jun 26, 2024
3e4eb49
Fix 1
DLochmelis33 Jun 26, 2024
c82e4e1
Fix 2 + add jcstress run to CI
DLochmelis33 Jun 26, 2024
a7ea1dd
Fix 3
DLochmelis33 Jul 4, 2024
cbc23b3
Fix 4 + fix bug in printing jcstress results
DLochmelis33 Jul 7, 2024
29cfa94
Fix 4 + fix bug in parsing jcstress results
DLochmelis33 Jul 7, 2024
5f54955
Upgrade to Kotlin 2.0.0
DLochmelis33 Jul 15, 2024
44d0abb
Support mingwX64 target
DLochmelis33 Jul 21, 2024
56faf56
Move result calculation inside thread routine
DLochmelis33 Jul 21, 2024
4fc7eb1
Minor improvements
DLochmelis33 Jul 21, 2024
57e58da
Fix affinity issue (and add -Werror)
DLochmelis33 Aug 3, 2024
d8dd41f
Add comment, fix jcstress result collection bug, run all tests with j…
DLochmelis33 Aug 4, 2024
e6fbc8f
Fix jcstress result not parsing default outcome (add parseOutcome() t…
DLochmelis33 Aug 4, 2024
fa868fc
Style changes
DLochmelis33 Aug 4, 2024
747d314
Merge pull request #19 from JetBrains-Research/dev-gh-ci
DLochmelis33 Aug 4, 2024
2c5bdbb
Merge pull request #20 from JetBrains-Research/dev-performance
DLochmelis33 Aug 4, 2024
4067297
Rewrite UPUB more explicitly (replace elvis with if)
DLochmelis33 Aug 6, 2024
07f1095
Replace all "join handles" with BlockingFuture
DLochmelis33 Aug 6, 2024
bc3f746
Quickfix for previous commit
DLochmelis33 Aug 6, 2024
b7091bc
Quickfix-2
DLochmelis33 Aug 6, 2024
bb73f00
Implement reset()
DLochmelis33 Aug 11, 2024
406d577
Remove sequence() as it gave a huge performance drop
DLochmelis33 Aug 11, 2024
388f2e9
Add a bunch of tests
DLochmelis33 Aug 11, 2024
c77e36f
Add more UPUB array tests
DLochmelis33 Aug 13, 2024
80d9450
Split new tests into respective platform modules
DLochmelis33 Aug 13, 2024
538b204
Remove the need for outcomeReset() in tests, move reset{} section to …
DLochmelis33 Sep 4, 2024
546d06c
Improve some tests
DLochmelis33 Sep 4, 2024
af2284a
Minor fixes
DLochmelis33 Sep 4, 2024
566ea7a
Merge pull request #22 from JetBrains-Research/dev-testing
DLochmelis33 Sep 4, 2024
a1935a1
Merge pull request #23 from JetBrains-Research/dev-litmus-tests
DLochmelis33 Sep 4, 2024
5695b4c
Merge branch 'dev-performance' into development
DLochmelis33 Sep 4, 2024
9ee0105
Merge fix-up
DLochmelis33 Sep 4, 2024
60fd1b6
Update README with reset{}
DLochmelis33 Sep 4, 2024
98bce9c
Add licenses for to-be-published subprojects
DLochmelis33 Sep 13, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 50 additions & 0 deletions .github/workflows/run-litmus.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
name: Run litmus tests on different platforms

on:
push:
branches:
- dev-gh-ci
- development
- main

# Note: this CI run is an "integration"-test or "smoke"-test. It is intended to verify that
# the basics of the tool work. It is NOT intended to be complete or to discover weak behaviors.

jobs:
linux-run:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-java@v4
with:
distribution: oracle
java-version: 17
- run: chmod +x gradlew
- name: Assemble CLI binary
run: ./gradlew cli:linkReleaseExecutableLinuxX64
- name: Run litmus tests via CLI
run: ./cli/build/bin/linuxX64/releaseExecutable/cli.kexe -r pthread ".*"
- name: Run litmus tests with JCStress
# takes ~10 mins
run: ./gradlew :cli:jvmRun --args="-r jcstress -j '-m sanity' .*"

macos-run:
runs-on: macos-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-java@v4
with:
distribution: oracle
java-version: 17
- run: chmod +x gradlew
- name: Assemble CLI binary (x64 + release)
run: ./gradlew cli:linkReleaseExecutableMacosX64
- name: Run litmus tests via CLI (x64 + release)
run: ./cli/build/bin/macosX64/releaseExecutable/cli.kexe -r pthread ".*"
- name: Run litmus tests with JCStress
# takes ~10 mins
run: ./gradlew :cli:jvmRun --args="-r jcstress -j '-m sanity' .*"
- name: Assemble CLI binary (arm + release)
run: ./gradlew cli:linkReleaseExecutableMacosArm64
- name: Run litmus tests via CLI (arm + release)
run: ./cli/build/bin/macosArm64/releaseExecutable/cli.kexe -r pthread ".*"
4 changes: 2 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@ build/
temp/
*.hprof
gitignored/
litmus/src/nativeInterop/kaffinity.def
litmus/src/nativeInterop/kaffinity_gnu.o
local.properties
.kotlin
14 changes: 0 additions & 14 deletions ArmWorkerHalts.kt

This file was deleted.

185 changes: 108 additions & 77 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,55 +1,66 @@
# LitmusKt
# LitmusKt

**LitmusKt** is a litmus testing tool for Kotlin.
Litmus tests are small concurrent programs exposing various relaxed behaviors,
arising due to compiler or hardware optimizations (for example, instruction reordering).
Litmus tests are small concurrent programs exposing various relaxed behaviors, arising due to compiler or hardware
optimizations (for example, instruction reordering).

This project is in an **experimental** stage of the development.
This project is in an **experimental** stage of the development.
The tool's API is unstable and might be a subject to a further change.

## Setup

Simply clone the project and run `./gradlew build`.

### Running
Note that for Kotlin/JVM this project relies on [jcstress](https://github.com/openjdk/jcstress).

All classic Gradle building tasks (like `run`, `build`, `-debug-` or `-release-`) work as expected.
The only important distinction is that on various platforms these tasks are named differently.
## Running

```bash
# Linux:
./gradlew runReleaseExecutableLinuxX64
The entry point is the CLI tool residing in `:cli` subproject. You can use the `--help` flag to find the details about
the CLI, but most basic example requires two settings:

1. Choose a runner with `-r` option
2. After the options are specified, choose the tests to run using regex patterns

### Running on Native

# MacOS (x86):
./gradlew runReleaseExecutableMacosX64
# MacOS (arm):
./gradlew runReleaseExecutableMacosArm64 -Parm # don't forget the -Parm flag!
Create an executable and run it:

```bash
./gradlew :cli:linkReleaseExecutableLinuxX64
./cli/build/bin/linuxX64/releaseExecutable/cli.kexe -r pthread 'StoreBuffering.*'
```

Substituting `Release` with `Debug` disables compiler `-opt` flag.
Depending on what you need, you can:

Also, it is possible to build the project manually with Kotlin CLI compiler.
You'd have to either declare several opt-ins or edit the code to remove `expect/actual` and C interop parts.
There aren't many benefits to manual compilation, but it allows at least some way to read the program's LLVM IR bitcode
(using `-Xtemporary-files-dir` compiler flag and then converting the `.bc` file into readable text with `llvm-dis`).
* Switch between `debug` and `release` (which, among other things, toggles the `-opt` compiler flag)
* Specify the platform (`linuxX64` / `macosX64` / `macosArm64`)

### Running on JVM

Simply run the project with Gradle:

```bash
./gradlew :cli:jvmRun --args="-r jcstress -j '-m sanity' 'StoreBuffering.*'"
```

## Overview

A single litmus test consists of the following parts:

* a state shared between threads;
* code for each thread;
* an outcome — a certain value which is the result of running the test;
* an outcome -- a certain value which is the result of running the test;
* a specification listing accepted and forbidden outcomes

The tool runs litmus tests with various parameters,
using the standard techniques also employed by other tools,
The tool runs litmus tests with various parameters,
using the standard techniques also employed by other tools,
like [herdtools/litmus7](https://github.com/herd/herdtools7) and [JCStress](https://github.com/openjdk/jcstress).

The tool allocates a batch of shared state instances
and runs the threads on one state instance after another,
occasionally synchronizing threads with barriers.
After all threads finish running, states are converted into outcomes, and the same outcomes are counted.
The end result is the list of all different observed outcomes,
and runs the threads on one state instance after another,
occasionally synchronizing threads with barriers.
After all threads finish running, states are converted into outcomes, and the same outcomes are counted.
The end result is the list of all different observed outcomes,
their frequencies and their types (accepted, interesting or forbidden).

### Litmus Test Syntax
Expand All @@ -74,14 +85,18 @@ val StoreBuffering = litmusTest(::StoreBufferingState) {
r2 = x
}
outcome {
listOf(r1, r2)
r1 to r2
}
spec {
accept(listOf(0, 1))
accept(listOf(1, 0))
accept(listOf(1, 1))
interesting(listOf(0, 0))
accept(listOf(0 to 1, 1 to 0, 1 to 1))
interesting(listOf(0 to 0))
}
reset {
x = 0
y = 0
r1 = 0
r2 = 0
}
}
```

Expand All @@ -99,25 +114,29 @@ And here is an example of the tool's output:
Let us describe the litmus test's declaration.

* As a first argument `litmusTest` takes a function producing the shared state instance.
* The second argument is DSL builder lambda, setting up the litmus test.
* `thread { ... }` lambdas set up the code run in different threads of the litmus tests —
these lambdas take shared state instance as a receiver.
* The second argument is DSL builder lambda, setting up the litmus test.
* `thread { ... }` lambdas set up the code run in different threads of the litmus tests —
these lambdas take shared state instance as a receiver.
* `outcome { ... }` lambda sets up the outcome of a test obtained after all threads have run —
these lambdas also take shared state instance as a receiver.
* the `spec { ... }` lambda classifies the outcomes into acceptable, interesting, and forbidden categories.
* `spec { ... }` lambda classifies the outcomes into acceptable, interesting, and forbidden categories.
* `reset { ... }` lambda is used to reset the shared state to its original value, so that the test can be run again
using the same state instance.

Here are a few additional convenient features.

* Classes implementing `LitmusAutoOutcome` interface set up an outcome automatically.
There are a few predefined subclasses of this interface.
For example, the class `LitmusIIOutcome` with `II` standing for "int, int" expects two integers as an outcome.
This class have two fields `var r1: Int` and `var r2: Int`.
These fields should be set inside litmus test's threads, and then they will be automatically used to form an outcome `listOf(r1, r2)`.

* If the outcome is a `List`, you can use a shorter syntax for declaring accepted / interesting / forbidden outcomes.
Just use `accept(vararg outcome)` counterparts to specify expected elements.

* Since each test usually has its own specific state, it is quite useful to use anonymous classes for them.
There are a few predefined subclasses of this interface.
For example, the class `LitmusIIOutcome` with `II` standing for "int, int" expects two integers as an outcome.
This class have two fields `var r1: Int` and `var r2: Int`.
These fields should be set inside litmus test's threads, and then they will be automatically used to form an outcome.
* Additionally, if the state implements `LitmusAutoOutcome`, you can use a shorter syntax for declaring accepted / interesting / forbidden outcomes.
For example, for `LitmusIIOutcome` you can use `accept(r1: Int, r2: Int)` to add `(r1, r2)` as an accepted outcome.
Moreover, `r1` and `r2` will be automatically reset after running the test, so you don't need to manually write them
in the `reset` section.
* Finally, `LitmusAutoOutcome` is considerably more performant than manually creating any extra outcome object. It is
therefore **strongly advised** to use this interface at all times.
* Since each test usually has its own specific state, it is quite convenient to use anonymous classes for them.

Using these features, the test from above can be shortened as follows:

Expand All @@ -142,58 +161,70 @@ val StoreBuffering: LitmusTest<*> = litmusTest({
accept(1, 1)
interesting(0, 0)
}
reset {
x = 0
y = 0
}
}
```

### Litmus Test Runners

The tests are run with an `LitmusRunner`.
Currently, there are two implementations.
* `WorkerRunner`: runner based on `Worker` API for Kotlin/Native;
* `JvmThreadRunner`: custom threads-based runner for Kotlin/JVM.
* A proper, JCStress based runner for Kotlin/JVM is **in development**.

`LitmusRunner` has several running functions:

* `runTest(params, test)` simply runs the test with the given parameters.
* `runTest(duration, params, test)` repeatedly runs the test with the given parameters until the given time duration passes.
* `runTestParallel(instances, ...)` it runs several instances of the test in parallel.
* `runTestParallel(...)` without explicit instances number will run `#{of cpu cores} / #{of threads in test}` instances.
Litmus tests are run with a `LitmusRunner`. This interface has several running functions:

### Entry point
* `runTests(tests, params, timeLimit)` runs several `tests` one after another, each with the given `params`, optionally repeating each test for the duration of `timeLimit`.
* `runSingleTestParallel(test, params, timeLimit = 0, instances = ...)` runs a single test in parallel `instances`, with the given `params` and optionally repeating for `timeLimit`. The default value for `instances` is `#{of cpu cores} / #{of threads in test}`.

Currently, the `main()` functions are the intended way of running particular litmus tests.
A proper CLI interface is in development.
The following implementations of `LitmusRunner` are available:

There is also an option to run the tests with `@Test` annotation using the default parameters.
However, the tests are run in debug mode by the `kotlinx.test` framework.
Running litmus tests in the debug mode can affect their results, potentially hiding some relaxed behaviors.
* For native:
* `WorkerRunner`: based on K/N `Worker` API
* `PthreadRunner`: based on C interop pthread API
* For JVM:
* `JvmThreadRunner`: a simple runner based on Java threads
* `JCStressRunner`: a **special** runner that delegates to JCStress. Note that many of `LitmusRunner` parameters are not applicable to JCStress. Furthermore, there are JCStress-exclusive options as well.

### Litmus Test Parameters

* `AffinityMap`: bindings from thread to CPU cores.
Obtained through `AffinityManager`, which is available from `getAffinityManager()` top-level function.
There is a number of parameters that can be varied between test runs. Their influence on the results can change
drastically depending on the particular test, hardware, and so on.

* `syncEvery`: the number of tests between barrier synchronizations.
Practice shows that on Native the reasonable range is somewhere in the range from 10 to 100,
while on JVM it works best in the range from 1000 to 10000.
This also depends on the particular test.

* `Barrier`: can be either Kotlin-implemented (`KNativeSpinBarrier`) or C-implemented (`CinteropSpinBarrier`).
* `AffinityMap`: bindings from thread to CPU cores.
Obtained through `AffinityManager`, which is available from `getAffinityManager()` top-level function.
* `syncEvery`: the number of tests between barrier synchronizations.
Practice shows that on Native the reasonable range is somewhere in the range from 10 to 100,
while on JVM it works best in the range from 1000 to 10000.
This highly depends on the particular test.
* `Barrier`: can be either Kotlin-implemented (`KNativeSpinBarrier`) or C-implemented (`CinteropSpinBarrier`).
C-implemented might yield better results.
On JVM, use `JvmSpinBarrier` in favor of `JvmCyclicBarrier`.

Common practice is to iterate through different parameter bundles and aggregate the results across them.
* Function `variateParameters()` takes the cross-product of all passed parameters

* Function `variateParameters()` takes the cross-product of all passed parameters
(hence use `listOf(null)` instead of `emptyList()` for unused arguments).
* For results aggregation, use `List<LitmusResult>.mergeResults()`.
* You can also use `LitmusResult.prettyPrint()` to print the results.
* You can also use `LitmusResult.generateTable()` to format the results into a human-readable table.

### Project structure

The project consists of several subprojects:

* `:core` contains the core infrastructure such as `LitmusTest` and `LitmusRunner` interfaces, etc.
* `:testsuite` contains the litmus tests themselves.
* `:codegen` uses KSP to collect all tests from `:testsuite`.
* `:jcstress-wrapper` contains the code to convert `LitmusTest`-s into JCStress-compatible Java wrappers.
* `:cli` is a user-friendly entry point.

### Notes
## Notes

* If you decide to add some litmus tests, and you wish for them to be registered in the CLI, you must put them into `:testsuite` subproject. Use the existing tests as reference for the proper test structure.
* Setting thread affinity is not supported on macOS yet. As such, `getAffinityManager()` returns `null` on macOS.
* For some reason, running a lot of different tests in one go will drastically reduce the performance and weak outcomes' frequency.
For now, please try to avoid running tests for longer than 5 minutes.
* It is possible to run the tests with `@Test` annotation. However, the tests are run in debug mode by
the `kotlinx.test` framework. Running litmus tests in the debug mode can affect their results, potentially hiding some
relaxed behaviors.
* In practice, all cases of currently found relaxed behaviors can be consistently found in under a minute of running.
* Avoid creating unnecessary objects inside threads, especially if they get shared. This not only significantly slows down the performance, but can also introduce unexpected relaxed behaviors.
* The tool currently doesn't address the false sharing problem. The memory shuffling API is in development.
* Avoid creating unnecessary objects inside threads, especially if they get shared. This not only significantly slows
down the performance, but can also introduce unexpected relaxed behaviors.
* The tool currently doesn't address the false sharing problem. It has been shown to be fairly significant, but we looked for a solution and found none good enough. This problem can be resolved with a `@Contended`-like annotation in Kotlin, which does not yet exist.
* When writing tests with `LitmusAutoOutcome`, it is possible to achieve a post-processing step similar to JCStress `@Arbiter`. To do that, you can write your code in the `outcome{}` section, and then return `this` from it. An example can be found in the [WordTearing](testsuite/src/commonMain/kotlin/org/jetbrains/litmuskt/tests/WordTearing.kt) test.
4 changes: 3 additions & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
plugins {
kotlin("multiplatform") version "1.9.10" apply false
kotlin("multiplatform") version "2.0.0" apply false
}

repositories {
Expand All @@ -8,6 +8,8 @@ repositories {
}

subprojects {
group = "org.jetbrains.litmuskt"
version = "1.0-SNAPSHOT"
repositories {
mavenCentral()
gradlePluginPortal()
Expand Down
Loading
Loading