From 5fa440271d44b24f0dd1ff1bfa2d766f5a6322d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lubom=C3=ADr=20Bulej?= Date: Sun, 26 May 2024 14:31:15 +0200 Subject: [PATCH 1/9] Add stmbench7 sources --- benchmarks/scala-stm/stmbench7/build.sbt | 12 + .../src/main/java/stmbench7/BenchThread.java | 166 ++++++ .../src/main/java/stmbench7/Benchmark.java | 556 ++++++++++++++++++ .../main/java/stmbench7/ImplParameters.java | 30 + .../java/stmbench7/OperationExecutor.java | 17 + .../stmbench7/OperationExecutorFactory.java | 41 ++ .../src/main/java/stmbench7/OperationId.java | 121 ++++ .../main/java/stmbench7/OperationType.java | 21 + .../src/main/java/stmbench7/Parameters.java | 121 ++++ .../src/main/java/stmbench7/Setup.java | 95 +++ .../stmbench7/SynchMethodInitializer.java | 20 + .../main/java/stmbench7/ThreadFactory.java | 20 + .../src/main/java/stmbench7/ThreadRandom.java | 134 +++++ .../java/stmbench7/annotations/Atomic.java | 17 + .../annotations/ContainedInAtomic.java | 17 + .../java/stmbench7/annotations/Immutable.java | 18 + .../java/stmbench7/annotations/NonAtomic.java | 17 + .../java/stmbench7/annotations/ReadOnly.java | 14 + .../stmbench7/annotations/ThreadLocal.java | 17 + .../stmbench7/annotations/Transactional.java | 14 + .../java/stmbench7/annotations/Update.java | 14 + .../stmbench7/backend/BackendFactory.java | 21 + .../main/java/stmbench7/backend/IdPool.java | 22 + .../backend/ImmutableCollection.java | 14 + .../main/java/stmbench7/backend/Index.java | 31 + .../main/java/stmbench7/backend/LargeSet.java | 28 + .../main/java/stmbench7/core/Assembly.java | 22 + .../java/stmbench7/core/AssemblyBuilder.java | 121 ++++ .../main/java/stmbench7/core/AtomicPart.java | 47 ++ .../stmbench7/core/AtomicPartBuilder.java | 57 ++ .../java/stmbench7/core/BaseAssembly.java | 23 + .../java/stmbench7/core/ComplexAssembly.java | 26 + .../java/stmbench7/core/CompositePart.java | 42 ++ .../stmbench7/core/CompositePartBuilder.java | 131 +++++ .../main/java/stmbench7/core/Connection.java | 17 + .../main/java/stmbench7/core/DesignObj.java | 28 + .../java/stmbench7/core/DesignObjBuilder.java | 38 ++ .../java/stmbench7/core/DesignObjFactory.java | 33 ++ .../main/java/stmbench7/core/Document.java | 40 ++ .../java/stmbench7/core/DocumentBuilder.java | 42 ++ .../src/main/java/stmbench7/core/Manual.java | 40 ++ .../java/stmbench7/core/ManualBuilder.java | 28 + .../src/main/java/stmbench7/core/Module.java | 22 + .../java/stmbench7/core/ModuleBuilder.java | 46 ++ .../main/java/stmbench7/core/Operation.java | 23 + .../core/OperationFailedException.java | 31 + .../java/stmbench7/core/RuntimeError.java | 31 + .../correctness/invariants/AssemblyTest.java | 31 + .../invariants/AtomicPartTest.java | 59 ++ .../invariants/BaseAssemblyTest.java | 28 + .../invariants/CheckInvariantsOperation.java | 42 ++ .../invariants/ComplexAssemblyTest.java | 44 ++ .../invariants/CompositePartTest.java | 65 ++ .../invariants/ConnectionTest.java | 28 + .../correctness/invariants/DesignObjTest.java | 45 ++ .../invariants/DocumentationTest.java | 39 ++ .../correctness/invariants/IndexTest.java | 121 ++++ .../correctness/invariants/InvariantTest.java | 35 ++ .../correctness/invariants/ManualTest.java | 36 ++ .../correctness/invariants/ModuleTest.java | 30 + .../invariants/TraversedObjects.java | 34 ++ .../opacity/SequentialReplayThread.java | 70 +++ .../opacity/StructureComparisonOperation.java | 336 +++++++++++ .../impl/DefaultOperationExecutor.java | 30 + .../impl/DefaultOperationExecutorFactory.java | 19 + .../stmbench7/impl/DefaultThreadFactory.java | 11 + .../impl/NoSynchronizationInitializer.java | 34 ++ .../impl/backend/BackendFactoryImpl.java | 30 + .../java/stmbench7/impl/backend/BagImpl.java | 27 + .../stmbench7/impl/backend/IdPoolImpl.java | 52 ++ .../impl/backend/ImmutableViewImpl.java | 32 + .../stmbench7/impl/backend/LargeSetImpl.java | 35 ++ .../stmbench7/impl/backend/SmallSetImpl.java | 35 ++ .../stmbench7/impl/backend/TreeMapIndex.java | 66 +++ .../stmbench7/impl/core/AssemblyImpl.java | 52 ++ .../stmbench7/impl/core/AtomicPartImpl.java | 111 ++++ .../stmbench7/impl/core/BaseAssemblyImpl.java | 72 +++ .../impl/core/ComplexAssemblyImpl.java | 84 +++ .../impl/core/CompositePartImpl.java | 96 +++ .../stmbench7/impl/core/ConnectionImpl.java | 53 ++ .../impl/core/DesignObjFactoryImpl.java | 63 ++ .../stmbench7/impl/core/DesignObjImpl.java | 85 +++ .../stmbench7/impl/core/DocumentImpl.java | 95 +++ .../java/stmbench7/impl/core/ManualImpl.java | 107 ++++ .../java/stmbench7/impl/core/ModuleImpl.java | 46 ++ .../impl/deucestm/DeuceSTMInitializer.java | 12 + .../deucestm/DeuceSTMOperationExecutor.java | 24 + .../DeuceSTMOperationExecutorFactory.java | 17 + .../locking/CGLockingInitializer.java | 16 + .../locking/CGLockingOperationExecutor.java | 64 ++ .../CGLockingOperationExecutorFactory.java | 17 + .../locking/MGLockingComplexAssemblyImpl.java | 50 ++ .../locking/MGLockingDesignObjFactory.java | 22 + .../locking/MGLockingInitializer.java | 20 + .../locking/MGLockingOperationExecutor.java | 316 ++++++++++ .../MGLockingOperationExecutorFactory.java | 17 + .../stmbench7/operations/BaseOperation.java | 54 ++ .../stmbench7/operations/Operation10.java | 35 ++ .../stmbench7/operations/Operation11.java | 38 ++ .../stmbench7/operations/Operation12.java | 35 ++ .../stmbench7/operations/Operation13.java | 35 ++ .../stmbench7/operations/Operation14.java | 35 ++ .../stmbench7/operations/Operation15.java | 42 ++ .../java/stmbench7/operations/Operation6.java | 56 ++ .../java/stmbench7/operations/Operation7.java | 53 ++ .../java/stmbench7/operations/Operation8.java | 50 ++ .../java/stmbench7/operations/Operation9.java | 35 ++ .../java/stmbench7/operations/Query1.java | 51 ++ .../java/stmbench7/operations/Query2.java | 57 ++ .../java/stmbench7/operations/Query3.java | 20 + .../java/stmbench7/operations/Query4.java | 52 ++ .../java/stmbench7/operations/Query5.java | 52 ++ .../java/stmbench7/operations/Query6.java | 55 ++ .../java/stmbench7/operations/Query7.java | 37 ++ .../operations/SetupDataStructure.java | 74 +++ .../stmbench7/operations/ShortTraversal1.java | 95 +++ .../operations/ShortTraversal10.java | 36 ++ .../stmbench7/operations/ShortTraversal2.java | 39 ++ .../stmbench7/operations/ShortTraversal6.java | 36 ++ .../stmbench7/operations/ShortTraversal7.java | 39 ++ .../stmbench7/operations/ShortTraversal8.java | 35 ++ .../stmbench7/operations/ShortTraversal9.java | 56 ++ .../operations/StructuralModification1.java | 32 + .../operations/StructuralModification2.java | 41 ++ .../operations/StructuralModification3.java | 47 ++ .../operations/StructuralModification4.java | 56 ++ .../operations/StructuralModification5.java | 48 ++ .../operations/StructuralModification6.java | 46 ++ .../operations/StructuralModification7.java | 46 ++ .../operations/StructuralModification8.java | 43 ++ .../java/stmbench7/operations/Traversal1.java | 89 +++ .../stmbench7/operations/Traversal2a.java | 43 ++ .../stmbench7/operations/Traversal2b.java | 30 + .../stmbench7/operations/Traversal2c.java | 33 ++ .../stmbench7/operations/Traversal3a.java | 54 ++ .../stmbench7/operations/Traversal3b.java | 30 + .../stmbench7/operations/Traversal3c.java | 32 + .../java/stmbench7/operations/Traversal4.java | 46 ++ .../java/stmbench7/operations/Traversal5.java | 44 ++ .../java/stmbench7/operations/Traversal6.java | 41 ++ .../java/stmbench7/operations/Traversal7.java | 70 +++ .../java/stmbench7/operations/Traversal8.java | 37 ++ .../java/stmbench7/operations/Traversal9.java | 26 + .../stmbench7/test/backend/IndexTest.java | 227 +++++++ 144 files changed, 7702 insertions(+) create mode 100644 benchmarks/scala-stm/stmbench7/build.sbt create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/BenchThread.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/Benchmark.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/ImplParameters.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/OperationExecutor.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/OperationExecutorFactory.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/OperationId.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/OperationType.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/Parameters.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/Setup.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/SynchMethodInitializer.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/ThreadFactory.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/ThreadRandom.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/annotations/Atomic.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/annotations/ContainedInAtomic.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/annotations/Immutable.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/annotations/NonAtomic.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/annotations/ReadOnly.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/annotations/ThreadLocal.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/annotations/Transactional.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/annotations/Update.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/backend/BackendFactory.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/backend/IdPool.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/backend/ImmutableCollection.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/backend/Index.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/backend/LargeSet.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/Assembly.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/AssemblyBuilder.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/AtomicPart.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/AtomicPartBuilder.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/BaseAssembly.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/ComplexAssembly.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/CompositePart.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/CompositePartBuilder.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/Connection.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/DesignObj.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/DesignObjBuilder.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/DesignObjFactory.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/Document.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/DocumentBuilder.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/Manual.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/ManualBuilder.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/Module.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/ModuleBuilder.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/Operation.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/OperationFailedException.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/RuntimeError.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/correctness/invariants/AssemblyTest.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/correctness/invariants/AtomicPartTest.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/correctness/invariants/BaseAssemblyTest.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/correctness/invariants/CheckInvariantsOperation.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/correctness/invariants/ComplexAssemblyTest.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/correctness/invariants/CompositePartTest.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/correctness/invariants/ConnectionTest.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/correctness/invariants/DesignObjTest.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/correctness/invariants/DocumentationTest.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/correctness/invariants/IndexTest.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/correctness/invariants/InvariantTest.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/correctness/invariants/ManualTest.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/correctness/invariants/ModuleTest.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/correctness/invariants/TraversedObjects.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/correctness/opacity/SequentialReplayThread.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/correctness/opacity/StructureComparisonOperation.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/DefaultOperationExecutor.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/DefaultOperationExecutorFactory.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/DefaultThreadFactory.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/NoSynchronizationInitializer.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/backend/BackendFactoryImpl.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/backend/BagImpl.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/backend/IdPoolImpl.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/backend/ImmutableViewImpl.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/backend/LargeSetImpl.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/backend/SmallSetImpl.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/backend/TreeMapIndex.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/core/AssemblyImpl.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/core/AtomicPartImpl.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/core/BaseAssemblyImpl.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/core/ComplexAssemblyImpl.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/core/CompositePartImpl.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/core/ConnectionImpl.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/core/DesignObjFactoryImpl.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/core/DesignObjImpl.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/core/DocumentImpl.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/core/ManualImpl.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/core/ModuleImpl.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/deucestm/DeuceSTMInitializer.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/deucestm/DeuceSTMOperationExecutor.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/deucestm/DeuceSTMOperationExecutorFactory.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/locking/CGLockingInitializer.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/locking/CGLockingOperationExecutor.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/locking/CGLockingOperationExecutorFactory.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/locking/MGLockingComplexAssemblyImpl.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/locking/MGLockingDesignObjFactory.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/locking/MGLockingInitializer.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/locking/MGLockingOperationExecutor.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/locking/MGLockingOperationExecutorFactory.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/BaseOperation.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Operation10.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Operation11.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Operation12.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Operation13.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Operation14.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Operation15.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Operation6.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Operation7.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Operation8.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Operation9.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Query1.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Query2.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Query3.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Query4.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Query5.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Query6.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Query7.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/SetupDataStructure.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/ShortTraversal1.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/ShortTraversal10.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/ShortTraversal2.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/ShortTraversal6.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/ShortTraversal7.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/ShortTraversal8.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/ShortTraversal9.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/StructuralModification1.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/StructuralModification2.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/StructuralModification3.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/StructuralModification4.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/StructuralModification5.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/StructuralModification6.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/StructuralModification7.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/StructuralModification8.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Traversal1.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Traversal2a.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Traversal2b.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Traversal2c.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Traversal3a.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Traversal3b.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Traversal3c.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Traversal4.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Traversal5.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Traversal6.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Traversal7.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Traversal8.java create mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Traversal9.java create mode 100644 benchmarks/scala-stm/stmbench7/src/test/java/stmbench7/test/backend/IndexTest.java diff --git a/benchmarks/scala-stm/stmbench7/build.sbt b/benchmarks/scala-stm/stmbench7/build.sbt new file mode 100644 index 00000000..c9315c27 --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/build.sbt @@ -0,0 +1,12 @@ +lazy val parentProject = ProjectRef(uri("../../.."), "scalaStmBenchmarks") + +lazy val stmBench7 = (project in file(".")) + .settings( + name := "stmbench7", + organization := "ch.epfl.dcl", + version := "1.0-20110215-nodeuce", + crossPaths := false, + autoScalaLibrary := false, + javacOptions := (parentProject / javacOptions).value, + exportJars := true + ) diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/BenchThread.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/BenchThread.java new file mode 100644 index 00000000..f9f50916 --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/BenchThread.java @@ -0,0 +1,166 @@ +package stmbench7; + +import java.lang.reflect.Constructor; +import java.util.ArrayList; + +import stmbench7.annotations.NonAtomic; +import stmbench7.core.Operation; +import stmbench7.core.RuntimeError; +import stmbench7.core.OperationFailedException; + +/** + * A single thread of the STMBench7 benchmark. Executes operations assigned to + * it one by one, randomly choosing the next operation and respecting the + * expected ratios of operations' counts. + */ +@NonAtomic +public class BenchThread implements Runnable { + + protected volatile boolean stop = false; + protected double[] operationCDF; + protected OperationExecutor[] operations; + protected final short myThreadNum; + + public int[] successfulOperations, failedOperations; + public int[][] operationsTTC, operationsHighTTCLog; + + public class ReplayLogEntry implements Comparable { + public final short threadNum; + public final int timestamp, result; + public final boolean failed; + public final int opNum; + + public ReplayLogEntry(int timestamp, int result, boolean failed, + int opNum) { + this.threadNum = myThreadNum; + this.timestamp = timestamp; + this.result = result; + this.failed = failed; + this.opNum = opNum; + } + + public int compareTo(ReplayLogEntry entry) { + return timestamp - entry.timestamp; + } + } + + public ArrayList replayLog; + + public BenchThread(Setup setup, double[] operationCDF, short myThreadNum) { + this.operationCDF = operationCDF; + + int numOfOperations = OperationId.values().length; + operationsTTC = new int[numOfOperations][Parameters.MAX_LOW_TTC + 1]; + operationsHighTTCLog = new int[numOfOperations][Parameters.HIGH_TTC_ENTRIES]; + successfulOperations = new int[numOfOperations]; + failedOperations = new int[numOfOperations]; + operations = new OperationExecutor[numOfOperations]; + this.myThreadNum = myThreadNum; + + createOperations(setup); + + if (Parameters.sequentialReplayEnabled) + replayLog = new ArrayList(); + } + + protected BenchThread(Setup setup, double[] operationCDF) { + this.operationCDF = operationCDF; + operations = new OperationExecutor[OperationId.values().length]; + createOperations(setup); + myThreadNum = 0; + } + + public void run() { + int i = 0; + while (!stop) { + //if (i++ > 55) continue; + int operationNumber = getNextOperationNumber(); + + OperationType type = OperationId.values()[operationNumber].getType(); + //if( (type != OperationType.SHORT_TRAVERSAL) ) continue; + // (type != OperationType.SHORT_TRAVERSAL_RO) && + // (type != OperationType.OPERATION) ) + // continue; + + //System.out.println(i + " > " + // + OperationId.values()[operationNumber]); + + OperationExecutor currentExecutor = operations[operationNumber]; + int result = 0; + boolean failed = false; + + try { + long startTime = System.currentTimeMillis(); + + result = currentExecutor.execute(); + + long endTime = System.currentTimeMillis(); + //System.out.println("success"); + + successfulOperations[operationNumber]++; + int ttc = (int) (endTime - startTime); + if (ttc <= Parameters.MAX_LOW_TTC) + operationsTTC[operationNumber][ttc]++; + else { + double logHighTtc = (Math.log(ttc) - Math + .log(Parameters.MAX_LOW_TTC + 1)) + / Math.log(Parameters.HIGH_TTC_LOG_BASE); + int intLogHighTtc = Math.min((int) logHighTtc, + Parameters.HIGH_TTC_ENTRIES - 1); + operationsHighTTCLog[operationNumber][intLogHighTtc]++; + } + } catch (OperationFailedException e) { + //System.out.println("failed"); + failedOperations[operationNumber]++; + failed = true; + } + + if (Parameters.sequentialReplayEnabled) { + ReplayLogEntry newEntry = new ReplayLogEntry( + currentExecutor.getLastOperationTimestamp(), result, failed, + operationNumber); + replayLog.add(newEntry); + //System.out.println("ts: " + newEntry.timestamp); + } + } + System.err.println("Thread #" + myThreadNum + " finished."); + //i = 0; + //for (ReplayLogEntry entry : replayLog) + // System.out.println(i++ + " % " + OperationId.values()[entry.opNum] + // + " -- " + entry.timestamp); + } + + public void stopThread() { + stop = true; + } + + protected void createOperations(Setup setup) { + for (OperationId operationDescr : OperationId.values()) { + Class operationClass = operationDescr + .getOperationClass(); + int operationIndex = operationDescr.ordinal(); + + try { + Constructor operationConstructor = operationClass + .getConstructor(Setup.class); + Operation operation = operationConstructor.newInstance(setup); + + operations[operationIndex] = OperationExecutorFactory.instance + .createOperationExecutor(operation); + assert (operation.getOperationId().getOperationClass() + .equals(operationClass)); + } catch (Exception e) { + throw new RuntimeError("Error while creating operation " + + operationDescr, e); + } + } + } + + protected int getNextOperationNumber() { + double whichOperation = ThreadRandom.nextDouble(); + int operationNumber = 0; + while (whichOperation >= operationCDF[operationNumber]) + operationNumber++; + return operationNumber; + } +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/Benchmark.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/Benchmark.java new file mode 100644 index 00000000..1cef2665 --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/Benchmark.java @@ -0,0 +1,556 @@ +package stmbench7; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Formatter; + +import stmbench7.annotations.NonAtomic; +import stmbench7.backend.BackendFactory; +import stmbench7.core.DesignObjFactory; +import stmbench7.core.Operation; +import stmbench7.core.RuntimeError; +import stmbench7.correctness.invariants.CheckInvariantsOperation; +import stmbench7.correctness.opacity.SequentialReplayThread; +import stmbench7.correctness.opacity.StructureComparisonOperation; +import stmbench7.impl.NoSynchronizationInitializer; + +/** + * STMBench7 benchmark, the main program. + * Run with argument "-h" or "--help" to see the syntax. + * + * TODO: The class got too large and needs some careful refactoring. + * TODO: An XML output of the benchmark results would be helpful. + */ +@NonAtomic +public class Benchmark { + + public static final String VERSION = "1.0(15.02.2011)"; + + class BenchmarkParametersException extends Exception { + private static final long serialVersionUID = 6341915439489283553L; + + public BenchmarkParametersException(String message, Exception cause) { + super(message + ": " + cause.toString()); + } + + public BenchmarkParametersException(String message) { + super(message); + } + + public BenchmarkParametersException() { + super(""); + } + } + + public static void main(String[] args) throws InterruptedException { + Benchmark benchmark = null; + + try { + benchmark = new Benchmark(args); + } + catch(BenchmarkParametersException e) { + System.err.println(e.getMessage()); + System.exit(1); + } + + //benchmark.checkInvariants(true); + benchmark.createInitialClone(); + benchmark.start(); + //benchmark.checkInvariants(false); + //benchmark.checkOpacity(); + benchmark.showTTCHistograms(); + benchmark.showStats(); + } + + private SynchMethodInitializer synchMethodInitializer; + private boolean printTTCHistograms = false; + private double[] operationCDF; + private BenchThread[] benchThreads; + private Thread[] threads; + private Setup setup, setupClone; + private double elapsedTime; + + private Benchmark(String[] args) throws BenchmarkParametersException, InterruptedException { + printHeader(); + + parseCommandLineParameters(args); + printRunTimeParametersInformation(); + + generateOperationCDF(); + setupStructures(); + } + + private void printHeader() { + String header = + "The STMBench7 Benchmark (Java version)\n" + + "A benchmark for comparing synchronization techniques\n" + + "Version: " + VERSION + "\n" + + "More information: http://lpd.epfl.ch/site/research/tmeval\n" + + "Copyright (C) 2006-2008 LPD, I&C, EPFL (http://lpd.epfl.ch)\n" + + "Implemented by Michal Kapalka (http://kapalka.eu)\n"+ + "Updated by Vincent Gramoli for compliance with the VELOX stack"; + + printLine('='); + System.out.println(header); + printLine('='); + System.out.println(); + } + + @SuppressWarnings("unchecked") + private void parseCommandLineParameters(String[] args) throws BenchmarkParametersException { + int argNumber = 0; + String workload = null, synchType = null, stmInitializerClassName = null; + + while(argNumber < args.length) { + String currentArg = args[argNumber++]; + + try { + if(currentArg.equals("--help") || currentArg.equals("-h")) { + printSyntax(); + throw new BenchmarkParametersException(); + } + else if(currentArg.equals("--no-traversals")) Parameters.longTraversalsEnabled = false; + else if(currentArg.equals("--no-sms")) Parameters.structureModificationEnabled = false; + else if(currentArg.equals("--ttc-histograms")) printTTCHistograms = true; + else if(currentArg.equals("--seq-replay")) Parameters.sequentialReplayEnabled = true; + else if(currentArg.equals("--")) { + Parameters.stmCommandLineParameters = new String[args.length - argNumber]; + int stmArgNum = 0; + while(argNumber < args.length) + Parameters.stmCommandLineParameters[stmArgNum++] = args[argNumber++]; + break; + } + else { + String optionValue = args[argNumber++]; + if(currentArg.equals("-t")) Parameters.numThreads = Integer.parseInt(optionValue); + else if(currentArg.equals("-l")) Parameters.numSeconds = Integer.parseInt(optionValue); + else if(currentArg.equals("-w")) workload = optionValue; + else if(currentArg.equals("-g")) synchType = optionValue; + else if(currentArg.equals("-s")) stmInitializerClassName = optionValue; + else throw new BenchmarkParametersException("Invalid option: " + currentArg); + } + } + catch(IndexOutOfBoundsException e) { + throw new BenchmarkParametersException("Missing value after option: " + currentArg); + } + catch(NumberFormatException e) { + throw new BenchmarkParametersException("Number expected after option: " + currentArg); + } + } + + if(workload != null) { + if(workload.equals("r")) + Parameters.workloadType = Parameters.WorkloadType.READ_DOMINATED; + else if(workload.equals("rw")) + Parameters.workloadType = Parameters.WorkloadType.READ_WRITE; + else if(workload.equals("w")) + Parameters.workloadType = Parameters.WorkloadType.WRITE_DOMINATED; + else throw new BenchmarkParametersException("Invalid workload type: " + workload); + } + + if(synchType != null) { + if(synchType.equals("coarse")) + Parameters.synchronizationType = Parameters.SynchronizationType.LOCK_COARSE; + else if(synchType.equals("medium")) + Parameters.synchronizationType = Parameters.SynchronizationType.LOCK_MEDIUM; + else if(synchType.equals("fine")) + Parameters.synchronizationType = Parameters.SynchronizationType.LOCK_FINE; + else if(synchType.equals("none")) + Parameters.synchronizationType = Parameters.SynchronizationType.NONE; + else if(synchType.equals("stm")) + Parameters.synchronizationType = Parameters.SynchronizationType.STM; + else throw new BenchmarkParametersException("Invalid lock granularity: " + synchType); + } + + Class synchMethodInitializerClass = null; + switch(Parameters.synchronizationType) { + case NONE: + synchMethodInitializerClass = ImplParameters.noSynchronizationInitializerClass; + break; + case LOCK_COARSE: + synchMethodInitializerClass = ImplParameters.coarseGrainedLockingInitializerClass; + break; + case LOCK_MEDIUM: + synchMethodInitializerClass = ImplParameters.mediumGrainedLockingInitializerClass; + break; + case LOCK_FINE: + synchMethodInitializerClass = ImplParameters.fineGrainedLockingInitializerClass; + break; + case STM: + if(stmInitializerClassName != null) { + try { + synchMethodInitializerClass = + (Class) + Class.forName(stmInitializerClassName); + } + catch(ClassNotFoundException e) { + throw new BenchmarkParametersException("Error instantiating the STM" + + " initializer class", e); + } + } + else if(ImplParameters.defaultSTMInitializerClass != null) { + synchMethodInitializerClass = ImplParameters.defaultSTMInitializerClass; + } + else throw new BenchmarkParametersException("STM initializer class name not given" + + " and a default class not specified" + + " in ImpParameters.defaultSTMInitializerClass"); + break; + } + try { + synchMethodInitializer = + synchMethodInitializerClass.newInstance(); + } + catch(Exception e) { + throw new BenchmarkParametersException("Error instantiating STM initializer class", e); + } + + setFactoryInstances(synchMethodInitializer); + } + + private void setFactoryInstances(SynchMethodInitializer synchMethodInitializer) { + DesignObjFactory.setInstance(synchMethodInitializer.createDesignObjFactory()); + BackendFactory.setInstance(synchMethodInitializer.createBackendFactory()); + OperationExecutorFactory.setInstance(synchMethodInitializer.createOperationExecutorFactory()); + ThreadFactory.setInstance(synchMethodInitializer.createThreadFactory()); + } + + private void printRunTimeParametersInformation() { + printSection("Benchmark parameters"); + + System.out.println("Number of threads: " + Parameters.numThreads + "\n" + + "Length: " + Parameters.numSeconds + " s\n" + + "Workload: " + Parameters.workloadType + "\n" + + "Synchronization method: " + Parameters.synchronizationType + "\n" + + "Long traversals " + (Parameters.longTraversalsEnabled ? "enabled" : "disabled") + "\n" + + "Structural modification operations " + + (Parameters.structureModificationEnabled ? "enabled" : "disabled") + "\n" + + "DesignObjFactory: " + DesignObjFactory.instance.getClass().getName() + "\n" + + "BackendFactory: " + BackendFactory.instance.getClass().getName() + "\n" + + "OperationExecutorFactory: " + + OperationExecutorFactory.instance.getClass().getName() + "\n" + + "ThreadFactory: " + ThreadFactory.instance.getClass().getName() + "\n" + + "Sequential replay " + (Parameters.sequentialReplayEnabled ? "enabled" : "disabled")); + + System.out.print("STM-specific parameters:"); + if(Parameters.stmCommandLineParameters == null) System.out.print(" none"); + else for(String parameter : Parameters.stmCommandLineParameters) + System.out.print(" " + parameter); + System.out.println("\n"); + } + + private void generateOperationCDF() { + double shortTraversalsRatio = (double)Parameters.ShortTraversalsRatio / 100.0, + operationsRatio = (double)Parameters.OperationsRatio / 100.0; + + double traversalsRatio, structuralModificationsRatio; + if(Parameters.longTraversalsEnabled) traversalsRatio = (double)Parameters.TraversalsRatio / 100.0; + else traversalsRatio = 0; + if(Parameters.structureModificationEnabled) + structuralModificationsRatio = (double)Parameters.StructuralModificationsRatio / 100.0; + else structuralModificationsRatio = 0; + + double readOnlyOperationsRatio = (double)Parameters.workloadType.readOnlyOperationsRatio / 100.0, + updateOperationsRatio = 1.0 - readOnlyOperationsRatio; + + double sumRatios = traversalsRatio + shortTraversalsRatio + operationsRatio + + structuralModificationsRatio * updateOperationsRatio; + traversalsRatio /= sumRatios; + shortTraversalsRatio /= sumRatios; + operationsRatio /= sumRatios; + structuralModificationsRatio /= sumRatios; + + OperationId[] operations = OperationId.values(); + for(OperationId operation : operations) operation.getType().count++; + + OperationType.TRAVERSAL.probability = + traversalsRatio * updateOperationsRatio / OperationType.TRAVERSAL.count; + OperationType.TRAVERSAL_RO.probability = + traversalsRatio * readOnlyOperationsRatio / OperationType.TRAVERSAL_RO.count; + OperationType.SHORT_TRAVERSAL.probability = + shortTraversalsRatio * updateOperationsRatio / OperationType.SHORT_TRAVERSAL.count; + OperationType.SHORT_TRAVERSAL_RO.probability = + shortTraversalsRatio * readOnlyOperationsRatio / OperationType.SHORT_TRAVERSAL_RO.count; + OperationType.OPERATION.probability = + operationsRatio * updateOperationsRatio / OperationType.OPERATION.count; + OperationType.OPERATION_RO.probability = + operationsRatio * readOnlyOperationsRatio / OperationType.OPERATION_RO.count; + OperationType.STRUCTURAL_MODIFICATION.probability = + structuralModificationsRatio * updateOperationsRatio / OperationType.STRUCTURAL_MODIFICATION.count; + + System.out.println("Operation ratios [%]:"); + for(OperationType type : OperationType.values()) + System.out.println(alignText(type.toString(), 23) + ": " + + formatDouble(type.probability * type.count * 100)); + System.out.println(); + + double[] operationProbabilities = new double[operations.length]; + for(OperationId operation : operations) { + double operationProbability = operation.getType().probability; + operationProbabilities[operation.ordinal()] = operationProbability; + } + + operationCDF = new double[operations.length]; + double prevProbValue = 0; + for(int opNum = 0; opNum < operations.length; opNum++) { + operationCDF[opNum] = prevProbValue + operationProbabilities[opNum]; + prevProbValue = operationCDF[opNum]; + } + operationCDF[operations.length - 1] = 1.0; // to avoid rounding errors + } + + private void setupStructures() throws InterruptedException { + System.err.println("Setup start..."); + setup = new Setup(); + + benchThreads = new BenchThread[Parameters.numThreads]; + threads = new Thread[Parameters.numThreads]; + for(short threadNum = 0; threadNum < Parameters.numThreads; threadNum++) { + benchThreads[threadNum] = + new BenchThread(setup, operationCDF, threadNum); + threads[threadNum] = ThreadFactory.instance.createThread(benchThreads[threadNum]); + } + System.err.println("Setup completed."); + } + + private void checkInvariants(boolean initial) throws InterruptedException { + if(initial) System.err.println("Checking invariants (initial data structure):"); + else System.err.println("Checking invariants (final data structure):"); + + Operation checkInvariantsOperation = + new CheckInvariantsOperation(setup, initial); + OperationExecutorFactory.executeSequentialOperation(checkInvariantsOperation); + } + + private void createInitialClone() throws InterruptedException { + if(! Parameters.sequentialReplayEnabled) return; + + System.err.println("Cloning the initial data structure..."); + ThreadRandom.reset(); + setFactoryInstances(new NoSynchronizationInitializer()); + setupClone = new Setup(); + setFactoryInstances(synchMethodInitializer); + System.err.println("Cloning completed."); + + System.err.println("Checking if the clone is the same as the data structure..."); + StructureComparisonOperation structureComparisonOperation = + new StructureComparisonOperation(setup, setupClone); + OperationExecutorFactory.executeSequentialOperation(structureComparisonOperation); + System.err.println("Check OK."); + } + + private void start() throws InterruptedException { + System.err.println("\nBenchmark started."); + ThreadRandom.startConcurrentPhase(); + + long startTime = System.currentTimeMillis(); + + for(Thread thread : threads) thread.start(); + + Thread.sleep(Parameters.numSeconds * 1000); + + for(BenchThread thread : benchThreads) thread.stopThread(); + for(Thread thread : threads) thread.join(); + + long endTime = System.currentTimeMillis(); + elapsedTime = ((double)(endTime - startTime)) / 1000.0; + System.err.println("Benchmark completed.\n"); + } + + private void checkOpacity() throws InterruptedException { + if(! Parameters.sequentialReplayEnabled) return; + + System.err.println("\nReplaying the execution in a single thread..."); + + ArrayList replayLog = new ArrayList(); + for(BenchThread thread : benchThreads) + replayLog.addAll(thread.replayLog); + BenchThread.ReplayLogEntry[] replayLogArray = replayLog.toArray(new BenchThread.ReplayLogEntry[0]); + Arrays.sort(replayLogArray); + replayLog = new ArrayList(); + for(BenchThread.ReplayLogEntry entry : replayLogArray) replayLog.add(entry); + replayLogArray = null; + + setFactoryInstances(new NoSynchronizationInitializer()); + ThreadRandom.startSequentialReplayPhase(); + SequentialReplayThread seqThread = new SequentialReplayThread(setupClone, + operationCDF, replayLog); + seqThread.run(); + setFactoryInstances(synchMethodInitializer); + + StructureComparisonOperation structureComparisonOperation = + new StructureComparisonOperation(setup, setupClone); + OperationExecutorFactory.executeSequentialOperation(structureComparisonOperation); + System.err.println("\nOpacity ensured.\n"); + } + + private void showTTCHistograms() { + if(! printTTCHistograms) return; + + printSection("TTC histograms"); + + OperationId[] operations = OperationId.values(); + for(OperationId operation : operations) { + System.out.print("TTC histogram for " + operation + ":"); + + for(int ttc = 0; ttc <= Parameters.MAX_LOW_TTC; ttc++) { + int count = 0; + for(BenchThread thread : benchThreads) + count += thread.operationsTTC[operation.ordinal()][ttc]; + + System.out.print(" " + ttc + "," + count); + } + + for(int logTtcIndex = 0; logTtcIndex < Parameters.HIGH_TTC_ENTRIES; logTtcIndex++) { + int count = 0; + for(BenchThread thread : benchThreads) + count += thread.operationsHighTTCLog[operation.ordinal()][logTtcIndex]; + + int ttc = logTtcIndex2Ttc(logTtcIndex); + System.out.print(" " + ttc + "," + count); + } + + System.out.println(); + } + System.out.println(); + } + + private int logTtcIndex2Ttc(double logTtcIndex) { + return (int)((Parameters.MAX_LOW_TTC + 1) * Math.pow(Parameters.HIGH_TTC_LOG_BASE, logTtcIndex)); + } + + private void showStats() { + printSection("Detailed results"); + + OperationId[] operations = OperationId.values(); + for(OperationId operation : operations) { + System.out.print("Operation " + alignText(operation.toString(), 4) + ": "); + + int opNumber = operation.ordinal(); + int successful = 0, failed = 0, maxttc = 0; + for(BenchThread thread : benchThreads) { + successful += thread.successfulOperations[opNumber]; + failed += thread.failedOperations[opNumber]; + maxttc = Math.max(maxttc, computeMaxThreadTTC(thread, opNumber)); + } + + System.out.println("successful = " + successful + "\tmaxttc = " + maxttc + "\tfailed = " + failed); + + OperationType operationType = operation.getType(); + operationType.successfulOperations += successful; + operationType.failedOperations += failed; + operationType.maxttc = Math.max(operationType.maxttc, maxttc); + } + System.out.println(); + + printSection("Sample errors (operation ratios [%])"); + + int totalSuccessful = 0, totalFailed = 0; + for(OperationType type : OperationType.values()) { + totalSuccessful += type.successfulOperations; + totalFailed += type.failedOperations; + } + + double totalError = 0, totalTError = 0; + for(OperationType type : OperationType.values()) { + double expectedRatio = type.probability * type.count * 100.0; + double realRatio = (double)type.successfulOperations / (double)totalSuccessful * 100.0; + double error = Math.abs(realRatio - expectedRatio); + double tRealRatio = (double)(type.successfulOperations + type.failedOperations) / + (double)(totalSuccessful + totalFailed) * 100.0; + double tError = Math.abs(tRealRatio - expectedRatio); + System.out.println(alignText(type.toString(), 23) + ": " + + "expected = " + formatDouble(expectedRatio) + + "\tsuccessful = " + formatDouble(realRatio) + + "\terror = " + formatDouble(error) + + "\t(total = " + formatDouble(tRealRatio) + + "\terror = " + formatDouble(tError) + ")"); + totalError += error; + totalTError += tError; + } + System.out.println(); + + printSection("Summary results"); + + int total = totalSuccessful + totalFailed; + for(OperationType type : OperationType.values()) { + int totalTypeOperations = type.successfulOperations + type.failedOperations; + System.out.println(alignText(type.toString(), 23) + ": " + + "successful = " + type.successfulOperations + + "\tmaxttc = " + type.maxttc + + "\tfailed = " + type.failedOperations + + "\ttotal = " + totalTypeOperations); + } + System.out.println(); + + System.out.println("Total sample error: " + formatDouble(totalError) + "%" + + " (" + formatDouble(totalTError) + "% including failed)"); + System.out.println("Total throughput: " + formatDouble( (double)totalSuccessful / elapsedTime ) + " op/s" + + " (" + formatDouble( (double)total / elapsedTime ) + " op/s including failed)"); + System.out.println("Elapsed time: " + formatDouble(elapsedTime) + " s"); + } + + private int computeMaxThreadTTC(BenchThread thread, int opNumber) { + for(int logTtcIndex = Parameters.HIGH_TTC_ENTRIES - 1; logTtcIndex >= 0; logTtcIndex--) { + if(thread.operationsHighTTCLog[opNumber][logTtcIndex] > 0) + return logTtcIndex2Ttc(logTtcIndex); + } + + for(int ttc = Parameters.MAX_LOW_TTC; ttc >= 0; ttc--) { + if(thread.operationsTTC[opNumber][ttc] > 0) return ttc; + } + + return 0; // operation never completed with success + } + + private void printSyntax() { + String syntax = + "Syntax:\n" + + "java stmbench7.Benchmark [options] [-- stm-specific options]\n\n" + + "Options:\n" + + "\t-t numThreads -- set the number of threads (default: 1)\n" + + "\t-l length -- set the length of the benchmark, in seconds (default: 10)\n" + + "\t-w r|rw|w -- set the workload: r = read-dominated, w = write-dominated\n" + + "\t rw = read-write (default: read-dominated)\n" + + "\t-g coarse|medium|fine|none|stm -- set synchronization method (default: coarse)\n" + + "\t-s stmInitializerClass -- set STM initializer class (default: none)\n" + + "\t--no-traversals -- do not use long traversals\n" + + "\t--no-sms -- do not use structural modification operations\n" + + "\t--seq-replay -- replay the execution in a single thread\n" + + "\t (checks for opacity violations)\n" + + "\t--ttc-histograms -- print TTC histograms to stdout\n\n" + + "Note: the benchmark needs a lot of lot of memory, so the -Xmx option of Java\n" + + "might be necessary."; + System.err.println(syntax); + } + + private void printSection(String title) { + printLine('-'); + System.out.println(title); + printLine('-'); + } + + private void printLine(char ch) { + StringBuffer line = new StringBuffer(79); + for(int i = 0; i < 79; i++) line.append(ch); + System.out.println(line); + } + + private String alignText(String text, int width) { + int textLen = text.length(); + int padding = width - textLen; + if(padding < 0) throw new RuntimeError("alignText: width too small!"); + + StringBuffer output = new StringBuffer(width); + for(int i = 0; i < padding; i++) output.append(' '); + output.append(text); + + return output.toString(); + } + + private String formatDouble(double number) { + Formatter formatter = new Formatter(); + formatter.format("%3.2f", number); + return formatter.toString(); + } +} + diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/ImplParameters.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/ImplParameters.java new file mode 100644 index 00000000..c791f38a --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/ImplParameters.java @@ -0,0 +1,30 @@ +package stmbench7; + +import stmbench7.annotations.NonAtomic; +import stmbench7.annotations.ThreadLocal; +import stmbench7.impl.NoSynchronizationInitializer; +import stmbench7.locking.CGLockingInitializer; +import stmbench7.locking.MGLockingInitializer; + +/** + * Parameters that describe the synchronization techniques + * compiled in the benchmark. + */ +@NonAtomic +@ThreadLocal +public class ImplParameters { + + public static final Class + noSynchronizationInitializerClass = NoSynchronizationInitializer.class, + coarseGrainedLockingInitializerClass = CGLockingInitializer.class, + mediumGrainedLockingInitializerClass = MGLockingInitializer.class, + fineGrainedLockingInitializerClass = null; // not implemented yet + + /** + * If non-null, the STM initializer does not have to be specified + * each time the benchmark is run with the "-g stm" command-line + * parameter. + */ + public static final Class + defaultSTMInitializerClass = null; +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/OperationExecutor.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/OperationExecutor.java new file mode 100644 index 00000000..603dba11 --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/OperationExecutor.java @@ -0,0 +1,17 @@ +package stmbench7; + +import stmbench7.annotations.NonAtomic; +import stmbench7.annotations.ThreadLocal; +import stmbench7.core.OperationFailedException; + +/** + * An interface representing a class that executes a given operation. + * Can set up a transaction and handle aborts. + */ +@NonAtomic +@ThreadLocal +public interface OperationExecutor { + + int execute() throws OperationFailedException; + int getLastOperationTimestamp(); +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/OperationExecutorFactory.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/OperationExecutorFactory.java new file mode 100644 index 00000000..1328afbb --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/OperationExecutorFactory.java @@ -0,0 +1,41 @@ +package stmbench7; + +import stmbench7.annotations.NonAtomic; +import stmbench7.core.Operation; +import stmbench7.core.OperationFailedException; +import stmbench7.core.RuntimeError; + +/** + * Creates an OperationExecutor object, which is used + * to execute the benchmark operations. For the default + * implementation, see stmbench7.impl.DefaultOperationExecutorFactory. + */ +@NonAtomic +public abstract class OperationExecutorFactory { + + public static OperationExecutorFactory instance = null; + + public static void setInstance(OperationExecutorFactory newInstance) { + instance = newInstance; + } + + public abstract OperationExecutor createOperationExecutor(Operation op); + + public static void executeSequentialOperation(final Operation op) throws InterruptedException { + Thread opThread = ThreadFactory.instance.createThread(new Runnable() { + public void run() { + OperationExecutor operationExecutor = + instance.createOperationExecutor(op); + try { + operationExecutor.execute(); + } + catch(OperationFailedException e) { + throw new RuntimeError("Unexpected failure of a sequential operation " + op); + } + + } + }); + opThread.start(); + opThread.join(); + } +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/OperationId.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/OperationId.java new file mode 100644 index 00000000..506aa70b --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/OperationId.java @@ -0,0 +1,121 @@ +package stmbench7; + +import stmbench7.annotations.NonAtomic; +import stmbench7.core.Operation; +import stmbench7.operations.Operation10; +import stmbench7.operations.Operation11; +import stmbench7.operations.Operation12; +import stmbench7.operations.Operation13; +import stmbench7.operations.Operation14; +import stmbench7.operations.Operation15; +import stmbench7.operations.Operation6; +import stmbench7.operations.Operation7; +import stmbench7.operations.Operation8; +import stmbench7.operations.Operation9; +import stmbench7.operations.Query1; +import stmbench7.operations.Query2; +import stmbench7.operations.Query3; +import stmbench7.operations.Query4; +import stmbench7.operations.Query5; +import stmbench7.operations.Query6; +import stmbench7.operations.Query7; +import stmbench7.operations.ShortTraversal1; +import stmbench7.operations.ShortTraversal10; +import stmbench7.operations.ShortTraversal2; +import stmbench7.operations.ShortTraversal6; +import stmbench7.operations.ShortTraversal7; +import stmbench7.operations.ShortTraversal8; +import stmbench7.operations.ShortTraversal9; +import stmbench7.operations.StructuralModification1; +import stmbench7.operations.StructuralModification2; +import stmbench7.operations.StructuralModification3; +import stmbench7.operations.StructuralModification4; +import stmbench7.operations.StructuralModification5; +import stmbench7.operations.StructuralModification6; +import stmbench7.operations.StructuralModification7; +import stmbench7.operations.StructuralModification8; +import stmbench7.operations.Traversal1; +import stmbench7.operations.Traversal2a; +import stmbench7.operations.Traversal2b; +import stmbench7.operations.Traversal2c; +import stmbench7.operations.Traversal3a; +import stmbench7.operations.Traversal3b; +import stmbench7.operations.Traversal3c; +import stmbench7.operations.Traversal4; +import stmbench7.operations.Traversal5; +import stmbench7.operations.Traversal6; +import stmbench7.operations.Traversal7; +import stmbench7.operations.Traversal8; +import stmbench7.operations.Traversal9; + +/** + * Lists all STMBench7 operations, together with the classes implementing them + * and their types. + */ +@NonAtomic +public enum OperationId { + T1(Traversal1.class, OperationType.TRAVERSAL_RO), + T2a(Traversal2a.class, OperationType.TRAVERSAL), + T2b(Traversal2b.class, OperationType.TRAVERSAL), + T2c(Traversal2c.class, OperationType.TRAVERSAL), + T3a(Traversal3a.class, OperationType.TRAVERSAL), + T3b(Traversal3b.class, OperationType.TRAVERSAL), + T3c(Traversal3c.class, OperationType.TRAVERSAL), + T4(Traversal4.class, OperationType.TRAVERSAL_RO), + T5(Traversal5.class, OperationType.TRAVERSAL), + T6(Traversal6.class, OperationType.TRAVERSAL_RO), + Q6(Query6.class, OperationType.TRAVERSAL_RO), + Q7(Query7.class, OperationType.TRAVERSAL_RO), + + ST1(ShortTraversal1.class, OperationType.SHORT_TRAVERSAL_RO), + ST2(ShortTraversal2.class, OperationType.SHORT_TRAVERSAL_RO), + ST3(Traversal7.class, OperationType.SHORT_TRAVERSAL_RO), + ST4(Query4.class, OperationType.SHORT_TRAVERSAL_RO), + ST5(Query5.class, OperationType.SHORT_TRAVERSAL_RO), + ST6(ShortTraversal6.class, OperationType.SHORT_TRAVERSAL), + ST7(ShortTraversal7.class, OperationType.SHORT_TRAVERSAL), + ST8(ShortTraversal8.class, OperationType.SHORT_TRAVERSAL), + ST9(ShortTraversal9.class, OperationType.SHORT_TRAVERSAL_RO), + ST10(ShortTraversal10.class, OperationType.SHORT_TRAVERSAL), + + OP1(Query1.class, OperationType.OPERATION_RO), + OP2(Query2.class, OperationType.OPERATION_RO), + OP3(Query3.class, OperationType.OPERATION_RO), + OP4(Traversal8.class, OperationType.OPERATION_RO), + OP5(Traversal9.class, OperationType.OPERATION_RO), + OP6(Operation6.class, OperationType.OPERATION_RO), + OP7(Operation7.class, OperationType.OPERATION_RO), + OP8(Operation8.class, OperationType.OPERATION_RO), + OP9(Operation9.class, OperationType.OPERATION), + OP10(Operation10.class, OperationType.OPERATION), + OP11(Operation11.class, OperationType.OPERATION), + OP12(Operation12.class, OperationType.OPERATION), + OP13(Operation13.class, OperationType.OPERATION), + OP14(Operation14.class, OperationType.OPERATION), + OP15(Operation15.class, OperationType.OPERATION), + + SM1(StructuralModification1.class, OperationType.STRUCTURAL_MODIFICATION), + SM2(StructuralModification2.class, OperationType.STRUCTURAL_MODIFICATION), + SM3(StructuralModification3.class, OperationType.STRUCTURAL_MODIFICATION), + SM4(StructuralModification4.class, OperationType.STRUCTURAL_MODIFICATION), + SM5(StructuralModification5.class, OperationType.STRUCTURAL_MODIFICATION), + SM6(StructuralModification6.class, OperationType.STRUCTURAL_MODIFICATION), + SM7(StructuralModification7.class, OperationType.STRUCTURAL_MODIFICATION), + SM8(StructuralModification8.class, OperationType.STRUCTURAL_MODIFICATION); + + protected Class operationClass; + protected OperationType type; + + private OperationId(Class operationClass, OperationType type) { + this.operationClass = operationClass; + this.type = type; + } + + public OperationType getType() { + return type; + } + + public Class getOperationClass() { + return operationClass; + } +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/OperationType.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/OperationType.java new file mode 100644 index 00000000..4079ce5c --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/OperationType.java @@ -0,0 +1,21 @@ +package stmbench7; + +import stmbench7.annotations.NonAtomic; + +/** + * Types of STMBench7 operations. The "RO" suffix means "read-only". + */ +@NonAtomic +public enum OperationType { + TRAVERSAL, TRAVERSAL_RO, + SHORT_TRAVERSAL, SHORT_TRAVERSAL_RO, + OPERATION, OPERATION_RO, + STRUCTURAL_MODIFICATION; + + /** + * Some helper fields to make life easier. + */ + public int count = 0; + public double probability = 0; + public int successfulOperations = 0, failedOperations = 0, maxttc = 0; +} \ No newline at end of file diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/Parameters.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/Parameters.java new file mode 100644 index 00000000..75e217c9 --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/Parameters.java @@ -0,0 +1,121 @@ +package stmbench7; + +import stmbench7.annotations.Immutable; + +/** + * Parameters of the STMBench7 benchmark (see the specification). + */ +@Immutable +public class Parameters { + + /** + * OO7 benchmark parameters for the "medium" size of the benchmark. + * Can be adjusted to match larger or smaller applications. + * Note: these values describe the data structure only at its initial + * state, before the first structure modification operation completes + * with success. + */ + public static final int NumAtomicPerComp = 200, + NumConnPerAtomic = 6, + DocumentSize = 20000, + ManualSize = 1000000, + NumCompPerModule = 500, + NumAssmPerAssm = 3, + NumAssmLevels = 7, + NumCompPerAssm = 3, + NumModules = 1; // currently not used (only a single module) + + /** + * Values derived from the OO7 parameters. Valid only before the first + * structure modification operation finishes with success. + */ + public static final int InitialTotalCompParts = NumModules * NumCompPerModule, + InitialTotalBaseAssemblies = (int)Math.pow(NumAssmPerAssm, NumAssmLevels - 1), + InitialTotalComplexAssemblies = + (1 - (int)Math.pow(NumAssmPerAssm, NumAssmLevels - 1)) / (1 - NumAssmPerAssm); + + /** + * Parameters defining how the size of the data structure can deviate + * from its initial size. Defines the size of the id pools. + */ + public static final int MaxCompParts = (int)(1.05 * InitialTotalCompParts), + MaxAtomicParts = MaxCompParts * NumAtomicPerComp, + MaxBaseAssemblies = (int)(1.05 * InitialTotalBaseAssemblies), + MaxComplexAssemblies = (int)(1.05 * InitialTotalComplexAssemblies); + + /** + * Constants used in various operations (values taken from the + * original OO7 source code). + */ + public static final int MinModuleDate = 1000, + MaxModuleDate = 1999, + MinAssmDate = 1000, + MaxAssmDate = 1999, + MinAtomicDate = 1000, + MaxAtomicDate = 1999, + MinOldCompDate = 0, + MaxOldCompDate = 999, + MinYoungCompDate = 2000, + MaxYoungCompDate = 2999, + YoungCompFrac = 10, + TypeSize = 10, + NumTypes = 10, + XYRange = 100000, + TitleSize = 40; + + /** + * Ratios of various operation types (in percents). + */ + public static final int TraversalsRatio = 5, + ShortTraversalsRatio = 40, + OperationsRatio = 45, + StructuralModificationsRatio = 10; + + /** + * Application workload. + */ + @Immutable + public enum WorkloadType { + READ_DOMINATED(90), + READ_WRITE(60), + WRITE_DOMINATED(10); + + public final int readOnlyOperationsRatio; + + private WorkloadType(int readOnlyOperationsRatio) { + this.readOnlyOperationsRatio = readOnlyOperationsRatio; + } + } + + /** + * Synchronization type. + */ + @Immutable + public enum SynchronizationType { + NONE, LOCK_COARSE, LOCK_MEDIUM, LOCK_FINE, STM; + } + + /** + * Command-line benchmark parameters. + */ + public static WorkloadType workloadType = WorkloadType.READ_DOMINATED; + public static SynchronizationType synchronizationType = SynchronizationType.LOCK_COARSE; + public static int numThreads = 1, + numSeconds = 10; + public static boolean longTraversalsEnabled = true, + structureModificationEnabled = true, + sequentialReplayEnabled = false; + + /** + * STM-specific command-line parameters. + * To be parsed by a given STM initializer. + */ + public static String[] stmCommandLineParameters = null; + + /** + * Parameters of the output TTC histograms. + */ + public static final int MAX_LOW_TTC = 999; + public static final int HIGH_TTC_ENTRIES = 200; + public static final double HIGH_TTC_LOG_BASE = 1.03; +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/Setup.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/Setup.java new file mode 100644 index 00000000..8646efb4 --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/Setup.java @@ -0,0 +1,95 @@ +package stmbench7; + +import stmbench7.annotations.Immutable; +import stmbench7.backend.BackendFactory; +import stmbench7.backend.Index; +import stmbench7.backend.LargeSet; +import stmbench7.core.AssemblyBuilder; +import stmbench7.core.AtomicPart; +import stmbench7.core.BaseAssembly; +import stmbench7.core.ComplexAssembly; +import stmbench7.core.CompositePart; +import stmbench7.core.CompositePartBuilder; +import stmbench7.core.Document; +import stmbench7.core.Module; +import stmbench7.core.ModuleBuilder; +import stmbench7.operations.SetupDataStructure; + +/** + * Sets up the benchmark structures according to given parameters, + * including indexes. + */ +@Immutable +public class Setup { + + protected Module module; + + protected Index atomicPartIdIndex; + protected Index> atomicPartBuildDateIndex; + protected Index documentTitleIndex; + protected Index compositePartIdIndex; + protected Index baseAssemblyIdIndex; + protected Index complexAssemblyIdIndex; + + protected CompositePartBuilder compositePartBuilder; + protected ModuleBuilder moduleBuilder; + + public Setup() throws InterruptedException { + BackendFactory backendFactory = BackendFactory.instance; + + atomicPartIdIndex = backendFactory.createIndex(); + atomicPartBuildDateIndex = backendFactory.>createIndex(); + documentTitleIndex = backendFactory.createIndex(); + compositePartIdIndex = backendFactory.createIndex(); + baseAssemblyIdIndex = backendFactory.createIndex(); + complexAssemblyIdIndex = backendFactory.createIndex(); + + compositePartBuilder = new CompositePartBuilder(compositePartIdIndex, + documentTitleIndex, atomicPartIdIndex, atomicPartBuildDateIndex); + moduleBuilder = new ModuleBuilder(baseAssemblyIdIndex, complexAssemblyIdIndex); + + SetupDataStructure setupOperation = new SetupDataStructure(this); + OperationExecutorFactory.executeSequentialOperation(setupOperation); + module = setupOperation.getModule(); + } + + public Index> getAtomicPartBuildDateIndex() { + return atomicPartBuildDateIndex; + } + + public Index getAtomicPartIdIndex() { + return atomicPartIdIndex; + } + + public Index getBaseAssemblyIdIndex() { + return baseAssemblyIdIndex; + } + + public Index getComplexAssemblyIdIndex() { + return complexAssemblyIdIndex; + } + + public Index getCompositePartIdIndex() { + return compositePartIdIndex; + } + + public Index getDocumentTitleIndex() { + return documentTitleIndex; + } + + public Module getModule() { + return module; + } + + public CompositePartBuilder getCompositePartBuilder() { + return compositePartBuilder; + } + + public ModuleBuilder getModuleBuilder() { + return moduleBuilder; + } + + public AssemblyBuilder getAssemblyBuilder() { + return moduleBuilder.getAssemblyBuilder(); + } +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/SynchMethodInitializer.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/SynchMethodInitializer.java new file mode 100644 index 00000000..f2aaed6e --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/SynchMethodInitializer.java @@ -0,0 +1,20 @@ +package stmbench7; + +import stmbench7.annotations.NonAtomic; +import stmbench7.backend.BackendFactory; +import stmbench7.core.DesignObjFactory; + +/** + * Creates factories suitable for a given synchonization method. + * Default implementations are provided for coarse-grained and + * medium-grained locking, as well as for single-threaded executions + * (i.e., without any thread synchronization). + */ +@NonAtomic +public interface SynchMethodInitializer { + + public DesignObjFactory createDesignObjFactory(); + public BackendFactory createBackendFactory(); + public OperationExecutorFactory createOperationExecutorFactory(); + public ThreadFactory createThreadFactory(); +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/ThreadFactory.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/ThreadFactory.java new file mode 100644 index 00000000..464f1729 --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/ThreadFactory.java @@ -0,0 +1,20 @@ +package stmbench7; + +import stmbench7.annotations.NonAtomic; + +/** + * In most cases, the factory will simply create a java.lang.Thread object using + * a given Runnable object. Some STMs, however, require that transactions are + * executed by threads of a specified class (descendant from java.lang.Thread). + */ +@NonAtomic +public abstract class ThreadFactory { + + public static ThreadFactory instance = null; + + public static void setInstance(ThreadFactory newInstance) { + instance = newInstance; + } + + public abstract Thread createThread(Runnable runnable); +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/ThreadRandom.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/ThreadRandom.java new file mode 100644 index 00000000..ca3bd12f --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/ThreadRandom.java @@ -0,0 +1,134 @@ +package stmbench7; + +import java.util.Random; + +import stmbench7.annotations.Immutable; +import stmbench7.core.RuntimeError; + +/** + * This is a central repository for thread-local random + * number generators. No other class should create an instance + * of class Random, but should use the methods in ThreadRandom + * instead. This way we can centrally control the (un)determinism + * of the benchmark and the implementation of a random number + * generator used. + */ +@Immutable +public class ThreadRandom { + + private static enum Phase { + INIT, + CONCURRENT, + SEQUENTIAL_REPLAY + } + + private static class CloneableRandom extends Random implements Cloneable { + public static final long serialVersionUID = 1L; + + public CloneableRandom(long seed) { + super(seed); + } + + @Override + public CloneableRandom clone() { + try { + return (CloneableRandom) super.clone(); + } + catch(CloneNotSupportedException e) { + throw new RuntimeException(e); + } + } + } + + private static class RandomState { + private CloneableRandom currentState, savedState; + + public RandomState() { + currentState = new CloneableRandom(3); + savedState = null; + } + + public void saveState() { + savedState = currentState.clone(); + } + + public void restoreState() { + currentState = savedState; + } + } + + private static Phase phase = Phase.INIT; + private static RandomState initRandom = new RandomState(); + private static short currentVirtualThreadNumber; + private static RandomState[] virtualRandom; + + private ThreadRandom() { } + + private static final ThreadLocal random = + new ThreadLocal() { + @Override + protected RandomState initialValue() { + return new RandomState(); + } + }; + + public static int nextInt(int n) { + int k = getCurrentRandom().currentState.nextInt(n); + //if(phase != Phase.INIT) + // System.out.println("int " + n + " = " + k + " " + getCurrentRandom().currentState); + return k; + } + + public static double nextDouble() { + double k = getCurrentRandom().currentState.nextDouble(); + //if(phase != Phase.INIT) + // System.out.println("double = " + k + " " + getCurrentRandom().currentState); + return k; + } + + public static void reset() { + if(phase != Phase.INIT) + throw new RuntimeError("Cannot reset ThreadRandom after the initialization phase"); + initRandom = new RandomState(); + } + + public static void startConcurrentPhase() { + phase = Phase.CONCURRENT; + } + + public static void startSequentialReplayPhase() { + phase = Phase.SEQUENTIAL_REPLAY; + virtualRandom = new RandomState[Parameters.numThreads]; + for(int n = 0; n < Parameters.numThreads; n++) + virtualRandom[n] = new RandomState(); + } + + public static void setVirtualThreadNumber(short threadNum) { + currentVirtualThreadNumber = threadNum; + } + + public static void saveState() { + getCurrentRandom().saveState(); + } + + public static void restoreState() { + getCurrentRandom().restoreState(); + } + + private static RandomState getCurrentRandom() { + /* + switch(phase) { + case INIT: return initRandom; + case CONCURRENT: return random.get(); + case SEQUENTIAL_REPLAY: return virtualRandom[currentVirtualThreadNumber]; + default: return null; + } + */ + switch(((Enum)phase).ordinal()) { + case 0: return initRandom; + case 1: return random.get(); + case 2: return virtualRandom[currentVirtualThreadNumber]; + default: return null; + } + } +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/annotations/Atomic.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/annotations/Atomic.java new file mode 100644 index 00000000..b84bfb79 --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/annotations/Atomic.java @@ -0,0 +1,17 @@ +package stmbench7.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Annotates objects that are used by transactions and thus should + * be atomic. + */ +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +@Inherited +public @interface Atomic { +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/annotations/ContainedInAtomic.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/annotations/ContainedInAtomic.java new file mode 100644 index 00000000..c3736424 --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/annotations/ContainedInAtomic.java @@ -0,0 +1,17 @@ +package stmbench7.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Annotates objects that are fully contained in an atomic object, + * and so do not have to be synchronized separately. + */ +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +@Inherited +public @interface ContainedInAtomic { +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/annotations/Immutable.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/annotations/Immutable.java new file mode 100644 index 00000000..5870f023 --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/annotations/Immutable.java @@ -0,0 +1,18 @@ +package stmbench7.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Annotates objects that never change after they are created. + * These can be used inside transactions, but are usually safe + * without any additional synchronization. + */ +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +@Inherited +public @interface Immutable { +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/annotations/NonAtomic.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/annotations/NonAtomic.java new file mode 100644 index 00000000..b6cbd9d1 --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/annotations/NonAtomic.java @@ -0,0 +1,17 @@ +package stmbench7.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Annotates objects that are never (and must never) be used inside + * transactions. + */ +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +@Inherited +public @interface NonAtomic { +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/annotations/ReadOnly.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/annotations/ReadOnly.java new file mode 100644 index 00000000..96126629 --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/annotations/ReadOnly.java @@ -0,0 +1,14 @@ +package stmbench7.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Annotates methods and transactions that are read-only. + */ +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +public @interface ReadOnly { +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/annotations/ThreadLocal.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/annotations/ThreadLocal.java new file mode 100644 index 00000000..ee717d3d --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/annotations/ThreadLocal.java @@ -0,0 +1,17 @@ +package stmbench7.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Annotates objects that are always used locally by + * each thread, and so do not have to be thread-safe. + */ +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +@Inherited +public @interface ThreadLocal { +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/annotations/Transactional.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/annotations/Transactional.java new file mode 100644 index 00000000..96abd9f7 --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/annotations/Transactional.java @@ -0,0 +1,14 @@ +package stmbench7.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Annotates methods that should be always executed as transactions. + */ +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +public @interface Transactional { +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/annotations/Update.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/annotations/Update.java new file mode 100644 index 00000000..a3a5e32d --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/annotations/Update.java @@ -0,0 +1,14 @@ +package stmbench7.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Annotates methods and transactions that are not read-only. + */ +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +public @interface Update { +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/backend/BackendFactory.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/backend/BackendFactory.java new file mode 100644 index 00000000..1292d5e2 --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/backend/BackendFactory.java @@ -0,0 +1,21 @@ +package stmbench7.backend; + +import stmbench7.annotations.Immutable; + +/** + * Creates the structures of the benchmark backend: indexes, + * id pools, and large sets. + */ +@Immutable +public abstract class BackendFactory { + + public static BackendFactory instance = null; + + public static void setInstance(BackendFactory newInstance) { + instance = newInstance; + } + + public abstract > LargeSet createLargeSet(); + public abstract , V> Index createIndex(); + public abstract IdPool createIdPool(int maxNumberOfIds); +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/backend/IdPool.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/backend/IdPool.java new file mode 100644 index 00000000..5be3aa7e --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/backend/IdPool.java @@ -0,0 +1,22 @@ +package stmbench7.backend; + +import stmbench7.annotations.Atomic; +import stmbench7.annotations.Update; +import stmbench7.core.OperationFailedException; + +/** + * Implements a pool of ids of various objects of the data structure. + * Necessary to ensure that no two objects of the same type and with + * the same id are created by different threads, and that the data + * structure does not grow beyond the limits defined in the Parameters + * class. + */ +@Atomic +public interface IdPool { + + @Update + public abstract int getId() throws OperationFailedException; + + @Update + public abstract void putUnusedId(int id); +} \ No newline at end of file diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/backend/ImmutableCollection.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/backend/ImmutableCollection.java new file mode 100644 index 00000000..996af431 --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/backend/ImmutableCollection.java @@ -0,0 +1,14 @@ +package stmbench7.backend; + +import stmbench7.annotations.Immutable; + +/** + * Represents a read-only view of a collection of elements. + */ +@Immutable +public interface ImmutableCollection extends Iterable { + + int size(); + boolean contains(E element); // not necessarily efficient! + public ImmutableCollection clone(); +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/backend/Index.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/backend/Index.java new file mode 100644 index 00000000..1ae3abcf --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/backend/Index.java @@ -0,0 +1,31 @@ +package stmbench7.backend; + +import stmbench7.annotations.Atomic; +import stmbench7.annotations.ReadOnly; +import stmbench7.annotations.Update; + +/** + * The interface of the core part of the "backbone" of the STMBench7 benchmark -- + * indexes used by many of the benchmark operations. + */ +@Atomic +public interface Index,V> extends Iterable { + + @ReadOnly + V get(K key); + + @Update + void put(K key, V value); + + @Update + V putIfAbsent(K key, V value); + + @Update + boolean remove(K key); + + @ReadOnly + public Iterable getRange(K minKey, K maxKey); + + @ReadOnly + public Iterable getKeys(); +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/backend/LargeSet.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/backend/LargeSet.java new file mode 100644 index 00000000..33548e4a --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/backend/LargeSet.java @@ -0,0 +1,28 @@ +package stmbench7.backend; + +import stmbench7.annotations.Atomic; +import stmbench7.annotations.ReadOnly; +import stmbench7.annotations.Update; + +/** + * A large set: of the size in the order of at least + * a few hundreds of elements. Used by a composite part + * to hold the set of child atomic parts, and by the + * AtomicPart.buildDate index to hold all atomic parts + * with the same build date. + */ +@Atomic +public interface LargeSet> extends Iterable { + + @Update + boolean add(E element); + + @Update + boolean remove(E element); + + @ReadOnly + boolean contains(E element); + + @ReadOnly + int size(); +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/Assembly.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/Assembly.java new file mode 100644 index 00000000..7304e223 --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/Assembly.java @@ -0,0 +1,22 @@ +package stmbench7.core; + +import stmbench7.annotations.Atomic; +import stmbench7.annotations.ReadOnly; +import stmbench7.annotations.Update; + +/** + * Part of the main benchmark data structure. For a default + * implementation, see stmbench7.impl.core.AssemblyImpl. + */ +@Atomic +public interface Assembly extends DesignObj { + + @ReadOnly + ComplexAssembly getSuperAssembly(); + + @ReadOnly + Module getModule(); + + @Update + void clearPointers(); +} \ No newline at end of file diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/AssemblyBuilder.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/AssemblyBuilder.java new file mode 100644 index 00000000..1562c31b --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/AssemblyBuilder.java @@ -0,0 +1,121 @@ +package stmbench7.core; + +import stmbench7.Parameters; +import stmbench7.annotations.Immutable; +import stmbench7.backend.BackendFactory; +import stmbench7.backend.IdPool; +import stmbench7.backend.ImmutableCollection; +import stmbench7.backend.Index; + +/** + * Used to create and destroy assembly elements while + * maintaining the consistency of the data structure + * and the indexes. + */ +@Immutable +public class AssemblyBuilder extends DesignObjBuilder { + + private final IdPool baseAssemblyIdPool, complexAssemblyIdPool; + + private final Index baseAssemblyIdIndex; + private final Index complexAssemblyIdIndex; + + public AssemblyBuilder(Index baseAssemblyIdIndex, + Index complexAssemblyIdIndex) { + this.baseAssemblyIdIndex = baseAssemblyIdIndex; + baseAssemblyIdPool = BackendFactory.instance.createIdPool(Parameters.MaxBaseAssemblies); + + this.complexAssemblyIdIndex = complexAssemblyIdIndex; + complexAssemblyIdPool = BackendFactory.instance.createIdPool(Parameters.MaxComplexAssemblies); + } + + public Assembly createAndRegisterAssembly(Module module, ComplexAssembly superAssembly) + throws OperationFailedException { + if( (superAssembly == null) || (superAssembly.getLevel() > 2) ) + return createAndRegisterComplexAssembly(module, superAssembly); + + return createAndRegisterBaseAssembly(module, superAssembly); + } + + public void unregisterAndRecycleAssembly(Assembly assembly) { + if(assembly instanceof ComplexAssembly) + unregisterAndRecycleComplexAssembly((ComplexAssembly)assembly); + else unregisterAndRecycleBaseAssembly((BaseAssembly)assembly); + } + + public void unregisterAndRecycleBaseAssembly(BaseAssembly baseAssembly) { + int baseAssemblyId = baseAssembly.getId(); + baseAssemblyIdIndex.remove(baseAssemblyId); + + baseAssembly.getSuperAssembly().removeSubAssembly(baseAssembly); + + ImmutableCollection componentsSet = baseAssembly.getComponents().clone(); + for(CompositePart component : componentsSet) + baseAssembly.removeComponent(component); + + baseAssembly.clearPointers(); + baseAssemblyIdPool.putUnusedId(baseAssemblyId); + } + + public void unregisterAndRecycleComplexAssembly(ComplexAssembly complexAssembly) { + short currentLevel = complexAssembly.getLevel(); + ComplexAssembly superAssembly = complexAssembly.getSuperAssembly(); + + if(superAssembly == null) + throw new RuntimeError("ComplexAssemblyFactory: root Complex Assembly cannot be removed!"); + + superAssembly.removeSubAssembly(complexAssembly); + + ImmutableCollection subAssembliesSet = complexAssembly.getSubAssemblies().clone(); + for(Assembly assembly : subAssembliesSet) { + if(currentLevel > 2) unregisterAndRecycleComplexAssembly((ComplexAssembly)assembly); + else unregisterAndRecycleBaseAssembly((BaseAssembly)assembly); + } + + int id = complexAssembly.getId(); + complexAssemblyIdIndex.remove(id); + + complexAssembly.clearPointers(); + complexAssemblyIdPool.putUnusedId(id); + } + + private BaseAssembly createAndRegisterBaseAssembly(Module module, ComplexAssembly superAssembly) + throws OperationFailedException { + int date = createBuildDate(Parameters.MinAssmDate, Parameters.MaxAssmDate); + int assemblyId = baseAssemblyIdPool.getId(); + BaseAssembly baseAssembly = + designObjFactory.createBaseAssembly(assemblyId, createType(), date, module, superAssembly); + + baseAssemblyIdIndex.put(assemblyId, baseAssembly); + + superAssembly.addSubAssembly(baseAssembly); + + return baseAssembly; + } + + private ComplexAssembly createAndRegisterComplexAssembly(Module module, ComplexAssembly superAssembly) + throws OperationFailedException { + int id = complexAssemblyIdPool.getId(); + int date = createBuildDate(Parameters.MinAssmDate, Parameters.MaxAssmDate); + ComplexAssembly complexAssembly = + designObjFactory.createComplexAssembly(id, createType(), date, module, superAssembly); + + try { + for(int i = 0; i < Parameters.NumAssmPerAssm; i++) + createAndRegisterAssembly(module, complexAssembly); + } + catch(OperationFailedException e) { + for(Assembly subAssembly : complexAssembly.getSubAssemblies().clone()) + unregisterAndRecycleAssembly(subAssembly); + complexAssemblyIdPool.putUnusedId(id); + complexAssembly.clearPointers(); + throw e; + } + + complexAssemblyIdIndex.put(id, complexAssembly); + + if(superAssembly != null) superAssembly.addSubAssembly(complexAssembly); + + return complexAssembly; + } +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/AtomicPart.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/AtomicPart.java new file mode 100644 index 00000000..206997a5 --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/AtomicPart.java @@ -0,0 +1,47 @@ +package stmbench7.core; + +import stmbench7.annotations.Atomic; +import stmbench7.annotations.ReadOnly; +import stmbench7.annotations.Update; +import stmbench7.backend.ImmutableCollection; + +/** + * Part of the main benchmark data structure. For a default + * implementation, see stmbench7.impl.core.AtomicPartImpl. + */ +@Atomic +public interface AtomicPart extends DesignObj, Comparable { + + @Update + void connectTo(AtomicPart destination, String type, int length); + + @Update + void addConnectionFromOtherPart(Connection connection); + + @Update + void setCompositePart(CompositePart partOf); + + @ReadOnly + int getNumToConnections(); + + @ReadOnly + ImmutableCollection getToConnections(); + + @ReadOnly + ImmutableCollection getFromConnections(); + + @ReadOnly + CompositePart getPartOf(); + + @Update + void swapXY(); + + @ReadOnly + int getX(); + + @ReadOnly + int getY(); + + @Update + void clearPointers(); +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/AtomicPartBuilder.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/AtomicPartBuilder.java new file mode 100644 index 00000000..2c5c16de --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/AtomicPartBuilder.java @@ -0,0 +1,57 @@ +package stmbench7.core; + +import stmbench7.Parameters; +import stmbench7.ThreadRandom; +import stmbench7.annotations.Immutable; +import stmbench7.backend.BackendFactory; +import stmbench7.backend.IdPool; +import stmbench7.backend.Index; +import stmbench7.backend.LargeSet; +import stmbench7.operations.BaseOperation; + +/** + * Used to create and destroy atomic parts while + * maintaining the consistency of the data structure + * and the indexes. + */ +@Immutable +public class AtomicPartBuilder extends DesignObjBuilder { + + private final IdPool idPool; + + private final Index partIdIndex; + private final Index> partBuildDateIndex; + + public AtomicPartBuilder(Index partIdIndex, + Index> partBuildDateIndex) { + + this.partIdIndex = partIdIndex; + this.partBuildDateIndex = partBuildDateIndex; + idPool = BackendFactory.instance.createIdPool(Parameters.MaxAtomicParts); + } + + public AtomicPart createAndRegisterAtomicPart() throws OperationFailedException{ + int id = idPool.getId(); + String type = createType(); + int buildDate = createBuildDate(Parameters.MinAtomicDate, Parameters.MaxAtomicDate); + int x = ThreadRandom.nextInt(Parameters.XYRange), + y = x + 1; // convenient for invariant tests + + AtomicPart part = designObjFactory.createAtomicPart(id, type, buildDate, x, y); + + partIdIndex.put(id, part); + BaseOperation.addAtomicPartToBuildDateIndex(partBuildDateIndex, part); + + return part; + } + + public void unregisterAndRecycleAtomicPart(AtomicPart part) { + int partId = part.getId(); + + BaseOperation.removeAtomicPartFromBuildDateIndex(partBuildDateIndex, part); + partIdIndex.remove(partId); + part.clearPointers(); + + idPool.putUnusedId(partId); + } +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/BaseAssembly.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/BaseAssembly.java new file mode 100644 index 00000000..91cdab64 --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/BaseAssembly.java @@ -0,0 +1,23 @@ +package stmbench7.core; + +import stmbench7.annotations.Atomic; +import stmbench7.annotations.ReadOnly; +import stmbench7.annotations.Update; +import stmbench7.backend.ImmutableCollection; + +/** + * Part of the main benchmark data structure. For a default + * implementation, see stmbench7.impl.core.BaseAssemblyImpl. + */ +@Atomic +public interface BaseAssembly extends Assembly { + + @Update + void addComponent(CompositePart component); + + @Update + boolean removeComponent(CompositePart component); + + @ReadOnly + ImmutableCollection getComponents(); +} \ No newline at end of file diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/ComplexAssembly.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/ComplexAssembly.java new file mode 100644 index 00000000..05e04baa --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/ComplexAssembly.java @@ -0,0 +1,26 @@ +package stmbench7.core; + +import stmbench7.annotations.Atomic; +import stmbench7.annotations.ReadOnly; +import stmbench7.annotations.Update; +import stmbench7.backend.ImmutableCollection; + +/** + * Part of the main benchmark data structure. For a default + * implementation, see stmbench7.impl.core.ComplexAssemblyImpl. + */ +@Atomic +public interface ComplexAssembly extends Assembly { + + @Update + boolean addSubAssembly(Assembly assembly); + + @Update + boolean removeSubAssembly(Assembly assembly); + + @ReadOnly + ImmutableCollection getSubAssemblies(); + + @ReadOnly + short getLevel(); +} \ No newline at end of file diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/CompositePart.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/CompositePart.java new file mode 100644 index 00000000..b18227af --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/CompositePart.java @@ -0,0 +1,42 @@ +package stmbench7.core; + +import stmbench7.annotations.Atomic; +import stmbench7.annotations.ReadOnly; +import stmbench7.annotations.Update; +import stmbench7.backend.ImmutableCollection; +import stmbench7.backend.LargeSet; + +/** + * Part of the main benchmark data structure. For a default + * implementation, see stmbench7.impl.core.CompositePartImpl. + */ +@Atomic +public interface CompositePart extends DesignObj { + + @Update + void addAssembly(BaseAssembly assembly); + + @Update + boolean addPart(AtomicPart part); + + @Update + void setRootPart(AtomicPart part); + + @ReadOnly + AtomicPart getRootPart(); + + @ReadOnly + Document getDocumentation(); + + @ReadOnly + LargeSet getParts(); + + @Update + void removeAssembly(BaseAssembly assembly); + + @ReadOnly + ImmutableCollection getUsedIn(); + + @Update + void clearPointers(); +} \ No newline at end of file diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/CompositePartBuilder.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/CompositePartBuilder.java new file mode 100644 index 00000000..e8e5c613 --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/CompositePartBuilder.java @@ -0,0 +1,131 @@ +package stmbench7.core; + +import stmbench7.Parameters; +import stmbench7.ThreadRandom; +import stmbench7.annotations.Immutable; +import stmbench7.backend.BackendFactory; +import stmbench7.backend.IdPool; +import stmbench7.backend.ImmutableCollection; +import stmbench7.backend.Index; +import stmbench7.backend.LargeSet; + +/** + * Used to create and destroy composite parts while + * maintaining the consistency of the data structure + * and the indexes. + */ +@Immutable +public class CompositePartBuilder extends DesignObjBuilder { + + private final IdPool idPool; + + private final Index compositePartIdIndex; + private final DocumentBuilder documentBuilder; + private final AtomicPartBuilder atomicPartBuilder; + + public CompositePartBuilder(Index compositePartIdIndex, + Index documentTitleIndex, + Index partIdIndex, + Index> partBuildDateIndex) { + + this.compositePartIdIndex = compositePartIdIndex; + documentBuilder = new DocumentBuilder(documentTitleIndex); + atomicPartBuilder = new AtomicPartBuilder(partIdIndex, partBuildDateIndex); + idPool = BackendFactory.instance.createIdPool(Parameters.MaxCompParts); + } + + /** + * Creates a component (composite part) with the documentation and + * a graph of atomic parts and updates all the relevant indexes. + */ + public CompositePart createAndRegisterCompositePart() throws OperationFailedException { + int id = idPool.getId(); + String type = createType(); + + int buildDate; + if(ThreadRandom.nextInt(100) < Parameters.YoungCompFrac) + buildDate = createBuildDate(Parameters.MinYoungCompDate, Parameters.MaxYoungCompDate); + else + buildDate = createBuildDate(Parameters.MinOldCompDate, Parameters.MaxOldCompDate); + + Document documentation = null; + AtomicPart parts[] = new AtomicPart[Parameters.NumAtomicPerComp]; + + try { + documentation = documentBuilder.createAndRegisterDocument(id); + createAtomicParts(parts); + } + catch(OperationFailedException e) { + if(documentation != null) documentBuilder.unregisterAndRecycleDocument(documentation); + for(AtomicPart part : parts) + if(part != null) atomicPartBuilder.unregisterAndRecycleAtomicPart(part); + idPool.putUnusedId(id); + throw e; + } + + createConnections(parts); + + CompositePart component = designObjFactory.createCompositePart(id, type, buildDate, documentation); + for(AtomicPart part : parts) component.addPart(part); + + compositePartIdIndex.put(id, component); + + return component; + } + + public void unregisterAndRecycleCompositePart(CompositePart compositePart) { + int id = compositePart.getId(); + compositePartIdIndex.remove(id); + + documentBuilder.unregisterAndRecycleDocument(compositePart.getDocumentation()); + + for(AtomicPart atomicPart : compositePart.getParts()) + atomicPartBuilder.unregisterAndRecycleAtomicPart(atomicPart); + + ImmutableCollection usedInList = compositePart.getUsedIn().clone(); + for(BaseAssembly ownerAssembly : usedInList) { + while(ownerAssembly.removeComponent(compositePart)); + } + + compositePart.clearPointers(); + idPool.putUnusedId(id); + } + + /** + * Create all atomic parts of a given composite part. + */ + private void createAtomicParts(AtomicPart[] parts) throws OperationFailedException { + + for(int partNum = 0; partNum < Parameters.NumAtomicPerComp; partNum++) { + AtomicPart part = atomicPartBuilder.createAndRegisterAtomicPart(); + parts[partNum] = part; + } + } + + /** + * Create connections between the parts. + */ + private void createConnections(AtomicPart[] parts) { + + // First, make all atomic parts be connected in a ring + // (so that the resulting graph is fully connected) + for(int partNum = 0; partNum < Parameters.NumAtomicPerComp; partNum++) { + int connectTo = (partNum + 1) % Parameters.NumAtomicPerComp; + parts[partNum].connectTo(parts[connectTo], createType(), + ThreadRandom.nextInt(Parameters.XYRange) + 1); + } + + // Then add other connections randomly, taking into account + // the NumConnPerAtomic parameter. The procedure is non-deterministic + // but it should eventually terminate. + for(int partNum = 0; partNum < Parameters.NumAtomicPerComp; partNum++) { + AtomicPart currentPart = parts[partNum]; + + while(currentPart.getNumToConnections() < Parameters.NumConnPerAtomic) { + int connectTo = ThreadRandom.nextInt(Parameters.NumAtomicPerComp); + parts[partNum].connectTo(parts[connectTo], createType(), + ThreadRandom.nextInt(Parameters.XYRange) + 1); + } + } + } +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/Connection.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/Connection.java new file mode 100644 index 00000000..ba758fe1 --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/Connection.java @@ -0,0 +1,17 @@ +package stmbench7.core; + +import stmbench7.annotations.Immutable; + +/** + * Part of the main benchmark data structure. For a default + * implementation, see stmbench7.impl.core.ConnectionImpl. + */ +@Immutable +public interface Connection { + + Connection getReversed(); + AtomicPart getDestination(); + AtomicPart getSource(); + String getType(); + int getLength(); +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/DesignObj.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/DesignObj.java new file mode 100644 index 00000000..a62f201b --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/DesignObj.java @@ -0,0 +1,28 @@ +package stmbench7.core; + +import stmbench7.annotations.Atomic; +import stmbench7.annotations.ReadOnly; +import stmbench7.annotations.Update; + +/** + * A class from which most parts of the main benchmark data structure descend. + * For a default implementation, see stmbench7.impl.core.DesignObjImpl. + */ +@Atomic +public interface DesignObj { + + @ReadOnly + int getId(); + + @ReadOnly + int getBuildDate(); + + @ReadOnly + String getType(); + + @Update + void updateBuildDate(); + + @ReadOnly + void nullOperation(); +} \ No newline at end of file diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/DesignObjBuilder.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/DesignObjBuilder.java new file mode 100644 index 00000000..2168f9c0 --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/DesignObjBuilder.java @@ -0,0 +1,38 @@ +package stmbench7.core; + +import stmbench7.Parameters; +import stmbench7.ThreadRandom; +import stmbench7.annotations.Immutable; + +/** + * Methods for constructing common attributes of objects implementing parts of + * the data structure. + */ +@Immutable +public abstract class DesignObjBuilder { + + protected final DesignObjFactory designObjFactory = DesignObjFactory.instance; + + protected String createType() { + String type = "type #" + ThreadRandom.nextInt(Parameters.NumTypes); + return type; + } + + protected int createBuildDate(int minBuildDate, int maxBuildDate) { + return minBuildDate + + ThreadRandom.nextInt(maxBuildDate - minBuildDate + 1); + } + + protected String createText(int textSize, String textPattern) { + int patternSize = textPattern.length(); + int size = 0; + StringBuilder stringBuilder = new StringBuilder(textSize); + + while (size + patternSize <= textSize) { + stringBuilder.append(textPattern); + size += patternSize; + } + + return stringBuilder.toString(); + } +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/DesignObjFactory.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/DesignObjFactory.java new file mode 100644 index 00000000..ee6e7898 --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/DesignObjFactory.java @@ -0,0 +1,33 @@ +package stmbench7.core; + +import stmbench7.annotations.Immutable; + +/** + * A factory for creating all the objects of the main benchmark + * data structure. A default implementation is provided by the + * stmbench7.impl.core.DesignObjFactoryImpl class, but most STM + * implementations will provide their own implementation, which + * will create transaction-safe versions of the data structure + * elements. + */ +@Immutable +public abstract class DesignObjFactory { + + public static DesignObjFactory instance = null; + + public static void setInstance(DesignObjFactory newInstance) { + instance = newInstance; + } + + public abstract AtomicPart createAtomicPart(int id, String type, int buildDate, int x, int y); + public abstract Connection createConnection(AtomicPart from, AtomicPart to, String type, int length); + public abstract BaseAssembly createBaseAssembly(int id, String type, int buildDate, + Module module, ComplexAssembly superAssembly); + public abstract ComplexAssembly createComplexAssembly(int id, String type, int buildDate, + Module module, ComplexAssembly superAssembly); + public abstract CompositePart createCompositePart(int id, String type, int buildDate, + Document documentation); + public abstract Document createDocument(int id, String title, String text); + public abstract Manual createManual(int id, String title, String text); + public abstract Module createModule(int id, String type, int buildDate, Manual man); +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/Document.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/Document.java new file mode 100644 index 00000000..ed925051 --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/Document.java @@ -0,0 +1,40 @@ +package stmbench7.core; + +import stmbench7.annotations.Atomic; +import stmbench7.annotations.ReadOnly; +import stmbench7.annotations.Update; + +/** + * Part of the main benchmark data structure. For a default + * implementation, see stmbench7.impl.core.DocumentImpl. + */ +@Atomic +public interface Document { + + @Update + void setPart(CompositePart part); + + @ReadOnly + CompositePart getCompositePart(); + + @ReadOnly + int getDocumentId(); + + @ReadOnly + String getTitle(); + + @ReadOnly + void nullOperation(); + + @ReadOnly + int searchText(char symbol); + + @Update + int replaceText(String from, String to); + + @ReadOnly + boolean textBeginsWith(String prefix); + + @ReadOnly + String getText(); +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/DocumentBuilder.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/DocumentBuilder.java new file mode 100644 index 00000000..6c815a8e --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/DocumentBuilder.java @@ -0,0 +1,42 @@ +package stmbench7.core; + +import stmbench7.Parameters; +import stmbench7.annotations.Immutable; +import stmbench7.backend.BackendFactory; +import stmbench7.backend.IdPool; +import stmbench7.backend.Index; + +/** + * Used to create and destroy document elements while + * maintaining the consistency of the data structure + * and the indexes. + */ +@Immutable +public class DocumentBuilder extends DesignObjBuilder { + + private final IdPool idPool; + private final Index documentTitleIndex; + + public DocumentBuilder(Index documentTitleIndex) { + this.documentTitleIndex = documentTitleIndex; + idPool = BackendFactory.instance.createIdPool(Parameters.MaxCompParts); + } + + public Document createAndRegisterDocument(int compositePartId) throws OperationFailedException { + int docId = idPool.getId(); + String docTitle = "Composite Part #" + compositePartId; + String docText = createText(Parameters.DocumentSize, + "I am the documentation for composite part #" + compositePartId + "\n"); + + Document documentation = designObjFactory.createDocument(docId, docTitle, docText); + documentTitleIndex.put(docTitle, documentation); + + return documentation; + } + + public void unregisterAndRecycleDocument(Document document) { + document.setPart(null); + documentTitleIndex.remove(document.getTitle()); + idPool.putUnusedId(document.getDocumentId()); + } +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/Manual.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/Manual.java new file mode 100644 index 00000000..ef6e9fac --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/Manual.java @@ -0,0 +1,40 @@ +package stmbench7.core; + +import stmbench7.annotations.Atomic; +import stmbench7.annotations.ReadOnly; +import stmbench7.annotations.Update; + +/** + * Part of the main benchmark data structure. For a default + * implementation, see stmbench7.impl.core.ManualImpl. + */ +@Atomic +public interface Manual { + + @ReadOnly + int getId(); + + @ReadOnly + String getTitle(); + + @ReadOnly + String getText(); + + @ReadOnly + Module getModule(); + + @Update + void setModule(Module module); + + @ReadOnly + int countOccurences(char ch); + + @ReadOnly + int checkFirstLastCharTheSame(); + + @ReadOnly + boolean startsWith(char ch); + + @Update + int replaceChar(char from, char to); +} \ No newline at end of file diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/ManualBuilder.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/ManualBuilder.java new file mode 100644 index 00000000..897d946f --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/ManualBuilder.java @@ -0,0 +1,28 @@ +package stmbench7.core; + +import stmbench7.Parameters; +import stmbench7.annotations.Immutable; +import stmbench7.backend.BackendFactory; +import stmbench7.backend.IdPool; + +/** + * Used to create a manual element that conforms to the + * benchmark specification. + */ +@Immutable +public class ManualBuilder extends DesignObjBuilder { + + private final IdPool idPool; + + public ManualBuilder() { + idPool = BackendFactory.instance.createIdPool(Parameters.NumModules); + } + + public Manual createManual(int moduleId) throws OperationFailedException { + int manualId = idPool.getId(); + String title = "Manual for module #" + moduleId; + String text = createText(Parameters.ManualSize, "I am the manual for module #" + moduleId + "\n"); + + return designObjFactory.createManual(manualId, title, text); + } +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/Module.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/Module.java new file mode 100644 index 00000000..9d4212b4 --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/Module.java @@ -0,0 +1,22 @@ +package stmbench7.core; + +import stmbench7.annotations.Atomic; +import stmbench7.annotations.ReadOnly; +import stmbench7.annotations.Update; + +/** + * Root of the benchmark main data structure. For a default + * implementation, see stmbench7.impl.core.ModuleImpl. + */ +@Atomic +public interface Module extends DesignObj { + + @Update + void setDesignRoot(ComplexAssembly designRoot); + + @ReadOnly + ComplexAssembly getDesignRoot(); + + @ReadOnly + Manual getManual(); +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/ModuleBuilder.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/ModuleBuilder.java new file mode 100644 index 00000000..d858b016 --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/ModuleBuilder.java @@ -0,0 +1,46 @@ +package stmbench7.core; + +import stmbench7.Parameters; +import stmbench7.annotations.Immutable; +import stmbench7.backend.BackendFactory; +import stmbench7.backend.IdPool; +import stmbench7.backend.Index; + +/** + * Used to create a module element with the default initial + * data structure underneath. Calls other builder classes + * to construct respective elements of the structure. + */ +@Immutable +public class ModuleBuilder extends DesignObjBuilder { + + private final IdPool idPool; + private final ManualBuilder manualFactory; + private final AssemblyBuilder assemblyBuilder; + + public ModuleBuilder(Index baseAssemblyIdIndex, + Index complexAssemblyIdIndex) { + manualFactory = new ManualBuilder(); + assemblyBuilder = new AssemblyBuilder(baseAssemblyIdIndex, + complexAssemblyIdIndex); + idPool = BackendFactory.instance.createIdPool(Parameters.NumModules); + } + + public Module createRegisterModule() throws OperationFailedException { + int moduleId = idPool.getId(); + Manual manual = manualFactory.createManual(moduleId); + String type = createType(); + int buildDate = createBuildDate(Parameters.MinModuleDate, Parameters.MaxModuleDate); + + Module module = designObjFactory.createModule(moduleId, type, buildDate, manual); + + ComplexAssembly designRoot = (ComplexAssembly) assemblyBuilder.createAndRegisterAssembly(module, null); + module.setDesignRoot(designRoot); + + return module; + } + + public AssemblyBuilder getAssemblyBuilder() { + return assemblyBuilder; + } +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/Operation.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/Operation.java new file mode 100644 index 00000000..4f5a6ddb --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/Operation.java @@ -0,0 +1,23 @@ +package stmbench7.core; + +import stmbench7.OperationId; +import stmbench7.annotations.ReadOnly; +import stmbench7.annotations.ThreadLocal; +import stmbench7.annotations.Transactional; + +/** + * Interface of a single operation (query, traversal + * or structural modification) of the STMBench7 benchmark. + * Each operation is instantiated separately by each + * thread, so the fields in a class implementing Operation + * can be considered thread-local. + */ +@ThreadLocal +public interface Operation { + + @Transactional + public int performOperation() throws OperationFailedException; + + @ReadOnly + public OperationId getOperationId(); +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/OperationFailedException.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/OperationFailedException.java new file mode 100644 index 00000000..0bd230da --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/OperationFailedException.java @@ -0,0 +1,31 @@ +package stmbench7.core; + +import stmbench7.annotations.Immutable; +import stmbench7.annotations.ThreadLocal; + +/** + * STMBench7 benchmark specific exception. Indicates that a benchmark operation + * failed. Note that operation failures are unavoidable in the benchmark: their + * number is indicated in the results shown at the end of the benchmark. + */ +@Immutable +@ThreadLocal +public class OperationFailedException extends Exception { + + private static final long serialVersionUID = -4829600105999291994L; + + public OperationFailedException(String message, Object reportingObject) { + super(message + " [" + reportingObject.toString() + "]"); + } + + public OperationFailedException(String message) { + super(message); + } + + public OperationFailedException(String message, Throwable cause) { + super(message, cause); + } + + public OperationFailedException() { + } +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/RuntimeError.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/RuntimeError.java new file mode 100644 index 00000000..7a1c89f8 --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/RuntimeError.java @@ -0,0 +1,31 @@ +package stmbench7.core; + +import stmbench7.annotations.Immutable; +import stmbench7.annotations.ThreadLocal; + +/** + * STMBench7 specific error. Indicates a serious problem, i.e., a violation of + * the data structure invariants, which causes the benchmark to terminate. + */ +@Immutable +@ThreadLocal +public class RuntimeError extends Error { + + private static final long serialVersionUID = -5671909838938354776L; + + public RuntimeError() { + } + + public RuntimeError(String message) { + super(message); + } + + public RuntimeError(Throwable cause) { + super(cause); + } + + public RuntimeError(String message, Throwable cause) { + super(message, cause); + } + +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/correctness/invariants/AssemblyTest.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/correctness/invariants/AssemblyTest.java new file mode 100644 index 00000000..3a1482e4 --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/correctness/invariants/AssemblyTest.java @@ -0,0 +1,31 @@ +package stmbench7.correctness.invariants; + +import stmbench7.Parameters; +import stmbench7.annotations.Immutable; +import stmbench7.annotations.ThreadLocal; +import stmbench7.core.Assembly; +import stmbench7.core.ComplexAssembly; +import stmbench7.core.Module; + +/** + * Test of invariants of an assembly. + */ +@Immutable +@ThreadLocal +public class AssemblyTest extends InvariantTest { + + public static void checkInvariants(Assembly assembly, boolean initial, int maxId, + ComplexAssembly parentAssembly, Module module) { + + DesignObjTest.checkInvariants(assembly, initial, maxId, Parameters.MinAssmDate, Parameters.MaxAssmDate); + + int id = assembly.getId(); + + if(assembly.getSuperAssembly() != parentAssembly) + reportError(assembly, id, "invalid reference to the parent ComplexAssembly"); + + if(assembly.getModule() != module) + reportError(assembly, id, "invalid reference to the parent Module"); + } + +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/correctness/invariants/AtomicPartTest.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/correctness/invariants/AtomicPartTest.java new file mode 100644 index 00000000..0173cd85 --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/correctness/invariants/AtomicPartTest.java @@ -0,0 +1,59 @@ +package stmbench7.correctness.invariants; + +import java.util.TreeSet; + +import stmbench7.Parameters; +import stmbench7.annotations.Immutable; +import stmbench7.annotations.ThreadLocal; +import stmbench7.backend.ImmutableCollection; +import stmbench7.core.AtomicPart; +import stmbench7.core.CompositePart; +import stmbench7.core.Connection; + +/** + * Test of invariants of an atomic part. + */ +@Immutable +@ThreadLocal +public class AtomicPartTest extends InvariantTest { + + public static void checkInvariants(AtomicPart part, boolean initial, CompositePart component, + TreeSet allParts, TraversedObjects traversedObjects) { + + traversedObjects.atomicParts.add(part); + + DesignObjTest.checkInvariants(part, initial, Parameters.MaxAtomicParts, + Parameters.MinAtomicDate, Parameters.MaxAtomicDate); + + int id = part.getId(), x = part.getX(), y = part.getY(); + if(Math.abs(x - y) != 1) + reportError(part, id, "inconsistent x and y attributes: x = " + x + ", y = " + y); + + if(part.getPartOf() != component) + reportError(part, id, "invalid reference to CompositePart parent"); + + ImmutableCollection to = part.getToConnections(), from = part.getFromConnections(); + if(to.size() != Parameters.NumConnPerAtomic) + reportError(part, id, "to", Parameters.NumConnPerAtomic, to.size()); + + for(Connection connection : from) { + ConnectionTest.checkInvariants(connection, part); + + ImmutableCollection sourceToSet = connection.getSource().getToConnections(); + boolean foundMyself = false; + for(Connection outConn : sourceToSet) + if(outConn.getSource() == part) { + foundMyself = true; + break; + } + if(! foundMyself) + reportError(part, id, "inconsistent 'from' set"); + } + + for(Connection connection : to) { + ConnectionTest.checkInvariants(connection, part); + + allParts.add(connection.getDestination()); + } + } +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/correctness/invariants/BaseAssemblyTest.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/correctness/invariants/BaseAssemblyTest.java new file mode 100644 index 00000000..850f595d --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/correctness/invariants/BaseAssemblyTest.java @@ -0,0 +1,28 @@ +package stmbench7.correctness.invariants; + +import stmbench7.Parameters; +import stmbench7.annotations.Immutable; +import stmbench7.annotations.ThreadLocal; +import stmbench7.core.BaseAssembly; +import stmbench7.core.ComplexAssembly; +import stmbench7.core.CompositePart; +import stmbench7.core.Module; + +/** + * Test of invariants of a base assembly. + */ +@Immutable +@ThreadLocal +public class BaseAssemblyTest extends InvariantTest { + + public static void checkInvariants(BaseAssembly assembly, boolean initial, + ComplexAssembly parentAssembly, Module module, TraversedObjects traversedObjects) { + + traversedObjects.baseAssemblies.add(assembly); + + AssemblyTest.checkInvariants(assembly, initial, Parameters.MaxBaseAssemblies, parentAssembly, module); + + for(CompositePart component : assembly.getComponents()) + CompositePartTest.checkInvariants(component, initial, assembly, traversedObjects); + } +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/correctness/invariants/CheckInvariantsOperation.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/correctness/invariants/CheckInvariantsOperation.java new file mode 100644 index 00000000..02b48f5f --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/correctness/invariants/CheckInvariantsOperation.java @@ -0,0 +1,42 @@ +package stmbench7.correctness.invariants; + +import stmbench7.OperationId; +import stmbench7.Setup; +import stmbench7.annotations.Immutable; +import stmbench7.annotations.ReadOnly; +import stmbench7.annotations.ThreadLocal; +import stmbench7.core.Operation; +import stmbench7.core.OperationFailedException; + +/** + * Performs the check of data structure invariants. The operation is always + * performed in a single thread, without any concurrency, and so it does not + * have to be thread-safe. However, it is executed by an OperationExecutor, as + * any other operation. + */ +@Immutable +@ThreadLocal +public class CheckInvariantsOperation implements Operation { + + private final Setup setup; + private final boolean initial; + + public CheckInvariantsOperation(Setup setup, boolean initial) { + this.setup = setup; + this.initial = initial; + } + + @ReadOnly + public int performOperation() throws OperationFailedException { + TraversedObjects traversedObjects = new TraversedObjects(); + ModuleTest.checkInvariants(setup.getModule(), initial, traversedObjects); + System.err.println("\nChecking indexes..."); + IndexTest.checkInvariants(setup, initial, traversedObjects); + System.err.println("\nInvariants OK."); + return 0; + } + + public OperationId getOperationId() { + return null; + } +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/correctness/invariants/ComplexAssemblyTest.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/correctness/invariants/ComplexAssemblyTest.java new file mode 100644 index 00000000..ce172870 --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/correctness/invariants/ComplexAssemblyTest.java @@ -0,0 +1,44 @@ +package stmbench7.correctness.invariants; + +import stmbench7.Parameters; +import stmbench7.annotations.Immutable; +import stmbench7.annotations.ThreadLocal; +import stmbench7.core.Assembly; +import stmbench7.core.BaseAssembly; +import stmbench7.core.ComplexAssembly; +import stmbench7.core.Module; + +/** + * Test of invariants of a complex assembly. + */ +@Immutable +@ThreadLocal +public class ComplexAssemblyTest extends InvariantTest { + + public static void checkInvariants(ComplexAssembly assembly, boolean initial, ComplexAssembly parentAssembly, + Module module, TraversedObjects traversedObjects) { + + traversedObjects.complexAssemblies.add(assembly); + + AssemblyTest.checkInvariants(assembly, initial, Parameters.MaxComplexAssemblies, parentAssembly, module); + + int id = assembly.getId(), level = assembly.getLevel(); + if(level <= 1 || level > Parameters.NumAssmLevels) + reportError(assembly, id, "level", 1, Parameters.NumAssmLevels, level); + + for(Assembly subAssembly : assembly.getSubAssemblies()) { + if(level > 2) { + if(! (subAssembly instanceof ComplexAssembly)) + reportError(assembly, id, "subAssembly not of type ComplexAssembly at level = " + level); + ComplexAssemblyTest.checkInvariants((ComplexAssembly)subAssembly, initial, assembly, module, traversedObjects); + } + else { + if(! (subAssembly instanceof BaseAssembly)) + reportError(assembly, id, "subAssembly not of type BaseAssembly at level = 2"); + BaseAssemblyTest.checkInvariants((BaseAssembly)subAssembly, initial, assembly, module, traversedObjects); + } + } + + } + +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/correctness/invariants/CompositePartTest.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/correctness/invariants/CompositePartTest.java new file mode 100644 index 00000000..dcb5fe5d --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/correctness/invariants/CompositePartTest.java @@ -0,0 +1,65 @@ +package stmbench7.correctness.invariants; + +import java.util.TreeSet; + +import stmbench7.Parameters; +import stmbench7.annotations.Immutable; +import stmbench7.annotations.ThreadLocal; +import stmbench7.backend.ImmutableCollection; +import stmbench7.backend.LargeSet; +import stmbench7.core.AtomicPart; +import stmbench7.core.BaseAssembly; +import stmbench7.core.CompositePart; + +/** + * Test of invariants of a composite part. + */ +@Immutable +@ThreadLocal +public class CompositePartTest extends InvariantTest { + + public static void checkInvariants(CompositePart component, boolean initial, BaseAssembly aParent, + TraversedObjects traversedObjects) { + + traversedObjects.components.add(component); + + System.err.print("Component " + traversedObjects.components.size() + "\r"); + + DesignObjTest.checkInvariants(component, initial, Parameters.MaxCompParts, 0, Integer.MAX_VALUE - 1); + + int id = component.getId(), buildDate = component.getBuildDate(); + int minOldDate = Parameters.MinOldCompDate, maxOldDate = Parameters.MaxOldCompDate, + minYoungDate = Parameters.MinYoungCompDate, maxYoungDate = Parameters.MaxYoungCompDate; + if(! initial) { + if(minOldDate % 2 == 0) minOldDate--; + if(maxOldDate % 2 != 0) maxOldDate++; + if(minYoungDate % 2 == 0) minYoungDate--; + if(maxYoungDate % 2 != 0) maxYoungDate++; + } + if( (buildDate < minOldDate|| buildDate > maxOldDate) && + (buildDate < minYoungDate || buildDate > maxYoungDate) ) + reportError(component, id, "wrong buildDate (" + buildDate + ")"); + + ImmutableCollection usedIn = component.getUsedIn(); + if(aParent != null && !usedIn.contains(aParent)) + reportError(component, id, "a BaseAssembly parent not in set usedIn"); + + for(BaseAssembly assembly : usedIn) { + if(! assembly.getComponents().contains(component)) + reportError(assembly, assembly.getId(), "a child CompositePart not in set of components"); + } + + DocumentationTest.checkInvariants(component.getDocumentation(), component, traversedObjects); + + LargeSet parts = component.getParts(); + if(! parts.contains(component.getRootPart())) + reportError(component, id, "rootPart not in set of parts"); + + TreeSet allConnectedParts = new TreeSet(); + for(AtomicPart part : parts) + AtomicPartTest.checkInvariants(part, initial, component, allConnectedParts, traversedObjects); + + for(AtomicPart part : allConnectedParts) + if(! parts.contains(part)) reportError(component, id, "a graph-connected AtomicPart not in set of all parts"); + } +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/correctness/invariants/ConnectionTest.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/correctness/invariants/ConnectionTest.java new file mode 100644 index 00000000..e16da58c --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/correctness/invariants/ConnectionTest.java @@ -0,0 +1,28 @@ +package stmbench7.correctness.invariants; + +import stmbench7.Parameters; +import stmbench7.annotations.Immutable; +import stmbench7.annotations.ThreadLocal; +import stmbench7.core.AtomicPart; +import stmbench7.core.Connection; + +/** + * Test of invariants of a connection. + */ +@Immutable +@ThreadLocal +public class ConnectionTest extends InvariantTest { + + public static void checkInvariants(Connection connection, AtomicPart from) { + + if(! DesignObjTest.checkType(connection.getType())) + reportError(connection, 0, "type", "type #...", connection.getType()); + + int length = connection.getLength(); + if(length < 1 || length > Parameters.XYRange) + reportError(connection, 0, "length", 1, Parameters.XYRange, length); + + if(connection.getSource() != from) + reportError(connection, 0, "invalid source (from) reference"); + } +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/correctness/invariants/DesignObjTest.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/correctness/invariants/DesignObjTest.java new file mode 100644 index 00000000..e6024322 --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/correctness/invariants/DesignObjTest.java @@ -0,0 +1,45 @@ +package stmbench7.correctness.invariants; + +import stmbench7.Parameters; +import stmbench7.annotations.Immutable; +import stmbench7.annotations.ThreadLocal; +import stmbench7.core.DesignObj; + +/** + * Test of common invariants of elements inherited from a design object. + */ +@Immutable +@ThreadLocal +public class DesignObjTest extends InvariantTest { + + public static void checkInvariants(DesignObj obj, boolean initial, int maxId, int minBuildDate, int maxBuildDate) { + int id = obj.getId(); + if(id < 1 || id > maxId) reportError(obj, id, "id", 1, maxId, id); + + String type = obj.getType(); + if(! checkType(type)) reportError(obj, id, "type", "type #(num)", type); + + int buildDate = obj.getBuildDate(); + if(! initial) { + if(minBuildDate % 2 == 0) minBuildDate--; + if(maxBuildDate % 2 != 0) maxBuildDate++; + } + if(buildDate < minBuildDate || buildDate > maxBuildDate) + reportError(obj, id, "buildDate", minBuildDate, maxBuildDate, buildDate); + } + + protected static boolean checkType(String type) { + if(! type.startsWith("type #")) return false; + + try { + int typeNum = Integer.parseInt(type.substring("type #".length())); + if(typeNum < 0 || typeNum >= Parameters.NumTypes) return false; + + } + catch(NumberFormatException e) { + return false; + } + + return true; + } +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/correctness/invariants/DocumentationTest.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/correctness/invariants/DocumentationTest.java new file mode 100644 index 00000000..68184abb --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/correctness/invariants/DocumentationTest.java @@ -0,0 +1,39 @@ +package stmbench7.correctness.invariants; + +import stmbench7.Parameters; +import stmbench7.annotations.Immutable; +import stmbench7.annotations.ThreadLocal; +import stmbench7.core.CompositePart; +import stmbench7.core.Document; + +/** + * Test of invariants of a documentation element. + */ +@Immutable +@ThreadLocal +public class DocumentationTest extends InvariantTest { + + public static void checkInvariants(Document documentation, + CompositePart component, TraversedObjects traversedObjects) { + + traversedObjects.documents.add(documentation); + + int id = documentation.getDocumentId(); + if(id < 1 || id > Parameters.MaxCompParts) + reportError(documentation, id, "id", 1, Parameters.MaxCompParts, id); + + if(documentation.getCompositePart() != component) + reportError(documentation, id, "invalid reference to CompositePart parent"); + + String title = documentation.getTitle(), + titleShouldBe = "Composite Part #" + component.getId(); + if(! title.equals(titleShouldBe)) + reportError(documentation, id, "title", titleShouldBe, title); + + String text = documentation.getText(); + if(!text.startsWith("I am the documentation for composite part #" + component.getId()) && + !text.startsWith("This is the documentation for composite part #" + component.getId()) ) + reportError(documentation, id, "text (prefix)", "I am / This is the documentation for composite part #...", + text.substring(0, 30)); + } +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/correctness/invariants/IndexTest.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/correctness/invariants/IndexTest.java new file mode 100644 index 00000000..1d9319c3 --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/correctness/invariants/IndexTest.java @@ -0,0 +1,121 @@ +package stmbench7.correctness.invariants; + +import java.util.HashSet; + +import stmbench7.Setup; +import stmbench7.annotations.Immutable; +import stmbench7.annotations.ThreadLocal; +import stmbench7.backend.Index; +import stmbench7.backend.LargeSet; +import stmbench7.core.AtomicPart; +import stmbench7.core.BaseAssembly; +import stmbench7.core.ComplexAssembly; +import stmbench7.core.CompositePart; +import stmbench7.core.Document; +import stmbench7.core.RuntimeError; + +/** + * Test of invariants of indexes, and their consistency + * with the main data structure. Checks also invariants + * of the composite parts that are not reachable from + * base assemblies. + */ +@Immutable +@ThreadLocal +public class IndexTest extends InvariantTest { + + public static void checkInvariants(Setup setup, boolean initial, TraversedObjects traversedObjects) { + + // Complex assemblies + Index complexAssemblyIdIndex = setup.getComplexAssemblyIdIndex(); + for(ComplexAssembly traversedAssembly : traversedObjects.complexAssemblies) { + int id = traversedAssembly.getId(); + ComplexAssembly indexedAssembly = complexAssemblyIdIndex.get(id); + checkIndexValue("ComplexAssembly.id", traversedAssembly, indexedAssembly, id); + } + checkAllTraversed(complexAssemblyIdIndex, traversedObjects.complexAssemblies, "ComplexAssembly.id"); + traversedObjects.complexAssemblies.clear(); + + // Base assemblies + Index baseAssemblyIdIndex = setup.getBaseAssemblyIdIndex(); + for(BaseAssembly traversedAssembly : traversedObjects.baseAssemblies) { + int id = traversedAssembly.getId(); + BaseAssembly indexedAssembly = baseAssemblyIdIndex.get(id); + checkIndexValue("BaseAssembly.id", traversedAssembly, indexedAssembly, id); + } + checkAllTraversed(baseAssemblyIdIndex, traversedObjects.baseAssemblies, "BaseAssembly.id"); + traversedObjects.baseAssemblies.clear(); + + // Composite parts + Index compositePartIdIndex = setup.getCompositePartIdIndex(); + for(CompositePart traversedComponent : traversedObjects.components) { + int id = traversedComponent.getId(); + CompositePart indexedComponent = compositePartIdIndex.get(id); + checkIndexValue("CompositePart.id", traversedComponent, indexedComponent, id); + } + + // Check invariants for components disconnected from the data structure + // (and add those components to the set of traversed objects) + for(CompositePart indexedComponent : compositePartIdIndex) + if(! traversedObjects.components.contains(indexedComponent)) + CompositePartTest.checkInvariants(indexedComponent, initial, null, traversedObjects); + traversedObjects.components.clear(); + + // Documents + Index documentTitleIndex = setup.getDocumentTitleIndex(); + for(Document traversedDocument : traversedObjects.documents) { + String title = traversedDocument.getTitle(); + int id = traversedDocument.getDocumentId(); + + Document indexedDocument = documentTitleIndex.get(title); + checkIndexValue("Document.title", traversedDocument, indexedDocument, id); + } + checkAllTraversed(documentTitleIndex, traversedObjects.documents, "Document.title"); + traversedObjects.documents.clear(); + + // Atomic parts (id index) + Index atomicPartIdIndex = setup.getAtomicPartIdIndex(); + for(AtomicPart traversedPart : traversedObjects.atomicParts) { + int id = traversedPart.getId(); + + AtomicPart indexedPart = atomicPartIdIndex.get(id); + checkIndexValue("AtomicPart.id", traversedPart, indexedPart, id); + } + checkAllTraversed(atomicPartIdIndex, traversedObjects.atomicParts, "AtomicPart.id"); + + // Atomic parts (buildDate index) + Index> atomicPartBuildDateIndex = setup.getAtomicPartBuildDateIndex(); + for(AtomicPart traversedPart : traversedObjects.atomicParts) { + int id = traversedPart.getId(); + LargeSet sameBuildDateParts = + atomicPartBuildDateIndex.get(traversedPart.getBuildDate()); + if(sameBuildDateParts == null || !sameBuildDateParts.contains(traversedPart)) + reportError("AtomicPart.buildDate", "element with id = " + id + " not in the index"); + } + + for(LargeSet sameBuildDateParts : atomicPartBuildDateIndex) + for(AtomicPart indexedPart : sameBuildDateParts) + if(! traversedObjects.atomicParts.contains(indexedPart)) + reportError("AtomicPart.buildDate", "index contains too many elements"); + traversedObjects.atomicParts.clear(); + } + + private static void reportError(String index, String message) { + throw new RuntimeError("Index " + index + ": " + message); + } + + private static void checkIndexValue(String index, Object traversedObject, Object indexedObject, int elementId) { + if(indexedObject == null) + reportError(index, "element with id = " + elementId + + " in the data structure but not in the index"); + if(indexedObject != traversedObject) + reportError(index, "element with id = " + elementId + + " is a different object in the index and in the data structure"); + } + + private static void checkAllTraversed(Index index, HashSet traversedSet, String indexName) { + for(Object indexedObject : index) + if(! traversedSet.contains(indexedObject)) + reportError(indexName, "index contains too many elements (element " + indexedObject.toString() + ")"); + } +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/correctness/invariants/InvariantTest.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/correctness/invariants/InvariantTest.java new file mode 100644 index 00000000..48865d65 --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/correctness/invariants/InvariantTest.java @@ -0,0 +1,35 @@ +package stmbench7.correctness.invariants; + +import stmbench7.annotations.Immutable; +import stmbench7.annotations.ThreadLocal; +import stmbench7.core.RuntimeError; + +/** + * Helper methods for all invariant tests. + */ +@Immutable +@ThreadLocal +public class InvariantTest { + + protected static void reportError(Object obj, int id, String message) { + String withId = ""; + if(id > 0) withId = " with id = " + id; + throw new RuntimeError("Invariant violated! Object " + obj.getClass().getName() + + withId + ": " + message); + } + + protected static void reportError(Object obj, int id, String attribute, int expected, int found) { + reportError(obj, id, "attribute " + attribute + + " --> expected value = " + expected + ", found = " + found); + } + + protected static void reportError(Object obj, int id, String attribute, int expectedMin, int expectedMax, int found) { + reportError(obj, id, "attribute " + attribute + + " --> expected value in [" + expectedMin + "," + expectedMax + "], found = " + found); + } + + protected static void reportError(Object obj, int id, String attribute, String expected, String found) { + reportError(obj, id, "attribute " + attribute + + " --> expected value = " + expected + ", found = " + found); + } +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/correctness/invariants/ManualTest.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/correctness/invariants/ManualTest.java new file mode 100644 index 00000000..d2431455 --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/correctness/invariants/ManualTest.java @@ -0,0 +1,36 @@ +package stmbench7.correctness.invariants; + +import stmbench7.annotations.Immutable; +import stmbench7.annotations.ThreadLocal; +import stmbench7.core.Manual; +import stmbench7.core.Module; + +/** + * Test of invariants of a manual. + */ +@Immutable +@ThreadLocal +public class ManualTest extends InvariantTest { + + public static void checkInvariants(Manual manual, Module module) { + int id = manual.getId(); + if(id != 1) reportError(manual, id, "id", 1, id); + + String title = manual.getTitle(), + titleShouldBe = "Manual for module #1"; + if(! title.equals(titleShouldBe)) + reportError(manual, id, "title", titleShouldBe, title); + + if(!manual.startsWith('I') && !manual.startsWith('i')) + reportError(manual, id, "text (prefix)", "'I' || 'i'", manual.getText().substring(0, 7) + " ..."); + + if(manual.startsWith('I') && manual.countOccurences('i') > 0) + reportError(manual, id, "text starts from 'I' but contains 'i'"); + + if(manual.startsWith('i') && manual.countOccurences('I') > 0) + reportError(manual, id, "text starts from 'i' but contains 'I'"); + + if(manual.getModule() != module) + reportError(manual, id, "invalid connection to Module"); + } +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/correctness/invariants/ModuleTest.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/correctness/invariants/ModuleTest.java new file mode 100644 index 00000000..5ead807d --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/correctness/invariants/ModuleTest.java @@ -0,0 +1,30 @@ +package stmbench7.correctness.invariants; + +import stmbench7.Parameters; +import stmbench7.annotations.Immutable; +import stmbench7.annotations.ThreadLocal; +import stmbench7.core.ComplexAssembly; +import stmbench7.core.Manual; +import stmbench7.core.Module; + +/** + * Test of invariants of the module. Starts a recursive + * invariant check down the whole data structure. + */ +@Immutable +@ThreadLocal +public class ModuleTest extends InvariantTest { + + public static void checkInvariants(Module module, boolean initial, TraversedObjects traversedObjects) { + DesignObjTest.checkInvariants(module, initial, 1, Parameters.MinModuleDate, Parameters.MaxModuleDate); + + int id = module.getId(); + Manual manual = module.getManual(); + if(manual == null) reportError(module, id, "Null manual in a module"); + ManualTest.checkInvariants(manual, module); + + ComplexAssembly rootAssembly = module.getDesignRoot(); + if(rootAssembly == null) reportError(module, id, "Null root assembly"); + ComplexAssemblyTest.checkInvariants(rootAssembly, initial, null, module, traversedObjects); + } +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/correctness/invariants/TraversedObjects.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/correctness/invariants/TraversedObjects.java new file mode 100644 index 00000000..1a98542f --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/correctness/invariants/TraversedObjects.java @@ -0,0 +1,34 @@ +package stmbench7.correctness.invariants; + +import java.util.HashSet; + +import stmbench7.annotations.Immutable; +import stmbench7.annotations.ThreadLocal; +import stmbench7.core.AtomicPart; +import stmbench7.core.BaseAssembly; +import stmbench7.core.ComplexAssembly; +import stmbench7.core.CompositePart; +import stmbench7.core.Document; + +/** + * Stores the sets of objects traversed during an invariants + * check performed by the CheckInvariantsOperation class. + */ +@Immutable +@ThreadLocal +public class TraversedObjects { + + public final HashSet complexAssemblies; + public final HashSet baseAssemblies; + public final HashSet components; + public final HashSet documents; + public final HashSet atomicParts; + + public TraversedObjects() { + complexAssemblies = new HashSet(); + baseAssemblies = new HashSet(); + components = new HashSet(); + documents = new HashSet(); + atomicParts = new HashSet(); + } +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/correctness/opacity/SequentialReplayThread.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/correctness/opacity/SequentialReplayThread.java new file mode 100644 index 00000000..825e9717 --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/correctness/opacity/SequentialReplayThread.java @@ -0,0 +1,70 @@ +package stmbench7.correctness.opacity; + +import java.util.ArrayList; + +import stmbench7.BenchThread; +import stmbench7.OperationId; +import stmbench7.OperationType; +import stmbench7.Setup; +import stmbench7.ThreadRandom; +import stmbench7.annotations.NonAtomic; +import stmbench7.core.OperationFailedException; +import stmbench7.core.RuntimeError; + +/** + * Replays sequentially a concurrent execution. Used to check + * whether a given concurrent execution ensures opacity, i.e., + * whether the synchronization method used in the execution + * was correctly synchronizing threads during this execution. + */ +@NonAtomic +public class SequentialReplayThread extends BenchThread { + + public SequentialReplayThread(Setup setup, double[] operationCDF, + ArrayList replayLog) { + super(setup, operationCDF); + this.replayLog = replayLog; + } + + public void run() { + int i = 0; + //for(ReplayLogEntry entry : replayLog) + // System.out.println(i++ + " @ " + OperationId.values()[entry.opNum] + " -- " + entry.timestamp); + i=0; + int opNum = 1, numOfOps = replayLog.size(); + for(ReplayLogEntry entry : replayLog) { + System.err.print("Operation " + (opNum++) + " out of " + numOfOps + "\r"); + short threadNum = entry.threadNum; + ThreadRandom.setVirtualThreadNumber(threadNum); + + //System.out.println(++i); + int operationNumber = getNextOperationNumber(); + + //System.out.println(entry.threadNum + " -- " + OperationId.values()[entry.opNum] + + // " / " + OperationId.values()[operationNumber]); + if(operationNumber != entry.opNum) + throw new RuntimeError("ThreadRandom skew"); + + int result = 0; + boolean failed = false; + + try { + ThreadRandom.saveState(); + result = operations[operationNumber].execute(); + } + catch(OperationFailedException e) { + failed = true; + ThreadRandom.restoreState(); + } + + if(result != entry.result || failed != entry.failed) { + String opName = OperationId.values()[operationNumber].toString(); + throw new RuntimeError("Different operation result in the sequential execution (" + + "operation " + opName + "): " + + "Sequential: result = " + result + ", failed = " + failed + ". " + + "Concurrent: result = " + entry.result + ", failed = " + entry.failed + "."); + } + } + System.err.println(); + } +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/correctness/opacity/StructureComparisonOperation.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/correctness/opacity/StructureComparisonOperation.java new file mode 100644 index 00000000..34ca87c1 --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/correctness/opacity/StructureComparisonOperation.java @@ -0,0 +1,336 @@ +package stmbench7.correctness.opacity; + +import java.util.HashSet; +import java.util.Iterator; + +import stmbench7.OperationId; +import stmbench7.Setup; +import stmbench7.annotations.Immutable; +import stmbench7.annotations.ThreadLocal; +import stmbench7.backend.ImmutableCollection; +import stmbench7.backend.Index; +import stmbench7.backend.LargeSet; +import stmbench7.core.Assembly; +import stmbench7.core.AtomicPart; +import stmbench7.core.BaseAssembly; +import stmbench7.core.ComplexAssembly; +import stmbench7.core.CompositePart; +import stmbench7.core.Connection; +import stmbench7.core.DesignObj; +import stmbench7.core.Document; +import stmbench7.core.Manual; +import stmbench7.core.Module; +import stmbench7.core.Operation; +import stmbench7.core.RuntimeError; + +/** + * An operation that compares two benchmark data structures + * and throws a RuntimeError if they differ. Used to check + * whether a concurrent execution ensures opacity. + */ +@Immutable +@ThreadLocal +public class StructureComparisonOperation implements Operation { + + private final Setup setup1, setup2; + + public StructureComparisonOperation(Setup setup1, Setup setup2) { + this.setup1 = setup1; + this.setup2 = setup2; + } + + public int performOperation() { + checkModulesEqual(); + checkDesignLibrariesEqual(); + checkIndexesEqual(); + return 0; + } + + private void checkModulesEqual() { + Module module1 = setup1.getModule(), module2 = setup2.getModule(); + checkReferences(module1, module2, setup1, 0, setup2, 0, "module"); + checkDesignObjEqual(module1, module2); + + int id1 = module1.getId(), id2 = module2.getId(); + Manual man1 = module1.getManual(), man2 = module2.getManual(); + checkReferences(man1, man2, module1, id1, module2, id2, "manual"); + checkManualsEqual(man1, man2); + + ComplexAssembly root1 = module1.getDesignRoot(), root2 = module2.getDesignRoot(); + checkReferences(root1, root2, module1, id1, module2, id2, "designRoot"); + checkAssembliesEqual(root1, root2); + } + + private void checkDesignObjEqual(DesignObj obj1, DesignObj obj2) { + int id1 = obj1.getId(), id2 = obj2.getId(); + checkEqual(id1, id2, obj1, id1, obj2, id2, "id"); + checkEqual(obj1.getType(), obj2.getType(), obj1, id1, obj2, id2, "type"); + checkEqual(obj1.getBuildDate(), obj2.getBuildDate(), obj1, id1, obj2, id2, "buildDate"); + } + + private void checkManualsEqual(Manual man1, Manual man2) { + int id1 = man1.getId(), id2 = man2.getId(); + checkEqual(id1, id2, man1, id1, man2, id2, "id"); + checkEqual(man1.getTitle(), man2.getTitle(), man1, id1, man2, id2, "title"); + checkEqual(man1.getText(), man2.getText(), man1, id1, man2, id2, "text"); + checkReferences(man1.getModule(), man2.getModule(), man1, id1, man2, id2, "module"); + } + + private void checkAssembliesEqual(Assembly assembly1, Assembly assembly2) { + checkDesignObjEqual(assembly1, assembly2); + int id1 = assembly1.getId(), id2 = assembly2.getId(); + checkReferences(assembly1.getModule(), assembly2.getModule(), + assembly1, id1, assembly2, id2, "module"); + checkReferences(assembly1.getSuperAssembly(), assembly2.getSuperAssembly(), + assembly1, id1, assembly2, id2, "superAssembly"); + + if(! assembly1.getClass().equals(assembly2.getClass())) + + if(assembly1 instanceof ComplexAssembly) { + if(! (assembly2 instanceof ComplexAssembly)) + reportError(assembly1, id1, assembly2, id2, "objects of different classes"); + checkComplexAssembliesEqual((ComplexAssembly)assembly1, (ComplexAssembly)assembly2); + } + else { + if(! (assembly2 instanceof BaseAssembly)) + reportError(assembly1, id1, assembly2, id2, "objects of different classes"); + checkBaseAssembliesEqual((BaseAssembly)assembly1, (BaseAssembly)assembly2); + } + } + + private void checkComplexAssembliesEqual(ComplexAssembly assembly1, + ComplexAssembly assembly2) { + int id1 = assembly1.getId(), id2 = assembly2.getId(); + checkEqual(assembly1.getLevel(), assembly2.getLevel(), + assembly1, id1, assembly2, id2, "level"); + + ImmutableCollection subAss1 = assembly1.getSubAssemblies(), + subAss2 = assembly2.getSubAssemblies(); + checkEqual(subAss1.size(), subAss2.size(), + assembly1, id1, assembly2, id2, "subAssemblies.size()"); + + Iterator it1 = subAss1.iterator(), it2 = subAss2.iterator(); + while(it1.hasNext()) { + Assembly child1 = it1.next(), child2 = it2.next(); + checkReferences(child1, child2, assembly1, id1, assembly2, id2, "subAssemblies"); + checkAssembliesEqual(child1, child2); + } + } + + private void checkBaseAssembliesEqual(BaseAssembly assembly1, + BaseAssembly assembly2) { + int id1 = assembly1.getId(), id2 = assembly2.getId(); + ImmutableCollection comp1 = assembly1.getComponents(), + comp2 = assembly2.getComponents(); + checkEqual(comp1.size(), comp2.size(), + assembly1, id1, assembly2, id2, "components.size()"); + + Iterator it1 = comp1.iterator(), it2 = comp2.iterator(); + while(it1.hasNext()) { + CompositePart component1 = it1.next(), component2 = it2.next(); + checkReferences(component1, component2, + assembly1, id1, assembly2, id2, "components"); + checkEqual(component1.getId(), component2.getId(), + assembly1, id1, assembly2, id2, "components"); + } + } + + private void checkDesignLibrariesEqual() { + Index library1 = setup1.getCompositePartIdIndex(), + library2 = setup2.getCompositePartIdIndex(); + checkReferences(library1, library2, setup1, 0, setup2, 0, "CompositePart.id index"); + + Iterator it1 = library1.iterator(), it2 = library2.iterator(); + while(it1.hasNext()) { + if(! it2.hasNext()) + reportError(setup1, 0, setup2, 0, "CompositePart.id index size differences"); + + CompositePart component1 = it1.next(), component2 = it2.next(); + checkReferences(component1, component2, setup1, 0, setup2, 0, "CompositePart.id index"); + checkCompositePartsEqual(component1, component2); + } + } + + private void checkCompositePartsEqual(CompositePart component1, + CompositePart component2) { + checkDesignObjEqual(component1, component2); + + int id1 = component1.getId(), id2 = component2.getId(); + Document doc1 = component1.getDocumentation(), doc2 = component2.getDocumentation(); + checkReferences(doc1, doc2, component1, id1, component2, id2, "documentation"); + checkDocumentsEqual(doc1, doc2); + + ImmutableCollection usedIn1 = component1.getUsedIn(), + usedIn2 = component2.getUsedIn(); + checkEqual(usedIn1.size(), usedIn2.size(), + component1, id1, component2, id2, "usedIn.size()"); + + Iterator it1 = usedIn1.iterator(), it2 = usedIn2.iterator(); + while(it1.hasNext()) { + BaseAssembly assembly1 = it1.next(), assembly2 = it2.next(); + checkReferences(assembly1, assembly2, + component1, id1, component2, id2, "usedIn"); + checkEqual(assembly1.getId(), assembly2.getId(), + component1, id1, component2, id2, "usedIn"); + } + + AtomicPart root1 = component1.getRootPart(), root2 = component2.getRootPart(); + checkReferences(root1, root2, component1, id1, component2, id2, "rootPart"); + checkEqual(root1.getId(), root2.getId(), component1, id1, component2, id2, "rootPart"); + + LargeSet parts1 = component1.getParts(), + parts2 = component2.getParts(); + checkReferences(parts1, parts2, component1, id1, component2, id2, "parts"); + checkEqual(parts1.size(), parts2.size(), component1, id1, component2, id2, + "parts.size()"); + + Iterator partsIt1 = parts1.iterator(), partsIt2 = parts2.iterator(); + while(partsIt1.hasNext()) { + AtomicPart part1 = partsIt1.next(), part2 = partsIt2.next(); + checkReferences(part1, part2, component1, id1, component2, id2, "parts"); + checkAtomicPartsEqual(part1, part2); + } + } + + private void checkDocumentsEqual(Document doc1, Document doc2) { + int id1 = doc1.getDocumentId(), id2 = doc2.getDocumentId(); + checkEqual(id1, id2, doc1, id1, doc2, id2, "id"); + checkEqual(doc1.getTitle(), doc2.getTitle(), doc1, id1, doc2, id2, "title"); + checkEqual(doc1.getText(), doc2.getText(), doc1, id1, doc2, id2, "text"); + checkReferences(doc1.getCompositePart(), doc2.getCompositePart(), + doc1, id1, doc2, id2, "part"); + } + + private void checkAtomicPartsEqual(AtomicPart part1, AtomicPart part2) { + checkDesignObjEqual(part1, part2); + int id1 = part1.getId(), id2 = part2.getId(); + checkEqual(part1.getX(), part2.getX(), part1, id1, part2, id2, "x"); + checkEqual(part1.getY(), part2.getY(), part1, id1, part2, id2, "y"); + checkReferences(part1.getPartOf(), part2.getPartOf(), + part1, id1, part2, id2, "partOf"); + + ImmutableCollection to1 = part1.getToConnections(), + to2 = part2.getToConnections(); + checkEqual(to1.size(), to2.size(), part1, id1, part2, id2, "to.size()"); + Iterator toIt1 = to1.iterator(), toIt2 = to2.iterator(); + while(toIt1.hasNext()) { + Connection conn1 = toIt1.next(), conn2 = toIt2.next(); + checkReferences(conn1, conn2, part1, id1, part2, id2, "to"); + checkConnectionsEqual(conn1, conn2); + } + } + + private void checkConnectionsEqual(Connection conn1, Connection conn2) { + checkEqual(conn1.getType(), conn2.getType(), conn1, 0, conn2, 0, "type"); + checkEqual(conn1.getLength(), conn2.getLength(), conn1, 0, conn2, 0, "length"); + + AtomicPart src1 = conn1.getSource(), src2 = conn2.getSource(); + checkReferences(src1, src2, conn1, 0, conn2, 0, "from"); + checkEqual(src1.getId(), src2.getId(), conn1, 0, conn2, 0, "from"); + + AtomicPart dest1 = conn1.getDestination(), dest2 = conn2.getDestination(); + checkReferences(dest1, dest2, conn1, 0, conn2, 0, "to"); + checkEqual(dest1.getId(), dest2.getId(), conn1, 0, conn2, 0, "to"); + } + + private void checkIndexesEqual() { + Index atomicPartIdIndex1 = setup1.getAtomicPartIdIndex(), + atomicPartIdIndex2 = setup2.getAtomicPartIdIndex(); + checkEqual(atomicPartIdIndex1, atomicPartIdIndex2, "AtomicPart.id"); + + Index> atomicPartBuildDateIndex1 = setup1.getAtomicPartBuildDateIndex(), + atomicPartBuildDateIndex2 = setup2.getAtomicPartBuildDateIndex(); + checkEqual(atomicPartBuildDateIndex1, atomicPartBuildDateIndex2, "AtomicPart.buildDate"); + + Index documentTitleIndex1 = setup1.getDocumentTitleIndex(), + documentTitleIndex2 = setup2.getDocumentTitleIndex(); + checkEqual(documentTitleIndex1, documentTitleIndex2, "Document.title"); + + Index compositePartIdIndex1 = setup1.getCompositePartIdIndex(), + compositePartIdIndex2 = setup2.getCompositePartIdIndex(); + checkEqual(compositePartIdIndex1, compositePartIdIndex2, "CompositePart.id"); + + Index baseAssemblyIdIndex1 = setup1.getBaseAssemblyIdIndex(), + baseAssemblyIdIndex2 = setup2.getBaseAssemblyIdIndex(); + checkEqual(baseAssemblyIdIndex1, baseAssemblyIdIndex2, "BaseAssembly.id"); + + Index complexAssemblyIdIndex1 = setup1.getComplexAssemblyIdIndex(), + complexAssemblyIdIndex2 = setup2.getComplexAssemblyIdIndex(); + checkEqual(complexAssemblyIdIndex1, complexAssemblyIdIndex2, "ComplexAssembly.id"); + } + + @SuppressWarnings("unchecked") + private void checkEqual(Index index1, Index index2, String indexName) { + for(Object key1 : index1.getKeys()) { + Object val1 = index1.get((Comparable) key1); + Object val2 = index2.get((Comparable) key1); + if(val2 == null) + throw new RuntimeError("Indexes " + indexName + ": index2 does not contain key " + key1.toString()); + + if(val1 instanceof Iterable) { + checkEqual((Iterable)val1, (Iterable)val2, indexName + " at key " + key1.toString()); + continue; + } + + if(! val1.equals(val2)) + throw new RuntimeError("Indexes " + indexName + ": different values for key " + key1.toString() + + " --> [" + val1.toString() + "] != [" + val2.toString() + "]"); + } + for(Object key2 : index2.getKeys()) { + if(index1.get((Comparable) key2) == null) + throw new RuntimeError("Indexes " + indexName + ": different number of keys"); + } + } + + @SuppressWarnings("unchecked") + private void checkEqual(Iterable setIter1, Iterable setIter2, String setName) { + HashSet set1 = new HashSet(), set2 = new HashSet(); + for(Object obj : setIter1) set1.add(obj); + for(Object obj : setIter2) set2.add(obj); + + for(Object obj1 : setIter1) { + if(! set2.contains(obj1)) + throw new RuntimeError("Sets " + setName + ": element [" + obj1.toString() + "] not in set2"); + } + for(Object obj2 : setIter2) { + if(! set1.contains(obj2)) + throw new RuntimeError("Sets " + setName + ": element [" + obj2.toString() + "] not in set1"); + } + } + + private void reportError(Object obj1, int id1, Object obj2, int id2, + String message) { + throw new RuntimeError("Object " + obj1.toString() + " with id = " + id1 + + " != object " + obj2.toString() + " with id = " + id2 + + ": " + message); + } + + private void checkEqual(int val1, int val2, + Object obj1, int id1, Object obj2, int id2, String attribute) { + if(val1 != val2) + reportError(obj1, id1, obj2, id2, "attribute " + attribute + " --> " + + val1 + " != " + val2); + } + + private void checkEqual(String val1, String val2, + Object obj1, int id1, Object obj2, int id2, String attribute) { + if(! val1.equals(val2)) + reportError(obj1, id1, obj2, id2, "attribute " + attribute + " --> " + + val1 + " != " + val2); + } + + private void checkReferences(Object val1, Object val2, + Object obj1, int id1, Object obj2, int id2, String attribute) { + + if(val1 != null && val1 == val2) + reportError(obj1, id1, obj2, id2, "attribute " + attribute + " --> " + + "references equal"); + else if( (val1 == null && val2 != null) || (val1 != null && val2 == null) ) + reportError(obj1, id1, obj2, id2, "attribute " + attribute + " --> " + + "one (and only one) reference is null"); + } + + public OperationId getOperationId() { + return null; + } +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/DefaultOperationExecutor.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/DefaultOperationExecutor.java new file mode 100644 index 00000000..8c29b619 --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/DefaultOperationExecutor.java @@ -0,0 +1,30 @@ +package stmbench7.impl; + +import stmbench7.OperationExecutor; +import stmbench7.core.Operation; +import stmbench7.core.OperationFailedException; + +/** + * Default implementation of an OperationExecutor. + * Does not provide any thread-safety. + */ +public class DefaultOperationExecutor implements OperationExecutor { + + private static int clock = 0; + + private final Operation op; + private int lastTimestamp = 0; + + public DefaultOperationExecutor(Operation op) { + this.op = op; + } + + public int execute() throws OperationFailedException { + lastTimestamp = clock++; + return op.performOperation(); + } + + public int getLastOperationTimestamp() { + return lastTimestamp; + } +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/DefaultOperationExecutorFactory.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/DefaultOperationExecutorFactory.java new file mode 100644 index 00000000..b1ed3038 --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/DefaultOperationExecutorFactory.java @@ -0,0 +1,19 @@ +package stmbench7.impl; + +import stmbench7.OperationExecutor; +import stmbench7.OperationExecutorFactory; +import stmbench7.annotations.Immutable; +import stmbench7.core.Operation; + +/** + * Default implementation of an OperationExecutorFactory. + * It creates an OperationExecutor that does not provide + * any synchronization between threads. + */ +@Immutable +public class DefaultOperationExecutorFactory extends OperationExecutorFactory { + + public OperationExecutor createOperationExecutor(Operation op) { + return new DefaultOperationExecutor(op); + } +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/DefaultThreadFactory.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/DefaultThreadFactory.java new file mode 100644 index 00000000..ac40cb59 --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/DefaultThreadFactory.java @@ -0,0 +1,11 @@ +package stmbench7.impl; + +import stmbench7.ThreadFactory; + +public class DefaultThreadFactory extends ThreadFactory { + + @Override + public Thread createThread(Runnable runnable) { + return new Thread(runnable); + } +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/NoSynchronizationInitializer.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/NoSynchronizationInitializer.java new file mode 100644 index 00000000..1c2ac0e8 --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/NoSynchronizationInitializer.java @@ -0,0 +1,34 @@ +package stmbench7.impl; + +import stmbench7.OperationExecutorFactory; +import stmbench7.SynchMethodInitializer; +import stmbench7.ThreadFactory; +import stmbench7.annotations.Immutable; +import stmbench7.backend.BackendFactory; +import stmbench7.core.DesignObjFactory; +import stmbench7.impl.backend.BackendFactoryImpl; +import stmbench7.impl.core.DesignObjFactoryImpl; + +/** + * An initializer that provides non-thread-safe (default) + * factories. Should normally be used only with a single thread. + */ +@Immutable +public class NoSynchronizationInitializer implements SynchMethodInitializer { + + public BackendFactory createBackendFactory() { + return new BackendFactoryImpl(); + } + + public DesignObjFactory createDesignObjFactory() { + return new DesignObjFactoryImpl(); + } + + public OperationExecutorFactory createOperationExecutorFactory() { + return new DefaultOperationExecutorFactory(); + } + + public ThreadFactory createThreadFactory() { + return new DefaultThreadFactory(); + } +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/backend/BackendFactoryImpl.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/backend/BackendFactoryImpl.java new file mode 100644 index 00000000..c55190bf --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/backend/BackendFactoryImpl.java @@ -0,0 +1,30 @@ +package stmbench7.impl.backend; + +import stmbench7.backend.BackendFactory; +import stmbench7.backend.IdPool; +import stmbench7.backend.Index; +import stmbench7.backend.LargeSet; + +/** + * Implements methods that create objects implementing + * interfaces defined in stmbench7.backend: Index, IdPool, + * and LargeSet. This default implementation constructs + * objects that are NOT thread-safe. + */ +public class BackendFactoryImpl extends BackendFactory { + + @Override + public > LargeSet createLargeSet() { + return new LargeSetImpl(); + } + + @Override + public , V> Index createIndex() { + return new TreeMapIndex(); + } + + @Override + public IdPool createIdPool(int maxNumberOfIds) { + return new IdPoolImpl(maxNumberOfIds); + } +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/backend/BagImpl.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/backend/BagImpl.java new file mode 100644 index 00000000..5818ca13 --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/backend/BagImpl.java @@ -0,0 +1,27 @@ +package stmbench7.impl.backend; + +import java.util.ArrayList; + +import stmbench7.annotations.ContainedInAtomic; +import stmbench7.backend.ImmutableCollection; + +/** + * Simple implementation of a bag of objects. + */ +@ContainedInAtomic +public class BagImpl extends ArrayList { + + private static final long serialVersionUID = 5329072640119174542L; + + public BagImpl() { + super(); + } + + public BagImpl(BagImpl source) { + super(source); + } + + public ImmutableCollection immutableView() { + return new ImmutableViewImpl(this); + } +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/backend/IdPoolImpl.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/backend/IdPoolImpl.java new file mode 100644 index 00000000..aedfcd5e --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/backend/IdPoolImpl.java @@ -0,0 +1,52 @@ +package stmbench7.impl.backend; + +import java.util.LinkedList; + +import stmbench7.annotations.Update; +import stmbench7.backend.IdPool; +import stmbench7.core.OperationFailedException; + +/** + * Used to generate ids of various elements. + * This default implementation is NOT thread-safe. + */ +public class IdPoolImpl implements IdPool, Cloneable { + + private final LinkedList idPool; + + public IdPoolImpl(int maxNumberOfIds) { + idPool = new LinkedList(); + for(int id = 1; id <= maxNumberOfIds; id++) { + idPool.offer(id); + } + } + + @Update + public int getId() throws OperationFailedException { + Integer id = idPool.poll(); + if(id == null) throw new OperationFailedException(); + + return id; + } + + @Update + public void putUnusedId(int id) { + idPool.offer(id); + } + + public String toString() { + String txt = "IdPool:"; + for(int id : idPool) txt += " " + id; + return txt; + } + + private IdPoolImpl(LinkedList idPool) { + this.idPool = idPool; + } + + @SuppressWarnings("unchecked") + @Override + public IdPoolImpl clone() { + return new IdPoolImpl((LinkedList) idPool.clone()); + } +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/backend/ImmutableViewImpl.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/backend/ImmutableViewImpl.java new file mode 100644 index 00000000..e5d965fe --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/backend/ImmutableViewImpl.java @@ -0,0 +1,32 @@ +package stmbench7.impl.backend; + +import java.util.ArrayList; +import java.util.Iterator; + +import stmbench7.backend.ImmutableCollection; + +public class ImmutableViewImpl implements ImmutableCollection, Cloneable { + + private final ArrayList elements; + + public ImmutableViewImpl(ArrayList elements) { + this.elements = elements; + } + + public boolean contains(E element) { + return elements.contains(element); + } + + public int size() { + return elements.size(); + } + + public Iterator iterator() { + return elements.iterator(); + } + + @SuppressWarnings("unchecked") + public ImmutableCollection clone() { + return new ImmutableViewImpl((ArrayList) elements.clone()); + } +} \ No newline at end of file diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/backend/LargeSetImpl.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/backend/LargeSetImpl.java new file mode 100644 index 00000000..ad12dec0 --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/backend/LargeSetImpl.java @@ -0,0 +1,35 @@ +package stmbench7.impl.backend; + +import java.util.TreeSet; + +import stmbench7.backend.LargeSet; + +/** + * A simple implementation of a large-size set + * (used by CompositePart objects). + * This default implementation is NOT thread-safe. + */ +public class LargeSetImpl> extends TreeSet implements LargeSet { + + private static final long serialVersionUID = -6991698966590705390L; + + public LargeSetImpl() { + super(); + } + + public LargeSetImpl(LargeSetImpl source) { + super(source); + } + + // The following methods are needed because TreeSet + // implements contains(Object) and remove(Object) + // instead of contains(E) and remove(E). + + public boolean contains(E element) { + return super.contains(element); + } + + public boolean remove(E element) { + return super.remove(element); + } +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/backend/SmallSetImpl.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/backend/SmallSetImpl.java new file mode 100644 index 00000000..c34a1bd4 --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/backend/SmallSetImpl.java @@ -0,0 +1,35 @@ +package stmbench7.impl.backend; + +import java.util.ArrayList; + +import stmbench7.annotations.ContainedInAtomic; +import stmbench7.backend.ImmutableCollection; + +/** + * A simple implementation of a small-size set + * (used by Assembly and AtomicPart objects). + */ +@ContainedInAtomic +public class SmallSetImpl extends ArrayList { + + private static final long serialVersionUID = 8608574819902616324L; + + public SmallSetImpl() { + super(); + } + + public SmallSetImpl(SmallSetImpl source) { + super(source); + } + + public boolean add(E element) { + if(contains(element)) return false; + + super.add(element); + return true; + } + + public ImmutableCollection immutableView() { + return new ImmutableViewImpl(this); + } +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/backend/TreeMapIndex.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/backend/TreeMapIndex.java new file mode 100644 index 00000000..b4b3c897 --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/backend/TreeMapIndex.java @@ -0,0 +1,66 @@ +package stmbench7.impl.backend; + +import java.util.Iterator; +import java.util.TreeMap; + +import stmbench7.backend.Index; +import stmbench7.core.RuntimeError; + +/** + * A simple implementation of an index + * (NOT thread-safe). + */ +public class TreeMapIndex,V> implements Index, Cloneable { + + private final TreeMap index; + + public TreeMapIndex() { + index = new TreeMap(); + } + + public void put(K key, V value) { + if(value == null) throw new RuntimeError("TreeMapIndex does not support null values!"); + index.put(key, value); + } + + public V putIfAbsent(K key, V value) { + if(value == null) throw new RuntimeError("TreeMapIndex does not support null values!"); + + V oldVal = index.get(key); + if(oldVal != null) return oldVal; + + index.put(key, value); + return null; + } + + public V get(K key) { + return index.get(key); + } + + public Iterable getRange(K minKey, K maxKey) { + return index.subMap(minKey, maxKey).values(); + } + + public boolean remove(K key) { + V removedValue = index.remove(key); + return (removedValue != null); + } + + public Iterator iterator() { + return index.values().iterator(); + } + + public Iterable getKeys() { + return index.keySet(); + } + + private TreeMapIndex(TreeMap index) { + this.index = index; + } + + @SuppressWarnings("unchecked") + @Override + public Object clone() { + return new TreeMapIndex((TreeMap) index.clone()); + } +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/core/AssemblyImpl.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/core/AssemblyImpl.java new file mode 100644 index 00000000..edc66166 --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/core/AssemblyImpl.java @@ -0,0 +1,52 @@ +package stmbench7.impl.core; + +import stmbench7.core.Assembly; +import stmbench7.core.ComplexAssembly; +import stmbench7.core.Module; + + +/** + * STMBench7 benchmark Assembly (see the specification). + * Default implementation. + */ +public abstract class AssemblyImpl extends DesignObjImpl implements Assembly { + + protected ComplexAssembly superAssembly; + protected Module module; + + public AssemblyImpl(int id, String type, int buildDate, Module module, ComplexAssembly superAssembly) { + super(id, type, buildDate); + this.module = module; + this.superAssembly = superAssembly; + } + + public AssemblyImpl(AssemblyImpl source) { + super(source); + this.superAssembly = source.superAssembly; + this.module = source.module; + } + + public ComplexAssembly getSuperAssembly() { + return superAssembly; + } + + public Module getModule() { + return module; + } + + public void clearPointers() { + superAssembly = null; + module = null; + } + + @Override + public boolean equals(Object obj) { + if(! (obj instanceof Assembly)) return false; + return super.equals(obj); + } + + @Override + public String toString() { + return super.toString() + ", superAssembly=[" + superAssembly + "]"; + } +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/core/AtomicPartImpl.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/core/AtomicPartImpl.java new file mode 100644 index 00000000..8b084493 --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/core/AtomicPartImpl.java @@ -0,0 +1,111 @@ +package stmbench7.impl.core; + +import stmbench7.backend.ImmutableCollection; +import stmbench7.core.AtomicPart; +import stmbench7.core.CompositePart; +import stmbench7.core.Connection; +import stmbench7.impl.backend.SmallSetImpl; + +/** + * STMBench7 benchmark Atomic Part (see the specification). + * Default implementation. + */ +public class AtomicPartImpl extends DesignObjImpl implements AtomicPart { + + private int x, y; + protected SmallSetImpl to, from; + private CompositePart partOf; + + public AtomicPartImpl(int id, String type, int buildDate, int x, int y) { + super(id, type, buildDate); + this.x = x; + this.y = y; + to = new SmallSetImpl(); + from = new SmallSetImpl(); + } + + public AtomicPartImpl(AtomicPartImpl source) { + super(source); + this.x = source.x; + this.y = source.y; + this.to = new SmallSetImpl(source.to); + this.from = new SmallSetImpl(source.from); + this.partOf = source.partOf; + } + + public void connectTo(AtomicPart destination, String type, int length) { + Connection connection = new ConnectionImpl(this, destination, type, length); + to.add(connection); + destination.addConnectionFromOtherPart(connection.getReversed()); + } + + public void addConnectionFromOtherPart(Connection connection) { + from.add(connection); + } + + public void setCompositePart(CompositePart partOf) { + this.partOf = partOf; + } + + public int getNumToConnections() { + return to.size(); + } + + public ImmutableCollection getToConnections() { + return to.immutableView(); + } + + public ImmutableCollection getFromConnections() { + return from.immutableView(); + } + + public CompositePart getPartOf() { + return partOf; + } + + public void swapXY() { + int tmp = y; + y = x; + x = tmp; + } + + public int getX() { + return x; + } + + public int getY() { + return y; + } + + public void clearPointers() { + x = y = 0; + to = null; + from = null; + partOf = null; + } + + public int compareTo(AtomicPart part) { + return id - part.getId(); + } + + @Override + public boolean equals(Object obj) { + if(! (obj instanceof AtomicPart)) return false; + return super.equals(obj); + } + + @SuppressWarnings("unchecked") + @Override + public AtomicPartImpl clone() { + AtomicPartImpl clone = (AtomicPartImpl) super.clone(); + clone.from = (SmallSetImpl) from.clone(); + clone.to = (SmallSetImpl) to.clone(); + return clone; + } + + @Override + public String toString() { + return super.toString() + ", x=" + x + ", y=" + y + ", partOf=[" + partOf + "]" + + ", to={ " + to.size() + " connections }, from={ " + from.size() + " connections }"; + } +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/core/BaseAssemblyImpl.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/core/BaseAssemblyImpl.java new file mode 100644 index 00000000..7a56e49c --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/core/BaseAssemblyImpl.java @@ -0,0 +1,72 @@ +package stmbench7.impl.core; + +import stmbench7.backend.ImmutableCollection; +import stmbench7.core.BaseAssembly; +import stmbench7.core.ComplexAssembly; +import stmbench7.core.CompositePart; +import stmbench7.core.Module; +import stmbench7.impl.backend.BagImpl; + +/** + * STMBench7 benchmark Base Assembly (see the specification). + * Default implementation. + */ +public class BaseAssemblyImpl extends AssemblyImpl implements BaseAssembly { + + protected BagImpl components; + + public BaseAssemblyImpl(int id, String type, int buildDate, Module module, ComplexAssembly superAssembly) { + super(id, type, buildDate, module, superAssembly); + components = new BagImpl(); + } + + public BaseAssemblyImpl(BaseAssemblyImpl source) { + super(source); + this.components = new BagImpl(source.components); + } + + public void addComponent(CompositePart component) { + components.add(component); + component.addAssembly(this); + } + + public boolean removeComponent(CompositePart component) { + boolean componentExists = components.remove(component); + if(! componentExists) return false; + + component.removeAssembly(this); + return true; + } + + public ImmutableCollection getComponents() { + return components.immutableView(); + } + + @Override + public void clearPointers() { + super.clearPointers(); + components = null; + } + + @Override + public boolean equals(Object obj) { + if(! (obj instanceof BaseAssembly)) return false; + return super.equals(obj); + } + + @SuppressWarnings("unchecked") + @Override + public BaseAssemblyImpl clone() { + BaseAssemblyImpl clone = (BaseAssemblyImpl) super.clone(); + clone.components = (BagImpl) components.clone(); + return clone; + } + + @Override + public String toString() { + String componentIds = "{ "; + for(CompositePart component : components) componentIds += component.getId() + " "; + componentIds += "}"; + return super.toString() + ", components=" + componentIds; + } +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/core/ComplexAssemblyImpl.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/core/ComplexAssemblyImpl.java new file mode 100644 index 00000000..5e1f4aa8 --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/core/ComplexAssemblyImpl.java @@ -0,0 +1,84 @@ +package stmbench7.impl.core; + +import stmbench7.Parameters; +import stmbench7.backend.ImmutableCollection; +import stmbench7.core.Assembly; +import stmbench7.core.BaseAssembly; +import stmbench7.core.ComplexAssembly; +import stmbench7.core.Module; +import stmbench7.core.RuntimeError; +import stmbench7.impl.backend.SmallSetImpl; + +/** + * STMBench7 benchmark Complex Assembly (see the specification). + * Default implementation. + */ +public class ComplexAssemblyImpl extends AssemblyImpl implements ComplexAssembly { + + private SmallSetImpl subAssemblies; + private short level; + + public ComplexAssemblyImpl(int id, String type, int buildDate, Module module, ComplexAssembly superAssembly) { + super(id, type, buildDate, module, superAssembly); + subAssemblies = new SmallSetImpl(); + + if(superAssembly == null) level = Parameters.NumAssmLevels; + else level = (short)(superAssembly.getLevel() - 1); + } + + public ComplexAssemblyImpl(ComplexAssemblyImpl source) { + super(source); + this.subAssemblies = new SmallSetImpl(subAssemblies); + this.level = source.level; + } + + public boolean addSubAssembly(Assembly assembly) { + if(assembly instanceof BaseAssembly && level != 2) + throw new RuntimeError("ComplexAssembly.addAssembly: BaseAssembly at wrong level!"); + + boolean notAddedBefore = subAssemblies.add(assembly); + return notAddedBefore; + } + + public boolean removeSubAssembly(Assembly assembly) { + return subAssemblies.remove(assembly); + } + + public ImmutableCollection getSubAssemblies() { + return subAssemblies.immutableView(); + } + + public short getLevel() { + return level; + } + + @Override + public void clearPointers() { + super.clearPointers(); + subAssemblies = null; + level = -1; + } + + @Override + public boolean equals(Object obj) { + if(! (obj instanceof ComplexAssembly)) return false; + return super.equals(obj); + } + + @SuppressWarnings("unchecked") + @Override + public ComplexAssemblyImpl clone() { + ComplexAssemblyImpl clone = (ComplexAssemblyImpl) super.clone(); + clone.subAssemblies = (SmallSetImpl) subAssemblies.clone(); + return clone; + } + + @Override + public String toString() { + String subAssString = "{ "; + for(Assembly subAssembly : subAssemblies) + subAssString += subAssembly.getId() + " "; + subAssString += "}"; + return super.toString() + ", level=" + level + ", subAssemblies=" + subAssString; + } +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/core/CompositePartImpl.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/core/CompositePartImpl.java new file mode 100644 index 00000000..d0d1e9e1 --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/core/CompositePartImpl.java @@ -0,0 +1,96 @@ +package stmbench7.impl.core; + +import stmbench7.backend.BackendFactory; +import stmbench7.backend.ImmutableCollection; +import stmbench7.backend.LargeSet; +import stmbench7.core.AtomicPart; +import stmbench7.core.BaseAssembly; +import stmbench7.core.CompositePart; +import stmbench7.core.Document; +import stmbench7.impl.backend.BagImpl; + +/** + * STMBench7 benchmark Composite Part (see the specification). + */ +public class CompositePartImpl extends DesignObjImpl implements CompositePart { + + private Document documentation; + private BagImpl usedIn; + private LargeSet parts; + private AtomicPart rootPart; + + public CompositePartImpl(int id, String type, int buildDate, Document documentation) { + super(id, type, buildDate); + this.documentation = documentation; + documentation.setPart(this); + usedIn = new BagImpl(); + parts = BackendFactory.instance.createLargeSet(); + } + + public CompositePartImpl(CompositePartImpl source) { + super(source); + this.documentation = source.documentation; + this.usedIn = new BagImpl(source.usedIn); + this.parts = source.parts; + this.rootPart = source.rootPart; + } + + public void addAssembly(BaseAssembly assembly) { + usedIn.add(assembly); + } + + public boolean addPart(AtomicPart part) { + boolean notAddedBefore = parts.add(part); + if(! notAddedBefore) return false; + + part.setCompositePart(this); + if(rootPart == null) rootPart = part; + + return true; + } + + public AtomicPart getRootPart() { + return rootPart; + } + + public void setRootPart(AtomicPart part) { + rootPart = part; + } + + public Document getDocumentation() { + return documentation; + } + + public LargeSet getParts() { + return parts; + } + + public void removeAssembly(BaseAssembly assembly) { + usedIn.remove(assembly); + } + + public ImmutableCollection getUsedIn() { + return usedIn.immutableView(); + } + + public void clearPointers() { + documentation = null; + parts = null; + usedIn = null; + rootPart = null; + } + + @Override + public boolean equals(Object obj) { + if(! (obj instanceof CompositePart)) return false; + return super.equals(obj); + } + + @SuppressWarnings("unchecked") + @Override + public Object clone() { + CompositePartImpl clone = (CompositePartImpl) super.clone(); + clone.usedIn = (BagImpl) usedIn.clone(); + return clone; + } +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/core/ConnectionImpl.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/core/ConnectionImpl.java new file mode 100644 index 00000000..dc4e0138 --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/core/ConnectionImpl.java @@ -0,0 +1,53 @@ +package stmbench7.impl.core; + +import stmbench7.core.AtomicPart; +import stmbench7.core.Connection; +import stmbench7.core.RuntimeError; + + +/** + * STMBench7 benchmark Connection (see the specification). + * Default implementation. + */ +public class ConnectionImpl implements Connection, Cloneable { + + protected final String type; + protected final int length; + protected final AtomicPart from, to; + + public ConnectionImpl(AtomicPart from, AtomicPart to, String type, int length) { + this.type = type; + this.length = length; + this.from = from; + this.to = to; + } + + public Connection getReversed() { + return new ConnectionImpl(to, from, new String(type), length); + } + + public AtomicPart getSource() { + return from; + } + + public AtomicPart getDestination() { + return to; + } + + public int getLength() { + return length; + } + + public String getType() { + return type; + } + + public Object clone() { + try { + return super.clone(); + } + catch(CloneNotSupportedException e) { + throw new RuntimeError(e); + } + } +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/core/DesignObjFactoryImpl.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/core/DesignObjFactoryImpl.java new file mode 100644 index 00000000..c8a83dc9 --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/core/DesignObjFactoryImpl.java @@ -0,0 +1,63 @@ +package stmbench7.impl.core; + +import stmbench7.core.AtomicPart; +import stmbench7.core.BaseAssembly; +import stmbench7.core.ComplexAssembly; +import stmbench7.core.CompositePart; +import stmbench7.core.Connection; +import stmbench7.core.DesignObjFactory; +import stmbench7.core.Document; +import stmbench7.core.Manual; +import stmbench7.core.Module; + +/** + * Implements methods that create objects implementing + * interfaces defined in stmbench7.core. This default implementation + * constructs objects that are NOT thread-safe. + */ +public class DesignObjFactoryImpl extends DesignObjFactory { + + @Override + public AtomicPart createAtomicPart(int id, String type, int buildDate, int x, int y) { + return new AtomicPartImpl(id, type, buildDate, x, y); + } + + @Override + public Connection createConnection(AtomicPart from, AtomicPart to, + String type, int length) { + return new ConnectionImpl(from, to, type, length); + } + + @Override + public BaseAssembly createBaseAssembly(int id, String type, int buildDate, + Module module, ComplexAssembly superAssembly) { + return new BaseAssemblyImpl(id, type, buildDate, module, superAssembly); + } + + @Override + public ComplexAssembly createComplexAssembly(int id, String type, int buildDate, + Module module, ComplexAssembly superAssembly) { + return new ComplexAssemblyImpl(id, type, buildDate, module, superAssembly); + } + + @Override + public CompositePart createCompositePart(int id, String type, int buildDate, + Document documentation) { + return new CompositePartImpl(id, type, buildDate, documentation); + } + + @Override + public Document createDocument(int id, String title, String text) { + return new DocumentImpl(id, title, text); + } + + @Override + public Manual createManual(int id, String title, String text) { + return new ManualImpl(id, title, text); + } + + @Override + public Module createModule(int id, String type, int buildDate, Manual man) { + return new ModuleImpl(id, type, buildDate, man); + } +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/core/DesignObjImpl.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/core/DesignObjImpl.java new file mode 100644 index 00000000..2463b371 --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/core/DesignObjImpl.java @@ -0,0 +1,85 @@ +package stmbench7.impl.core; + +import stmbench7.core.DesignObj; +import stmbench7.core.RuntimeError; + +/** + * STMBench7 benchmark Design Object (see the specification). Default + * implementation. + */ +public class DesignObjImpl implements DesignObj, Cloneable { + + protected final int id; + protected final String type; + protected int buildDate; + + public DesignObjImpl(int id, String type, int buildDate) { + this.id = id; + this.type = type; + this.buildDate = buildDate; + } + + public DesignObjImpl(DesignObjImpl source) { + this.id = source.id; + this.type = source.type; + this.buildDate = source.buildDate; + } + + public int getId() { + return id; + } + + public int getBuildDate() { + return buildDate; + } + + public void updateBuildDate() { + if (buildDate % 2 == 0) + buildDate--; + else + buildDate++; + } + + public void nullOperation() { + } + + public String getType() { + return type; + } + + @Override + public boolean equals(Object obj) { + if(! (obj instanceof DesignObj)) return false; + return ((DesignObj) obj).getId() == id; + } + + @Override + public int hashCode() { + return id; + } + + @Override + public Object clone() { + try { + return super.clone(); + } + catch(CloneNotSupportedException e) { + throw new RuntimeError(e); + } + } + + @Override + public String toString() { + return this.getClass().getName() + + ": id=" + id + + ", type=" + type + + ", buildDate=" + buildDate; + } + + protected String sequenceToString(Iterable sequence) { + String seqString = "{ "; + for(Object element : sequence) seqString += element + " "; + seqString += "}"; + return seqString; + } +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/core/DocumentImpl.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/core/DocumentImpl.java new file mode 100644 index 00000000..e073e852 --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/core/DocumentImpl.java @@ -0,0 +1,95 @@ +package stmbench7.impl.core; + +import stmbench7.core.CompositePart; +import stmbench7.core.Document; +import stmbench7.core.RuntimeError; + + +/** + * STMBench7 benchmark Document (see the specification). + * Default implementation. + */ +public class DocumentImpl implements Document, Cloneable { + + private final int id; + private String title; + private String text; + private CompositePart part; + + public DocumentImpl(int id, String title, String text) { + this.id = id; + this.title = title; + this.text = text; + } + + public DocumentImpl(DocumentImpl source) { + this.title = source.title; + this.id = source.id; + this.text = source.text; + this.part = source.part; + } + + public void setPart(CompositePart part) { + this.part = part; + } + + public CompositePart getCompositePart() { + return part; + } + + public int getDocumentId() { + return id; + } + + public String getTitle() { + return title; + } + + public void nullOperation() { + } + + public int searchText(char symbol) { + int occurences = 0; + + for(int i = 0; i < text.length(); i++) + if(text.charAt(i) == symbol) occurences++; + + return occurences; + } + + public int replaceText(String from, String to) { + if(! text.startsWith(from)) return 0; + + text = text.replaceFirst(from, to); + return 1; + } + + public boolean textBeginsWith(String prefix) { + return text.startsWith(prefix); + } + + public String getText() { + return text; + } + + @Override + public boolean equals(Object obj) { + if(! (obj instanceof Document)) return false; + return ((Document) obj).getDocumentId() == id; + } + + @Override + public int hashCode() { + return id; + } + + @Override + public Object clone() { + try { + return super.clone(); + } + catch(CloneNotSupportedException e) { + throw new RuntimeError(e); + } + } +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/core/ManualImpl.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/core/ManualImpl.java new file mode 100644 index 00000000..1f3360df --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/core/ManualImpl.java @@ -0,0 +1,107 @@ +package stmbench7.impl.core; + +import stmbench7.core.Manual; +import stmbench7.core.Module; +import stmbench7.core.RuntimeError; + + +/** + * STMBench7 benchmark Manual (see the specification). + * Default implementation. + */ +public class ManualImpl implements Manual, Cloneable { + + private final int id; + private String title; + private String text; + private Module module; + + public ManualImpl(int id, String title, String text) { + this.id = id; + this.title = title; + this.text = text; + } + + public ManualImpl(ManualImpl source) { + this.title = source.title; + this.id = source.id; + this.text = source.text; + this.module = source.module; + } + + public void setModule(Module module) { + this.module = module; + } + + public int countOccurences(char ch) { + int position = 0, count = 0, newPosition, textLen = text.length(); + + do { + newPosition = text.indexOf(ch, position); + if(newPosition == -1) break; + + position = newPosition + 1; + count++; + } + while(position < textLen); + + return count; + } + + public int checkFirstLastCharTheSame() { + if(text.charAt(0) == text.charAt(text.length() - 1)) return 1; + return 0; + } + + public boolean startsWith(char ch) { + return (text.charAt(0) == ch); + } + + public int replaceChar(char from, char to) { + text = text.replace(from, to); + return countOccurences(to); + } + + public int getId() { + return id; + } + + public Module getModule() { + return module; + } + + public String getText() { + return text; + } + + public String getTitle() { + return title; + } + + @Override + public boolean equals(Object obj) { + if(! (obj instanceof Manual)) return false; + return ((Manual) obj).getId() == id; + } + + @Override + public int hashCode() { + return id; + } + + @Override + public Object clone() { + try { + return super.clone(); + } + catch(CloneNotSupportedException e) { + throw new RuntimeError(e); + } + } + + @Override + public String toString() { + return getClass().getName() + ": id=" + id + ", title=" + title + ", text=" + + text.substring(0, 10) + " (...) " + text.substring(text.length() - 10, text.length()); + } +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/core/ModuleImpl.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/core/ModuleImpl.java new file mode 100644 index 00000000..33720cdb --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/core/ModuleImpl.java @@ -0,0 +1,46 @@ +package stmbench7.impl.core; + +import stmbench7.core.ComplexAssembly; +import stmbench7.core.Manual; +import stmbench7.core.Module; + + +/** + * STMBench7 benchmark Module (see the specification). + * Default implementation. + */ +public class ModuleImpl extends DesignObjImpl implements Module { + + private final Manual man; + private ComplexAssembly designRoot; + + public ModuleImpl(int id, String type, int buildDate, Manual man) { + super(id, type, buildDate); + this.man = man; + man.setModule(this); + } + + public ModuleImpl(ModuleImpl source) { + super(source); + this.man = source.man; + this.designRoot = source.designRoot; + } + + public void setDesignRoot(ComplexAssembly designRoot) { + this.designRoot = designRoot; + } + + public ComplexAssembly getDesignRoot() { + return designRoot; + } + + public Manual getManual() { + return man; + } + + @Override + public boolean equals(Object obj) { + if(! (obj instanceof Module)) return false; + return super.equals(obj); + } +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/deucestm/DeuceSTMInitializer.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/deucestm/DeuceSTMInitializer.java new file mode 100644 index 00000000..08783dc9 --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/deucestm/DeuceSTMInitializer.java @@ -0,0 +1,12 @@ +package stmbench7.impl.deucestm; + +import stmbench7.OperationExecutorFactory; +import stmbench7.impl.NoSynchronizationInitializer; + +public class DeuceSTMInitializer extends NoSynchronizationInitializer { + + @Override + public OperationExecutorFactory createOperationExecutorFactory() { + return new DeuceSTMOperationExecutorFactory(); + } +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/deucestm/DeuceSTMOperationExecutor.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/deucestm/DeuceSTMOperationExecutor.java new file mode 100644 index 00000000..349bec54 --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/deucestm/DeuceSTMOperationExecutor.java @@ -0,0 +1,24 @@ +package stmbench7.impl.deucestm; + +import stmbench7.OperationExecutor; +import stmbench7.core.Operation; +import stmbench7.core.OperationFailedException; + +public class DeuceSTMOperationExecutor implements OperationExecutor { + + private final Operation op; + + public DeuceSTMOperationExecutor(Operation op) { + this.op = op; + } + + @org.deuce.Atomic + public int execute() throws OperationFailedException { + return op.performOperation(); + } + + public int getLastOperationTimestamp() { + return 0; + } + +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/deucestm/DeuceSTMOperationExecutorFactory.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/deucestm/DeuceSTMOperationExecutorFactory.java new file mode 100644 index 00000000..37449f52 --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/deucestm/DeuceSTMOperationExecutorFactory.java @@ -0,0 +1,17 @@ +package stmbench7.impl.deucestm; + +import stmbench7.OperationExecutor; +import stmbench7.OperationExecutorFactory; +import stmbench7.core.Operation; +import stmbench7.impl.DefaultOperationExecutor; + +public class DeuceSTMOperationExecutorFactory extends OperationExecutorFactory { + + @Override + public OperationExecutor createOperationExecutor(Operation op) { + if(op.getOperationId() != null) + return new DeuceSTMOperationExecutor(op); + return new DefaultOperationExecutor(op); + } + +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/locking/CGLockingInitializer.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/locking/CGLockingInitializer.java new file mode 100644 index 00000000..e6af62a0 --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/locking/CGLockingInitializer.java @@ -0,0 +1,16 @@ +package stmbench7.locking; + +import stmbench7.OperationExecutorFactory; +import stmbench7.impl.NoSynchronizationInitializer; + +/** + * An initializer for the coarse-grained locking + * thread synchronization. + */ +public class CGLockingInitializer extends NoSynchronizationInitializer { + + @Override + public OperationExecutorFactory createOperationExecutorFactory() { + return new CGLockingOperationExecutorFactory(); + } +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/locking/CGLockingOperationExecutor.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/locking/CGLockingOperationExecutor.java new file mode 100644 index 00000000..c37b0402 --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/locking/CGLockingOperationExecutor.java @@ -0,0 +1,64 @@ +package stmbench7.locking; + +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantReadWriteLock; + +import stmbench7.OperationExecutor; +import stmbench7.core.Operation; +import stmbench7.core.OperationFailedException; +import stmbench7.core.RuntimeError; + +public class CGLockingOperationExecutor implements OperationExecutor { + + private static final Lock globalReadLock, globalWriteLock; + private static int globalCounter = 0; + + static { + ReentrantReadWriteLock globalLock = new ReentrantReadWriteLock(true); + globalReadLock = globalLock.readLock(); + globalWriteLock = globalLock.writeLock(); + } + + private final Operation op; + private final Lock globalLock; + private int lastOperationTimestamp; + + public CGLockingOperationExecutor(Operation op) { + this.op = op; + if(op.getOperationId() == null) { + globalLock = null; + return; + } + + switch(op.getOperationId().getType()) { + case OPERATION_RO: + case SHORT_TRAVERSAL_RO: + case TRAVERSAL_RO: + globalLock = globalReadLock; + break; + case OPERATION: + case SHORT_TRAVERSAL: + case TRAVERSAL: + case STRUCTURAL_MODIFICATION: + globalLock = globalWriteLock; + break; + default: + throw new RuntimeError("Unexpected operation type"); + } + } + + public int execute() throws OperationFailedException { + try { + if(globalLock != null) globalLock.lock(); + return op.performOperation(); + } + finally { + lastOperationTimestamp = globalCounter++; + if(globalLock != null) globalLock.unlock(); + } + } + + public int getLastOperationTimestamp() { + return lastOperationTimestamp; + } +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/locking/CGLockingOperationExecutorFactory.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/locking/CGLockingOperationExecutorFactory.java new file mode 100644 index 00000000..1e58ad82 --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/locking/CGLockingOperationExecutorFactory.java @@ -0,0 +1,17 @@ +package stmbench7.locking; + +import stmbench7.OperationExecutor; +import stmbench7.OperationExecutorFactory; +import stmbench7.core.Operation; + +/** + * An implementation of the OperationExecutorFactory + * for the coarse-grained locking synchronization. + */ +public class CGLockingOperationExecutorFactory extends OperationExecutorFactory { + + @Override + public OperationExecutor createOperationExecutor(Operation op) { + return new CGLockingOperationExecutor(op); + } +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/locking/MGLockingComplexAssemblyImpl.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/locking/MGLockingComplexAssemblyImpl.java new file mode 100644 index 00000000..4f4ba2bf --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/locking/MGLockingComplexAssemblyImpl.java @@ -0,0 +1,50 @@ +package stmbench7.locking; + +import stmbench7.core.ComplexAssembly; +import stmbench7.core.Module; +import stmbench7.impl.core.ComplexAssemblyImpl; + +/** + * An implementation of the ComplexAssembly interface used in the + * medium-grained locking synchronization method. The complex + * assembly is locked for reading or writing by the methods that read + * or modify the object (except for cases when the required + * locking is done externally). + */ +public class MGLockingComplexAssemblyImpl extends ComplexAssemblyImpl { + + public MGLockingComplexAssemblyImpl(int id, String type, int buildDate, + Module module, ComplexAssembly superAssembly) { + super(id, type, buildDate, module, superAssembly); + } + + /* + * Methods "add/removeSubAssembly", "getSubAssemblies" and "clearPointers" + * assume global structure lock is held when those are called. Attributes + * "level", "superAssembly" and "module" can also be changed only when the + * global structure lock is held in write mode. + */ + + @Override + public int getBuildDate() { + MGLockingOperationExecutor.readLockAssemblyLevel(getLevel()); + return super.getBuildDate(); + } + + @Override + public void updateBuildDate() { + MGLockingOperationExecutor.writeLockAssemblyLevel(getLevel()); + super.updateBuildDate(); + } + + @Override + public void nullOperation() { + MGLockingOperationExecutor.readLockAssemblyLevel(getLevel()); + } + + @Override + public String getType() { + MGLockingOperationExecutor.readLockAssemblyLevel(getLevel()); + return super.getType(); + } +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/locking/MGLockingDesignObjFactory.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/locking/MGLockingDesignObjFactory.java new file mode 100644 index 00000000..371967ed --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/locking/MGLockingDesignObjFactory.java @@ -0,0 +1,22 @@ +package stmbench7.locking; + +import stmbench7.core.ComplexAssembly; +import stmbench7.core.Module; +import stmbench7.impl.core.DesignObjFactoryImpl; + +/** + * Implementation of the DesignObjFactory used in the medium-grained + * locking synchronization method. + */ +public class MGLockingDesignObjFactory extends DesignObjFactoryImpl { + + public MGLockingDesignObjFactory() { + super(); + } + + @Override + public ComplexAssembly createComplexAssembly(int id, String type, int buildDate, + Module module, ComplexAssembly superAssembly) { + return new MGLockingComplexAssemblyImpl(id, type, buildDate, module, superAssembly); + } +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/locking/MGLockingInitializer.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/locking/MGLockingInitializer.java new file mode 100644 index 00000000..176478b9 --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/locking/MGLockingInitializer.java @@ -0,0 +1,20 @@ +package stmbench7.locking; + +import stmbench7.OperationExecutorFactory; +import stmbench7.core.DesignObjFactory; +import stmbench7.impl.NoSynchronizationInitializer; + +/** + * An initializer for the medium-grained locking synchronization + * method. + */ +public class MGLockingInitializer extends NoSynchronizationInitializer { + + public DesignObjFactory createDesignObjFactory() { + return new MGLockingDesignObjFactory(); + } + + public OperationExecutorFactory createOperationExecutorFactory() { + return new MGLockingOperationExecutorFactory(); + } +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/locking/MGLockingOperationExecutor.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/locking/MGLockingOperationExecutor.java new file mode 100644 index 00000000..2b879b45 --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/locking/MGLockingOperationExecutor.java @@ -0,0 +1,316 @@ +package stmbench7.locking; + +import java.util.ArrayList; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantReadWriteLock; + +import stmbench7.OperationExecutor; +import stmbench7.OperationId; +import stmbench7.OperationType; +import stmbench7.Parameters; +import stmbench7.core.Operation; +import stmbench7.core.OperationFailedException; +import stmbench7.core.RuntimeError; + +/** + * Implementation of the OperationExecutor used by the medium-grained + * locking method. It implements externally most of the locking + * for each operation. The locks for each operation are predefined, + * except for some complex assembly locks that may be acquired + * by some complex assembly methods (see the MGLockingComplexAssemblyImpl + * class). + * + * Locking order: + *
    + *
  1. Global structure lock, + *
  2. Manual lock, + *
  3. Base assemblies lock, + *
  4. Composite parts lock, + *
  5. Documents lock, + *
  6. Atomic parts lock, + *
  7. Complex assemblies locks: starting from the highest level + * (Parameters.NumAssmLevels), down to the lowest level + * (BASE_ASSEMBLY_LEVEL + 1). + *
+ */ +public class MGLockingOperationExecutor implements OperationExecutor { + + private static final int BASE_ASSEMBLY_LEVEL = 1; + + /** + * Global structure lock is acquired by every operation: + *
    + *
  1. in write mode, if the operation modifies the data structure (i.e., + * adds or removes some elements) or modifies one of the indexes; and + *
  2. in read mode otherwise. + *
+ */ + private static final Lock globalStructureReadLock, + globalStructureWriteLock; + + /** + * Per-assembly-level locks. + */ + private static final ReentrantReadWriteLock[] assemblyLocks; + private static final Lock[] assemblyReadLocks, assemblyWriteLocks; + + /** + * Per-object-type locks. + */ + private static final Lock compositePartReadLock, compositePartWriteLock, + atomicPartReadLock, atomicPartWriteLock, documentReadLock, + documentWriteLock, manualReadLock, manualWriteLock; + + /** + * Used for generating timestamps for the replay log. + */ + private static final AtomicInteger globalCounter = new AtomicInteger(); + + /** + * Determines which per-assembly-level locks were acquired by the + * MGLockingComplexAssemblyImpl class. + */ + private static class AssemblyLocksAcquired { + public final boolean[] isReadAcquired, isWriteAcquired; + + public AssemblyLocksAcquired() { + isReadAcquired = new boolean[Parameters.NumAssmLevels + 1]; + isWriteAcquired = new boolean[Parameters.NumAssmLevels + 1]; + clear(); + } + + public void clear() { + for (int level = 0; level <= Parameters.NumAssmLevels; level++) { + isReadAcquired[level] = false; + isWriteAcquired[level] = false; + } + } + } + + private static final ThreadLocal assemblyLocksAcquired = + new ThreadLocal() { + @Override + protected AssemblyLocksAcquired initialValue() { + return new AssemblyLocksAcquired(); + } + }; + + static { + ReentrantReadWriteLock globalStructureLock = new ReentrantReadWriteLock( + false); + globalStructureReadLock = globalStructureLock.readLock(); + globalStructureWriteLock = globalStructureLock.writeLock(); + + assemblyLocks = new ReentrantReadWriteLock[Parameters.NumAssmLevels + 1]; + assemblyReadLocks = new Lock[Parameters.NumAssmLevels + 1]; + assemblyWriteLocks = new Lock[Parameters.NumAssmLevels + 1]; + for (int level = 1; level <= Parameters.NumAssmLevels; level++) { + assemblyLocks[level] = new ReentrantReadWriteLock(false); + assemblyReadLocks[level] = assemblyLocks[level].readLock(); + assemblyWriteLocks[level] = assemblyLocks[level].writeLock(); + } + ReentrantReadWriteLock compositePartLock = new ReentrantReadWriteLock( + false); + compositePartReadLock = compositePartLock.readLock(); + compositePartWriteLock = compositePartLock.writeLock(); + + ReentrantReadWriteLock atomicPartLock = new ReentrantReadWriteLock( + false); + atomicPartReadLock = atomicPartLock.readLock(); + atomicPartWriteLock = atomicPartLock.writeLock(); + + ReentrantReadWriteLock documentLock = new ReentrantReadWriteLock(false); + documentReadLock = documentLock.readLock(); + documentWriteLock = documentLock.writeLock(); + + ReentrantReadWriteLock manualLock = new ReentrantReadWriteLock(false); + manualReadLock = manualLock.readLock(); + manualWriteLock = manualLock.writeLock(); + } + + /** + * Called by a MGLockingComplexAssemblyImpl method to + * read-lock a given complex assembly level. + */ + public static void readLockAssemblyLevel(int level) { + AssemblyLocksAcquired threadAssemblyLocksAcquired = + assemblyLocksAcquired.get(); + if (threadAssemblyLocksAcquired.isReadAcquired[level] + || threadAssemblyLocksAcquired.isWriteAcquired[level]) + return; + + assemblyReadLocks[level].lock(); + threadAssemblyLocksAcquired.isReadAcquired[level] = true; + } + + /** + * Called by a MGLockingComplexAssemblyImpl method to + * write-lock a given complex assembly level. + */ + public static void writeLockAssemblyLevel(int level) { + AssemblyLocksAcquired threadAssemblyLocksAcquired = + assemblyLocksAcquired.get(); + if (threadAssemblyLocksAcquired.isWriteAcquired[level]) + return; + + assemblyWriteLocks[level].lock(); + threadAssemblyLocksAcquired.isWriteAcquired[level] = true; + } + + private final Operation op; + private final ArrayList locksToAcquire; + private int lastOperationTimestamp; + + public MGLockingOperationExecutor(Operation op) { + this.op = op; + + // Decide which locks should be acquired when a given + // operation is executed + locksToAcquire = new ArrayList(); + OperationId operationId = op.getOperationId(); + if(operationId == null) return; + OperationType operationType = operationId.getType(); + + // Structural modification operations: exclusive access + if (operationType == OperationType.STRUCTURAL_MODIFICATION) { + locksToAcquire.add(globalStructureWriteLock); + return; + } + + // Other operations: assume the structure is not modified + locksToAcquire.add(globalStructureReadLock); + + // Handling of individual cases + switch (op.getOperationId()) { + case T1: + case T6: + case Q7: + case ST1: + case ST9: + case OP1: + case OP2: + case OP3: + locksToAcquire.add(atomicPartReadLock); + break; + case T2a: + case T2b: + case T2c: + case T3a: + case T3b: + case T3c: + case ST6: + case ST10: + case OP9: + case OP10: + case OP15: + locksToAcquire.add(atomicPartWriteLock); + break; + + case T4: + case ST2: + locksToAcquire.add(documentReadLock); + break; + case T5: + case ST7: + locksToAcquire.add(documentWriteLock); + break; + + case Q6: + locksToAcquire.add(assemblyReadLocks[BASE_ASSEMBLY_LEVEL]); + locksToAcquire.add(compositePartReadLock); + // Pre-lock all assembly levels to avoid deadlocks + for (int level = Parameters.NumAssmLevels; level > 1; level--) + locksToAcquire.add(assemblyReadLocks[level]); + break; + + case ST3: + locksToAcquire.add(assemblyReadLocks[BASE_ASSEMBLY_LEVEL]); + // Pre-lock all assembly levels to avoid deadlocks + for (int level = Parameters.NumAssmLevels; level > 1; level--) + locksToAcquire.add(assemblyReadLocks[level]); + break; + + case ST4: + locksToAcquire.add(assemblyReadLocks[BASE_ASSEMBLY_LEVEL]); + locksToAcquire.add(documentReadLock); + break; + + case ST5: + locksToAcquire.add(assemblyReadLocks[BASE_ASSEMBLY_LEVEL]); + locksToAcquire.add(compositePartReadLock); + break; + + case ST8: + locksToAcquire.add(assemblyWriteLocks[BASE_ASSEMBLY_LEVEL]); + // Pre-lock all assembly levels to avoid deadlocks + for (int level = Parameters.NumAssmLevels; level > 1; level--) + locksToAcquire.add(assemblyWriteLocks[level]); + break; + + case OP4: + case OP5: + locksToAcquire.add(manualReadLock); + break; + + case OP6: + break; + + case OP7: + locksToAcquire.add(assemblyReadLocks[BASE_ASSEMBLY_LEVEL]); + break; + + case OP8: + locksToAcquire.add(compositePartReadLock); + break; + + case OP11: + locksToAcquire.add(manualWriteLock); + break; + + case OP12: + break; + + case OP13: + locksToAcquire.add(assemblyWriteLocks[BASE_ASSEMBLY_LEVEL]); + break; + + case OP14: + locksToAcquire.add(compositePartWriteLock); + break; + + default: + throw new RuntimeError("Unknown operation: " + + op.getOperationId().toString()); + } + } + + public int execute() throws OperationFailedException { + try { + + for (Lock lock : locksToAcquire) lock.lock(); + return op.performOperation(); + } + finally { + if (Parameters.sequentialReplayEnabled) + lastOperationTimestamp = globalCounter.getAndIncrement(); + + AssemblyLocksAcquired threadAssemblyLocksAcquired = + assemblyLocksAcquired.get(); + + for (int level = 1; level <= Parameters.NumAssmLevels; level++) { + if (threadAssemblyLocksAcquired.isReadAcquired[level]) + assemblyReadLocks[level].unlock(); + if (threadAssemblyLocksAcquired.isWriteAcquired[level]) + assemblyWriteLocks[level].unlock(); + } + threadAssemblyLocksAcquired.clear(); + + for (Lock lock : locksToAcquire) lock.unlock(); + } + } + + public int getLastOperationTimestamp() { + return lastOperationTimestamp; + } +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/locking/MGLockingOperationExecutorFactory.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/locking/MGLockingOperationExecutorFactory.java new file mode 100644 index 00000000..99231e44 --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/locking/MGLockingOperationExecutorFactory.java @@ -0,0 +1,17 @@ +package stmbench7.locking; + +import stmbench7.OperationExecutor; +import stmbench7.OperationExecutorFactory; +import stmbench7.core.Operation; + +/** + * An implementation of the OperationExecutorFactory + * for the medium-grained locking synchronization. + */ +public class MGLockingOperationExecutorFactory extends OperationExecutorFactory { + + @Override + public OperationExecutor createOperationExecutor(Operation op) { + return new MGLockingOperationExecutor(op); + } +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/BaseOperation.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/BaseOperation.java new file mode 100644 index 00000000..b505056d --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/BaseOperation.java @@ -0,0 +1,54 @@ +package stmbench7.operations; + +import stmbench7.OperationId; +import stmbench7.annotations.Transactional; +import stmbench7.annotations.Update; +import stmbench7.backend.BackendFactory; +import stmbench7.backend.Index; +import stmbench7.backend.LargeSet; +import stmbench7.core.AtomicPart; +import stmbench7.core.Operation; +import stmbench7.core.OperationFailedException; + +/** + * Base class for all the benchmark operations. + */ +public abstract class BaseOperation implements Operation { + + @Transactional + @Update + public abstract int performOperation() throws OperationFailedException; + + public abstract OperationId getOperationId(); + + /** + * The method of adding and AtomicPart to the AtomicPartBuildDateIndex is + * non-trivial and is used in a few places. That is why it is put here for + * later reuse. + * + * At first glance, it may seem more complicated than it is necessary, + * but that is because we want to use only locking implemented by + * an Index and Set implementations. + */ + public static void addAtomicPartToBuildDateIndex( + Index> atomicPartBuildDateIndex, + AtomicPart atomicPart) { + LargeSet newSet = BackendFactory.instance.createLargeSet(); + newSet.add(atomicPart); + LargeSet sameDateSet = + atomicPartBuildDateIndex.putIfAbsent(atomicPart.getBuildDate(), newSet); + if(sameDateSet != null) sameDateSet.add(atomicPart); + } + + /** + * The method of removing and AtomicPart from the AtomicPartBuildDateIndex is + * non-trivial and is used in a few places. That is why it is put here for + * later reuse. + */ + public static void removeAtomicPartFromBuildDateIndex( + Index> atomicPartBuildDateIndex, + AtomicPart atomicPart) { + LargeSet sameDateSet = atomicPartBuildDateIndex.get(atomicPart.getBuildDate()); + sameDateSet.remove(atomicPart); + } +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Operation10.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Operation10.java new file mode 100644 index 00000000..2e55b898 --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Operation10.java @@ -0,0 +1,35 @@ +package stmbench7.operations; + +import stmbench7.OperationId; +import stmbench7.Setup; +import stmbench7.annotations.Transactional; +import stmbench7.annotations.Update; +import stmbench7.core.AtomicPart; +import stmbench7.core.OperationFailedException; + +/** + * Operation OP10 (see the specification). + * Simple update, range query on index. + */ +public class Operation10 extends Query2 { + + public Operation10(Setup oo7setup) { + super(oo7setup, 1); + } + + @Override + @Transactional @Update + public int performOperation() throws OperationFailedException { + return super.performOperation(); + } + + @Override + protected void performOperationInAtomicPart(AtomicPart atomicPart) { + atomicPart.swapXY(); + } + + @Override + public OperationId getOperationId() { + return OperationId.OP10; + } +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Operation11.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Operation11.java new file mode 100644 index 00000000..37c239d8 --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Operation11.java @@ -0,0 +1,38 @@ +package stmbench7.operations; + +import stmbench7.OperationId; +import stmbench7.Setup; +import stmbench7.annotations.Transactional; +import stmbench7.annotations.Update; +import stmbench7.core.Manual; +import stmbench7.core.RuntimeError; + +/** + * Operation OP11 (see the specification). + * Simple update. + */ +public class Operation11 extends Traversal8 { + + public Operation11(Setup oo7setup) { + super(oo7setup); + } + + @Override + @Transactional @Update + public int performOperation() { + return super.performOperation(); + } + + @Override + protected int traverse(Manual manual) { + if(manual.startsWith('I')) return manual.replaceChar('I', 'i'); + if(manual.startsWith('i')) return manual.replaceChar('i', 'I'); + + throw new RuntimeError("OP11: unexpected Manual.text!"); + } + + @Override + public OperationId getOperationId() { + return OperationId.OP11; + } +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Operation12.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Operation12.java new file mode 100644 index 00000000..0e6926f8 --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Operation12.java @@ -0,0 +1,35 @@ +package stmbench7.operations; + +import stmbench7.OperationId; +import stmbench7.Setup; +import stmbench7.annotations.Transactional; +import stmbench7.annotations.Update; +import stmbench7.core.ComplexAssembly; +import stmbench7.core.OperationFailedException; + +/** + * Operation OP12 (see the specification). + * Simple update, search on index. + */ +public class Operation12 extends Operation6 { + + public Operation12(Setup oo7setup) { + super(oo7setup); + } + + @Override + @Transactional @Update + public int performOperation() throws OperationFailedException { + return super.performOperation(); + } + + @Override + protected void performOperationInComplexAssembly(ComplexAssembly assembly) { + assembly.updateBuildDate(); + } + + @Override + public OperationId getOperationId() { + return OperationId.OP12; + } +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Operation13.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Operation13.java new file mode 100644 index 00000000..d4d99914 --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Operation13.java @@ -0,0 +1,35 @@ +package stmbench7.operations; + +import stmbench7.OperationId; +import stmbench7.Setup; +import stmbench7.annotations.Transactional; +import stmbench7.annotations.Update; +import stmbench7.core.BaseAssembly; +import stmbench7.core.OperationFailedException; + +/** + * Operation OP13 (see the specification). + * Simple update, search on index. + */ +public class Operation13 extends Operation7 { + + public Operation13(Setup oo7setup) { + super(oo7setup); + } + + @Override + @Transactional @Update + public int performOperation() throws OperationFailedException { + return super.performOperation(); + } + + @Override + protected void performOperationInBaseAssembly(BaseAssembly assembly) { + assembly.updateBuildDate(); + } + + @Override + public OperationId getOperationId() { + return OperationId.OP13; + } +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Operation14.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Operation14.java new file mode 100644 index 00000000..6da9d7c7 --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Operation14.java @@ -0,0 +1,35 @@ +package stmbench7.operations; + +import stmbench7.OperationId; +import stmbench7.Setup; +import stmbench7.annotations.Transactional; +import stmbench7.annotations.Update; +import stmbench7.core.CompositePart; +import stmbench7.core.OperationFailedException; + +/** + * Operation OP14 (see the specification). + * Simple update, search on index. + */ +public class Operation14 extends Operation8 { + + public Operation14(Setup oo7setup) { + super(oo7setup); + } + + @Override + @Transactional @Update + public int performOperation() throws OperationFailedException { + return super.performOperation(); + } + + @Override + protected void performOperationInComponent(CompositePart component) { + component.updateBuildDate(); + } + + @Override + public OperationId getOperationId() { + return OperationId.OP14; + } +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Operation15.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Operation15.java new file mode 100644 index 00000000..82bbc8f8 --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Operation15.java @@ -0,0 +1,42 @@ +package stmbench7.operations; + +import stmbench7.OperationId; +import stmbench7.Setup; +import stmbench7.annotations.Transactional; +import stmbench7.annotations.Update; +import stmbench7.backend.Index; +import stmbench7.backend.LargeSet; +import stmbench7.core.AtomicPart; +import stmbench7.core.OperationFailedException; + +/** + * Operation OP15 (see the specification). + * Simple update, search and update on index. + */ +public class Operation15 extends Query1 { + + protected Index> partBuildDateIndex; + + public Operation15(Setup oo7setup) { + super(oo7setup); + this.partBuildDateIndex = oo7setup.getAtomicPartBuildDateIndex(); + } + + @Override + @Transactional @Update + public int performOperation() throws OperationFailedException { + return super.performOperation(); + } + + @Override + protected void performOperationInAtomicPart(AtomicPart atomicPart) { + removeAtomicPartFromBuildDateIndex(partBuildDateIndex, atomicPart); + atomicPart.updateBuildDate(); + addAtomicPartToBuildDateIndex(partBuildDateIndex, atomicPart); + } + + @Override + public OperationId getOperationId() { + return OperationId.OP15; + } +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Operation6.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Operation6.java new file mode 100644 index 00000000..0d13d52f --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Operation6.java @@ -0,0 +1,56 @@ +package stmbench7.operations; + +import stmbench7.OperationId; +import stmbench7.Parameters; +import stmbench7.Setup; +import stmbench7.ThreadRandom; +import stmbench7.annotations.ReadOnly; +import stmbench7.annotations.Transactional; +import stmbench7.backend.Index; +import stmbench7.core.Assembly; +import stmbench7.core.ComplexAssembly; +import stmbench7.core.OperationFailedException; + +/** + * Operation OP6 (see the specification). + * Read-only, search on index. + */ +public class Operation6 extends BaseOperation { + + protected Index complexAssemblyIdIndex; + + public Operation6(Setup oo7setup) { + this.complexAssemblyIdIndex = oo7setup.getComplexAssemblyIdIndex(); + } + + @Override + @Transactional @ReadOnly + public int performOperation() throws OperationFailedException { + int complexAssemblyId = ThreadRandom.nextInt(Parameters.MaxComplexAssemblies) +1; + ComplexAssembly complexAssembly = complexAssemblyIdIndex.get(complexAssemblyId); + if(complexAssembly == null) throw new OperationFailedException(); + + ComplexAssembly superAssembly = complexAssembly.getSuperAssembly(); + if(superAssembly == null) { + performOperationInComplexAssembly((ComplexAssembly)complexAssembly); + return 1; + } + + int count = 0; + for(Assembly siblingAssembly : superAssembly.getSubAssemblies()) { + performOperationInComplexAssembly((ComplexAssembly)siblingAssembly); + count++; + } + + return count; + } + + protected void performOperationInComplexAssembly(ComplexAssembly assembly) { + assembly.nullOperation(); + } + + @Override + public OperationId getOperationId() { + return OperationId.OP6; + } +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Operation7.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Operation7.java new file mode 100644 index 00000000..ac6b693c --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Operation7.java @@ -0,0 +1,53 @@ +package stmbench7.operations; + +import stmbench7.OperationId; +import stmbench7.Parameters; +import stmbench7.Setup; +import stmbench7.ThreadRandom; +import stmbench7.annotations.ReadOnly; +import stmbench7.annotations.Transactional; +import stmbench7.backend.Index; +import stmbench7.core.Assembly; +import stmbench7.core.BaseAssembly; +import stmbench7.core.ComplexAssembly; +import stmbench7.core.OperationFailedException; + +/** + * Operation OP7 (see the specification). + * Read-only, search on index. + */ +public class Operation7 extends BaseOperation { + + protected Index baseAssemblyIdIndex; + + public Operation7(Setup oo7setup) { + this.baseAssemblyIdIndex = oo7setup.getBaseAssemblyIdIndex(); + } + + @Override + @Transactional @ReadOnly + public int performOperation() throws OperationFailedException { + int baseAssemblyId = ThreadRandom.nextInt(Parameters.MaxBaseAssemblies) +1; + BaseAssembly baseAssembly = baseAssemblyIdIndex.get(baseAssemblyId); + if(baseAssembly == null) throw new OperationFailedException(); + + ComplexAssembly superAssembly = baseAssembly.getSuperAssembly(); + + int count = 0; + for(Assembly siblingAssembly : superAssembly.getSubAssemblies()) { + performOperationInBaseAssembly((BaseAssembly)siblingAssembly); + count++; + } + + return count; + } + + protected void performOperationInBaseAssembly(BaseAssembly assembly) { + assembly.nullOperation(); + } + + @Override + public OperationId getOperationId() { + return OperationId.OP7; + } +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Operation8.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Operation8.java new file mode 100644 index 00000000..b9f6ba1f --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Operation8.java @@ -0,0 +1,50 @@ +package stmbench7.operations; + +import stmbench7.OperationId; +import stmbench7.Parameters; +import stmbench7.Setup; +import stmbench7.ThreadRandom; +import stmbench7.annotations.ReadOnly; +import stmbench7.annotations.Transactional; +import stmbench7.backend.Index; +import stmbench7.core.BaseAssembly; +import stmbench7.core.CompositePart; +import stmbench7.core.OperationFailedException; + +/** + * Operation OP8 (see the specification). + * Read-only, search on index. + */ +public class Operation8 extends BaseOperation { + + protected Index baseAssemblyIdIndex; + + public Operation8(Setup oo7setup) { + this.baseAssemblyIdIndex = oo7setup.getBaseAssemblyIdIndex(); + } + + @Override + @Transactional @ReadOnly + public int performOperation() throws OperationFailedException { + int baseAssemblyId = ThreadRandom.nextInt(Parameters.MaxBaseAssemblies) +1; + BaseAssembly baseAssembly = baseAssemblyIdIndex.get(baseAssemblyId); + if(baseAssembly == null) throw new OperationFailedException(); + + int count = 0; + for(CompositePart component : baseAssembly.getComponents()) { + performOperationInComponent(component); + count++; + } + + return count; + } + + protected void performOperationInComponent(CompositePart component) { + component.nullOperation(); + } + + @Override + public OperationId getOperationId() { + return OperationId.OP8; + } +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Operation9.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Operation9.java new file mode 100644 index 00000000..a3031253 --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Operation9.java @@ -0,0 +1,35 @@ +package stmbench7.operations; + +import stmbench7.OperationId; +import stmbench7.Setup; +import stmbench7.annotations.Transactional; +import stmbench7.annotations.Update; +import stmbench7.core.AtomicPart; +import stmbench7.core.OperationFailedException; + +/** + * Operation OP9 (see the specification). + * Simple update, search on index. + */ +public class Operation9 extends Query1 { + + public Operation9(Setup oo7setup) { + super(oo7setup); + } + + @Override + @Transactional @Update + public int performOperation() throws OperationFailedException { + return super.performOperation(); + } + + @Override + protected void performOperationInAtomicPart(AtomicPart atomicPart) { + atomicPart.swapXY(); + } + + @Override + public OperationId getOperationId() { + return OperationId.OP9; + } +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Query1.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Query1.java new file mode 100644 index 00000000..df5082ca --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Query1.java @@ -0,0 +1,51 @@ +package stmbench7.operations; + +import stmbench7.OperationId; +import stmbench7.Parameters; +import stmbench7.Setup; +import stmbench7.ThreadRandom; +import stmbench7.annotations.ReadOnly; +import stmbench7.annotations.Transactional; +import stmbench7.backend.Index; +import stmbench7.core.AtomicPart; +import stmbench7.core.OperationFailedException; + +/** + * Query Q1 / Operation OP1 (see the specification). + * Read-only, search on index. + */ +public class Query1 extends BaseOperation { + + Index partIdIndex; + + public Query1(Setup oo7setup) { + this.partIdIndex = oo7setup.getAtomicPartIdIndex(); + } + + @Override + @Transactional @ReadOnly + public int performOperation() throws OperationFailedException { + int count = 0; + + for(int i = 0; i < 10; i++) { + int partId = ThreadRandom.nextInt(Parameters.MaxAtomicParts) + 1; + AtomicPart part = partIdIndex.get(partId); + + if(part == null) continue; + + performOperationInAtomicPart(part); + count++; + } + + return count; + } + + protected void performOperationInAtomicPart(AtomicPart atomicPart) { + atomicPart.nullOperation(); + } + + @Override + public OperationId getOperationId() { + return OperationId.OP1; + } +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Query2.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Query2.java new file mode 100644 index 00000000..c5dc259f --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Query2.java @@ -0,0 +1,57 @@ +package stmbench7.operations; + +import stmbench7.OperationId; +import stmbench7.Parameters; +import stmbench7.Setup; +import stmbench7.annotations.ReadOnly; +import stmbench7.annotations.Transactional; +import stmbench7.backend.Index; +import stmbench7.backend.LargeSet; +import stmbench7.core.AtomicPart; +import stmbench7.core.OperationFailedException; + +/** + * Query Q2 / Operation OP2 (see the specification). + * Read-only, range query on index. + */ +public class Query2 extends BaseOperation { + + protected Index> partBuildDateIndex; + protected Integer minAtomicDate, maxAtomicDate; + + public Query2(Setup oo7setup) { + this(oo7setup, 1); + } + + protected Query2(Setup oo7setup, int percent) { + this.partBuildDateIndex = oo7setup.getAtomicPartBuildDateIndex(); + this.maxAtomicDate = Parameters.MaxAtomicDate; + this.minAtomicDate = Parameters.MaxAtomicDate - + percent * (Parameters.MaxAtomicDate - Parameters.MinAtomicDate) / 100; + } + + @Override + @Transactional @ReadOnly + public int performOperation() throws OperationFailedException { + Iterable> partSets = partBuildDateIndex.getRange(minAtomicDate, maxAtomicDate); + int count = 0; + + for(LargeSet partSet : partSets) { + for(AtomicPart part : partSet) { + performOperationInAtomicPart(part); + count++; + } + } + + return count; + } + + protected void performOperationInAtomicPart(AtomicPart atomicPart) { + atomicPart.nullOperation(); + } + + @Override + public OperationId getOperationId() { + return OperationId.OP2; + } +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Query3.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Query3.java new file mode 100644 index 00000000..8ad70c66 --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Query3.java @@ -0,0 +1,20 @@ +package stmbench7.operations; + +import stmbench7.OperationId; +import stmbench7.Setup; + +/** + * Query Q3 / Operation OP3 (see the specification). + * Read-only, range query on index. + */ +public class Query3 extends Query2 { + + public Query3(Setup oo7setup) { + super(oo7setup, 10); + } + + @Override + public OperationId getOperationId() { + return OperationId.OP3; + } +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Query4.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Query4.java new file mode 100644 index 00000000..2b9ca7b5 --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Query4.java @@ -0,0 +1,52 @@ +package stmbench7.operations; + +import stmbench7.OperationId; +import stmbench7.Parameters; +import stmbench7.Setup; +import stmbench7.ThreadRandom; +import stmbench7.annotations.ReadOnly; +import stmbench7.annotations.Transactional; +import stmbench7.backend.Index; +import stmbench7.core.BaseAssembly; +import stmbench7.core.Document; +import stmbench7.core.OperationFailedException; + +/** + * Query Q4 / Short traversal ST4 (see the specification). + * Read-only, search on index, short. + */ +public class Query4 extends BaseOperation { + + Index documentTitleIndex; + + public Query4(Setup oo7setup) { + this.documentTitleIndex = oo7setup.getDocumentTitleIndex(); + } + + @Override + @Transactional @ReadOnly + public int performOperation() throws OperationFailedException { + int result = 0; + + for(int i = 0; i < 100; i++) { + int partId = ThreadRandom.nextInt(Parameters.MaxCompParts) + 1; + String docTitle = "Composite Part #" + partId; + + Document document = documentTitleIndex.get(docTitle); + if(document == null) continue; + + for(BaseAssembly assembly : document.getCompositePart().getUsedIn()) { + assembly.nullOperation(); + result++; + } + } + + return result; + } + + @Override + public OperationId getOperationId() { + return OperationId.ST4; + } +} + diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Query5.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Query5.java new file mode 100644 index 00000000..bf7c11c3 --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Query5.java @@ -0,0 +1,52 @@ +package stmbench7.operations; + +import stmbench7.OperationId; +import stmbench7.Setup; +import stmbench7.annotations.ReadOnly; +import stmbench7.annotations.Transactional; +import stmbench7.backend.Index; +import stmbench7.core.BaseAssembly; +import stmbench7.core.CompositePart; + +/** + * Query Q5 / Short traversal ST5 (see the specification). + * Read-only, iterate on index, short. + */ +public class Query5 extends BaseOperation { + + protected Index baseAssemblyIdIndex; + + public Query5(Setup oo7setup) { + this.baseAssemblyIdIndex = oo7setup.getBaseAssemblyIdIndex(); + } + + @Override + @Transactional @ReadOnly + public int performOperation() { + int result = 0; + + for(BaseAssembly assembly : baseAssemblyIdIndex) { + result += checkBaseAssembly(assembly); + } + + return result; + } + + protected int checkBaseAssembly(BaseAssembly assembly) { + int assBuildDate = assembly.getBuildDate(); + + for(CompositePart part : assembly.getComponents()) { + if(part.getBuildDate() > assBuildDate) { + assembly.nullOperation(); + return 1; + } + } + + return 0; + } + + @Override + public OperationId getOperationId() { + return OperationId.ST5; + } +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Query6.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Query6.java new file mode 100644 index 00000000..5e978789 --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Query6.java @@ -0,0 +1,55 @@ +package stmbench7.operations; + +import stmbench7.OperationId; +import stmbench7.Setup; +import stmbench7.annotations.ReadOnly; +import stmbench7.annotations.Transactional; +import stmbench7.core.Assembly; +import stmbench7.core.BaseAssembly; +import stmbench7.core.ComplexAssembly; +import stmbench7.core.Module; + +/** + * Query Q6 (see the specification). Read-only, long traversal. + */ +public class Query6 extends Query5 { + + protected Module module; + + public Query6(Setup oo7setup) { + super(oo7setup); + this.module = oo7setup.getModule(); + } + + @Override + @Transactional + @ReadOnly + public int performOperation() { + return checkComplexAssembly(module.getDesignRoot()); + } + + protected int checkAssembly(Assembly assembly) { + if (assembly instanceof BaseAssembly) + return checkBaseAssembly((BaseAssembly) assembly); + else + return checkComplexAssembly((ComplexAssembly) assembly); + } + + protected int checkComplexAssembly(ComplexAssembly assembly) { + int result = 0; + + for (Assembly subAssembly : assembly.getSubAssemblies()) + result += checkAssembly(subAssembly); + + if (result == 0) + return 0; + + assembly.nullOperation(); + return result + 1; + } + + @Override + public OperationId getOperationId() { + return OperationId.Q6; + } +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Query7.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Query7.java new file mode 100644 index 00000000..045350d0 --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Query7.java @@ -0,0 +1,37 @@ +package stmbench7.operations; + +import stmbench7.OperationId; +import stmbench7.Setup; +import stmbench7.annotations.ReadOnly; +import stmbench7.annotations.Transactional; +import stmbench7.backend.Index; +import stmbench7.core.AtomicPart; + +/** + * Query Q7 (see the specification). + * Read-only, iterate on index, long. + */ +public class Query7 extends BaseOperation { + + protected Index partIdIndex; + + public Query7(Setup oo7setup) { + this.partIdIndex = oo7setup.getAtomicPartIdIndex(); + } + + @Override + @Transactional @ReadOnly + public int performOperation() { + int result = 0; + for(AtomicPart part : partIdIndex) { + part.nullOperation(); + result++; + } + return result; + } + + @Override + public OperationId getOperationId() { + return OperationId.Q7; + } +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/SetupDataStructure.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/SetupDataStructure.java new file mode 100644 index 00000000..b9a1b4e5 --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/SetupDataStructure.java @@ -0,0 +1,74 @@ +package stmbench7.operations; + +import stmbench7.OperationId; +import stmbench7.Parameters; +import stmbench7.Setup; +import stmbench7.ThreadRandom; +import stmbench7.annotations.Update; +import stmbench7.core.BaseAssembly; +import stmbench7.core.CompositePart; +import stmbench7.core.CompositePartBuilder; +import stmbench7.core.Module; +import stmbench7.core.Operation; +import stmbench7.core.OperationFailedException; +import stmbench7.core.RuntimeError; + +/** + * An operation that initializes the benchmark data structure. + */ +public class SetupDataStructure implements Operation { + + private final Setup setup; + private Module module; + + public SetupDataStructure(Setup setup) { + this.setup = setup; + } + + @Update + public int performOperation() throws OperationFailedException { + System.err.println("Setting up the design library:"); + CompositePart designLibrary[] = new CompositePart[Parameters.InitialTotalCompParts]; + CompositePartBuilder compositePartBuilder = setup.getCompositePartBuilder(); + + for(int i = 0; i < Parameters.InitialTotalCompParts; i++) { + System.err.print("Component " + (i+1) + " of " + Parameters.InitialTotalCompParts + "\r"); + try { + designLibrary[i] = compositePartBuilder.createAndRegisterCompositePart(); + } + catch(OperationFailedException e) { + throw new RuntimeError("Unexpected failure of createAndRegisterCompositePart!", e); + } + } + System.err.println(); + + System.err.println("Setting up the module:"); + try { + module = setup.getModuleBuilder().createRegisterModule(); + } + catch(OperationFailedException e) { + throw new RuntimeError("Unexpected failure of createRegisterModule!", e); + } + + int i = 1; + for(BaseAssembly baseAssembly : setup.getBaseAssemblyIdIndex()) { + System.err.print("Base Assembly " + (i++) + " of " + Parameters.InitialTotalBaseAssemblies + "\r"); + + for(int connections = 0; connections < Parameters.NumCompPerAssm; connections++) { + int compositePartNum = ThreadRandom.nextInt(designLibrary.length); + baseAssembly.addComponent(designLibrary[compositePartNum]); + } + } + System.err.println(); + + return 0; + } + + public OperationId getOperationId() { + return null; + } + + public Module getModule() { + return module; + } +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/ShortTraversal1.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/ShortTraversal1.java new file mode 100644 index 00000000..f53b530e --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/ShortTraversal1.java @@ -0,0 +1,95 @@ +package stmbench7.operations; + +import stmbench7.OperationId; +import stmbench7.Setup; +import stmbench7.ThreadRandom; +import stmbench7.annotations.ReadOnly; +import stmbench7.annotations.Transactional; +import stmbench7.backend.ImmutableCollection; +import stmbench7.backend.LargeSet; +import stmbench7.core.Assembly; +import stmbench7.core.AtomicPart; +import stmbench7.core.BaseAssembly; +import stmbench7.core.ComplexAssembly; +import stmbench7.core.CompositePart; +import stmbench7.core.Module; +import stmbench7.core.OperationFailedException; +import stmbench7.core.RuntimeError; + +/** + * Short traversal ST1 (see the specification). + * Read-only, short. + */ +public class ShortTraversal1 extends BaseOperation { + + protected Module module; + + public ShortTraversal1(Setup oo7setup) { + this.module = oo7setup.getModule(); + } + + @Override + @Transactional @ReadOnly + public int performOperation() throws OperationFailedException { + ComplexAssembly designRoot = module.getDesignRoot(); + return traverse(designRoot); + } + + protected int traverse(Assembly assembly) throws OperationFailedException { + if(assembly instanceof ComplexAssembly) return traverse((ComplexAssembly)assembly); + else return traverse((BaseAssembly)assembly); + } + + protected int traverse(ComplexAssembly complexAssembly) throws OperationFailedException { + ImmutableCollection subAssemblies = complexAssembly.getSubAssemblies(); + int numOfSubAssemblies = subAssemblies.size(); + int nextAssembly = ThreadRandom.nextInt(numOfSubAssemblies); + + int subAssemblyNumber = 0; + for(Assembly subAssembly : subAssemblies) { + if(subAssemblyNumber == nextAssembly) return traverse(subAssembly); + subAssemblyNumber++; + } + + throw new RuntimeError("ST1: size of ComplexAssemby.subAssemblies has changed!"); + } + + protected int traverse(BaseAssembly baseAssembly) throws OperationFailedException { + ImmutableCollection components = baseAssembly.getComponents(); + int numOfComponents = components.size(); + if(numOfComponents == 0) throw new OperationFailedException(); + + int nextComponent = ThreadRandom.nextInt(numOfComponents); + + int componentNumber = 0; + for(CompositePart component : components) { + if(componentNumber == nextComponent) return traverse(component); + componentNumber++; + } + + throw new RuntimeError("ST1: size of BaseAssembly.components has changed!"); + } + + protected int traverse(CompositePart component) { + LargeSet atomicParts = component.getParts(); + int numOfAtomicParts = atomicParts.size(); + int nextAtomicPart = ThreadRandom.nextInt(numOfAtomicParts); + + int atomicPartNumber = 0; + for(AtomicPart atomicPart : atomicParts) { + if(atomicPartNumber == nextAtomicPart) return traverse(atomicPart); + atomicPartNumber++; + } + + throw new RuntimeError("ST1: illegal size of CompositePart.parts!"); + } + + protected int traverse(AtomicPart atomicPart) { + return atomicPart.getX() + atomicPart.getY(); + } + + @Override + public OperationId getOperationId() { + return OperationId.ST1; + } +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/ShortTraversal10.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/ShortTraversal10.java new file mode 100644 index 00000000..eb8fee67 --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/ShortTraversal10.java @@ -0,0 +1,36 @@ +package stmbench7.operations; + +import stmbench7.OperationId; +import stmbench7.Setup; +import stmbench7.annotations.Transactional; +import stmbench7.annotations.Update; +import stmbench7.core.AtomicPart; +import stmbench7.core.OperationFailedException; + +/** + * Short traversal ST10 (see the specification). + * Simple update, short. + */ +public class ShortTraversal10 extends ShortTraversal9 { + + public ShortTraversal10(Setup oo7setup) { + super(oo7setup); + } + + @Override + @Transactional @Update + public int performOperation() throws OperationFailedException { + return super.performOperation(); + } + + @Override + protected int performOperationInAtomicPart(AtomicPart part) { + part.swapXY(); + return 1; + } + + @Override + public OperationId getOperationId() { + return OperationId.ST10; + } +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/ShortTraversal2.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/ShortTraversal2.java new file mode 100644 index 00000000..413d0fdc --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/ShortTraversal2.java @@ -0,0 +1,39 @@ +package stmbench7.operations; + +import stmbench7.OperationId; +import stmbench7.Setup; +import stmbench7.core.AtomicPart; +import stmbench7.core.CompositePart; +import stmbench7.core.Document; +import stmbench7.core.RuntimeError; + +/** + * Short traversal ST2 (see the specification). + * Read-only, short. + */ +public class ShortTraversal2 extends ShortTraversal1 { + + public ShortTraversal2(Setup oo7setup) { + super(oo7setup); + } + + @Override + protected int traverse(CompositePart component) { + Document documentation = component.getDocumentation(); + return traverse(documentation); + } + + protected int traverse(Document documentation) { + return documentation.searchText('I'); + } + + @Override + protected int traverse(AtomicPart atomicPart) { + throw new RuntimeError("ST2: unexpected call to traverse(AtomicPart)!"); + } + + @Override + public OperationId getOperationId() { + return OperationId.ST2; + } +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/ShortTraversal6.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/ShortTraversal6.java new file mode 100644 index 00000000..97f6009b --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/ShortTraversal6.java @@ -0,0 +1,36 @@ +package stmbench7.operations; + +import stmbench7.OperationId; +import stmbench7.Setup; +import stmbench7.annotations.Transactional; +import stmbench7.annotations.Update; +import stmbench7.core.AtomicPart; +import stmbench7.core.OperationFailedException; + +/** + * Short traversal ST6 (see the specification). + * Simple update, short. + */ +public class ShortTraversal6 extends ShortTraversal1 { + + public ShortTraversal6(Setup oo7setup) { + super(oo7setup); + } + + @Override + @Transactional @Update + public int performOperation() throws OperationFailedException { + return super.performOperation(); + } + + @Override + protected int traverse(AtomicPart atomicPart) { + atomicPart.swapXY(); + return super.traverse(atomicPart); + } + + @Override + public OperationId getOperationId() { + return OperationId.ST6; + } +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/ShortTraversal7.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/ShortTraversal7.java new file mode 100644 index 00000000..0e66faba --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/ShortTraversal7.java @@ -0,0 +1,39 @@ +package stmbench7.operations; + +import stmbench7.OperationId; +import stmbench7.Setup; +import stmbench7.annotations.Transactional; +import stmbench7.annotations.Update; +import stmbench7.core.Document; +import stmbench7.core.OperationFailedException; +import stmbench7.core.RuntimeError; + +/** + * Short traversal ST7 (see the specification). + * Simple update, short. + */ +public class ShortTraversal7 extends ShortTraversal2 { + + public ShortTraversal7(Setup oo7setup) { + super(oo7setup); + } + + @Override + @Transactional @Update + public int performOperation() throws OperationFailedException { + return super.performOperation(); + } + + @Override + protected int traverse(Document documentation) { + if(documentation.textBeginsWith("I am")) return documentation.replaceText("I am", "This is"); + if(documentation.textBeginsWith("This is")) return documentation.replaceText("This is", "I am"); + + throw new RuntimeError("ST7: unexpected beginning of Document.text!"); + } + + @Override + public OperationId getOperationId() { + return OperationId.ST7; + } +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/ShortTraversal8.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/ShortTraversal8.java new file mode 100644 index 00000000..99511321 --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/ShortTraversal8.java @@ -0,0 +1,35 @@ +package stmbench7.operations; + +import stmbench7.OperationId; +import stmbench7.Setup; +import stmbench7.annotations.Transactional; +import stmbench7.annotations.Update; +import stmbench7.core.Assembly; +import stmbench7.core.OperationFailedException; + +/** + * Short traversal ST8 (see the specification). + * Indexed update, short. + */ +public class ShortTraversal8 extends Traversal7 { + + public ShortTraversal8(Setup oo7setup) { + super(oo7setup); + } + + @Override + @Transactional @Update + public int performOperation() throws OperationFailedException { + return super.performOperation(); + } + + @Override + protected void performOperationOnAssembly(Assembly assembly) { + assembly.updateBuildDate(); + } + + @Override + public OperationId getOperationId() { + return OperationId.ST8; + } +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/ShortTraversal9.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/ShortTraversal9.java new file mode 100644 index 00000000..14681785 --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/ShortTraversal9.java @@ -0,0 +1,56 @@ +package stmbench7.operations; + +import java.util.HashSet; + +import stmbench7.OperationId; +import stmbench7.Setup; +import stmbench7.core.AtomicPart; +import stmbench7.core.CompositePart; +import stmbench7.core.Connection; +import stmbench7.core.RuntimeError; + +/** + * Short traversal ST9 (see the specification). + * Read-only, short. + */ +public class ShortTraversal9 extends ShortTraversal1 { + + public ShortTraversal9(Setup oo7setup) { + super(oo7setup); + } + + @Override + protected int traverse(CompositePart component) { + HashSet setOfVisitedPartIds = new HashSet(); + return traverse(component.getRootPart(), setOfVisitedPartIds); + } + + protected int traverse(AtomicPart atomicPart, HashSet setOfVisitedPartIds) { + if(atomicPart == null) return 0; + if(setOfVisitedPartIds.contains(atomicPart)) return 0; + + int result = performOperationInAtomicPart(atomicPart); + + setOfVisitedPartIds.add(atomicPart); + + for(Connection connection : atomicPart.getToConnections()) + result += traverse(connection.getDestination(), setOfVisitedPartIds); + + return result; + } + + protected int performOperationInAtomicPart(AtomicPart part) { + part.nullOperation(); + return 1; + } + + @Override + protected int traverse(AtomicPart atomicPart) { + throw new RuntimeError("ST9: unexpected call to traverse(AtomicPart)!"); + } + + @Override + public OperationId getOperationId() { + return OperationId.ST9; + } +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/StructuralModification1.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/StructuralModification1.java new file mode 100644 index 00000000..73eb81c0 --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/StructuralModification1.java @@ -0,0 +1,32 @@ +package stmbench7.operations; + +import stmbench7.OperationId; +import stmbench7.Setup; +import stmbench7.annotations.Transactional; +import stmbench7.annotations.Update; +import stmbench7.core.CompositePartBuilder; +import stmbench7.core.OperationFailedException; + +/** + * Structural modification operation SM1 (see the specification). + */ +public class StructuralModification1 extends BaseOperation { + + protected CompositePartBuilder compositePartBuilder; + + public StructuralModification1(Setup oo7setup) { + compositePartBuilder = oo7setup.getCompositePartBuilder(); + } + + @Override + @Transactional @Update + public int performOperation() throws OperationFailedException { + compositePartBuilder.createAndRegisterCompositePart(); + return 0; + } + + @Override + public OperationId getOperationId() { + return OperationId.SM1; + } +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/StructuralModification2.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/StructuralModification2.java new file mode 100644 index 00000000..af59fa09 --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/StructuralModification2.java @@ -0,0 +1,41 @@ +package stmbench7.operations; + +import stmbench7.OperationId; +import stmbench7.Parameters; +import stmbench7.Setup; +import stmbench7.ThreadRandom; +import stmbench7.annotations.Transactional; +import stmbench7.annotations.Update; +import stmbench7.backend.Index; +import stmbench7.core.CompositePart; +import stmbench7.core.OperationFailedException; + +/** + * Structural modification operation SM2 (see the specification). + */ +public class StructuralModification2 extends StructuralModification1 { + + protected Index compositePartIdIndex; + + public StructuralModification2(Setup oo7setup) { + + super(oo7setup); + this.compositePartIdIndex = oo7setup.getCompositePartIdIndex(); + } + + @Override + @Transactional @Update + public int performOperation() throws OperationFailedException { + int partToRemoveId = ThreadRandom.nextInt(Parameters.MaxCompParts) + 1; + CompositePart partToRemove = compositePartIdIndex.get(partToRemoveId); + if(partToRemove == null) throw new OperationFailedException(); + + compositePartBuilder.unregisterAndRecycleCompositePart(partToRemove); + return 0; + } + + @Override + public OperationId getOperationId() { + return OperationId.SM2; + } +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/StructuralModification3.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/StructuralModification3.java new file mode 100644 index 00000000..a5d8024a --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/StructuralModification3.java @@ -0,0 +1,47 @@ +package stmbench7.operations; + +import stmbench7.OperationId; +import stmbench7.Parameters; +import stmbench7.Setup; +import stmbench7.ThreadRandom; +import stmbench7.annotations.Transactional; +import stmbench7.annotations.Update; +import stmbench7.backend.Index; +import stmbench7.core.BaseAssembly; +import stmbench7.core.CompositePart; +import stmbench7.core.OperationFailedException; + +/** + * Structural modification operation SM3 (see the specification). + */ +public class StructuralModification3 extends BaseOperation { + + protected Index baseAssemblyIdIndex; + protected Index compositePartIdIndex; + + public StructuralModification3(Setup oo7setup) { + + this.baseAssemblyIdIndex = oo7setup.getBaseAssemblyIdIndex(); + this.compositePartIdIndex = oo7setup.getCompositePartIdIndex(); + } + + @Override + @Transactional @Update + public int performOperation() throws OperationFailedException { + int baseAssemblyId = ThreadRandom.nextInt(Parameters.MaxBaseAssemblies) + 1; + int componentId = ThreadRandom.nextInt(Parameters.MaxCompParts) + 1; + BaseAssembly baseAssembly = baseAssemblyIdIndex.get(baseAssemblyId); + CompositePart component = compositePartIdIndex.get(componentId); + + if(baseAssembly == null || component == null) throw new OperationFailedException(); + + baseAssembly.addComponent(component); + + return 0; + } + + @Override + public OperationId getOperationId() { + return OperationId.SM3; + } +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/StructuralModification4.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/StructuralModification4.java new file mode 100644 index 00000000..bfa8a732 --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/StructuralModification4.java @@ -0,0 +1,56 @@ +package stmbench7.operations; + +import stmbench7.OperationId; +import stmbench7.Parameters; +import stmbench7.Setup; +import stmbench7.ThreadRandom; +import stmbench7.annotations.Transactional; +import stmbench7.annotations.Update; +import stmbench7.backend.ImmutableCollection; +import stmbench7.backend.Index; +import stmbench7.core.BaseAssembly; +import stmbench7.core.CompositePart; +import stmbench7.core.OperationFailedException; +import stmbench7.core.RuntimeError; + +/** + * Structural modification operation SM4 (see the specification). + */ +public class StructuralModification4 extends BaseOperation { + + protected Index baseAssemblyIdIndex; + + public StructuralModification4(Setup oo7setup) { + this.baseAssemblyIdIndex = oo7setup.getBaseAssemblyIdIndex(); + } + + @Override + @Transactional @Update + public int performOperation() throws OperationFailedException { + int baseAssemblyId = ThreadRandom.nextInt(Parameters.MaxBaseAssemblies) + 1; + BaseAssembly baseAssembly = baseAssemblyIdIndex.get(baseAssemblyId); + if(baseAssembly == null) throw new OperationFailedException(); + + ImmutableCollection components = baseAssembly.getComponents(); + int numOfComponents = components.size(); + if(numOfComponents == 0) throw new OperationFailedException(); + + int componentToRemove = ThreadRandom.nextInt(numOfComponents); + + int componentNumber = 0; + for(CompositePart component : components) { + if(componentNumber == componentToRemove) { + baseAssembly.removeComponent(component); + return 0; + } + componentNumber++; + } + + throw new RuntimeError("SM4: concurrent modification of BaseAssembly.components!"); + } + + @Override + public OperationId getOperationId() { + return OperationId.SM4; + } +} \ No newline at end of file diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/StructuralModification5.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/StructuralModification5.java new file mode 100644 index 00000000..f00d16f1 --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/StructuralModification5.java @@ -0,0 +1,48 @@ +package stmbench7.operations; + +import stmbench7.OperationId; +import stmbench7.Parameters; +import stmbench7.Setup; +import stmbench7.ThreadRandom; +import stmbench7.annotations.Transactional; +import stmbench7.annotations.Update; +import stmbench7.backend.Index; +import stmbench7.core.AssemblyBuilder; +import stmbench7.core.BaseAssembly; +import stmbench7.core.ComplexAssembly; +import stmbench7.core.Module; +import stmbench7.core.OperationFailedException; + +/** + * Structural modification operation SM5 (see the specification). + */ +public class StructuralModification5 extends BaseOperation { + + protected AssemblyBuilder assemblyBuilder; + protected Index baseAssemblyIdIndex; + protected Module module; + + public StructuralModification5(Setup oo7setup) { + this.baseAssemblyIdIndex = oo7setup.getBaseAssemblyIdIndex(); + assemblyBuilder = oo7setup.getAssemblyBuilder(); + this.module = oo7setup.getModule(); + } + + @Override + @Transactional @Update + public int performOperation() throws OperationFailedException { + int siblingBaseAssemblyId = ThreadRandom.nextInt(Parameters.MaxBaseAssemblies) + 1; + BaseAssembly siblingBaseAssembly = baseAssemblyIdIndex.get(siblingBaseAssemblyId); + if(siblingBaseAssembly == null) throw new OperationFailedException(); + + ComplexAssembly superAssembly = siblingBaseAssembly.getSuperAssembly(); + assemblyBuilder.createAndRegisterAssembly(module, superAssembly); + + return 0; + } + + @Override + public OperationId getOperationId() { + return OperationId.SM5; + } +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/StructuralModification6.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/StructuralModification6.java new file mode 100644 index 00000000..c7c69ded --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/StructuralModification6.java @@ -0,0 +1,46 @@ +package stmbench7.operations; + +import stmbench7.OperationId; +import stmbench7.Parameters; +import stmbench7.Setup; +import stmbench7.ThreadRandom; +import stmbench7.annotations.Transactional; +import stmbench7.annotations.Update; +import stmbench7.backend.Index; +import stmbench7.core.BaseAssembly; +import stmbench7.core.OperationFailedException; + +/** + * Structural modification SM6 (see the specification). + */ +public class StructuralModification6 extends StructuralModification5 { + + protected Index baseAssemblyIdIndex; + + public StructuralModification6(Setup oo7setup) { + super(oo7setup); + this.baseAssemblyIdIndex = oo7setup.getBaseAssemblyIdIndex(); + } + + @Override + @Transactional @Update + public int performOperation() throws OperationFailedException { + int baseAssemblyToRemoveId = ThreadRandom.nextInt(Parameters.MaxBaseAssemblies) + 1; + BaseAssembly baseAssemblyToRemove = baseAssemblyIdIndex.get(baseAssemblyToRemoveId); + if(baseAssemblyToRemove == null) throw new OperationFailedException(); + + // We want the tree of BAs/CAs to keep its form + // so that each CA has always at least one child sub-assembly + if(baseAssemblyToRemove.getSuperAssembly().getSubAssemblies().size() == 1) + throw new OperationFailedException(); + + assemblyBuilder.unregisterAndRecycleBaseAssembly(baseAssemblyToRemove); + + return 1; + } + + @Override + public OperationId getOperationId() { + return OperationId.SM6; + } +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/StructuralModification7.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/StructuralModification7.java new file mode 100644 index 00000000..00b91534 --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/StructuralModification7.java @@ -0,0 +1,46 @@ +package stmbench7.operations; + +import stmbench7.OperationId; +import stmbench7.Parameters; +import stmbench7.Setup; +import stmbench7.ThreadRandom; +import stmbench7.annotations.Transactional; +import stmbench7.annotations.Update; +import stmbench7.backend.Index; +import stmbench7.core.AssemblyBuilder; +import stmbench7.core.ComplexAssembly; +import stmbench7.core.Module; +import stmbench7.core.OperationFailedException; + +/** + * Structural modification SM7 (see the specification). + */ +public class StructuralModification7 extends BaseOperation { + + protected AssemblyBuilder assemblyBuilder; + protected Index complexAssemblyIdIndex; + protected Module module; + + public StructuralModification7(Setup oo7setup) { + this.complexAssemblyIdIndex = oo7setup.getComplexAssemblyIdIndex(); + this.module = oo7setup.getModule(); + assemblyBuilder = oo7setup.getAssemblyBuilder(); + } + + @Override + @Transactional @Update + public int performOperation() throws OperationFailedException { + int superAssemblyId = ThreadRandom.nextInt(Parameters.MaxComplexAssemblies) + 1; + ComplexAssembly superAssembly = complexAssemblyIdIndex.get(superAssemblyId); + if(superAssembly == null) throw new OperationFailedException(); + + assemblyBuilder.createAndRegisterAssembly(module, superAssembly); + + return 1; + } + + @Override + public OperationId getOperationId() { + return OperationId.SM7; + } +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/StructuralModification8.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/StructuralModification8.java new file mode 100644 index 00000000..29b019f4 --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/StructuralModification8.java @@ -0,0 +1,43 @@ +package stmbench7.operations; + +import stmbench7.OperationId; +import stmbench7.Parameters; +import stmbench7.Setup; +import stmbench7.ThreadRandom; +import stmbench7.annotations.Transactional; +import stmbench7.annotations.Update; +import stmbench7.core.ComplexAssembly; +import stmbench7.core.OperationFailedException; + +/** + * Structural modification SM8 (see the specification). + */ +public class StructuralModification8 extends StructuralModification7 { + + public StructuralModification8(Setup oo7setup) { + super(oo7setup); + } + + @Override + @Transactional @Update + public int performOperation() throws OperationFailedException { + int complexAssemblyId = ThreadRandom.nextInt(Parameters.MaxComplexAssemblies) + 1; + ComplexAssembly complexAssembly = complexAssemblyIdIndex.get(complexAssemblyId); + if(complexAssembly == null) throw new OperationFailedException(); + + // We want the tree of BAs/CAs to keep its form + // so that each CA has always at least one child sub-assembly + ComplexAssembly superAssembly = complexAssembly.getSuperAssembly(); + if(superAssembly == null || superAssembly.getSubAssemblies().size() == 1) + throw new OperationFailedException(); + + assemblyBuilder.unregisterAndRecycleComplexAssembly(complexAssembly); + + return 1; + } + + @Override + public OperationId getOperationId() { + return OperationId.SM8; + } +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Traversal1.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Traversal1.java new file mode 100644 index 00000000..f52dea0a --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Traversal1.java @@ -0,0 +1,89 @@ +package stmbench7.operations; + +import java.util.HashSet; + +import stmbench7.OperationId; +import stmbench7.Setup; +import stmbench7.annotations.ReadOnly; +import stmbench7.annotations.Transactional; +import stmbench7.core.Assembly; +import stmbench7.core.AtomicPart; +import stmbench7.core.BaseAssembly; +import stmbench7.core.ComplexAssembly; +import stmbench7.core.CompositePart; +import stmbench7.core.Connection; +import stmbench7.core.Module; + +/** + * Traversal T1 (see the specification). + * Read-only, long. + */ +public class Traversal1 extends BaseOperation { + + protected Module module; + + public Traversal1(Setup oo7setup) { + this.module = oo7setup.getModule(); + } + + @Override + @Transactional @ReadOnly + public int performOperation() { + ComplexAssembly designRoot = module.getDesignRoot(); + return traverse(designRoot); + } + + protected int traverse(Assembly assembly) { + if(assembly instanceof BaseAssembly) return traverse((BaseAssembly)assembly); + else return traverse((ComplexAssembly)assembly); + } + + protected int traverse(ComplexAssembly complexAssembly) { + int partsVisited = 0; + + for(Assembly assembly : complexAssembly.getSubAssemblies()) + partsVisited += traverse(assembly); + + return partsVisited; + } + + protected int traverse(BaseAssembly baseAssembly) { + int partsVisited = 0; + + for(CompositePart component : baseAssembly.getComponents()) + partsVisited += traverse(component); + + return partsVisited; + } + + protected int traverse(CompositePart component) { + AtomicPart rootPart = component.getRootPart(); + HashSet setOfVisitedPartIds = new HashSet(); + + return traverse(rootPart, setOfVisitedPartIds); + } + + protected int traverse(AtomicPart part, HashSet setOfVisitedPartIds) { + if(part == null) return 0; + if(setOfVisitedPartIds.contains(part)) return 0; + + int result = performOperationInAtomicPart(part, setOfVisitedPartIds); + + setOfVisitedPartIds.add(part); + + for(Connection connection : part.getToConnections()) + result += traverse(connection.getDestination(), setOfVisitedPartIds); + + return result; + } + + protected int performOperationInAtomicPart(AtomicPart part, HashSet setOfVisitedPartIds) { + part.nullOperation(); + return 1; + } + + @Override + public OperationId getOperationId() { + return OperationId.T1; + } +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Traversal2a.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Traversal2a.java new file mode 100644 index 00000000..d72f814f --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Traversal2a.java @@ -0,0 +1,43 @@ +package stmbench7.operations; + +import java.util.HashSet; + +import stmbench7.OperationId; +import stmbench7.Setup; +import stmbench7.annotations.Transactional; +import stmbench7.annotations.Update; +import stmbench7.core.AtomicPart; + +/** + * Traversal T2, variant (a) (see the specification). + * Simple update, long. + */ +public class Traversal2a extends Traversal1 { + + public Traversal2a(Setup oo7setup) { + super(oo7setup); + } + + @Override + @Transactional @Update + public int performOperation() { + return super.performOperation(); + } + + @Override + protected int performOperationInAtomicPart(AtomicPart part, HashSet setOfVisitedPartIds) { + if(setOfVisitedPartIds.isEmpty()) { + part.swapXY(); + return 1; + } + + part.nullOperation(); + return 0; + } + + @Override + public OperationId getOperationId() { + return OperationId.T2a; + } +} + diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Traversal2b.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Traversal2b.java new file mode 100644 index 00000000..73244c4d --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Traversal2b.java @@ -0,0 +1,30 @@ +package stmbench7.operations; + +import java.util.HashSet; + +import stmbench7.OperationId; +import stmbench7.Setup; +import stmbench7.core.AtomicPart; + +/** + * Traversal T2, variant (b) (see the specification). + * Simple update, long. + */ +public class Traversal2b extends Traversal2a { + + public Traversal2b(Setup oo7setup) { + super(oo7setup); + } + + @Override + protected int performOperationInAtomicPart(AtomicPart part, HashSet setOfVisitedPartIds) { + part.swapXY(); + return 1; + } + + @Override + public OperationId getOperationId() { + return OperationId.T2b; + } +} + diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Traversal2c.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Traversal2c.java new file mode 100644 index 00000000..2ec192e0 --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Traversal2c.java @@ -0,0 +1,33 @@ +package stmbench7.operations; + +import java.util.HashSet; + +import stmbench7.OperationId; +import stmbench7.Setup; +import stmbench7.core.AtomicPart; + +/** + * Traversal T2, variant (c) (see the specification). + * Simple update, long. + */ +public class Traversal2c extends Traversal2a { + + public Traversal2c(Setup oo7setup) { + super(oo7setup); + } + + @Override + protected int performOperationInAtomicPart(AtomicPart part, HashSet setOfVisitedPartIds) { + part.swapXY(); + part.swapXY(); + part.swapXY(); + part.swapXY(); + return 4; + } + + @Override + public OperationId getOperationId() { + return OperationId.T2c; + } +} + diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Traversal3a.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Traversal3a.java new file mode 100644 index 00000000..cfdf54ab --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Traversal3a.java @@ -0,0 +1,54 @@ +package stmbench7.operations; + +import java.util.HashSet; + +import stmbench7.OperationId; +import stmbench7.Setup; +import stmbench7.annotations.Transactional; +import stmbench7.annotations.Update; +import stmbench7.backend.Index; +import stmbench7.backend.LargeSet; +import stmbench7.core.AtomicPart; + +/** + * Traversal T3, variant (a) (see the specification). + * Simple update, update on index, long. + */ +public class Traversal3a extends Traversal1 { + + Index> partBuildDateIndex; + + public Traversal3a(Setup oo7setup) { + super(oo7setup); + this.partBuildDateIndex = oo7setup.getAtomicPartBuildDateIndex(); + } + + @Override + @Transactional @Update + public int performOperation() { + return super.performOperation(); + } + + @Override + protected int performOperationInAtomicPart(AtomicPart part, HashSet setOfVisitedPartIds) { + if(setOfVisitedPartIds.isEmpty()) { + updateBuildDate(part); + return 1; + } + + part.nullOperation(); + return 0; + } + + protected void updateBuildDate(AtomicPart part) { + removeAtomicPartFromBuildDateIndex(partBuildDateIndex, part); + part.updateBuildDate(); + addAtomicPartToBuildDateIndex(partBuildDateIndex, part); + } + + @Override + public OperationId getOperationId() { + return OperationId.T3a; + } +} + diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Traversal3b.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Traversal3b.java new file mode 100644 index 00000000..147cfda6 --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Traversal3b.java @@ -0,0 +1,30 @@ +package stmbench7.operations; + +import java.util.HashSet; + +import stmbench7.OperationId; +import stmbench7.Setup; +import stmbench7.core.AtomicPart; + +/** + * Traversal T3, variant (b) (see the specification). + * Simple update, update on index, long. + */ +public class Traversal3b extends Traversal3a { + + public Traversal3b(Setup oo7setup) { + super(oo7setup); + } + + @Override + protected int performOperationInAtomicPart(AtomicPart part, HashSet setOfVisitedPartIds) { + updateBuildDate(part); + return 1; + } + + @Override + public OperationId getOperationId() { + return OperationId.T3b; + } +} + diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Traversal3c.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Traversal3c.java new file mode 100644 index 00000000..0af9895d --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Traversal3c.java @@ -0,0 +1,32 @@ +package stmbench7.operations; + +import java.util.HashSet; + +import stmbench7.OperationId; +import stmbench7.Setup; +import stmbench7.core.AtomicPart; + +/** + * Traversal T3, variant (c) (see the specification). + * Simple update, update on index, long. + */ +public class Traversal3c extends Traversal3a { + + public Traversal3c(Setup oo7setup) { + super(oo7setup); + } + + @Override + protected int performOperationInAtomicPart(AtomicPart part, HashSet setOfVisitedPartIds) { + updateBuildDate(part); + updateBuildDate(part); + updateBuildDate(part); + updateBuildDate(part); + return 4; + } + + @Override + public OperationId getOperationId() { + return OperationId.T3c; + } +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Traversal4.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Traversal4.java new file mode 100644 index 00000000..ca5db668 --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Traversal4.java @@ -0,0 +1,46 @@ +package stmbench7.operations; + +import java.util.HashSet; + +import stmbench7.OperationId; +import stmbench7.Setup; +import stmbench7.core.AtomicPart; +import stmbench7.core.CompositePart; +import stmbench7.core.Document; +import stmbench7.core.RuntimeError; + +/** + * Traversal T4 (see the specification). + * Read-only, long. + */ +public class Traversal4 extends Traversal1 { + + public Traversal4(Setup oo7setup) { + super(oo7setup); + } + + @Override + protected int traverse(CompositePart component) { + Document documentation = component.getDocumentation(); + return traverse(documentation); + } + + protected int traverse(Document documentation) { + return documentation.searchText('I'); + } + + @Override + protected int traverse(AtomicPart part, HashSet setOfVisitedPartIds) { + throw new RuntimeError("T4: traverse(AtomicPart, HashSet) called!"); + } + + @Override + protected int performOperationInAtomicPart(AtomicPart part, HashSet setOfVisitedPartIds) { + throw new RuntimeError("T4: performOperationInAtomicPart(..) called!"); + } + + @Override + public OperationId getOperationId() { + return OperationId.T4; + } +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Traversal5.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Traversal5.java new file mode 100644 index 00000000..4565bdd9 --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Traversal5.java @@ -0,0 +1,44 @@ +package stmbench7.operations; + +import stmbench7.OperationId; +import stmbench7.Setup; +import stmbench7.annotations.Transactional; +import stmbench7.annotations.Update; +import stmbench7.core.Document; +import stmbench7.core.RuntimeError; + +/** + * Traversal T5 (see the specification). + */ +public class Traversal5 extends Traversal4 { + + public Traversal5(Setup oo7setup) { + super(oo7setup); + } + + @Override + @Transactional @Update + public int performOperation() { + return super.performOperation(); + } + + @Override + protected int traverse(Document documentation) { + int result; + + if(documentation.textBeginsWith("I am")) + result = documentation.replaceText("I am", "This is"); + else if(documentation.textBeginsWith("This is")) + result = documentation.replaceText("This is", "I am"); + else + throw new RuntimeError("T5: illegal document text: " + documentation.getText()); + + if(result == 0) throw new RuntimeError("T5: concurrent modification!"); + return result; + } + + @Override + public OperationId getOperationId() { + return OperationId.T5; + } +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Traversal6.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Traversal6.java new file mode 100644 index 00000000..4d00a68b --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Traversal6.java @@ -0,0 +1,41 @@ +package stmbench7.operations; + +import java.util.HashSet; + +import stmbench7.OperationId; +import stmbench7.Setup; +import stmbench7.core.AtomicPart; +import stmbench7.core.CompositePart; + +/** + * Traversal T6 (see the specification). + * Read-only, long. + */ +public class Traversal6 extends Traversal1 { + + public Traversal6(Setup oo7setup) { + super(oo7setup); + } + + @Override + protected int traverse(CompositePart component) { + AtomicPart rootPart = component.getRootPart(); + return traverse(rootPart, null); + } + + @Override + protected int traverse(AtomicPart part, HashSet setOfVisitedPartIds) { + return performOperationInAtomicPart(part, null); + } + + @Override + protected int performOperationInAtomicPart(AtomicPart part, HashSet setOfVisitedPartIds) { + part.nullOperation(); + return 1; + } + + @Override + public OperationId getOperationId() { + return OperationId.T6; + } +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Traversal7.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Traversal7.java new file mode 100644 index 00000000..e086ade8 --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Traversal7.java @@ -0,0 +1,70 @@ +package stmbench7.operations; + +import java.util.HashSet; + +import stmbench7.OperationId; +import stmbench7.Parameters; +import stmbench7.Setup; +import stmbench7.ThreadRandom; +import stmbench7.annotations.ReadOnly; +import stmbench7.annotations.Transactional; +import stmbench7.backend.Index; +import stmbench7.core.Assembly; +import stmbench7.core.AtomicPart; +import stmbench7.core.BaseAssembly; +import stmbench7.core.CompositePart; +import stmbench7.core.OperationFailedException; + +/** + * Traversal T7 / Short traversal ST3 (see the specification). + * Read-only, search on index, short. + */ +public class Traversal7 extends BaseOperation { + + Index partIdIndex; + + public Traversal7(Setup oo7setup) { + this.partIdIndex = oo7setup.getAtomicPartIdIndex(); + } + + @Override + @Transactional @ReadOnly + public int performOperation() throws OperationFailedException { + int partId = ThreadRandom.nextInt(Parameters.MaxAtomicParts) + 1; + AtomicPart part = partIdIndex.get(partId); + if(part == null) throw new OperationFailedException(); + + return traverse(part.getPartOf()); + } + + protected int traverse(CompositePart part) { + HashSet visitedAssemblies = new HashSet(); + + int result = 0; + Iterable ownerBaseAssemblies = part.getUsedIn(); + for(BaseAssembly assembly : ownerBaseAssemblies) + result += traverse(assembly, visitedAssemblies); + + return result; + } + + protected int traverse(Assembly assembly, HashSet visitedAssemblies) { + if(assembly == null) return 0; + if(visitedAssemblies.contains(assembly)) return 0; + + visitedAssemblies.add(assembly); + + performOperationOnAssembly(assembly); + + return traverse(assembly.getSuperAssembly(), visitedAssemblies) + 1; + } + + protected void performOperationOnAssembly(Assembly assembly) { + assembly.nullOperation(); + } + + @Override + public OperationId getOperationId() { + return OperationId.ST3; + } +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Traversal8.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Traversal8.java new file mode 100644 index 00000000..cf64b7d2 --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Traversal8.java @@ -0,0 +1,37 @@ +package stmbench7.operations; + +import stmbench7.OperationId; +import stmbench7.Setup; +import stmbench7.annotations.ReadOnly; +import stmbench7.annotations.Transactional; +import stmbench7.core.Manual; +import stmbench7.core.Module; + +/** + * Traversal T8 / Operation OP4 (see the specification). + * Read-only. + */ +public class Traversal8 extends BaseOperation { + + protected Module module; + + public Traversal8(Setup oo7setup) { + this.module = oo7setup.getModule(); + } + + @Override + @Transactional @ReadOnly + public int performOperation() { + Manual manual = module.getManual(); + return traverse(manual); + } + + protected int traverse(Manual manual) { + return manual.countOccurences('I'); + } + + @Override + public OperationId getOperationId() { + return OperationId.OP4; + } +} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Traversal9.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Traversal9.java new file mode 100644 index 00000000..ab320a76 --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Traversal9.java @@ -0,0 +1,26 @@ +package stmbench7.operations; + +import stmbench7.OperationId; +import stmbench7.Setup; +import stmbench7.core.Manual; + +/** + * Traversal T9 / Operation OP5 (see the specification). + * Read-only. + */ +public class Traversal9 extends Traversal8 { + + public Traversal9(Setup oo7setup) { + super(oo7setup); + } + + @Override + protected int traverse(Manual manual) { + return manual.checkFirstLastCharTheSame(); + } + + @Override + public OperationId getOperationId() { + return OperationId.OP5; + } +} diff --git a/benchmarks/scala-stm/stmbench7/src/test/java/stmbench7/test/backend/IndexTest.java b/benchmarks/scala-stm/stmbench7/src/test/java/stmbench7/test/backend/IndexTest.java new file mode 100644 index 00000000..e41ab0cc --- /dev/null +++ b/benchmarks/scala-stm/stmbench7/src/test/java/stmbench7/test/backend/IndexTest.java @@ -0,0 +1,227 @@ +package stmbench7.test.backend; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import java.util.Iterator; +import java.util.Random; +import java.util.TreeMap; + +import org.junit.Before; +import org.junit.Test; + +import stmbench7.backend.BackendFactory; +import stmbench7.backend.Index; +import stmbench7.impl.backend.BackendFactoryImpl; + +/** + * JUnit test for an Index class. + */ +public class IndexTest { + + /** + * Change the factory to test other implementation. + */ + protected BackendFactory backendFactory; + + private Index index, emptyIndex; + + public IndexTest() { + backendFactory = new BackendFactoryImpl(); + } + + @Before + public void setUp() throws Exception { + index = backendFactory.createIndex(); + emptyIndex = backendFactory.createIndex(); + + for(int key = 0; key < 100; key++) { + int val = key * 2; + index.put(key, val); + } + + for(int key = 100; key >= 0; key -= 2) { + int val = key; + index.put(key, val); + } + } + + /** + * Test method for {@link stmbench7.impl.backend.TreeMapIndex#put(stmbench7.backend.IndexKey, java.lang.Object)}. + */ + @Test + public void testPut() { + emptyIndex.put(5, 10); + emptyIndex.put(10, 11); + emptyIndex.put(1, 12); + emptyIndex.put(7, 10); + assertTrue(emptyIndex.get(5) == 10); + assertTrue(emptyIndex.get(10) == 11); + assertTrue(emptyIndex.get(1) == 12); + assertTrue(emptyIndex.get(7) == 10); + } + + /** + * Test method for {@link stmbench7.impl.backend.TreeMapIndex#putIfAbsent(stmbench7.backend.IndexKey, java.lang.Object)}. + */ + @Test + public void testPutIfAbsent() { + assertNull(index.putIfAbsent(101, 111)); + assertNull(index.putIfAbsent(-101, 111)); + assertTrue(index.putIfAbsent(10, 111) == 10); + assertTrue(index.putIfAbsent(-101, 222) == 111); + assertTrue(index.get(10) == 10); + assertTrue(index.get(-101) == 111); + } + + /** + * Test method for {@link stmbench7.impl.backend.TreeMapIndex#get(stmbench7.backend.IndexKey)}. + */ + @Test + public void testGet() { + assertNull(emptyIndex.get(4)); + assertNull(index.get(101)); + assertNull(index.get(-101)); + + for(int key = 0; key <= 100; key += 2) + assertTrue(index.get(key) == key); + for(int key = 1; key <= 100; key += 2) + assertTrue(index.get(key) == key * 2); + } + + /** + * Test method for {@link stmbench7.impl.backend.TreeMapIndex#getRange(stmbench7.backend.IndexKey, stmbench7.backend.IndexKey)}. + */ + @Test + public void testGetRange() { + Iterator range = index.getRange(5, 9).iterator(); + assertTrue(range.next() == 10); + assertTrue(range.next() == 6); + assertTrue(range.next() == 14); + assertTrue(range.next() == 8); + assertFalse(range.hasNext()); + + range = index.getRange(-5, 2).iterator(); + assertTrue(range.next() == 0); + assertTrue(range.next() == 2); + assertFalse(range.hasNext()); + + range = index.getRange(98, 120).iterator(); + assertTrue(range.next() == 98); + assertTrue(range.next() == 99 * 2); + assertTrue(range.next() == 100); + assertFalse(range.hasNext()); + + range = index.getRange(110, 120).iterator(); + assertFalse(range.hasNext()); + range = index.getRange(-120, -110).iterator(); + assertFalse(range.hasNext()); + + range = emptyIndex.getRange(110, 120).iterator(); + assertFalse(range.hasNext()); + } + + /** + * Test method for {@link stmbench7.impl.backend.TreeMapIndex#remove(stmbench7.backend.IndexKey)}. + */ + @Test + public void testRemove() { + assertFalse(emptyIndex.remove(4)); + assertFalse(index.remove(200)); + assertFalse(index.remove(-20)); + + assertTrue(index.remove(20)); + assertFalse(index.remove(20)); + assertNull(index.get(20)); + + assertTrue(index.remove(50)); + assertFalse(index.remove(50)); + assertNull(index.get(50)); + + assertTrue(index.remove(0)); + assertFalse(index.remove(0)); + assertNull(index.get(0)); + + assertTrue(index.remove(100)); + assertFalse(index.remove(100)); + assertNull(index.get(100)); + } + + /** + * Test method for {@link stmbench7.impl.backend.TreeMapIndex#iterator()}. + */ + @Test + public void testIterator() { + Iterator it = emptyIndex.iterator(); + assertFalse(it.hasNext()); + + int key = 0; + for(int val : index) { + if(key % 2 == 0) assertEquals(val, key); + else assertEquals(val, key * 2); + assertTrue(key <= 100); + key++; + } + assertEquals(key, 101); + } + + @Test + public void randomTest() { + final int N = 10000; + long time = System.currentTimeMillis(); + + Index randomIndex = backendFactory.createIndex(); + TreeMap refIndex = new TreeMap(); + + Random random = new Random(); + int max = Integer.MIN_VALUE, min = Integer.MAX_VALUE; + for(int n = 0; n < N; n++) { + int key = random.nextInt(); + assertEquals(randomIndex.get(key), refIndex.get(key)); + randomIndex.put(key, key); + assertTrue(randomIndex.get(key) == key); + + refIndex.put(key, key); + + max = Math.max(max, key); + min = Math.min(min, key); + } + + for(int n = 0; n < N; n++) { + int key = random.nextInt(); + Integer val = randomIndex.putIfAbsent(key, key); + assertEquals(refIndex.get(key), val); + if(val == null) refIndex.put(key, key); + } + + Iterator it = randomIndex.iterator(), refIt = refIndex.values().iterator(); + int prevVal = Integer.MIN_VALUE; + while(it.hasNext() && refIt.hasNext()) { + int val = it.next(), refVal = refIt.next(); + assertTrue(val > prevVal); + assertEquals(val, refVal); + prevVal = val; + } + assertFalse(it.hasNext()); + assertFalse(refIt.hasNext()); + + it = randomIndex.getRange(min/2, max/2).iterator(); + refIt = refIndex.subMap(min/2, max/2).values().iterator(); + while(it.hasNext()) + assertEquals(it.next(), refIt.next()); + assertFalse(refIt.hasNext()); + + for(int n = 0; n < N; n++) { + int key = random.nextInt(); + boolean res = randomIndex.remove(key); + boolean refRes = ( refIndex.remove(key) != null ); + assertEquals(refRes, res); + assertNull(randomIndex.get(key)); + } + + time = System.currentTimeMillis() - time; + System.err.println("randomTest time: " + time + " ms"); + } +} From 08ac889f72568c54a7def4c510b9d28b7ed56e34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lubom=C3=ADr=20Bulej?= Date: Sun, 26 May 2024 14:35:11 +0200 Subject: [PATCH 2/9] Remove DeuceSTM adapter for stmbench7 This allows dropping the deuceAgent jar --- .../impl/deucestm/DeuceSTMInitializer.java | 12 ---------- .../deucestm/DeuceSTMOperationExecutor.java | 24 ------------------- .../DeuceSTMOperationExecutorFactory.java | 17 ------------- 3 files changed, 53 deletions(-) delete mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/deucestm/DeuceSTMInitializer.java delete mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/deucestm/DeuceSTMOperationExecutor.java delete mode 100644 benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/deucestm/DeuceSTMOperationExecutorFactory.java diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/deucestm/DeuceSTMInitializer.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/deucestm/DeuceSTMInitializer.java deleted file mode 100644 index 08783dc9..00000000 --- a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/deucestm/DeuceSTMInitializer.java +++ /dev/null @@ -1,12 +0,0 @@ -package stmbench7.impl.deucestm; - -import stmbench7.OperationExecutorFactory; -import stmbench7.impl.NoSynchronizationInitializer; - -public class DeuceSTMInitializer extends NoSynchronizationInitializer { - - @Override - public OperationExecutorFactory createOperationExecutorFactory() { - return new DeuceSTMOperationExecutorFactory(); - } -} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/deucestm/DeuceSTMOperationExecutor.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/deucestm/DeuceSTMOperationExecutor.java deleted file mode 100644 index 349bec54..00000000 --- a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/deucestm/DeuceSTMOperationExecutor.java +++ /dev/null @@ -1,24 +0,0 @@ -package stmbench7.impl.deucestm; - -import stmbench7.OperationExecutor; -import stmbench7.core.Operation; -import stmbench7.core.OperationFailedException; - -public class DeuceSTMOperationExecutor implements OperationExecutor { - - private final Operation op; - - public DeuceSTMOperationExecutor(Operation op) { - this.op = op; - } - - @org.deuce.Atomic - public int execute() throws OperationFailedException { - return op.performOperation(); - } - - public int getLastOperationTimestamp() { - return 0; - } - -} diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/deucestm/DeuceSTMOperationExecutorFactory.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/deucestm/DeuceSTMOperationExecutorFactory.java deleted file mode 100644 index 37449f52..00000000 --- a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/deucestm/DeuceSTMOperationExecutorFactory.java +++ /dev/null @@ -1,17 +0,0 @@ -package stmbench7.impl.deucestm; - -import stmbench7.OperationExecutor; -import stmbench7.OperationExecutorFactory; -import stmbench7.core.Operation; -import stmbench7.impl.DefaultOperationExecutor; - -public class DeuceSTMOperationExecutorFactory extends OperationExecutorFactory { - - @Override - public OperationExecutor createOperationExecutor(Operation op) { - if(op.getOperationId() != null) - return new DeuceSTMOperationExecutor(op); - return new DefaultOperationExecutor(op); - } - -} From 01e66e461e9423376d1952889411b5c1d721f86f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lubom=C3=ADr=20Bulej?= Date: Sun, 26 May 2024 18:13:18 +0200 Subject: [PATCH 3/9] Execute fixed number of operations in stmbench7 These are more or less original modifications by Alex @axel22 --- .../src/main/java/stmbench7/BenchThread.java | 20 +++++++++++-------- .../src/main/java/stmbench7/Benchmark.java | 20 +++++++++++++------ .../src/main/java/stmbench7/ThreadRandom.java | 8 +++++--- .../opacity/SequentialReplayThread.java | 12 +++++------ .../operations/SetupDataStructure.java | 6 ++++-- .../operations/StructuralModification8.java | 4 ++-- 6 files changed, 43 insertions(+), 27 deletions(-) diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/BenchThread.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/BenchThread.java index f9f50916..94713e3d 100644 --- a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/BenchThread.java +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/BenchThread.java @@ -20,6 +20,7 @@ public class BenchThread implements Runnable { protected double[] operationCDF; protected OperationExecutor[] operations; protected final short myThreadNum; + protected final int countOfOperations; public int[] successfulOperations, failedOperations; public int[][] operationsTTC, operationsHighTTCLog; @@ -46,7 +47,7 @@ public int compareTo(ReplayLogEntry entry) { public ArrayList replayLog; - public BenchThread(Setup setup, double[] operationCDF, short myThreadNum) { + public BenchThread(Setup setup, double[] operationCDF, short myThreadNum, int countOfOperations) { this.operationCDF = operationCDF; int numOfOperations = OperationId.values().length; @@ -56,6 +57,7 @@ public BenchThread(Setup setup, double[] operationCDF, short myThreadNum) { failedOperations = new int[numOfOperations]; operations = new OperationExecutor[numOfOperations]; this.myThreadNum = myThreadNum; + this.countOfOperations = countOfOperations; createOperations(setup); @@ -68,15 +70,17 @@ protected BenchThread(Setup setup, double[] operationCDF) { operations = new OperationExecutor[OperationId.values().length]; createOperations(setup); myThreadNum = 0; + throw new RuntimeException("This ctor is no longer allowed."); } public void run() { - int i = 0; - while (!stop) { + int opIndex = 0; + while (!stop && opIndex < countOfOperations) { + opIndex++; //if (i++ > 55) continue; - int operationNumber = getNextOperationNumber(); + int operationNumber = getNextOperationNumber(opIndex); - OperationType type = OperationId.values()[operationNumber].getType(); + // OperationType type = OperationId.values()[operationNumber].getType(); //if( (type != OperationType.SHORT_TRAVERSAL) ) continue; // (type != OperationType.SHORT_TRAVERSAL_RO) && // (type != OperationType.OPERATION) ) @@ -110,7 +114,6 @@ public void run() { operationsHighTTCLog[operationNumber][intLogHighTtc]++; } } catch (OperationFailedException e) { - //System.out.println("failed"); failedOperations[operationNumber]++; failed = true; } @@ -156,8 +159,9 @@ protected void createOperations(Setup setup) { } } - protected int getNextOperationNumber() { - double whichOperation = ThreadRandom.nextDouble(); + protected int getNextOperationNumber(int iteration) { + // double whichOperation = ThreadRandom.nextDouble(); + double whichOperation = (iteration % 20) / 20.0; int operationNumber = 0; while (whichOperation >= operationCDF[operationNumber]) operationNumber++; diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/Benchmark.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/Benchmark.java index 1cef2665..f5421728 100644 --- a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/Benchmark.java +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/Benchmark.java @@ -13,6 +13,7 @@ import stmbench7.correctness.opacity.SequentialReplayThread; import stmbench7.correctness.opacity.StructureComparisonOperation; import stmbench7.impl.NoSynchronizationInitializer; +import stmbench7.ThreadRandom.Phase; /** * STMBench7 benchmark, the main program. @@ -44,6 +45,7 @@ public BenchmarkParametersException() { public static void main(String[] args) throws InterruptedException { Benchmark benchmark = null; + ThreadRandom.phase = Phase.INIT; try { benchmark = new Benchmark(args); @@ -69,7 +71,8 @@ public static void main(String[] args) throws InterruptedException { private Thread[] threads; private Setup setup, setupClone; private double elapsedTime; - + private int countOfOperations; + private Benchmark(String[] args) throws BenchmarkParametersException, InterruptedException { printHeader(); @@ -100,10 +103,10 @@ private void printHeader() { private void parseCommandLineParameters(String[] args) throws BenchmarkParametersException { int argNumber = 0; String workload = null, synchType = null, stmInitializerClassName = null; - + while(argNumber < args.length) { String currentArg = args[argNumber++]; - + try { if(currentArg.equals("--help") || currentArg.equals("-h")) { printSyntax(); @@ -127,6 +130,7 @@ else if(currentArg.equals("--")) { else if(currentArg.equals("-w")) workload = optionValue; else if(currentArg.equals("-g")) synchType = optionValue; else if(currentArg.equals("-s")) stmInitializerClassName = optionValue; + else if(currentArg.equals("-c")) countOfOperations = Integer.parseInt(optionValue); else throw new BenchmarkParametersException("Invalid option: " + currentArg); } } @@ -259,6 +263,7 @@ private void generateOperationCDF() { operationsRatio /= sumRatios; structuralModificationsRatio /= sumRatios; + for (OperationType type : OperationType.values()) type.count = 0; OperationId[] operations = OperationId.values(); for(OperationId operation : operations) operation.getType().count++; @@ -296,6 +301,7 @@ private void generateOperationCDF() { prevProbValue = operationCDF[opNum]; } operationCDF[operations.length - 1] = 1.0; // to avoid rounding errors + // System.out.println(Arrays.stream(operationCDF).boxed().collect(java.util.stream.Collectors.toList())); } private void setupStructures() throws InterruptedException { @@ -306,7 +312,7 @@ private void setupStructures() throws InterruptedException { threads = new Thread[Parameters.numThreads]; for(short threadNum = 0; threadNum < Parameters.numThreads; threadNum++) { benchThreads[threadNum] = - new BenchThread(setup, operationCDF, threadNum); + new BenchThread(setup, operationCDF, threadNum, countOfOperations); threads[threadNum] = ThreadFactory.instance.createThread(benchThreads[threadNum]); } System.err.println("Setup completed."); @@ -346,9 +352,10 @@ private void start() throws InterruptedException { for(Thread thread : threads) thread.start(); - Thread.sleep(Parameters.numSeconds * 1000); + // Renaissance: we require the threads to execute the specified number of operations. + // Thread.sleep(Parameters.numSeconds * 1000); + // for(BenchThread thread : benchThreads) thread.stopThread(); - for(BenchThread thread : benchThreads) thread.stopThread(); for(Thread thread : threads) thread.join(); long endTime = System.currentTimeMillis(); @@ -509,6 +516,7 @@ private void printSyntax() { "Options:\n" + "\t-t numThreads -- set the number of threads (default: 1)\n" + "\t-l length -- set the length of the benchmark, in seconds (default: 10)\n" + + "\t-c count -- set the length of the benchmark, in operations\n" + "\t-w r|rw|w -- set the workload: r = read-dominated, w = write-dominated\n" + "\t rw = read-write (default: read-dominated)\n" + "\t-g coarse|medium|fine|none|stm -- set synchronization method (default: coarse)\n" + diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/ThreadRandom.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/ThreadRandom.java index ca3bd12f..ce7df7fd 100644 --- a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/ThreadRandom.java +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/ThreadRandom.java @@ -16,7 +16,7 @@ @Immutable public class ThreadRandom { - private static enum Phase { + public static enum Phase { INIT, CONCURRENT, SEQUENTIAL_REPLAY @@ -57,7 +57,7 @@ public void restoreState() { } } - private static Phase phase = Phase.INIT; + public static Phase phase = Phase.INIT; private static RandomState initRandom = new RandomState(); private static short currentVirtualThreadNumber; private static RandomState[] virtualRandom; @@ -87,8 +87,10 @@ public static double nextDouble() { } public static void reset() { - if(phase != Phase.INIT) + if(phase != Phase.INIT) { + System.out.println("Warning, cannot reset!"); throw new RuntimeError("Cannot reset ThreadRandom after the initialization phase"); + } initRandom = new RandomState(); } diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/correctness/opacity/SequentialReplayThread.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/correctness/opacity/SequentialReplayThread.java index 825e9717..b0017e65 100644 --- a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/correctness/opacity/SequentialReplayThread.java +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/correctness/opacity/SequentialReplayThread.java @@ -27,19 +27,19 @@ public SequentialReplayThread(Setup setup, double[] operationCDF, } public void run() { - int i = 0; + // int i = 0; //for(ReplayLogEntry entry : replayLog) // System.out.println(i++ + " @ " + OperationId.values()[entry.opNum] + " -- " + entry.timestamp); - i=0; - int opNum = 1, numOfOps = replayLog.size(); + int opIndex = 1, opCount = replayLog.size(); for(ReplayLogEntry entry : replayLog) { - System.err.print("Operation " + (opNum++) + " out of " + numOfOps + "\r"); + System.err.print("Operation " + opIndex + " out of " + opCount + "\r"); short threadNum = entry.threadNum; ThreadRandom.setVirtualThreadNumber(threadNum); //System.out.println(++i); - int operationNumber = getNextOperationNumber(); - + int operationNumber = getNextOperationNumber(opIndex); + opIndex++; + //System.out.println(entry.threadNum + " -- " + OperationId.values()[entry.opNum] + // " / " + OperationId.values()[operationNumber]); if(operationNumber != entry.opNum) diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/SetupDataStructure.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/SetupDataStructure.java index b9a1b4e5..57d7c207 100644 --- a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/SetupDataStructure.java +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/SetupDataStructure.java @@ -32,7 +32,8 @@ public int performOperation() throws OperationFailedException { CompositePartBuilder compositePartBuilder = setup.getCompositePartBuilder(); for(int i = 0; i < Parameters.InitialTotalCompParts; i++) { - System.err.print("Component " + (i+1) + " of " + Parameters.InitialTotalCompParts + "\r"); + // Renaissance: Removed, because of too much output. + // System.err.print("Component " + (i+1) + " of " + Parameters.InitialTotalCompParts + "\r"); try { designLibrary[i] = compositePartBuilder.createAndRegisterCompositePart(); } @@ -52,7 +53,8 @@ public int performOperation() throws OperationFailedException { int i = 1; for(BaseAssembly baseAssembly : setup.getBaseAssemblyIdIndex()) { - System.err.print("Base Assembly " + (i++) + " of " + Parameters.InitialTotalBaseAssemblies + "\r"); + // Renaissance: Removed, because of too much output. + // System.err.print("Base Assembly " + (i++) + " of " + Parameters.InitialTotalBaseAssemblies + "\r"); for(int connections = 0; connections < Parameters.NumCompPerAssm; connections++) { int compositePartNum = ThreadRandom.nextInt(designLibrary.length); diff --git a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/StructuralModification8.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/StructuralModification8.java index 29b019f4..c30246f1 100644 --- a/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/StructuralModification8.java +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/StructuralModification8.java @@ -23,13 +23,13 @@ public StructuralModification8(Setup oo7setup) { public int performOperation() throws OperationFailedException { int complexAssemblyId = ThreadRandom.nextInt(Parameters.MaxComplexAssemblies) + 1; ComplexAssembly complexAssembly = complexAssemblyIdIndex.get(complexAssemblyId); - if(complexAssembly == null) throw new OperationFailedException(); + if(complexAssembly == null) throw new OperationFailedException("Complex assembly: " + complexAssembly); // We want the tree of BAs/CAs to keep its form // so that each CA has always at least one child sub-assembly ComplexAssembly superAssembly = complexAssembly.getSuperAssembly(); if(superAssembly == null || superAssembly.getSubAssemblies().size() == 1) - throw new OperationFailedException(); + throw new OperationFailedException("Super assembly: " + superAssembly); assemblyBuilder.unregisterAndRecycleComplexAssembly(complexAssembly); From e180c76360522bb83ae74839c8b14c3f7f0e0848 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lubom=C3=ADr=20Bulej?= Date: Sun, 26 May 2024 16:08:41 +0200 Subject: [PATCH 4/9] Add scala-stm adapter for stmbench7 --- .../stmbench7/scalastm/AssemblyImpl.scala | 21 +++++ .../stmbench7/scalastm/AtomicPartImpl.scala | 46 +++++++++++ .../stmbench7/scalastm/BaseAssemblyImpl.scala | 32 ++++++++ .../scalastm/ComplexAssemblyImpl.scala | 32 ++++++++ .../scalastm/CompositePartImpl.scala | 47 ++++++++++++ .../stmbench7/scalastm/DesignObjImpl.scala | 16 ++++ .../stmbench7/scalastm/DocumentImpl.scala | 34 +++++++++ .../scala/stmbench7/scalastm/IdPoolImpl.scala | 22 ++++++ .../stmbench7/scalastm/ImmutableSeqImpl.scala | 13 ++++ .../stmbench7/scalastm/ImmutableSetImpl.scala | 15 ++++ .../scala/stmbench7/scalastm/IndexImpl.scala | 46 +++++++++++ .../stmbench7/scalastm/LargeSetImpl.scala | 19 +++++ .../scala/stmbench7/scalastm/ManualImpl.scala | 40 ++++++++++ .../scala/stmbench7/scalastm/ModuleImpl.scala | 18 +++++ .../scalastm/ScalaSTMInitializer.scala | 76 +++++++++++++++++++ 15 files changed, 477 insertions(+) create mode 100644 benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/AssemblyImpl.scala create mode 100644 benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/AtomicPartImpl.scala create mode 100644 benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/BaseAssemblyImpl.scala create mode 100644 benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/ComplexAssemblyImpl.scala create mode 100644 benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/CompositePartImpl.scala create mode 100644 benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/DesignObjImpl.scala create mode 100644 benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/DocumentImpl.scala create mode 100644 benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/IdPoolImpl.scala create mode 100644 benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/ImmutableSeqImpl.scala create mode 100644 benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/ImmutableSetImpl.scala create mode 100644 benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/IndexImpl.scala create mode 100644 benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/LargeSetImpl.scala create mode 100644 benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/ManualImpl.scala create mode 100644 benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/ModuleImpl.scala create mode 100644 benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/ScalaSTMInitializer.scala diff --git a/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/AssemblyImpl.scala b/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/AssemblyImpl.scala new file mode 100644 index 00000000..d790edd4 --- /dev/null +++ b/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/AssemblyImpl.scala @@ -0,0 +1,21 @@ +/* scala-stm - (c) 2009-2011, Stanford University, PPL */ + +package stmbench7.scalastm + +import scala.concurrent.stm._ +import stmbench7.core._ + +abstract class AssemblyImpl(id: Int, typ: String, buildDate: Int, module0: Module, superAssembly0: ComplexAssembly + ) extends DesignObjImpl(id, typ, buildDate) with Assembly { + + private val module = Ref(module0).single + private val superAssembly = Ref(superAssembly0).single + + def getSuperAssembly = superAssembly() + def getModule = module() + + def clearPointers() { + superAssembly() = null + module() = null + } +} diff --git a/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/AtomicPartImpl.scala b/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/AtomicPartImpl.scala new file mode 100644 index 00000000..24fa8cc5 --- /dev/null +++ b/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/AtomicPartImpl.scala @@ -0,0 +1,46 @@ +/* scala-stm - (c) 2009-2011, Stanford University, PPL */ + +package stmbench7.scalastm + +import scala.concurrent.stm._ +import stmbench7.core._ +import stmbench7.impl.core.ConnectionImpl + +class AtomicPartImpl(id0: Int, typ0: String, bd0: Int, x0: Int, y0: Int) extends DesignObjImpl(id0, typ0, bd0) with AtomicPart { + val x = Ref(x0) + val y = Ref(y0) + val partOf = Ref(null : CompositePart).single + val from = TSet.empty[Connection].single // this is the equivant of SmallSetImpl + val to = TSet.empty[Connection].single + + def connectTo(dest: AtomicPart, typ: String, length: Int) { + val c = new ConnectionImpl(this, dest, typ, length) + to += c + dest.addConnectionFromOtherPart(c.getReversed) + } + def addConnectionFromOtherPart(c: Connection) { from += c } + def setCompositePart(po: CompositePart) { partOf() = po } + def getNumToConnections = to.size + def getToConnections = new ImmutableSetImpl[Connection](to) + def getFromConnections = new ImmutableSetImpl[Connection](from) + def getPartOf = partOf() + def swapXY() { + atomic { implicit t => + y() = x.swap(y()) + } + } + def getX = x.single() + def getY = y.single() + def clearPointers() { + atomic { implicit t => + x() = 0 + y() = 0 + to.clear() + from.clear() + partOf() = null + } + } + + // Comparable[AtomicPart] + def compareTo(rhs: AtomicPart) = getId - rhs.getId // subtraction is faithful to reference impl +} diff --git a/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/BaseAssemblyImpl.scala b/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/BaseAssemblyImpl.scala new file mode 100644 index 00000000..09330be6 --- /dev/null +++ b/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/BaseAssemblyImpl.scala @@ -0,0 +1,32 @@ +/* scala-stm - (c) 2009-2011, Stanford University, PPL */ + +package stmbench7.scalastm + +import scala.concurrent.stm._ +import stmbench7.core._ + +class BaseAssemblyImpl(id: Int, typ: String, buildDate: Int, module: Module, superAssembly: ComplexAssembly + ) extends AssemblyImpl(id, typ, buildDate, module, superAssembly) with BaseAssembly { + + val components = Ref(List.empty[CompositePart]).single // the original BagImpl was just an ArrayList + + def addComponent(component: CompositePart) { + components.transform(component :: _) + component.addAssembly(this) + } + + def removeComponent(component: CompositePart) = { + val f = components transformIfDefined { + case x if x contains component => x filterNot { _ == component } + } + if (f) component.removeAssembly(this) + f + } + + def getComponents = new ImmutableSeqImpl[CompositePart](components()) + + override def clearPointers() { + super.clearPointers() + components() = null + } +} diff --git a/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/ComplexAssemblyImpl.scala b/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/ComplexAssemblyImpl.scala new file mode 100644 index 00000000..ce6834eb --- /dev/null +++ b/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/ComplexAssemblyImpl.scala @@ -0,0 +1,32 @@ +/* scala-stm - (c) 2009-2011, Stanford University, PPL */ + +package stmbench7.scalastm + +import scala.concurrent.stm._ +import stmbench7.core._ +import stmbench7.Parameters + +class ComplexAssemblyImpl(id: Int, typ: String, buildDate: Int, module: Module, superAssembly: ComplexAssembly + ) extends AssemblyImpl(id, typ, buildDate, module, superAssembly) with ComplexAssembly { + + val subAssemblies = TSet.empty[Assembly].single + val level = if (superAssembly == null) Parameters.NumAssmLevels else superAssembly.getLevel - 1 + + def addSubAssembly(assembly: Assembly) = { + if(assembly.isInstanceOf[BaseAssembly] && level != 2) + throw new RuntimeError("ComplexAssembly.addAssembly: BaseAssembly at wrong level!"); + + subAssemblies.add(assembly) + } + + def removeSubAssembly(assembly: Assembly) = subAssemblies.remove(assembly) + + def getSubAssemblies = new ImmutableSetImpl[Assembly](subAssemblies) + + def getLevel = level.asInstanceOf[Short] + + override def clearPointers() { + super.clearPointers() + subAssemblies.clear() + } +} diff --git a/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/CompositePartImpl.scala b/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/CompositePartImpl.scala new file mode 100644 index 00000000..9ee21881 --- /dev/null +++ b/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/CompositePartImpl.scala @@ -0,0 +1,47 @@ +/* scala-stm - (c) 2009-2011, Stanford University, PPL */ + +package stmbench7.scalastm + +import scala.concurrent.stm._ +import stmbench7.core._ +import stmbench7.backend.BackendFactory + +class CompositePartImpl(id: Int, typ: String, buildDate: Int, documentation0: Document + ) extends DesignObjImpl(id, typ, buildDate) with CompositePart { + val documentation = Ref(documentation0).single + val usedIn = Ref(List.empty[BaseAssembly]).single + val parts = Ref(BackendFactory.instance.createLargeSet[AtomicPart]).single + val rootPart = Ref(null : AtomicPart).single + documentation0.setPart(this) + + def addAssembly(assembly: BaseAssembly) { usedIn.transform(assembly :: _) } + + def addPart(part: AtomicPart) = { + val f = parts().add(part) + if (f) { + part.setCompositePart(this) + if(rootPart() == null) rootPart() = part + } + f + } + + def getRootPart = rootPart() + def setRootPart(part: AtomicPart) { rootPart() = part } + + def getDocumentation = documentation() + + def getParts = parts() + + def removeAssembly(assembly: BaseAssembly ) { + usedIn.transform { _.filterNot(_ == assembly) } + } + + def getUsedIn = new ImmutableSeqImpl[BaseAssembly](usedIn()) + + def clearPointers() { + documentation() = null + parts() = null + usedIn() = null + rootPart() = null + } +} diff --git a/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/DesignObjImpl.scala b/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/DesignObjImpl.scala new file mode 100644 index 00000000..a8aff59c --- /dev/null +++ b/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/DesignObjImpl.scala @@ -0,0 +1,16 @@ +/* scala-stm - (c) 2009-2011, Stanford University, PPL */ + +package stmbench7.scalastm + +import scala.concurrent.stm._ +import stmbench7.core._ + +class DesignObjImpl(id: Int, typ: String, buildDate0: Int) extends DesignObj { + val bd = Ref(buildDate0).single + + def getId = id + def getType = typ + def getBuildDate = bd() + def updateBuildDate() { if (bd() % 2 == 0) bd -= 1 else bd += 1 } + def nullOperation() {} +} diff --git a/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/DocumentImpl.scala b/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/DocumentImpl.scala new file mode 100644 index 00000000..9325f3ee --- /dev/null +++ b/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/DocumentImpl.scala @@ -0,0 +1,34 @@ +/* scala-stm - (c) 2009-2011, Stanford University, PPL */ + +package stmbench7.scalastm + +import scala.annotation.tailrec +import scala.concurrent.stm._ +import stmbench7.core._ + +class DocumentImpl(id: Int, title: String, text0: String) extends Document { + val text = Ref(text0).single + val part = Ref(null : CompositePart).single + + def getDocumentId = id + def getTitle = title + + def getCompositePart = part() + def setPart(v: CompositePart) { part() = v } + + def nullOperation() {} + + def getText = text() + def searchText(symbol: Char): Int = searchText(text(), symbol, 0, 0) + @tailrec private def searchText(s: String, c: Char, pos: Int, n: Int): Int = { + val i = s.indexOf(c, pos) + if (i < 0) n else searchText(s, c, i + 1, n + 1) + } + def replaceText(from: String, to: String) = { + val f = text transformIfDefined { + case s if s.startsWith(from) => s.replaceFirst(from, to) + } + if (f) 1 else 0 + } + def textBeginsWith(prefix: String) = text().startsWith(prefix) +} diff --git a/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/IdPoolImpl.scala b/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/IdPoolImpl.scala new file mode 100644 index 00000000..c1e43b03 --- /dev/null +++ b/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/IdPoolImpl.scala @@ -0,0 +1,22 @@ +/* scala-stm - (c) 2009-2011, Stanford University, PPL */ + +package stmbench7.scalastm + +import scala.concurrent.stm._ +import stmbench7.core._ +import stmbench7.backend.IdPool + +object IdPoolImpl { + class BoxedList(n: Int) extends IdPool { + val underlying = Ref(List.range(1, n + 1)).single + + def putUnusedId(id: Int) { underlying.transform(id :: _) } + + def getId = { + underlying.getAndTransform(_.drop(1)) match { + case head :: _ => head + case _ => throw new OperationFailedException + } + } + } +} \ No newline at end of file diff --git a/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/ImmutableSeqImpl.scala b/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/ImmutableSeqImpl.scala new file mode 100644 index 00000000..e9f4e1a4 --- /dev/null +++ b/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/ImmutableSeqImpl.scala @@ -0,0 +1,13 @@ +/* scala-stm - (c) 2009-2012, Stanford University, PPL */ + +package stmbench7.scalastm + +import scala.collection.JavaConversions +import stmbench7.backend.ImmutableCollection + +class ImmutableSeqImpl[A](contents: Seq[A]) extends ImmutableCollection[A] { + override def clone = this + def contains(element: A) = contents.contains(element) + def size = contents.size + def iterator = JavaConversions.asJavaIterator(contents.iterator) +} diff --git a/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/ImmutableSetImpl.scala b/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/ImmutableSetImpl.scala new file mode 100644 index 00000000..8cd68cfd --- /dev/null +++ b/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/ImmutableSetImpl.scala @@ -0,0 +1,15 @@ +/* scala-stm - (c) 2009-2012, Stanford University, PPL */ + +package stmbench7.scalastm + +import scala.collection.JavaConversions +import scala.concurrent.stm._ +import stmbench7.backend.ImmutableCollection + +/** Read-only wrapper */ +class ImmutableSetImpl[A](contents: TSet.View[A], shared: Boolean = true) extends ImmutableCollection[A] { + override def clone: ImmutableSetImpl[A] = if (!shared) this else new ImmutableSetImpl(contents.clone(), false) + def contains(element: A) = contents.contains(element) + def size = contents.size + def iterator = JavaConversions.asJavaIterator(contents.iterator) +} diff --git a/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/IndexImpl.scala b/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/IndexImpl.scala new file mode 100644 index 00000000..3efd4b08 --- /dev/null +++ b/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/IndexImpl.scala @@ -0,0 +1,46 @@ +/* scala-stm - (c) 2009-2012, Stanford University, PPL */ + +package stmbench7.scalastm + +import scala.annotation._ +import scala.collection.immutable.TreeMap +import scala.collection.mutable.ArrayBuffer +import scala.collection.JavaConversions +import scala.concurrent.stm._ +import stmbench7.backend.Index + +object IndexImpl { + class BoxedImmutable[A <: Comparable[A], B] extends Index[A,B] { + // needed for 2.8, harmless in 2.9 + implicit val order = new Ordering[A] { + def compare(lhs: A, rhs: A) = lhs compareTo rhs + } + + val underlying = Ref(TreeMap.empty[A,B]).single + + def get(key: A) = underlying().getOrElse(key, null.asInstanceOf[B]) + + def put(key: A, value: B) { underlying.transform(_ + (key -> value)) } + + def putIfAbsent(key: A, value: B): B = { + underlying.getAndTransform({ m => if (m.contains(key)) m else m + (key -> value) }).getOrElse(key, null.asInstanceOf[B]) + } + + def remove(key: A) = underlying transformIfDefined { + case m if m.contains(key) => m - key + } + + def iterator = makeValuesIterator(underlying()) + + def getKeys = JavaConversions.setAsJavaSet(underlying().keySet) + + def getRange(minKey: A, maxKey: A) = new java.lang.Iterable[B] { + val range = underlying().range(minKey, maxKey) + def iterator = makeValuesIterator(range) + } + + private def makeValuesIterator(m: TreeMap[A, B]) = { + JavaConversions.asJavaIterator(m.values.iterator) + } + } +} diff --git a/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/LargeSetImpl.scala b/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/LargeSetImpl.scala new file mode 100644 index 00000000..56bb62f7 --- /dev/null +++ b/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/LargeSetImpl.scala @@ -0,0 +1,19 @@ +/* scala-stm - (c) 2009-2012, Stanford University, PPL */ + +package stmbench7.scalastm + +import scala.collection.JavaConversions +import scala.concurrent.stm._ +import stmbench7.backend.LargeSet + +// LargeSetImpl + +class LargeSetImpl[A <: Comparable[A]] extends LargeSet[A] { + val underlying = TMap.empty[A,Unit].single + + def add(e: A) = underlying.put(e, ()).isEmpty + def remove(e: A) = !underlying.remove(e).isEmpty + def contains(e: A) = underlying.contains(e) + def size = underlying.size + def iterator = JavaConversions.asJavaIterator(underlying.keysIterator) +} diff --git a/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/ManualImpl.scala b/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/ManualImpl.scala new file mode 100644 index 00000000..3edbbdab --- /dev/null +++ b/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/ManualImpl.scala @@ -0,0 +1,40 @@ +/* scala-stm - (c) 2009-2011, Stanford University, PPL */ + +package stmbench7.scalastm + +import scala.concurrent.stm._ +import scala.collection.immutable.WrappedString +import scala.annotation.tailrec +import stmbench7.core._ + +class ManualImpl(id: Int, title0: String, text0: String) extends Manual { + val title = Ref(title0).single + val text = Ref(text0).single + val module = Ref(null : Module).single + + def getId = id + def getTitle = title() + def getText = text() + def getModule = module() + + def setModule(v: Module) { module() = v } + + def countOccurences(ch: Char): Int = countOccurrences(ch) + def countOccurrences(ch: Char): Int = countOccurrences(text(), ch, 0, 0) + @tailrec private def countOccurrences(s: String, c: Char, pos: Int, n: Int): Int = { + val i = s.indexOf(c, pos) + if (i < 0) n else countOccurrences(s, c, i + 1, n + 1) + } + + def checkFirstLastCharTheSame = { + val t = text() + if (t.charAt(0) == t.charAt(t.length - 1)) 1 else 0 + } + + def startsWith(ch: Char) = text().charAt(0) == ch + + def replaceChar(from: Char, to: Char) = { + text.transform(_.replace(from, to)) + countOccurences(to) + } +} diff --git a/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/ModuleImpl.scala b/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/ModuleImpl.scala new file mode 100644 index 00000000..7ccac29c --- /dev/null +++ b/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/ModuleImpl.scala @@ -0,0 +1,18 @@ +/* scala-stm - (c) 2009-2011, Stanford University, PPL */ + +package stmbench7.scalastm + +import scala.concurrent.stm._ +import stmbench7.core._ + +class ModuleImpl(id: Int, typ: String, buildDate: Int, man: Manual + ) extends DesignObjImpl(id, typ, buildDate) with Module { + + val designRoot = Ref(null : ComplexAssembly).single + + man.setModule(this) + + def setDesignRoot(v: ComplexAssembly ) { designRoot() = v } + def getDesignRoot = designRoot() + def getManual = man +} diff --git a/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/ScalaSTMInitializer.scala b/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/ScalaSTMInitializer.scala new file mode 100644 index 00000000..aea0a5c5 --- /dev/null +++ b/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/ScalaSTMInitializer.scala @@ -0,0 +1,76 @@ +/* scala-stm - (c) 2009-2011, Stanford University, PPL */ + +package stmbench7.scalastm + +import scala.concurrent.stm._ +import stmbench7.backend._ +import stmbench7.core._ +import stmbench7.impl.core.ConnectionImpl +import stmbench7._ + +class ScalaSTMInitializer extends SynchMethodInitializer { + def createOperationExecutorFactory() = new OperationExecutorFactory { + + val timestamp = Ref(0) + + def createOperationExecutor(op: Operation) = new OperationExecutor { + var lastTS = 0 + + def execute(): Int = { + atomic { implicit t => + val z = op.performOperation() + if (Parameters.sequentialReplayEnabled) { + timestamp += 1 + lastTS = timestamp() + } + z + } + } + + def getLastOperationTimestamp = lastTS + } + } + + def createBackendFactory() = new BackendFactory { + + // a couple hundred, not ordered, except for huge numbers of discarded + // sets with exactly 1 element + def createLargeSet[E <: Comparable[E]](): LargeSet[E] = new LargeSetImpl[E] + + // ordered + def createIndex[K <: Comparable[K],V](): Index[K,V] = new IndexImpl.BoxedImmutable[K,V] + + def createIdPool(maxNumberOfIds: Int): IdPool = new IdPoolImpl.BoxedList(maxNumberOfIds) + } + + def createDesignObjFactory() = new DesignObjFactory { + + def createAtomicPart(id: Int, typ: String, bd: Int, x: Int, y: Int) = + new AtomicPartImpl(id, typ, bd, x, y) + + def createConnection(from: AtomicPart, to: AtomicPart, typ: String, length: Int) = + new ConnectionImpl(from, to, typ, length) + + def createBaseAssembly(id: Int, typ: String, buildDate: Int, module: Module, superAssembly: ComplexAssembly) = + new BaseAssemblyImpl(id, typ, buildDate, module, superAssembly) + + def createComplexAssembly(id: Int, typ: String, buildDate: Int, module: Module, superAssembly: ComplexAssembly) = + new ComplexAssemblyImpl(id, typ, buildDate, module, superAssembly) + + def createCompositePart(id: Int, typ: String, buildDate: Int, documentation: Document) = + new CompositePartImpl(id, typ, buildDate, documentation) + + def createDocument(id: Int, title: String, text: String) = + new DocumentImpl(id, title, text) + + def createManual(id: Int, title: String, text: String) = + new ManualImpl(id, title, text) + + def createModule(id: Int, typ: String, buildDate: Int, man: Manual) = + new ModuleImpl(id, typ, buildDate, man) + } + + def createThreadFactory() = new stmbench7.ThreadFactory { + def createThread(body: Runnable) = new Thread(body) + } +} \ No newline at end of file From 257c1cbf068bd780c1dea5ee4db3ad1d201bb71f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lubom=C3=ADr=20Bulej?= Date: Sun, 26 May 2024 16:11:37 +0200 Subject: [PATCH 5/9] Reformat scala-stm adapter code using scalafmt --- .../stmbench7/scalastm/AssemblyImpl.scala | 12 ++- .../stmbench7/scalastm/AtomicPartImpl.scala | 11 ++- .../stmbench7/scalastm/BaseAssemblyImpl.scala | 17 +++- .../scalastm/ComplexAssemblyImpl.scala | 18 +++- .../scalastm/CompositePartImpl.scala | 13 +-- .../stmbench7/scalastm/DesignObjImpl.scala | 8 +- .../stmbench7/scalastm/DocumentImpl.scala | 4 +- .../scala/stmbench7/scalastm/IdPoolImpl.scala | 5 +- .../stmbench7/scalastm/ImmutableSetImpl.scala | 7 +- .../scala/stmbench7/scalastm/IndexImpl.scala | 26 +++-- .../stmbench7/scalastm/LargeSetImpl.scala | 2 +- .../scala/stmbench7/scalastm/ManualImpl.scala | 3 +- .../scala/stmbench7/scalastm/ModuleImpl.scala | 9 +- .../scalastm/ScalaSTMInitializer.scala | 96 +++++++++++-------- 14 files changed, 145 insertions(+), 86 deletions(-) diff --git a/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/AssemblyImpl.scala b/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/AssemblyImpl.scala index d790edd4..ccd6169e 100644 --- a/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/AssemblyImpl.scala +++ b/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/AssemblyImpl.scala @@ -5,15 +5,21 @@ package stmbench7.scalastm import scala.concurrent.stm._ import stmbench7.core._ -abstract class AssemblyImpl(id: Int, typ: String, buildDate: Int, module0: Module, superAssembly0: ComplexAssembly - ) extends DesignObjImpl(id, typ, buildDate) with Assembly { +abstract class AssemblyImpl( + id: Int, + typ: String, + buildDate: Int, + module0: Module, + superAssembly0: ComplexAssembly +) extends DesignObjImpl(id, typ, buildDate) + with Assembly { private val module = Ref(module0).single private val superAssembly = Ref(superAssembly0).single def getSuperAssembly = superAssembly() def getModule = module() - + def clearPointers() { superAssembly() = null module() = null diff --git a/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/AtomicPartImpl.scala b/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/AtomicPartImpl.scala index 24fa8cc5..8fb491ef 100644 --- a/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/AtomicPartImpl.scala +++ b/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/AtomicPartImpl.scala @@ -6,10 +6,12 @@ import scala.concurrent.stm._ import stmbench7.core._ import stmbench7.impl.core.ConnectionImpl -class AtomicPartImpl(id0: Int, typ0: String, bd0: Int, x0: Int, y0: Int) extends DesignObjImpl(id0, typ0, bd0) with AtomicPart { +class AtomicPartImpl(id0: Int, typ0: String, bd0: Int, x0: Int, y0: Int) + extends DesignObjImpl(id0, typ0, bd0) + with AtomicPart { val x = Ref(x0) val y = Ref(y0) - val partOf = Ref(null : CompositePart).single + val partOf = Ref(null: CompositePart).single val from = TSet.empty[Connection].single // this is the equivant of SmallSetImpl val to = TSet.empty[Connection].single @@ -24,6 +26,7 @@ class AtomicPartImpl(id0: Int, typ0: String, bd0: Int, x0: Int, y0: Int) extends def getToConnections = new ImmutableSetImpl[Connection](to) def getFromConnections = new ImmutableSetImpl[Connection](from) def getPartOf = partOf() + def swapXY() { atomic { implicit t => y() = x.swap(y()) @@ -31,6 +34,7 @@ class AtomicPartImpl(id0: Int, typ0: String, bd0: Int, x0: Int, y0: Int) extends } def getX = x.single() def getY = y.single() + def clearPointers() { atomic { implicit t => x() = 0 @@ -42,5 +46,6 @@ class AtomicPartImpl(id0: Int, typ0: String, bd0: Int, x0: Int, y0: Int) extends } // Comparable[AtomicPart] - def compareTo(rhs: AtomicPart) = getId - rhs.getId // subtraction is faithful to reference impl + def compareTo(rhs: AtomicPart) = + getId - rhs.getId // subtraction is faithful to reference impl } diff --git a/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/BaseAssemblyImpl.scala b/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/BaseAssemblyImpl.scala index 09330be6..fc7abed3 100644 --- a/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/BaseAssemblyImpl.scala +++ b/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/BaseAssemblyImpl.scala @@ -5,10 +5,17 @@ package stmbench7.scalastm import scala.concurrent.stm._ import stmbench7.core._ -class BaseAssemblyImpl(id: Int, typ: String, buildDate: Int, module: Module, superAssembly: ComplexAssembly - ) extends AssemblyImpl(id, typ, buildDate, module, superAssembly) with BaseAssembly { - - val components = Ref(List.empty[CompositePart]).single // the original BagImpl was just an ArrayList +class BaseAssemblyImpl( + id: Int, + typ: String, + buildDate: Int, + module: Module, + superAssembly: ComplexAssembly +) extends AssemblyImpl(id, typ, buildDate, module, superAssembly) + with BaseAssembly { + + val components = + Ref(List.empty[CompositePart]).single // the original BagImpl was just an ArrayList def addComponent(component: CompositePart) { components.transform(component :: _) @@ -28,5 +35,5 @@ class BaseAssemblyImpl(id: Int, typ: String, buildDate: Int, module: Module, sup override def clearPointers() { super.clearPointers() components() = null - } + } } diff --git a/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/ComplexAssemblyImpl.scala b/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/ComplexAssemblyImpl.scala index ce6834eb..41101442 100644 --- a/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/ComplexAssemblyImpl.scala +++ b/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/ComplexAssemblyImpl.scala @@ -6,16 +6,24 @@ import scala.concurrent.stm._ import stmbench7.core._ import stmbench7.Parameters -class ComplexAssemblyImpl(id: Int, typ: String, buildDate: Int, module: Module, superAssembly: ComplexAssembly - ) extends AssemblyImpl(id, typ, buildDate, module, superAssembly) with ComplexAssembly { +class ComplexAssemblyImpl( + id: Int, + typ: String, + buildDate: Int, + module: Module, + superAssembly: ComplexAssembly +) extends AssemblyImpl(id, typ, buildDate, module, superAssembly) + with ComplexAssembly { val subAssemblies = TSet.empty[Assembly].single - val level = if (superAssembly == null) Parameters.NumAssmLevels else superAssembly.getLevel - 1 + + val level = + if (superAssembly == null) Parameters.NumAssmLevels else superAssembly.getLevel - 1 def addSubAssembly(assembly: Assembly) = { - if(assembly.isInstanceOf[BaseAssembly] && level != 2) + if (assembly.isInstanceOf[BaseAssembly] && level != 2) throw new RuntimeError("ComplexAssembly.addAssembly: BaseAssembly at wrong level!"); - + subAssemblies.add(assembly) } diff --git a/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/CompositePartImpl.scala b/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/CompositePartImpl.scala index 9ee21881..0fa84dde 100644 --- a/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/CompositePartImpl.scala +++ b/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/CompositePartImpl.scala @@ -6,12 +6,13 @@ import scala.concurrent.stm._ import stmbench7.core._ import stmbench7.backend.BackendFactory -class CompositePartImpl(id: Int, typ: String, buildDate: Int, documentation0: Document - ) extends DesignObjImpl(id, typ, buildDate) with CompositePart { +class CompositePartImpl(id: Int, typ: String, buildDate: Int, documentation0: Document) + extends DesignObjImpl(id, typ, buildDate) + with CompositePart { val documentation = Ref(documentation0).single val usedIn = Ref(List.empty[BaseAssembly]).single val parts = Ref(BackendFactory.instance.createLargeSet[AtomicPart]).single - val rootPart = Ref(null : AtomicPart).single + val rootPart = Ref(null: AtomicPart).single documentation0.setPart(this) def addAssembly(assembly: BaseAssembly) { usedIn.transform(assembly :: _) } @@ -20,19 +21,19 @@ class CompositePartImpl(id: Int, typ: String, buildDate: Int, documentation0: Do val f = parts().add(part) if (f) { part.setCompositePart(this) - if(rootPart() == null) rootPart() = part + if (rootPart() == null) rootPart() = part } f } def getRootPart = rootPart() - def setRootPart(part: AtomicPart) { rootPart() = part } + def setRootPart(part: AtomicPart) { rootPart() = part } def getDocumentation = documentation() def getParts = parts() - def removeAssembly(assembly: BaseAssembly ) { + def removeAssembly(assembly: BaseAssembly) { usedIn.transform { _.filterNot(_ == assembly) } } diff --git a/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/DesignObjImpl.scala b/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/DesignObjImpl.scala index a8aff59c..f29f415c 100644 --- a/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/DesignObjImpl.scala +++ b/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/DesignObjImpl.scala @@ -8,9 +8,9 @@ import stmbench7.core._ class DesignObjImpl(id: Int, typ: String, buildDate0: Int) extends DesignObj { val bd = Ref(buildDate0).single - def getId = id + def getId = id def getType = typ - def getBuildDate = bd() - def updateBuildDate() { if (bd() % 2 == 0) bd -= 1 else bd += 1 } - def nullOperation() {} + def getBuildDate = bd() + def updateBuildDate() { if (bd() % 2 == 0) bd -= 1 else bd += 1 } + def nullOperation() {} } diff --git a/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/DocumentImpl.scala b/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/DocumentImpl.scala index 9325f3ee..2dc0d4c2 100644 --- a/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/DocumentImpl.scala +++ b/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/DocumentImpl.scala @@ -8,7 +8,7 @@ import stmbench7.core._ class DocumentImpl(id: Int, title: String, text0: String) extends Document { val text = Ref(text0).single - val part = Ref(null : CompositePart).single + val part = Ref(null: CompositePart).single def getDocumentId = id def getTitle = title @@ -20,10 +20,12 @@ class DocumentImpl(id: Int, title: String, text0: String) extends Document { def getText = text() def searchText(symbol: Char): Int = searchText(text(), symbol, 0, 0) + @tailrec private def searchText(s: String, c: Char, pos: Int, n: Int): Int = { val i = s.indexOf(c, pos) if (i < 0) n else searchText(s, c, i + 1, n + 1) } + def replaceText(from: String, to: String) = { val f = text transformIfDefined { case s if s.startsWith(from) => s.replaceFirst(from, to) diff --git a/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/IdPoolImpl.scala b/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/IdPoolImpl.scala index c1e43b03..9aac4f0b 100644 --- a/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/IdPoolImpl.scala +++ b/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/IdPoolImpl.scala @@ -7,9 +7,10 @@ import stmbench7.core._ import stmbench7.backend.IdPool object IdPoolImpl { + class BoxedList(n: Int) extends IdPool { val underlying = Ref(List.range(1, n + 1)).single - + def putUnusedId(id: Int) { underlying.transform(id :: _) } def getId = { @@ -19,4 +20,4 @@ object IdPoolImpl { } } } -} \ No newline at end of file +} diff --git a/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/ImmutableSetImpl.scala b/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/ImmutableSetImpl.scala index 8cd68cfd..66a0b6e5 100644 --- a/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/ImmutableSetImpl.scala +++ b/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/ImmutableSetImpl.scala @@ -7,8 +7,11 @@ import scala.concurrent.stm._ import stmbench7.backend.ImmutableCollection /** Read-only wrapper */ -class ImmutableSetImpl[A](contents: TSet.View[A], shared: Boolean = true) extends ImmutableCollection[A] { - override def clone: ImmutableSetImpl[A] = if (!shared) this else new ImmutableSetImpl(contents.clone(), false) +class ImmutableSetImpl[A](contents: TSet.View[A], shared: Boolean = true) + extends ImmutableCollection[A] { + + override def clone: ImmutableSetImpl[A] = + if (!shared) this else new ImmutableSetImpl(contents.clone(), false) def contains(element: A) = contents.contains(element) def size = contents.size def iterator = JavaConversions.asJavaIterator(contents.iterator) diff --git a/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/IndexImpl.scala b/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/IndexImpl.scala index 3efd4b08..6e60af48 100644 --- a/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/IndexImpl.scala +++ b/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/IndexImpl.scala @@ -10,34 +10,40 @@ import scala.concurrent.stm._ import stmbench7.backend.Index object IndexImpl { - class BoxedImmutable[A <: Comparable[A], B] extends Index[A,B] { + + class BoxedImmutable[A <: Comparable[A], B] extends Index[A, B] { + // needed for 2.8, harmless in 2.9 implicit val order = new Ordering[A] { def compare(lhs: A, rhs: A) = lhs compareTo rhs } - val underlying = Ref(TreeMap.empty[A,B]).single + val underlying = Ref(TreeMap.empty[A, B]).single def get(key: A) = underlying().getOrElse(key, null.asInstanceOf[B]) def put(key: A, value: B) { underlying.transform(_ + (key -> value)) } def putIfAbsent(key: A, value: B): B = { - underlying.getAndTransform({ m => if (m.contains(key)) m else m + (key -> value) }).getOrElse(key, null.asInstanceOf[B]) + underlying + .getAndTransform({ m => if (m.contains(key)) m else m + (key -> value) }) + .getOrElse(key, null.asInstanceOf[B]) } - def remove(key: A) = underlying transformIfDefined { - case m if m.contains(key) => m - key - } + def remove(key: A) = + underlying transformIfDefined { + case m if m.contains(key) => m - key + } def iterator = makeValuesIterator(underlying()) def getKeys = JavaConversions.setAsJavaSet(underlying().keySet) - def getRange(minKey: A, maxKey: A) = new java.lang.Iterable[B] { - val range = underlying().range(minKey, maxKey) - def iterator = makeValuesIterator(range) - } + def getRange(minKey: A, maxKey: A) = + new java.lang.Iterable[B] { + val range = underlying().range(minKey, maxKey) + def iterator = makeValuesIterator(range) + } private def makeValuesIterator(m: TreeMap[A, B]) = { JavaConversions.asJavaIterator(m.values.iterator) diff --git a/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/LargeSetImpl.scala b/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/LargeSetImpl.scala index 56bb62f7..2422f004 100644 --- a/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/LargeSetImpl.scala +++ b/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/LargeSetImpl.scala @@ -9,7 +9,7 @@ import stmbench7.backend.LargeSet // LargeSetImpl class LargeSetImpl[A <: Comparable[A]] extends LargeSet[A] { - val underlying = TMap.empty[A,Unit].single + val underlying = TMap.empty[A, Unit].single def add(e: A) = underlying.put(e, ()).isEmpty def remove(e: A) = !underlying.remove(e).isEmpty diff --git a/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/ManualImpl.scala b/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/ManualImpl.scala index 3edbbdab..09688b7e 100644 --- a/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/ManualImpl.scala +++ b/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/ManualImpl.scala @@ -10,7 +10,7 @@ import stmbench7.core._ class ManualImpl(id: Int, title0: String, text0: String) extends Manual { val title = Ref(title0).single val text = Ref(text0).single - val module = Ref(null : Module).single + val module = Ref(null: Module).single def getId = id def getTitle = title() @@ -21,6 +21,7 @@ class ManualImpl(id: Int, title0: String, text0: String) extends Manual { def countOccurences(ch: Char): Int = countOccurrences(ch) def countOccurrences(ch: Char): Int = countOccurrences(text(), ch, 0, 0) + @tailrec private def countOccurrences(s: String, c: Char, pos: Int, n: Int): Int = { val i = s.indexOf(c, pos) if (i < 0) n else countOccurrences(s, c, i + 1, n + 1) diff --git a/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/ModuleImpl.scala b/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/ModuleImpl.scala index 7ccac29c..223df5ca 100644 --- a/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/ModuleImpl.scala +++ b/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/ModuleImpl.scala @@ -5,14 +5,15 @@ package stmbench7.scalastm import scala.concurrent.stm._ import stmbench7.core._ -class ModuleImpl(id: Int, typ: String, buildDate: Int, man: Manual - ) extends DesignObjImpl(id, typ, buildDate) with Module { +class ModuleImpl(id: Int, typ: String, buildDate: Int, man: Manual) + extends DesignObjImpl(id, typ, buildDate) + with Module { - val designRoot = Ref(null : ComplexAssembly).single + val designRoot = Ref(null: ComplexAssembly).single man.setModule(this) - def setDesignRoot(v: ComplexAssembly ) { designRoot() = v } + def setDesignRoot(v: ComplexAssembly) { designRoot() = v } def getDesignRoot = designRoot() def getManual = man } diff --git a/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/ScalaSTMInitializer.scala b/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/ScalaSTMInitializer.scala index aea0a5c5..cc25bcaa 100644 --- a/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/ScalaSTMInitializer.scala +++ b/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/ScalaSTMInitializer.scala @@ -9,68 +9,86 @@ import stmbench7.impl.core.ConnectionImpl import stmbench7._ class ScalaSTMInitializer extends SynchMethodInitializer { - def createOperationExecutorFactory() = new OperationExecutorFactory { - val timestamp = Ref(0) + def createOperationExecutorFactory() = + new OperationExecutorFactory { - def createOperationExecutor(op: Operation) = new OperationExecutor { - var lastTS = 0 + val timestamp = Ref(0) - def execute(): Int = { - atomic { implicit t => - val z = op.performOperation() - if (Parameters.sequentialReplayEnabled) { - timestamp += 1 - lastTS = timestamp() + def createOperationExecutor(op: Operation) = + new OperationExecutor { + var lastTS = 0 + + def execute(): Int = { + atomic { implicit t => + val z = op.performOperation() + if (Parameters.sequentialReplayEnabled) { + timestamp += 1 + lastTS = timestamp() + } + z + } } - z - } - } - def getLastOperationTimestamp = lastTS + def getLastOperationTimestamp = lastTS + } } - } - def createBackendFactory() = new BackendFactory { + def createBackendFactory() = + new BackendFactory { - // a couple hundred, not ordered, except for huge numbers of discarded - // sets with exactly 1 element - def createLargeSet[E <: Comparable[E]](): LargeSet[E] = new LargeSetImpl[E] + // a couple hundred, not ordered, except for huge numbers of discarded + // sets with exactly 1 element + def createLargeSet[E <: Comparable[E]](): LargeSet[E] = new LargeSetImpl[E] - // ordered - def createIndex[K <: Comparable[K],V](): Index[K,V] = new IndexImpl.BoxedImmutable[K,V] + // ordered + def createIndex[K <: Comparable[K], V](): Index[K, V] = new IndexImpl.BoxedImmutable[K, V] - def createIdPool(maxNumberOfIds: Int): IdPool = new IdPoolImpl.BoxedList(maxNumberOfIds) - } + def createIdPool(maxNumberOfIds: Int): IdPool = new IdPoolImpl.BoxedList(maxNumberOfIds) + } - def createDesignObjFactory() = new DesignObjFactory { + def createDesignObjFactory() = + new DesignObjFactory { - def createAtomicPart(id: Int, typ: String, bd: Int, x: Int, y: Int) = + def createAtomicPart(id: Int, typ: String, bd: Int, x: Int, y: Int) = new AtomicPartImpl(id, typ, bd, x, y) - def createConnection(from: AtomicPart, to: AtomicPart, typ: String, length: Int) = + def createConnection(from: AtomicPart, to: AtomicPart, typ: String, length: Int) = new ConnectionImpl(from, to, typ, length) - - def createBaseAssembly(id: Int, typ: String, buildDate: Int, module: Module, superAssembly: ComplexAssembly) = + + def createBaseAssembly( + id: Int, + typ: String, + buildDate: Int, + module: Module, + superAssembly: ComplexAssembly + ) = new BaseAssemblyImpl(id, typ, buildDate, module, superAssembly) - def createComplexAssembly(id: Int, typ: String, buildDate: Int, module: Module, superAssembly: ComplexAssembly) = + def createComplexAssembly( + id: Int, + typ: String, + buildDate: Int, + module: Module, + superAssembly: ComplexAssembly + ) = new ComplexAssemblyImpl(id, typ, buildDate, module, superAssembly) - def createCompositePart(id: Int, typ: String, buildDate: Int, documentation: Document) = + def createCompositePart(id: Int, typ: String, buildDate: Int, documentation: Document) = new CompositePartImpl(id, typ, buildDate, documentation) - def createDocument(id: Int, title: String, text: String) = + def createDocument(id: Int, title: String, text: String) = new DocumentImpl(id, title, text) - def createManual(id: Int, title: String, text: String) = + def createManual(id: Int, title: String, text: String) = new ManualImpl(id, title, text) - - def createModule(id: Int, typ: String, buildDate: Int, man: Manual) = + + def createModule(id: Int, typ: String, buildDate: Int, man: Manual) = new ModuleImpl(id, typ, buildDate, man) - } + } - def createThreadFactory() = new stmbench7.ThreadFactory { - def createThread(body: Runnable) = new Thread(body) - } -} \ No newline at end of file + def createThreadFactory() = + new stmbench7.ThreadFactory { + def createThread(body: Runnable) = new Thread(body) + } +} From ddea03ec9d26173ffa167c814cbc2c95726182e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lubom=C3=ADr=20Bulej?= Date: Sun, 26 May 2024 17:04:39 +0200 Subject: [PATCH 6/9] Use explicit imports, mark override functions, make values private --- .../stmbench7/scalastm/AssemblyImpl.scala | 13 +++-- .../stmbench7/scalastm/AtomicPartImpl.scala | 47 +++++++++++-------- .../stmbench7/scalastm/BaseAssemblyImpl.scala | 18 ++++--- .../scalastm/ComplexAssemblyImpl.scala | 23 +++++---- .../scalastm/CompositePartImpl.scala | 37 +++++++++------ .../stmbench7/scalastm/DesignObjImpl.scala | 17 +++---- .../stmbench7/scalastm/DocumentImpl.scala | 30 +++++++----- .../scala/stmbench7/scalastm/IdPoolImpl.scala | 11 +++-- .../stmbench7/scalastm/ImmutableSeqImpl.scala | 11 +++-- .../stmbench7/scalastm/ImmutableSetImpl.scala | 15 ++++-- .../scala/stmbench7/scalastm/IndexImpl.scala | 42 ++++++++--------- .../stmbench7/scalastm/LargeSetImpl.scala | 20 ++++---- .../scala/stmbench7/scalastm/ManualImpl.scala | 33 ++++++------- .../scala/stmbench7/scalastm/ModuleImpl.scala | 15 +++--- .../scalastm/ScalaSTMInitializer.scala | 43 +++++++++++------ 15 files changed, 216 insertions(+), 159 deletions(-) diff --git a/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/AssemblyImpl.scala b/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/AssemblyImpl.scala index ccd6169e..edae77b8 100644 --- a/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/AssemblyImpl.scala +++ b/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/AssemblyImpl.scala @@ -2,8 +2,11 @@ package stmbench7.scalastm -import scala.concurrent.stm._ -import stmbench7.core._ +import scala.concurrent.stm.Ref + +import stmbench7.core.Assembly +import stmbench7.core.ComplexAssembly +import stmbench7.core.Module abstract class AssemblyImpl( id: Int, @@ -17,10 +20,10 @@ abstract class AssemblyImpl( private val module = Ref(module0).single private val superAssembly = Ref(superAssembly0).single - def getSuperAssembly = superAssembly() - def getModule = module() + override def getSuperAssembly: ComplexAssembly = superAssembly() + override def getModule: Module = module() - def clearPointers() { + override def clearPointers(): Unit = { superAssembly() = null module() = null } diff --git a/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/AtomicPartImpl.scala b/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/AtomicPartImpl.scala index 8fb491ef..bd5f5480 100644 --- a/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/AtomicPartImpl.scala +++ b/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/AtomicPartImpl.scala @@ -2,40 +2,47 @@ package stmbench7.scalastm -import scala.concurrent.stm._ -import stmbench7.core._ +import scala.concurrent.stm.atomic +import scala.concurrent.stm.Ref +import scala.concurrent.stm.TSet + +import stmbench7.core.AtomicPart +import stmbench7.core.CompositePart +import stmbench7.core.Connection import stmbench7.impl.core.ConnectionImpl class AtomicPartImpl(id0: Int, typ0: String, bd0: Int, x0: Int, y0: Int) extends DesignObjImpl(id0, typ0, bd0) with AtomicPart { - val x = Ref(x0) - val y = Ref(y0) - val partOf = Ref(null: CompositePart).single - val from = TSet.empty[Connection].single // this is the equivant of SmallSetImpl - val to = TSet.empty[Connection].single - def connectTo(dest: AtomicPart, typ: String, length: Int) { + private val x = Ref(x0) + private val y = Ref(y0) + private val partOf = Ref(null: CompositePart).single + private val from = TSet.empty[Connection].single // this is the equivalent of SmallSetImpl + private val to = TSet.empty[Connection].single + + override def connectTo(dest: AtomicPart, typ: String, length: Int): Unit = { val c = new ConnectionImpl(this, dest, typ, length) to += c dest.addConnectionFromOtherPart(c.getReversed) } - def addConnectionFromOtherPart(c: Connection) { from += c } - def setCompositePart(po: CompositePart) { partOf() = po } - def getNumToConnections = to.size - def getToConnections = new ImmutableSetImpl[Connection](to) - def getFromConnections = new ImmutableSetImpl[Connection](from) - def getPartOf = partOf() - - def swapXY() { + + override def addConnectionFromOtherPart(c: Connection): Unit = { from += c } + override def setCompositePart(po: CompositePart): Unit = { partOf() = po } + override def getNumToConnections: Int = to.size + override def getToConnections = new ImmutableSetImpl[Connection](to) + override def getFromConnections = new ImmutableSetImpl[Connection](from) + override def getPartOf: CompositePart = partOf() + + override def swapXY(): Unit = { atomic { implicit t => y() = x.swap(y()) } } - def getX = x.single() - def getY = y.single() + override def getX: Int = x.single() + override def getY: Int = y.single() - def clearPointers() { + override def clearPointers(): Unit = { atomic { implicit t => x() = 0 y() = 0 @@ -46,6 +53,6 @@ class AtomicPartImpl(id0: Int, typ0: String, bd0: Int, x0: Int, y0: Int) } // Comparable[AtomicPart] - def compareTo(rhs: AtomicPart) = + override def compareTo(rhs: AtomicPart): Int = getId - rhs.getId // subtraction is faithful to reference impl } diff --git a/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/BaseAssemblyImpl.scala b/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/BaseAssemblyImpl.scala index fc7abed3..850e542d 100644 --- a/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/BaseAssemblyImpl.scala +++ b/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/BaseAssemblyImpl.scala @@ -2,8 +2,12 @@ package stmbench7.scalastm -import scala.concurrent.stm._ -import stmbench7.core._ +import scala.concurrent.stm.Ref + +import stmbench7.core.BaseAssembly +import stmbench7.core.ComplexAssembly +import stmbench7.core.CompositePart +import stmbench7.core.Module class BaseAssemblyImpl( id: Int, @@ -14,15 +18,15 @@ class BaseAssemblyImpl( ) extends AssemblyImpl(id, typ, buildDate, module, superAssembly) with BaseAssembly { - val components = + private val components = Ref(List.empty[CompositePart]).single // the original BagImpl was just an ArrayList - def addComponent(component: CompositePart) { + override def addComponent(component: CompositePart): Unit = { components.transform(component :: _) component.addAssembly(this) } - def removeComponent(component: CompositePart) = { + override def removeComponent(component: CompositePart): Boolean = { val f = components transformIfDefined { case x if x contains component => x filterNot { _ == component } } @@ -30,9 +34,9 @@ class BaseAssemblyImpl( f } - def getComponents = new ImmutableSeqImpl[CompositePart](components()) + override def getComponents = new ImmutableSeqImpl[CompositePart](components()) - override def clearPointers() { + override def clearPointers(): Unit = { super.clearPointers() components() = null } diff --git a/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/ComplexAssemblyImpl.scala b/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/ComplexAssemblyImpl.scala index 41101442..99306215 100644 --- a/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/ComplexAssemblyImpl.scala +++ b/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/ComplexAssemblyImpl.scala @@ -2,9 +2,14 @@ package stmbench7.scalastm -import scala.concurrent.stm._ -import stmbench7.core._ +import scala.concurrent.stm.TSet + import stmbench7.Parameters +import stmbench7.core.Assembly +import stmbench7.core.BaseAssembly +import stmbench7.core.ComplexAssembly +import stmbench7.core.Module +import stmbench7.core.RuntimeError class ComplexAssemblyImpl( id: Int, @@ -15,25 +20,25 @@ class ComplexAssemblyImpl( ) extends AssemblyImpl(id, typ, buildDate, module, superAssembly) with ComplexAssembly { - val subAssemblies = TSet.empty[Assembly].single + private val subAssemblies = TSet.empty[Assembly].single - val level = + private val level = if (superAssembly == null) Parameters.NumAssmLevels else superAssembly.getLevel - 1 - def addSubAssembly(assembly: Assembly) = { + override def addSubAssembly(assembly: Assembly): Boolean = { if (assembly.isInstanceOf[BaseAssembly] && level != 2) throw new RuntimeError("ComplexAssembly.addAssembly: BaseAssembly at wrong level!"); subAssemblies.add(assembly) } - def removeSubAssembly(assembly: Assembly) = subAssemblies.remove(assembly) + override def removeSubAssembly(assembly: Assembly): Boolean = subAssemblies.remove(assembly) - def getSubAssemblies = new ImmutableSetImpl[Assembly](subAssemblies) + override def getSubAssemblies = new ImmutableSetImpl[Assembly](subAssemblies) - def getLevel = level.asInstanceOf[Short] + override def getLevel: Short = level.asInstanceOf[Short] - override def clearPointers() { + override def clearPointers(): Unit = { super.clearPointers() subAssemblies.clear() } diff --git a/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/CompositePartImpl.scala b/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/CompositePartImpl.scala index 0fa84dde..8192aa59 100644 --- a/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/CompositePartImpl.scala +++ b/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/CompositePartImpl.scala @@ -2,22 +2,29 @@ package stmbench7.scalastm -import scala.concurrent.stm._ -import stmbench7.core._ +import scala.concurrent.stm.Ref + import stmbench7.backend.BackendFactory +import stmbench7.backend.LargeSet +import stmbench7.core.AtomicPart +import stmbench7.core.BaseAssembly +import stmbench7.core.CompositePart +import stmbench7.core.Document class CompositePartImpl(id: Int, typ: String, buildDate: Int, documentation0: Document) extends DesignObjImpl(id, typ, buildDate) with CompositePart { - val documentation = Ref(documentation0).single - val usedIn = Ref(List.empty[BaseAssembly]).single - val parts = Ref(BackendFactory.instance.createLargeSet[AtomicPart]).single - val rootPart = Ref(null: AtomicPart).single + + private val documentation = Ref(documentation0).single + private val usedIn = Ref(List.empty[BaseAssembly]).single + private val parts = Ref(BackendFactory.instance.createLargeSet[AtomicPart]).single + private val rootPart = Ref(null: AtomicPart).single + documentation0.setPart(this) - def addAssembly(assembly: BaseAssembly) { usedIn.transform(assembly :: _) } + override def addAssembly(assembly: BaseAssembly): Unit = { usedIn.transform(assembly :: _) } - def addPart(part: AtomicPart) = { + override def addPart(part: AtomicPart): Boolean = { val f = parts().add(part) if (f) { part.setCompositePart(this) @@ -26,20 +33,20 @@ class CompositePartImpl(id: Int, typ: String, buildDate: Int, documentation0: Do f } - def getRootPart = rootPart() - def setRootPart(part: AtomicPart) { rootPart() = part } + override def getRootPart: AtomicPart = rootPart() + override def setRootPart(part: AtomicPart): Unit = { rootPart() = part } - def getDocumentation = documentation() + override def getDocumentation: Document = documentation() - def getParts = parts() + override def getParts: LargeSet[AtomicPart] = parts() - def removeAssembly(assembly: BaseAssembly) { + override def removeAssembly(assembly: BaseAssembly): Unit = { usedIn.transform { _.filterNot(_ == assembly) } } - def getUsedIn = new ImmutableSeqImpl[BaseAssembly](usedIn()) + override def getUsedIn = new ImmutableSeqImpl[BaseAssembly](usedIn()) - def clearPointers() { + override def clearPointers(): Unit = { documentation() = null parts() = null usedIn() = null diff --git a/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/DesignObjImpl.scala b/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/DesignObjImpl.scala index f29f415c..426fd98a 100644 --- a/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/DesignObjImpl.scala +++ b/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/DesignObjImpl.scala @@ -2,15 +2,16 @@ package stmbench7.scalastm -import scala.concurrent.stm._ -import stmbench7.core._ +import scala.concurrent.stm.Ref + +import stmbench7.core.DesignObj class DesignObjImpl(id: Int, typ: String, buildDate0: Int) extends DesignObj { - val bd = Ref(buildDate0).single + private val bd = Ref(buildDate0).single - def getId = id - def getType = typ - def getBuildDate = bd() - def updateBuildDate() { if (bd() % 2 == 0) bd -= 1 else bd += 1 } - def nullOperation() {} + override def getId: Int = id + override def getType: String = typ + override def getBuildDate: Int = bd() + override def updateBuildDate(): Unit = { if (bd() % 2 == 0) bd -= 1 else bd += 1 } + override def nullOperation(): Unit = {} } diff --git a/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/DocumentImpl.scala b/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/DocumentImpl.scala index 2dc0d4c2..bb210ad6 100644 --- a/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/DocumentImpl.scala +++ b/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/DocumentImpl.scala @@ -3,34 +3,38 @@ package stmbench7.scalastm import scala.annotation.tailrec -import scala.concurrent.stm._ -import stmbench7.core._ + +import scala.concurrent.stm.Ref + +import stmbench7.core.CompositePart +import stmbench7.core.Document class DocumentImpl(id: Int, title: String, text0: String) extends Document { - val text = Ref(text0).single - val part = Ref(null: CompositePart).single + private val text = Ref(text0).single + private val part = Ref(null: CompositePart).single - def getDocumentId = id - def getTitle = title + override def getDocumentId: Int = id + override def getTitle: String = title - def getCompositePart = part() - def setPart(v: CompositePart) { part() = v } + override def getCompositePart: CompositePart = part() + override def setPart(v: CompositePart): Unit = { part() = v } - def nullOperation() {} + override def nullOperation(): Unit = {} - def getText = text() - def searchText(symbol: Char): Int = searchText(text(), symbol, 0, 0) + override def getText: String = text() + override def searchText(symbol: Char): Int = searchText(text(), symbol, 0, 0) @tailrec private def searchText(s: String, c: Char, pos: Int, n: Int): Int = { val i = s.indexOf(c, pos) if (i < 0) n else searchText(s, c, i + 1, n + 1) } - def replaceText(from: String, to: String) = { + override def replaceText(from: String, to: String): Int = { val f = text transformIfDefined { case s if s.startsWith(from) => s.replaceFirst(from, to) } if (f) 1 else 0 } - def textBeginsWith(prefix: String) = text().startsWith(prefix) + + override def textBeginsWith(prefix: String): Boolean = text().startsWith(prefix) } diff --git a/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/IdPoolImpl.scala b/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/IdPoolImpl.scala index 9aac4f0b..144954a6 100644 --- a/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/IdPoolImpl.scala +++ b/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/IdPoolImpl.scala @@ -2,18 +2,19 @@ package stmbench7.scalastm -import scala.concurrent.stm._ -import stmbench7.core._ +import scala.concurrent.stm.Ref + import stmbench7.backend.IdPool +import stmbench7.core.OperationFailedException object IdPoolImpl { class BoxedList(n: Int) extends IdPool { - val underlying = Ref(List.range(1, n + 1)).single + private val underlying = Ref(List.range(1, n + 1)).single - def putUnusedId(id: Int) { underlying.transform(id :: _) } + override def putUnusedId(id: Int): Unit = { underlying.transform(id :: _) } - def getId = { + override def getId: Int = { underlying.getAndTransform(_.drop(1)) match { case head :: _ => head case _ => throw new OperationFailedException diff --git a/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/ImmutableSeqImpl.scala b/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/ImmutableSeqImpl.scala index e9f4e1a4..2d95f8e4 100644 --- a/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/ImmutableSeqImpl.scala +++ b/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/ImmutableSeqImpl.scala @@ -3,11 +3,14 @@ package stmbench7.scalastm import scala.collection.JavaConversions + import stmbench7.backend.ImmutableCollection class ImmutableSeqImpl[A](contents: Seq[A]) extends ImmutableCollection[A] { - override def clone = this - def contains(element: A) = contents.contains(element) - def size = contents.size - def iterator = JavaConversions.asJavaIterator(contents.iterator) + override def clone: ImmutableCollection[A] = this + override def contains(element: A): Boolean = contents.contains(element) + override def size: Int = contents.size + + override def iterator: java.util.Iterator[A] = + JavaConversions.asJavaIterator(contents.iterator) } diff --git a/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/ImmutableSetImpl.scala b/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/ImmutableSetImpl.scala index 66a0b6e5..a350d560 100644 --- a/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/ImmutableSetImpl.scala +++ b/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/ImmutableSetImpl.scala @@ -3,16 +3,21 @@ package stmbench7.scalastm import scala.collection.JavaConversions -import scala.concurrent.stm._ + +import scala.concurrent.stm.TSet + import stmbench7.backend.ImmutableCollection /** Read-only wrapper */ class ImmutableSetImpl[A](contents: TSet.View[A], shared: Boolean = true) extends ImmutableCollection[A] { - override def clone: ImmutableSetImpl[A] = + override def clone: ImmutableCollection[A] = if (!shared) this else new ImmutableSetImpl(contents.clone(), false) - def contains(element: A) = contents.contains(element) - def size = contents.size - def iterator = JavaConversions.asJavaIterator(contents.iterator) + + override def contains(element: A): Boolean = contents.contains(element) + override def size: Int = contents.size + + override def iterator: java.util.Iterator[A] = + JavaConversions.asJavaIterator(contents.iterator) } diff --git a/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/IndexImpl.scala b/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/IndexImpl.scala index 6e60af48..88fb9ee2 100644 --- a/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/IndexImpl.scala +++ b/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/IndexImpl.scala @@ -2,50 +2,48 @@ package stmbench7.scalastm -import scala.annotation._ -import scala.collection.immutable.TreeMap -import scala.collection.mutable.ArrayBuffer import scala.collection.JavaConversions -import scala.concurrent.stm._ +import scala.collection.immutable.TreeMap + +import scala.concurrent.stm.Ref + import stmbench7.backend.Index object IndexImpl { - class BoxedImmutable[A <: Comparable[A], B] extends Index[A, B] { - + class BoxedImmutable[K <: Comparable[K], V] extends Index[K, V] { // needed for 2.8, harmless in 2.9 - implicit val order = new Ordering[A] { - def compare(lhs: A, rhs: A) = lhs compareTo rhs - } + implicit val order: Ordering[K] = (lhs: K, rhs: K) => lhs compareTo rhs - val underlying = Ref(TreeMap.empty[A, B]).single + private val underlying = Ref(TreeMap.empty[K, V]).single - def get(key: A) = underlying().getOrElse(key, null.asInstanceOf[B]) + override def get(key: K): V = underlying().getOrElse(key, null.asInstanceOf[V]) - def put(key: A, value: B) { underlying.transform(_ + (key -> value)) } + override def put(key: K, value: V): Unit = { underlying.transform(_ + (key -> value)) } - def putIfAbsent(key: A, value: B): B = { + override def putIfAbsent(key: K, value: V): V = { underlying .getAndTransform({ m => if (m.contains(key)) m else m + (key -> value) }) - .getOrElse(key, null.asInstanceOf[B]) + .getOrElse(key, null.asInstanceOf[V]) } - def remove(key: A) = + override def remove(key: K): Boolean = underlying transformIfDefined { case m if m.contains(key) => m - key } - def iterator = makeValuesIterator(underlying()) + override def iterator: java.util.Iterator[V] = makeValuesIterator(underlying()) - def getKeys = JavaConversions.setAsJavaSet(underlying().keySet) + override def getKeys: java.lang.Iterable[K] = + JavaConversions.setAsJavaSet(underlying().keySet) - def getRange(minKey: A, maxKey: A) = - new java.lang.Iterable[B] { - val range = underlying().range(minKey, maxKey) - def iterator = makeValuesIterator(range) + override def getRange(minKey: K, maxKey: K): java.lang.Iterable[V] = + new java.lang.Iterable[V] { + private val range = underlying().range(minKey, maxKey) + override def iterator: java.util.Iterator[V] = makeValuesIterator(range) } - private def makeValuesIterator(m: TreeMap[A, B]) = { + private def makeValuesIterator(m: TreeMap[K, V]) = { JavaConversions.asJavaIterator(m.values.iterator) } } diff --git a/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/LargeSetImpl.scala b/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/LargeSetImpl.scala index 2422f004..614c4265 100644 --- a/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/LargeSetImpl.scala +++ b/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/LargeSetImpl.scala @@ -3,17 +3,19 @@ package stmbench7.scalastm import scala.collection.JavaConversions -import scala.concurrent.stm._ -import stmbench7.backend.LargeSet -// LargeSetImpl +import scala.concurrent.stm.TMap + +import stmbench7.backend.LargeSet class LargeSetImpl[A <: Comparable[A]] extends LargeSet[A] { - val underlying = TMap.empty[A, Unit].single + private val underlying = TMap.empty[A, Unit].single + + override def add(e: A): Boolean = underlying.put(e, ()).isEmpty + override def remove(e: A): Boolean = underlying.remove(e).isDefined + override def contains(e: A): Boolean = underlying.contains(e) + override def size: Int = underlying.size - def add(e: A) = underlying.put(e, ()).isEmpty - def remove(e: A) = !underlying.remove(e).isEmpty - def contains(e: A) = underlying.contains(e) - def size = underlying.size - def iterator = JavaConversions.asJavaIterator(underlying.keysIterator) + override def iterator: java.util.Iterator[A] = + JavaConversions.asJavaIterator(underlying.keysIterator) } diff --git a/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/ManualImpl.scala b/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/ManualImpl.scala index 09688b7e..b34fc8e7 100644 --- a/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/ManualImpl.scala +++ b/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/ManualImpl.scala @@ -2,39 +2,40 @@ package stmbench7.scalastm -import scala.concurrent.stm._ -import scala.collection.immutable.WrappedString import scala.annotation.tailrec -import stmbench7.core._ + +import scala.concurrent.stm.Ref + +import stmbench7.core.Manual +import stmbench7.core.Module class ManualImpl(id: Int, title0: String, text0: String) extends Manual { - val title = Ref(title0).single - val text = Ref(text0).single - val module = Ref(null: Module).single + private val title = Ref(title0).single + private val text = Ref(text0).single + private val module = Ref(null: Module).single - def getId = id - def getTitle = title() - def getText = text() - def getModule = module() + override def getId: Int = id + override def getTitle: String = title() + override def getText: String = text() + override def getModule: Module = module() - def setModule(v: Module) { module() = v } + override def setModule(v: Module): Unit = { module() = v } - def countOccurences(ch: Char): Int = countOccurrences(ch) - def countOccurrences(ch: Char): Int = countOccurrences(text(), ch, 0, 0) + override def countOccurences(ch: Char): Int = countOccurrences(text(), ch, 0, 0) @tailrec private def countOccurrences(s: String, c: Char, pos: Int, n: Int): Int = { val i = s.indexOf(c, pos) if (i < 0) n else countOccurrences(s, c, i + 1, n + 1) } - def checkFirstLastCharTheSame = { + override def checkFirstLastCharTheSame: Int = { val t = text() if (t.charAt(0) == t.charAt(t.length - 1)) 1 else 0 } - def startsWith(ch: Char) = text().charAt(0) == ch + override def startsWith(ch: Char): Boolean = text().charAt(0) == ch - def replaceChar(from: Char, to: Char) = { + override def replaceChar(from: Char, to: Char): Int = { text.transform(_.replace(from, to)) countOccurences(to) } diff --git a/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/ModuleImpl.scala b/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/ModuleImpl.scala index 223df5ca..4bc462cc 100644 --- a/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/ModuleImpl.scala +++ b/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/ModuleImpl.scala @@ -2,18 +2,21 @@ package stmbench7.scalastm -import scala.concurrent.stm._ -import stmbench7.core._ +import scala.concurrent.stm.Ref + +import stmbench7.core.ComplexAssembly +import stmbench7.core.Manual +import stmbench7.core.Module class ModuleImpl(id: Int, typ: String, buildDate: Int, man: Manual) extends DesignObjImpl(id, typ, buildDate) with Module { - val designRoot = Ref(null: ComplexAssembly).single + private val designRoot = Ref(null: ComplexAssembly).single man.setModule(this) - def setDesignRoot(v: ComplexAssembly) { designRoot() = v } - def getDesignRoot = designRoot() - def getManual = man + override def setDesignRoot(v: ComplexAssembly): Unit = { designRoot() = v } + override def getDesignRoot: ComplexAssembly = designRoot() + override def getManual: Manual = man } diff --git a/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/ScalaSTMInitializer.scala b/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/ScalaSTMInitializer.scala index cc25bcaa..16aad7d8 100644 --- a/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/ScalaSTMInitializer.scala +++ b/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/ScalaSTMInitializer.scala @@ -2,22 +2,37 @@ package stmbench7.scalastm -import scala.concurrent.stm._ -import stmbench7.backend._ -import stmbench7.core._ +import scala.concurrent.stm.atomic +import scala.concurrent.stm.Ref + +import stmbench7.OperationExecutor +import stmbench7.OperationExecutorFactory +import stmbench7.Parameters +import stmbench7.SynchMethodInitializer +import stmbench7.ThreadFactory +import stmbench7.backend.BackendFactory +import stmbench7.backend.IdPool +import stmbench7.backend.Index +import stmbench7.backend.LargeSet +import stmbench7.core.AtomicPart +import stmbench7.core.ComplexAssembly +import stmbench7.core.DesignObjFactory +import stmbench7.core.Document +import stmbench7.core.Manual +import stmbench7.core.Module +import stmbench7.core.Operation import stmbench7.impl.core.ConnectionImpl -import stmbench7._ class ScalaSTMInitializer extends SynchMethodInitializer { - def createOperationExecutorFactory() = + def createOperationExecutorFactory(): OperationExecutorFactory = new OperationExecutorFactory { - val timestamp = Ref(0) + private val timestamp = Ref(0) - def createOperationExecutor(op: Operation) = + def createOperationExecutor(op: Operation): OperationExecutor = new OperationExecutor { - var lastTS = 0 + private var lastTS = 0 def execute(): Int = { atomic { implicit t => @@ -30,11 +45,11 @@ class ScalaSTMInitializer extends SynchMethodInitializer { } } - def getLastOperationTimestamp = lastTS + def getLastOperationTimestamp: Int = lastTS } } - def createBackendFactory() = + def createBackendFactory(): BackendFactory = new BackendFactory { // a couple hundred, not ordered, except for huge numbers of discarded @@ -47,7 +62,7 @@ class ScalaSTMInitializer extends SynchMethodInitializer { def createIdPool(maxNumberOfIds: Int): IdPool = new IdPoolImpl.BoxedList(maxNumberOfIds) } - def createDesignObjFactory() = + def createDesignObjFactory(): DesignObjFactory = new DesignObjFactory { def createAtomicPart(id: Int, typ: String, bd: Int, x: Int, y: Int) = @@ -87,8 +102,6 @@ class ScalaSTMInitializer extends SynchMethodInitializer { new ModuleImpl(id, typ, buildDate, man) } - def createThreadFactory() = - new stmbench7.ThreadFactory { - def createThread(body: Runnable) = new Thread(body) - } + def createThreadFactory(): ThreadFactory = + (body: Runnable) => new Thread(body) } From cdb788f0a99835bbd1430d23461c71b23a5367b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lubom=C3=ADr=20Bulej?= Date: Sun, 26 May 2024 15:57:04 +0200 Subject: [PATCH 7/9] Remove the scala-stm-library subproject This removes both the scala-stm library sources, the (unused, uncompilable) stmbench7 sources, and the stmbench7-VELOX and deuceAgent jars. --- .../scala-stm/scala-stm-library/.gitignore | 10 - .../scala-stm/scala-stm-library/BUILDING.txt | 15 - .../scala-stm/scala-stm-library/LICENSE.txt | 24 - benchmarks/scala-stm/scala-stm-library/README | 6 - .../scala-stm-library/RELEASE-NOTES.txt | 94 -- .../scala-stm/scala-stm-library/bin/all_tests | 19 - .../scala-stm-library/bin/fix_copyrights | 8 - .../scala-stm-library/bin/perf_sample | 34 - .../scala-stm-library/bin/test_coverage | 44 - .../scala-stm/scala-stm-library/build.sbt | 25 - .../dep_tests/PUBLISHING.txt | 20 - .../scala-stm-library/dep_tests/check_central | 26 - .../maven/RUN_MAVEN_HERE_TO_TEST_DEPS | 0 .../scala-stm-library/dep_tests/maven/pom.xml | 91 -- .../maven/src/main/scala/HelloWorld.scala | 8 - .../dep_tests/sbt/RUN_SBT_HERE_TO_TEST_DEPS | 0 .../scala-stm-library/dep_tests/sbt/build.sbt | 16 - .../sbt/src/main/scala/HelloWorld.scala | 8 - .../lib/deuceAgent-1.3.0.jar | Bin 212722 -> 0 bytes .../lib/sb7-java-v1.2/README | 106 -- .../lib/sb7-java-v1.2/README.VELOX | 55 -- .../lib/sb7-java-v1.2/build.xml | 97 -- .../src/stmbench7/BenchThread.java | 172 ---- .../src/stmbench7/Benchmark.java | 563 ----------- .../src/stmbench7/ImplParameters.java | 30 - .../src/stmbench7/OperationExecutor.java | 17 - .../stmbench7/OperationExecutorFactory.java | 41 - .../src/stmbench7/OperationId.java | 121 --- .../src/stmbench7/OperationType.java | 22 - .../src/stmbench7/Parameters.java | 121 --- .../sb7-java-v1.2/src/stmbench7/Setup.java | 95 -- .../src/stmbench7/SynchMethodInitializer.java | 20 - .../src/stmbench7/ThreadFactory.java | 20 - .../src/stmbench7/ThreadRandom.java | 136 --- .../src/stmbench7/annotations/Atomic.java | 17 - .../annotations/ContainedInAtomic.java | 17 - .../src/stmbench7/annotations/Immutable.java | 18 - .../src/stmbench7/annotations/NonAtomic.java | 17 - .../src/stmbench7/annotations/ReadOnly.java | 14 - .../stmbench7/annotations/ThreadLocal.java | 17 - .../stmbench7/annotations/Transactional.java | 14 - .../src/stmbench7/annotations/Update.java | 14 - .../src/stmbench7/backend/BackendFactory.java | 21 - .../src/stmbench7/backend/IdPool.java | 22 - .../backend/ImmutableCollection.java | 14 - .../src/stmbench7/backend/Index.java | 31 - .../src/stmbench7/backend/LargeSet.java | 28 - .../src/stmbench7/core/Assembly.java | 22 - .../src/stmbench7/core/AssemblyBuilder.java | 121 --- .../src/stmbench7/core/AtomicPart.java | 47 - .../src/stmbench7/core/AtomicPartBuilder.java | 57 -- .../src/stmbench7/core/BaseAssembly.java | 23 - .../src/stmbench7/core/ComplexAssembly.java | 26 - .../src/stmbench7/core/CompositePart.java | 42 - .../stmbench7/core/CompositePartBuilder.java | 131 --- .../src/stmbench7/core/Connection.java | 17 - .../src/stmbench7/core/DesignObj.java | 28 - .../src/stmbench7/core/DesignObjBuilder.java | 38 - .../src/stmbench7/core/DesignObjFactory.java | 33 - .../src/stmbench7/core/Document.java | 40 - .../src/stmbench7/core/DocumentBuilder.java | 42 - .../src/stmbench7/core/Manual.java | 40 - .../src/stmbench7/core/ManualBuilder.java | 28 - .../src/stmbench7/core/Module.java | 22 - .../src/stmbench7/core/ModuleBuilder.java | 46 - .../src/stmbench7/core/Operation.java | 23 - .../core/OperationFailedException.java | 31 - .../src/stmbench7/core/RuntimeError.java | 31 - .../correctness/invariants/AssemblyTest.java | 31 - .../invariants/AtomicPartTest.java | 59 -- .../invariants/BaseAssemblyTest.java | 28 - .../invariants/CheckInvariantsOperation.java | 42 - .../invariants/ComplexAssemblyTest.java | 44 - .../invariants/CompositePartTest.java | 65 -- .../invariants/ConnectionTest.java | 28 - .../correctness/invariants/DesignObjTest.java | 45 - .../invariants/DocumentationTest.java | 39 - .../correctness/invariants/IndexTest.java | 121 --- .../correctness/invariants/InvariantTest.java | 35 - .../correctness/invariants/ManualTest.java | 36 - .../correctness/invariants/ModuleTest.java | 30 - .../invariants/TraversedObjects.java | 34 - .../opacity/SequentialReplayThread.java | 70 -- .../opacity/StructureComparisonOperation.java | 336 ------- .../impl/DefaultOperationExecutor.java | 30 - .../impl/DefaultOperationExecutorFactory.java | 19 - .../stmbench7/impl/DefaultThreadFactory.java | 11 - .../impl/NoSynchronizationInitializer.java | 34 - .../impl/backend/BackendFactoryImpl.java | 30 - .../src/stmbench7/impl/backend/BagImpl.java | 27 - .../stmbench7/impl/backend/IdPoolImpl.java | 52 - .../impl/backend/ImmutableViewImpl.java | 32 - .../stmbench7/impl/backend/LargeSetImpl.java | 35 - .../stmbench7/impl/backend/SmallSetImpl.java | 35 - .../stmbench7/impl/backend/TreeMapIndex.java | 66 -- .../src/stmbench7/impl/core/AssemblyImpl.java | 52 - .../stmbench7/impl/core/AtomicPartImpl.java | 111 --- .../stmbench7/impl/core/BaseAssemblyImpl.java | 72 -- .../impl/core/ComplexAssemblyImpl.java | 84 -- .../impl/core/CompositePartImpl.java | 96 -- .../stmbench7/impl/core/ConnectionImpl.java | 53 - .../impl/core/DesignObjFactoryImpl.java | 63 -- .../stmbench7/impl/core/DesignObjImpl.java | 85 -- .../src/stmbench7/impl/core/DocumentImpl.java | 95 -- .../src/stmbench7/impl/core/ManualImpl.java | 107 -- .../src/stmbench7/impl/core/ModuleImpl.java | 46 - .../impl/deucestm/DeuceSTMInitializer.java | 12 - .../deucestm/DeuceSTMOperationExecutor.java | 24 - .../DeuceSTMOperationExecutorFactory.java | 17 - .../locking/CGLockingInitializer.java | 16 - .../locking/CGLockingOperationExecutor.java | 64 -- .../CGLockingOperationExecutorFactory.java | 17 - .../locking/MGLockingComplexAssemblyImpl.java | 50 - .../locking/MGLockingDesignObjFactory.java | 22 - .../locking/MGLockingInitializer.java | 20 - .../locking/MGLockingOperationExecutor.java | 316 ------ .../MGLockingOperationExecutorFactory.java | 17 - .../stmbench7/operations/BaseOperation.java | 54 -- .../src/stmbench7/operations/Operation10.java | 35 - .../src/stmbench7/operations/Operation11.java | 38 - .../src/stmbench7/operations/Operation12.java | 35 - .../src/stmbench7/operations/Operation13.java | 35 - .../src/stmbench7/operations/Operation14.java | 35 - .../src/stmbench7/operations/Operation15.java | 42 - .../src/stmbench7/operations/Operation6.java | 56 -- .../src/stmbench7/operations/Operation7.java | 53 - .../src/stmbench7/operations/Operation8.java | 50 - .../src/stmbench7/operations/Operation9.java | 35 - .../src/stmbench7/operations/Query1.java | 51 - .../src/stmbench7/operations/Query2.java | 57 -- .../src/stmbench7/operations/Query3.java | 20 - .../src/stmbench7/operations/Query4.java | 52 - .../src/stmbench7/operations/Query5.java | 52 - .../src/stmbench7/operations/Query6.java | 55 -- .../src/stmbench7/operations/Query7.java | 37 - .../operations/SetupDataStructure.java | 76 -- .../stmbench7/operations/ShortTraversal1.java | 95 -- .../operations/ShortTraversal10.java | 36 - .../stmbench7/operations/ShortTraversal2.java | 39 - .../stmbench7/operations/ShortTraversal6.java | 36 - .../stmbench7/operations/ShortTraversal7.java | 39 - .../stmbench7/operations/ShortTraversal8.java | 35 - .../stmbench7/operations/ShortTraversal9.java | 56 -- .../operations/StructuralModification1.java | 32 - .../operations/StructuralModification2.java | 41 - .../operations/StructuralModification3.java | 47 - .../operations/StructuralModification4.java | 56 -- .../operations/StructuralModification5.java | 48 - .../operations/StructuralModification6.java | 46 - .../operations/StructuralModification7.java | 46 - .../operations/StructuralModification8.java | 43 - .../src/stmbench7/operations/Traversal1.java | 89 -- .../src/stmbench7/operations/Traversal2a.java | 43 - .../src/stmbench7/operations/Traversal2b.java | 30 - .../src/stmbench7/operations/Traversal2c.java | 33 - .../src/stmbench7/operations/Traversal3a.java | 54 -- .../src/stmbench7/operations/Traversal3b.java | 30 - .../src/stmbench7/operations/Traversal3c.java | 32 - .../src/stmbench7/operations/Traversal4.java | 46 - .../src/stmbench7/operations/Traversal5.java | 44 - .../src/stmbench7/operations/Traversal6.java | 41 - .../src/stmbench7/operations/Traversal7.java | 70 -- .../src/stmbench7/operations/Traversal8.java | 37 - .../src/stmbench7/operations/Traversal9.java | 26 - .../src/stmbench7/test/backend/IndexTest.java | 227 ----- .../lib/sb7-java-v1.2/stmbench7-VELOX-1.2.tgz | Bin 44037 -> 0 bytes .../lib/stmbench7-VELOX-1.2.jar | Bin 135813 -> 0 bytes .../scala/concurrent/stm/CommitBarrier.scala | 184 ---- .../scala/scala/concurrent/stm/InTxn.scala | 14 - .../scala/scala/concurrent/stm/InTxnEnd.scala | 31 - .../scala/scala/concurrent/stm/MaybeTxn.scala | 17 - .../scala/concurrent/stm/NestingLevel.scala | 60 -- .../concurrent/stm/PendingAtomicBlock.scala | 37 - .../main/scala/scala/concurrent/stm/Ref.scala | 302 ------ .../scala/scala/concurrent/stm/RefLike.scala | 119 --- .../scala/scala/concurrent/stm/Sink.scala | 48 - .../scala/scala/concurrent/stm/SinkLike.scala | 43 - .../scala/scala/concurrent/stm/Source.scala | 102 -- .../scala/concurrent/stm/SourceLike.scala | 79 -- .../scala/scala/concurrent/stm/TArray.scala | 94 -- .../scala/scala/concurrent/stm/TMap.scala | 121 --- .../scala/scala/concurrent/stm/TSet.scala | 115 --- .../main/scala/scala/concurrent/stm/Txn.scala | 325 ------- .../scala/concurrent/stm/TxnDebuggable.scala | 62 -- .../scala/concurrent/stm/TxnExecutor.scala | 226 ----- .../scala/scala/concurrent/stm/TxnLocal.scala | 79 -- .../scala/concurrent/stm/TxnUnknown.scala | 11 - .../concurrent/stm/ccstm/AccessHistory.scala | 745 -------------- .../scala/concurrent/stm/ccstm/CCSTM.scala | 325 ------- .../concurrent/stm/ccstm/CCSTMExecutor.scala | 104 -- .../concurrent/stm/ccstm/CCSTMRefs.scala | 133 --- .../stm/ccstm/CommitBarrierImpl.scala | 233 ----- .../scala/concurrent/stm/ccstm/Counter.scala | 52 - .../scala/concurrent/stm/ccstm/GV6.scala | 139 --- .../scala/concurrent/stm/ccstm/Handle.scala | 52 - .../concurrent/stm/ccstm/InTxnImpl.scala | 914 ------------------ .../concurrent/stm/ccstm/InTxnRefOps.scala | 430 -------- .../scala/concurrent/stm/ccstm/NonTxn.scala | 594 ------------ .../scala/concurrent/stm/ccstm/RefOps.scala | 47 - .../scala/concurrent/stm/ccstm/RetrySet.scala | 107 -- .../stm/ccstm/RetrySetBuilder.scala | 80 -- .../scala/concurrent/stm/ccstm/Stats.scala | 131 --- .../concurrent/stm/ccstm/TArrayImpl.scala | 99 -- .../concurrent/stm/ccstm/TxnLevelImpl.scala | 291 ------ .../concurrent/stm/ccstm/TxnLocalImpl.scala | 109 --- .../concurrent/stm/ccstm/TxnSlotManager.scala | 109 --- .../concurrent/stm/ccstm/UnrecordedRead.scala | 58 -- .../scala/concurrent/stm/ccstm/ViewOps.scala | 74 -- .../concurrent/stm/ccstm/WakeupManager.scala | 191 ---- .../stm/impl/AlternativeResult.scala | 9 - .../concurrent/stm/impl/RefFactory.scala | 42 - .../scala/concurrent/stm/impl/STMImpl.scala | 135 --- .../concurrent/stm/impl/TxnContext.scala | 24 - .../scala/scala/concurrent/stm/japi/STM.scala | 188 ---- .../scala/scala/concurrent/stm/package.scala | 24 - .../concurrent/stm/skel/AbstractInTxn.scala | 262 ----- .../stm/skel/AbstractNestingLevel.scala | 21 - .../concurrent/stm/skel/AtomicArray.scala | 272 ------ .../stm/skel/AtomicArrayBuilder.scala | 240 ----- .../concurrent/stm/skel/CallbackList.scala | 96 -- .../concurrent/stm/skel/HashTrieTMap.scala | 73 -- .../concurrent/stm/skel/HashTrieTSet.scala | 64 -- .../concurrent/stm/skel/RollbackError.scala | 16 - .../concurrent/stm/skel/SimpleRandom.scala | 120 --- .../scala/concurrent/stm/skel/StubInTxn.scala | 23 - .../concurrent/stm/skel/StubSTMImpl.scala | 66 -- .../concurrent/stm/skel/TMapViaClone.scala | 87 -- .../concurrent/stm/skel/TSetViaClone.scala | 67 -- .../concurrent/stm/skel/TxnHashTrie.scala | 840 ---------------- .../scala/concurrent/stm/JavaAPITests.java | 176 ---- .../scala/concurrent/stm/TestException.java | 9 - .../scala/concurrent/stm/CallbackSuite.scala | 582 ----------- .../concurrent/stm/CommitBarrierSuite.scala | 447 --------- .../concurrent/stm/ContentionSuite.scala | 170 ---- .../scala/concurrent/stm/FlipperSuite.scala | 282 ------ .../scala/concurrent/stm/HistogramSuite.scala | 120 --- .../scala/concurrent/stm/InterruptSuite.scala | 133 --- .../concurrent/stm/IsolatedRefSuite.scala | 644 ------------ .../scala/concurrent/stm/JavaAPISuite.scala | 7 - .../scala/concurrent/stm/MaybeTxnSuite.scala | 90 -- .../stm/RelaxedValidationSuite.scala | 184 ---- .../scala/concurrent/stm/RetrySuite.scala | 520 ---------- .../scala/scala/concurrent/stm/Slow.scala | 7 - .../scala/concurrent/stm/TMapSuite.scala | 680 ------------- .../scala/concurrent/stm/TSetSuite.scala | 421 -------- .../scala/concurrent/stm/TokenRingSuite.scala | 85 -- .../scala/concurrent/stm/TxnLocalSuite.scala | 332 ------- .../scala/scala/concurrent/stm/TxnSuite.scala | 640 ------------ .../concurrent/stm/UnrecordedTxnSuite.scala | 154 --- .../scala/concurrent/stm/WriteSkewSuite.scala | 61 -- .../concurrent/stm/examples/BasicSyntax.scala | 49 - .../stm/examples/ConcurrentIntList.scala | 80 -- .../stm/examples/DiningPhilosophers.scala | 57 -- .../concurrent/stm/examples/IndexedMap.scala | 152 --- .../examples/RealityShowPhilosophers.scala | 92 -- .../stm/examples/SyntaxCheatSheet.scala | 39 - .../concurrent/stm/impl/RefFactorySuite.scala | 145 --- .../stm/skel/AtomicArraySuite.scala | 133 --- .../stm/skel/SimpleRandomSuite.scala | 65 -- .../stmbench7/scalastm/AssemblyImpl.scala | 21 - .../stmbench7/scalastm/AtomicPartImpl.scala | 46 - .../stmbench7/scalastm/BaseAssemblyImpl.scala | 32 - .../scalastm/ComplexAssemblyImpl.scala | 32 - .../scalastm/CompositePartImpl.scala | 47 - .../stmbench7/scalastm/DesignObjImpl.scala | 16 - .../stmbench7/scalastm/DocumentImpl.scala | 34 - .../scala/stmbench7/scalastm/IdPoolImpl.scala | 22 - .../stmbench7/scalastm/ImmutableSeqImpl.scala | 13 - .../stmbench7/scalastm/ImmutableSetImpl.scala | 15 - .../scala/stmbench7/scalastm/IndexImpl.scala | 46 - .../stmbench7/scalastm/LargeSetImpl.scala | 19 - .../scala/stmbench7/scalastm/ManualImpl.scala | 40 - .../scala/stmbench7/scalastm/ModuleImpl.scala | 18 - .../scalastm/ScalaSTMInitializer.scala | 76 -- 274 files changed, 25202 deletions(-) delete mode 100644 benchmarks/scala-stm/scala-stm-library/.gitignore delete mode 100644 benchmarks/scala-stm/scala-stm-library/BUILDING.txt delete mode 100644 benchmarks/scala-stm/scala-stm-library/LICENSE.txt delete mode 100644 benchmarks/scala-stm/scala-stm-library/README delete mode 100644 benchmarks/scala-stm/scala-stm-library/RELEASE-NOTES.txt delete mode 100755 benchmarks/scala-stm/scala-stm-library/bin/all_tests delete mode 100755 benchmarks/scala-stm/scala-stm-library/bin/fix_copyrights delete mode 100755 benchmarks/scala-stm/scala-stm-library/bin/perf_sample delete mode 100755 benchmarks/scala-stm/scala-stm-library/bin/test_coverage delete mode 100644 benchmarks/scala-stm/scala-stm-library/build.sbt delete mode 100644 benchmarks/scala-stm/scala-stm-library/dep_tests/PUBLISHING.txt delete mode 100755 benchmarks/scala-stm/scala-stm-library/dep_tests/check_central delete mode 100644 benchmarks/scala-stm/scala-stm-library/dep_tests/maven/RUN_MAVEN_HERE_TO_TEST_DEPS delete mode 100644 benchmarks/scala-stm/scala-stm-library/dep_tests/maven/pom.xml delete mode 100644 benchmarks/scala-stm/scala-stm-library/dep_tests/maven/src/main/scala/HelloWorld.scala delete mode 100644 benchmarks/scala-stm/scala-stm-library/dep_tests/sbt/RUN_SBT_HERE_TO_TEST_DEPS delete mode 100644 benchmarks/scala-stm/scala-stm-library/dep_tests/sbt/build.sbt delete mode 100644 benchmarks/scala-stm/scala-stm-library/dep_tests/sbt/src/main/scala/HelloWorld.scala delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/deuceAgent-1.3.0.jar delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/README delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/README.VELOX delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/build.xml delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/BenchThread.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/Benchmark.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/ImplParameters.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/OperationExecutor.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/OperationExecutorFactory.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/OperationId.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/OperationType.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/Parameters.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/Setup.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/SynchMethodInitializer.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/ThreadFactory.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/ThreadRandom.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/annotations/Atomic.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/annotations/ContainedInAtomic.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/annotations/Immutable.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/annotations/NonAtomic.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/annotations/ReadOnly.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/annotations/ThreadLocal.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/annotations/Transactional.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/annotations/Update.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/backend/BackendFactory.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/backend/IdPool.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/backend/ImmutableCollection.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/backend/Index.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/backend/LargeSet.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/Assembly.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/AssemblyBuilder.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/AtomicPart.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/AtomicPartBuilder.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/BaseAssembly.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/ComplexAssembly.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/CompositePart.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/CompositePartBuilder.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/Connection.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/DesignObj.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/DesignObjBuilder.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/DesignObjFactory.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/Document.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/DocumentBuilder.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/Manual.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/ManualBuilder.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/Module.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/ModuleBuilder.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/Operation.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/OperationFailedException.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/RuntimeError.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/correctness/invariants/AssemblyTest.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/correctness/invariants/AtomicPartTest.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/correctness/invariants/BaseAssemblyTest.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/correctness/invariants/CheckInvariantsOperation.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/correctness/invariants/ComplexAssemblyTest.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/correctness/invariants/CompositePartTest.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/correctness/invariants/ConnectionTest.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/correctness/invariants/DesignObjTest.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/correctness/invariants/DocumentationTest.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/correctness/invariants/IndexTest.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/correctness/invariants/InvariantTest.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/correctness/invariants/ManualTest.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/correctness/invariants/ModuleTest.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/correctness/invariants/TraversedObjects.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/correctness/opacity/SequentialReplayThread.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/correctness/opacity/StructureComparisonOperation.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/DefaultOperationExecutor.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/DefaultOperationExecutorFactory.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/DefaultThreadFactory.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/NoSynchronizationInitializer.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/backend/BackendFactoryImpl.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/backend/BagImpl.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/backend/IdPoolImpl.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/backend/ImmutableViewImpl.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/backend/LargeSetImpl.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/backend/SmallSetImpl.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/backend/TreeMapIndex.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/core/AssemblyImpl.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/core/AtomicPartImpl.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/core/BaseAssemblyImpl.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/core/ComplexAssemblyImpl.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/core/CompositePartImpl.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/core/ConnectionImpl.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/core/DesignObjFactoryImpl.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/core/DesignObjImpl.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/core/DocumentImpl.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/core/ManualImpl.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/core/ModuleImpl.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/deucestm/DeuceSTMInitializer.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/deucestm/DeuceSTMOperationExecutor.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/deucestm/DeuceSTMOperationExecutorFactory.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/locking/CGLockingInitializer.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/locking/CGLockingOperationExecutor.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/locking/CGLockingOperationExecutorFactory.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/locking/MGLockingComplexAssemblyImpl.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/locking/MGLockingDesignObjFactory.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/locking/MGLockingInitializer.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/locking/MGLockingOperationExecutor.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/locking/MGLockingOperationExecutorFactory.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/BaseOperation.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Operation10.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Operation11.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Operation12.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Operation13.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Operation14.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Operation15.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Operation6.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Operation7.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Operation8.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Operation9.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Query1.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Query2.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Query3.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Query4.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Query5.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Query6.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Query7.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/SetupDataStructure.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/ShortTraversal1.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/ShortTraversal10.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/ShortTraversal2.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/ShortTraversal6.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/ShortTraversal7.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/ShortTraversal8.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/ShortTraversal9.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/StructuralModification1.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/StructuralModification2.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/StructuralModification3.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/StructuralModification4.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/StructuralModification5.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/StructuralModification6.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/StructuralModification7.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/StructuralModification8.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Traversal1.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Traversal2a.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Traversal2b.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Traversal2c.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Traversal3a.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Traversal3b.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Traversal3c.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Traversal4.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Traversal5.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Traversal6.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Traversal7.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Traversal8.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Traversal9.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/test/backend/IndexTest.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/stmbench7-VELOX-1.2.tgz delete mode 100644 benchmarks/scala-stm/scala-stm-library/lib/stmbench7-VELOX-1.2.jar delete mode 100644 benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/CommitBarrier.scala delete mode 100644 benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/InTxn.scala delete mode 100644 benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/InTxnEnd.scala delete mode 100644 benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/MaybeTxn.scala delete mode 100644 benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/NestingLevel.scala delete mode 100644 benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/PendingAtomicBlock.scala delete mode 100644 benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/Ref.scala delete mode 100644 benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/RefLike.scala delete mode 100644 benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/Sink.scala delete mode 100644 benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/SinkLike.scala delete mode 100644 benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/Source.scala delete mode 100644 benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/SourceLike.scala delete mode 100644 benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/TArray.scala delete mode 100644 benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/TMap.scala delete mode 100644 benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/TSet.scala delete mode 100644 benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/Txn.scala delete mode 100644 benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/TxnDebuggable.scala delete mode 100644 benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/TxnExecutor.scala delete mode 100644 benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/TxnLocal.scala delete mode 100644 benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/TxnUnknown.scala delete mode 100644 benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/ccstm/AccessHistory.scala delete mode 100644 benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/ccstm/CCSTM.scala delete mode 100644 benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/ccstm/CCSTMExecutor.scala delete mode 100644 benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/ccstm/CCSTMRefs.scala delete mode 100644 benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/ccstm/CommitBarrierImpl.scala delete mode 100644 benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/ccstm/Counter.scala delete mode 100644 benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/ccstm/GV6.scala delete mode 100644 benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/ccstm/Handle.scala delete mode 100644 benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/ccstm/InTxnImpl.scala delete mode 100644 benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/ccstm/InTxnRefOps.scala delete mode 100644 benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/ccstm/NonTxn.scala delete mode 100644 benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/ccstm/RefOps.scala delete mode 100644 benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/ccstm/RetrySet.scala delete mode 100644 benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/ccstm/RetrySetBuilder.scala delete mode 100644 benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/ccstm/Stats.scala delete mode 100644 benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/ccstm/TArrayImpl.scala delete mode 100644 benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/ccstm/TxnLevelImpl.scala delete mode 100644 benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/ccstm/TxnLocalImpl.scala delete mode 100644 benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/ccstm/TxnSlotManager.scala delete mode 100644 benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/ccstm/UnrecordedRead.scala delete mode 100644 benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/ccstm/ViewOps.scala delete mode 100644 benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/ccstm/WakeupManager.scala delete mode 100644 benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/impl/AlternativeResult.scala delete mode 100644 benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/impl/RefFactory.scala delete mode 100644 benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/impl/STMImpl.scala delete mode 100644 benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/impl/TxnContext.scala delete mode 100644 benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/japi/STM.scala delete mode 100644 benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/package.scala delete mode 100644 benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/skel/AbstractInTxn.scala delete mode 100644 benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/skel/AbstractNestingLevel.scala delete mode 100644 benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/skel/AtomicArray.scala delete mode 100644 benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/skel/AtomicArrayBuilder.scala delete mode 100644 benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/skel/CallbackList.scala delete mode 100644 benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/skel/HashTrieTMap.scala delete mode 100644 benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/skel/HashTrieTSet.scala delete mode 100644 benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/skel/RollbackError.scala delete mode 100644 benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/skel/SimpleRandom.scala delete mode 100644 benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/skel/StubInTxn.scala delete mode 100644 benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/skel/StubSTMImpl.scala delete mode 100644 benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/skel/TMapViaClone.scala delete mode 100644 benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/skel/TSetViaClone.scala delete mode 100644 benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/skel/TxnHashTrie.scala delete mode 100644 benchmarks/scala-stm/scala-stm-library/src/test/java/scala/concurrent/stm/JavaAPITests.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/src/test/java/scala/concurrent/stm/TestException.java delete mode 100644 benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/CallbackSuite.scala delete mode 100644 benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/CommitBarrierSuite.scala delete mode 100644 benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/ContentionSuite.scala delete mode 100644 benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/FlipperSuite.scala delete mode 100644 benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/HistogramSuite.scala delete mode 100644 benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/InterruptSuite.scala delete mode 100644 benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/IsolatedRefSuite.scala delete mode 100644 benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/JavaAPISuite.scala delete mode 100644 benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/MaybeTxnSuite.scala delete mode 100644 benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/RelaxedValidationSuite.scala delete mode 100644 benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/RetrySuite.scala delete mode 100644 benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/Slow.scala delete mode 100644 benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/TMapSuite.scala delete mode 100644 benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/TSetSuite.scala delete mode 100644 benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/TokenRingSuite.scala delete mode 100644 benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/TxnLocalSuite.scala delete mode 100644 benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/TxnSuite.scala delete mode 100644 benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/UnrecordedTxnSuite.scala delete mode 100644 benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/WriteSkewSuite.scala delete mode 100644 benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/examples/BasicSyntax.scala delete mode 100644 benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/examples/ConcurrentIntList.scala delete mode 100644 benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/examples/DiningPhilosophers.scala delete mode 100644 benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/examples/IndexedMap.scala delete mode 100644 benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/examples/RealityShowPhilosophers.scala delete mode 100644 benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/examples/SyntaxCheatSheet.scala delete mode 100644 benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/impl/RefFactorySuite.scala delete mode 100644 benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/skel/AtomicArraySuite.scala delete mode 100644 benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/skel/SimpleRandomSuite.scala delete mode 100644 benchmarks/scala-stm/scala-stm-library/src/test/scala/stmbench7/scalastm/AssemblyImpl.scala delete mode 100644 benchmarks/scala-stm/scala-stm-library/src/test/scala/stmbench7/scalastm/AtomicPartImpl.scala delete mode 100644 benchmarks/scala-stm/scala-stm-library/src/test/scala/stmbench7/scalastm/BaseAssemblyImpl.scala delete mode 100644 benchmarks/scala-stm/scala-stm-library/src/test/scala/stmbench7/scalastm/ComplexAssemblyImpl.scala delete mode 100644 benchmarks/scala-stm/scala-stm-library/src/test/scala/stmbench7/scalastm/CompositePartImpl.scala delete mode 100644 benchmarks/scala-stm/scala-stm-library/src/test/scala/stmbench7/scalastm/DesignObjImpl.scala delete mode 100644 benchmarks/scala-stm/scala-stm-library/src/test/scala/stmbench7/scalastm/DocumentImpl.scala delete mode 100644 benchmarks/scala-stm/scala-stm-library/src/test/scala/stmbench7/scalastm/IdPoolImpl.scala delete mode 100644 benchmarks/scala-stm/scala-stm-library/src/test/scala/stmbench7/scalastm/ImmutableSeqImpl.scala delete mode 100644 benchmarks/scala-stm/scala-stm-library/src/test/scala/stmbench7/scalastm/ImmutableSetImpl.scala delete mode 100644 benchmarks/scala-stm/scala-stm-library/src/test/scala/stmbench7/scalastm/IndexImpl.scala delete mode 100644 benchmarks/scala-stm/scala-stm-library/src/test/scala/stmbench7/scalastm/LargeSetImpl.scala delete mode 100644 benchmarks/scala-stm/scala-stm-library/src/test/scala/stmbench7/scalastm/ManualImpl.scala delete mode 100644 benchmarks/scala-stm/scala-stm-library/src/test/scala/stmbench7/scalastm/ModuleImpl.scala delete mode 100644 benchmarks/scala-stm/scala-stm-library/src/test/scala/stmbench7/scalastm/ScalaSTMInitializer.scala diff --git a/benchmarks/scala-stm/scala-stm-library/.gitignore b/benchmarks/scala-stm/scala-stm-library/.gitignore deleted file mode 100644 index bfb102ab..00000000 --- a/benchmarks/scala-stm/scala-stm-library/.gitignore +++ /dev/null @@ -1,10 +0,0 @@ -*.iws -.*.swp -.idea/workspace.xml -out/ -target -lib_managed/ -src_managed/ -project/boot/ -dep_tests/sbt/project/boot/ -cover/ diff --git a/benchmarks/scala-stm/scala-stm-library/BUILDING.txt b/benchmarks/scala-stm/scala-stm-library/BUILDING.txt deleted file mode 100644 index 9fc7daf6..00000000 --- a/benchmarks/scala-stm/scala-stm-library/BUILDING.txt +++ /dev/null @@ -1,15 +0,0 @@ -BUILDING FROM SOURCE - -scala-stm is built using sbt: http://code.google.com/p/simple-build-tool/ -Once you've installed sbt you can download scala-stm's compile dependency -(ScalaTest), build, and run the unit tests with - - sbt update test - -You can get a list of sbt build targets with "sbt actions". If you -compile, generate documentation or build a JAR, look in target/scala_* for -the results. The Scala version is configured in project/build.properties. -The left-most value for "build.scala.versions" is the default. To run -a build target for all of the versions prefix the action with a "+", -for example "sbt +test". - diff --git a/benchmarks/scala-stm/scala-stm-library/LICENSE.txt b/benchmarks/scala-stm/scala-stm-library/LICENSE.txt deleted file mode 100644 index 055aefb5..00000000 --- a/benchmarks/scala-stm/scala-stm-library/LICENSE.txt +++ /dev/null @@ -1,24 +0,0 @@ -Copyright (c) 2009-2012 Stanford University, unless otherwise specified. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - * Neither the name of the Stanford University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL STANFORD UNIVERSITY BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/benchmarks/scala-stm/scala-stm-library/README b/benchmarks/scala-stm/scala-stm-library/README deleted file mode 100644 index d65e1c49..00000000 --- a/benchmarks/scala-stm/scala-stm-library/README +++ /dev/null @@ -1,6 +0,0 @@ -ScalaSTM is a lightweight software transactional memory for Scala, -inspired by the STMs in Haskell and Clojure. - -The current release is 0.8. There is not currently a published -snapshot release. For download info and documentation see -http://scala-stm.org diff --git a/benchmarks/scala-stm/scala-stm-library/RELEASE-NOTES.txt b/benchmarks/scala-stm/scala-stm-library/RELEASE-NOTES.txt deleted file mode 100644 index b0a93535..00000000 --- a/benchmarks/scala-stm/scala-stm-library/RELEASE-NOTES.txt +++ /dev/null @@ -1,94 +0,0 @@ -ScalaSTM - 0.8-SNAPSHOT RELEASE NOTES - -Changes between 0.7 and 0.8-SNAPSHOT: - -* correctness fix for TArray[Long] and AtomicArray.ofLong. - -* small improvement to TxnLocal interface. - -* add 2.12 build and remove 2.10 build. - -* add deprecated message about incomplete deadlock detection for - CommitBarrier. - -Snapshot releases deployed to the oss.sonatype.org repository are tested -and functional, but may have changing APIs. - ----- - -Changes between 0.6 and 0.7: - -* better support for interactive debuggers, via TxnDebuggable and - atomic.unrecorded. IntelliJ IDEA and Eclipse can now watch Ref - values inside a transaction without affecting the read or write sets. - -* ScalaSTM cooperates with 2.10's scala.concurrent.BlockingContext. - -* added transformAndExtract, which allows an arbitrary value to be - returned from the transformation function. - -* added transformAndGet and getAndTransform to Ref and TxnLocal, - previously these were only defined for Ref.View. - ----- - -Changes between 0.5 and 0.6: - -* retry and retryFor added to the Java compatibility interface. - -* uses of scala.actor.threadpool.TimeUnit in the interface replaced with - java.util.concurrent.TimeUnit, to avoid making ScalaSTM depend on the - separate scala-actors jar in Scala 2.10. - ----- - -Changes between 0.4 and 0.5: - -* Added scala.concurrent.stm.japi.STM, which makes it much cleaner to - access ScalaSTM functionality from Java. - ----- - -Changes between 0.3 and 0.4: - -* CommitBarrier added, which allows multiple atomic blocks (each on its - own thread) to commit together. - -* Small performance improvements. - -* STMBench7 benchmark support added. - -* Automatic selection of STMImpl in most cases. - ----- - -Changes between 0.2 and 0.3: - -* Support for Scala 2.9.0.RC1. - -* Bug fixes (see https://github.com/nbronson/scala-stm/issues/closed ). - -* Timeouts for modular blocking. Set timeouts at the atomic block using - atomic.withRetryTimeout, or at the retry site using retryFor. - ----- - -Changes between 0.1 and 0.2: - -* Substantial performance improvements, especially for nested atomic - blocks. - -* TSet.View and TMap.View are integrated into the Scala collection - class hierarchy, with factory companion objects and Builder and - CanBuildFrom instances. - -* A fix for whileCommitting handlers (issue #3). - -* TxnLocal can now be read and written from while-preparing and while- - committing handlers. Combining TxnLocal and life-cycle handlers is - now more concise. - -* Transaction statistics can be enabled for the default algorithm - with the VM argument -Dccstm.stats=1 (details in the ScalaDoc for - scala.concurrent.stm.ccstm.CCSTM). - diff --git a/benchmarks/scala-stm/scala-stm-library/bin/all_tests b/benchmarks/scala-stm/scala-stm-library/bin/all_tests deleted file mode 100755 index 205a4afb..00000000 --- a/benchmarks/scala-stm/scala-stm-library/bin/all_tests +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/sh - -set -x -set -e - -BASE="`dirname $0`/.." -cd $BASE - -if [ "x$SCALA_VERSIONS" = "x" ]; then - SCALA_VERSIONS="`awk -F= '$1==\"build.scala.versions\" {print $2}' project/build.properties`" -fi - -for v in $SCALA_VERSIONS; do - TARGET_BASE="target/scala_$v" - SCALATEST=$(echo lib_managed/scala_$v/compile/scalatest*.jar) - sbt ++$v test-compile - scala -Dccstm.stats=1 -cp ${SCALATEST}:$TARGET_BASE/classes org.scalatest.tools.Runner -l slow -oW -p $TARGET_BASE/test-classes - scala -cp ${SCALATEST}:$TARGET_BASE/classes org.scalatest.tools.Runner -oW -p $TARGET_BASE/test-classes -done diff --git a/benchmarks/scala-stm/scala-stm-library/bin/fix_copyrights b/benchmarks/scala-stm/scala-stm-library/bin/fix_copyrights deleted file mode 100755 index e4c96e33..00000000 --- a/benchmarks/scala-stm/scala-stm-library/bin/fix_copyrights +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/bash - -cd `dirname $0`/.. -for f in `grep -l -r '(c) 2009' src`; do - d=`git log -1 --date=short --no-notes -- $f | awk 'NR==3 {print $2}'` - y=`echo $d | sed 's/-.*//'` - sed -i "s/(c) 2009-201./(c) 2009-$y/" $f -done diff --git a/benchmarks/scala-stm/scala-stm-library/bin/perf_sample b/benchmarks/scala-stm/scala-stm-library/bin/perf_sample deleted file mode 100755 index 468b7c0d..00000000 --- a/benchmarks/scala-stm/scala-stm-library/bin/perf_sample +++ /dev/null @@ -1,34 +0,0 @@ -#!/bin/sh - -set -x - -BASE="`dirname $0`/.." -BRANCH="`git status | awk '/^# On branch/ {print $NF}'`" - -cd $BASE -WHEN=`date '+%Y%m%d-%H%M%S'` -DIR="perf/`hostname`/perf-$BRANCH-$WHEN" - -if [ "x$VERSIONS" = "x" ]; then - VERSIONS="`awk -F= '$1==\"build.scala.versions\" {print $2}' project/build.properties | sed 's/,/ /g'`" -fi - -mkdir -p "$DIR" -git show --quiet HEAD > "$DIR"/git.hash - -for v in $VERSIONS; do - sbt ++$v test-compile > /dev/null 2>&1 - sbt ++$v test test > "$DIR"/.out 2>&1 - ( - cd "$DIR" - sed 's/[^m]*m//g' .out | uniq | gawk ' - /== test-start ==/ {x=x+1;y=0} - /== test-finish ==/ {y=1} - {z=1} - /^.info/ {z=0} - x>0 && (y || z) {print >> ("." x)}' - rm .out - mv .1 test-first-$v.log - mv .2 test-second-$v.log - ) -done diff --git a/benchmarks/scala-stm/scala-stm-library/bin/test_coverage b/benchmarks/scala-stm/scala-stm-library/bin/test_coverage deleted file mode 100755 index ed3f5ff9..00000000 --- a/benchmarks/scala-stm/scala-stm-library/bin/test_coverage +++ /dev/null @@ -1,44 +0,0 @@ -#!/bin/sh - -set -x - -COBERTURA_DIR=$HOME/cobertura/cobertura-1.9.4.1 -SCALATEST_VERSION=1.2 - -BASE="`dirname $0`/.." -cd $BASE - -WHEN=`date '+%Y%m%d-%H%M%S'` -DIR="cover/cover-$WHEN" -SER="$DIR/cobertura.ser" - -if [ "x$SCALA_VERSION" = "x" ]; then - SCALA_VERSION="`awk -F= '$1==\"build.scala.versions\" {print $2}' project/build.properties | sed 's/ .*//g'`" -fi -TARGET_BASE="target/scala_$SCALA_VERSION" - -SCALATEST="lib_managed/scala_$SCALA_VERSION/compile/scalatest-$SCALATEST_VERSION.jar" - -mkdir -p $DIR -git show --quiet HEAD > $DIR/git.hash - -sbt ++$SCALA_VERSION test-compile > "$DIR"/log 2>&1 - -rm -rf $TARGET_BASE/classes-instr -sh $COBERTURA_DIR/cobertura-instrument.sh \ - --basedir $TARGET_BASE/classes \ - --datafile $SER \ - --destination $TARGET_BASE/classes-instr \ - scala - -# we have to include classes because cobertura skips those with no methods -scala -cp ${SCALATEST}:$COBERTURA_DIR/cobertura.jar:$TARGET_BASE/classes-instr:$TARGET_BASE/classes \ - -Dnet.sourceforge.cobertura.datafile=$SER \ - -Dccstm.stats=1 \ - org.scalatest.tools.Runner \ - -oW -l slow -p $TARGET_BASE/test-classes - -sh $COBERTURA_DIR/cobertura-report.sh \ - --datafile $SER \ - --destination $DIR \ - $BASE/src/main/scala diff --git a/benchmarks/scala-stm/scala-stm-library/build.sbt b/benchmarks/scala-stm/scala-stm-library/build.sbt deleted file mode 100644 index 600c0a76..00000000 --- a/benchmarks/scala-stm/scala-stm-library/build.sbt +++ /dev/null @@ -1,25 +0,0 @@ -lazy val parentProject = ProjectRef(uri("../../.."), "scalaStmBenchmarks") - -name := "scala-stm-library" - -organization := "org.scala-stm" - -version := "0.8-SNAPSHOT" - -scalaVersion := (parentProject / scalaVersion).value -scalacOptions := (parentProject / scalacOptions).value ++ Seq("-feature") - -// Silence warnings from test sources. -Test / scalacOptions += "-Wconf:src=src/test/scala/.*:s" - -libraryDependencies += ("org.scalatest" %% "scalatest" % "3.0.4" % "test") -libraryDependencies += ("junit" % "junit" % "4.12" % "test") - -// skip exhaustive tests -testOptions += Tests.Argument("-l", "slow") - -// test of TxnExecutor.transformDefault must be run by itself -Test / parallelExecution := false - -exportJars := true - diff --git a/benchmarks/scala-stm/scala-stm-library/dep_tests/PUBLISHING.txt b/benchmarks/scala-stm/scala-stm-library/dep_tests/PUBLISHING.txt deleted file mode 100644 index 83b8ac9c..00000000 --- a/benchmarks/scala-stm/scala-stm-library/dep_tests/PUBLISHING.txt +++ /dev/null @@ -1,20 +0,0 @@ -DEPLOYING THE SCALA-STM ARTIFACT - -With a proper credentials file publishing a snapshot or release artifact is -accomplished with - - sbt +test (or bin/all_tests) - sbt +publish - -TESTING DEPLOYMENT AND ARTIFACT USAGE - -To test using published artifacts via sbt, select the desired scala-stm -artifact in dep_tests/sbt/build.sbt . Then - - cd dep_tests/sbt - sbt +run - -To test building using maven2, edit dep_tests/maven/pom.xml, then - - cd dep_tests/maven - mvn -U compile diff --git a/benchmarks/scala-stm/scala-stm-library/dep_tests/check_central b/benchmarks/scala-stm/scala-stm-library/dep_tests/check_central deleted file mode 100755 index ef7a96c7..00000000 --- a/benchmarks/scala-stm/scala-stm-library/dep_tests/check_central +++ /dev/null @@ -1,26 +0,0 @@ -#!/bin/bash - -# http://search.maven.org/remotecontent?filepath=org/scala-tools/scala-stm_2.10.0-M7/0.6/scala-stm_2.10.0-M7-0.6.pom - -BUILD_SBT=$(dirname $0)/../build.sbt -GROUP_ID="scala-stm" - -echo "Checking groupId [[$GROUP_ID]]" -echo - -sed 's/[":=(,)]/ /g' "$BUILD_SBT" | \ - awk '$1=="version" {stm=$2} - $1=="crossScalaVersions" {for(i=3;i<=NF;++i) {print stm,$i}}' | \ - while read x y; do - /bin/echo -en "stm $x scala $y \t" - # URL="http://search.maven.org/remotecontent?filepath=org/scala-stm/scala-stm_$y/$x/scala-stm_$y-$x.pom" - URL="http://repo1.maven.org/maven2/org/$GROUP_ID/scala-stm_$y/$x/scala-stm_$y-$x.pom" - curl -s "$URL" | grep -q "scala-stm_$y" - if [ $? -eq 0 ]; then - echo "synced" - else - echo "NOT SYNCED" - fi - done - - diff --git a/benchmarks/scala-stm/scala-stm-library/dep_tests/maven/RUN_MAVEN_HERE_TO_TEST_DEPS b/benchmarks/scala-stm/scala-stm-library/dep_tests/maven/RUN_MAVEN_HERE_TO_TEST_DEPS deleted file mode 100644 index e69de29b..00000000 diff --git a/benchmarks/scala-stm/scala-stm-library/dep_tests/maven/pom.xml b/benchmarks/scala-stm/scala-stm-library/dep_tests/maven/pom.xml deleted file mode 100644 index c503f3f8..00000000 --- a/benchmarks/scala-stm/scala-stm-library/dep_tests/maven/pom.xml +++ /dev/null @@ -1,91 +0,0 @@ - - - 2.12.4 - 2.12 - 0.8-SNAPSHOT - - - 4.0.0 - org.scala-stm - scala-stm-dep-tests-maven - 0.1-SNAPSHOT - jar - - - - oss.sonatype.org - OSS Sonatype Release Repository - https://oss.sonatype.org/content/repositories/releases - - - oss.sonatype.org.snapshots - OSS Sonatype Snapshot Repository - https://oss.sonatype.org/content/repositories/snapshots - - - - - - - oss.sonatype.org - OSS Sonatype Release Repository - https://oss.sonatype.org/content/repositories/releases - - - oss.sonatype.org.snapshots - OSS Sonatype Snapshot Repository - https://oss.sonatype.org/content/repositories/snapshots - - - - - - org.scala-lang - scala-compiler - ${scala.version} - - - org.scala-lang - scala-library - ${scala.version} - - - org.scala-stm - scala-stm_${scala.major.version} - ${scala.stm.version} - - - - - - - org.apache.maven.plugins - maven-compiler-plugin - 2.0.2 - - 1.6 - 1.6 - - - - org.scala-tools - maven-scala-plugin - 2.14 - - - - compile - testCompile - - - - - ${scala.version} - - -target:jvm-1.5 - - - - - - diff --git a/benchmarks/scala-stm/scala-stm-library/dep_tests/maven/src/main/scala/HelloWorld.scala b/benchmarks/scala-stm/scala-stm-library/dep_tests/maven/src/main/scala/HelloWorld.scala deleted file mode 100644 index c65d492c..00000000 --- a/benchmarks/scala-stm/scala-stm-library/dep_tests/maven/src/main/scala/HelloWorld.scala +++ /dev/null @@ -1,8 +0,0 @@ -import scala.concurrent.stm._ - -object HelloWorld { - def main(args: Array[String]) { - val x = Ref("hello world!") - println(x.single()) - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/dep_tests/sbt/RUN_SBT_HERE_TO_TEST_DEPS b/benchmarks/scala-stm/scala-stm-library/dep_tests/sbt/RUN_SBT_HERE_TO_TEST_DEPS deleted file mode 100644 index e69de29b..00000000 diff --git a/benchmarks/scala-stm/scala-stm-library/dep_tests/sbt/build.sbt b/benchmarks/scala-stm/scala-stm-library/dep_tests/sbt/build.sbt deleted file mode 100644 index 2731f782..00000000 --- a/benchmarks/scala-stm/scala-stm-library/dep_tests/sbt/build.sbt +++ /dev/null @@ -1,16 +0,0 @@ - -name := "scala-stm-dep-tests-sbt" - -organization := "org.scala-stm" - -version := "0.1-SNAPSHOT" - -scalaVersion := "2.12.15" - -crossScalaVersions := Seq("2.12.0", "2.11.6") - -resolvers += ("releases" at "https://oss.sonatype.org/content/repositories/releases") - -resolvers += ("snapshots" at "https://oss.sonatype.org/content/repositories/snapshots") - -libraryDependencies += ("org.scala-stm" %% "scala-stm" % "0.8-SNAPSHOT") diff --git a/benchmarks/scala-stm/scala-stm-library/dep_tests/sbt/src/main/scala/HelloWorld.scala b/benchmarks/scala-stm/scala-stm-library/dep_tests/sbt/src/main/scala/HelloWorld.scala deleted file mode 100644 index c65d492c..00000000 --- a/benchmarks/scala-stm/scala-stm-library/dep_tests/sbt/src/main/scala/HelloWorld.scala +++ /dev/null @@ -1,8 +0,0 @@ -import scala.concurrent.stm._ - -object HelloWorld { - def main(args: Array[String]) { - val x = Ref("hello world!") - println(x.single()) - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/deuceAgent-1.3.0.jar b/benchmarks/scala-stm/scala-stm-library/lib/deuceAgent-1.3.0.jar deleted file mode 100644 index 99124e9065f2eacb50ee1a8834792dff0aa164b1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 212722 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℞qDhrnDtR++%=zGAo_xy%o=X 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�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

c92O*Px{{ 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 OpUy(P)O8#{wtoTpGOf-4 diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/README b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/README deleted file mode 100644 index 640ea69b..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/README +++ /dev/null @@ -1,106 +0,0 @@ -STMBench7 Java -============== - STMBench7 Java is built using Apache Ant building system. - The building process consists in compiling the STMBench7 java - code and instrumenting the bytecode. - - Note that STMBench7 successfully passes the Java-to-Java - precompilation phase of TMJava, however, this action is - idempotent as no __transaction{} blocks are used in STMBench7 - but each transaction in the code is already an annotated method. - - For automatic instrumentation of transactional accesses - STMBench7 uses the Deuce bytecode instrumentation framework, - which detects bytecode annotation to instrument memory accesses - with a dedicated TM backend. - -PREREQUISITES -============= - In order the build to work properly and resolve jar dependencies, - you have to download the Deuce agent. Deuce can be downloaded from: - - > http://www.velox-project.eu/software/deuce - > http://sites.google.com/site/deucestm - - Set the the deuceAgent path in file build.xml under variable - named 'agent'. - - In addition, you must set the path towards your local Java RunTime - jar archive (e.g., /usr/lib/jvm/java-1.6.0-openjdk/jre/lib/rt.jar) - - STMBench7 Java has been successfully tested with - * ant 1.7.1 - * java 1.6.0_20 - * deuceAgent 1.3.0 - - Optionally, TMJava variable 'precompiler' can be set to - the path of TMJava. TMJava can be downloaded from: - - > http://www.velox-project.eu/software/tmjava - > http://tinystm.org/tmjava - -ORGANIZATION -============ - build.xml the xml build file - src/ the source directory - COPYING licence - README install information - README.sb7 STMBench7 overview - -INSTALL -======= - Set first the appropriate variable 'agent' and 'javart.home' - in build.xml - - > ant clean - > ant - > ant instrument - > ant instrument-rt - - You may test the benchmark with: - - > ant test - - * which essentially runs java with the following arguments on - the command line: - -Dorg.deuce.exclude="java.lang.Enum,sun.*" - (for classes that must not be instrumented) - -Dorg.deuce.transaction.contextClass=org.deuce.transaction.lsacm.Context - (specifying to run the LSA library including a Contention Manager provided with Deuce) - -Xbootclasspath/p:rt_instrumented.jar:deuceAgent.jar, offline instrumentation - (to support boot classloader) - -cp jars/stmbench7-VELOX-v1.2_instrumented.jar indicating the jars - - * and runs STMBench7 with options: - -l 1 during 1 second - -t 16 running 16 threads - -w rw workload mixed of reads and writes - -g stm with the default Deuce STM algorithm - --no-traversals disable traversal operations - - -OPTIONS -======= - -h help -- print usage - -t numThreads -- set the number of threads (default: 1) - -l length -- set the length of the benchmark, in seconds (default: 10) - -w r|rw|w -- set the workload: r = read-dominated, w = write-dominated - rw = read-write (default: read-dominated) - -g coarse|medium|fine|none|stm -- set synchronization method (default: coarse) - -s stmInitializerClass -- set STM initializer class (default: none) - --no-traversals -- do not use long traversals - --no-sms -- do not use structural modification operations - --seq-replay -- replay the execution in a single thread - (checks for opacity violations) - --ttc-histograms -- print TTC histograms to stdout - - NB. the benchmark needs a lot of lot of memory, so the -Xmx option of Java - might be necessary. - - -CONTACT -======= - http://lpd.epfl.ch/transactions - Vincent Gramoli (vincent.gramoli@epfl.ch) - Michal Kapalka (http://kapalka.eu) - diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/README.VELOX b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/README.VELOX deleted file mode 100644 index d730126c..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/README.VELOX +++ /dev/null @@ -1,55 +0,0 @@ -//===----------------------------------------------------------------------===// -// Steps for building STMBench7 for DTMC -//===----------------------------------------------------------------------===// - - -//===----------------------- Contact - -Contact information: - http://lpd.epfl.ch/transactions - Vincent Gramoli - Michal Kapalka - -//===----------------------- Version - -STMBench7 Java version 1.2. - -//===----------------------- Introduction - -STMBench7 is a benchmark for evaluating Transactional Memory (TM) -implementations. The benchmark aims at providing a workload that is both -realistic and non-trivial to implement in a scalable way. The implementation -(in Java and C++) contains a lock-based synchronization strategy that can serve -as a baseline for comparison with various TMs. - -http://lpd.epfl.ch/site/research/tmeval#the_stmbench7_benchmark - -The underlying data structure consists of a set of graphs and indexes intended -to be suggestive of many complex applications, e.g., CAD/CAM. A collection of -operations is supported to model a wide range of workloads and concurrency -patterns. Companion locking strategies serve as a baseline for TM performance -comparisons. STMBench7 strives for simplicity. Users may choose a workload, -number of threads, benchmark length, as well as the possibility of structure -modification and the nature of traversals of shared data structures. - -The C++ release compiles with the Dresden TM compiler (DTMC) from Velox. -The Java release uses the Deuce framework from Velox for bytecode -instrumentation of transactions. - -//===----------------------- System requirements - -check the README file - -//===----------------------- VELOX project - -European research consortium VELOX supports programming of multi-core systems - -Research project will aim to make parallel programming easier for -the masses by developing integrated Transactional Memory systems -for multi-core computers. - -This document was prepared by Javier Arias. If you have any comment or -suggestion feel free to send an email to javier.arias@bsc.es. - - - diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/build.xml b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/build.xml deleted file mode 100644 index 4d2b457a..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/build.xml +++ /dev/null @@ -1,97 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/BenchThread.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/BenchThread.java deleted file mode 100644 index 8da09477..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/BenchThread.java +++ /dev/null @@ -1,172 +0,0 @@ -package stmbench7; - -import java.lang.reflect.Constructor; -import java.util.ArrayList; - -import stmbench7.annotations.NonAtomic; -import stmbench7.core.Operation; -import stmbench7.core.RuntimeError; -import stmbench7.core.OperationFailedException; - -/** - * A single thread of the STMBench7 benchmark. Executes operations assigned to - * it one by one, randomly choosing the next operation and respecting the - * expected ratios of operations' counts. - */ -@NonAtomic -public class BenchThread implements Runnable { - - protected volatile boolean stop = false; - protected double[] operationCDF; - protected OperationExecutor[] operations; - protected final short myThreadNum; - protected final int countOfOperations; - - public int[] successfulOperations, failedOperations; - public int[][] operationsTTC, operationsHighTTCLog; - - public class ReplayLogEntry implements Comparable { - public final short threadNum; - public final int timestamp, result; - public final boolean failed; - public final int opNum; - - public ReplayLogEntry(int timestamp, int result, boolean failed, - int opNum) { - this.threadNum = myThreadNum; - this.timestamp = timestamp; - this.result = result; - this.failed = failed; - this.opNum = opNum; - } - - public int compareTo(ReplayLogEntry entry) { - return timestamp - entry.timestamp; - } - } - - public ArrayList replayLog; - - public BenchThread(Setup setup, double[] operationCDF, short myThreadNum, int countOfOperations) { - this.operationCDF = operationCDF; - - int numOfOperations = OperationId.values().length; - operationsTTC = new int[numOfOperations][Parameters.MAX_LOW_TTC + 1]; - operationsHighTTCLog = new int[numOfOperations][Parameters.HIGH_TTC_ENTRIES]; - successfulOperations = new int[numOfOperations]; - failedOperations = new int[numOfOperations]; - operations = new OperationExecutor[numOfOperations]; - this.myThreadNum = myThreadNum; - this.countOfOperations = countOfOperations; - - createOperations(setup); - - if (Parameters.sequentialReplayEnabled) - replayLog = new ArrayList(); - } - - protected BenchThread(Setup setup, double[] operationCDF) { - this.operationCDF = operationCDF; - operations = new OperationExecutor[OperationId.values().length]; - createOperations(setup); - myThreadNum = 0; - throw new RuntimeException("This ctor is no longer allowed."); - } - - public void run() { - int i = 0; - int iteration = 0; - while (!stop && iteration < countOfOperations) { - iteration++; - //if (i++ > 55) continue; - int operationNumber = getNextOperationNumber(iteration); - - OperationType type = OperationId.values()[operationNumber].getType(); - // System.out.println(iteration + ": " + operationNumber + ", " + type); - //if( (type != OperationType.SHORT_TRAVERSAL) ) continue; - // (type != OperationType.SHORT_TRAVERSAL_RO) && - // (type != OperationType.OPERATION) ) - // continue; - - //System.out.println(i + " > " - // + OperationId.values()[operationNumber]); - - OperationExecutor currentExecutor = operations[operationNumber]; - int result = 0; - boolean failed = false; - - try { - long startTime = System.currentTimeMillis(); - - result = currentExecutor.execute(); - - long endTime = System.currentTimeMillis(); - //System.out.println("success"); - - successfulOperations[operationNumber]++; - int ttc = (int) (endTime - startTime); - if (ttc <= Parameters.MAX_LOW_TTC) - operationsTTC[operationNumber][ttc]++; - else { - double logHighTtc = (Math.log(ttc) - Math - .log(Parameters.MAX_LOW_TTC + 1)) - / Math.log(Parameters.HIGH_TTC_LOG_BASE); - int intLogHighTtc = Math.min((int) logHighTtc, - Parameters.HIGH_TTC_ENTRIES - 1); - operationsHighTTCLog[operationNumber][intLogHighTtc]++; - } - } catch (OperationFailedException e) { - failedOperations[operationNumber]++; - failed = true; - } - - if (Parameters.sequentialReplayEnabled) { - ReplayLogEntry newEntry = new ReplayLogEntry( - currentExecutor.getLastOperationTimestamp(), result, failed, - operationNumber); - replayLog.add(newEntry); - //System.out.println("ts: " + newEntry.timestamp); - } - } - System.err.println("Thread #" + myThreadNum + " finished."); - //i = 0; - //for (ReplayLogEntry entry : replayLog) - // System.out.println(i++ + " % " + OperationId.values()[entry.opNum] - // + " -- " + entry.timestamp); - } - - public void stopThread() { - stop = true; - } - - protected void createOperations(Setup setup) { - for (OperationId operationDescr : OperationId.values()) { - Class operationClass = operationDescr - .getOperationClass(); - int operationIndex = operationDescr.ordinal(); - - try { - Constructor operationConstructor = operationClass - .getConstructor(Setup.class); - Operation operation = operationConstructor.newInstance(setup); - - operations[operationIndex] = OperationExecutorFactory.instance - .createOperationExecutor(operation); - assert (operation.getOperationId().getOperationClass() - .equals(operationClass)); - } catch (Exception e) { - throw new RuntimeError("Error while creating operation " - + operationDescr, e); - } - } - } - - protected int getNextOperationNumber(int iteration) { - // double whichOperation = ThreadRandom.nextDouble(); - double whichOperation = (iteration % 20) / 20.0; - int operationNumber = 0; - while (whichOperation >= operationCDF[operationNumber]) - operationNumber++; - return operationNumber; - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/Benchmark.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/Benchmark.java deleted file mode 100644 index 8f35d51a..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/Benchmark.java +++ /dev/null @@ -1,563 +0,0 @@ -package stmbench7; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Formatter; - -import stmbench7.annotations.NonAtomic; -import stmbench7.backend.BackendFactory; -import stmbench7.core.DesignObjFactory; -import stmbench7.core.Operation; -import stmbench7.core.RuntimeError; -import stmbench7.correctness.invariants.CheckInvariantsOperation; -import stmbench7.correctness.opacity.SequentialReplayThread; -import stmbench7.correctness.opacity.StructureComparisonOperation; -import stmbench7.impl.NoSynchronizationInitializer; -import stmbench7.ThreadRandom.Phase; - -/** - * STMBench7 benchmark, the main program. - * Run with argument "-h" or "--help" to see the syntax. - * - * TODO: The class got too large and needs some careful refactoring. - * TODO: An XML output of the benchmark results would be helpful. - */ -@NonAtomic -public class Benchmark { - - public static final String VERSION = "1.0(15.02.2011)"; - - class BenchmarkParametersException extends Exception { - private static final long serialVersionUID = 6341915439489283553L; - - public BenchmarkParametersException(String message, Exception cause) { - super(message + ": " + cause.toString()); - } - - public BenchmarkParametersException(String message) { - super(message); - } - - public BenchmarkParametersException() { - super(""); - } - } - - public static void main(String[] args) throws InterruptedException { - Benchmark benchmark = null; - ThreadRandom.phase = Phase.INIT; - - try { - benchmark = new Benchmark(args); - } - catch(BenchmarkParametersException e) { - System.err.println(e.getMessage()); - System.exit(1); - } - - //benchmark.checkInvariants(true); - benchmark.createInitialClone(); - benchmark.start(); - //benchmark.checkInvariants(false); - //benchmark.checkOpacity(); - benchmark.showTTCHistograms(); - benchmark.showStats(); - } - - private SynchMethodInitializer synchMethodInitializer; - private boolean printTTCHistograms = false; - private double[] operationCDF; - private BenchThread[] benchThreads; - private Thread[] threads; - private Setup setup, setupClone; - private double elapsedTime; - private int countOfOperations; - - private Benchmark(String[] args) throws BenchmarkParametersException, InterruptedException { - printHeader(); - - parseCommandLineParameters(args); - printRunTimeParametersInformation(); - - generateOperationCDF(); - setupStructures(); - } - - private void printHeader() { - String header = - "The STMBench7 Benchmark (Java version)\n" + - "A benchmark for comparing synchronization techniques\n" + - "Version: " + VERSION + "\n" + - "More information: http://lpd.epfl.ch/site/research/tmeval\n" + - "Copyright (C) 2006-2008 LPD, I&C, EPFL (http://lpd.epfl.ch)\n" + - "Implemented by Michal Kapalka (http://kapalka.eu)\n"+ - "Updated by Vincent Gramoli for compliance with the VELOX stack"; - - printLine('='); - System.out.println(header); - printLine('='); - System.out.println(); - } - - @SuppressWarnings("unchecked") - private void parseCommandLineParameters(String[] args) throws BenchmarkParametersException { - int argNumber = 0; - String workload = null, synchType = null, stmInitializerClassName = null; - - while(argNumber < args.length) { - String currentArg = args[argNumber++]; - - try { - if(currentArg.equals("--help") || currentArg.equals("-h")) { - printSyntax(); - throw new BenchmarkParametersException(); - } - else if(currentArg.equals("--no-traversals")) Parameters.longTraversalsEnabled = false; - else if(currentArg.equals("--no-sms")) Parameters.structureModificationEnabled = false; - else if(currentArg.equals("--ttc-histograms")) printTTCHistograms = true; - else if(currentArg.equals("--seq-replay")) Parameters.sequentialReplayEnabled = true; - else if(currentArg.equals("--")) { - Parameters.stmCommandLineParameters = new String[args.length - argNumber]; - int stmArgNum = 0; - while(argNumber < args.length) - Parameters.stmCommandLineParameters[stmArgNum++] = args[argNumber++]; - break; - } - else { - String optionValue = args[argNumber++]; - if(currentArg.equals("-t")) Parameters.numThreads = Integer.parseInt(optionValue); - else if(currentArg.equals("-l")) Parameters.numSeconds = Integer.parseInt(optionValue); - else if(currentArg.equals("-w")) workload = optionValue; - else if(currentArg.equals("-g")) synchType = optionValue; - else if(currentArg.equals("-s")) stmInitializerClassName = optionValue; - else if(currentArg.equals("-c")) countOfOperations = Integer.parseInt(optionValue); - else throw new BenchmarkParametersException("Invalid option: " + currentArg); - } - } - catch(IndexOutOfBoundsException e) { - throw new BenchmarkParametersException("Missing value after option: " + currentArg); - } - catch(NumberFormatException e) { - throw new BenchmarkParametersException("Number expected after option: " + currentArg); - } - } - - if(workload != null) { - if(workload.equals("r")) - Parameters.workloadType = Parameters.WorkloadType.READ_DOMINATED; - else if(workload.equals("rw")) - Parameters.workloadType = Parameters.WorkloadType.READ_WRITE; - else if(workload.equals("w")) - Parameters.workloadType = Parameters.WorkloadType.WRITE_DOMINATED; - else throw new BenchmarkParametersException("Invalid workload type: " + workload); - } - - if(synchType != null) { - if(synchType.equals("coarse")) - Parameters.synchronizationType = Parameters.SynchronizationType.LOCK_COARSE; - else if(synchType.equals("medium")) - Parameters.synchronizationType = Parameters.SynchronizationType.LOCK_MEDIUM; - else if(synchType.equals("fine")) - Parameters.synchronizationType = Parameters.SynchronizationType.LOCK_FINE; - else if(synchType.equals("none")) - Parameters.synchronizationType = Parameters.SynchronizationType.NONE; - else if(synchType.equals("stm")) - Parameters.synchronizationType = Parameters.SynchronizationType.STM; - else throw new BenchmarkParametersException("Invalid lock granularity: " + synchType); - } - - Class synchMethodInitializerClass = null; - switch(Parameters.synchronizationType) { - case NONE: - synchMethodInitializerClass = ImplParameters.noSynchronizationInitializerClass; - break; - case LOCK_COARSE: - synchMethodInitializerClass = ImplParameters.coarseGrainedLockingInitializerClass; - break; - case LOCK_MEDIUM: - synchMethodInitializerClass = ImplParameters.mediumGrainedLockingInitializerClass; - break; - case LOCK_FINE: - synchMethodInitializerClass = ImplParameters.fineGrainedLockingInitializerClass; - break; - case STM: - if(stmInitializerClassName != null) { - try { - synchMethodInitializerClass = - (Class) - Class.forName(stmInitializerClassName); - } - catch(ClassNotFoundException e) { - throw new BenchmarkParametersException("Error instantiating the STM" + - " initializer class", e); - } - } - else if(ImplParameters.defaultSTMInitializerClass != null) { - synchMethodInitializerClass = ImplParameters.defaultSTMInitializerClass; - } - else throw new BenchmarkParametersException("STM initializer class name not given" + - " and a default class not specified" + - " in ImpParameters.defaultSTMInitializerClass"); - break; - } - try { - synchMethodInitializer = - synchMethodInitializerClass.newInstance(); - } - catch(Exception e) { - throw new BenchmarkParametersException("Error instantiating STM initializer class", e); - } - - setFactoryInstances(synchMethodInitializer); - } - - private void setFactoryInstances(SynchMethodInitializer synchMethodInitializer) { - DesignObjFactory.setInstance(synchMethodInitializer.createDesignObjFactory()); - BackendFactory.setInstance(synchMethodInitializer.createBackendFactory()); - OperationExecutorFactory.setInstance(synchMethodInitializer.createOperationExecutorFactory()); - ThreadFactory.setInstance(synchMethodInitializer.createThreadFactory()); - } - - private void printRunTimeParametersInformation() { - printSection("Benchmark parameters"); - - System.out.println("Number of threads: " + Parameters.numThreads + "\n" + - "Length: " + Parameters.numSeconds + " s\n" + - "Workload: " + Parameters.workloadType + "\n" + - "Synchronization method: " + Parameters.synchronizationType + "\n" + - "Long traversals " + (Parameters.longTraversalsEnabled ? "enabled" : "disabled") + "\n" + - "Structural modification operations " + - (Parameters.structureModificationEnabled ? "enabled" : "disabled") + "\n" + - "DesignObjFactory: " + DesignObjFactory.instance.getClass().getName() + "\n" + - "BackendFactory: " + BackendFactory.instance.getClass().getName() + "\n" + - "OperationExecutorFactory: " + - OperationExecutorFactory.instance.getClass().getName() + "\n" + - "ThreadFactory: " + ThreadFactory.instance.getClass().getName() + "\n" + - "Sequential replay " + (Parameters.sequentialReplayEnabled ? "enabled" : "disabled")); - - System.out.print("STM-specific parameters:"); - if(Parameters.stmCommandLineParameters == null) System.out.print(" none"); - else for(String parameter : Parameters.stmCommandLineParameters) - System.out.print(" " + parameter); - System.out.println("\n"); - } - - private void generateOperationCDF() { - double shortTraversalsRatio = (double)Parameters.ShortTraversalsRatio / 100.0, - operationsRatio = (double)Parameters.OperationsRatio / 100.0; - - double traversalsRatio, structuralModificationsRatio; - if(Parameters.longTraversalsEnabled) traversalsRatio = (double)Parameters.TraversalsRatio / 100.0; - else traversalsRatio = 0; - if(Parameters.structureModificationEnabled) - structuralModificationsRatio = (double)Parameters.StructuralModificationsRatio / 100.0; - else structuralModificationsRatio = 0; - - double readOnlyOperationsRatio = (double)Parameters.workloadType.readOnlyOperationsRatio / 100.0, - updateOperationsRatio = 1.0 - readOnlyOperationsRatio; - - double sumRatios = traversalsRatio + shortTraversalsRatio + operationsRatio + - structuralModificationsRatio * updateOperationsRatio; - traversalsRatio /= sumRatios; - shortTraversalsRatio /= sumRatios; - operationsRatio /= sumRatios; - structuralModificationsRatio /= sumRatios; - - for (OperationType type : OperationType.values()) type.count = 0; - OperationId[] operations = OperationId.values(); - for(OperationId operation : operations) operation.getType().count++; - - OperationType.TRAVERSAL.probability = - traversalsRatio * updateOperationsRatio / OperationType.TRAVERSAL.count; - OperationType.TRAVERSAL_RO.probability = - traversalsRatio * readOnlyOperationsRatio / OperationType.TRAVERSAL_RO.count; - OperationType.SHORT_TRAVERSAL.probability = - shortTraversalsRatio * updateOperationsRatio / OperationType.SHORT_TRAVERSAL.count; - OperationType.SHORT_TRAVERSAL_RO.probability = - shortTraversalsRatio * readOnlyOperationsRatio / OperationType.SHORT_TRAVERSAL_RO.count; - OperationType.OPERATION.probability = - operationsRatio * updateOperationsRatio / OperationType.OPERATION.count; - OperationType.OPERATION_RO.probability = - operationsRatio * readOnlyOperationsRatio / OperationType.OPERATION_RO.count; - OperationType.STRUCTURAL_MODIFICATION.probability = - structuralModificationsRatio * updateOperationsRatio / OperationType.STRUCTURAL_MODIFICATION.count; - - System.out.println("Operation ratios [%]:"); - for(OperationType type : OperationType.values()) - System.out.println(alignText(type.toString(), 23) + ": " + - formatDouble(type.probability * type.count * 100)); - System.out.println(); - - double[] operationProbabilities = new double[operations.length]; - for(OperationId operation : operations) { - double operationProbability = operation.getType().probability; - operationProbabilities[operation.ordinal()] = operationProbability; - } - - operationCDF = new double[operations.length]; - double prevProbValue = 0; - for(int opNum = 0; opNum < operations.length; opNum++) { - operationCDF[opNum] = prevProbValue + operationProbabilities[opNum]; - prevProbValue = operationCDF[opNum]; - } - operationCDF[operations.length - 1] = 1.0; // to avoid rounding errors - // System.out.println(Arrays.stream(operationCDF).boxed().collect(java.util.stream.Collectors.toList())); - } - - private void setupStructures() throws InterruptedException { - System.err.println("Setup start..."); - setup = new Setup(); - - benchThreads = new BenchThread[Parameters.numThreads]; - threads = new Thread[Parameters.numThreads]; - for(short threadNum = 0; threadNum < Parameters.numThreads; threadNum++) { - benchThreads[threadNum] = - new BenchThread(setup, operationCDF, threadNum, countOfOperations); - threads[threadNum] = ThreadFactory.instance.createThread(benchThreads[threadNum]); - } - System.err.println("Setup completed."); - } - - private void checkInvariants(boolean initial) throws InterruptedException { - if(initial) System.err.println("Checking invariants (initial data structure):"); - else System.err.println("Checking invariants (final data structure):"); - - Operation checkInvariantsOperation = - new CheckInvariantsOperation(setup, initial); - OperationExecutorFactory.executeSequentialOperation(checkInvariantsOperation); - } - - private void createInitialClone() throws InterruptedException { - if(! Parameters.sequentialReplayEnabled) return; - - System.err.println("Cloning the initial data structure..."); - ThreadRandom.reset(); - setFactoryInstances(new NoSynchronizationInitializer()); - setupClone = new Setup(); - setFactoryInstances(synchMethodInitializer); - System.err.println("Cloning completed."); - - System.err.println("Checking if the clone is the same as the data structure..."); - StructureComparisonOperation structureComparisonOperation = - new StructureComparisonOperation(setup, setupClone); - OperationExecutorFactory.executeSequentialOperation(structureComparisonOperation); - System.err.println("Check OK."); - } - - private void start() throws InterruptedException { - System.err.println("\nBenchmark started."); - ThreadRandom.startConcurrentPhase(); - - long startTime = System.currentTimeMillis(); - - for(Thread thread : threads) thread.start(); - - // Note: we require the threads to execute the specified number of operations. - // Thread.sleep(Parameters.numSeconds * 1000); - - // for(BenchThread thread : benchThreads) thread.stopThread(); - for(Thread thread : threads) thread.join(); - - long endTime = System.currentTimeMillis(); - elapsedTime = ((double)(endTime - startTime)) / 1000.0; - System.err.println("Benchmark completed.\n"); - } - - private void checkOpacity() throws InterruptedException { - if(! Parameters.sequentialReplayEnabled) return; - - System.err.println("\nReplaying the execution in a single thread..."); - - ArrayList replayLog = new ArrayList(); - for(BenchThread thread : benchThreads) - replayLog.addAll(thread.replayLog); - BenchThread.ReplayLogEntry[] replayLogArray = replayLog.toArray(new BenchThread.ReplayLogEntry[0]); - Arrays.sort(replayLogArray); - replayLog = new ArrayList(); - for(BenchThread.ReplayLogEntry entry : replayLogArray) replayLog.add(entry); - replayLogArray = null; - - setFactoryInstances(new NoSynchronizationInitializer()); - ThreadRandom.startSequentialReplayPhase(); - SequentialReplayThread seqThread = new SequentialReplayThread(setupClone, - operationCDF, replayLog); - seqThread.run(); - setFactoryInstances(synchMethodInitializer); - - StructureComparisonOperation structureComparisonOperation = - new StructureComparisonOperation(setup, setupClone); - OperationExecutorFactory.executeSequentialOperation(structureComparisonOperation); - System.err.println("\nOpacity ensured.\n"); - } - - private void showTTCHistograms() { - if(! printTTCHistograms) return; - - printSection("TTC histograms"); - - OperationId[] operations = OperationId.values(); - for(OperationId operation : operations) { - System.out.print("TTC histogram for " + operation + ":"); - - for(int ttc = 0; ttc <= Parameters.MAX_LOW_TTC; ttc++) { - int count = 0; - for(BenchThread thread : benchThreads) - count += thread.operationsTTC[operation.ordinal()][ttc]; - - System.out.print(" " + ttc + "," + count); - } - - for(int logTtcIndex = 0; logTtcIndex < Parameters.HIGH_TTC_ENTRIES; logTtcIndex++) { - int count = 0; - for(BenchThread thread : benchThreads) - count += thread.operationsHighTTCLog[operation.ordinal()][logTtcIndex]; - - int ttc = logTtcIndex2Ttc(logTtcIndex); - System.out.print(" " + ttc + "," + count); - } - - System.out.println(); - } - System.out.println(); - } - - private int logTtcIndex2Ttc(double logTtcIndex) { - return (int)((Parameters.MAX_LOW_TTC + 1) * Math.pow(Parameters.HIGH_TTC_LOG_BASE, logTtcIndex)); - } - - private void showStats() { - printSection("Detailed results"); - - OperationId[] operations = OperationId.values(); - for(OperationId operation : operations) { - System.out.print("Operation " + alignText(operation.toString(), 4) + ": "); - - int opNumber = operation.ordinal(); - int successful = 0, failed = 0, maxttc = 0; - for(BenchThread thread : benchThreads) { - successful += thread.successfulOperations[opNumber]; - failed += thread.failedOperations[opNumber]; - maxttc = Math.max(maxttc, computeMaxThreadTTC(thread, opNumber)); - } - - System.out.println("successful = " + successful + "\tmaxttc = " + maxttc + "\tfailed = " + failed); - - OperationType operationType = operation.getType(); - operationType.successfulOperations += successful; - operationType.failedOperations += failed; - operationType.maxttc = Math.max(operationType.maxttc, maxttc); - } - System.out.println(); - - printSection("Sample errors (operation ratios [%])"); - - int totalSuccessful = 0, totalFailed = 0; - for(OperationType type : OperationType.values()) { - totalSuccessful += type.successfulOperations; - totalFailed += type.failedOperations; - } - - double totalError = 0, totalTError = 0; - for(OperationType type : OperationType.values()) { - double expectedRatio = type.probability * type.count * 100.0; - double realRatio = (double)type.successfulOperations / (double)totalSuccessful * 100.0; - double error = Math.abs(realRatio - expectedRatio); - double tRealRatio = (double)(type.successfulOperations + type.failedOperations) / - (double)(totalSuccessful + totalFailed) * 100.0; - double tError = Math.abs(tRealRatio - expectedRatio); - System.out.println(alignText(type.toString(), 23) + ": " + - "expected = " + formatDouble(expectedRatio) + - "\tsuccessful = " + formatDouble(realRatio) + - "\terror = " + formatDouble(error) + - "\t(total = " + formatDouble(tRealRatio) + - "\terror = " + formatDouble(tError) + ")"); - totalError += error; - totalTError += tError; - } - System.out.println(); - - printSection("Summary results"); - - int total = totalSuccessful + totalFailed; - for(OperationType type : OperationType.values()) { - int totalTypeOperations = type.successfulOperations + type.failedOperations; - System.out.println(alignText(type.toString(), 23) + ": " + - "successful = " + type.successfulOperations + - "\tmaxttc = " + type.maxttc + - "\tfailed = " + type.failedOperations + - "\ttotal = " + totalTypeOperations); - } - System.out.println(); - - System.out.println("Total sample error: " + formatDouble(totalError) + "%" + - " (" + formatDouble(totalTError) + "% including failed)"); - System.out.println("Total throughput: " + formatDouble( (double)totalSuccessful / elapsedTime ) + " op/s" + - " (" + formatDouble( (double)total / elapsedTime ) + " op/s including failed)"); - System.out.println("Elapsed time: " + formatDouble(elapsedTime) + " s"); - } - - private int computeMaxThreadTTC(BenchThread thread, int opNumber) { - for(int logTtcIndex = Parameters.HIGH_TTC_ENTRIES - 1; logTtcIndex >= 0; logTtcIndex--) { - if(thread.operationsHighTTCLog[opNumber][logTtcIndex] > 0) - return logTtcIndex2Ttc(logTtcIndex); - } - - for(int ttc = Parameters.MAX_LOW_TTC; ttc >= 0; ttc--) { - if(thread.operationsTTC[opNumber][ttc] > 0) return ttc; - } - - return 0; // operation never completed with success - } - - private void printSyntax() { - String syntax = - "Syntax:\n" + - "java stmbench7.Benchmark [options] [-- stm-specific options]\n\n" + - "Options:\n" + - "\t-t numThreads -- set the number of threads (default: 1)\n" + - "\t-l length -- set the length of the benchmark, in seconds (default: 10)\n" + - "\t-w r|rw|w -- set the workload: r = read-dominated, w = write-dominated\n" + - "\t rw = read-write (default: read-dominated)\n" + - "\t-g coarse|medium|fine|none|stm -- set synchronization method (default: coarse)\n" + - "\t-s stmInitializerClass -- set STM initializer class (default: none)\n" + - "\t--no-traversals -- do not use long traversals\n" + - "\t--no-sms -- do not use structural modification operations\n" + - "\t--seq-replay -- replay the execution in a single thread\n" + - "\t (checks for opacity violations)\n" + - "\t--ttc-histograms -- print TTC histograms to stdout\n\n" + - "Note: the benchmark needs a lot of lot of memory, so the -Xmx option of Java\n" + - "might be necessary."; - System.err.println(syntax); - } - - private void printSection(String title) { - printLine('-'); - System.out.println(title); - printLine('-'); - } - - private void printLine(char ch) { - StringBuffer line = new StringBuffer(79); - for(int i = 0; i < 79; i++) line.append(ch); - System.out.println(line); - } - - private String alignText(String text, int width) { - int textLen = text.length(); - int padding = width - textLen; - if(padding < 0) throw new RuntimeError("alignText: width too small!"); - - StringBuffer output = new StringBuffer(width); - for(int i = 0; i < padding; i++) output.append(' '); - output.append(text); - - return output.toString(); - } - - private String formatDouble(double number) { - Formatter formatter = new Formatter(); - formatter.format("%3.2f", number); - return formatter.toString(); - } -} - diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/ImplParameters.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/ImplParameters.java deleted file mode 100644 index c791f38a..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/ImplParameters.java +++ /dev/null @@ -1,30 +0,0 @@ -package stmbench7; - -import stmbench7.annotations.NonAtomic; -import stmbench7.annotations.ThreadLocal; -import stmbench7.impl.NoSynchronizationInitializer; -import stmbench7.locking.CGLockingInitializer; -import stmbench7.locking.MGLockingInitializer; - -/** - * Parameters that describe the synchronization techniques - * compiled in the benchmark. - */ -@NonAtomic -@ThreadLocal -public class ImplParameters { - - public static final Class - noSynchronizationInitializerClass = NoSynchronizationInitializer.class, - coarseGrainedLockingInitializerClass = CGLockingInitializer.class, - mediumGrainedLockingInitializerClass = MGLockingInitializer.class, - fineGrainedLockingInitializerClass = null; // not implemented yet - - /** - * If non-null, the STM initializer does not have to be specified - * each time the benchmark is run with the "-g stm" command-line - * parameter. - */ - public static final Class - defaultSTMInitializerClass = null; -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/OperationExecutor.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/OperationExecutor.java deleted file mode 100644 index 603dba11..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/OperationExecutor.java +++ /dev/null @@ -1,17 +0,0 @@ -package stmbench7; - -import stmbench7.annotations.NonAtomic; -import stmbench7.annotations.ThreadLocal; -import stmbench7.core.OperationFailedException; - -/** - * An interface representing a class that executes a given operation. - * Can set up a transaction and handle aborts. - */ -@NonAtomic -@ThreadLocal -public interface OperationExecutor { - - int execute() throws OperationFailedException; - int getLastOperationTimestamp(); -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/OperationExecutorFactory.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/OperationExecutorFactory.java deleted file mode 100644 index 1328afbb..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/OperationExecutorFactory.java +++ /dev/null @@ -1,41 +0,0 @@ -package stmbench7; - -import stmbench7.annotations.NonAtomic; -import stmbench7.core.Operation; -import stmbench7.core.OperationFailedException; -import stmbench7.core.RuntimeError; - -/** - * Creates an OperationExecutor object, which is used - * to execute the benchmark operations. For the default - * implementation, see stmbench7.impl.DefaultOperationExecutorFactory. - */ -@NonAtomic -public abstract class OperationExecutorFactory { - - public static OperationExecutorFactory instance = null; - - public static void setInstance(OperationExecutorFactory newInstance) { - instance = newInstance; - } - - public abstract OperationExecutor createOperationExecutor(Operation op); - - public static void executeSequentialOperation(final Operation op) throws InterruptedException { - Thread opThread = ThreadFactory.instance.createThread(new Runnable() { - public void run() { - OperationExecutor operationExecutor = - instance.createOperationExecutor(op); - try { - operationExecutor.execute(); - } - catch(OperationFailedException e) { - throw new RuntimeError("Unexpected failure of a sequential operation " + op); - } - - } - }); - opThread.start(); - opThread.join(); - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/OperationId.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/OperationId.java deleted file mode 100644 index 506aa70b..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/OperationId.java +++ /dev/null @@ -1,121 +0,0 @@ -package stmbench7; - -import stmbench7.annotations.NonAtomic; -import stmbench7.core.Operation; -import stmbench7.operations.Operation10; -import stmbench7.operations.Operation11; -import stmbench7.operations.Operation12; -import stmbench7.operations.Operation13; -import stmbench7.operations.Operation14; -import stmbench7.operations.Operation15; -import stmbench7.operations.Operation6; -import stmbench7.operations.Operation7; -import stmbench7.operations.Operation8; -import stmbench7.operations.Operation9; -import stmbench7.operations.Query1; -import stmbench7.operations.Query2; -import stmbench7.operations.Query3; -import stmbench7.operations.Query4; -import stmbench7.operations.Query5; -import stmbench7.operations.Query6; -import stmbench7.operations.Query7; -import stmbench7.operations.ShortTraversal1; -import stmbench7.operations.ShortTraversal10; -import stmbench7.operations.ShortTraversal2; -import stmbench7.operations.ShortTraversal6; -import stmbench7.operations.ShortTraversal7; -import stmbench7.operations.ShortTraversal8; -import stmbench7.operations.ShortTraversal9; -import stmbench7.operations.StructuralModification1; -import stmbench7.operations.StructuralModification2; -import stmbench7.operations.StructuralModification3; -import stmbench7.operations.StructuralModification4; -import stmbench7.operations.StructuralModification5; -import stmbench7.operations.StructuralModification6; -import stmbench7.operations.StructuralModification7; -import stmbench7.operations.StructuralModification8; -import stmbench7.operations.Traversal1; -import stmbench7.operations.Traversal2a; -import stmbench7.operations.Traversal2b; -import stmbench7.operations.Traversal2c; -import stmbench7.operations.Traversal3a; -import stmbench7.operations.Traversal3b; -import stmbench7.operations.Traversal3c; -import stmbench7.operations.Traversal4; -import stmbench7.operations.Traversal5; -import stmbench7.operations.Traversal6; -import stmbench7.operations.Traversal7; -import stmbench7.operations.Traversal8; -import stmbench7.operations.Traversal9; - -/** - * Lists all STMBench7 operations, together with the classes implementing them - * and their types. - */ -@NonAtomic -public enum OperationId { - T1(Traversal1.class, OperationType.TRAVERSAL_RO), - T2a(Traversal2a.class, OperationType.TRAVERSAL), - T2b(Traversal2b.class, OperationType.TRAVERSAL), - T2c(Traversal2c.class, OperationType.TRAVERSAL), - T3a(Traversal3a.class, OperationType.TRAVERSAL), - T3b(Traversal3b.class, OperationType.TRAVERSAL), - T3c(Traversal3c.class, OperationType.TRAVERSAL), - T4(Traversal4.class, OperationType.TRAVERSAL_RO), - T5(Traversal5.class, OperationType.TRAVERSAL), - T6(Traversal6.class, OperationType.TRAVERSAL_RO), - Q6(Query6.class, OperationType.TRAVERSAL_RO), - Q7(Query7.class, OperationType.TRAVERSAL_RO), - - ST1(ShortTraversal1.class, OperationType.SHORT_TRAVERSAL_RO), - ST2(ShortTraversal2.class, OperationType.SHORT_TRAVERSAL_RO), - ST3(Traversal7.class, OperationType.SHORT_TRAVERSAL_RO), - ST4(Query4.class, OperationType.SHORT_TRAVERSAL_RO), - ST5(Query5.class, OperationType.SHORT_TRAVERSAL_RO), - ST6(ShortTraversal6.class, OperationType.SHORT_TRAVERSAL), - ST7(ShortTraversal7.class, OperationType.SHORT_TRAVERSAL), - ST8(ShortTraversal8.class, OperationType.SHORT_TRAVERSAL), - ST9(ShortTraversal9.class, OperationType.SHORT_TRAVERSAL_RO), - ST10(ShortTraversal10.class, OperationType.SHORT_TRAVERSAL), - - OP1(Query1.class, OperationType.OPERATION_RO), - OP2(Query2.class, OperationType.OPERATION_RO), - OP3(Query3.class, OperationType.OPERATION_RO), - OP4(Traversal8.class, OperationType.OPERATION_RO), - OP5(Traversal9.class, OperationType.OPERATION_RO), - OP6(Operation6.class, OperationType.OPERATION_RO), - OP7(Operation7.class, OperationType.OPERATION_RO), - OP8(Operation8.class, OperationType.OPERATION_RO), - OP9(Operation9.class, OperationType.OPERATION), - OP10(Operation10.class, OperationType.OPERATION), - OP11(Operation11.class, OperationType.OPERATION), - OP12(Operation12.class, OperationType.OPERATION), - OP13(Operation13.class, OperationType.OPERATION), - OP14(Operation14.class, OperationType.OPERATION), - OP15(Operation15.class, OperationType.OPERATION), - - SM1(StructuralModification1.class, OperationType.STRUCTURAL_MODIFICATION), - SM2(StructuralModification2.class, OperationType.STRUCTURAL_MODIFICATION), - SM3(StructuralModification3.class, OperationType.STRUCTURAL_MODIFICATION), - SM4(StructuralModification4.class, OperationType.STRUCTURAL_MODIFICATION), - SM5(StructuralModification5.class, OperationType.STRUCTURAL_MODIFICATION), - SM6(StructuralModification6.class, OperationType.STRUCTURAL_MODIFICATION), - SM7(StructuralModification7.class, OperationType.STRUCTURAL_MODIFICATION), - SM8(StructuralModification8.class, OperationType.STRUCTURAL_MODIFICATION); - - protected Class operationClass; - protected OperationType type; - - private OperationId(Class operationClass, OperationType type) { - this.operationClass = operationClass; - this.type = type; - } - - public OperationType getType() { - return type; - } - - public Class getOperationClass() { - return operationClass; - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/OperationType.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/OperationType.java deleted file mode 100644 index 983d8c69..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/OperationType.java +++ /dev/null @@ -1,22 +0,0 @@ -package stmbench7; - -import stmbench7.annotations.NonAtomic; - -/** - * Types of STMBench7 operations. The "RO" suffix means "read-only". - */ -@NonAtomic -public enum OperationType { - TRAVERSAL, TRAVERSAL_RO, - SHORT_TRAVERSAL, SHORT_TRAVERSAL_RO, - OPERATION, OPERATION_RO, - STRUCTURAL_MODIFICATION; - - /** - * Some helper fields to make life easier. - * Lord... - */ - public int count = 0; - public double probability = 0; - public int successfulOperations = 0, failedOperations = 0, maxttc = 0; -} \ No newline at end of file diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/Parameters.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/Parameters.java deleted file mode 100644 index 75e217c9..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/Parameters.java +++ /dev/null @@ -1,121 +0,0 @@ -package stmbench7; - -import stmbench7.annotations.Immutable; - -/** - * Parameters of the STMBench7 benchmark (see the specification). - */ -@Immutable -public class Parameters { - - /** - * OO7 benchmark parameters for the "medium" size of the benchmark. - * Can be adjusted to match larger or smaller applications. - * Note: these values describe the data structure only at its initial - * state, before the first structure modification operation completes - * with success. - */ - public static final int NumAtomicPerComp = 200, - NumConnPerAtomic = 6, - DocumentSize = 20000, - ManualSize = 1000000, - NumCompPerModule = 500, - NumAssmPerAssm = 3, - NumAssmLevels = 7, - NumCompPerAssm = 3, - NumModules = 1; // currently not used (only a single module) - - /** - * Values derived from the OO7 parameters. Valid only before the first - * structure modification operation finishes with success. - */ - public static final int InitialTotalCompParts = NumModules * NumCompPerModule, - InitialTotalBaseAssemblies = (int)Math.pow(NumAssmPerAssm, NumAssmLevels - 1), - InitialTotalComplexAssemblies = - (1 - (int)Math.pow(NumAssmPerAssm, NumAssmLevels - 1)) / (1 - NumAssmPerAssm); - - /** - * Parameters defining how the size of the data structure can deviate - * from its initial size. Defines the size of the id pools. - */ - public static final int MaxCompParts = (int)(1.05 * InitialTotalCompParts), - MaxAtomicParts = MaxCompParts * NumAtomicPerComp, - MaxBaseAssemblies = (int)(1.05 * InitialTotalBaseAssemblies), - MaxComplexAssemblies = (int)(1.05 * InitialTotalComplexAssemblies); - - /** - * Constants used in various operations (values taken from the - * original OO7 source code). - */ - public static final int MinModuleDate = 1000, - MaxModuleDate = 1999, - MinAssmDate = 1000, - MaxAssmDate = 1999, - MinAtomicDate = 1000, - MaxAtomicDate = 1999, - MinOldCompDate = 0, - MaxOldCompDate = 999, - MinYoungCompDate = 2000, - MaxYoungCompDate = 2999, - YoungCompFrac = 10, - TypeSize = 10, - NumTypes = 10, - XYRange = 100000, - TitleSize = 40; - - /** - * Ratios of various operation types (in percents). - */ - public static final int TraversalsRatio = 5, - ShortTraversalsRatio = 40, - OperationsRatio = 45, - StructuralModificationsRatio = 10; - - /** - * Application workload. - */ - @Immutable - public enum WorkloadType { - READ_DOMINATED(90), - READ_WRITE(60), - WRITE_DOMINATED(10); - - public final int readOnlyOperationsRatio; - - private WorkloadType(int readOnlyOperationsRatio) { - this.readOnlyOperationsRatio = readOnlyOperationsRatio; - } - } - - /** - * Synchronization type. - */ - @Immutable - public enum SynchronizationType { - NONE, LOCK_COARSE, LOCK_MEDIUM, LOCK_FINE, STM; - } - - /** - * Command-line benchmark parameters. - */ - public static WorkloadType workloadType = WorkloadType.READ_DOMINATED; - public static SynchronizationType synchronizationType = SynchronizationType.LOCK_COARSE; - public static int numThreads = 1, - numSeconds = 10; - public static boolean longTraversalsEnabled = true, - structureModificationEnabled = true, - sequentialReplayEnabled = false; - - /** - * STM-specific command-line parameters. - * To be parsed by a given STM initializer. - */ - public static String[] stmCommandLineParameters = null; - - /** - * Parameters of the output TTC histograms. - */ - public static final int MAX_LOW_TTC = 999; - public static final int HIGH_TTC_ENTRIES = 200; - public static final double HIGH_TTC_LOG_BASE = 1.03; -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/Setup.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/Setup.java deleted file mode 100644 index 8646efb4..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/Setup.java +++ /dev/null @@ -1,95 +0,0 @@ -package stmbench7; - -import stmbench7.annotations.Immutable; -import stmbench7.backend.BackendFactory; -import stmbench7.backend.Index; -import stmbench7.backend.LargeSet; -import stmbench7.core.AssemblyBuilder; -import stmbench7.core.AtomicPart; -import stmbench7.core.BaseAssembly; -import stmbench7.core.ComplexAssembly; -import stmbench7.core.CompositePart; -import stmbench7.core.CompositePartBuilder; -import stmbench7.core.Document; -import stmbench7.core.Module; -import stmbench7.core.ModuleBuilder; -import stmbench7.operations.SetupDataStructure; - -/** - * Sets up the benchmark structures according to given parameters, - * including indexes. - */ -@Immutable -public class Setup { - - protected Module module; - - protected Index atomicPartIdIndex; - protected Index> atomicPartBuildDateIndex; - protected Index documentTitleIndex; - protected Index compositePartIdIndex; - protected Index baseAssemblyIdIndex; - protected Index complexAssemblyIdIndex; - - protected CompositePartBuilder compositePartBuilder; - protected ModuleBuilder moduleBuilder; - - public Setup() throws InterruptedException { - BackendFactory backendFactory = BackendFactory.instance; - - atomicPartIdIndex = backendFactory.createIndex(); - atomicPartBuildDateIndex = backendFactory.>createIndex(); - documentTitleIndex = backendFactory.createIndex(); - compositePartIdIndex = backendFactory.createIndex(); - baseAssemblyIdIndex = backendFactory.createIndex(); - complexAssemblyIdIndex = backendFactory.createIndex(); - - compositePartBuilder = new CompositePartBuilder(compositePartIdIndex, - documentTitleIndex, atomicPartIdIndex, atomicPartBuildDateIndex); - moduleBuilder = new ModuleBuilder(baseAssemblyIdIndex, complexAssemblyIdIndex); - - SetupDataStructure setupOperation = new SetupDataStructure(this); - OperationExecutorFactory.executeSequentialOperation(setupOperation); - module = setupOperation.getModule(); - } - - public Index> getAtomicPartBuildDateIndex() { - return atomicPartBuildDateIndex; - } - - public Index getAtomicPartIdIndex() { - return atomicPartIdIndex; - } - - public Index getBaseAssemblyIdIndex() { - return baseAssemblyIdIndex; - } - - public Index getComplexAssemblyIdIndex() { - return complexAssemblyIdIndex; - } - - public Index getCompositePartIdIndex() { - return compositePartIdIndex; - } - - public Index getDocumentTitleIndex() { - return documentTitleIndex; - } - - public Module getModule() { - return module; - } - - public CompositePartBuilder getCompositePartBuilder() { - return compositePartBuilder; - } - - public ModuleBuilder getModuleBuilder() { - return moduleBuilder; - } - - public AssemblyBuilder getAssemblyBuilder() { - return moduleBuilder.getAssemblyBuilder(); - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/SynchMethodInitializer.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/SynchMethodInitializer.java deleted file mode 100644 index f2aaed6e..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/SynchMethodInitializer.java +++ /dev/null @@ -1,20 +0,0 @@ -package stmbench7; - -import stmbench7.annotations.NonAtomic; -import stmbench7.backend.BackendFactory; -import stmbench7.core.DesignObjFactory; - -/** - * Creates factories suitable for a given synchonization method. - * Default implementations are provided for coarse-grained and - * medium-grained locking, as well as for single-threaded executions - * (i.e., without any thread synchronization). - */ -@NonAtomic -public interface SynchMethodInitializer { - - public DesignObjFactory createDesignObjFactory(); - public BackendFactory createBackendFactory(); - public OperationExecutorFactory createOperationExecutorFactory(); - public ThreadFactory createThreadFactory(); -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/ThreadFactory.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/ThreadFactory.java deleted file mode 100644 index 464f1729..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/ThreadFactory.java +++ /dev/null @@ -1,20 +0,0 @@ -package stmbench7; - -import stmbench7.annotations.NonAtomic; - -/** - * In most cases, the factory will simply create a java.lang.Thread object using - * a given Runnable object. Some STMs, however, require that transactions are - * executed by threads of a specified class (descendant from java.lang.Thread). - */ -@NonAtomic -public abstract class ThreadFactory { - - public static ThreadFactory instance = null; - - public static void setInstance(ThreadFactory newInstance) { - instance = newInstance; - } - - public abstract Thread createThread(Runnable runnable); -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/ThreadRandom.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/ThreadRandom.java deleted file mode 100644 index ba226c8f..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/ThreadRandom.java +++ /dev/null @@ -1,136 +0,0 @@ -package stmbench7; - -import java.util.Random; - -import stmbench7.annotations.Immutable; -import stmbench7.core.RuntimeError; - -/** - * This is a central repository for thread-local random - * number generators. No other class should create an instance - * of class Random, but should use the methods in ThreadRandom - * instead. This way we can centrally control the (un)determinism - * of the benchmark and the implementation of a random number - * generator used. - */ -@Immutable -public class ThreadRandom { - - public static enum Phase { - INIT, - CONCURRENT, - SEQUENTIAL_REPLAY - } - - private static class CloneableRandom extends Random implements Cloneable { - public static final long serialVersionUID = 1L; - - public CloneableRandom(long seed) { - super(seed); - } - - @Override - public CloneableRandom clone() { - try { - return (CloneableRandom) super.clone(); - } - catch(CloneNotSupportedException e) { - throw new RuntimeException(e); - } - } - } - - private static class RandomState { - private CloneableRandom currentState, savedState; - - public RandomState() { - currentState = new CloneableRandom(3); - savedState = null; - } - - public void saveState() { - savedState = currentState.clone(); - } - - public void restoreState() { - currentState = savedState; - } - } - - public static Phase phase = Phase.INIT; - private static RandomState initRandom = new RandomState(); - private static short currentVirtualThreadNumber; - private static RandomState[] virtualRandom; - - private ThreadRandom() { } - - private static final ThreadLocal random = - new ThreadLocal() { - @Override - protected RandomState initialValue() { - return new RandomState(); - } - }; - - public static int nextInt(int n) { - int k = getCurrentRandom().currentState.nextInt(n); - //if(phase != Phase.INIT) - // System.out.println("int " + n + " = " + k + " " + getCurrentRandom().currentState); - return k; - } - - public static double nextDouble() { - double k = getCurrentRandom().currentState.nextDouble(); - //if(phase != Phase.INIT) - // System.out.println("double = " + k + " " + getCurrentRandom().currentState); - return k; - } - - public static void reset() { - if(phase != Phase.INIT) { - System.out.println("Warning, cannot reset!"); - throw new RuntimeError("Cannot reset ThreadRandom after the initialization phase"); - } - initRandom = new RandomState(); - } - - public static void startConcurrentPhase() { - phase = Phase.CONCURRENT; - } - - public static void startSequentialReplayPhase() { - phase = Phase.SEQUENTIAL_REPLAY; - virtualRandom = new RandomState[Parameters.numThreads]; - for(int n = 0; n < Parameters.numThreads; n++) - virtualRandom[n] = new RandomState(); - } - - public static void setVirtualThreadNumber(short threadNum) { - currentVirtualThreadNumber = threadNum; - } - - public static void saveState() { - getCurrentRandom().saveState(); - } - - public static void restoreState() { - getCurrentRandom().restoreState(); - } - - private static RandomState getCurrentRandom() { - /* - switch(phase) { - case INIT: return initRandom; - case CONCURRENT: return random.get(); - case SEQUENTIAL_REPLAY: return virtualRandom[currentVirtualThreadNumber]; - default: return null; - } - */ - switch(((Enum)phase).ordinal()) { - case 0: return initRandom; - case 1: return random.get(); - case 2: return virtualRandom[currentVirtualThreadNumber]; - default: return null; - } - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/annotations/Atomic.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/annotations/Atomic.java deleted file mode 100644 index b84bfb79..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/annotations/Atomic.java +++ /dev/null @@ -1,17 +0,0 @@ -package stmbench7.annotations; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Inherited; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Annotates objects that are used by transactions and thus should - * be atomic. - */ -@Target(ElementType.TYPE) -@Retention(RetentionPolicy.RUNTIME) -@Inherited -public @interface Atomic { -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/annotations/ContainedInAtomic.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/annotations/ContainedInAtomic.java deleted file mode 100644 index c3736424..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/annotations/ContainedInAtomic.java +++ /dev/null @@ -1,17 +0,0 @@ -package stmbench7.annotations; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Inherited; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Annotates objects that are fully contained in an atomic object, - * and so do not have to be synchronized separately. - */ -@Target(ElementType.TYPE) -@Retention(RetentionPolicy.RUNTIME) -@Inherited -public @interface ContainedInAtomic { -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/annotations/Immutable.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/annotations/Immutable.java deleted file mode 100644 index 5870f023..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/annotations/Immutable.java +++ /dev/null @@ -1,18 +0,0 @@ -package stmbench7.annotations; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Inherited; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Annotates objects that never change after they are created. - * These can be used inside transactions, but are usually safe - * without any additional synchronization. - */ -@Target(ElementType.TYPE) -@Retention(RetentionPolicy.RUNTIME) -@Inherited -public @interface Immutable { -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/annotations/NonAtomic.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/annotations/NonAtomic.java deleted file mode 100644 index b6cbd9d1..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/annotations/NonAtomic.java +++ /dev/null @@ -1,17 +0,0 @@ -package stmbench7.annotations; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Inherited; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Annotates objects that are never (and must never) be used inside - * transactions. - */ -@Target(ElementType.TYPE) -@Retention(RetentionPolicy.RUNTIME) -@Inherited -public @interface NonAtomic { -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/annotations/ReadOnly.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/annotations/ReadOnly.java deleted file mode 100644 index 96126629..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/annotations/ReadOnly.java +++ /dev/null @@ -1,14 +0,0 @@ -package stmbench7.annotations; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Annotates methods and transactions that are read-only. - */ -@Target(ElementType.METHOD) -@Retention(RetentionPolicy.RUNTIME) -public @interface ReadOnly { -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/annotations/ThreadLocal.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/annotations/ThreadLocal.java deleted file mode 100644 index ee717d3d..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/annotations/ThreadLocal.java +++ /dev/null @@ -1,17 +0,0 @@ -package stmbench7.annotations; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Inherited; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Annotates objects that are always used locally by - * each thread, and so do not have to be thread-safe. - */ -@Target(ElementType.TYPE) -@Retention(RetentionPolicy.RUNTIME) -@Inherited -public @interface ThreadLocal { -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/annotations/Transactional.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/annotations/Transactional.java deleted file mode 100644 index 96abd9f7..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/annotations/Transactional.java +++ /dev/null @@ -1,14 +0,0 @@ -package stmbench7.annotations; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Annotates methods that should be always executed as transactions. - */ -@Target(ElementType.METHOD) -@Retention(RetentionPolicy.RUNTIME) -public @interface Transactional { -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/annotations/Update.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/annotations/Update.java deleted file mode 100644 index a3a5e32d..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/annotations/Update.java +++ /dev/null @@ -1,14 +0,0 @@ -package stmbench7.annotations; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Annotates methods and transactions that are not read-only. - */ -@Target(ElementType.METHOD) -@Retention(RetentionPolicy.RUNTIME) -public @interface Update { -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/backend/BackendFactory.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/backend/BackendFactory.java deleted file mode 100644 index 1292d5e2..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/backend/BackendFactory.java +++ /dev/null @@ -1,21 +0,0 @@ -package stmbench7.backend; - -import stmbench7.annotations.Immutable; - -/** - * Creates the structures of the benchmark backend: indexes, - * id pools, and large sets. - */ -@Immutable -public abstract class BackendFactory { - - public static BackendFactory instance = null; - - public static void setInstance(BackendFactory newInstance) { - instance = newInstance; - } - - public abstract > LargeSet createLargeSet(); - public abstract , V> Index createIndex(); - public abstract IdPool createIdPool(int maxNumberOfIds); -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/backend/IdPool.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/backend/IdPool.java deleted file mode 100644 index 5be3aa7e..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/backend/IdPool.java +++ /dev/null @@ -1,22 +0,0 @@ -package stmbench7.backend; - -import stmbench7.annotations.Atomic; -import stmbench7.annotations.Update; -import stmbench7.core.OperationFailedException; - -/** - * Implements a pool of ids of various objects of the data structure. - * Necessary to ensure that no two objects of the same type and with - * the same id are created by different threads, and that the data - * structure does not grow beyond the limits defined in the Parameters - * class. - */ -@Atomic -public interface IdPool { - - @Update - public abstract int getId() throws OperationFailedException; - - @Update - public abstract void putUnusedId(int id); -} \ No newline at end of file diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/backend/ImmutableCollection.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/backend/ImmutableCollection.java deleted file mode 100644 index 996af431..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/backend/ImmutableCollection.java +++ /dev/null @@ -1,14 +0,0 @@ -package stmbench7.backend; - -import stmbench7.annotations.Immutable; - -/** - * Represents a read-only view of a collection of elements. - */ -@Immutable -public interface ImmutableCollection extends Iterable { - - int size(); - boolean contains(E element); // not necessarily efficient! - public ImmutableCollection clone(); -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/backend/Index.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/backend/Index.java deleted file mode 100644 index 1ae3abcf..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/backend/Index.java +++ /dev/null @@ -1,31 +0,0 @@ -package stmbench7.backend; - -import stmbench7.annotations.Atomic; -import stmbench7.annotations.ReadOnly; -import stmbench7.annotations.Update; - -/** - * The interface of the core part of the "backbone" of the STMBench7 benchmark -- - * indexes used by many of the benchmark operations. - */ -@Atomic -public interface Index,V> extends Iterable { - - @ReadOnly - V get(K key); - - @Update - void put(K key, V value); - - @Update - V putIfAbsent(K key, V value); - - @Update - boolean remove(K key); - - @ReadOnly - public Iterable getRange(K minKey, K maxKey); - - @ReadOnly - public Iterable getKeys(); -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/backend/LargeSet.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/backend/LargeSet.java deleted file mode 100644 index 33548e4a..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/backend/LargeSet.java +++ /dev/null @@ -1,28 +0,0 @@ -package stmbench7.backend; - -import stmbench7.annotations.Atomic; -import stmbench7.annotations.ReadOnly; -import stmbench7.annotations.Update; - -/** - * A large set: of the size in the order of at least - * a few hundreds of elements. Used by a composite part - * to hold the set of child atomic parts, and by the - * AtomicPart.buildDate index to hold all atomic parts - * with the same build date. - */ -@Atomic -public interface LargeSet> extends Iterable { - - @Update - boolean add(E element); - - @Update - boolean remove(E element); - - @ReadOnly - boolean contains(E element); - - @ReadOnly - int size(); -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/Assembly.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/Assembly.java deleted file mode 100644 index 7304e223..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/Assembly.java +++ /dev/null @@ -1,22 +0,0 @@ -package stmbench7.core; - -import stmbench7.annotations.Atomic; -import stmbench7.annotations.ReadOnly; -import stmbench7.annotations.Update; - -/** - * Part of the main benchmark data structure. For a default - * implementation, see stmbench7.impl.core.AssemblyImpl. - */ -@Atomic -public interface Assembly extends DesignObj { - - @ReadOnly - ComplexAssembly getSuperAssembly(); - - @ReadOnly - Module getModule(); - - @Update - void clearPointers(); -} \ No newline at end of file diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/AssemblyBuilder.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/AssemblyBuilder.java deleted file mode 100644 index 1562c31b..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/AssemblyBuilder.java +++ /dev/null @@ -1,121 +0,0 @@ -package stmbench7.core; - -import stmbench7.Parameters; -import stmbench7.annotations.Immutable; -import stmbench7.backend.BackendFactory; -import stmbench7.backend.IdPool; -import stmbench7.backend.ImmutableCollection; -import stmbench7.backend.Index; - -/** - * Used to create and destroy assembly elements while - * maintaining the consistency of the data structure - * and the indexes. - */ -@Immutable -public class AssemblyBuilder extends DesignObjBuilder { - - private final IdPool baseAssemblyIdPool, complexAssemblyIdPool; - - private final Index baseAssemblyIdIndex; - private final Index complexAssemblyIdIndex; - - public AssemblyBuilder(Index baseAssemblyIdIndex, - Index complexAssemblyIdIndex) { - this.baseAssemblyIdIndex = baseAssemblyIdIndex; - baseAssemblyIdPool = BackendFactory.instance.createIdPool(Parameters.MaxBaseAssemblies); - - this.complexAssemblyIdIndex = complexAssemblyIdIndex; - complexAssemblyIdPool = BackendFactory.instance.createIdPool(Parameters.MaxComplexAssemblies); - } - - public Assembly createAndRegisterAssembly(Module module, ComplexAssembly superAssembly) - throws OperationFailedException { - if( (superAssembly == null) || (superAssembly.getLevel() > 2) ) - return createAndRegisterComplexAssembly(module, superAssembly); - - return createAndRegisterBaseAssembly(module, superAssembly); - } - - public void unregisterAndRecycleAssembly(Assembly assembly) { - if(assembly instanceof ComplexAssembly) - unregisterAndRecycleComplexAssembly((ComplexAssembly)assembly); - else unregisterAndRecycleBaseAssembly((BaseAssembly)assembly); - } - - public void unregisterAndRecycleBaseAssembly(BaseAssembly baseAssembly) { - int baseAssemblyId = baseAssembly.getId(); - baseAssemblyIdIndex.remove(baseAssemblyId); - - baseAssembly.getSuperAssembly().removeSubAssembly(baseAssembly); - - ImmutableCollection componentsSet = baseAssembly.getComponents().clone(); - for(CompositePart component : componentsSet) - baseAssembly.removeComponent(component); - - baseAssembly.clearPointers(); - baseAssemblyIdPool.putUnusedId(baseAssemblyId); - } - - public void unregisterAndRecycleComplexAssembly(ComplexAssembly complexAssembly) { - short currentLevel = complexAssembly.getLevel(); - ComplexAssembly superAssembly = complexAssembly.getSuperAssembly(); - - if(superAssembly == null) - throw new RuntimeError("ComplexAssemblyFactory: root Complex Assembly cannot be removed!"); - - superAssembly.removeSubAssembly(complexAssembly); - - ImmutableCollection subAssembliesSet = complexAssembly.getSubAssemblies().clone(); - for(Assembly assembly : subAssembliesSet) { - if(currentLevel > 2) unregisterAndRecycleComplexAssembly((ComplexAssembly)assembly); - else unregisterAndRecycleBaseAssembly((BaseAssembly)assembly); - } - - int id = complexAssembly.getId(); - complexAssemblyIdIndex.remove(id); - - complexAssembly.clearPointers(); - complexAssemblyIdPool.putUnusedId(id); - } - - private BaseAssembly createAndRegisterBaseAssembly(Module module, ComplexAssembly superAssembly) - throws OperationFailedException { - int date = createBuildDate(Parameters.MinAssmDate, Parameters.MaxAssmDate); - int assemblyId = baseAssemblyIdPool.getId(); - BaseAssembly baseAssembly = - designObjFactory.createBaseAssembly(assemblyId, createType(), date, module, superAssembly); - - baseAssemblyIdIndex.put(assemblyId, baseAssembly); - - superAssembly.addSubAssembly(baseAssembly); - - return baseAssembly; - } - - private ComplexAssembly createAndRegisterComplexAssembly(Module module, ComplexAssembly superAssembly) - throws OperationFailedException { - int id = complexAssemblyIdPool.getId(); - int date = createBuildDate(Parameters.MinAssmDate, Parameters.MaxAssmDate); - ComplexAssembly complexAssembly = - designObjFactory.createComplexAssembly(id, createType(), date, module, superAssembly); - - try { - for(int i = 0; i < Parameters.NumAssmPerAssm; i++) - createAndRegisterAssembly(module, complexAssembly); - } - catch(OperationFailedException e) { - for(Assembly subAssembly : complexAssembly.getSubAssemblies().clone()) - unregisterAndRecycleAssembly(subAssembly); - complexAssemblyIdPool.putUnusedId(id); - complexAssembly.clearPointers(); - throw e; - } - - complexAssemblyIdIndex.put(id, complexAssembly); - - if(superAssembly != null) superAssembly.addSubAssembly(complexAssembly); - - return complexAssembly; - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/AtomicPart.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/AtomicPart.java deleted file mode 100644 index 206997a5..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/AtomicPart.java +++ /dev/null @@ -1,47 +0,0 @@ -package stmbench7.core; - -import stmbench7.annotations.Atomic; -import stmbench7.annotations.ReadOnly; -import stmbench7.annotations.Update; -import stmbench7.backend.ImmutableCollection; - -/** - * Part of the main benchmark data structure. For a default - * implementation, see stmbench7.impl.core.AtomicPartImpl. - */ -@Atomic -public interface AtomicPart extends DesignObj, Comparable { - - @Update - void connectTo(AtomicPart destination, String type, int length); - - @Update - void addConnectionFromOtherPart(Connection connection); - - @Update - void setCompositePart(CompositePart partOf); - - @ReadOnly - int getNumToConnections(); - - @ReadOnly - ImmutableCollection getToConnections(); - - @ReadOnly - ImmutableCollection getFromConnections(); - - @ReadOnly - CompositePart getPartOf(); - - @Update - void swapXY(); - - @ReadOnly - int getX(); - - @ReadOnly - int getY(); - - @Update - void clearPointers(); -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/AtomicPartBuilder.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/AtomicPartBuilder.java deleted file mode 100644 index 2c5c16de..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/AtomicPartBuilder.java +++ /dev/null @@ -1,57 +0,0 @@ -package stmbench7.core; - -import stmbench7.Parameters; -import stmbench7.ThreadRandom; -import stmbench7.annotations.Immutable; -import stmbench7.backend.BackendFactory; -import stmbench7.backend.IdPool; -import stmbench7.backend.Index; -import stmbench7.backend.LargeSet; -import stmbench7.operations.BaseOperation; - -/** - * Used to create and destroy atomic parts while - * maintaining the consistency of the data structure - * and the indexes. - */ -@Immutable -public class AtomicPartBuilder extends DesignObjBuilder { - - private final IdPool idPool; - - private final Index partIdIndex; - private final Index> partBuildDateIndex; - - public AtomicPartBuilder(Index partIdIndex, - Index> partBuildDateIndex) { - - this.partIdIndex = partIdIndex; - this.partBuildDateIndex = partBuildDateIndex; - idPool = BackendFactory.instance.createIdPool(Parameters.MaxAtomicParts); - } - - public AtomicPart createAndRegisterAtomicPart() throws OperationFailedException{ - int id = idPool.getId(); - String type = createType(); - int buildDate = createBuildDate(Parameters.MinAtomicDate, Parameters.MaxAtomicDate); - int x = ThreadRandom.nextInt(Parameters.XYRange), - y = x + 1; // convenient for invariant tests - - AtomicPart part = designObjFactory.createAtomicPart(id, type, buildDate, x, y); - - partIdIndex.put(id, part); - BaseOperation.addAtomicPartToBuildDateIndex(partBuildDateIndex, part); - - return part; - } - - public void unregisterAndRecycleAtomicPart(AtomicPart part) { - int partId = part.getId(); - - BaseOperation.removeAtomicPartFromBuildDateIndex(partBuildDateIndex, part); - partIdIndex.remove(partId); - part.clearPointers(); - - idPool.putUnusedId(partId); - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/BaseAssembly.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/BaseAssembly.java deleted file mode 100644 index 91cdab64..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/BaseAssembly.java +++ /dev/null @@ -1,23 +0,0 @@ -package stmbench7.core; - -import stmbench7.annotations.Atomic; -import stmbench7.annotations.ReadOnly; -import stmbench7.annotations.Update; -import stmbench7.backend.ImmutableCollection; - -/** - * Part of the main benchmark data structure. For a default - * implementation, see stmbench7.impl.core.BaseAssemblyImpl. - */ -@Atomic -public interface BaseAssembly extends Assembly { - - @Update - void addComponent(CompositePart component); - - @Update - boolean removeComponent(CompositePart component); - - @ReadOnly - ImmutableCollection getComponents(); -} \ No newline at end of file diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/ComplexAssembly.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/ComplexAssembly.java deleted file mode 100644 index 05e04baa..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/ComplexAssembly.java +++ /dev/null @@ -1,26 +0,0 @@ -package stmbench7.core; - -import stmbench7.annotations.Atomic; -import stmbench7.annotations.ReadOnly; -import stmbench7.annotations.Update; -import stmbench7.backend.ImmutableCollection; - -/** - * Part of the main benchmark data structure. For a default - * implementation, see stmbench7.impl.core.ComplexAssemblyImpl. - */ -@Atomic -public interface ComplexAssembly extends Assembly { - - @Update - boolean addSubAssembly(Assembly assembly); - - @Update - boolean removeSubAssembly(Assembly assembly); - - @ReadOnly - ImmutableCollection getSubAssemblies(); - - @ReadOnly - short getLevel(); -} \ No newline at end of file diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/CompositePart.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/CompositePart.java deleted file mode 100644 index b18227af..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/CompositePart.java +++ /dev/null @@ -1,42 +0,0 @@ -package stmbench7.core; - -import stmbench7.annotations.Atomic; -import stmbench7.annotations.ReadOnly; -import stmbench7.annotations.Update; -import stmbench7.backend.ImmutableCollection; -import stmbench7.backend.LargeSet; - -/** - * Part of the main benchmark data structure. For a default - * implementation, see stmbench7.impl.core.CompositePartImpl. - */ -@Atomic -public interface CompositePart extends DesignObj { - - @Update - void addAssembly(BaseAssembly assembly); - - @Update - boolean addPart(AtomicPart part); - - @Update - void setRootPart(AtomicPart part); - - @ReadOnly - AtomicPart getRootPart(); - - @ReadOnly - Document getDocumentation(); - - @ReadOnly - LargeSet getParts(); - - @Update - void removeAssembly(BaseAssembly assembly); - - @ReadOnly - ImmutableCollection getUsedIn(); - - @Update - void clearPointers(); -} \ No newline at end of file diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/CompositePartBuilder.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/CompositePartBuilder.java deleted file mode 100644 index e8e5c613..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/CompositePartBuilder.java +++ /dev/null @@ -1,131 +0,0 @@ -package stmbench7.core; - -import stmbench7.Parameters; -import stmbench7.ThreadRandom; -import stmbench7.annotations.Immutable; -import stmbench7.backend.BackendFactory; -import stmbench7.backend.IdPool; -import stmbench7.backend.ImmutableCollection; -import stmbench7.backend.Index; -import stmbench7.backend.LargeSet; - -/** - * Used to create and destroy composite parts while - * maintaining the consistency of the data structure - * and the indexes. - */ -@Immutable -public class CompositePartBuilder extends DesignObjBuilder { - - private final IdPool idPool; - - private final Index compositePartIdIndex; - private final DocumentBuilder documentBuilder; - private final AtomicPartBuilder atomicPartBuilder; - - public CompositePartBuilder(Index compositePartIdIndex, - Index documentTitleIndex, - Index partIdIndex, - Index> partBuildDateIndex) { - - this.compositePartIdIndex = compositePartIdIndex; - documentBuilder = new DocumentBuilder(documentTitleIndex); - atomicPartBuilder = new AtomicPartBuilder(partIdIndex, partBuildDateIndex); - idPool = BackendFactory.instance.createIdPool(Parameters.MaxCompParts); - } - - /** - * Creates a component (composite part) with the documentation and - * a graph of atomic parts and updates all the relevant indexes. - */ - public CompositePart createAndRegisterCompositePart() throws OperationFailedException { - int id = idPool.getId(); - String type = createType(); - - int buildDate; - if(ThreadRandom.nextInt(100) < Parameters.YoungCompFrac) - buildDate = createBuildDate(Parameters.MinYoungCompDate, Parameters.MaxYoungCompDate); - else - buildDate = createBuildDate(Parameters.MinOldCompDate, Parameters.MaxOldCompDate); - - Document documentation = null; - AtomicPart parts[] = new AtomicPart[Parameters.NumAtomicPerComp]; - - try { - documentation = documentBuilder.createAndRegisterDocument(id); - createAtomicParts(parts); - } - catch(OperationFailedException e) { - if(documentation != null) documentBuilder.unregisterAndRecycleDocument(documentation); - for(AtomicPart part : parts) - if(part != null) atomicPartBuilder.unregisterAndRecycleAtomicPart(part); - idPool.putUnusedId(id); - throw e; - } - - createConnections(parts); - - CompositePart component = designObjFactory.createCompositePart(id, type, buildDate, documentation); - for(AtomicPart part : parts) component.addPart(part); - - compositePartIdIndex.put(id, component); - - return component; - } - - public void unregisterAndRecycleCompositePart(CompositePart compositePart) { - int id = compositePart.getId(); - compositePartIdIndex.remove(id); - - documentBuilder.unregisterAndRecycleDocument(compositePart.getDocumentation()); - - for(AtomicPart atomicPart : compositePart.getParts()) - atomicPartBuilder.unregisterAndRecycleAtomicPart(atomicPart); - - ImmutableCollection usedInList = compositePart.getUsedIn().clone(); - for(BaseAssembly ownerAssembly : usedInList) { - while(ownerAssembly.removeComponent(compositePart)); - } - - compositePart.clearPointers(); - idPool.putUnusedId(id); - } - - /** - * Create all atomic parts of a given composite part. - */ - private void createAtomicParts(AtomicPart[] parts) throws OperationFailedException { - - for(int partNum = 0; partNum < Parameters.NumAtomicPerComp; partNum++) { - AtomicPart part = atomicPartBuilder.createAndRegisterAtomicPart(); - parts[partNum] = part; - } - } - - /** - * Create connections between the parts. - */ - private void createConnections(AtomicPart[] parts) { - - // First, make all atomic parts be connected in a ring - // (so that the resulting graph is fully connected) - for(int partNum = 0; partNum < Parameters.NumAtomicPerComp; partNum++) { - int connectTo = (partNum + 1) % Parameters.NumAtomicPerComp; - parts[partNum].connectTo(parts[connectTo], createType(), - ThreadRandom.nextInt(Parameters.XYRange) + 1); - } - - // Then add other connections randomly, taking into account - // the NumConnPerAtomic parameter. The procedure is non-deterministic - // but it should eventually terminate. - for(int partNum = 0; partNum < Parameters.NumAtomicPerComp; partNum++) { - AtomicPart currentPart = parts[partNum]; - - while(currentPart.getNumToConnections() < Parameters.NumConnPerAtomic) { - int connectTo = ThreadRandom.nextInt(Parameters.NumAtomicPerComp); - parts[partNum].connectTo(parts[connectTo], createType(), - ThreadRandom.nextInt(Parameters.XYRange) + 1); - } - } - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/Connection.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/Connection.java deleted file mode 100644 index ba758fe1..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/Connection.java +++ /dev/null @@ -1,17 +0,0 @@ -package stmbench7.core; - -import stmbench7.annotations.Immutable; - -/** - * Part of the main benchmark data structure. For a default - * implementation, see stmbench7.impl.core.ConnectionImpl. - */ -@Immutable -public interface Connection { - - Connection getReversed(); - AtomicPart getDestination(); - AtomicPart getSource(); - String getType(); - int getLength(); -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/DesignObj.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/DesignObj.java deleted file mode 100644 index a62f201b..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/DesignObj.java +++ /dev/null @@ -1,28 +0,0 @@ -package stmbench7.core; - -import stmbench7.annotations.Atomic; -import stmbench7.annotations.ReadOnly; -import stmbench7.annotations.Update; - -/** - * A class from which most parts of the main benchmark data structure descend. - * For a default implementation, see stmbench7.impl.core.DesignObjImpl. - */ -@Atomic -public interface DesignObj { - - @ReadOnly - int getId(); - - @ReadOnly - int getBuildDate(); - - @ReadOnly - String getType(); - - @Update - void updateBuildDate(); - - @ReadOnly - void nullOperation(); -} \ No newline at end of file diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/DesignObjBuilder.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/DesignObjBuilder.java deleted file mode 100644 index 2168f9c0..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/DesignObjBuilder.java +++ /dev/null @@ -1,38 +0,0 @@ -package stmbench7.core; - -import stmbench7.Parameters; -import stmbench7.ThreadRandom; -import stmbench7.annotations.Immutable; - -/** - * Methods for constructing common attributes of objects implementing parts of - * the data structure. - */ -@Immutable -public abstract class DesignObjBuilder { - - protected final DesignObjFactory designObjFactory = DesignObjFactory.instance; - - protected String createType() { - String type = "type #" + ThreadRandom.nextInt(Parameters.NumTypes); - return type; - } - - protected int createBuildDate(int minBuildDate, int maxBuildDate) { - return minBuildDate - + ThreadRandom.nextInt(maxBuildDate - minBuildDate + 1); - } - - protected String createText(int textSize, String textPattern) { - int patternSize = textPattern.length(); - int size = 0; - StringBuilder stringBuilder = new StringBuilder(textSize); - - while (size + patternSize <= textSize) { - stringBuilder.append(textPattern); - size += patternSize; - } - - return stringBuilder.toString(); - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/DesignObjFactory.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/DesignObjFactory.java deleted file mode 100644 index ee6e7898..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/DesignObjFactory.java +++ /dev/null @@ -1,33 +0,0 @@ -package stmbench7.core; - -import stmbench7.annotations.Immutable; - -/** - * A factory for creating all the objects of the main benchmark - * data structure. A default implementation is provided by the - * stmbench7.impl.core.DesignObjFactoryImpl class, but most STM - * implementations will provide their own implementation, which - * will create transaction-safe versions of the data structure - * elements. - */ -@Immutable -public abstract class DesignObjFactory { - - public static DesignObjFactory instance = null; - - public static void setInstance(DesignObjFactory newInstance) { - instance = newInstance; - } - - public abstract AtomicPart createAtomicPart(int id, String type, int buildDate, int x, int y); - public abstract Connection createConnection(AtomicPart from, AtomicPart to, String type, int length); - public abstract BaseAssembly createBaseAssembly(int id, String type, int buildDate, - Module module, ComplexAssembly superAssembly); - public abstract ComplexAssembly createComplexAssembly(int id, String type, int buildDate, - Module module, ComplexAssembly superAssembly); - public abstract CompositePart createCompositePart(int id, String type, int buildDate, - Document documentation); - public abstract Document createDocument(int id, String title, String text); - public abstract Manual createManual(int id, String title, String text); - public abstract Module createModule(int id, String type, int buildDate, Manual man); -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/Document.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/Document.java deleted file mode 100644 index ed925051..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/Document.java +++ /dev/null @@ -1,40 +0,0 @@ -package stmbench7.core; - -import stmbench7.annotations.Atomic; -import stmbench7.annotations.ReadOnly; -import stmbench7.annotations.Update; - -/** - * Part of the main benchmark data structure. For a default - * implementation, see stmbench7.impl.core.DocumentImpl. - */ -@Atomic -public interface Document { - - @Update - void setPart(CompositePart part); - - @ReadOnly - CompositePart getCompositePart(); - - @ReadOnly - int getDocumentId(); - - @ReadOnly - String getTitle(); - - @ReadOnly - void nullOperation(); - - @ReadOnly - int searchText(char symbol); - - @Update - int replaceText(String from, String to); - - @ReadOnly - boolean textBeginsWith(String prefix); - - @ReadOnly - String getText(); -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/DocumentBuilder.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/DocumentBuilder.java deleted file mode 100644 index 6c815a8e..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/DocumentBuilder.java +++ /dev/null @@ -1,42 +0,0 @@ -package stmbench7.core; - -import stmbench7.Parameters; -import stmbench7.annotations.Immutable; -import stmbench7.backend.BackendFactory; -import stmbench7.backend.IdPool; -import stmbench7.backend.Index; - -/** - * Used to create and destroy document elements while - * maintaining the consistency of the data structure - * and the indexes. - */ -@Immutable -public class DocumentBuilder extends DesignObjBuilder { - - private final IdPool idPool; - private final Index documentTitleIndex; - - public DocumentBuilder(Index documentTitleIndex) { - this.documentTitleIndex = documentTitleIndex; - idPool = BackendFactory.instance.createIdPool(Parameters.MaxCompParts); - } - - public Document createAndRegisterDocument(int compositePartId) throws OperationFailedException { - int docId = idPool.getId(); - String docTitle = "Composite Part #" + compositePartId; - String docText = createText(Parameters.DocumentSize, - "I am the documentation for composite part #" + compositePartId + "\n"); - - Document documentation = designObjFactory.createDocument(docId, docTitle, docText); - documentTitleIndex.put(docTitle, documentation); - - return documentation; - } - - public void unregisterAndRecycleDocument(Document document) { - document.setPart(null); - documentTitleIndex.remove(document.getTitle()); - idPool.putUnusedId(document.getDocumentId()); - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/Manual.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/Manual.java deleted file mode 100644 index ef6e9fac..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/Manual.java +++ /dev/null @@ -1,40 +0,0 @@ -package stmbench7.core; - -import stmbench7.annotations.Atomic; -import stmbench7.annotations.ReadOnly; -import stmbench7.annotations.Update; - -/** - * Part of the main benchmark data structure. For a default - * implementation, see stmbench7.impl.core.ManualImpl. - */ -@Atomic -public interface Manual { - - @ReadOnly - int getId(); - - @ReadOnly - String getTitle(); - - @ReadOnly - String getText(); - - @ReadOnly - Module getModule(); - - @Update - void setModule(Module module); - - @ReadOnly - int countOccurences(char ch); - - @ReadOnly - int checkFirstLastCharTheSame(); - - @ReadOnly - boolean startsWith(char ch); - - @Update - int replaceChar(char from, char to); -} \ No newline at end of file diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/ManualBuilder.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/ManualBuilder.java deleted file mode 100644 index 897d946f..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/ManualBuilder.java +++ /dev/null @@ -1,28 +0,0 @@ -package stmbench7.core; - -import stmbench7.Parameters; -import stmbench7.annotations.Immutable; -import stmbench7.backend.BackendFactory; -import stmbench7.backend.IdPool; - -/** - * Used to create a manual element that conforms to the - * benchmark specification. - */ -@Immutable -public class ManualBuilder extends DesignObjBuilder { - - private final IdPool idPool; - - public ManualBuilder() { - idPool = BackendFactory.instance.createIdPool(Parameters.NumModules); - } - - public Manual createManual(int moduleId) throws OperationFailedException { - int manualId = idPool.getId(); - String title = "Manual for module #" + moduleId; - String text = createText(Parameters.ManualSize, "I am the manual for module #" + moduleId + "\n"); - - return designObjFactory.createManual(manualId, title, text); - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/Module.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/Module.java deleted file mode 100644 index 9d4212b4..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/Module.java +++ /dev/null @@ -1,22 +0,0 @@ -package stmbench7.core; - -import stmbench7.annotations.Atomic; -import stmbench7.annotations.ReadOnly; -import stmbench7.annotations.Update; - -/** - * Root of the benchmark main data structure. For a default - * implementation, see stmbench7.impl.core.ModuleImpl. - */ -@Atomic -public interface Module extends DesignObj { - - @Update - void setDesignRoot(ComplexAssembly designRoot); - - @ReadOnly - ComplexAssembly getDesignRoot(); - - @ReadOnly - Manual getManual(); -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/ModuleBuilder.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/ModuleBuilder.java deleted file mode 100644 index d858b016..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/ModuleBuilder.java +++ /dev/null @@ -1,46 +0,0 @@ -package stmbench7.core; - -import stmbench7.Parameters; -import stmbench7.annotations.Immutable; -import stmbench7.backend.BackendFactory; -import stmbench7.backend.IdPool; -import stmbench7.backend.Index; - -/** - * Used to create a module element with the default initial - * data structure underneath. Calls other builder classes - * to construct respective elements of the structure. - */ -@Immutable -public class ModuleBuilder extends DesignObjBuilder { - - private final IdPool idPool; - private final ManualBuilder manualFactory; - private final AssemblyBuilder assemblyBuilder; - - public ModuleBuilder(Index baseAssemblyIdIndex, - Index complexAssemblyIdIndex) { - manualFactory = new ManualBuilder(); - assemblyBuilder = new AssemblyBuilder(baseAssemblyIdIndex, - complexAssemblyIdIndex); - idPool = BackendFactory.instance.createIdPool(Parameters.NumModules); - } - - public Module createRegisterModule() throws OperationFailedException { - int moduleId = idPool.getId(); - Manual manual = manualFactory.createManual(moduleId); - String type = createType(); - int buildDate = createBuildDate(Parameters.MinModuleDate, Parameters.MaxModuleDate); - - Module module = designObjFactory.createModule(moduleId, type, buildDate, manual); - - ComplexAssembly designRoot = (ComplexAssembly) assemblyBuilder.createAndRegisterAssembly(module, null); - module.setDesignRoot(designRoot); - - return module; - } - - public AssemblyBuilder getAssemblyBuilder() { - return assemblyBuilder; - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/Operation.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/Operation.java deleted file mode 100644 index 4f5a6ddb..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/Operation.java +++ /dev/null @@ -1,23 +0,0 @@ -package stmbench7.core; - -import stmbench7.OperationId; -import stmbench7.annotations.ReadOnly; -import stmbench7.annotations.ThreadLocal; -import stmbench7.annotations.Transactional; - -/** - * Interface of a single operation (query, traversal - * or structural modification) of the STMBench7 benchmark. - * Each operation is instantiated separately by each - * thread, so the fields in a class implementing Operation - * can be considered thread-local. - */ -@ThreadLocal -public interface Operation { - - @Transactional - public int performOperation() throws OperationFailedException; - - @ReadOnly - public OperationId getOperationId(); -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/OperationFailedException.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/OperationFailedException.java deleted file mode 100644 index 0bd230da..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/OperationFailedException.java +++ /dev/null @@ -1,31 +0,0 @@ -package stmbench7.core; - -import stmbench7.annotations.Immutable; -import stmbench7.annotations.ThreadLocal; - -/** - * STMBench7 benchmark specific exception. Indicates that a benchmark operation - * failed. Note that operation failures are unavoidable in the benchmark: their - * number is indicated in the results shown at the end of the benchmark. - */ -@Immutable -@ThreadLocal -public class OperationFailedException extends Exception { - - private static final long serialVersionUID = -4829600105999291994L; - - public OperationFailedException(String message, Object reportingObject) { - super(message + " [" + reportingObject.toString() + "]"); - } - - public OperationFailedException(String message) { - super(message); - } - - public OperationFailedException(String message, Throwable cause) { - super(message, cause); - } - - public OperationFailedException() { - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/RuntimeError.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/RuntimeError.java deleted file mode 100644 index 7a1c89f8..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/RuntimeError.java +++ /dev/null @@ -1,31 +0,0 @@ -package stmbench7.core; - -import stmbench7.annotations.Immutable; -import stmbench7.annotations.ThreadLocal; - -/** - * STMBench7 specific error. Indicates a serious problem, i.e., a violation of - * the data structure invariants, which causes the benchmark to terminate. - */ -@Immutable -@ThreadLocal -public class RuntimeError extends Error { - - private static final long serialVersionUID = -5671909838938354776L; - - public RuntimeError() { - } - - public RuntimeError(String message) { - super(message); - } - - public RuntimeError(Throwable cause) { - super(cause); - } - - public RuntimeError(String message, Throwable cause) { - super(message, cause); - } - -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/correctness/invariants/AssemblyTest.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/correctness/invariants/AssemblyTest.java deleted file mode 100644 index 3a1482e4..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/correctness/invariants/AssemblyTest.java +++ /dev/null @@ -1,31 +0,0 @@ -package stmbench7.correctness.invariants; - -import stmbench7.Parameters; -import stmbench7.annotations.Immutable; -import stmbench7.annotations.ThreadLocal; -import stmbench7.core.Assembly; -import stmbench7.core.ComplexAssembly; -import stmbench7.core.Module; - -/** - * Test of invariants of an assembly. - */ -@Immutable -@ThreadLocal -public class AssemblyTest extends InvariantTest { - - public static void checkInvariants(Assembly assembly, boolean initial, int maxId, - ComplexAssembly parentAssembly, Module module) { - - DesignObjTest.checkInvariants(assembly, initial, maxId, Parameters.MinAssmDate, Parameters.MaxAssmDate); - - int id = assembly.getId(); - - if(assembly.getSuperAssembly() != parentAssembly) - reportError(assembly, id, "invalid reference to the parent ComplexAssembly"); - - if(assembly.getModule() != module) - reportError(assembly, id, "invalid reference to the parent Module"); - } - -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/correctness/invariants/AtomicPartTest.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/correctness/invariants/AtomicPartTest.java deleted file mode 100644 index 0173cd85..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/correctness/invariants/AtomicPartTest.java +++ /dev/null @@ -1,59 +0,0 @@ -package stmbench7.correctness.invariants; - -import java.util.TreeSet; - -import stmbench7.Parameters; -import stmbench7.annotations.Immutable; -import stmbench7.annotations.ThreadLocal; -import stmbench7.backend.ImmutableCollection; -import stmbench7.core.AtomicPart; -import stmbench7.core.CompositePart; -import stmbench7.core.Connection; - -/** - * Test of invariants of an atomic part. - */ -@Immutable -@ThreadLocal -public class AtomicPartTest extends InvariantTest { - - public static void checkInvariants(AtomicPart part, boolean initial, CompositePart component, - TreeSet allParts, TraversedObjects traversedObjects) { - - traversedObjects.atomicParts.add(part); - - DesignObjTest.checkInvariants(part, initial, Parameters.MaxAtomicParts, - Parameters.MinAtomicDate, Parameters.MaxAtomicDate); - - int id = part.getId(), x = part.getX(), y = part.getY(); - if(Math.abs(x - y) != 1) - reportError(part, id, "inconsistent x and y attributes: x = " + x + ", y = " + y); - - if(part.getPartOf() != component) - reportError(part, id, "invalid reference to CompositePart parent"); - - ImmutableCollection to = part.getToConnections(), from = part.getFromConnections(); - if(to.size() != Parameters.NumConnPerAtomic) - reportError(part, id, "to", Parameters.NumConnPerAtomic, to.size()); - - for(Connection connection : from) { - ConnectionTest.checkInvariants(connection, part); - - ImmutableCollection sourceToSet = connection.getSource().getToConnections(); - boolean foundMyself = false; - for(Connection outConn : sourceToSet) - if(outConn.getSource() == part) { - foundMyself = true; - break; - } - if(! foundMyself) - reportError(part, id, "inconsistent 'from' set"); - } - - for(Connection connection : to) { - ConnectionTest.checkInvariants(connection, part); - - allParts.add(connection.getDestination()); - } - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/correctness/invariants/BaseAssemblyTest.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/correctness/invariants/BaseAssemblyTest.java deleted file mode 100644 index 850f595d..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/correctness/invariants/BaseAssemblyTest.java +++ /dev/null @@ -1,28 +0,0 @@ -package stmbench7.correctness.invariants; - -import stmbench7.Parameters; -import stmbench7.annotations.Immutable; -import stmbench7.annotations.ThreadLocal; -import stmbench7.core.BaseAssembly; -import stmbench7.core.ComplexAssembly; -import stmbench7.core.CompositePart; -import stmbench7.core.Module; - -/** - * Test of invariants of a base assembly. - */ -@Immutable -@ThreadLocal -public class BaseAssemblyTest extends InvariantTest { - - public static void checkInvariants(BaseAssembly assembly, boolean initial, - ComplexAssembly parentAssembly, Module module, TraversedObjects traversedObjects) { - - traversedObjects.baseAssemblies.add(assembly); - - AssemblyTest.checkInvariants(assembly, initial, Parameters.MaxBaseAssemblies, parentAssembly, module); - - for(CompositePart component : assembly.getComponents()) - CompositePartTest.checkInvariants(component, initial, assembly, traversedObjects); - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/correctness/invariants/CheckInvariantsOperation.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/correctness/invariants/CheckInvariantsOperation.java deleted file mode 100644 index 02b48f5f..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/correctness/invariants/CheckInvariantsOperation.java +++ /dev/null @@ -1,42 +0,0 @@ -package stmbench7.correctness.invariants; - -import stmbench7.OperationId; -import stmbench7.Setup; -import stmbench7.annotations.Immutable; -import stmbench7.annotations.ReadOnly; -import stmbench7.annotations.ThreadLocal; -import stmbench7.core.Operation; -import stmbench7.core.OperationFailedException; - -/** - * Performs the check of data structure invariants. The operation is always - * performed in a single thread, without any concurrency, and so it does not - * have to be thread-safe. However, it is executed by an OperationExecutor, as - * any other operation. - */ -@Immutable -@ThreadLocal -public class CheckInvariantsOperation implements Operation { - - private final Setup setup; - private final boolean initial; - - public CheckInvariantsOperation(Setup setup, boolean initial) { - this.setup = setup; - this.initial = initial; - } - - @ReadOnly - public int performOperation() throws OperationFailedException { - TraversedObjects traversedObjects = new TraversedObjects(); - ModuleTest.checkInvariants(setup.getModule(), initial, traversedObjects); - System.err.println("\nChecking indexes..."); - IndexTest.checkInvariants(setup, initial, traversedObjects); - System.err.println("\nInvariants OK."); - return 0; - } - - public OperationId getOperationId() { - return null; - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/correctness/invariants/ComplexAssemblyTest.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/correctness/invariants/ComplexAssemblyTest.java deleted file mode 100644 index ce172870..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/correctness/invariants/ComplexAssemblyTest.java +++ /dev/null @@ -1,44 +0,0 @@ -package stmbench7.correctness.invariants; - -import stmbench7.Parameters; -import stmbench7.annotations.Immutable; -import stmbench7.annotations.ThreadLocal; -import stmbench7.core.Assembly; -import stmbench7.core.BaseAssembly; -import stmbench7.core.ComplexAssembly; -import stmbench7.core.Module; - -/** - * Test of invariants of a complex assembly. - */ -@Immutable -@ThreadLocal -public class ComplexAssemblyTest extends InvariantTest { - - public static void checkInvariants(ComplexAssembly assembly, boolean initial, ComplexAssembly parentAssembly, - Module module, TraversedObjects traversedObjects) { - - traversedObjects.complexAssemblies.add(assembly); - - AssemblyTest.checkInvariants(assembly, initial, Parameters.MaxComplexAssemblies, parentAssembly, module); - - int id = assembly.getId(), level = assembly.getLevel(); - if(level <= 1 || level > Parameters.NumAssmLevels) - reportError(assembly, id, "level", 1, Parameters.NumAssmLevels, level); - - for(Assembly subAssembly : assembly.getSubAssemblies()) { - if(level > 2) { - if(! (subAssembly instanceof ComplexAssembly)) - reportError(assembly, id, "subAssembly not of type ComplexAssembly at level = " + level); - ComplexAssemblyTest.checkInvariants((ComplexAssembly)subAssembly, initial, assembly, module, traversedObjects); - } - else { - if(! (subAssembly instanceof BaseAssembly)) - reportError(assembly, id, "subAssembly not of type BaseAssembly at level = 2"); - BaseAssemblyTest.checkInvariants((BaseAssembly)subAssembly, initial, assembly, module, traversedObjects); - } - } - - } - -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/correctness/invariants/CompositePartTest.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/correctness/invariants/CompositePartTest.java deleted file mode 100644 index dcb5fe5d..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/correctness/invariants/CompositePartTest.java +++ /dev/null @@ -1,65 +0,0 @@ -package stmbench7.correctness.invariants; - -import java.util.TreeSet; - -import stmbench7.Parameters; -import stmbench7.annotations.Immutable; -import stmbench7.annotations.ThreadLocal; -import stmbench7.backend.ImmutableCollection; -import stmbench7.backend.LargeSet; -import stmbench7.core.AtomicPart; -import stmbench7.core.BaseAssembly; -import stmbench7.core.CompositePart; - -/** - * Test of invariants of a composite part. - */ -@Immutable -@ThreadLocal -public class CompositePartTest extends InvariantTest { - - public static void checkInvariants(CompositePart component, boolean initial, BaseAssembly aParent, - TraversedObjects traversedObjects) { - - traversedObjects.components.add(component); - - System.err.print("Component " + traversedObjects.components.size() + "\r"); - - DesignObjTest.checkInvariants(component, initial, Parameters.MaxCompParts, 0, Integer.MAX_VALUE - 1); - - int id = component.getId(), buildDate = component.getBuildDate(); - int minOldDate = Parameters.MinOldCompDate, maxOldDate = Parameters.MaxOldCompDate, - minYoungDate = Parameters.MinYoungCompDate, maxYoungDate = Parameters.MaxYoungCompDate; - if(! initial) { - if(minOldDate % 2 == 0) minOldDate--; - if(maxOldDate % 2 != 0) maxOldDate++; - if(minYoungDate % 2 == 0) minYoungDate--; - if(maxYoungDate % 2 != 0) maxYoungDate++; - } - if( (buildDate < minOldDate|| buildDate > maxOldDate) && - (buildDate < minYoungDate || buildDate > maxYoungDate) ) - reportError(component, id, "wrong buildDate (" + buildDate + ")"); - - ImmutableCollection usedIn = component.getUsedIn(); - if(aParent != null && !usedIn.contains(aParent)) - reportError(component, id, "a BaseAssembly parent not in set usedIn"); - - for(BaseAssembly assembly : usedIn) { - if(! assembly.getComponents().contains(component)) - reportError(assembly, assembly.getId(), "a child CompositePart not in set of components"); - } - - DocumentationTest.checkInvariants(component.getDocumentation(), component, traversedObjects); - - LargeSet parts = component.getParts(); - if(! parts.contains(component.getRootPart())) - reportError(component, id, "rootPart not in set of parts"); - - TreeSet allConnectedParts = new TreeSet(); - for(AtomicPart part : parts) - AtomicPartTest.checkInvariants(part, initial, component, allConnectedParts, traversedObjects); - - for(AtomicPart part : allConnectedParts) - if(! parts.contains(part)) reportError(component, id, "a graph-connected AtomicPart not in set of all parts"); - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/correctness/invariants/ConnectionTest.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/correctness/invariants/ConnectionTest.java deleted file mode 100644 index e16da58c..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/correctness/invariants/ConnectionTest.java +++ /dev/null @@ -1,28 +0,0 @@ -package stmbench7.correctness.invariants; - -import stmbench7.Parameters; -import stmbench7.annotations.Immutable; -import stmbench7.annotations.ThreadLocal; -import stmbench7.core.AtomicPart; -import stmbench7.core.Connection; - -/** - * Test of invariants of a connection. - */ -@Immutable -@ThreadLocal -public class ConnectionTest extends InvariantTest { - - public static void checkInvariants(Connection connection, AtomicPart from) { - - if(! DesignObjTest.checkType(connection.getType())) - reportError(connection, 0, "type", "type #...", connection.getType()); - - int length = connection.getLength(); - if(length < 1 || length > Parameters.XYRange) - reportError(connection, 0, "length", 1, Parameters.XYRange, length); - - if(connection.getSource() != from) - reportError(connection, 0, "invalid source (from) reference"); - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/correctness/invariants/DesignObjTest.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/correctness/invariants/DesignObjTest.java deleted file mode 100644 index e6024322..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/correctness/invariants/DesignObjTest.java +++ /dev/null @@ -1,45 +0,0 @@ -package stmbench7.correctness.invariants; - -import stmbench7.Parameters; -import stmbench7.annotations.Immutable; -import stmbench7.annotations.ThreadLocal; -import stmbench7.core.DesignObj; - -/** - * Test of common invariants of elements inherited from a design object. - */ -@Immutable -@ThreadLocal -public class DesignObjTest extends InvariantTest { - - public static void checkInvariants(DesignObj obj, boolean initial, int maxId, int minBuildDate, int maxBuildDate) { - int id = obj.getId(); - if(id < 1 || id > maxId) reportError(obj, id, "id", 1, maxId, id); - - String type = obj.getType(); - if(! checkType(type)) reportError(obj, id, "type", "type #(num)", type); - - int buildDate = obj.getBuildDate(); - if(! initial) { - if(minBuildDate % 2 == 0) minBuildDate--; - if(maxBuildDate % 2 != 0) maxBuildDate++; - } - if(buildDate < minBuildDate || buildDate > maxBuildDate) - reportError(obj, id, "buildDate", minBuildDate, maxBuildDate, buildDate); - } - - protected static boolean checkType(String type) { - if(! type.startsWith("type #")) return false; - - try { - int typeNum = Integer.parseInt(type.substring("type #".length())); - if(typeNum < 0 || typeNum >= Parameters.NumTypes) return false; - - } - catch(NumberFormatException e) { - return false; - } - - return true; - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/correctness/invariants/DocumentationTest.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/correctness/invariants/DocumentationTest.java deleted file mode 100644 index 68184abb..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/correctness/invariants/DocumentationTest.java +++ /dev/null @@ -1,39 +0,0 @@ -package stmbench7.correctness.invariants; - -import stmbench7.Parameters; -import stmbench7.annotations.Immutable; -import stmbench7.annotations.ThreadLocal; -import stmbench7.core.CompositePart; -import stmbench7.core.Document; - -/** - * Test of invariants of a documentation element. - */ -@Immutable -@ThreadLocal -public class DocumentationTest extends InvariantTest { - - public static void checkInvariants(Document documentation, - CompositePart component, TraversedObjects traversedObjects) { - - traversedObjects.documents.add(documentation); - - int id = documentation.getDocumentId(); - if(id < 1 || id > Parameters.MaxCompParts) - reportError(documentation, id, "id", 1, Parameters.MaxCompParts, id); - - if(documentation.getCompositePart() != component) - reportError(documentation, id, "invalid reference to CompositePart parent"); - - String title = documentation.getTitle(), - titleShouldBe = "Composite Part #" + component.getId(); - if(! title.equals(titleShouldBe)) - reportError(documentation, id, "title", titleShouldBe, title); - - String text = documentation.getText(); - if(!text.startsWith("I am the documentation for composite part #" + component.getId()) && - !text.startsWith("This is the documentation for composite part #" + component.getId()) ) - reportError(documentation, id, "text (prefix)", "I am / This is the documentation for composite part #...", - text.substring(0, 30)); - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/correctness/invariants/IndexTest.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/correctness/invariants/IndexTest.java deleted file mode 100644 index 1d9319c3..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/correctness/invariants/IndexTest.java +++ /dev/null @@ -1,121 +0,0 @@ -package stmbench7.correctness.invariants; - -import java.util.HashSet; - -import stmbench7.Setup; -import stmbench7.annotations.Immutable; -import stmbench7.annotations.ThreadLocal; -import stmbench7.backend.Index; -import stmbench7.backend.LargeSet; -import stmbench7.core.AtomicPart; -import stmbench7.core.BaseAssembly; -import stmbench7.core.ComplexAssembly; -import stmbench7.core.CompositePart; -import stmbench7.core.Document; -import stmbench7.core.RuntimeError; - -/** - * Test of invariants of indexes, and their consistency - * with the main data structure. Checks also invariants - * of the composite parts that are not reachable from - * base assemblies. - */ -@Immutable -@ThreadLocal -public class IndexTest extends InvariantTest { - - public static void checkInvariants(Setup setup, boolean initial, TraversedObjects traversedObjects) { - - // Complex assemblies - Index complexAssemblyIdIndex = setup.getComplexAssemblyIdIndex(); - for(ComplexAssembly traversedAssembly : traversedObjects.complexAssemblies) { - int id = traversedAssembly.getId(); - ComplexAssembly indexedAssembly = complexAssemblyIdIndex.get(id); - checkIndexValue("ComplexAssembly.id", traversedAssembly, indexedAssembly, id); - } - checkAllTraversed(complexAssemblyIdIndex, traversedObjects.complexAssemblies, "ComplexAssembly.id"); - traversedObjects.complexAssemblies.clear(); - - // Base assemblies - Index baseAssemblyIdIndex = setup.getBaseAssemblyIdIndex(); - for(BaseAssembly traversedAssembly : traversedObjects.baseAssemblies) { - int id = traversedAssembly.getId(); - BaseAssembly indexedAssembly = baseAssemblyIdIndex.get(id); - checkIndexValue("BaseAssembly.id", traversedAssembly, indexedAssembly, id); - } - checkAllTraversed(baseAssemblyIdIndex, traversedObjects.baseAssemblies, "BaseAssembly.id"); - traversedObjects.baseAssemblies.clear(); - - // Composite parts - Index compositePartIdIndex = setup.getCompositePartIdIndex(); - for(CompositePart traversedComponent : traversedObjects.components) { - int id = traversedComponent.getId(); - CompositePart indexedComponent = compositePartIdIndex.get(id); - checkIndexValue("CompositePart.id", traversedComponent, indexedComponent, id); - } - - // Check invariants for components disconnected from the data structure - // (and add those components to the set of traversed objects) - for(CompositePart indexedComponent : compositePartIdIndex) - if(! traversedObjects.components.contains(indexedComponent)) - CompositePartTest.checkInvariants(indexedComponent, initial, null, traversedObjects); - traversedObjects.components.clear(); - - // Documents - Index documentTitleIndex = setup.getDocumentTitleIndex(); - for(Document traversedDocument : traversedObjects.documents) { - String title = traversedDocument.getTitle(); - int id = traversedDocument.getDocumentId(); - - Document indexedDocument = documentTitleIndex.get(title); - checkIndexValue("Document.title", traversedDocument, indexedDocument, id); - } - checkAllTraversed(documentTitleIndex, traversedObjects.documents, "Document.title"); - traversedObjects.documents.clear(); - - // Atomic parts (id index) - Index atomicPartIdIndex = setup.getAtomicPartIdIndex(); - for(AtomicPart traversedPart : traversedObjects.atomicParts) { - int id = traversedPart.getId(); - - AtomicPart indexedPart = atomicPartIdIndex.get(id); - checkIndexValue("AtomicPart.id", traversedPart, indexedPart, id); - } - checkAllTraversed(atomicPartIdIndex, traversedObjects.atomicParts, "AtomicPart.id"); - - // Atomic parts (buildDate index) - Index> atomicPartBuildDateIndex = setup.getAtomicPartBuildDateIndex(); - for(AtomicPart traversedPart : traversedObjects.atomicParts) { - int id = traversedPart.getId(); - LargeSet sameBuildDateParts = - atomicPartBuildDateIndex.get(traversedPart.getBuildDate()); - if(sameBuildDateParts == null || !sameBuildDateParts.contains(traversedPart)) - reportError("AtomicPart.buildDate", "element with id = " + id + " not in the index"); - } - - for(LargeSet sameBuildDateParts : atomicPartBuildDateIndex) - for(AtomicPart indexedPart : sameBuildDateParts) - if(! traversedObjects.atomicParts.contains(indexedPart)) - reportError("AtomicPart.buildDate", "index contains too many elements"); - traversedObjects.atomicParts.clear(); - } - - private static void reportError(String index, String message) { - throw new RuntimeError("Index " + index + ": " + message); - } - - private static void checkIndexValue(String index, Object traversedObject, Object indexedObject, int elementId) { - if(indexedObject == null) - reportError(index, "element with id = " + elementId + - " in the data structure but not in the index"); - if(indexedObject != traversedObject) - reportError(index, "element with id = " + elementId + - " is a different object in the index and in the data structure"); - } - - private static void checkAllTraversed(Index index, HashSet traversedSet, String indexName) { - for(Object indexedObject : index) - if(! traversedSet.contains(indexedObject)) - reportError(indexName, "index contains too many elements (element " + indexedObject.toString() + ")"); - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/correctness/invariants/InvariantTest.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/correctness/invariants/InvariantTest.java deleted file mode 100644 index 48865d65..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/correctness/invariants/InvariantTest.java +++ /dev/null @@ -1,35 +0,0 @@ -package stmbench7.correctness.invariants; - -import stmbench7.annotations.Immutable; -import stmbench7.annotations.ThreadLocal; -import stmbench7.core.RuntimeError; - -/** - * Helper methods for all invariant tests. - */ -@Immutable -@ThreadLocal -public class InvariantTest { - - protected static void reportError(Object obj, int id, String message) { - String withId = ""; - if(id > 0) withId = " with id = " + id; - throw new RuntimeError("Invariant violated! Object " + obj.getClass().getName() + - withId + ": " + message); - } - - protected static void reportError(Object obj, int id, String attribute, int expected, int found) { - reportError(obj, id, "attribute " + attribute + - " --> expected value = " + expected + ", found = " + found); - } - - protected static void reportError(Object obj, int id, String attribute, int expectedMin, int expectedMax, int found) { - reportError(obj, id, "attribute " + attribute + - " --> expected value in [" + expectedMin + "," + expectedMax + "], found = " + found); - } - - protected static void reportError(Object obj, int id, String attribute, String expected, String found) { - reportError(obj, id, "attribute " + attribute + - " --> expected value = " + expected + ", found = " + found); - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/correctness/invariants/ManualTest.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/correctness/invariants/ManualTest.java deleted file mode 100644 index d2431455..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/correctness/invariants/ManualTest.java +++ /dev/null @@ -1,36 +0,0 @@ -package stmbench7.correctness.invariants; - -import stmbench7.annotations.Immutable; -import stmbench7.annotations.ThreadLocal; -import stmbench7.core.Manual; -import stmbench7.core.Module; - -/** - * Test of invariants of a manual. - */ -@Immutable -@ThreadLocal -public class ManualTest extends InvariantTest { - - public static void checkInvariants(Manual manual, Module module) { - int id = manual.getId(); - if(id != 1) reportError(manual, id, "id", 1, id); - - String title = manual.getTitle(), - titleShouldBe = "Manual for module #1"; - if(! title.equals(titleShouldBe)) - reportError(manual, id, "title", titleShouldBe, title); - - if(!manual.startsWith('I') && !manual.startsWith('i')) - reportError(manual, id, "text (prefix)", "'I' || 'i'", manual.getText().substring(0, 7) + " ..."); - - if(manual.startsWith('I') && manual.countOccurences('i') > 0) - reportError(manual, id, "text starts from 'I' but contains 'i'"); - - if(manual.startsWith('i') && manual.countOccurences('I') > 0) - reportError(manual, id, "text starts from 'i' but contains 'I'"); - - if(manual.getModule() != module) - reportError(manual, id, "invalid connection to Module"); - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/correctness/invariants/ModuleTest.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/correctness/invariants/ModuleTest.java deleted file mode 100644 index 5ead807d..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/correctness/invariants/ModuleTest.java +++ /dev/null @@ -1,30 +0,0 @@ -package stmbench7.correctness.invariants; - -import stmbench7.Parameters; -import stmbench7.annotations.Immutable; -import stmbench7.annotations.ThreadLocal; -import stmbench7.core.ComplexAssembly; -import stmbench7.core.Manual; -import stmbench7.core.Module; - -/** - * Test of invariants of the module. Starts a recursive - * invariant check down the whole data structure. - */ -@Immutable -@ThreadLocal -public class ModuleTest extends InvariantTest { - - public static void checkInvariants(Module module, boolean initial, TraversedObjects traversedObjects) { - DesignObjTest.checkInvariants(module, initial, 1, Parameters.MinModuleDate, Parameters.MaxModuleDate); - - int id = module.getId(); - Manual manual = module.getManual(); - if(manual == null) reportError(module, id, "Null manual in a module"); - ManualTest.checkInvariants(manual, module); - - ComplexAssembly rootAssembly = module.getDesignRoot(); - if(rootAssembly == null) reportError(module, id, "Null root assembly"); - ComplexAssemblyTest.checkInvariants(rootAssembly, initial, null, module, traversedObjects); - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/correctness/invariants/TraversedObjects.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/correctness/invariants/TraversedObjects.java deleted file mode 100644 index 1a98542f..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/correctness/invariants/TraversedObjects.java +++ /dev/null @@ -1,34 +0,0 @@ -package stmbench7.correctness.invariants; - -import java.util.HashSet; - -import stmbench7.annotations.Immutable; -import stmbench7.annotations.ThreadLocal; -import stmbench7.core.AtomicPart; -import stmbench7.core.BaseAssembly; -import stmbench7.core.ComplexAssembly; -import stmbench7.core.CompositePart; -import stmbench7.core.Document; - -/** - * Stores the sets of objects traversed during an invariants - * check performed by the CheckInvariantsOperation class. - */ -@Immutable -@ThreadLocal -public class TraversedObjects { - - public final HashSet complexAssemblies; - public final HashSet baseAssemblies; - public final HashSet components; - public final HashSet documents; - public final HashSet atomicParts; - - public TraversedObjects() { - complexAssemblies = new HashSet(); - baseAssemblies = new HashSet(); - components = new HashSet(); - documents = new HashSet(); - atomicParts = new HashSet(); - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/correctness/opacity/SequentialReplayThread.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/correctness/opacity/SequentialReplayThread.java deleted file mode 100644 index 825e9717..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/correctness/opacity/SequentialReplayThread.java +++ /dev/null @@ -1,70 +0,0 @@ -package stmbench7.correctness.opacity; - -import java.util.ArrayList; - -import stmbench7.BenchThread; -import stmbench7.OperationId; -import stmbench7.OperationType; -import stmbench7.Setup; -import stmbench7.ThreadRandom; -import stmbench7.annotations.NonAtomic; -import stmbench7.core.OperationFailedException; -import stmbench7.core.RuntimeError; - -/** - * Replays sequentially a concurrent execution. Used to check - * whether a given concurrent execution ensures opacity, i.e., - * whether the synchronization method used in the execution - * was correctly synchronizing threads during this execution. - */ -@NonAtomic -public class SequentialReplayThread extends BenchThread { - - public SequentialReplayThread(Setup setup, double[] operationCDF, - ArrayList replayLog) { - super(setup, operationCDF); - this.replayLog = replayLog; - } - - public void run() { - int i = 0; - //for(ReplayLogEntry entry : replayLog) - // System.out.println(i++ + " @ " + OperationId.values()[entry.opNum] + " -- " + entry.timestamp); - i=0; - int opNum = 1, numOfOps = replayLog.size(); - for(ReplayLogEntry entry : replayLog) { - System.err.print("Operation " + (opNum++) + " out of " + numOfOps + "\r"); - short threadNum = entry.threadNum; - ThreadRandom.setVirtualThreadNumber(threadNum); - - //System.out.println(++i); - int operationNumber = getNextOperationNumber(); - - //System.out.println(entry.threadNum + " -- " + OperationId.values()[entry.opNum] + - // " / " + OperationId.values()[operationNumber]); - if(operationNumber != entry.opNum) - throw new RuntimeError("ThreadRandom skew"); - - int result = 0; - boolean failed = false; - - try { - ThreadRandom.saveState(); - result = operations[operationNumber].execute(); - } - catch(OperationFailedException e) { - failed = true; - ThreadRandom.restoreState(); - } - - if(result != entry.result || failed != entry.failed) { - String opName = OperationId.values()[operationNumber].toString(); - throw new RuntimeError("Different operation result in the sequential execution (" + - "operation " + opName + "): " + - "Sequential: result = " + result + ", failed = " + failed + ". " + - "Concurrent: result = " + entry.result + ", failed = " + entry.failed + "."); - } - } - System.err.println(); - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/correctness/opacity/StructureComparisonOperation.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/correctness/opacity/StructureComparisonOperation.java deleted file mode 100644 index 34ca87c1..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/correctness/opacity/StructureComparisonOperation.java +++ /dev/null @@ -1,336 +0,0 @@ -package stmbench7.correctness.opacity; - -import java.util.HashSet; -import java.util.Iterator; - -import stmbench7.OperationId; -import stmbench7.Setup; -import stmbench7.annotations.Immutable; -import stmbench7.annotations.ThreadLocal; -import stmbench7.backend.ImmutableCollection; -import stmbench7.backend.Index; -import stmbench7.backend.LargeSet; -import stmbench7.core.Assembly; -import stmbench7.core.AtomicPart; -import stmbench7.core.BaseAssembly; -import stmbench7.core.ComplexAssembly; -import stmbench7.core.CompositePart; -import stmbench7.core.Connection; -import stmbench7.core.DesignObj; -import stmbench7.core.Document; -import stmbench7.core.Manual; -import stmbench7.core.Module; -import stmbench7.core.Operation; -import stmbench7.core.RuntimeError; - -/** - * An operation that compares two benchmark data structures - * and throws a RuntimeError if they differ. Used to check - * whether a concurrent execution ensures opacity. - */ -@Immutable -@ThreadLocal -public class StructureComparisonOperation implements Operation { - - private final Setup setup1, setup2; - - public StructureComparisonOperation(Setup setup1, Setup setup2) { - this.setup1 = setup1; - this.setup2 = setup2; - } - - public int performOperation() { - checkModulesEqual(); - checkDesignLibrariesEqual(); - checkIndexesEqual(); - return 0; - } - - private void checkModulesEqual() { - Module module1 = setup1.getModule(), module2 = setup2.getModule(); - checkReferences(module1, module2, setup1, 0, setup2, 0, "module"); - checkDesignObjEqual(module1, module2); - - int id1 = module1.getId(), id2 = module2.getId(); - Manual man1 = module1.getManual(), man2 = module2.getManual(); - checkReferences(man1, man2, module1, id1, module2, id2, "manual"); - checkManualsEqual(man1, man2); - - ComplexAssembly root1 = module1.getDesignRoot(), root2 = module2.getDesignRoot(); - checkReferences(root1, root2, module1, id1, module2, id2, "designRoot"); - checkAssembliesEqual(root1, root2); - } - - private void checkDesignObjEqual(DesignObj obj1, DesignObj obj2) { - int id1 = obj1.getId(), id2 = obj2.getId(); - checkEqual(id1, id2, obj1, id1, obj2, id2, "id"); - checkEqual(obj1.getType(), obj2.getType(), obj1, id1, obj2, id2, "type"); - checkEqual(obj1.getBuildDate(), obj2.getBuildDate(), obj1, id1, obj2, id2, "buildDate"); - } - - private void checkManualsEqual(Manual man1, Manual man2) { - int id1 = man1.getId(), id2 = man2.getId(); - checkEqual(id1, id2, man1, id1, man2, id2, "id"); - checkEqual(man1.getTitle(), man2.getTitle(), man1, id1, man2, id2, "title"); - checkEqual(man1.getText(), man2.getText(), man1, id1, man2, id2, "text"); - checkReferences(man1.getModule(), man2.getModule(), man1, id1, man2, id2, "module"); - } - - private void checkAssembliesEqual(Assembly assembly1, Assembly assembly2) { - checkDesignObjEqual(assembly1, assembly2); - int id1 = assembly1.getId(), id2 = assembly2.getId(); - checkReferences(assembly1.getModule(), assembly2.getModule(), - assembly1, id1, assembly2, id2, "module"); - checkReferences(assembly1.getSuperAssembly(), assembly2.getSuperAssembly(), - assembly1, id1, assembly2, id2, "superAssembly"); - - if(! assembly1.getClass().equals(assembly2.getClass())) - - if(assembly1 instanceof ComplexAssembly) { - if(! (assembly2 instanceof ComplexAssembly)) - reportError(assembly1, id1, assembly2, id2, "objects of different classes"); - checkComplexAssembliesEqual((ComplexAssembly)assembly1, (ComplexAssembly)assembly2); - } - else { - if(! (assembly2 instanceof BaseAssembly)) - reportError(assembly1, id1, assembly2, id2, "objects of different classes"); - checkBaseAssembliesEqual((BaseAssembly)assembly1, (BaseAssembly)assembly2); - } - } - - private void checkComplexAssembliesEqual(ComplexAssembly assembly1, - ComplexAssembly assembly2) { - int id1 = assembly1.getId(), id2 = assembly2.getId(); - checkEqual(assembly1.getLevel(), assembly2.getLevel(), - assembly1, id1, assembly2, id2, "level"); - - ImmutableCollection subAss1 = assembly1.getSubAssemblies(), - subAss2 = assembly2.getSubAssemblies(); - checkEqual(subAss1.size(), subAss2.size(), - assembly1, id1, assembly2, id2, "subAssemblies.size()"); - - Iterator it1 = subAss1.iterator(), it2 = subAss2.iterator(); - while(it1.hasNext()) { - Assembly child1 = it1.next(), child2 = it2.next(); - checkReferences(child1, child2, assembly1, id1, assembly2, id2, "subAssemblies"); - checkAssembliesEqual(child1, child2); - } - } - - private void checkBaseAssembliesEqual(BaseAssembly assembly1, - BaseAssembly assembly2) { - int id1 = assembly1.getId(), id2 = assembly2.getId(); - ImmutableCollection comp1 = assembly1.getComponents(), - comp2 = assembly2.getComponents(); - checkEqual(comp1.size(), comp2.size(), - assembly1, id1, assembly2, id2, "components.size()"); - - Iterator it1 = comp1.iterator(), it2 = comp2.iterator(); - while(it1.hasNext()) { - CompositePart component1 = it1.next(), component2 = it2.next(); - checkReferences(component1, component2, - assembly1, id1, assembly2, id2, "components"); - checkEqual(component1.getId(), component2.getId(), - assembly1, id1, assembly2, id2, "components"); - } - } - - private void checkDesignLibrariesEqual() { - Index library1 = setup1.getCompositePartIdIndex(), - library2 = setup2.getCompositePartIdIndex(); - checkReferences(library1, library2, setup1, 0, setup2, 0, "CompositePart.id index"); - - Iterator it1 = library1.iterator(), it2 = library2.iterator(); - while(it1.hasNext()) { - if(! it2.hasNext()) - reportError(setup1, 0, setup2, 0, "CompositePart.id index size differences"); - - CompositePart component1 = it1.next(), component2 = it2.next(); - checkReferences(component1, component2, setup1, 0, setup2, 0, "CompositePart.id index"); - checkCompositePartsEqual(component1, component2); - } - } - - private void checkCompositePartsEqual(CompositePart component1, - CompositePart component2) { - checkDesignObjEqual(component1, component2); - - int id1 = component1.getId(), id2 = component2.getId(); - Document doc1 = component1.getDocumentation(), doc2 = component2.getDocumentation(); - checkReferences(doc1, doc2, component1, id1, component2, id2, "documentation"); - checkDocumentsEqual(doc1, doc2); - - ImmutableCollection usedIn1 = component1.getUsedIn(), - usedIn2 = component2.getUsedIn(); - checkEqual(usedIn1.size(), usedIn2.size(), - component1, id1, component2, id2, "usedIn.size()"); - - Iterator it1 = usedIn1.iterator(), it2 = usedIn2.iterator(); - while(it1.hasNext()) { - BaseAssembly assembly1 = it1.next(), assembly2 = it2.next(); - checkReferences(assembly1, assembly2, - component1, id1, component2, id2, "usedIn"); - checkEqual(assembly1.getId(), assembly2.getId(), - component1, id1, component2, id2, "usedIn"); - } - - AtomicPart root1 = component1.getRootPart(), root2 = component2.getRootPart(); - checkReferences(root1, root2, component1, id1, component2, id2, "rootPart"); - checkEqual(root1.getId(), root2.getId(), component1, id1, component2, id2, "rootPart"); - - LargeSet parts1 = component1.getParts(), - parts2 = component2.getParts(); - checkReferences(parts1, parts2, component1, id1, component2, id2, "parts"); - checkEqual(parts1.size(), parts2.size(), component1, id1, component2, id2, - "parts.size()"); - - Iterator partsIt1 = parts1.iterator(), partsIt2 = parts2.iterator(); - while(partsIt1.hasNext()) { - AtomicPart part1 = partsIt1.next(), part2 = partsIt2.next(); - checkReferences(part1, part2, component1, id1, component2, id2, "parts"); - checkAtomicPartsEqual(part1, part2); - } - } - - private void checkDocumentsEqual(Document doc1, Document doc2) { - int id1 = doc1.getDocumentId(), id2 = doc2.getDocumentId(); - checkEqual(id1, id2, doc1, id1, doc2, id2, "id"); - checkEqual(doc1.getTitle(), doc2.getTitle(), doc1, id1, doc2, id2, "title"); - checkEqual(doc1.getText(), doc2.getText(), doc1, id1, doc2, id2, "text"); - checkReferences(doc1.getCompositePart(), doc2.getCompositePart(), - doc1, id1, doc2, id2, "part"); - } - - private void checkAtomicPartsEqual(AtomicPart part1, AtomicPart part2) { - checkDesignObjEqual(part1, part2); - int id1 = part1.getId(), id2 = part2.getId(); - checkEqual(part1.getX(), part2.getX(), part1, id1, part2, id2, "x"); - checkEqual(part1.getY(), part2.getY(), part1, id1, part2, id2, "y"); - checkReferences(part1.getPartOf(), part2.getPartOf(), - part1, id1, part2, id2, "partOf"); - - ImmutableCollection to1 = part1.getToConnections(), - to2 = part2.getToConnections(); - checkEqual(to1.size(), to2.size(), part1, id1, part2, id2, "to.size()"); - Iterator toIt1 = to1.iterator(), toIt2 = to2.iterator(); - while(toIt1.hasNext()) { - Connection conn1 = toIt1.next(), conn2 = toIt2.next(); - checkReferences(conn1, conn2, part1, id1, part2, id2, "to"); - checkConnectionsEqual(conn1, conn2); - } - } - - private void checkConnectionsEqual(Connection conn1, Connection conn2) { - checkEqual(conn1.getType(), conn2.getType(), conn1, 0, conn2, 0, "type"); - checkEqual(conn1.getLength(), conn2.getLength(), conn1, 0, conn2, 0, "length"); - - AtomicPart src1 = conn1.getSource(), src2 = conn2.getSource(); - checkReferences(src1, src2, conn1, 0, conn2, 0, "from"); - checkEqual(src1.getId(), src2.getId(), conn1, 0, conn2, 0, "from"); - - AtomicPart dest1 = conn1.getDestination(), dest2 = conn2.getDestination(); - checkReferences(dest1, dest2, conn1, 0, conn2, 0, "to"); - checkEqual(dest1.getId(), dest2.getId(), conn1, 0, conn2, 0, "to"); - } - - private void checkIndexesEqual() { - Index atomicPartIdIndex1 = setup1.getAtomicPartIdIndex(), - atomicPartIdIndex2 = setup2.getAtomicPartIdIndex(); - checkEqual(atomicPartIdIndex1, atomicPartIdIndex2, "AtomicPart.id"); - - Index> atomicPartBuildDateIndex1 = setup1.getAtomicPartBuildDateIndex(), - atomicPartBuildDateIndex2 = setup2.getAtomicPartBuildDateIndex(); - checkEqual(atomicPartBuildDateIndex1, atomicPartBuildDateIndex2, "AtomicPart.buildDate"); - - Index documentTitleIndex1 = setup1.getDocumentTitleIndex(), - documentTitleIndex2 = setup2.getDocumentTitleIndex(); - checkEqual(documentTitleIndex1, documentTitleIndex2, "Document.title"); - - Index compositePartIdIndex1 = setup1.getCompositePartIdIndex(), - compositePartIdIndex2 = setup2.getCompositePartIdIndex(); - checkEqual(compositePartIdIndex1, compositePartIdIndex2, "CompositePart.id"); - - Index baseAssemblyIdIndex1 = setup1.getBaseAssemblyIdIndex(), - baseAssemblyIdIndex2 = setup2.getBaseAssemblyIdIndex(); - checkEqual(baseAssemblyIdIndex1, baseAssemblyIdIndex2, "BaseAssembly.id"); - - Index complexAssemblyIdIndex1 = setup1.getComplexAssemblyIdIndex(), - complexAssemblyIdIndex2 = setup2.getComplexAssemblyIdIndex(); - checkEqual(complexAssemblyIdIndex1, complexAssemblyIdIndex2, "ComplexAssembly.id"); - } - - @SuppressWarnings("unchecked") - private void checkEqual(Index index1, Index index2, String indexName) { - for(Object key1 : index1.getKeys()) { - Object val1 = index1.get((Comparable) key1); - Object val2 = index2.get((Comparable) key1); - if(val2 == null) - throw new RuntimeError("Indexes " + indexName + ": index2 does not contain key " + key1.toString()); - - if(val1 instanceof Iterable) { - checkEqual((Iterable)val1, (Iterable)val2, indexName + " at key " + key1.toString()); - continue; - } - - if(! val1.equals(val2)) - throw new RuntimeError("Indexes " + indexName + ": different values for key " + key1.toString() + - " --> [" + val1.toString() + "] != [" + val2.toString() + "]"); - } - for(Object key2 : index2.getKeys()) { - if(index1.get((Comparable) key2) == null) - throw new RuntimeError("Indexes " + indexName + ": different number of keys"); - } - } - - @SuppressWarnings("unchecked") - private void checkEqual(Iterable setIter1, Iterable setIter2, String setName) { - HashSet set1 = new HashSet(), set2 = new HashSet(); - for(Object obj : setIter1) set1.add(obj); - for(Object obj : setIter2) set2.add(obj); - - for(Object obj1 : setIter1) { - if(! set2.contains(obj1)) - throw new RuntimeError("Sets " + setName + ": element [" + obj1.toString() + "] not in set2"); - } - for(Object obj2 : setIter2) { - if(! set1.contains(obj2)) - throw new RuntimeError("Sets " + setName + ": element [" + obj2.toString() + "] not in set1"); - } - } - - private void reportError(Object obj1, int id1, Object obj2, int id2, - String message) { - throw new RuntimeError("Object " + obj1.toString() + " with id = " + id1 + - " != object " + obj2.toString() + " with id = " + id2 + - ": " + message); - } - - private void checkEqual(int val1, int val2, - Object obj1, int id1, Object obj2, int id2, String attribute) { - if(val1 != val2) - reportError(obj1, id1, obj2, id2, "attribute " + attribute + " --> " + - val1 + " != " + val2); - } - - private void checkEqual(String val1, String val2, - Object obj1, int id1, Object obj2, int id2, String attribute) { - if(! val1.equals(val2)) - reportError(obj1, id1, obj2, id2, "attribute " + attribute + " --> " + - val1 + " != " + val2); - } - - private void checkReferences(Object val1, Object val2, - Object obj1, int id1, Object obj2, int id2, String attribute) { - - if(val1 != null && val1 == val2) - reportError(obj1, id1, obj2, id2, "attribute " + attribute + " --> " + - "references equal"); - else if( (val1 == null && val2 != null) || (val1 != null && val2 == null) ) - reportError(obj1, id1, obj2, id2, "attribute " + attribute + " --> " + - "one (and only one) reference is null"); - } - - public OperationId getOperationId() { - return null; - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/DefaultOperationExecutor.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/DefaultOperationExecutor.java deleted file mode 100644 index 8c29b619..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/DefaultOperationExecutor.java +++ /dev/null @@ -1,30 +0,0 @@ -package stmbench7.impl; - -import stmbench7.OperationExecutor; -import stmbench7.core.Operation; -import stmbench7.core.OperationFailedException; - -/** - * Default implementation of an OperationExecutor. - * Does not provide any thread-safety. - */ -public class DefaultOperationExecutor implements OperationExecutor { - - private static int clock = 0; - - private final Operation op; - private int lastTimestamp = 0; - - public DefaultOperationExecutor(Operation op) { - this.op = op; - } - - public int execute() throws OperationFailedException { - lastTimestamp = clock++; - return op.performOperation(); - } - - public int getLastOperationTimestamp() { - return lastTimestamp; - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/DefaultOperationExecutorFactory.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/DefaultOperationExecutorFactory.java deleted file mode 100644 index b1ed3038..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/DefaultOperationExecutorFactory.java +++ /dev/null @@ -1,19 +0,0 @@ -package stmbench7.impl; - -import stmbench7.OperationExecutor; -import stmbench7.OperationExecutorFactory; -import stmbench7.annotations.Immutable; -import stmbench7.core.Operation; - -/** - * Default implementation of an OperationExecutorFactory. - * It creates an OperationExecutor that does not provide - * any synchronization between threads. - */ -@Immutable -public class DefaultOperationExecutorFactory extends OperationExecutorFactory { - - public OperationExecutor createOperationExecutor(Operation op) { - return new DefaultOperationExecutor(op); - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/DefaultThreadFactory.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/DefaultThreadFactory.java deleted file mode 100644 index ac40cb59..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/DefaultThreadFactory.java +++ /dev/null @@ -1,11 +0,0 @@ -package stmbench7.impl; - -import stmbench7.ThreadFactory; - -public class DefaultThreadFactory extends ThreadFactory { - - @Override - public Thread createThread(Runnable runnable) { - return new Thread(runnable); - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/NoSynchronizationInitializer.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/NoSynchronizationInitializer.java deleted file mode 100644 index 1c2ac0e8..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/NoSynchronizationInitializer.java +++ /dev/null @@ -1,34 +0,0 @@ -package stmbench7.impl; - -import stmbench7.OperationExecutorFactory; -import stmbench7.SynchMethodInitializer; -import stmbench7.ThreadFactory; -import stmbench7.annotations.Immutable; -import stmbench7.backend.BackendFactory; -import stmbench7.core.DesignObjFactory; -import stmbench7.impl.backend.BackendFactoryImpl; -import stmbench7.impl.core.DesignObjFactoryImpl; - -/** - * An initializer that provides non-thread-safe (default) - * factories. Should normally be used only with a single thread. - */ -@Immutable -public class NoSynchronizationInitializer implements SynchMethodInitializer { - - public BackendFactory createBackendFactory() { - return new BackendFactoryImpl(); - } - - public DesignObjFactory createDesignObjFactory() { - return new DesignObjFactoryImpl(); - } - - public OperationExecutorFactory createOperationExecutorFactory() { - return new DefaultOperationExecutorFactory(); - } - - public ThreadFactory createThreadFactory() { - return new DefaultThreadFactory(); - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/backend/BackendFactoryImpl.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/backend/BackendFactoryImpl.java deleted file mode 100644 index c55190bf..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/backend/BackendFactoryImpl.java +++ /dev/null @@ -1,30 +0,0 @@ -package stmbench7.impl.backend; - -import stmbench7.backend.BackendFactory; -import stmbench7.backend.IdPool; -import stmbench7.backend.Index; -import stmbench7.backend.LargeSet; - -/** - * Implements methods that create objects implementing - * interfaces defined in stmbench7.backend: Index, IdPool, - * and LargeSet. This default implementation constructs - * objects that are NOT thread-safe. - */ -public class BackendFactoryImpl extends BackendFactory { - - @Override - public > LargeSet createLargeSet() { - return new LargeSetImpl(); - } - - @Override - public , V> Index createIndex() { - return new TreeMapIndex(); - } - - @Override - public IdPool createIdPool(int maxNumberOfIds) { - return new IdPoolImpl(maxNumberOfIds); - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/backend/BagImpl.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/backend/BagImpl.java deleted file mode 100644 index 5818ca13..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/backend/BagImpl.java +++ /dev/null @@ -1,27 +0,0 @@ -package stmbench7.impl.backend; - -import java.util.ArrayList; - -import stmbench7.annotations.ContainedInAtomic; -import stmbench7.backend.ImmutableCollection; - -/** - * Simple implementation of a bag of objects. - */ -@ContainedInAtomic -public class BagImpl extends ArrayList { - - private static final long serialVersionUID = 5329072640119174542L; - - public BagImpl() { - super(); - } - - public BagImpl(BagImpl source) { - super(source); - } - - public ImmutableCollection immutableView() { - return new ImmutableViewImpl(this); - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/backend/IdPoolImpl.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/backend/IdPoolImpl.java deleted file mode 100644 index aedfcd5e..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/backend/IdPoolImpl.java +++ /dev/null @@ -1,52 +0,0 @@ -package stmbench7.impl.backend; - -import java.util.LinkedList; - -import stmbench7.annotations.Update; -import stmbench7.backend.IdPool; -import stmbench7.core.OperationFailedException; - -/** - * Used to generate ids of various elements. - * This default implementation is NOT thread-safe. - */ -public class IdPoolImpl implements IdPool, Cloneable { - - private final LinkedList idPool; - - public IdPoolImpl(int maxNumberOfIds) { - idPool = new LinkedList(); - for(int id = 1; id <= maxNumberOfIds; id++) { - idPool.offer(id); - } - } - - @Update - public int getId() throws OperationFailedException { - Integer id = idPool.poll(); - if(id == null) throw new OperationFailedException(); - - return id; - } - - @Update - public void putUnusedId(int id) { - idPool.offer(id); - } - - public String toString() { - String txt = "IdPool:"; - for(int id : idPool) txt += " " + id; - return txt; - } - - private IdPoolImpl(LinkedList idPool) { - this.idPool = idPool; - } - - @SuppressWarnings("unchecked") - @Override - public IdPoolImpl clone() { - return new IdPoolImpl((LinkedList) idPool.clone()); - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/backend/ImmutableViewImpl.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/backend/ImmutableViewImpl.java deleted file mode 100644 index e5d965fe..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/backend/ImmutableViewImpl.java +++ /dev/null @@ -1,32 +0,0 @@ -package stmbench7.impl.backend; - -import java.util.ArrayList; -import java.util.Iterator; - -import stmbench7.backend.ImmutableCollection; - -public class ImmutableViewImpl implements ImmutableCollection, Cloneable { - - private final ArrayList elements; - - public ImmutableViewImpl(ArrayList elements) { - this.elements = elements; - } - - public boolean contains(E element) { - return elements.contains(element); - } - - public int size() { - return elements.size(); - } - - public Iterator iterator() { - return elements.iterator(); - } - - @SuppressWarnings("unchecked") - public ImmutableCollection clone() { - return new ImmutableViewImpl((ArrayList) elements.clone()); - } -} \ No newline at end of file diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/backend/LargeSetImpl.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/backend/LargeSetImpl.java deleted file mode 100644 index ad12dec0..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/backend/LargeSetImpl.java +++ /dev/null @@ -1,35 +0,0 @@ -package stmbench7.impl.backend; - -import java.util.TreeSet; - -import stmbench7.backend.LargeSet; - -/** - * A simple implementation of a large-size set - * (used by CompositePart objects). - * This default implementation is NOT thread-safe. - */ -public class LargeSetImpl> extends TreeSet implements LargeSet { - - private static final long serialVersionUID = -6991698966590705390L; - - public LargeSetImpl() { - super(); - } - - public LargeSetImpl(LargeSetImpl source) { - super(source); - } - - // The following methods are needed because TreeSet - // implements contains(Object) and remove(Object) - // instead of contains(E) and remove(E). - - public boolean contains(E element) { - return super.contains(element); - } - - public boolean remove(E element) { - return super.remove(element); - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/backend/SmallSetImpl.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/backend/SmallSetImpl.java deleted file mode 100644 index c34a1bd4..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/backend/SmallSetImpl.java +++ /dev/null @@ -1,35 +0,0 @@ -package stmbench7.impl.backend; - -import java.util.ArrayList; - -import stmbench7.annotations.ContainedInAtomic; -import stmbench7.backend.ImmutableCollection; - -/** - * A simple implementation of a small-size set - * (used by Assembly and AtomicPart objects). - */ -@ContainedInAtomic -public class SmallSetImpl extends ArrayList { - - private static final long serialVersionUID = 8608574819902616324L; - - public SmallSetImpl() { - super(); - } - - public SmallSetImpl(SmallSetImpl source) { - super(source); - } - - public boolean add(E element) { - if(contains(element)) return false; - - super.add(element); - return true; - } - - public ImmutableCollection immutableView() { - return new ImmutableViewImpl(this); - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/backend/TreeMapIndex.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/backend/TreeMapIndex.java deleted file mode 100644 index b4b3c897..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/backend/TreeMapIndex.java +++ /dev/null @@ -1,66 +0,0 @@ -package stmbench7.impl.backend; - -import java.util.Iterator; -import java.util.TreeMap; - -import stmbench7.backend.Index; -import stmbench7.core.RuntimeError; - -/** - * A simple implementation of an index - * (NOT thread-safe). - */ -public class TreeMapIndex,V> implements Index, Cloneable { - - private final TreeMap index; - - public TreeMapIndex() { - index = new TreeMap(); - } - - public void put(K key, V value) { - if(value == null) throw new RuntimeError("TreeMapIndex does not support null values!"); - index.put(key, value); - } - - public V putIfAbsent(K key, V value) { - if(value == null) throw new RuntimeError("TreeMapIndex does not support null values!"); - - V oldVal = index.get(key); - if(oldVal != null) return oldVal; - - index.put(key, value); - return null; - } - - public V get(K key) { - return index.get(key); - } - - public Iterable getRange(K minKey, K maxKey) { - return index.subMap(minKey, maxKey).values(); - } - - public boolean remove(K key) { - V removedValue = index.remove(key); - return (removedValue != null); - } - - public Iterator iterator() { - return index.values().iterator(); - } - - public Iterable getKeys() { - return index.keySet(); - } - - private TreeMapIndex(TreeMap index) { - this.index = index; - } - - @SuppressWarnings("unchecked") - @Override - public Object clone() { - return new TreeMapIndex((TreeMap) index.clone()); - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/core/AssemblyImpl.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/core/AssemblyImpl.java deleted file mode 100644 index edc66166..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/core/AssemblyImpl.java +++ /dev/null @@ -1,52 +0,0 @@ -package stmbench7.impl.core; - -import stmbench7.core.Assembly; -import stmbench7.core.ComplexAssembly; -import stmbench7.core.Module; - - -/** - * STMBench7 benchmark Assembly (see the specification). - * Default implementation. - */ -public abstract class AssemblyImpl extends DesignObjImpl implements Assembly { - - protected ComplexAssembly superAssembly; - protected Module module; - - public AssemblyImpl(int id, String type, int buildDate, Module module, ComplexAssembly superAssembly) { - super(id, type, buildDate); - this.module = module; - this.superAssembly = superAssembly; - } - - public AssemblyImpl(AssemblyImpl source) { - super(source); - this.superAssembly = source.superAssembly; - this.module = source.module; - } - - public ComplexAssembly getSuperAssembly() { - return superAssembly; - } - - public Module getModule() { - return module; - } - - public void clearPointers() { - superAssembly = null; - module = null; - } - - @Override - public boolean equals(Object obj) { - if(! (obj instanceof Assembly)) return false; - return super.equals(obj); - } - - @Override - public String toString() { - return super.toString() + ", superAssembly=[" + superAssembly + "]"; - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/core/AtomicPartImpl.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/core/AtomicPartImpl.java deleted file mode 100644 index 8b084493..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/core/AtomicPartImpl.java +++ /dev/null @@ -1,111 +0,0 @@ -package stmbench7.impl.core; - -import stmbench7.backend.ImmutableCollection; -import stmbench7.core.AtomicPart; -import stmbench7.core.CompositePart; -import stmbench7.core.Connection; -import stmbench7.impl.backend.SmallSetImpl; - -/** - * STMBench7 benchmark Atomic Part (see the specification). - * Default implementation. - */ -public class AtomicPartImpl extends DesignObjImpl implements AtomicPart { - - private int x, y; - protected SmallSetImpl to, from; - private CompositePart partOf; - - public AtomicPartImpl(int id, String type, int buildDate, int x, int y) { - super(id, type, buildDate); - this.x = x; - this.y = y; - to = new SmallSetImpl(); - from = new SmallSetImpl(); - } - - public AtomicPartImpl(AtomicPartImpl source) { - super(source); - this.x = source.x; - this.y = source.y; - this.to = new SmallSetImpl(source.to); - this.from = new SmallSetImpl(source.from); - this.partOf = source.partOf; - } - - public void connectTo(AtomicPart destination, String type, int length) { - Connection connection = new ConnectionImpl(this, destination, type, length); - to.add(connection); - destination.addConnectionFromOtherPart(connection.getReversed()); - } - - public void addConnectionFromOtherPart(Connection connection) { - from.add(connection); - } - - public void setCompositePart(CompositePart partOf) { - this.partOf = partOf; - } - - public int getNumToConnections() { - return to.size(); - } - - public ImmutableCollection getToConnections() { - return to.immutableView(); - } - - public ImmutableCollection getFromConnections() { - return from.immutableView(); - } - - public CompositePart getPartOf() { - return partOf; - } - - public void swapXY() { - int tmp = y; - y = x; - x = tmp; - } - - public int getX() { - return x; - } - - public int getY() { - return y; - } - - public void clearPointers() { - x = y = 0; - to = null; - from = null; - partOf = null; - } - - public int compareTo(AtomicPart part) { - return id - part.getId(); - } - - @Override - public boolean equals(Object obj) { - if(! (obj instanceof AtomicPart)) return false; - return super.equals(obj); - } - - @SuppressWarnings("unchecked") - @Override - public AtomicPartImpl clone() { - AtomicPartImpl clone = (AtomicPartImpl) super.clone(); - clone.from = (SmallSetImpl) from.clone(); - clone.to = (SmallSetImpl) to.clone(); - return clone; - } - - @Override - public String toString() { - return super.toString() + ", x=" + x + ", y=" + y + ", partOf=[" + partOf + "]" + - ", to={ " + to.size() + " connections }, from={ " + from.size() + " connections }"; - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/core/BaseAssemblyImpl.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/core/BaseAssemblyImpl.java deleted file mode 100644 index 7a56e49c..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/core/BaseAssemblyImpl.java +++ /dev/null @@ -1,72 +0,0 @@ -package stmbench7.impl.core; - -import stmbench7.backend.ImmutableCollection; -import stmbench7.core.BaseAssembly; -import stmbench7.core.ComplexAssembly; -import stmbench7.core.CompositePart; -import stmbench7.core.Module; -import stmbench7.impl.backend.BagImpl; - -/** - * STMBench7 benchmark Base Assembly (see the specification). - * Default implementation. - */ -public class BaseAssemblyImpl extends AssemblyImpl implements BaseAssembly { - - protected BagImpl components; - - public BaseAssemblyImpl(int id, String type, int buildDate, Module module, ComplexAssembly superAssembly) { - super(id, type, buildDate, module, superAssembly); - components = new BagImpl(); - } - - public BaseAssemblyImpl(BaseAssemblyImpl source) { - super(source); - this.components = new BagImpl(source.components); - } - - public void addComponent(CompositePart component) { - components.add(component); - component.addAssembly(this); - } - - public boolean removeComponent(CompositePart component) { - boolean componentExists = components.remove(component); - if(! componentExists) return false; - - component.removeAssembly(this); - return true; - } - - public ImmutableCollection getComponents() { - return components.immutableView(); - } - - @Override - public void clearPointers() { - super.clearPointers(); - components = null; - } - - @Override - public boolean equals(Object obj) { - if(! (obj instanceof BaseAssembly)) return false; - return super.equals(obj); - } - - @SuppressWarnings("unchecked") - @Override - public BaseAssemblyImpl clone() { - BaseAssemblyImpl clone = (BaseAssemblyImpl) super.clone(); - clone.components = (BagImpl) components.clone(); - return clone; - } - - @Override - public String toString() { - String componentIds = "{ "; - for(CompositePart component : components) componentIds += component.getId() + " "; - componentIds += "}"; - return super.toString() + ", components=" + componentIds; - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/core/ComplexAssemblyImpl.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/core/ComplexAssemblyImpl.java deleted file mode 100644 index 5e1f4aa8..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/core/ComplexAssemblyImpl.java +++ /dev/null @@ -1,84 +0,0 @@ -package stmbench7.impl.core; - -import stmbench7.Parameters; -import stmbench7.backend.ImmutableCollection; -import stmbench7.core.Assembly; -import stmbench7.core.BaseAssembly; -import stmbench7.core.ComplexAssembly; -import stmbench7.core.Module; -import stmbench7.core.RuntimeError; -import stmbench7.impl.backend.SmallSetImpl; - -/** - * STMBench7 benchmark Complex Assembly (see the specification). - * Default implementation. - */ -public class ComplexAssemblyImpl extends AssemblyImpl implements ComplexAssembly { - - private SmallSetImpl subAssemblies; - private short level; - - public ComplexAssemblyImpl(int id, String type, int buildDate, Module module, ComplexAssembly superAssembly) { - super(id, type, buildDate, module, superAssembly); - subAssemblies = new SmallSetImpl(); - - if(superAssembly == null) level = Parameters.NumAssmLevels; - else level = (short)(superAssembly.getLevel() - 1); - } - - public ComplexAssemblyImpl(ComplexAssemblyImpl source) { - super(source); - this.subAssemblies = new SmallSetImpl(subAssemblies); - this.level = source.level; - } - - public boolean addSubAssembly(Assembly assembly) { - if(assembly instanceof BaseAssembly && level != 2) - throw new RuntimeError("ComplexAssembly.addAssembly: BaseAssembly at wrong level!"); - - boolean notAddedBefore = subAssemblies.add(assembly); - return notAddedBefore; - } - - public boolean removeSubAssembly(Assembly assembly) { - return subAssemblies.remove(assembly); - } - - public ImmutableCollection getSubAssemblies() { - return subAssemblies.immutableView(); - } - - public short getLevel() { - return level; - } - - @Override - public void clearPointers() { - super.clearPointers(); - subAssemblies = null; - level = -1; - } - - @Override - public boolean equals(Object obj) { - if(! (obj instanceof ComplexAssembly)) return false; - return super.equals(obj); - } - - @SuppressWarnings("unchecked") - @Override - public ComplexAssemblyImpl clone() { - ComplexAssemblyImpl clone = (ComplexAssemblyImpl) super.clone(); - clone.subAssemblies = (SmallSetImpl) subAssemblies.clone(); - return clone; - } - - @Override - public String toString() { - String subAssString = "{ "; - for(Assembly subAssembly : subAssemblies) - subAssString += subAssembly.getId() + " "; - subAssString += "}"; - return super.toString() + ", level=" + level + ", subAssemblies=" + subAssString; - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/core/CompositePartImpl.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/core/CompositePartImpl.java deleted file mode 100644 index d0d1e9e1..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/core/CompositePartImpl.java +++ /dev/null @@ -1,96 +0,0 @@ -package stmbench7.impl.core; - -import stmbench7.backend.BackendFactory; -import stmbench7.backend.ImmutableCollection; -import stmbench7.backend.LargeSet; -import stmbench7.core.AtomicPart; -import stmbench7.core.BaseAssembly; -import stmbench7.core.CompositePart; -import stmbench7.core.Document; -import stmbench7.impl.backend.BagImpl; - -/** - * STMBench7 benchmark Composite Part (see the specification). - */ -public class CompositePartImpl extends DesignObjImpl implements CompositePart { - - private Document documentation; - private BagImpl usedIn; - private LargeSet parts; - private AtomicPart rootPart; - - public CompositePartImpl(int id, String type, int buildDate, Document documentation) { - super(id, type, buildDate); - this.documentation = documentation; - documentation.setPart(this); - usedIn = new BagImpl(); - parts = BackendFactory.instance.createLargeSet(); - } - - public CompositePartImpl(CompositePartImpl source) { - super(source); - this.documentation = source.documentation; - this.usedIn = new BagImpl(source.usedIn); - this.parts = source.parts; - this.rootPart = source.rootPart; - } - - public void addAssembly(BaseAssembly assembly) { - usedIn.add(assembly); - } - - public boolean addPart(AtomicPart part) { - boolean notAddedBefore = parts.add(part); - if(! notAddedBefore) return false; - - part.setCompositePart(this); - if(rootPart == null) rootPart = part; - - return true; - } - - public AtomicPart getRootPart() { - return rootPart; - } - - public void setRootPart(AtomicPart part) { - rootPart = part; - } - - public Document getDocumentation() { - return documentation; - } - - public LargeSet getParts() { - return parts; - } - - public void removeAssembly(BaseAssembly assembly) { - usedIn.remove(assembly); - } - - public ImmutableCollection getUsedIn() { - return usedIn.immutableView(); - } - - public void clearPointers() { - documentation = null; - parts = null; - usedIn = null; - rootPart = null; - } - - @Override - public boolean equals(Object obj) { - if(! (obj instanceof CompositePart)) return false; - return super.equals(obj); - } - - @SuppressWarnings("unchecked") - @Override - public Object clone() { - CompositePartImpl clone = (CompositePartImpl) super.clone(); - clone.usedIn = (BagImpl) usedIn.clone(); - return clone; - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/core/ConnectionImpl.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/core/ConnectionImpl.java deleted file mode 100644 index dc4e0138..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/core/ConnectionImpl.java +++ /dev/null @@ -1,53 +0,0 @@ -package stmbench7.impl.core; - -import stmbench7.core.AtomicPart; -import stmbench7.core.Connection; -import stmbench7.core.RuntimeError; - - -/** - * STMBench7 benchmark Connection (see the specification). - * Default implementation. - */ -public class ConnectionImpl implements Connection, Cloneable { - - protected final String type; - protected final int length; - protected final AtomicPart from, to; - - public ConnectionImpl(AtomicPart from, AtomicPart to, String type, int length) { - this.type = type; - this.length = length; - this.from = from; - this.to = to; - } - - public Connection getReversed() { - return new ConnectionImpl(to, from, new String(type), length); - } - - public AtomicPart getSource() { - return from; - } - - public AtomicPart getDestination() { - return to; - } - - public int getLength() { - return length; - } - - public String getType() { - return type; - } - - public Object clone() { - try { - return super.clone(); - } - catch(CloneNotSupportedException e) { - throw new RuntimeError(e); - } - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/core/DesignObjFactoryImpl.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/core/DesignObjFactoryImpl.java deleted file mode 100644 index c8a83dc9..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/core/DesignObjFactoryImpl.java +++ /dev/null @@ -1,63 +0,0 @@ -package stmbench7.impl.core; - -import stmbench7.core.AtomicPart; -import stmbench7.core.BaseAssembly; -import stmbench7.core.ComplexAssembly; -import stmbench7.core.CompositePart; -import stmbench7.core.Connection; -import stmbench7.core.DesignObjFactory; -import stmbench7.core.Document; -import stmbench7.core.Manual; -import stmbench7.core.Module; - -/** - * Implements methods that create objects implementing - * interfaces defined in stmbench7.core. This default implementation - * constructs objects that are NOT thread-safe. - */ -public class DesignObjFactoryImpl extends DesignObjFactory { - - @Override - public AtomicPart createAtomicPart(int id, String type, int buildDate, int x, int y) { - return new AtomicPartImpl(id, type, buildDate, x, y); - } - - @Override - public Connection createConnection(AtomicPart from, AtomicPart to, - String type, int length) { - return new ConnectionImpl(from, to, type, length); - } - - @Override - public BaseAssembly createBaseAssembly(int id, String type, int buildDate, - Module module, ComplexAssembly superAssembly) { - return new BaseAssemblyImpl(id, type, buildDate, module, superAssembly); - } - - @Override - public ComplexAssembly createComplexAssembly(int id, String type, int buildDate, - Module module, ComplexAssembly superAssembly) { - return new ComplexAssemblyImpl(id, type, buildDate, module, superAssembly); - } - - @Override - public CompositePart createCompositePart(int id, String type, int buildDate, - Document documentation) { - return new CompositePartImpl(id, type, buildDate, documentation); - } - - @Override - public Document createDocument(int id, String title, String text) { - return new DocumentImpl(id, title, text); - } - - @Override - public Manual createManual(int id, String title, String text) { - return new ManualImpl(id, title, text); - } - - @Override - public Module createModule(int id, String type, int buildDate, Manual man) { - return new ModuleImpl(id, type, buildDate, man); - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/core/DesignObjImpl.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/core/DesignObjImpl.java deleted file mode 100644 index 2463b371..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/core/DesignObjImpl.java +++ /dev/null @@ -1,85 +0,0 @@ -package stmbench7.impl.core; - -import stmbench7.core.DesignObj; -import stmbench7.core.RuntimeError; - -/** - * STMBench7 benchmark Design Object (see the specification). Default - * implementation. - */ -public class DesignObjImpl implements DesignObj, Cloneable { - - protected final int id; - protected final String type; - protected int buildDate; - - public DesignObjImpl(int id, String type, int buildDate) { - this.id = id; - this.type = type; - this.buildDate = buildDate; - } - - public DesignObjImpl(DesignObjImpl source) { - this.id = source.id; - this.type = source.type; - this.buildDate = source.buildDate; - } - - public int getId() { - return id; - } - - public int getBuildDate() { - return buildDate; - } - - public void updateBuildDate() { - if (buildDate % 2 == 0) - buildDate--; - else - buildDate++; - } - - public void nullOperation() { - } - - public String getType() { - return type; - } - - @Override - public boolean equals(Object obj) { - if(! (obj instanceof DesignObj)) return false; - return ((DesignObj) obj).getId() == id; - } - - @Override - public int hashCode() { - return id; - } - - @Override - public Object clone() { - try { - return super.clone(); - } - catch(CloneNotSupportedException e) { - throw new RuntimeError(e); - } - } - - @Override - public String toString() { - return this.getClass().getName() + - ": id=" + id + - ", type=" + type + - ", buildDate=" + buildDate; - } - - protected String sequenceToString(Iterable sequence) { - String seqString = "{ "; - for(Object element : sequence) seqString += element + " "; - seqString += "}"; - return seqString; - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/core/DocumentImpl.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/core/DocumentImpl.java deleted file mode 100644 index e073e852..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/core/DocumentImpl.java +++ /dev/null @@ -1,95 +0,0 @@ -package stmbench7.impl.core; - -import stmbench7.core.CompositePart; -import stmbench7.core.Document; -import stmbench7.core.RuntimeError; - - -/** - * STMBench7 benchmark Document (see the specification). - * Default implementation. - */ -public class DocumentImpl implements Document, Cloneable { - - private final int id; - private String title; - private String text; - private CompositePart part; - - public DocumentImpl(int id, String title, String text) { - this.id = id; - this.title = title; - this.text = text; - } - - public DocumentImpl(DocumentImpl source) { - this.title = source.title; - this.id = source.id; - this.text = source.text; - this.part = source.part; - } - - public void setPart(CompositePart part) { - this.part = part; - } - - public CompositePart getCompositePart() { - return part; - } - - public int getDocumentId() { - return id; - } - - public String getTitle() { - return title; - } - - public void nullOperation() { - } - - public int searchText(char symbol) { - int occurences = 0; - - for(int i = 0; i < text.length(); i++) - if(text.charAt(i) == symbol) occurences++; - - return occurences; - } - - public int replaceText(String from, String to) { - if(! text.startsWith(from)) return 0; - - text = text.replaceFirst(from, to); - return 1; - } - - public boolean textBeginsWith(String prefix) { - return text.startsWith(prefix); - } - - public String getText() { - return text; - } - - @Override - public boolean equals(Object obj) { - if(! (obj instanceof Document)) return false; - return ((Document) obj).getDocumentId() == id; - } - - @Override - public int hashCode() { - return id; - } - - @Override - public Object clone() { - try { - return super.clone(); - } - catch(CloneNotSupportedException e) { - throw new RuntimeError(e); - } - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/core/ManualImpl.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/core/ManualImpl.java deleted file mode 100644 index 1f3360df..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/core/ManualImpl.java +++ /dev/null @@ -1,107 +0,0 @@ -package stmbench7.impl.core; - -import stmbench7.core.Manual; -import stmbench7.core.Module; -import stmbench7.core.RuntimeError; - - -/** - * STMBench7 benchmark Manual (see the specification). - * Default implementation. - */ -public class ManualImpl implements Manual, Cloneable { - - private final int id; - private String title; - private String text; - private Module module; - - public ManualImpl(int id, String title, String text) { - this.id = id; - this.title = title; - this.text = text; - } - - public ManualImpl(ManualImpl source) { - this.title = source.title; - this.id = source.id; - this.text = source.text; - this.module = source.module; - } - - public void setModule(Module module) { - this.module = module; - } - - public int countOccurences(char ch) { - int position = 0, count = 0, newPosition, textLen = text.length(); - - do { - newPosition = text.indexOf(ch, position); - if(newPosition == -1) break; - - position = newPosition + 1; - count++; - } - while(position < textLen); - - return count; - } - - public int checkFirstLastCharTheSame() { - if(text.charAt(0) == text.charAt(text.length() - 1)) return 1; - return 0; - } - - public boolean startsWith(char ch) { - return (text.charAt(0) == ch); - } - - public int replaceChar(char from, char to) { - text = text.replace(from, to); - return countOccurences(to); - } - - public int getId() { - return id; - } - - public Module getModule() { - return module; - } - - public String getText() { - return text; - } - - public String getTitle() { - return title; - } - - @Override - public boolean equals(Object obj) { - if(! (obj instanceof Manual)) return false; - return ((Manual) obj).getId() == id; - } - - @Override - public int hashCode() { - return id; - } - - @Override - public Object clone() { - try { - return super.clone(); - } - catch(CloneNotSupportedException e) { - throw new RuntimeError(e); - } - } - - @Override - public String toString() { - return getClass().getName() + ": id=" + id + ", title=" + title + ", text=" + - text.substring(0, 10) + " (...) " + text.substring(text.length() - 10, text.length()); - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/core/ModuleImpl.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/core/ModuleImpl.java deleted file mode 100644 index 33720cdb..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/core/ModuleImpl.java +++ /dev/null @@ -1,46 +0,0 @@ -package stmbench7.impl.core; - -import stmbench7.core.ComplexAssembly; -import stmbench7.core.Manual; -import stmbench7.core.Module; - - -/** - * STMBench7 benchmark Module (see the specification). - * Default implementation. - */ -public class ModuleImpl extends DesignObjImpl implements Module { - - private final Manual man; - private ComplexAssembly designRoot; - - public ModuleImpl(int id, String type, int buildDate, Manual man) { - super(id, type, buildDate); - this.man = man; - man.setModule(this); - } - - public ModuleImpl(ModuleImpl source) { - super(source); - this.man = source.man; - this.designRoot = source.designRoot; - } - - public void setDesignRoot(ComplexAssembly designRoot) { - this.designRoot = designRoot; - } - - public ComplexAssembly getDesignRoot() { - return designRoot; - } - - public Manual getManual() { - return man; - } - - @Override - public boolean equals(Object obj) { - if(! (obj instanceof Module)) return false; - return super.equals(obj); - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/deucestm/DeuceSTMInitializer.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/deucestm/DeuceSTMInitializer.java deleted file mode 100644 index 08783dc9..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/deucestm/DeuceSTMInitializer.java +++ /dev/null @@ -1,12 +0,0 @@ -package stmbench7.impl.deucestm; - -import stmbench7.OperationExecutorFactory; -import stmbench7.impl.NoSynchronizationInitializer; - -public class DeuceSTMInitializer extends NoSynchronizationInitializer { - - @Override - public OperationExecutorFactory createOperationExecutorFactory() { - return new DeuceSTMOperationExecutorFactory(); - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/deucestm/DeuceSTMOperationExecutor.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/deucestm/DeuceSTMOperationExecutor.java deleted file mode 100644 index 349bec54..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/deucestm/DeuceSTMOperationExecutor.java +++ /dev/null @@ -1,24 +0,0 @@ -package stmbench7.impl.deucestm; - -import stmbench7.OperationExecutor; -import stmbench7.core.Operation; -import stmbench7.core.OperationFailedException; - -public class DeuceSTMOperationExecutor implements OperationExecutor { - - private final Operation op; - - public DeuceSTMOperationExecutor(Operation op) { - this.op = op; - } - - @org.deuce.Atomic - public int execute() throws OperationFailedException { - return op.performOperation(); - } - - public int getLastOperationTimestamp() { - return 0; - } - -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/deucestm/DeuceSTMOperationExecutorFactory.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/deucestm/DeuceSTMOperationExecutorFactory.java deleted file mode 100644 index 37449f52..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/deucestm/DeuceSTMOperationExecutorFactory.java +++ /dev/null @@ -1,17 +0,0 @@ -package stmbench7.impl.deucestm; - -import stmbench7.OperationExecutor; -import stmbench7.OperationExecutorFactory; -import stmbench7.core.Operation; -import stmbench7.impl.DefaultOperationExecutor; - -public class DeuceSTMOperationExecutorFactory extends OperationExecutorFactory { - - @Override - public OperationExecutor createOperationExecutor(Operation op) { - if(op.getOperationId() != null) - return new DeuceSTMOperationExecutor(op); - return new DefaultOperationExecutor(op); - } - -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/locking/CGLockingInitializer.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/locking/CGLockingInitializer.java deleted file mode 100644 index e6af62a0..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/locking/CGLockingInitializer.java +++ /dev/null @@ -1,16 +0,0 @@ -package stmbench7.locking; - -import stmbench7.OperationExecutorFactory; -import stmbench7.impl.NoSynchronizationInitializer; - -/** - * An initializer for the coarse-grained locking - * thread synchronization. - */ -public class CGLockingInitializer extends NoSynchronizationInitializer { - - @Override - public OperationExecutorFactory createOperationExecutorFactory() { - return new CGLockingOperationExecutorFactory(); - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/locking/CGLockingOperationExecutor.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/locking/CGLockingOperationExecutor.java deleted file mode 100644 index c37b0402..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/locking/CGLockingOperationExecutor.java +++ /dev/null @@ -1,64 +0,0 @@ -package stmbench7.locking; - -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReentrantReadWriteLock; - -import stmbench7.OperationExecutor; -import stmbench7.core.Operation; -import stmbench7.core.OperationFailedException; -import stmbench7.core.RuntimeError; - -public class CGLockingOperationExecutor implements OperationExecutor { - - private static final Lock globalReadLock, globalWriteLock; - private static int globalCounter = 0; - - static { - ReentrantReadWriteLock globalLock = new ReentrantReadWriteLock(true); - globalReadLock = globalLock.readLock(); - globalWriteLock = globalLock.writeLock(); - } - - private final Operation op; - private final Lock globalLock; - private int lastOperationTimestamp; - - public CGLockingOperationExecutor(Operation op) { - this.op = op; - if(op.getOperationId() == null) { - globalLock = null; - return; - } - - switch(op.getOperationId().getType()) { - case OPERATION_RO: - case SHORT_TRAVERSAL_RO: - case TRAVERSAL_RO: - globalLock = globalReadLock; - break; - case OPERATION: - case SHORT_TRAVERSAL: - case TRAVERSAL: - case STRUCTURAL_MODIFICATION: - globalLock = globalWriteLock; - break; - default: - throw new RuntimeError("Unexpected operation type"); - } - } - - public int execute() throws OperationFailedException { - try { - if(globalLock != null) globalLock.lock(); - return op.performOperation(); - } - finally { - lastOperationTimestamp = globalCounter++; - if(globalLock != null) globalLock.unlock(); - } - } - - public int getLastOperationTimestamp() { - return lastOperationTimestamp; - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/locking/CGLockingOperationExecutorFactory.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/locking/CGLockingOperationExecutorFactory.java deleted file mode 100644 index 1e58ad82..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/locking/CGLockingOperationExecutorFactory.java +++ /dev/null @@ -1,17 +0,0 @@ -package stmbench7.locking; - -import stmbench7.OperationExecutor; -import stmbench7.OperationExecutorFactory; -import stmbench7.core.Operation; - -/** - * An implementation of the OperationExecutorFactory - * for the coarse-grained locking synchronization. - */ -public class CGLockingOperationExecutorFactory extends OperationExecutorFactory { - - @Override - public OperationExecutor createOperationExecutor(Operation op) { - return new CGLockingOperationExecutor(op); - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/locking/MGLockingComplexAssemblyImpl.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/locking/MGLockingComplexAssemblyImpl.java deleted file mode 100644 index 4f4ba2bf..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/locking/MGLockingComplexAssemblyImpl.java +++ /dev/null @@ -1,50 +0,0 @@ -package stmbench7.locking; - -import stmbench7.core.ComplexAssembly; -import stmbench7.core.Module; -import stmbench7.impl.core.ComplexAssemblyImpl; - -/** - * An implementation of the ComplexAssembly interface used in the - * medium-grained locking synchronization method. The complex - * assembly is locked for reading or writing by the methods that read - * or modify the object (except for cases when the required - * locking is done externally). - */ -public class MGLockingComplexAssemblyImpl extends ComplexAssemblyImpl { - - public MGLockingComplexAssemblyImpl(int id, String type, int buildDate, - Module module, ComplexAssembly superAssembly) { - super(id, type, buildDate, module, superAssembly); - } - - /* - * Methods "add/removeSubAssembly", "getSubAssemblies" and "clearPointers" - * assume global structure lock is held when those are called. Attributes - * "level", "superAssembly" and "module" can also be changed only when the - * global structure lock is held in write mode. - */ - - @Override - public int getBuildDate() { - MGLockingOperationExecutor.readLockAssemblyLevel(getLevel()); - return super.getBuildDate(); - } - - @Override - public void updateBuildDate() { - MGLockingOperationExecutor.writeLockAssemblyLevel(getLevel()); - super.updateBuildDate(); - } - - @Override - public void nullOperation() { - MGLockingOperationExecutor.readLockAssemblyLevel(getLevel()); - } - - @Override - public String getType() { - MGLockingOperationExecutor.readLockAssemblyLevel(getLevel()); - return super.getType(); - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/locking/MGLockingDesignObjFactory.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/locking/MGLockingDesignObjFactory.java deleted file mode 100644 index 371967ed..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/locking/MGLockingDesignObjFactory.java +++ /dev/null @@ -1,22 +0,0 @@ -package stmbench7.locking; - -import stmbench7.core.ComplexAssembly; -import stmbench7.core.Module; -import stmbench7.impl.core.DesignObjFactoryImpl; - -/** - * Implementation of the DesignObjFactory used in the medium-grained - * locking synchronization method. - */ -public class MGLockingDesignObjFactory extends DesignObjFactoryImpl { - - public MGLockingDesignObjFactory() { - super(); - } - - @Override - public ComplexAssembly createComplexAssembly(int id, String type, int buildDate, - Module module, ComplexAssembly superAssembly) { - return new MGLockingComplexAssemblyImpl(id, type, buildDate, module, superAssembly); - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/locking/MGLockingInitializer.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/locking/MGLockingInitializer.java deleted file mode 100644 index 176478b9..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/locking/MGLockingInitializer.java +++ /dev/null @@ -1,20 +0,0 @@ -package stmbench7.locking; - -import stmbench7.OperationExecutorFactory; -import stmbench7.core.DesignObjFactory; -import stmbench7.impl.NoSynchronizationInitializer; - -/** - * An initializer for the medium-grained locking synchronization - * method. - */ -public class MGLockingInitializer extends NoSynchronizationInitializer { - - public DesignObjFactory createDesignObjFactory() { - return new MGLockingDesignObjFactory(); - } - - public OperationExecutorFactory createOperationExecutorFactory() { - return new MGLockingOperationExecutorFactory(); - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/locking/MGLockingOperationExecutor.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/locking/MGLockingOperationExecutor.java deleted file mode 100644 index 2b879b45..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/locking/MGLockingOperationExecutor.java +++ /dev/null @@ -1,316 +0,0 @@ -package stmbench7.locking; - -import java.util.ArrayList; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReentrantReadWriteLock; - -import stmbench7.OperationExecutor; -import stmbench7.OperationId; -import stmbench7.OperationType; -import stmbench7.Parameters; -import stmbench7.core.Operation; -import stmbench7.core.OperationFailedException; -import stmbench7.core.RuntimeError; - -/** - * Implementation of the OperationExecutor used by the medium-grained - * locking method. It implements externally most of the locking - * for each operation. The locks for each operation are predefined, - * except for some complex assembly locks that may be acquired - * by some complex assembly methods (see the MGLockingComplexAssemblyImpl - * class). - * - * Locking order: - *

    - *
  1. Global structure lock, - *
  2. Manual lock, - *
  3. Base assemblies lock, - *
  4. Composite parts lock, - *
  5. Documents lock, - *
  6. Atomic parts lock, - *
  7. Complex assemblies locks: starting from the highest level - * (Parameters.NumAssmLevels), down to the lowest level - * (BASE_ASSEMBLY_LEVEL + 1). - *
- */ -public class MGLockingOperationExecutor implements OperationExecutor { - - private static final int BASE_ASSEMBLY_LEVEL = 1; - - /** - * Global structure lock is acquired by every operation: - *
    - *
  1. in write mode, if the operation modifies the data structure (i.e., - * adds or removes some elements) or modifies one of the indexes; and - *
  2. in read mode otherwise. - *
- */ - private static final Lock globalStructureReadLock, - globalStructureWriteLock; - - /** - * Per-assembly-level locks. - */ - private static final ReentrantReadWriteLock[] assemblyLocks; - private static final Lock[] assemblyReadLocks, assemblyWriteLocks; - - /** - * Per-object-type locks. - */ - private static final Lock compositePartReadLock, compositePartWriteLock, - atomicPartReadLock, atomicPartWriteLock, documentReadLock, - documentWriteLock, manualReadLock, manualWriteLock; - - /** - * Used for generating timestamps for the replay log. - */ - private static final AtomicInteger globalCounter = new AtomicInteger(); - - /** - * Determines which per-assembly-level locks were acquired by the - * MGLockingComplexAssemblyImpl class. - */ - private static class AssemblyLocksAcquired { - public final boolean[] isReadAcquired, isWriteAcquired; - - public AssemblyLocksAcquired() { - isReadAcquired = new boolean[Parameters.NumAssmLevels + 1]; - isWriteAcquired = new boolean[Parameters.NumAssmLevels + 1]; - clear(); - } - - public void clear() { - for (int level = 0; level <= Parameters.NumAssmLevels; level++) { - isReadAcquired[level] = false; - isWriteAcquired[level] = false; - } - } - } - - private static final ThreadLocal assemblyLocksAcquired = - new ThreadLocal() { - @Override - protected AssemblyLocksAcquired initialValue() { - return new AssemblyLocksAcquired(); - } - }; - - static { - ReentrantReadWriteLock globalStructureLock = new ReentrantReadWriteLock( - false); - globalStructureReadLock = globalStructureLock.readLock(); - globalStructureWriteLock = globalStructureLock.writeLock(); - - assemblyLocks = new ReentrantReadWriteLock[Parameters.NumAssmLevels + 1]; - assemblyReadLocks = new Lock[Parameters.NumAssmLevels + 1]; - assemblyWriteLocks = new Lock[Parameters.NumAssmLevels + 1]; - for (int level = 1; level <= Parameters.NumAssmLevels; level++) { - assemblyLocks[level] = new ReentrantReadWriteLock(false); - assemblyReadLocks[level] = assemblyLocks[level].readLock(); - assemblyWriteLocks[level] = assemblyLocks[level].writeLock(); - } - ReentrantReadWriteLock compositePartLock = new ReentrantReadWriteLock( - false); - compositePartReadLock = compositePartLock.readLock(); - compositePartWriteLock = compositePartLock.writeLock(); - - ReentrantReadWriteLock atomicPartLock = new ReentrantReadWriteLock( - false); - atomicPartReadLock = atomicPartLock.readLock(); - atomicPartWriteLock = atomicPartLock.writeLock(); - - ReentrantReadWriteLock documentLock = new ReentrantReadWriteLock(false); - documentReadLock = documentLock.readLock(); - documentWriteLock = documentLock.writeLock(); - - ReentrantReadWriteLock manualLock = new ReentrantReadWriteLock(false); - manualReadLock = manualLock.readLock(); - manualWriteLock = manualLock.writeLock(); - } - - /** - * Called by a MGLockingComplexAssemblyImpl method to - * read-lock a given complex assembly level. - */ - public static void readLockAssemblyLevel(int level) { - AssemblyLocksAcquired threadAssemblyLocksAcquired = - assemblyLocksAcquired.get(); - if (threadAssemblyLocksAcquired.isReadAcquired[level] - || threadAssemblyLocksAcquired.isWriteAcquired[level]) - return; - - assemblyReadLocks[level].lock(); - threadAssemblyLocksAcquired.isReadAcquired[level] = true; - } - - /** - * Called by a MGLockingComplexAssemblyImpl method to - * write-lock a given complex assembly level. - */ - public static void writeLockAssemblyLevel(int level) { - AssemblyLocksAcquired threadAssemblyLocksAcquired = - assemblyLocksAcquired.get(); - if (threadAssemblyLocksAcquired.isWriteAcquired[level]) - return; - - assemblyWriteLocks[level].lock(); - threadAssemblyLocksAcquired.isWriteAcquired[level] = true; - } - - private final Operation op; - private final ArrayList locksToAcquire; - private int lastOperationTimestamp; - - public MGLockingOperationExecutor(Operation op) { - this.op = op; - - // Decide which locks should be acquired when a given - // operation is executed - locksToAcquire = new ArrayList(); - OperationId operationId = op.getOperationId(); - if(operationId == null) return; - OperationType operationType = operationId.getType(); - - // Structural modification operations: exclusive access - if (operationType == OperationType.STRUCTURAL_MODIFICATION) { - locksToAcquire.add(globalStructureWriteLock); - return; - } - - // Other operations: assume the structure is not modified - locksToAcquire.add(globalStructureReadLock); - - // Handling of individual cases - switch (op.getOperationId()) { - case T1: - case T6: - case Q7: - case ST1: - case ST9: - case OP1: - case OP2: - case OP3: - locksToAcquire.add(atomicPartReadLock); - break; - case T2a: - case T2b: - case T2c: - case T3a: - case T3b: - case T3c: - case ST6: - case ST10: - case OP9: - case OP10: - case OP15: - locksToAcquire.add(atomicPartWriteLock); - break; - - case T4: - case ST2: - locksToAcquire.add(documentReadLock); - break; - case T5: - case ST7: - locksToAcquire.add(documentWriteLock); - break; - - case Q6: - locksToAcquire.add(assemblyReadLocks[BASE_ASSEMBLY_LEVEL]); - locksToAcquire.add(compositePartReadLock); - // Pre-lock all assembly levels to avoid deadlocks - for (int level = Parameters.NumAssmLevels; level > 1; level--) - locksToAcquire.add(assemblyReadLocks[level]); - break; - - case ST3: - locksToAcquire.add(assemblyReadLocks[BASE_ASSEMBLY_LEVEL]); - // Pre-lock all assembly levels to avoid deadlocks - for (int level = Parameters.NumAssmLevels; level > 1; level--) - locksToAcquire.add(assemblyReadLocks[level]); - break; - - case ST4: - locksToAcquire.add(assemblyReadLocks[BASE_ASSEMBLY_LEVEL]); - locksToAcquire.add(documentReadLock); - break; - - case ST5: - locksToAcquire.add(assemblyReadLocks[BASE_ASSEMBLY_LEVEL]); - locksToAcquire.add(compositePartReadLock); - break; - - case ST8: - locksToAcquire.add(assemblyWriteLocks[BASE_ASSEMBLY_LEVEL]); - // Pre-lock all assembly levels to avoid deadlocks - for (int level = Parameters.NumAssmLevels; level > 1; level--) - locksToAcquire.add(assemblyWriteLocks[level]); - break; - - case OP4: - case OP5: - locksToAcquire.add(manualReadLock); - break; - - case OP6: - break; - - case OP7: - locksToAcquire.add(assemblyReadLocks[BASE_ASSEMBLY_LEVEL]); - break; - - case OP8: - locksToAcquire.add(compositePartReadLock); - break; - - case OP11: - locksToAcquire.add(manualWriteLock); - break; - - case OP12: - break; - - case OP13: - locksToAcquire.add(assemblyWriteLocks[BASE_ASSEMBLY_LEVEL]); - break; - - case OP14: - locksToAcquire.add(compositePartWriteLock); - break; - - default: - throw new RuntimeError("Unknown operation: " - + op.getOperationId().toString()); - } - } - - public int execute() throws OperationFailedException { - try { - - for (Lock lock : locksToAcquire) lock.lock(); - return op.performOperation(); - } - finally { - if (Parameters.sequentialReplayEnabled) - lastOperationTimestamp = globalCounter.getAndIncrement(); - - AssemblyLocksAcquired threadAssemblyLocksAcquired = - assemblyLocksAcquired.get(); - - for (int level = 1; level <= Parameters.NumAssmLevels; level++) { - if (threadAssemblyLocksAcquired.isReadAcquired[level]) - assemblyReadLocks[level].unlock(); - if (threadAssemblyLocksAcquired.isWriteAcquired[level]) - assemblyWriteLocks[level].unlock(); - } - threadAssemblyLocksAcquired.clear(); - - for (Lock lock : locksToAcquire) lock.unlock(); - } - } - - public int getLastOperationTimestamp() { - return lastOperationTimestamp; - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/locking/MGLockingOperationExecutorFactory.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/locking/MGLockingOperationExecutorFactory.java deleted file mode 100644 index 99231e44..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/locking/MGLockingOperationExecutorFactory.java +++ /dev/null @@ -1,17 +0,0 @@ -package stmbench7.locking; - -import stmbench7.OperationExecutor; -import stmbench7.OperationExecutorFactory; -import stmbench7.core.Operation; - -/** - * An implementation of the OperationExecutorFactory - * for the medium-grained locking synchronization. - */ -public class MGLockingOperationExecutorFactory extends OperationExecutorFactory { - - @Override - public OperationExecutor createOperationExecutor(Operation op) { - return new MGLockingOperationExecutor(op); - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/BaseOperation.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/BaseOperation.java deleted file mode 100644 index b505056d..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/BaseOperation.java +++ /dev/null @@ -1,54 +0,0 @@ -package stmbench7.operations; - -import stmbench7.OperationId; -import stmbench7.annotations.Transactional; -import stmbench7.annotations.Update; -import stmbench7.backend.BackendFactory; -import stmbench7.backend.Index; -import stmbench7.backend.LargeSet; -import stmbench7.core.AtomicPart; -import stmbench7.core.Operation; -import stmbench7.core.OperationFailedException; - -/** - * Base class for all the benchmark operations. - */ -public abstract class BaseOperation implements Operation { - - @Transactional - @Update - public abstract int performOperation() throws OperationFailedException; - - public abstract OperationId getOperationId(); - - /** - * The method of adding and AtomicPart to the AtomicPartBuildDateIndex is - * non-trivial and is used in a few places. That is why it is put here for - * later reuse. - * - * At first glance, it may seem more complicated than it is necessary, - * but that is because we want to use only locking implemented by - * an Index and Set implementations. - */ - public static void addAtomicPartToBuildDateIndex( - Index> atomicPartBuildDateIndex, - AtomicPart atomicPart) { - LargeSet newSet = BackendFactory.instance.createLargeSet(); - newSet.add(atomicPart); - LargeSet sameDateSet = - atomicPartBuildDateIndex.putIfAbsent(atomicPart.getBuildDate(), newSet); - if(sameDateSet != null) sameDateSet.add(atomicPart); - } - - /** - * The method of removing and AtomicPart from the AtomicPartBuildDateIndex is - * non-trivial and is used in a few places. That is why it is put here for - * later reuse. - */ - public static void removeAtomicPartFromBuildDateIndex( - Index> atomicPartBuildDateIndex, - AtomicPart atomicPart) { - LargeSet sameDateSet = atomicPartBuildDateIndex.get(atomicPart.getBuildDate()); - sameDateSet.remove(atomicPart); - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Operation10.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Operation10.java deleted file mode 100644 index 2e55b898..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Operation10.java +++ /dev/null @@ -1,35 +0,0 @@ -package stmbench7.operations; - -import stmbench7.OperationId; -import stmbench7.Setup; -import stmbench7.annotations.Transactional; -import stmbench7.annotations.Update; -import stmbench7.core.AtomicPart; -import stmbench7.core.OperationFailedException; - -/** - * Operation OP10 (see the specification). - * Simple update, range query on index. - */ -public class Operation10 extends Query2 { - - public Operation10(Setup oo7setup) { - super(oo7setup, 1); - } - - @Override - @Transactional @Update - public int performOperation() throws OperationFailedException { - return super.performOperation(); - } - - @Override - protected void performOperationInAtomicPart(AtomicPart atomicPart) { - atomicPart.swapXY(); - } - - @Override - public OperationId getOperationId() { - return OperationId.OP10; - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Operation11.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Operation11.java deleted file mode 100644 index 37c239d8..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Operation11.java +++ /dev/null @@ -1,38 +0,0 @@ -package stmbench7.operations; - -import stmbench7.OperationId; -import stmbench7.Setup; -import stmbench7.annotations.Transactional; -import stmbench7.annotations.Update; -import stmbench7.core.Manual; -import stmbench7.core.RuntimeError; - -/** - * Operation OP11 (see the specification). - * Simple update. - */ -public class Operation11 extends Traversal8 { - - public Operation11(Setup oo7setup) { - super(oo7setup); - } - - @Override - @Transactional @Update - public int performOperation() { - return super.performOperation(); - } - - @Override - protected int traverse(Manual manual) { - if(manual.startsWith('I')) return manual.replaceChar('I', 'i'); - if(manual.startsWith('i')) return manual.replaceChar('i', 'I'); - - throw new RuntimeError("OP11: unexpected Manual.text!"); - } - - @Override - public OperationId getOperationId() { - return OperationId.OP11; - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Operation12.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Operation12.java deleted file mode 100644 index 0e6926f8..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Operation12.java +++ /dev/null @@ -1,35 +0,0 @@ -package stmbench7.operations; - -import stmbench7.OperationId; -import stmbench7.Setup; -import stmbench7.annotations.Transactional; -import stmbench7.annotations.Update; -import stmbench7.core.ComplexAssembly; -import stmbench7.core.OperationFailedException; - -/** - * Operation OP12 (see the specification). - * Simple update, search on index. - */ -public class Operation12 extends Operation6 { - - public Operation12(Setup oo7setup) { - super(oo7setup); - } - - @Override - @Transactional @Update - public int performOperation() throws OperationFailedException { - return super.performOperation(); - } - - @Override - protected void performOperationInComplexAssembly(ComplexAssembly assembly) { - assembly.updateBuildDate(); - } - - @Override - public OperationId getOperationId() { - return OperationId.OP12; - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Operation13.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Operation13.java deleted file mode 100644 index d4d99914..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Operation13.java +++ /dev/null @@ -1,35 +0,0 @@ -package stmbench7.operations; - -import stmbench7.OperationId; -import stmbench7.Setup; -import stmbench7.annotations.Transactional; -import stmbench7.annotations.Update; -import stmbench7.core.BaseAssembly; -import stmbench7.core.OperationFailedException; - -/** - * Operation OP13 (see the specification). - * Simple update, search on index. - */ -public class Operation13 extends Operation7 { - - public Operation13(Setup oo7setup) { - super(oo7setup); - } - - @Override - @Transactional @Update - public int performOperation() throws OperationFailedException { - return super.performOperation(); - } - - @Override - protected void performOperationInBaseAssembly(BaseAssembly assembly) { - assembly.updateBuildDate(); - } - - @Override - public OperationId getOperationId() { - return OperationId.OP13; - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Operation14.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Operation14.java deleted file mode 100644 index 6da9d7c7..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Operation14.java +++ /dev/null @@ -1,35 +0,0 @@ -package stmbench7.operations; - -import stmbench7.OperationId; -import stmbench7.Setup; -import stmbench7.annotations.Transactional; -import stmbench7.annotations.Update; -import stmbench7.core.CompositePart; -import stmbench7.core.OperationFailedException; - -/** - * Operation OP14 (see the specification). - * Simple update, search on index. - */ -public class Operation14 extends Operation8 { - - public Operation14(Setup oo7setup) { - super(oo7setup); - } - - @Override - @Transactional @Update - public int performOperation() throws OperationFailedException { - return super.performOperation(); - } - - @Override - protected void performOperationInComponent(CompositePart component) { - component.updateBuildDate(); - } - - @Override - public OperationId getOperationId() { - return OperationId.OP14; - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Operation15.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Operation15.java deleted file mode 100644 index 82bbc8f8..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Operation15.java +++ /dev/null @@ -1,42 +0,0 @@ -package stmbench7.operations; - -import stmbench7.OperationId; -import stmbench7.Setup; -import stmbench7.annotations.Transactional; -import stmbench7.annotations.Update; -import stmbench7.backend.Index; -import stmbench7.backend.LargeSet; -import stmbench7.core.AtomicPart; -import stmbench7.core.OperationFailedException; - -/** - * Operation OP15 (see the specification). - * Simple update, search and update on index. - */ -public class Operation15 extends Query1 { - - protected Index> partBuildDateIndex; - - public Operation15(Setup oo7setup) { - super(oo7setup); - this.partBuildDateIndex = oo7setup.getAtomicPartBuildDateIndex(); - } - - @Override - @Transactional @Update - public int performOperation() throws OperationFailedException { - return super.performOperation(); - } - - @Override - protected void performOperationInAtomicPart(AtomicPart atomicPart) { - removeAtomicPartFromBuildDateIndex(partBuildDateIndex, atomicPart); - atomicPart.updateBuildDate(); - addAtomicPartToBuildDateIndex(partBuildDateIndex, atomicPart); - } - - @Override - public OperationId getOperationId() { - return OperationId.OP15; - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Operation6.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Operation6.java deleted file mode 100644 index 0d13d52f..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Operation6.java +++ /dev/null @@ -1,56 +0,0 @@ -package stmbench7.operations; - -import stmbench7.OperationId; -import stmbench7.Parameters; -import stmbench7.Setup; -import stmbench7.ThreadRandom; -import stmbench7.annotations.ReadOnly; -import stmbench7.annotations.Transactional; -import stmbench7.backend.Index; -import stmbench7.core.Assembly; -import stmbench7.core.ComplexAssembly; -import stmbench7.core.OperationFailedException; - -/** - * Operation OP6 (see the specification). - * Read-only, search on index. - */ -public class Operation6 extends BaseOperation { - - protected Index complexAssemblyIdIndex; - - public Operation6(Setup oo7setup) { - this.complexAssemblyIdIndex = oo7setup.getComplexAssemblyIdIndex(); - } - - @Override - @Transactional @ReadOnly - public int performOperation() throws OperationFailedException { - int complexAssemblyId = ThreadRandom.nextInt(Parameters.MaxComplexAssemblies) +1; - ComplexAssembly complexAssembly = complexAssemblyIdIndex.get(complexAssemblyId); - if(complexAssembly == null) throw new OperationFailedException(); - - ComplexAssembly superAssembly = complexAssembly.getSuperAssembly(); - if(superAssembly == null) { - performOperationInComplexAssembly((ComplexAssembly)complexAssembly); - return 1; - } - - int count = 0; - for(Assembly siblingAssembly : superAssembly.getSubAssemblies()) { - performOperationInComplexAssembly((ComplexAssembly)siblingAssembly); - count++; - } - - return count; - } - - protected void performOperationInComplexAssembly(ComplexAssembly assembly) { - assembly.nullOperation(); - } - - @Override - public OperationId getOperationId() { - return OperationId.OP6; - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Operation7.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Operation7.java deleted file mode 100644 index ac6b693c..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Operation7.java +++ /dev/null @@ -1,53 +0,0 @@ -package stmbench7.operations; - -import stmbench7.OperationId; -import stmbench7.Parameters; -import stmbench7.Setup; -import stmbench7.ThreadRandom; -import stmbench7.annotations.ReadOnly; -import stmbench7.annotations.Transactional; -import stmbench7.backend.Index; -import stmbench7.core.Assembly; -import stmbench7.core.BaseAssembly; -import stmbench7.core.ComplexAssembly; -import stmbench7.core.OperationFailedException; - -/** - * Operation OP7 (see the specification). - * Read-only, search on index. - */ -public class Operation7 extends BaseOperation { - - protected Index baseAssemblyIdIndex; - - public Operation7(Setup oo7setup) { - this.baseAssemblyIdIndex = oo7setup.getBaseAssemblyIdIndex(); - } - - @Override - @Transactional @ReadOnly - public int performOperation() throws OperationFailedException { - int baseAssemblyId = ThreadRandom.nextInt(Parameters.MaxBaseAssemblies) +1; - BaseAssembly baseAssembly = baseAssemblyIdIndex.get(baseAssemblyId); - if(baseAssembly == null) throw new OperationFailedException(); - - ComplexAssembly superAssembly = baseAssembly.getSuperAssembly(); - - int count = 0; - for(Assembly siblingAssembly : superAssembly.getSubAssemblies()) { - performOperationInBaseAssembly((BaseAssembly)siblingAssembly); - count++; - } - - return count; - } - - protected void performOperationInBaseAssembly(BaseAssembly assembly) { - assembly.nullOperation(); - } - - @Override - public OperationId getOperationId() { - return OperationId.OP7; - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Operation8.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Operation8.java deleted file mode 100644 index b9f6ba1f..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Operation8.java +++ /dev/null @@ -1,50 +0,0 @@ -package stmbench7.operations; - -import stmbench7.OperationId; -import stmbench7.Parameters; -import stmbench7.Setup; -import stmbench7.ThreadRandom; -import stmbench7.annotations.ReadOnly; -import stmbench7.annotations.Transactional; -import stmbench7.backend.Index; -import stmbench7.core.BaseAssembly; -import stmbench7.core.CompositePart; -import stmbench7.core.OperationFailedException; - -/** - * Operation OP8 (see the specification). - * Read-only, search on index. - */ -public class Operation8 extends BaseOperation { - - protected Index baseAssemblyIdIndex; - - public Operation8(Setup oo7setup) { - this.baseAssemblyIdIndex = oo7setup.getBaseAssemblyIdIndex(); - } - - @Override - @Transactional @ReadOnly - public int performOperation() throws OperationFailedException { - int baseAssemblyId = ThreadRandom.nextInt(Parameters.MaxBaseAssemblies) +1; - BaseAssembly baseAssembly = baseAssemblyIdIndex.get(baseAssemblyId); - if(baseAssembly == null) throw new OperationFailedException(); - - int count = 0; - for(CompositePart component : baseAssembly.getComponents()) { - performOperationInComponent(component); - count++; - } - - return count; - } - - protected void performOperationInComponent(CompositePart component) { - component.nullOperation(); - } - - @Override - public OperationId getOperationId() { - return OperationId.OP8; - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Operation9.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Operation9.java deleted file mode 100644 index a3031253..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Operation9.java +++ /dev/null @@ -1,35 +0,0 @@ -package stmbench7.operations; - -import stmbench7.OperationId; -import stmbench7.Setup; -import stmbench7.annotations.Transactional; -import stmbench7.annotations.Update; -import stmbench7.core.AtomicPart; -import stmbench7.core.OperationFailedException; - -/** - * Operation OP9 (see the specification). - * Simple update, search on index. - */ -public class Operation9 extends Query1 { - - public Operation9(Setup oo7setup) { - super(oo7setup); - } - - @Override - @Transactional @Update - public int performOperation() throws OperationFailedException { - return super.performOperation(); - } - - @Override - protected void performOperationInAtomicPart(AtomicPart atomicPart) { - atomicPart.swapXY(); - } - - @Override - public OperationId getOperationId() { - return OperationId.OP9; - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Query1.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Query1.java deleted file mode 100644 index df5082ca..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Query1.java +++ /dev/null @@ -1,51 +0,0 @@ -package stmbench7.operations; - -import stmbench7.OperationId; -import stmbench7.Parameters; -import stmbench7.Setup; -import stmbench7.ThreadRandom; -import stmbench7.annotations.ReadOnly; -import stmbench7.annotations.Transactional; -import stmbench7.backend.Index; -import stmbench7.core.AtomicPart; -import stmbench7.core.OperationFailedException; - -/** - * Query Q1 / Operation OP1 (see the specification). - * Read-only, search on index. - */ -public class Query1 extends BaseOperation { - - Index partIdIndex; - - public Query1(Setup oo7setup) { - this.partIdIndex = oo7setup.getAtomicPartIdIndex(); - } - - @Override - @Transactional @ReadOnly - public int performOperation() throws OperationFailedException { - int count = 0; - - for(int i = 0; i < 10; i++) { - int partId = ThreadRandom.nextInt(Parameters.MaxAtomicParts) + 1; - AtomicPart part = partIdIndex.get(partId); - - if(part == null) continue; - - performOperationInAtomicPart(part); - count++; - } - - return count; - } - - protected void performOperationInAtomicPart(AtomicPart atomicPart) { - atomicPart.nullOperation(); - } - - @Override - public OperationId getOperationId() { - return OperationId.OP1; - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Query2.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Query2.java deleted file mode 100644 index c5dc259f..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Query2.java +++ /dev/null @@ -1,57 +0,0 @@ -package stmbench7.operations; - -import stmbench7.OperationId; -import stmbench7.Parameters; -import stmbench7.Setup; -import stmbench7.annotations.ReadOnly; -import stmbench7.annotations.Transactional; -import stmbench7.backend.Index; -import stmbench7.backend.LargeSet; -import stmbench7.core.AtomicPart; -import stmbench7.core.OperationFailedException; - -/** - * Query Q2 / Operation OP2 (see the specification). - * Read-only, range query on index. - */ -public class Query2 extends BaseOperation { - - protected Index> partBuildDateIndex; - protected Integer minAtomicDate, maxAtomicDate; - - public Query2(Setup oo7setup) { - this(oo7setup, 1); - } - - protected Query2(Setup oo7setup, int percent) { - this.partBuildDateIndex = oo7setup.getAtomicPartBuildDateIndex(); - this.maxAtomicDate = Parameters.MaxAtomicDate; - this.minAtomicDate = Parameters.MaxAtomicDate - - percent * (Parameters.MaxAtomicDate - Parameters.MinAtomicDate) / 100; - } - - @Override - @Transactional @ReadOnly - public int performOperation() throws OperationFailedException { - Iterable> partSets = partBuildDateIndex.getRange(minAtomicDate, maxAtomicDate); - int count = 0; - - for(LargeSet partSet : partSets) { - for(AtomicPart part : partSet) { - performOperationInAtomicPart(part); - count++; - } - } - - return count; - } - - protected void performOperationInAtomicPart(AtomicPart atomicPart) { - atomicPart.nullOperation(); - } - - @Override - public OperationId getOperationId() { - return OperationId.OP2; - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Query3.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Query3.java deleted file mode 100644 index 8ad70c66..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Query3.java +++ /dev/null @@ -1,20 +0,0 @@ -package stmbench7.operations; - -import stmbench7.OperationId; -import stmbench7.Setup; - -/** - * Query Q3 / Operation OP3 (see the specification). - * Read-only, range query on index. - */ -public class Query3 extends Query2 { - - public Query3(Setup oo7setup) { - super(oo7setup, 10); - } - - @Override - public OperationId getOperationId() { - return OperationId.OP3; - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Query4.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Query4.java deleted file mode 100644 index 2b9ca7b5..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Query4.java +++ /dev/null @@ -1,52 +0,0 @@ -package stmbench7.operations; - -import stmbench7.OperationId; -import stmbench7.Parameters; -import stmbench7.Setup; -import stmbench7.ThreadRandom; -import stmbench7.annotations.ReadOnly; -import stmbench7.annotations.Transactional; -import stmbench7.backend.Index; -import stmbench7.core.BaseAssembly; -import stmbench7.core.Document; -import stmbench7.core.OperationFailedException; - -/** - * Query Q4 / Short traversal ST4 (see the specification). - * Read-only, search on index, short. - */ -public class Query4 extends BaseOperation { - - Index documentTitleIndex; - - public Query4(Setup oo7setup) { - this.documentTitleIndex = oo7setup.getDocumentTitleIndex(); - } - - @Override - @Transactional @ReadOnly - public int performOperation() throws OperationFailedException { - int result = 0; - - for(int i = 0; i < 100; i++) { - int partId = ThreadRandom.nextInt(Parameters.MaxCompParts) + 1; - String docTitle = "Composite Part #" + partId; - - Document document = documentTitleIndex.get(docTitle); - if(document == null) continue; - - for(BaseAssembly assembly : document.getCompositePart().getUsedIn()) { - assembly.nullOperation(); - result++; - } - } - - return result; - } - - @Override - public OperationId getOperationId() { - return OperationId.ST4; - } -} - diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Query5.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Query5.java deleted file mode 100644 index bf7c11c3..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Query5.java +++ /dev/null @@ -1,52 +0,0 @@ -package stmbench7.operations; - -import stmbench7.OperationId; -import stmbench7.Setup; -import stmbench7.annotations.ReadOnly; -import stmbench7.annotations.Transactional; -import stmbench7.backend.Index; -import stmbench7.core.BaseAssembly; -import stmbench7.core.CompositePart; - -/** - * Query Q5 / Short traversal ST5 (see the specification). - * Read-only, iterate on index, short. - */ -public class Query5 extends BaseOperation { - - protected Index baseAssemblyIdIndex; - - public Query5(Setup oo7setup) { - this.baseAssemblyIdIndex = oo7setup.getBaseAssemblyIdIndex(); - } - - @Override - @Transactional @ReadOnly - public int performOperation() { - int result = 0; - - for(BaseAssembly assembly : baseAssemblyIdIndex) { - result += checkBaseAssembly(assembly); - } - - return result; - } - - protected int checkBaseAssembly(BaseAssembly assembly) { - int assBuildDate = assembly.getBuildDate(); - - for(CompositePart part : assembly.getComponents()) { - if(part.getBuildDate() > assBuildDate) { - assembly.nullOperation(); - return 1; - } - } - - return 0; - } - - @Override - public OperationId getOperationId() { - return OperationId.ST5; - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Query6.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Query6.java deleted file mode 100644 index 5e978789..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Query6.java +++ /dev/null @@ -1,55 +0,0 @@ -package stmbench7.operations; - -import stmbench7.OperationId; -import stmbench7.Setup; -import stmbench7.annotations.ReadOnly; -import stmbench7.annotations.Transactional; -import stmbench7.core.Assembly; -import stmbench7.core.BaseAssembly; -import stmbench7.core.ComplexAssembly; -import stmbench7.core.Module; - -/** - * Query Q6 (see the specification). Read-only, long traversal. - */ -public class Query6 extends Query5 { - - protected Module module; - - public Query6(Setup oo7setup) { - super(oo7setup); - this.module = oo7setup.getModule(); - } - - @Override - @Transactional - @ReadOnly - public int performOperation() { - return checkComplexAssembly(module.getDesignRoot()); - } - - protected int checkAssembly(Assembly assembly) { - if (assembly instanceof BaseAssembly) - return checkBaseAssembly((BaseAssembly) assembly); - else - return checkComplexAssembly((ComplexAssembly) assembly); - } - - protected int checkComplexAssembly(ComplexAssembly assembly) { - int result = 0; - - for (Assembly subAssembly : assembly.getSubAssemblies()) - result += checkAssembly(subAssembly); - - if (result == 0) - return 0; - - assembly.nullOperation(); - return result + 1; - } - - @Override - public OperationId getOperationId() { - return OperationId.Q6; - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Query7.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Query7.java deleted file mode 100644 index 045350d0..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Query7.java +++ /dev/null @@ -1,37 +0,0 @@ -package stmbench7.operations; - -import stmbench7.OperationId; -import stmbench7.Setup; -import stmbench7.annotations.ReadOnly; -import stmbench7.annotations.Transactional; -import stmbench7.backend.Index; -import stmbench7.core.AtomicPart; - -/** - * Query Q7 (see the specification). - * Read-only, iterate on index, long. - */ -public class Query7 extends BaseOperation { - - protected Index partIdIndex; - - public Query7(Setup oo7setup) { - this.partIdIndex = oo7setup.getAtomicPartIdIndex(); - } - - @Override - @Transactional @ReadOnly - public int performOperation() { - int result = 0; - for(AtomicPart part : partIdIndex) { - part.nullOperation(); - result++; - } - return result; - } - - @Override - public OperationId getOperationId() { - return OperationId.Q7; - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/SetupDataStructure.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/SetupDataStructure.java deleted file mode 100644 index a4e5eec1..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/SetupDataStructure.java +++ /dev/null @@ -1,76 +0,0 @@ -package stmbench7.operations; - -import stmbench7.OperationId; -import stmbench7.Parameters; -import stmbench7.Setup; -import stmbench7.ThreadRandom; -import stmbench7.annotations.Update; -import stmbench7.core.BaseAssembly; -import stmbench7.core.CompositePart; -import stmbench7.core.CompositePartBuilder; -import stmbench7.core.Module; -import stmbench7.core.Operation; -import stmbench7.core.OperationFailedException; -import stmbench7.core.RuntimeError; - -/** - * An operation that initializes the benchmark data structure. - */ -public class SetupDataStructure implements Operation { - - private final Setup setup; - private Module module; - - public SetupDataStructure(Setup setup) { - this.setup = setup; - } - - @Update - public int performOperation() throws OperationFailedException { - System.err.println("Setting up the design library:"); - CompositePart designLibrary[] = new CompositePart[Parameters.InitialTotalCompParts]; - CompositePartBuilder compositePartBuilder = setup.getCompositePartBuilder(); - - for(int i = 0; i < Parameters.InitialTotalCompParts; i++) { - // Removed, because of too much output. - // System.err.print("Component " + (i+1) + " of " + Parameters.InitialTotalCompParts + "\r"); - try { - designLibrary[i] = compositePartBuilder.createAndRegisterCompositePart(); - } - catch(OperationFailedException e) { - throw new RuntimeError("Unexpected failure of createAndRegisterCompositePart!", e); - } - } - System.err.println(); - - System.err.println("Setting up the module:"); - try { - module = setup.getModuleBuilder().createRegisterModule(); - } - catch(OperationFailedException e) { - throw new RuntimeError("Unexpected failure of createRegisterModule!", e); - } - - int i = 1; - for(BaseAssembly baseAssembly : setup.getBaseAssemblyIdIndex()) { - // Removed, because of too much output. - // System.err.print("Base Assembly " + (i++) + " of " + Parameters.InitialTotalBaseAssemblies + "\r"); - - for(int connections = 0; connections < Parameters.NumCompPerAssm; connections++) { - int compositePartNum = ThreadRandom.nextInt(designLibrary.length); - baseAssembly.addComponent(designLibrary[compositePartNum]); - } - } - System.err.println(); - - return 0; - } - - public OperationId getOperationId() { - return null; - } - - public Module getModule() { - return module; - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/ShortTraversal1.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/ShortTraversal1.java deleted file mode 100644 index f53b530e..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/ShortTraversal1.java +++ /dev/null @@ -1,95 +0,0 @@ -package stmbench7.operations; - -import stmbench7.OperationId; -import stmbench7.Setup; -import stmbench7.ThreadRandom; -import stmbench7.annotations.ReadOnly; -import stmbench7.annotations.Transactional; -import stmbench7.backend.ImmutableCollection; -import stmbench7.backend.LargeSet; -import stmbench7.core.Assembly; -import stmbench7.core.AtomicPart; -import stmbench7.core.BaseAssembly; -import stmbench7.core.ComplexAssembly; -import stmbench7.core.CompositePart; -import stmbench7.core.Module; -import stmbench7.core.OperationFailedException; -import stmbench7.core.RuntimeError; - -/** - * Short traversal ST1 (see the specification). - * Read-only, short. - */ -public class ShortTraversal1 extends BaseOperation { - - protected Module module; - - public ShortTraversal1(Setup oo7setup) { - this.module = oo7setup.getModule(); - } - - @Override - @Transactional @ReadOnly - public int performOperation() throws OperationFailedException { - ComplexAssembly designRoot = module.getDesignRoot(); - return traverse(designRoot); - } - - protected int traverse(Assembly assembly) throws OperationFailedException { - if(assembly instanceof ComplexAssembly) return traverse((ComplexAssembly)assembly); - else return traverse((BaseAssembly)assembly); - } - - protected int traverse(ComplexAssembly complexAssembly) throws OperationFailedException { - ImmutableCollection subAssemblies = complexAssembly.getSubAssemblies(); - int numOfSubAssemblies = subAssemblies.size(); - int nextAssembly = ThreadRandom.nextInt(numOfSubAssemblies); - - int subAssemblyNumber = 0; - for(Assembly subAssembly : subAssemblies) { - if(subAssemblyNumber == nextAssembly) return traverse(subAssembly); - subAssemblyNumber++; - } - - throw new RuntimeError("ST1: size of ComplexAssemby.subAssemblies has changed!"); - } - - protected int traverse(BaseAssembly baseAssembly) throws OperationFailedException { - ImmutableCollection components = baseAssembly.getComponents(); - int numOfComponents = components.size(); - if(numOfComponents == 0) throw new OperationFailedException(); - - int nextComponent = ThreadRandom.nextInt(numOfComponents); - - int componentNumber = 0; - for(CompositePart component : components) { - if(componentNumber == nextComponent) return traverse(component); - componentNumber++; - } - - throw new RuntimeError("ST1: size of BaseAssembly.components has changed!"); - } - - protected int traverse(CompositePart component) { - LargeSet atomicParts = component.getParts(); - int numOfAtomicParts = atomicParts.size(); - int nextAtomicPart = ThreadRandom.nextInt(numOfAtomicParts); - - int atomicPartNumber = 0; - for(AtomicPart atomicPart : atomicParts) { - if(atomicPartNumber == nextAtomicPart) return traverse(atomicPart); - atomicPartNumber++; - } - - throw new RuntimeError("ST1: illegal size of CompositePart.parts!"); - } - - protected int traverse(AtomicPart atomicPart) { - return atomicPart.getX() + atomicPart.getY(); - } - - @Override - public OperationId getOperationId() { - return OperationId.ST1; - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/ShortTraversal10.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/ShortTraversal10.java deleted file mode 100644 index eb8fee67..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/ShortTraversal10.java +++ /dev/null @@ -1,36 +0,0 @@ -package stmbench7.operations; - -import stmbench7.OperationId; -import stmbench7.Setup; -import stmbench7.annotations.Transactional; -import stmbench7.annotations.Update; -import stmbench7.core.AtomicPart; -import stmbench7.core.OperationFailedException; - -/** - * Short traversal ST10 (see the specification). - * Simple update, short. - */ -public class ShortTraversal10 extends ShortTraversal9 { - - public ShortTraversal10(Setup oo7setup) { - super(oo7setup); - } - - @Override - @Transactional @Update - public int performOperation() throws OperationFailedException { - return super.performOperation(); - } - - @Override - protected int performOperationInAtomicPart(AtomicPart part) { - part.swapXY(); - return 1; - } - - @Override - public OperationId getOperationId() { - return OperationId.ST10; - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/ShortTraversal2.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/ShortTraversal2.java deleted file mode 100644 index 413d0fdc..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/ShortTraversal2.java +++ /dev/null @@ -1,39 +0,0 @@ -package stmbench7.operations; - -import stmbench7.OperationId; -import stmbench7.Setup; -import stmbench7.core.AtomicPart; -import stmbench7.core.CompositePart; -import stmbench7.core.Document; -import stmbench7.core.RuntimeError; - -/** - * Short traversal ST2 (see the specification). - * Read-only, short. - */ -public class ShortTraversal2 extends ShortTraversal1 { - - public ShortTraversal2(Setup oo7setup) { - super(oo7setup); - } - - @Override - protected int traverse(CompositePart component) { - Document documentation = component.getDocumentation(); - return traverse(documentation); - } - - protected int traverse(Document documentation) { - return documentation.searchText('I'); - } - - @Override - protected int traverse(AtomicPart atomicPart) { - throw new RuntimeError("ST2: unexpected call to traverse(AtomicPart)!"); - } - - @Override - public OperationId getOperationId() { - return OperationId.ST2; - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/ShortTraversal6.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/ShortTraversal6.java deleted file mode 100644 index 97f6009b..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/ShortTraversal6.java +++ /dev/null @@ -1,36 +0,0 @@ -package stmbench7.operations; - -import stmbench7.OperationId; -import stmbench7.Setup; -import stmbench7.annotations.Transactional; -import stmbench7.annotations.Update; -import stmbench7.core.AtomicPart; -import stmbench7.core.OperationFailedException; - -/** - * Short traversal ST6 (see the specification). - * Simple update, short. - */ -public class ShortTraversal6 extends ShortTraversal1 { - - public ShortTraversal6(Setup oo7setup) { - super(oo7setup); - } - - @Override - @Transactional @Update - public int performOperation() throws OperationFailedException { - return super.performOperation(); - } - - @Override - protected int traverse(AtomicPart atomicPart) { - atomicPart.swapXY(); - return super.traverse(atomicPart); - } - - @Override - public OperationId getOperationId() { - return OperationId.ST6; - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/ShortTraversal7.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/ShortTraversal7.java deleted file mode 100644 index 0e66faba..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/ShortTraversal7.java +++ /dev/null @@ -1,39 +0,0 @@ -package stmbench7.operations; - -import stmbench7.OperationId; -import stmbench7.Setup; -import stmbench7.annotations.Transactional; -import stmbench7.annotations.Update; -import stmbench7.core.Document; -import stmbench7.core.OperationFailedException; -import stmbench7.core.RuntimeError; - -/** - * Short traversal ST7 (see the specification). - * Simple update, short. - */ -public class ShortTraversal7 extends ShortTraversal2 { - - public ShortTraversal7(Setup oo7setup) { - super(oo7setup); - } - - @Override - @Transactional @Update - public int performOperation() throws OperationFailedException { - return super.performOperation(); - } - - @Override - protected int traverse(Document documentation) { - if(documentation.textBeginsWith("I am")) return documentation.replaceText("I am", "This is"); - if(documentation.textBeginsWith("This is")) return documentation.replaceText("This is", "I am"); - - throw new RuntimeError("ST7: unexpected beginning of Document.text!"); - } - - @Override - public OperationId getOperationId() { - return OperationId.ST7; - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/ShortTraversal8.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/ShortTraversal8.java deleted file mode 100644 index 99511321..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/ShortTraversal8.java +++ /dev/null @@ -1,35 +0,0 @@ -package stmbench7.operations; - -import stmbench7.OperationId; -import stmbench7.Setup; -import stmbench7.annotations.Transactional; -import stmbench7.annotations.Update; -import stmbench7.core.Assembly; -import stmbench7.core.OperationFailedException; - -/** - * Short traversal ST8 (see the specification). - * Indexed update, short. - */ -public class ShortTraversal8 extends Traversal7 { - - public ShortTraversal8(Setup oo7setup) { - super(oo7setup); - } - - @Override - @Transactional @Update - public int performOperation() throws OperationFailedException { - return super.performOperation(); - } - - @Override - protected void performOperationOnAssembly(Assembly assembly) { - assembly.updateBuildDate(); - } - - @Override - public OperationId getOperationId() { - return OperationId.ST8; - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/ShortTraversal9.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/ShortTraversal9.java deleted file mode 100644 index 14681785..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/ShortTraversal9.java +++ /dev/null @@ -1,56 +0,0 @@ -package stmbench7.operations; - -import java.util.HashSet; - -import stmbench7.OperationId; -import stmbench7.Setup; -import stmbench7.core.AtomicPart; -import stmbench7.core.CompositePart; -import stmbench7.core.Connection; -import stmbench7.core.RuntimeError; - -/** - * Short traversal ST9 (see the specification). - * Read-only, short. - */ -public class ShortTraversal9 extends ShortTraversal1 { - - public ShortTraversal9(Setup oo7setup) { - super(oo7setup); - } - - @Override - protected int traverse(CompositePart component) { - HashSet setOfVisitedPartIds = new HashSet(); - return traverse(component.getRootPart(), setOfVisitedPartIds); - } - - protected int traverse(AtomicPart atomicPart, HashSet setOfVisitedPartIds) { - if(atomicPart == null) return 0; - if(setOfVisitedPartIds.contains(atomicPart)) return 0; - - int result = performOperationInAtomicPart(atomicPart); - - setOfVisitedPartIds.add(atomicPart); - - for(Connection connection : atomicPart.getToConnections()) - result += traverse(connection.getDestination(), setOfVisitedPartIds); - - return result; - } - - protected int performOperationInAtomicPart(AtomicPart part) { - part.nullOperation(); - return 1; - } - - @Override - protected int traverse(AtomicPart atomicPart) { - throw new RuntimeError("ST9: unexpected call to traverse(AtomicPart)!"); - } - - @Override - public OperationId getOperationId() { - return OperationId.ST9; - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/StructuralModification1.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/StructuralModification1.java deleted file mode 100644 index 73eb81c0..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/StructuralModification1.java +++ /dev/null @@ -1,32 +0,0 @@ -package stmbench7.operations; - -import stmbench7.OperationId; -import stmbench7.Setup; -import stmbench7.annotations.Transactional; -import stmbench7.annotations.Update; -import stmbench7.core.CompositePartBuilder; -import stmbench7.core.OperationFailedException; - -/** - * Structural modification operation SM1 (see the specification). - */ -public class StructuralModification1 extends BaseOperation { - - protected CompositePartBuilder compositePartBuilder; - - public StructuralModification1(Setup oo7setup) { - compositePartBuilder = oo7setup.getCompositePartBuilder(); - } - - @Override - @Transactional @Update - public int performOperation() throws OperationFailedException { - compositePartBuilder.createAndRegisterCompositePart(); - return 0; - } - - @Override - public OperationId getOperationId() { - return OperationId.SM1; - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/StructuralModification2.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/StructuralModification2.java deleted file mode 100644 index af59fa09..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/StructuralModification2.java +++ /dev/null @@ -1,41 +0,0 @@ -package stmbench7.operations; - -import stmbench7.OperationId; -import stmbench7.Parameters; -import stmbench7.Setup; -import stmbench7.ThreadRandom; -import stmbench7.annotations.Transactional; -import stmbench7.annotations.Update; -import stmbench7.backend.Index; -import stmbench7.core.CompositePart; -import stmbench7.core.OperationFailedException; - -/** - * Structural modification operation SM2 (see the specification). - */ -public class StructuralModification2 extends StructuralModification1 { - - protected Index compositePartIdIndex; - - public StructuralModification2(Setup oo7setup) { - - super(oo7setup); - this.compositePartIdIndex = oo7setup.getCompositePartIdIndex(); - } - - @Override - @Transactional @Update - public int performOperation() throws OperationFailedException { - int partToRemoveId = ThreadRandom.nextInt(Parameters.MaxCompParts) + 1; - CompositePart partToRemove = compositePartIdIndex.get(partToRemoveId); - if(partToRemove == null) throw new OperationFailedException(); - - compositePartBuilder.unregisterAndRecycleCompositePart(partToRemove); - return 0; - } - - @Override - public OperationId getOperationId() { - return OperationId.SM2; - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/StructuralModification3.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/StructuralModification3.java deleted file mode 100644 index a5d8024a..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/StructuralModification3.java +++ /dev/null @@ -1,47 +0,0 @@ -package stmbench7.operations; - -import stmbench7.OperationId; -import stmbench7.Parameters; -import stmbench7.Setup; -import stmbench7.ThreadRandom; -import stmbench7.annotations.Transactional; -import stmbench7.annotations.Update; -import stmbench7.backend.Index; -import stmbench7.core.BaseAssembly; -import stmbench7.core.CompositePart; -import stmbench7.core.OperationFailedException; - -/** - * Structural modification operation SM3 (see the specification). - */ -public class StructuralModification3 extends BaseOperation { - - protected Index baseAssemblyIdIndex; - protected Index compositePartIdIndex; - - public StructuralModification3(Setup oo7setup) { - - this.baseAssemblyIdIndex = oo7setup.getBaseAssemblyIdIndex(); - this.compositePartIdIndex = oo7setup.getCompositePartIdIndex(); - } - - @Override - @Transactional @Update - public int performOperation() throws OperationFailedException { - int baseAssemblyId = ThreadRandom.nextInt(Parameters.MaxBaseAssemblies) + 1; - int componentId = ThreadRandom.nextInt(Parameters.MaxCompParts) + 1; - BaseAssembly baseAssembly = baseAssemblyIdIndex.get(baseAssemblyId); - CompositePart component = compositePartIdIndex.get(componentId); - - if(baseAssembly == null || component == null) throw new OperationFailedException(); - - baseAssembly.addComponent(component); - - return 0; - } - - @Override - public OperationId getOperationId() { - return OperationId.SM3; - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/StructuralModification4.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/StructuralModification4.java deleted file mode 100644 index bfa8a732..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/StructuralModification4.java +++ /dev/null @@ -1,56 +0,0 @@ -package stmbench7.operations; - -import stmbench7.OperationId; -import stmbench7.Parameters; -import stmbench7.Setup; -import stmbench7.ThreadRandom; -import stmbench7.annotations.Transactional; -import stmbench7.annotations.Update; -import stmbench7.backend.ImmutableCollection; -import stmbench7.backend.Index; -import stmbench7.core.BaseAssembly; -import stmbench7.core.CompositePart; -import stmbench7.core.OperationFailedException; -import stmbench7.core.RuntimeError; - -/** - * Structural modification operation SM4 (see the specification). - */ -public class StructuralModification4 extends BaseOperation { - - protected Index baseAssemblyIdIndex; - - public StructuralModification4(Setup oo7setup) { - this.baseAssemblyIdIndex = oo7setup.getBaseAssemblyIdIndex(); - } - - @Override - @Transactional @Update - public int performOperation() throws OperationFailedException { - int baseAssemblyId = ThreadRandom.nextInt(Parameters.MaxBaseAssemblies) + 1; - BaseAssembly baseAssembly = baseAssemblyIdIndex.get(baseAssemblyId); - if(baseAssembly == null) throw new OperationFailedException(); - - ImmutableCollection components = baseAssembly.getComponents(); - int numOfComponents = components.size(); - if(numOfComponents == 0) throw new OperationFailedException(); - - int componentToRemove = ThreadRandom.nextInt(numOfComponents); - - int componentNumber = 0; - for(CompositePart component : components) { - if(componentNumber == componentToRemove) { - baseAssembly.removeComponent(component); - return 0; - } - componentNumber++; - } - - throw new RuntimeError("SM4: concurrent modification of BaseAssembly.components!"); - } - - @Override - public OperationId getOperationId() { - return OperationId.SM4; - } -} \ No newline at end of file diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/StructuralModification5.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/StructuralModification5.java deleted file mode 100644 index f00d16f1..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/StructuralModification5.java +++ /dev/null @@ -1,48 +0,0 @@ -package stmbench7.operations; - -import stmbench7.OperationId; -import stmbench7.Parameters; -import stmbench7.Setup; -import stmbench7.ThreadRandom; -import stmbench7.annotations.Transactional; -import stmbench7.annotations.Update; -import stmbench7.backend.Index; -import stmbench7.core.AssemblyBuilder; -import stmbench7.core.BaseAssembly; -import stmbench7.core.ComplexAssembly; -import stmbench7.core.Module; -import stmbench7.core.OperationFailedException; - -/** - * Structural modification operation SM5 (see the specification). - */ -public class StructuralModification5 extends BaseOperation { - - protected AssemblyBuilder assemblyBuilder; - protected Index baseAssemblyIdIndex; - protected Module module; - - public StructuralModification5(Setup oo7setup) { - this.baseAssemblyIdIndex = oo7setup.getBaseAssemblyIdIndex(); - assemblyBuilder = oo7setup.getAssemblyBuilder(); - this.module = oo7setup.getModule(); - } - - @Override - @Transactional @Update - public int performOperation() throws OperationFailedException { - int siblingBaseAssemblyId = ThreadRandom.nextInt(Parameters.MaxBaseAssemblies) + 1; - BaseAssembly siblingBaseAssembly = baseAssemblyIdIndex.get(siblingBaseAssemblyId); - if(siblingBaseAssembly == null) throw new OperationFailedException(); - - ComplexAssembly superAssembly = siblingBaseAssembly.getSuperAssembly(); - assemblyBuilder.createAndRegisterAssembly(module, superAssembly); - - return 0; - } - - @Override - public OperationId getOperationId() { - return OperationId.SM5; - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/StructuralModification6.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/StructuralModification6.java deleted file mode 100644 index c7c69ded..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/StructuralModification6.java +++ /dev/null @@ -1,46 +0,0 @@ -package stmbench7.operations; - -import stmbench7.OperationId; -import stmbench7.Parameters; -import stmbench7.Setup; -import stmbench7.ThreadRandom; -import stmbench7.annotations.Transactional; -import stmbench7.annotations.Update; -import stmbench7.backend.Index; -import stmbench7.core.BaseAssembly; -import stmbench7.core.OperationFailedException; - -/** - * Structural modification SM6 (see the specification). - */ -public class StructuralModification6 extends StructuralModification5 { - - protected Index baseAssemblyIdIndex; - - public StructuralModification6(Setup oo7setup) { - super(oo7setup); - this.baseAssemblyIdIndex = oo7setup.getBaseAssemblyIdIndex(); - } - - @Override - @Transactional @Update - public int performOperation() throws OperationFailedException { - int baseAssemblyToRemoveId = ThreadRandom.nextInt(Parameters.MaxBaseAssemblies) + 1; - BaseAssembly baseAssemblyToRemove = baseAssemblyIdIndex.get(baseAssemblyToRemoveId); - if(baseAssemblyToRemove == null) throw new OperationFailedException(); - - // We want the tree of BAs/CAs to keep its form - // so that each CA has always at least one child sub-assembly - if(baseAssemblyToRemove.getSuperAssembly().getSubAssemblies().size() == 1) - throw new OperationFailedException(); - - assemblyBuilder.unregisterAndRecycleBaseAssembly(baseAssemblyToRemove); - - return 1; - } - - @Override - public OperationId getOperationId() { - return OperationId.SM6; - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/StructuralModification7.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/StructuralModification7.java deleted file mode 100644 index 00b91534..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/StructuralModification7.java +++ /dev/null @@ -1,46 +0,0 @@ -package stmbench7.operations; - -import stmbench7.OperationId; -import stmbench7.Parameters; -import stmbench7.Setup; -import stmbench7.ThreadRandom; -import stmbench7.annotations.Transactional; -import stmbench7.annotations.Update; -import stmbench7.backend.Index; -import stmbench7.core.AssemblyBuilder; -import stmbench7.core.ComplexAssembly; -import stmbench7.core.Module; -import stmbench7.core.OperationFailedException; - -/** - * Structural modification SM7 (see the specification). - */ -public class StructuralModification7 extends BaseOperation { - - protected AssemblyBuilder assemblyBuilder; - protected Index complexAssemblyIdIndex; - protected Module module; - - public StructuralModification7(Setup oo7setup) { - this.complexAssemblyIdIndex = oo7setup.getComplexAssemblyIdIndex(); - this.module = oo7setup.getModule(); - assemblyBuilder = oo7setup.getAssemblyBuilder(); - } - - @Override - @Transactional @Update - public int performOperation() throws OperationFailedException { - int superAssemblyId = ThreadRandom.nextInt(Parameters.MaxComplexAssemblies) + 1; - ComplexAssembly superAssembly = complexAssemblyIdIndex.get(superAssemblyId); - if(superAssembly == null) throw new OperationFailedException(); - - assemblyBuilder.createAndRegisterAssembly(module, superAssembly); - - return 1; - } - - @Override - public OperationId getOperationId() { - return OperationId.SM7; - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/StructuralModification8.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/StructuralModification8.java deleted file mode 100644 index c30246f1..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/StructuralModification8.java +++ /dev/null @@ -1,43 +0,0 @@ -package stmbench7.operations; - -import stmbench7.OperationId; -import stmbench7.Parameters; -import stmbench7.Setup; -import stmbench7.ThreadRandom; -import stmbench7.annotations.Transactional; -import stmbench7.annotations.Update; -import stmbench7.core.ComplexAssembly; -import stmbench7.core.OperationFailedException; - -/** - * Structural modification SM8 (see the specification). - */ -public class StructuralModification8 extends StructuralModification7 { - - public StructuralModification8(Setup oo7setup) { - super(oo7setup); - } - - @Override - @Transactional @Update - public int performOperation() throws OperationFailedException { - int complexAssemblyId = ThreadRandom.nextInt(Parameters.MaxComplexAssemblies) + 1; - ComplexAssembly complexAssembly = complexAssemblyIdIndex.get(complexAssemblyId); - if(complexAssembly == null) throw new OperationFailedException("Complex assembly: " + complexAssembly); - - // We want the tree of BAs/CAs to keep its form - // so that each CA has always at least one child sub-assembly - ComplexAssembly superAssembly = complexAssembly.getSuperAssembly(); - if(superAssembly == null || superAssembly.getSubAssemblies().size() == 1) - throw new OperationFailedException("Super assembly: " + superAssembly); - - assemblyBuilder.unregisterAndRecycleComplexAssembly(complexAssembly); - - return 1; - } - - @Override - public OperationId getOperationId() { - return OperationId.SM8; - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Traversal1.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Traversal1.java deleted file mode 100644 index f52dea0a..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Traversal1.java +++ /dev/null @@ -1,89 +0,0 @@ -package stmbench7.operations; - -import java.util.HashSet; - -import stmbench7.OperationId; -import stmbench7.Setup; -import stmbench7.annotations.ReadOnly; -import stmbench7.annotations.Transactional; -import stmbench7.core.Assembly; -import stmbench7.core.AtomicPart; -import stmbench7.core.BaseAssembly; -import stmbench7.core.ComplexAssembly; -import stmbench7.core.CompositePart; -import stmbench7.core.Connection; -import stmbench7.core.Module; - -/** - * Traversal T1 (see the specification). - * Read-only, long. - */ -public class Traversal1 extends BaseOperation { - - protected Module module; - - public Traversal1(Setup oo7setup) { - this.module = oo7setup.getModule(); - } - - @Override - @Transactional @ReadOnly - public int performOperation() { - ComplexAssembly designRoot = module.getDesignRoot(); - return traverse(designRoot); - } - - protected int traverse(Assembly assembly) { - if(assembly instanceof BaseAssembly) return traverse((BaseAssembly)assembly); - else return traverse((ComplexAssembly)assembly); - } - - protected int traverse(ComplexAssembly complexAssembly) { - int partsVisited = 0; - - for(Assembly assembly : complexAssembly.getSubAssemblies()) - partsVisited += traverse(assembly); - - return partsVisited; - } - - protected int traverse(BaseAssembly baseAssembly) { - int partsVisited = 0; - - for(CompositePart component : baseAssembly.getComponents()) - partsVisited += traverse(component); - - return partsVisited; - } - - protected int traverse(CompositePart component) { - AtomicPart rootPart = component.getRootPart(); - HashSet setOfVisitedPartIds = new HashSet(); - - return traverse(rootPart, setOfVisitedPartIds); - } - - protected int traverse(AtomicPart part, HashSet setOfVisitedPartIds) { - if(part == null) return 0; - if(setOfVisitedPartIds.contains(part)) return 0; - - int result = performOperationInAtomicPart(part, setOfVisitedPartIds); - - setOfVisitedPartIds.add(part); - - for(Connection connection : part.getToConnections()) - result += traverse(connection.getDestination(), setOfVisitedPartIds); - - return result; - } - - protected int performOperationInAtomicPart(AtomicPart part, HashSet setOfVisitedPartIds) { - part.nullOperation(); - return 1; - } - - @Override - public OperationId getOperationId() { - return OperationId.T1; - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Traversal2a.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Traversal2a.java deleted file mode 100644 index d72f814f..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Traversal2a.java +++ /dev/null @@ -1,43 +0,0 @@ -package stmbench7.operations; - -import java.util.HashSet; - -import stmbench7.OperationId; -import stmbench7.Setup; -import stmbench7.annotations.Transactional; -import stmbench7.annotations.Update; -import stmbench7.core.AtomicPart; - -/** - * Traversal T2, variant (a) (see the specification). - * Simple update, long. - */ -public class Traversal2a extends Traversal1 { - - public Traversal2a(Setup oo7setup) { - super(oo7setup); - } - - @Override - @Transactional @Update - public int performOperation() { - return super.performOperation(); - } - - @Override - protected int performOperationInAtomicPart(AtomicPart part, HashSet setOfVisitedPartIds) { - if(setOfVisitedPartIds.isEmpty()) { - part.swapXY(); - return 1; - } - - part.nullOperation(); - return 0; - } - - @Override - public OperationId getOperationId() { - return OperationId.T2a; - } -} - diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Traversal2b.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Traversal2b.java deleted file mode 100644 index 73244c4d..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Traversal2b.java +++ /dev/null @@ -1,30 +0,0 @@ -package stmbench7.operations; - -import java.util.HashSet; - -import stmbench7.OperationId; -import stmbench7.Setup; -import stmbench7.core.AtomicPart; - -/** - * Traversal T2, variant (b) (see the specification). - * Simple update, long. - */ -public class Traversal2b extends Traversal2a { - - public Traversal2b(Setup oo7setup) { - super(oo7setup); - } - - @Override - protected int performOperationInAtomicPart(AtomicPart part, HashSet setOfVisitedPartIds) { - part.swapXY(); - return 1; - } - - @Override - public OperationId getOperationId() { - return OperationId.T2b; - } -} - diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Traversal2c.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Traversal2c.java deleted file mode 100644 index 2ec192e0..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Traversal2c.java +++ /dev/null @@ -1,33 +0,0 @@ -package stmbench7.operations; - -import java.util.HashSet; - -import stmbench7.OperationId; -import stmbench7.Setup; -import stmbench7.core.AtomicPart; - -/** - * Traversal T2, variant (c) (see the specification). - * Simple update, long. - */ -public class Traversal2c extends Traversal2a { - - public Traversal2c(Setup oo7setup) { - super(oo7setup); - } - - @Override - protected int performOperationInAtomicPart(AtomicPart part, HashSet setOfVisitedPartIds) { - part.swapXY(); - part.swapXY(); - part.swapXY(); - part.swapXY(); - return 4; - } - - @Override - public OperationId getOperationId() { - return OperationId.T2c; - } -} - diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Traversal3a.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Traversal3a.java deleted file mode 100644 index cfdf54ab..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Traversal3a.java +++ /dev/null @@ -1,54 +0,0 @@ -package stmbench7.operations; - -import java.util.HashSet; - -import stmbench7.OperationId; -import stmbench7.Setup; -import stmbench7.annotations.Transactional; -import stmbench7.annotations.Update; -import stmbench7.backend.Index; -import stmbench7.backend.LargeSet; -import stmbench7.core.AtomicPart; - -/** - * Traversal T3, variant (a) (see the specification). - * Simple update, update on index, long. - */ -public class Traversal3a extends Traversal1 { - - Index> partBuildDateIndex; - - public Traversal3a(Setup oo7setup) { - super(oo7setup); - this.partBuildDateIndex = oo7setup.getAtomicPartBuildDateIndex(); - } - - @Override - @Transactional @Update - public int performOperation() { - return super.performOperation(); - } - - @Override - protected int performOperationInAtomicPart(AtomicPart part, HashSet setOfVisitedPartIds) { - if(setOfVisitedPartIds.isEmpty()) { - updateBuildDate(part); - return 1; - } - - part.nullOperation(); - return 0; - } - - protected void updateBuildDate(AtomicPart part) { - removeAtomicPartFromBuildDateIndex(partBuildDateIndex, part); - part.updateBuildDate(); - addAtomicPartToBuildDateIndex(partBuildDateIndex, part); - } - - @Override - public OperationId getOperationId() { - return OperationId.T3a; - } -} - diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Traversal3b.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Traversal3b.java deleted file mode 100644 index 147cfda6..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Traversal3b.java +++ /dev/null @@ -1,30 +0,0 @@ -package stmbench7.operations; - -import java.util.HashSet; - -import stmbench7.OperationId; -import stmbench7.Setup; -import stmbench7.core.AtomicPart; - -/** - * Traversal T3, variant (b) (see the specification). - * Simple update, update on index, long. - */ -public class Traversal3b extends Traversal3a { - - public Traversal3b(Setup oo7setup) { - super(oo7setup); - } - - @Override - protected int performOperationInAtomicPart(AtomicPart part, HashSet setOfVisitedPartIds) { - updateBuildDate(part); - return 1; - } - - @Override - public OperationId getOperationId() { - return OperationId.T3b; - } -} - diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Traversal3c.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Traversal3c.java deleted file mode 100644 index 0af9895d..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Traversal3c.java +++ /dev/null @@ -1,32 +0,0 @@ -package stmbench7.operations; - -import java.util.HashSet; - -import stmbench7.OperationId; -import stmbench7.Setup; -import stmbench7.core.AtomicPart; - -/** - * Traversal T3, variant (c) (see the specification). - * Simple update, update on index, long. - */ -public class Traversal3c extends Traversal3a { - - public Traversal3c(Setup oo7setup) { - super(oo7setup); - } - - @Override - protected int performOperationInAtomicPart(AtomicPart part, HashSet setOfVisitedPartIds) { - updateBuildDate(part); - updateBuildDate(part); - updateBuildDate(part); - updateBuildDate(part); - return 4; - } - - @Override - public OperationId getOperationId() { - return OperationId.T3c; - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Traversal4.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Traversal4.java deleted file mode 100644 index ca5db668..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Traversal4.java +++ /dev/null @@ -1,46 +0,0 @@ -package stmbench7.operations; - -import java.util.HashSet; - -import stmbench7.OperationId; -import stmbench7.Setup; -import stmbench7.core.AtomicPart; -import stmbench7.core.CompositePart; -import stmbench7.core.Document; -import stmbench7.core.RuntimeError; - -/** - * Traversal T4 (see the specification). - * Read-only, long. - */ -public class Traversal4 extends Traversal1 { - - public Traversal4(Setup oo7setup) { - super(oo7setup); - } - - @Override - protected int traverse(CompositePart component) { - Document documentation = component.getDocumentation(); - return traverse(documentation); - } - - protected int traverse(Document documentation) { - return documentation.searchText('I'); - } - - @Override - protected int traverse(AtomicPart part, HashSet setOfVisitedPartIds) { - throw new RuntimeError("T4: traverse(AtomicPart, HashSet) called!"); - } - - @Override - protected int performOperationInAtomicPart(AtomicPart part, HashSet setOfVisitedPartIds) { - throw new RuntimeError("T4: performOperationInAtomicPart(..) called!"); - } - - @Override - public OperationId getOperationId() { - return OperationId.T4; - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Traversal5.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Traversal5.java deleted file mode 100644 index 4565bdd9..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Traversal5.java +++ /dev/null @@ -1,44 +0,0 @@ -package stmbench7.operations; - -import stmbench7.OperationId; -import stmbench7.Setup; -import stmbench7.annotations.Transactional; -import stmbench7.annotations.Update; -import stmbench7.core.Document; -import stmbench7.core.RuntimeError; - -/** - * Traversal T5 (see the specification). - */ -public class Traversal5 extends Traversal4 { - - public Traversal5(Setup oo7setup) { - super(oo7setup); - } - - @Override - @Transactional @Update - public int performOperation() { - return super.performOperation(); - } - - @Override - protected int traverse(Document documentation) { - int result; - - if(documentation.textBeginsWith("I am")) - result = documentation.replaceText("I am", "This is"); - else if(documentation.textBeginsWith("This is")) - result = documentation.replaceText("This is", "I am"); - else - throw new RuntimeError("T5: illegal document text: " + documentation.getText()); - - if(result == 0) throw new RuntimeError("T5: concurrent modification!"); - return result; - } - - @Override - public OperationId getOperationId() { - return OperationId.T5; - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Traversal6.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Traversal6.java deleted file mode 100644 index 4d00a68b..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Traversal6.java +++ /dev/null @@ -1,41 +0,0 @@ -package stmbench7.operations; - -import java.util.HashSet; - -import stmbench7.OperationId; -import stmbench7.Setup; -import stmbench7.core.AtomicPart; -import stmbench7.core.CompositePart; - -/** - * Traversal T6 (see the specification). - * Read-only, long. - */ -public class Traversal6 extends Traversal1 { - - public Traversal6(Setup oo7setup) { - super(oo7setup); - } - - @Override - protected int traverse(CompositePart component) { - AtomicPart rootPart = component.getRootPart(); - return traverse(rootPart, null); - } - - @Override - protected int traverse(AtomicPart part, HashSet setOfVisitedPartIds) { - return performOperationInAtomicPart(part, null); - } - - @Override - protected int performOperationInAtomicPart(AtomicPart part, HashSet setOfVisitedPartIds) { - part.nullOperation(); - return 1; - } - - @Override - public OperationId getOperationId() { - return OperationId.T6; - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Traversal7.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Traversal7.java deleted file mode 100644 index e086ade8..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Traversal7.java +++ /dev/null @@ -1,70 +0,0 @@ -package stmbench7.operations; - -import java.util.HashSet; - -import stmbench7.OperationId; -import stmbench7.Parameters; -import stmbench7.Setup; -import stmbench7.ThreadRandom; -import stmbench7.annotations.ReadOnly; -import stmbench7.annotations.Transactional; -import stmbench7.backend.Index; -import stmbench7.core.Assembly; -import stmbench7.core.AtomicPart; -import stmbench7.core.BaseAssembly; -import stmbench7.core.CompositePart; -import stmbench7.core.OperationFailedException; - -/** - * Traversal T7 / Short traversal ST3 (see the specification). - * Read-only, search on index, short. - */ -public class Traversal7 extends BaseOperation { - - Index partIdIndex; - - public Traversal7(Setup oo7setup) { - this.partIdIndex = oo7setup.getAtomicPartIdIndex(); - } - - @Override - @Transactional @ReadOnly - public int performOperation() throws OperationFailedException { - int partId = ThreadRandom.nextInt(Parameters.MaxAtomicParts) + 1; - AtomicPart part = partIdIndex.get(partId); - if(part == null) throw new OperationFailedException(); - - return traverse(part.getPartOf()); - } - - protected int traverse(CompositePart part) { - HashSet visitedAssemblies = new HashSet(); - - int result = 0; - Iterable ownerBaseAssemblies = part.getUsedIn(); - for(BaseAssembly assembly : ownerBaseAssemblies) - result += traverse(assembly, visitedAssemblies); - - return result; - } - - protected int traverse(Assembly assembly, HashSet visitedAssemblies) { - if(assembly == null) return 0; - if(visitedAssemblies.contains(assembly)) return 0; - - visitedAssemblies.add(assembly); - - performOperationOnAssembly(assembly); - - return traverse(assembly.getSuperAssembly(), visitedAssemblies) + 1; - } - - protected void performOperationOnAssembly(Assembly assembly) { - assembly.nullOperation(); - } - - @Override - public OperationId getOperationId() { - return OperationId.ST3; - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Traversal8.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Traversal8.java deleted file mode 100644 index cf64b7d2..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Traversal8.java +++ /dev/null @@ -1,37 +0,0 @@ -package stmbench7.operations; - -import stmbench7.OperationId; -import stmbench7.Setup; -import stmbench7.annotations.ReadOnly; -import stmbench7.annotations.Transactional; -import stmbench7.core.Manual; -import stmbench7.core.Module; - -/** - * Traversal T8 / Operation OP4 (see the specification). - * Read-only. - */ -public class Traversal8 extends BaseOperation { - - protected Module module; - - public Traversal8(Setup oo7setup) { - this.module = oo7setup.getModule(); - } - - @Override - @Transactional @ReadOnly - public int performOperation() { - Manual manual = module.getManual(); - return traverse(manual); - } - - protected int traverse(Manual manual) { - return manual.countOccurences('I'); - } - - @Override - public OperationId getOperationId() { - return OperationId.OP4; - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Traversal9.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Traversal9.java deleted file mode 100644 index ab320a76..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Traversal9.java +++ /dev/null @@ -1,26 +0,0 @@ -package stmbench7.operations; - -import stmbench7.OperationId; -import stmbench7.Setup; -import stmbench7.core.Manual; - -/** - * Traversal T9 / Operation OP5 (see the specification). - * Read-only. - */ -public class Traversal9 extends Traversal8 { - - public Traversal9(Setup oo7setup) { - super(oo7setup); - } - - @Override - protected int traverse(Manual manual) { - return manual.checkFirstLastCharTheSame(); - } - - @Override - public OperationId getOperationId() { - return OperationId.OP5; - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/test/backend/IndexTest.java b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/test/backend/IndexTest.java deleted file mode 100644 index e41ab0cc..00000000 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/test/backend/IndexTest.java +++ /dev/null @@ -1,227 +0,0 @@ -package stmbench7.test.backend; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; - -import java.util.Iterator; -import java.util.Random; -import java.util.TreeMap; - -import org.junit.Before; -import org.junit.Test; - -import stmbench7.backend.BackendFactory; -import stmbench7.backend.Index; -import stmbench7.impl.backend.BackendFactoryImpl; - -/** - * JUnit test for an Index class. - */ -public class IndexTest { - - /** - * Change the factory to test other implementation. - */ - protected BackendFactory backendFactory; - - private Index index, emptyIndex; - - public IndexTest() { - backendFactory = new BackendFactoryImpl(); - } - - @Before - public void setUp() throws Exception { - index = backendFactory.createIndex(); - emptyIndex = backendFactory.createIndex(); - - for(int key = 0; key < 100; key++) { - int val = key * 2; - index.put(key, val); - } - - for(int key = 100; key >= 0; key -= 2) { - int val = key; - index.put(key, val); - } - } - - /** - * Test method for {@link stmbench7.impl.backend.TreeMapIndex#put(stmbench7.backend.IndexKey, java.lang.Object)}. - */ - @Test - public void testPut() { - emptyIndex.put(5, 10); - emptyIndex.put(10, 11); - emptyIndex.put(1, 12); - emptyIndex.put(7, 10); - assertTrue(emptyIndex.get(5) == 10); - assertTrue(emptyIndex.get(10) == 11); - assertTrue(emptyIndex.get(1) == 12); - assertTrue(emptyIndex.get(7) == 10); - } - - /** - * Test method for {@link stmbench7.impl.backend.TreeMapIndex#putIfAbsent(stmbench7.backend.IndexKey, java.lang.Object)}. - */ - @Test - public void testPutIfAbsent() { - assertNull(index.putIfAbsent(101, 111)); - assertNull(index.putIfAbsent(-101, 111)); - assertTrue(index.putIfAbsent(10, 111) == 10); - assertTrue(index.putIfAbsent(-101, 222) == 111); - assertTrue(index.get(10) == 10); - assertTrue(index.get(-101) == 111); - } - - /** - * Test method for {@link stmbench7.impl.backend.TreeMapIndex#get(stmbench7.backend.IndexKey)}. - */ - @Test - public void testGet() { - assertNull(emptyIndex.get(4)); - assertNull(index.get(101)); - assertNull(index.get(-101)); - - for(int key = 0; key <= 100; key += 2) - assertTrue(index.get(key) == key); - for(int key = 1; key <= 100; key += 2) - assertTrue(index.get(key) == key * 2); - } - - /** - * Test method for {@link stmbench7.impl.backend.TreeMapIndex#getRange(stmbench7.backend.IndexKey, stmbench7.backend.IndexKey)}. - */ - @Test - public void testGetRange() { - Iterator range = index.getRange(5, 9).iterator(); - assertTrue(range.next() == 10); - assertTrue(range.next() == 6); - assertTrue(range.next() == 14); - assertTrue(range.next() == 8); - assertFalse(range.hasNext()); - - range = index.getRange(-5, 2).iterator(); - assertTrue(range.next() == 0); - assertTrue(range.next() == 2); - assertFalse(range.hasNext()); - - range = index.getRange(98, 120).iterator(); - assertTrue(range.next() == 98); - assertTrue(range.next() == 99 * 2); - assertTrue(range.next() == 100); - assertFalse(range.hasNext()); - - range = index.getRange(110, 120).iterator(); - assertFalse(range.hasNext()); - range = index.getRange(-120, -110).iterator(); - assertFalse(range.hasNext()); - - range = emptyIndex.getRange(110, 120).iterator(); - assertFalse(range.hasNext()); - } - - /** - * Test method for {@link stmbench7.impl.backend.TreeMapIndex#remove(stmbench7.backend.IndexKey)}. - */ - @Test - public void testRemove() { - assertFalse(emptyIndex.remove(4)); - assertFalse(index.remove(200)); - assertFalse(index.remove(-20)); - - assertTrue(index.remove(20)); - assertFalse(index.remove(20)); - assertNull(index.get(20)); - - assertTrue(index.remove(50)); - assertFalse(index.remove(50)); - assertNull(index.get(50)); - - assertTrue(index.remove(0)); - assertFalse(index.remove(0)); - assertNull(index.get(0)); - - assertTrue(index.remove(100)); - assertFalse(index.remove(100)); - assertNull(index.get(100)); - } - - /** - * Test method for {@link stmbench7.impl.backend.TreeMapIndex#iterator()}. - */ - @Test - public void testIterator() { - Iterator it = emptyIndex.iterator(); - assertFalse(it.hasNext()); - - int key = 0; - for(int val : index) { - if(key % 2 == 0) assertEquals(val, key); - else assertEquals(val, key * 2); - assertTrue(key <= 100); - key++; - } - assertEquals(key, 101); - } - - @Test - public void randomTest() { - final int N = 10000; - long time = System.currentTimeMillis(); - - Index randomIndex = backendFactory.createIndex(); - TreeMap refIndex = new TreeMap(); - - Random random = new Random(); - int max = Integer.MIN_VALUE, min = Integer.MAX_VALUE; - for(int n = 0; n < N; n++) { - int key = random.nextInt(); - assertEquals(randomIndex.get(key), refIndex.get(key)); - randomIndex.put(key, key); - assertTrue(randomIndex.get(key) == key); - - refIndex.put(key, key); - - max = Math.max(max, key); - min = Math.min(min, key); - } - - for(int n = 0; n < N; n++) { - int key = random.nextInt(); - Integer val = randomIndex.putIfAbsent(key, key); - assertEquals(refIndex.get(key), val); - if(val == null) refIndex.put(key, key); - } - - Iterator it = randomIndex.iterator(), refIt = refIndex.values().iterator(); - int prevVal = Integer.MIN_VALUE; - while(it.hasNext() && refIt.hasNext()) { - int val = it.next(), refVal = refIt.next(); - assertTrue(val > prevVal); - assertEquals(val, refVal); - prevVal = val; - } - assertFalse(it.hasNext()); - assertFalse(refIt.hasNext()); - - it = randomIndex.getRange(min/2, max/2).iterator(); - refIt = refIndex.subMap(min/2, max/2).values().iterator(); - while(it.hasNext()) - assertEquals(it.next(), refIt.next()); - assertFalse(refIt.hasNext()); - - for(int n = 0; n < N; n++) { - int key = random.nextInt(); - boolean res = randomIndex.remove(key); - boolean refRes = ( refIndex.remove(key) != null ); - assertEquals(refRes, res); - assertNull(randomIndex.get(key)); - } - - time = System.currentTimeMillis() - time; - System.err.println("randomTest time: " + time + " ms"); - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/stmbench7-VELOX-1.2.tgz b/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/stmbench7-VELOX-1.2.tgz deleted file mode 100644 index 39874f714b335a035c4adee37fc96f19013080fa..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 44037 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 N{{bRx2d@B71pu)SFa-br diff --git a/benchmarks/scala-stm/scala-stm-library/lib/stmbench7-VELOX-1.2.jar b/benchmarks/scala-stm/scala-stm-library/lib/stmbench7-VELOX-1.2.jar deleted file mode 100644 index 9d9c2eec87ef2b171ae7800d03a0425b98003663..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 135813 zcmagG19WB2wmlrDqmHdk$F|Lmd19W}wrxA<*tTukcE{}4UthfU?(e?$zuy^qpK;C@ zbM0DHYpxor_MWxnrNALzK|sEMfN+M1ON0E&2L=QJL`D=KNGl;LM*lGe0wVuU=ob)< zKhRyi1!1>8@UTB8+Mn~kp)!K95@MoC06G~lnMg*sJ_aPQ$AGtxNG=irevJdclU#&Gt`gS;Vc^Co$<88N~?^8pdK-?sbae`Ro%Hc({{O^Nw{DKa)NodS=g< z_enOnql~mo(QJZ9An673Ra)&rK)pY*0h70AoUGKUu_Ul{ZMP@*O(ACo`oCNS0WtIW zYp?$F6~w{OO5e!Zz?7Z-e{ib*hQs&^4rpy{;|O##v$1yg4>l-&vC#(_SQuFw{s%nb zU+@Mt_D25#{&&a!>d+ssy^(>VwUNVra){{P8~ASm?LWBt*S?uq*;@VwFy>zx`aAf4kKVs~_czl0PbB|t^#3!2SpVC?(8$Ta=+9OD zgL8k4s-=yAg_*UpeIaXU78C@89vlRO>Mtfjf8!>=)ZPea zNTO(DYYB9dwlNX4cC>e+Gq40YI7BJQ*vtzcdHozcQBVef z3@wEWVA-2lCsRjJ{Rp*$ru+qk-%*#Odbg?Z5fy%)brqsyE6G~d6f2vk3WRf5e^7?_tflX z_TRi4bl*njGKm+(<4MPx5-D;@VzF(FiBhQa8$M7?&7%ig4A)9S=Z-L?F*;7oT7GUW zU(JwIvGX7kiqNCoR6H7cekX6O()`g&gYnE%*pB#F{HB0yYM_rd_8y__G1I)OKQ9I+ zCw*sm4(uN?f>hmEF{Nk;w_r=R#ahEeZnQ&Pho9;e!%jEhG@|f0wcBKF#6F!hzw-dE zk@~3s-N{sT5al^%&6=o;k9#H_>||NCVYd*Nm{M9DbQZ{dCzdP@e(l-}vac(@x2co} z2Y6Be4Y0v1v2RxFIjBcPYH&@hUe3cvLV&1Q+PVPx}E4^w>g}AGv4YbhD*uf zfy;sXj1P-^nh8^oy^ObG-=f*2MX}!9Z??BbB)8c=xIo$Jedgxm92jjk{C@S2ixNV* zL7h)$bIyyhbvF2F_;lmlwFka&>BV$846a<#7r?|9is;s~(GB@FUH`o8(&_rX|Iz+@ z7eeYO()Z)JF2sq?MMQPtRprDCN_h< z`oh6`6ckxIk781uQTck!@q&d}I){>Z+X@9JQfsXA#VkcD&3bH+bw*}*OL~ckNaNCI zYn%)Gb!;jqF06wSPK|cMoN?#5R~BN%j;>Y{$r;W((zkGOTav7dd6c4TdM4PP0*6UCvNIU-~;t6PuZk zUmsdY%Z6&l);LcwTz}j$vVe4^b!Z^ z)CyT0Yjd1|S*y3>aZ_7NhRJoqN${nmz8Vr8<6=4IsVhK0LqXcs;E+33NVbu+HQz@w-LQ}T*=n(R^z9o zByvUUHlz(&y)ieavfh%5s5k`^YyH+F^gAXf-c>u8JbAi%s<7Tsx9|?(WSdYz%=J`~ zy*AgHWnFuHSzfP=fyBEmusQ=*CmbCb=O`aJJ26iQ{`~u-kT!dTH%uRSJJqhy3*i{e zvYAb?<4l#Mfo*vx2N;uUCRDj@nT2$S_;_R;!j}p}zC!cwBm;uaxFL5}3&LZE0=@j# za=|ayqz2dE(laTg6J4|L5*UeAxi^NELu{mA<|NPyfaK=Wpxq+X*mK&ZGmbh;hdiN0}OE)>I}ba0blwtK8ygf} z3X{CP>D)!Z3QB-Wl}uo|>`fC*Fn9W~Gx8jlQ5h4S%TK9Tyi>&s{oCC`s~*+JXMUYNqDt-|tG&B8_8TPVMEj8I?JH z6ttwa?I{oF3{S}2YMTq}giwlYh%CKyUERTfy6Q2J*$ zu9dEHsU)*g2cPwUt5PJU*EIB^fi7z0i9q32wfSDU3v*)?*P4@1tWz7GGX}jSDZ!6d z%{4ZcZ?N$ycDywF8Y=JPgoW++FxhlbqQ+uNOrDxZMy1w#Bt=Y5SA2U0!YA`nT_WGj zzyOpUDwwDO2G6;|5-Ho`vCAB9zwu98)@G(GSZ>b6&uhmLAj-1&fIRNuxYITH?z+1t zJ71qAZ3TSq25QT?e7EE8#?Y2!C$<~90;F6~+O}C~Z|Uwha-wu5bx~grtwDCMw_iz% zA^djEqlzN%1wpjqWdg-O9#TM7XZ^a1Hc&r1CZ1C#>-voCN;O1u13GmCt%Jiu8q=@3 z!*s)3f)j#bhV{dVWy@h07%#kRy>6yu1&2X)m_Ev4UIC5}Y0zimm9=oC3`juK+oBOs}`HkRmg zmpBdM3CCKScx#JUF6(IVGKvbcP}cQCVS+Slp@uG}rH`=!fg(f>7)KZp_Vu|oFts(; zUGUz^$@KwEXqK~Jhct*2GU!ExesaWZUmsw? z2BI56yU%+_B#y}rxx87TCI67ADrjfSjfhc0y9fRLGSwR>O0kVTti2)nVN5-un?q>L zbdw)w^;lN_Gq3~;2{(GTR~aSVf!fw-=D^_x zrCt*fmS=rsp!f{8pViUVFw670(OfeT4B{1luQ3c2yh5=A@8Q_`)DSq8R%epYas-F)0@BeL2qhL<{tC*&;f82(Oq@( zw!zvAer+#PcujjYHwL%Mc?TF-D)jy2{m;Jt}Zw@bqqhps{2H9U zL0m(f5awI*g!&^Tb(D81A~`{C`)Iy6D5qL5VHjzdxazgp1WcT*zYR#&3ogfWe4skS zkbCZ!c*mz-a*D=tz;4~pgyv5@hfT|Km@-mKcQAzdTL$E+m3QmMrrX6p4R1zz3@6s~ zx97^;W0O^k!0oeyezoF18|KAkH%#TS28xD6+u^e=I92Si^=}~a??=V{2#In&&vJji z=t1;Qi601y=GI?JXK)EJ%b8+$H`$KD6oTU6WLw6*Q$c%{U_LNAEru7%T0S9o))|t= zu2mf34c6ehZq6@>j7*+(b)_n+T0Dhr|4hH2%ml8RX~LI(){8|a=pfzLx*|F<8nnwg z9LdbDdY))>k2W=Fys`yw6uZ8~hOCD$sv@&uuvUd=5H88UM+fw|WHL#+L-1?u@kU*NC|FpJU$`)&IUpKN-A~g5byaFGh;UIjU_p}Cenia;5@?wY^^Ym4e%aDiD?LMZj(Sq1+-htj+P!J_*5p${?W3al?MEbcX6g~a~Hw9{4 zZ6p|SlOYHA&!DJH0b zg2d@S?hy5G5O3n$uT|rk;cH()_u{yGJYVwR!`M^ z+*p*Y+9~nmOo)Tu1bgamOE%)B=%podG{Q!sN8X-1KtFEq7(t|Umb*+9Pg^Vnu?yr4 z^sn*P?0o)e^yePKI4=kY_WvFKe}>wrNOa1u4Ni=d`Oork)`riZ$v z{1Dy>(cjY@SL+F)@CW#}hm$|qnQe@>UVm@a>vBVaP#2((!_|P2Gq2=K1OsAMY9{<; zooUze{WF6AY<+!H&crNil7mhFk~8LI5$RTH!a^)xS8V7BT? zV8Z5TmjFvwNe#V%i6T(9=!Gt5v$Dn`7lcyz|x2leO<+1c0Jn235Jye5VWi{cPeBq^Z%zMbYszw*-Lkaek)aq6h)mh3V=~&@*%J9B%sCIj|e|H;bFsThQ0&W}-_((szhX2hQ@L=;m zNRClmcHVu?O7-z$lNrzjXBa%nfq2#m`cp^m5Ts2j0f$JK zba#KjR>wYrp%Wayp;u9N#MjXEf%jmR+9Ixg@OF&VKIB^rLYXb;2hl4$DW<8GU*msw z#H{Ycs7`XjU(`usFX@P*&!4jYzD#l(q3jx8owJ7$#7_OD7}PDgOUtrae4PZ)730?V zrFPqVmc99uG=~f5O0QOU(g><1rrgNAz7JfK6vfSLLLGt%vH?7i1-Zl`u`AheqG!Th z<=t2ZJyLi^^lg`2>jXVgcIfVEqIb#cuA_Sg^|?^INd{d3p4QR4llrPvo>-Z-3z??g z0q0`nJD@yWo&tx#ebCBew?sJDL;jmYw>e`hJnnBAX;%tvp)q>dAuyo<$WR(TI4ngp zg+J6LLK!J^Z34mji9e3BXg^AP210RX)n2=N8F3KB`rr?&E;_yNc{ky;GM8T-UvPy# zuH_AMd2rwnD-C0}abSk`K5RXI^0Ne=M>3_NuE#*MM?Tpa<`CmWLcizk+>0glie}b6 zjaX}3%nfyAaEQ;ah9~a7zgPbBuXQ#2!YM?snl$2UxDfghR=U)L0RJ?_76@bh-mlQl z?`vwrJ+GpcjU!ZN&*KNEW40n3wey$=jUl=nJmEq4G7Ml`!U+#VfN~QX;m2WydI=z2 zF&GiC`^JP3{Rsa+@MJ%= z_t$(7C=e~S(xB7{1<&Yle~Qw@5r3pvGQ*4lDrMAKxBL&&3Dc;^$fthr%-)(fMY1;Q zyS8I{qv(t3{0L#9on*Er@EdVQpO6_{UumG-eGscigfc9Y`*0sg;DQkTZm+nbNT|S} zT_h;HWJn}~#Ne@nQr5(8<+=IpU3;`w{&zN%SF|> zyeg0~Dr>b4wY3`JD+MicK4};h=lZ^HGWXo;~(&!DMLo=zSqfHs61OOep zq-I(yxbJ&ywj3yOE7nG9Q17LFLzm*N+B{4s@D+*Ad{Mg7HnGp3QQeu_0uPClsP^PI zn!TskG~AMSn>Po`%b-%_f7OKP-W&%ou zcjrU)ZxnP53``w!da>}~Ss{XP4SHKe2ausq(08d;gz_;K)XqR&jfy3f}c zP3q8W<+)g!l`nHAH!Pi9XtFt;E*{O5D{za62@i!LN8^IOT)w-jGBBJYo}|3~c+chi zI7s9*?(W4ZS7?s@`b2wfC3pw1+tP*HhynwdAoK-tRP=bi_o;^9hq|@J)p@H>Ox)4j z4CmFtlZOQGN(>m#e}>N{l#jzdupQ#P#$8c+Atd+q?)tl9%XR=a=0)Q0Ltc8HP!Am* z4KzAR?=xV5{r)P zkLO{Q51)$UZ$wc(8@ybIidCKwhX2zdK)zE%eC2k%9-sfra+~(>IB9c#NV@$C%yTFl(g4 z1Tj57nB^$1{9|=_n^h7uz+tob8$-9ue)H|Rt;eig)V3gPaFm>qfweySe%x`E`~ZK> z@M8=P%Q|wXJVo5I3CjoPhg+1~^)#{L0M?i2DAPCD(^aThb+b3PJp5?+*NBDW>k5lE zsfCObwQp!J=d%hSyR}FJg-_ln8zi4~Lsxq)<8K5}gu9RCZ`1(Kr100LPOK6ZZ~kok zoZ%!a)hv#tbJTVN}JV)SOFik@;rY2`HYF)whW=a5rdt094Y0N^oWR`8%8LfmY?kS zqSo8wQx{iw*a$bx&0o#9t4165Z_k}sHS=$EaNVVl5L>u4C5N;J)q+;9l`OA4KFc5|N?)D^o3 zl$tdUjlSz0?kc?2X`O_w@W@c8a1$4F6u1baS_V?m;|LHkB1NiCQnAJ{N;93I9~w@7|NMc*9nyywO!UV+Xt?hnti> z;iGpS$r+f(Ze-GxrFJ>oDDy>W4_1lA_-O){YqW7R1#31lC&Ozu7tO_fl;dxS}VeZYxXPhE6 zy${C52rN9|Pwn^e+sDE-)N7`L!9k7Q~9& zZS60;eoP#+GN#2er$5WlpiHei!MRQi{&t`Kg`Y}38@1&j*ZxMK1lE6?gd!E5=2VHwPVsK8`XMGy;nNLOXDwAC>PurOGs{kI6VjamzGDy!h=0vi z%9jW~7?9a}8O;d(g2_>z?8F6$Z?SmFp(8T^IiY2rCcecOuii)?iYgW?S_V_qJL=y)+#ryVa3n|^1= zF-w1F1UUNC*A@51q=KEsLMZa!yV%fmuJ;0&h8*PiVG^4k_l^t(V&71vNE#zeqt0f* zXK%pwR~v>BT0u%#hS*3Y+$YWZ;xV@i%* zfHME&6)-yog>8eDZ-7y$uXZ=~ju%@l5WLebh(E`pA59abcS%nB{^Ja_b|NA!l@AHI z^iT~RJuVGf{mIopQkM>a-?Sh zS~bZ;#wqmZ;`&~-(0;>#b$~Xbu1AsPa2aJ|8>@c>`#~_FPKsXLsF+1&_GUc+!@SWx zYs#A+8i@BJL5_{Dg9>p*o6}zt`zAyv=}xvb;P{t`2>q=yW-(lm*Ucb;OaQhU3R%_h zSEEva1lYpwGE~W0M`Y@If<~NNJr$236~$8r>(l;s7F1Pu__%}nan9Wo6K#&9SYO3( znnR&0IdFQv=-kZh8#2Y;?ep3jEooZX*92^7Y;rJqwW8|>bzHP ztjurECv2X57CWXs!RI>SK*3>!DdfjHj~PV3i*ptCk^mn)Mzp_WsoWH((DLbs&eW+0vfBOy#hRN13!L->?9_VZvI_=C!TKV$Hpc zt8MwdxtURI!ACySFd0zp=iEHvSgQWfvgsd<=W2R#&YiYdN>_UBc zJp^vy(3o*}BI!=j!`ol`!U|urok19-69Ioyd}C=-I4KZ0vUgC~Yrof3uVtJ+eXOdS zt^v9Wby6r=1o{|?j8DZeHQ3}vx;p73SQXnl;5GJFR5*7%9-4LK82lJ+zIVfc-&AM| zP9}Hb82lTiPd~3S2TZ9cfD%m?XBPN+_D)IWa-A+>&e?iM@W7R@7F7?cDOmO-uHjv z1lb)Qz*Vy#!NZCWvty;UqHSuso9v**f`v5rj%Pi@;9(W`A>V^7!$VKXJTn1Zm6Rxk z0AB$I{B{p01~!NZ5#18kj}ZNG6`3HKy_m35bm&1DwKW%fxh9AZ*5j&AbJ1(qHBPerRpDhKbNPA3b$BmXK>Wz8~n>u`1cYP6%>4r#ENieIxqd!3~_Vghe z=jxCJ zJeL+u`{p-KCsRQyL);I$1UW~wH0jB9Sf8?-nXY$LLd`#-o-n;@*TOT;aK$z18Lf&+Fhmem(!Ojk zGhZQ`NCbXDnu7b&$@y|Y9_vFmkqT^rB~qpntfkQog4}Wz>5ZdVrUo~&ZA3Y@#GGUM zTs&z~N@MA9el+b|wNW15bCTt{z`m4h@j$)J7e>)A*2Wxslwc0VH)xG>jZw~(fy0A6{z#hY4he5F};h-JKcmaYST92V)}>m)z%}(dwXZz4uD@>X&`9{p=xW&dX0Nm`Y}_GvS6Ru}9F zUo0yi7hJV_>9XeZ`}Kv0yr$(6bY*e}0-}ad00A5~U;(Rdh=J7~#-xUAS9m4!_){L+ zQm6844SOYkk2rT6smu=6ycjrujxp(OE+*n|&l1^Ig*u6_5E*{h*Pqj(pP=V5SbK$o z+A}7-qXUYU9qctRgjM!=xqhXU+hbNp{}qm0&svv(oJTPDYUI z@3Zld(dvZN7xl!hV<}@oCvLbZxO~fYB*|au@+0XhRdok{Gqx~`3V>!Y2Hon98M!s-C5%L0H2_qUf;KnnAY2Az-3jNXr(zKGB z$!Fqqjp@f@8dg&DTT7uLCOLdT?tBOz(cNL?STQ9g2QT$qW+5hS(Apw?deX(f1uRWM zM<^&xXZy+_rB{zAIhM7mnLD>?U+%%E?NHjcr+boS#hbMl4Kuc^HboS**pAgJT}x=O zApTjJbJ$YY<5_3=%Mp!)<;WEZgrvY0^iz&lNkL9oQI1@&f*n1e9Yo{!IsAbAZC0yX zp_J2FHJ#&Z7NPEG)AS^ZElz8-TQBNhvg2UrlRXS3IJ~1mWzE+BP1WHU&9ZYbX?Q5Lq|z1#wL{v?LK+=J6WIc1pD-RmQ_v-`=&jdP6%hbBUDSG z+#pSZFo8yf;m1ftRIa8sI#0bkgvN^i_Xqp%42cbLXtmHX&CAdmO#_0&L}9hC-+)fQ zplK`ato>xhkyolyY%xx6$Jo87q>^l3ihM`H@a}lyu^EAXdvyP%@mbcstw@_CUlaL` z;>O(Otz4frcg>B_+O{W6@^nw9ml~m90WPH2Jd0;4_r==0Jy z)vm}4OVqQPC(Qr`Nhpg$LbB~$+s%+$a>@b@tw)1f5^0#PhtoZ?RWGQvG@|QJ9r9D( z+BsVxanwYa3C21z&QMN$w?!iQINxsy2&!q`<)akKJ|pa5GQ(s zGo41jqB6%;ibS$VG84uVGNf~gQ)&qc)e+$^2slA?b)^)~AF|AwBqp7kH?4m9Dps%4 zq4b(P4GD6mFT&Y`-pZgtn^jg?{*6!y659?Td)w@|HS9vEBMH^9ssi%@35HUyo<}DIAoX#u2!$9)({j8i% zBg{pJnZSOx4v!K5L1UTE`&uo5<}Y2{bw-n# z-h_cV+$Yh<-cyieQ#7 zl|+$ZRRE6>#+6f%BFg2J)7a?N*vQqdLIk8p()*@^Zux+%`#v?9`q&@6*$g5=OXDvU zo>KvC6mGemJR*hHXNBZD%^rOA17qtis8lIBy|)a|XO)drCJrSyI$S>%yHOS33LiaI z!wr1I%e1~UuKMA`rlXgxQr_jbFDOmADb^n@ZMdP%>?v$&B+wJy$NIp3n40%g${)$) z<+o%uW_dOnKxJ`*`dB*?EXXeu&vUr)<-#uOmi#JMf`buFi%Y<24N@8M+!bw(gz1mS zdym)beUKu+>cVyWzzlLR4oUM zt$wl2I;eGi7Lq@Q!I*q0d_zhZP$n9+exqk>%b=ne^v(YBR~jGprZpP|0fy9pOUVX@EaBsh0;eH~+>;>i<=bdfoUL z#=Wf$*ja`}psj7kJy9)uq_zc^y~dWepdKM2;G~$;pAnXm-FL8kOF3-m?89?c;ELZU zfx|QD8M;<9=Lbijc9+p&ZYJMOAFF64s|=jgOv|4_L3JynUik_q)m$TK5z%ont*{`W zr#tGbv0}A^k(^=Z`9onEKB4W}UuA(AH0b`eIL)fPCG;J?bU}{ULy{8bdYMwf3zy7c zQ2d6_gAgC92^<&t#V#SKaek%oBZH zduV!(a}LeT=&I0Pn<-iiSOv>K0)x>cDZ5`5D|8mW+_h33^0E!rqOp^=FKB^~O(AN# zU(HTnR2JAL!<#*d)6V#$V7+gOhF7c$bi*&mY-><(s1)UYqc|Ac!n8yz6U+Kydwyyl zZY^$)^9S7{SMawl-G2Vhv+2KW1!&>jKyCP=O;GuxP57$}UgD3G{eQ#=|9C(hq_{1I zDv0#a^w!cuutpG$2A~1t{kEkSAzX`%xk`4nvsvD-k~!#R@?yC0`6Ek#856e%KqTP!Q>k{Wpl5M?^bzgmjc_wHw#Qu_%YaA?&wx^mpx?j% z?SyvIaK_Sb9MC4_4gLi8*LW|V%S&wk(IANai8;| zgr)M?xdEZb#TdD6A`b$Q|-@^p`-;H7xjhANa-WGK({D zZZUK~wiyAn+m`abDmDI=4JKs;EXrUYASMw1zE|OYjgA=5;LjMj{g=8c2%!BZGthYF zRf-xS06D(jS{A4ZLkAH>AZ`K@0}BENsDg)2oP7t4oHsX7-bDEf8lvKl+xaCs*Y$DX zXn&q(rg580^EzB*zTdyTB7($R*I~ZT7>MhYVJ3(Vj%mQ%uFsTM8W9Q$+KpkR69|O!3eCzL1z@qDH0b84 z{n0*L>KxADOUDhAT8%b|BPN+yYvC1?+`8nUf+R8NO!A?y8MP=q-TcxEt?}ohGSr^a zM%<~bhH@xY1{i}s;2nQsryfI{!>+?WM%PZ()MQS zJcvItJJVbTXv#!A%#{^?3oZCk2>1d4M+M1m%@)vUyBgtwTgopL1Pl8C;*-eXQQMlV zf7UlOF*RQAFn#|1^8QZlTkLw?+h2)eu2u>}Z`R(p*~!_x0Z#U7vsAVm?R7;sfp+J! z7IN24FpWW!#Z5&nghQlnPQZH(n zJn`a#9kv6XrpcWUt=s%FcM0V<*v&)v;PUSKM!T6>Fzp7%HYF^1$9ua;%p zSSGOYpz?f#!V}j&3W9fQ0x8h92Ve4q?7YSH&o7J@ABL%@%>qb{5gw_Wv}w#)+PfKs zO>+0HTH1%hiT2e~-@+Q^cOEZpJTNQL1e(SynX_q*o*jc4Yqp|nkg|cQQJJdKf!%qD zA^3h4Em_5zJz$b<8VNobC})NAsn4KC_yI{V@+Z~=y}z_GLFm`)gEfWF@0IXZlre@? z85WqvVWF+-vVL9EUL4e({);~KZ=5-$GpEe_v&ZKB&t|Q^>Qn!FLX$B32ThVv+ynr_ z_`}`caLhZXgv8;#&{R|@_5l!iC%ff%;w2tezHk) zUcI_+JzA}^$gJOWUA=Z)HFT$WAu15@yzM`}Pab*s+#b5tf2HqqJ_Pf%U&?|&^iGW= z+#SZNwtXYPrr#;1dXwgTZiVeea*f+hk$6J)&Xm5`rg+lybHeLZx_&HshxWV2^8uV> zL$KMtsTcYnuZ-NNCVj~0p$=~=zaaWe;(Y>6x*?iu-!uz9kyplUbd$QsYNGai5}CeO z9z~Y2$m&6x+)&+rIX|HB+nPdA{t0)!CtboKp~r4AN`+5W6T&Q9*bn(&pPV;`4ED;w ztZY?gF6H;05d|D|Kw>5uBP+<`UaMGQp;rMB|uHPcFkRU)zU>wq?^PM1`Q4 zs#E4t*r6~<0C1`AV3}}IWq!BKs4u0;B(wFe*Gf8s$vB|VErbLs=AZ^-%BfypgB5d9 zE1K2zU{6T`G^lKo>zR_0;WG9sgbI_ujyTH|Po(|eGL*~j==>rw7E1^$lwYm=q%tNI zPb~e$GbRca} zna$Zn{9aoO>8hBjQ&SYa%n&@EG@mfeJU4HkZY2gpUT}~?}87Ul3cmo1F z+i8^LCvFdamcEIN4nOUzmk}m++-2h{`(XbKKJW+8cA;H#RyXkO0yea-q9%+JC&d*v z(S_KyvTj!JaP}chfa-N@UF687)1Zm53zw${#iICWkM-o}f^cs3#wS^>6_xNcf#OcS zn^tpxmxt+>$BHU^J)p9kn3Nm`jt0IZoKpxFSAf&5ElFAS{1@_v(%WrM`344*st7Ta z5HMCKzUmKR*Fn8WOQQY~?`?w})*bp zx4*$DTkA!@X$JXK(pe@!HBoA+bT zs-%@V)l6xSx2t!t-tQQ4e>aqcd1rkFdoR@FAs60c2bptfs%mx$sKm9}G(0obY+h+w zT(WAiZgvW(ydN-At-CwO7V0B))z9K^iYh4K z*+-6nP)yThcpyQ!EhdDXp1#Hl;mGT(o%M`*dFJW@KK_&}dyyI8heAG!-~IWNylJ#O z{AQc2(}m!7wbNd!!*gaTX1+F^5mc;AHYk-oR+GRGt=~dMNx<3XUn)^X#v~Z+D4tH1 zkMhejq`-nHcpN^&&^(^>KrJM4-moK$f}DdwGe3+hB_ZQcZi!+T%|3iTy=<0+S>lkZ ziYMy#q@nswj!;z5&;A2=Xmm4xB~IOdP^p*^PSVeQqo4pP)-oog18Hbw3&#{rp(TzI zmHc)Yr78Ov%c#TD(z>ZWUYtb>mgU5{Ucp=_>RMCX*}M{RU(yd?T{DA zRq`XB^^oM54VpJ^R>Psrvps-d@fhDY+Os%-VE$P95bfC-?rQefE^5m{HtEV?1{J4s zJA;gWCx@K%B`1xV{~)KB<)tQ#oPRH;nALq~B8AXtrXI&@f+m*GWyS%=tB)oz+i~Xh z@a`63pBDbH(SxSoWet_4;CT&|_NCM22!qM%qOXrbw_SqbXW)tZaRME#4EaBrth{ZU+>3x_Q;Cd(&M$) z`~3Jd_|CuFwD{XA8AeM-zHa_mrZGZ-fZ+e%l`z1~*61H~jTgX22}J>omwJS*g(@v~ zhyG0g)ZEZaB~>C+qV%lh7=E5`%D=p_p5`l!tak*T0O5DLiK3#R?pJx4D?YY9F>T{1 zx1&ynZLh~mP4D-Q2h<)KwocpqRzw(@&{UM0z7S9vl#YTVQh$1*^n-Vj;eK<8 zQcmJkZ(S60Z@}5!inMoIRG z(6D2!)rKH0$67*OnZC1xqYQk3Vk9w0)eHP4%^=Aj#t=;es+~fe->#QTyA-%3-cV>> zXq$s+rLv)A0j^Y}Qb|_jj-KKoLo-=(#^1x&HdXj76IPGs{5rHB81e(3z`->G3oL0g zO?ixS@3^F&QQs%@Ww-%XM|vOhXACpCo^(w0*Il?Zx}BGa#*{|8q7$=yI^CH6kFaf$#;yAmedP6dn`oLJo+f$X^)W zd%eQB_K3S=7v7=hXghVb-#FS=W=G=D*?6{{9PY)8iuy(Jg-80(1-ysQAE5g(TvilH zPj#N(RQ`J4digf$d3K_DXNdcWm40!y_UO%uswhW@!~UyvmOGw2rsqm}?kC^BjVk$r z?f;T(>ec}GMKnOZp!>}){ww5>D7youE;!iQSa|$7uHnCqlB{fLi}Z(tp|cWfqvzLE z75h~cPfgRh8p^^P0hx%lWSx!BhXJ~#4HhOuCu2dcn5AB<@YKvV>GnHHGMSgTS)%8| zWES^hy{qq^ZbJ3rQ`sm;{E#>79Tpx4qL5sg3GOZdE*TWOP3hS%1!*5oVuU!qTLkMvfqM{;dlR9g&Xpiibo+gQeFV9Sh zuc2z4^bT55#q@_|DIK=uLbA`xTZ~pk72r$x$(CAO$;{n316sfCilUZP{p#wyS6E{c^<$-O7{cuXX8SUUVO-As4TY_K7SzY>tiXr~1+NQz*V zOfL`bShjR#tszJji=Wl7!d;YzFNzF{ntj2(tiqXiZHsl``_j`UG>=!HH=-vKhVrR@ z1z}%U28NN+j*aqJ5RVGDE#zFkO^`;4Ld_270Tj7Zflm@I4~^z^UPeNdp~$qS-xcbo z3^O5@h?;r7!pWy58JBmE_i3d%3Q^a*eY(}g32iBXswLO5pK&Ew0{mhE33*gwMI<5e z36zp0ZwZqUOqG&Mr5^+(FyT9Kcr`G>DulG zp8TXAg%DIq^|W6_1sB+Yz_1)4HRmfyPrx0Mkl|~!99&6vzs(^HnX`C3#4>%Si%u#E z?}op7xcol3o}T^kcKkvQG~tF87!Vag<3OcEb@dgakJsQTGSLggKKjO=Kw6OmlrPFq zdxscx0%l;*!QyVy^f36gL513u>13Vux^TVW;p<2!n_{5j`nnzMcB^;DFIs-{tF^9M z1J;l6A5|r|D>=DW(Uc74Os6i3WyzRgBo9(D9xcu4yI1yyGY?h07WUt${QNOtzIN!Y zdFZfV&e?)1MdE1KXldIJCgRcvt(spdT35hSb(wvcvcml$uC~?utqLPae5?{?cC}WnZCAdy3NlM&WFch*L4Q(eJBPu2Ra*J90i z#MMQobI_fdM_J}@KISKz(*0_H)~L565c{WL;0K?=U=&kv}=W)R*9 zJYu}<@6%=y9u|5g$tQNu5-*+ zP(NcsgCHhx4rL&uld}Yk#L$s{``cKOKY}QnokVUIz&5KPfq=07hkgD_SX0w-R8~dN z?aY@&Rx&4q5JW*(2oUN9h`%hdLg6H^Wc3@cons}uc65ZtMNOhZ)MfDRK)J7=-zD(u zylz(Qo$l$MiemYmCZDPu=Zqg^%vhMsF5kQ@FPoQjEibd~?)LG0ND7GWO_DO~*92Qb z$wJ3IU}di$$n3wyV-pMFMLx`&e)HYku8l&|*a)Ac)7)Eih*E0mZ|tPmGP>o9g#WT( zbW0c+TX1im#E00_++ekgt{G!pB{6Mxaps^5DRp42)y!1lq;n{Cs?30%wM07~AKk0( zRAODsJHm8!Y;gQVR*;C^oMeBchTPg#EyEgB@PZ$-Wykspm~B3U?X6DhS!)|>$N3{46s5c?@E)uNoIcBkbhlT%^?cR=Z#Lm~R%lkt{`gsZg zon_K{$Yca%(I99*j9!;Y+7pj@=*<>ns3OFy!lo19M@#!!LS)6E)I6=@3lneHf+|{8 z3i@1M$ASv&w~3dfP>{5LH$(!6)8y{EmixvS62NPb2? zNy;02^4Ac=W|9k>@NKYh`K8hxtw76a*#=f1v(9Fdp@%K#*{nU@V@PDHVI4aigphb% z%q_@%s+PnjJ>%^Wm#1#-8lY=pA2no;mOEbzqGNmusv|jLf~KxvA3fBmB0b}bmN0~~ zX#eUHAmzxex`_<VLgv`n-JN0!O!PlQ;#>mczuuX zb0C0kK{vh+ec~)P*&p@HGHUYHGkMcG(n=(ff!oUWm2j}OCxyc&MvcPtBt!UfH-TC+ zWUua%xv@M&vbbxnabnyoE&0M)V*9vj5t2yLEfS$Q2)Ju_R@?$?zRCJV;QNVgEq>CU zuCruz&!KEz#umQ){w5cobu>T%V%{(e5YX>qy_8LyobCP!chzc<4(loiykBvsT~L0M zWwOA+hQBy$_~kdD*g>qgD=2eA%0dRU(&%Xyrx+hllV$IIe!|iJp??B{-z&~|p=vA{ zb0|YrW7ehK>FF}dbN_&ya3&* zvZd^+=m@)5mFVBd)p%EGrf}naH<9%Cl_9pEko{{VmD!fl8G4b0(L{xg*?JUxHYX@! zcz8xJCm8cD~7^5^75@FR}SgGz0)_R6Bv|A@rU{w2MvTuc^J+jAWvStN5Y_F+nk5xu^ z0u9@4PztzQ6C@%OS=CQtODfMw!T|#6uJz9mR8GlzAB`K=r<(K&F<^))#DKbzGW+7M* z+CbT3Gb7n#8DWbo<)RqZ5$yhKRHO5A2G!UoriJrUOI+PjDPPPc+oY$;ZY&H}uMKl2 z6IQPaJ%&oTtq-V7Q>%+$g)9_AV^4x3DNCL@!<*;W49a%?x-OU4nBhA;8}5v*duyz% z&T6wtPXcpl8d+H)Mw%Q`HZRAKJzrf0yDF3}+w7-v*QzCLO%LQSCH!+S|6u zSKRDf!r3I_Yg@y(EcAFk4fivzhRv%g=sbO1^pZRL)7?EGyC{AnBJnkQ+A1O074h}q< z68An>?C@}f2nL6EH!Nrytlck!a()6IPS+Tut&$J!w&N+=ESB(L!T1MPbhm~&*D)`C zBsAy&ytrT85-SQA4{?*%;{8YlE8xcO3`k_52JTGsqWyaYE8@l_?_};+DO~=NPawe% zt#dBu^+>yT)}5#0Hyf1Gv@wSF5bA4T&I$Hd{Gjju89E68^ao!$pFMkd2k@j$KxvZf zH@@^|rYURUWNvFLX=CAJVPIw9Ve;>`g19NEK?amy`KFe4YKj1e0*Zo4D-iS=Qw&f+ zTm}1FQ@Z&mYa(kg9Q>(Z_#NT!Wwa8p8@emVtUFw~U#}h?Kz0$$Ak>g*pe;_4&WFQB(<}?GG0i0=_b0rxNvrMXYIacGjPW8)=PKu(np%(tU;7Hy zgX%`yYpBBXZA;=uDbyD`_bc5*vY`>#6Js+Yc3Riw8lTw`}M;3kVSx)BHjw? z!`W9u9$D)25|M+XxQ$dz^s@gReGA6n1)<4GEa^i zuXFn; z=x&=7F9u_sOEvnK%UA?27MDYGH~%ygC0Q=UTx*zNiryg(+vz99v2IJA(ap9?oJwkv zi{(GM0f#iOKKj0!V@8XRH;~-cL0+3@wt!d=zQq3wss+8a>#Cob3B>JNvamZB8|AO_ z9dDWK=5GxCSD=K9!^^=i697vLK$iJ?Pt#v`DjC=q+gks-b0b<&_76b4GmB(p3aj55 zbVZAPB7yb=Hm9BmmO-dN;kAy>mT(yG5sIozV0+RXwlW6$0CL{4mIZ!lSzlwKPG8Q3aNJLVh%&6Mx^dBLWuP zt@dF_(4JB%=+XX6lkOqeyZ_*en68=EDwqbap41jh$0BxGz{Qoz! zg{^FDObiUIO#VXuUm29*x)iY>0&g;h1upUMi}SM90tp|8aUZy797Wj)og3uSN;(S{ z*C`}3?$5^ipCr)|A0`TFiWi~JZf1!Bok2NDWk$r!loNURI8FRSMN3|nna)DuHtc$) z>QI#tJ8ptytB)yFsmTJk5<0M!LH99BR8*i$F{&~Y2R}UP%T<#ezNlumsO=t-eznwGdKRJ;Hh&^2rq37c69q+s zfYw7UG1_BhWAIJbaiwf|V6^Nk6Ug8-+ht~ExVD^qCW2n`kPy#0a*4r5!3!1Ri9~-$ zFB~6>2*y{3$$;fC-#etAI@5?%Z#tqT8T@sV&~D#9}g~*hwIebEg}Nl_MZ)=qO{hizd$T;YUVO zce!1-y^>^~sHu=I*awXheBt;Qet#c&^~a5)3Vbhm1l)KWpb>@Wf8V%*xq;)qH27d8 z1KT+T6y8`g&5jsrKMG{_(z4)kE3tj>QDDNi84!cH`k<#iCk1~{DItSz6ZM0b(Wbd? zio-8>gLOes%LiLI4;!xEy&vCxz3j95wQ|4+4uT4`UlO-tM@2@Eo%|wz{u4eSW}9O$yCh%g$#gK~vtsR0?CzxqO>- zYb;`z(D$t@Sj|`0xlX~@BT;bIrn|5!#?wm#61Vn7Q!s|mSv@$$8s|h}H$Dbd#Cgyy zjCdTOy;_FY>SrikdK7j#sCsjwV=HTk9P)%S#ulv$9a*lPOI+*Wk0Id>A;b<}2gb4L zPf131ILGdenUCX`5c_<1euR<~g6Z_uP!F*F*b;i6aLSeNACABQ#iEB7t{}Dq(;T0C zkWe_u!NTzb#;!_h5IazUa0SkK%n@& zf9bbC@mG9M227#;m+?d=tV;m`bjXJVmXTr8Pwi>V!oiIu^Z@h-_HHE+LD3tBOd321 zWQl_5;+;<@UO@O#S+YimidMj#jp^4P%#EGb`1H0wZ1tx7B2xjun4cZFI$}))2fCza z%gkqc6Z}mAF1Ja-qZ$%rj1v?rg6&B}xsyhSp!VQCdn%G7s!`0Tlz==EOmSIb{z}z~ zo}Unj$b;tM4_XJIMr~!Hhyr)10Z^CJymoA}AO~u=r^@oUfI8%KQ~MvyO+nWaEY2BI zWCmrHnniFQG<(=B-LtmEY#|JWg%OIMse^vL8%rs)Dk{#Yas)kpup(A0@2Rl}A?mQi ztS!$?LnwbccZ=QdZdUE6^^v*R=;7{X%55Af)!j?YoG6syOBJk8#v5@v6gY+`bDySg zubuf$uHZA=OFUXAj`8?wlQ8NLh1Ep~YW)sRKpx{&O!mHPEPx5sq)sbF1)P&nhX6`7 ztj6mKD%1dPKkkiH@27eQAURwH^bz6wPj~;fBxbFQt%~Af zgS2wdps)oksr9+o!n`v7Nr@#1O<1$gLIOF@aM1&Dy^dwIxD(r|690|#yHl2ZRy-MV zKJos9nQsJtpZ$U(J9YrX_;>-Bm<_x?HUW7IKh0a9D)hsSeC~sjm_n=ns(!eQgURFMTP41)xs^% zI|S}EGpZ2_GP6+eH+Qw9H=5zr;99eaEZkt+TM-==K`-r-ow#lbtdoB!PjkrR#27On zP=_@cXWCj;1IACrSTyT;N@pZmiG5YXjh4-cI^VIXzewiKs8!NLwH9r4rZU=MkO4j| zF<_3uy%}B)aqCbj=PEb}iU1^H_Q-csY{9APqRU!?qz*Cx`Tc`v!fm)U62ZgW3rZ;_NTkeTpG%3rDE7~J6qQ;7zrATb5?dDbNG1Zi%4U(cd7HnasrPNjLIr1ppQt2k% zs0=ZC^)Wce#8vLq#InrFws5=KTPss5*^0*6JDOi$et%sKQ-1kjsMvTJUS3WaVs$~X zX>SFM8zF0rB4IW!{W1FOX2FF;YQk2nJR<)n>dchK>@-B#ZZwmF-7YA@)K2mHa9sHLH9rL%d7=7xWIIV7?g)MbM2yOW35}^@Q{- z^Y68K;)WMXJnj?YNm~nIow4VB?hegZjZOC3UKF)FsS@;v$;S$KbND=t*P-^ZsN?j} z6`HfClT}fuPBL)AR_#;A!0BPOJ?odrM6fucE^bDBImowz226M00Q=^QXtg7Lzrc7R zA7uW~48eo(LkP78_~oc}du`YF>0JQ-CA%VlG4eb#9cqzr0gChSIx8#yEJVu>djv?1 z{Zqsf>m3khs*rxjiG}`wR(-C}-EBKM;2UN!xP%_kyCSJG}lTZsm~^XnK`7=e{}tCL!PbK~wmj>(mMxJ=o;#IR}GN ziqGsqJbmB(Mo|AqQ0Zg_nRWqjD;V(h{7zT?zU@HJ$=2G!=&vXiJR>L#EQkVr^HFI< zRow*^KHGP$3j&|Ry3Gq*F!QI|tMe#Eu( zm@?dImn+G*If3XElh7RkgCu$uWWG+i`%^xgzg>ZI#M>16bAr^_O}54cYuU#ZJZ1&Y)k;T{O?$Ollm-(0Cr=$*!Ip| z9V|j)=pLIgZ(GjM4x7!*^R zz0)Tz;>(XkZpy6*J#p{AO4H1EibXk-M|`G;zEtX9Hcz~R)A{XkN_mT`;Nb|{ujNpC z4jzxv3uD5@_Bj?=4)TVF(t!_bmR}~zPy*$QULP7ez`(dQJ6CYLtG95oHP^1c^&!x} z*|nuZh;s}>-oXC%P5i^Ajy|~u>;a$(13*UlKOvK}wsv;}NfTA_-P~(BCoP#3(RM7anp-AM>^&IvFshAI~_>(?9-M&C=V$(a5 zI~zLzcIm8&+B;_Io&9$@QORHIRjVN1UW#?r2iG~|FQ!Ek))%u5Q)V=@wi$LSHlumL zV-jq)zT67FGvOkKT(TJ{RwR$l@*8WqtJ|PtT$~chllzvI*!NMBzgD;@NKO)pK#?w@$dxq-aO*eU0Aqo(mILneUFhoTL1SW4=85YzJnD;bh-*i7~>_NBK{X zY?CV5_WyrDlC%A%J$(iK)1Hhbk9@6^L4={!ErBVOG`>L0j@mgD=iM{c?wY}jTHl2p2ge~vGI{}>|3OTQX@trG^ zD>XXEn9}fUi3NXDY z)U|u-w4dOi$}c>H!RXHl8#P6f;gPHJIb{h32Q`Cp=wQ`4!mU;j28_779~#9O?x4nWBeU`iza)0C6|OETnb ztp2qbBRFmv020jbw}rEnHGbX5l@z?LtKywL<$P$`GU|ynY5B(WJmSX2y_o(UO?YoV zJ{5~Db9iW25-&*~NrG+uTs`)a#PnOWO17D^NH-%)ivmD>_#@N4ho zz|}fM^WdWiW-~!w5cAvTT_%D;J?NUU8t){VP5reJ8QjBjARm7^P3r0^_QSmkng+9K zkmf}k&mTA=A=yahmR>X*-b{;75T>qz3lL<5vDdNpmk;Ks zWE5y!6NCt1o4rKY$9(_KzLCE|Q=Bxp%>e+E2mm<0Hw*kdH2sx7$k-YgSp8p5`!guf z&gl|=`Jzz-Ap$!>6}GrxGHSiDp4cf%P-_aPQYh>dF;dDkFigPQ?FVjN=T6fDwVq&Q zVP#=vA=Aydht(vhFSkuj2t%kIoK(yp(1|na+U;@5Airyoq@0%zdJ38K`OpPry0G6U zNrk!mB8+&vSa%a>``TJAQoL4vVN19_-sx37Q$#QC^7Q0;#(<*KNr61HEK9=->2BXj zm@$afd}FL~cmcWTJnqPr$b;lj-FI$#h717+NMCThOSgElxc~tv5CjaILt8e07-t{k z>2I3XA69hX6@UGQ6`28mqWqs$q~c&;;|Tb;1Q;s(AE@G{0r4APN@bT%tsba|qWR0+ z5O_S0Itq1aDYKEK7f5GGs~V>=(B7=@e1Pz6O20G^;2%UkMh|&#{<4qUiwXz(01F2L z7PN1Om{55*B&zPw4x2BTrHxFqdv7o-{hcS&V)$G1 z?#TW(dz))A;(m8_9SNl`$qfU(aiznZUyJi7bMP11bo0?N$NE z=mQY?-!wqg&iFrxXK-An)MrIN;;EQu)KvnDg%a7c4uPf?01eeX+E8E5)rq+WX*Lb! ziZoiO@dU(|WIRWL2923!K)0=(w*BoIALy}-g@YOJt`RsTh$5)pbXIB~{h|y~s%m3W z39|7uO=bJRCPUmwD^mWJ(ZGX*C4G)A(^h$GI1LIesqU!O#u+xBI?KG#jZi&mt)hAxyU4fqn z*n~Lc-E%U+Z%5z&0uZ%CW|+0(^pCf!nygtX007D-fSmKYfdB8^L_&XUc=}C;4py1~ zWaTKl%JZpe)wY(ZRRk*Rs}KROptPt$&=FEP^7Hv6Y{-%&1-YbjAm~1R_@rAT)zeGg zkNCdx9_JVzUA`Tn_VO)}=Nqs_Lmni2ktUjsYbdU5YXTW?*;JQPmNKt{s{SeRACD>krHd*@6cc=i<0neSmM0$hy zAk;x9&a^gaZ8Vxy$lV9Fb0F$j@mNLdW=-PSdPr-DHI#Ls)}QW}kB4?4g#> zbt`e)MP%T?n#qBrxU#K5=adF)o7~N8Rc%rUlY-W(-)AZo zd&G zryXE%L=Qwb;(O4HV)uDq!7O87>%&oL;o@F|d$L^1L-4Uef#dI!63<`z zL=C+7e}&MR;4(_=8EZZhEf?j`&udqp%gS4*p(LlaFD`%AyfVUp1^M3k#(h9YOosta zuI?;b$hAh0z8tCAx{XKPit4U>0lZ)?z6NR`cqgC=qd0?envD*JL_l&9l@bbA3C3ooB}O|< zn(-g4Y`^*BMX^si=&w*gmob@j{hinBswh_v5J&A`&8V`<>?(x(1)4@c{3i?><;hjB z6}INDw9O>M7jWvNEF^8xy-mZR{0F-?_f?|AqXfEEW~qx~{2gj|kNREG3_RI#svWPO zsH{>wLB40^*vSl6r(#Fb`7N0?t?va=;>E&^U>s19NHBguNeA5npp`X&P7+1p`< zyWSsg5sXzD#C{g{4AORkY0t`a*BzjA)Um#CAK&N{0Z#$+$BA!H03%uE2CAAjAUcl1EUIz6hA1%DxTtRZF~kQpU+J516YVu#YyG9%e7W4m-}gq&I-Kp0}Ke>WTg25gfhJW2+G_hf`SNs6O%pvg=9w&6=d+wk?{)k4I7W{Bze zOH%^ifJp?1|IB@UgG5u+1><-+5Rq_SDg#X7{*Q95{sih1;S#R?SnqLgV!c#`H>6~SbO@xXdJdOJ9L z_gd4tMsVfruIde>)maV%(ekEOlN;@iuD*_DS7)`h-LF)BTDPePtRrhTx*MAzu{(v< zZIJlT@%Q#QFCgr>2b|f(P8gS?K@#H*g)BJ7KAHoNSJ4by49NYwqrvf^W5SWGlMVOf z3{VsfMxl!RIPAGg4AYj-8ynceW;Ys3tt?(OsJZZjAun#Pps;!eJ|UT&tX|>W-sy{G z7)x(FuTl_tL(41IpR0Znz~k=)hqChYzb&(R2@kM?cFcJwUQ(f{@?~pDn2^&@liOXs z7i7y*Gdu3JI#=x>}16B-HksPD)q31D-W4aSNwumc^Pcu}OuJ z(%;tf;C`4saeP*gV=uMnSDUY3P%6xHGDTpp|N$+_r>4w=EJ_RbE|BhvTc9? z)>B1a%WFzvSsNn_>E^nn0p%mn(&hsnqOC)aY23Ud&q?c&sWEi1NwG;azk{u~RfqPH5AEsbIvCG)4~=sPc5- z^Hft&q^nl1G{Gc?jPhf4{V8F$=Wfb+e@^ae(k|V%{o3=zvob_z@plDM>)jV5`5kbi^*S9xaGTU8!s*T70rK0VK?4~nnH^!^%-Sdw zLw-1jdu@N|aCidJTb7*Jo2tRso2(FgX`a|ziC2_JB>n+tB>oXeDWY(_ouWbdTWTrt zaJ~JcL5r+>92?*PDy)`_8R(Wl+na(x4W1GM$vqt1A4C;(ZKVozP{6J%LG|j>D{2M? z9BOqm+-e$8s_I6Vp&MT`hoGozr^>DP?=(}~Fv&q{H1=H}ooZ_k+Y1g@B7GadCwUL!m((_9(jCbq9j?>bDFIs#HC657Jm~I-S6)q47civ1y3bKV z9se>mYJv*tqZ8QQMx`{%nUte3+m=6Oq#;|nsYX}IbP-EceCLv4Ma-VmfQfR4W#NGj zqPh27dY_f|=mGT|R1>z*{Mkn(4B zs=ZC)5FW9Mt=c1%@8SAN1OmwARm?=>**QN5^QKPQ6S$nRBIsW3(b77+%BjUw zcsK70r15K4$9gF|pSa*RXzOwqWKv8mrN5^By z`OR{#H04!w!Q0TNgx~iEnWT9^g0fX7!vXKECU~c6P*u?6Hs^kiPheN_BuRAXV<^r3 zaf&D2!Dh|1ao||9zyT>D#*@4krIA~`)tVf2Z5zb5l_!K4svRhfW~xd|jY^{4wo0AT zK~;Blb}Ykl*qq`K`t>U`B6XZLaeKGf)N9Rr<7!7%ben-&h5b8jbdlnxxBJFjwdeE$ zar9-ygpM{pF5YA<2$;l+0f=bVg(z1cVt15l@?UTnt08F5pTUrh36RDbZ%DuA9m2dy zLu83EFuI{-aL=DjHf4i-I7VL*DXWlEmDrT0o#A$cJ@hdNCAm!#CrQBN2tOswk103N zFe;##3l>|;GMHZ(`ciX`%%(Gydh zAQy)gTY}Q%nQ_ELfsLOO(?(8w3G0K@e6v5h7KUg`|=>F%`? zBf_d_B*aXz(9(Tm!)y}N@e0^AOXQ`5U}s~j5&4G@uo2r~cB2gTO`JFi|6;dUuscE0 zq~{bD-Zo7Z&Lt>GKfe_*o50Rq+fG5iH!&Q?ASm@gLPqp8gdFQR*g*md#SEd}Bgeq$ zT|#4zb4AWG-$_c;tfbuChwqEX^^H$uJJZu2jJcgvjjhS$b3wjs%+22wn0U}9!SI61 zhU97|?K(br6RdB0JtBI51z$Bu)=vFGTcH}ZIj9u8vLuq!@SZYs=-aT&7fQAzJt!J@ zoIcZ&AwVaz1WJrhYRPtVz&6hXVvQ+jjum6x7P*2dQx8OEFpw5fK5YR0sJ2O7Z;3Ho{(DyWc{BB$qr|4 z%%$DH)W*hzgwFa^Nt2)`k-j3(_d&^CSYXtd72JX>=o$5a-xpTslA|)V1jeBg=Xy@> z>&AY(dV7G``SF6U!@1xr;9fAPcvUCeT(+C8*y4<^ok1OL`#5`B2YH%1le{6@RJnSM z;J0BrEILkC#aA3RXQsk5&-*tpA*C{-qNHx-^T4kf(C zUcNqax)ooVy7)n8n2{85nwgm9kO-5CP3gRt5Kp$5t%%LKK=$Jl+hm@xN;YDoPBW=? zvX?=0nnmhO#Xlg@gj_h!~|lfpWF#?8&T<{B&k})BXVT8^YH^VzVIXJjGLfGzF zgSPhTZ(A^OZKN!_?xhWBN4Z>&9_l3cym-UhjY?Y(hID=j+vV-TA0bLH{4y+s^H?;@ zq;|Lo{^Kd%cox;GXvZj|%-XumCV2NO1D}JGZZf-FdyFC1-r(>)gk~C{7E3oztE29T zPxuE<8499<`8*voahZFT;B_!{)g_jvSdC#AlMYDNWVaXik`r%^7L4`?8~dn@kG~u8 zTwrmAPQ6-`UoMBzdn}k-y=92{Q6>+?JuBUmICM*0AZQ4;=Jbvy)Z98uyvcGw((8uu zo8Iw(Z-fq4E)%buh8~Jqe5y77jxP2fLw@m#9mC+&Wo8%FO3e*w6{B_~T;{t1l3V*2?$b;y?R|r(F{R(?f=bW*q2367lZC?zXaD8W^Ni#rxIj^|a%JOD~ z(NXhwT@=rpEo*RrnT)09D-}N;lzZtNGQmp*O4_DLY}TL|y4G+$Q)bN~H9{LaFlBlt z+q$|jPjpv~<+WA8>G3PXq*-U%p_BY^gCDE#_`ye>vHi$?Wb<6&zT%i`v!qZKf$=8< z_gmO5a5Txlx}7zlncpkWQUG|tk)!ldF-@Aa%&a)OWbQQsk^|2S9bqVxx!){b(7992 z1&2Ihg4ZB*lW($(%?zi^w91isoy-G5{^TTKe|j#0q)2QYj^T~?sGjm0tCCN4QpR{J zVzAJ(;SoB_662u4C=Q_uKQq$1k;tz%h}+;Gk0|KI_ej&8^`)LB{$|f%PrQ!+pM(3_cJM{{aSVpSV z;qdAhz&@CS8>Gafz=)C|OO-md(wo@I(P8)t+mSJNZNlIZ#5yhVWYrow2OWiAl1WC$;W3pI<3% zDOXaYMB#UDkEXiPNo=p_Yk}zOF!E6K`Fs5ZbV@9y&%#-ayL#PUmfUd@C3ENs2hmWx zVY7cYkwb4oiUW@fl;29tOK_qdFR%`KoF=o%?Kp|jr3RiDBuL5Q`kM-_eLvw(i3N_1 zdKKztGvL-n9Aa`OOBD02F4c7?%9(PM;>%vGcd2C}erqD|f7f$X|7O;4)NO`c!$pz~ zC&PDb>y{X}ox>K#=E1A6VQnz}7)kAaAgAl3%+9 zLZxmyBU84&P7ArtSV^Ouw}$~%nJA)Gn}v;;rqw|`0@hq{k=f=XMh&A z1q^C5ar+(OXvK*?s`6EmhD%Rj;ZQ^pH)*_=qBjVLDQ<|s{vf<=nVZ&ogYH2WRx^5c zJK#@>hScV2_I(2kPO9q8KLI;K@1XsdallT%R^aUjW>PfRXcIW5$4H(fcZ&GOyCp|U z9*-5zQc%3@18?MZ+?2l5!faM(lV%uNW~b_MW2GueppA32*I zEc+2XK)x7^QO2KsUZv?^E4fK9gUen@^7+zeVp(CT_G~B#tp2g6qf+BGmQsppDI;NO zG$9L|iQ^$cJqP^Lhof4T_u+e45^A>|a_Dy&7T%OC13Go4xw-EJ_DsiFz~ZQsnZUrT ze9rIR#f0Eb4DdgN^yD%De>?LG?>`nX#!lBh!UMI1NJC4ZWog;<5e)FwmasyRyBXQ3 z+L#mLBwbBJUsfPode+>s>sH@mpsW#Fc=_|{y~z2oQYP;Xt1B_LrHvnbeCp)BZ|kG_ z99hxqW*&xBslqJvWP?(zmNS+nHm^2bB}}fB{?78&rLECd%9n~^P5hXVz-1Cg+$Vk* z12Qg|B*<9vJdqcKLMrlO7RNLU&Q(v*!zD1(`$B(E*7ddLz!Zfj@J#B*Wdz@qgax}u z{_xYcewNjfulHxhZ4C+?bc3UIYny>kz)po*5+@cqHj}fH;UYN=Hhw%-lzLb&7C4!Q z=E4&(Mso^nv_;MxzDCCmi$FhB0r1!NtI%@aNa!alQ|?#x4i zL9P_2C+JE(YXJon6W|WC5F!t_5O4=yzUzC&MH;-=39!OLuKN|XuiOSaliNLyOi$lJ z+p$gLdZ7LvRZfhU79#987IxU`xF5V0#mz-#R-E=3&4(N| zknx8_HbRmDE-*2Peq~0XE0U5@gqEkOt14@(b5w&0S2JjuHkuL>ijxL5Yf9^i((?{1 zNkaL#7<@Ou1{h#H%=5P#tRJljR=6n%V>_7Fo$trjzFnoMx}MKS0HG-Yzg2%O)CWh| zegmG}CNm|l5uW7?CpGOJKL!-5U%x*umXC*W`IfcI6izREz0oR)PLkd6F_(zn|`C>tKMUV(IvJYY*2#1E!5!VC7paa z?S51Cc(pMgdp7#M3N$d>mYmbl5JDSsg2|l{mJVqjBd8TCj)xd&+b@yPkv#zsGV9?K zSZH?N=;15Hp4em%Su_fhG&@`!b%IZ+&dVTDpoOHylZsZ-&2LtOL^M#>oN+2Z3d#uT zye@@pPidTdIsCO{_bZm+Jsehv0X!qgfb-@XKi)l_nSxkVkp6|fPVjQzdh=*T9dk%} z6{4!p9aix|qdDy6Il4*#?jo}!BjH6~h*Ss;N9!Q7Q0q`#ItNvP*b-Vglof?{e|Pk( zk$Fy?S@-v$Em!C07PNCQ4JKgtPqpXJMC1KnpiueT`ycx{a#I!Nk8i8Gy zY_bze(kZFo3(IiNMyF2SQ+nX-V0I#LYzM1BtoJ(-i}dzZBH58g)hk&gUrl0K2`cue zao~3izVcYgh?JLte#$s}qUss0hwfC>-f;tob@0O7R=AaovE5~iu{BD`s;Z3L=YFCa z!5GGDQCEzXkBr*CCESz!gZZXzv0qd6LA6UH9ADv5F}W(O z)@sd$?AWO1l*=(=&~H6sQjJ00{rDZaqWJA!F=LrF7AP{+Jat{22Srk_em*Uvt41uH z`SjWeXEQJdVFBEly&*h*N-?=HTE%xVrB|!ScbzLcKgo+&jY@UY7|iuciCdYEddi4x zM@$Lrua+geEBdI=dyaI@ff?g84K4Qlf*(X0xmk5P!G=+&^cyvHRjsqxo$Xtgf#j4Y zNG=Friu;tK*;(mi(ril9m8ZurnM*;kIb=Tu6*pzRSb!~}9ABhG6$w4WHKhcwkYmHm z1T_U4eGdn$NST<+n@b-JfUW_X-4SG0&w98S2$UFS#ELue~i6@d!5_bH`-V;HXGZvlg74fn@yt`+idK{ zw$n7W?KDmrhvb>8b-`#*TD@!aDcH-1>fyY}9t86(fuf&a$i%$392b{Z9E zXH&8|&Gvyts3kBM=?XF1u9#RDP zZL%%&s}YS=QX2Qf>b@=b{15Akej=T@q`sBXrB5+Ly!gGuIp>87f;zrd>zLY*QFjvq znBLGA=zLiD;{#%@mk~Lc^|01ywSiV}m>x&6&O+lMBu36rRj<`<7IZ<#&9OGQuE zwI`i%6F*+{S7$Ru5E-pDj|eidtYv?%&rpQA$6w(&6H+)EOnm=RiqOJW@Gk9FJsAaS zy~*FcPJZbOGqZM#+L&N5u>UOmSYyPeS{HyTZwIA+Re_UW`z(~VOKip87>)JZ4g6%! zy!b@RFS|{54D3nN8d@WS-&Rk&L!w$8pTQj9JE7ZqWDUG5zE0@oZ=OzNXBC$`oRJ60 zP9Gc56>6&S$@}2kv?dtaSrT!v=n2Ef8%$mC8`p6EM5WF;)OZ(ZTq8fnhi_cNEr=|^ z$Y}nRF@PEC!(N`ZB(b*Hmhv(A<25D~6*|KAXP-W$99RyKSIxGC%SAJVn_(X`W+A(w zWJlzHtd#+&rrwQ&w%knD-K{}B%l;;I!E3riN23#%zo~zI4*HQkM$$(W+(Taz09&{J zkhMtfCPG{MRFq|JBC++HZzM(HA7jM25~dFH7fuR}Wl#uLJbn?ZpI=FH9X!Ee9sRb+ z%aiKVaOe;_sM+wZEwmF!pJ+?^mf8Kw;ndQ@2-P=yfGR*m59Jx^cTkJo!mCUxp5kFs zDo>Q*hJ~O;_Qn^~d%S{mROphg+d9Fm`Ui>wYNoiaNtN>e0XBM5Rd33oRH2?8Z4c|} zrnPpvy`rC~I#4wCyF9Y_bp6*}tYpzxF;>)16!RooS8C)od~K9^A9!a-pI55r@!dF=nJe^ox>=C0P34vHo=|7X+d9@_=d`bG({Bx!zty2B@GK2U6s?+S)o(avz$q#cn#BefloPk!~jQsZMeO0m6IwtNHe_meqVSk<;G-1DndDMJGK0a%n{U$R`$>(~M zo8fvi?kDtigV+mBgnK+>1#gO@xC8HSoX(tQ+=##><|{i=6iB1BlaKOVf;eu(d3Wfx zzNl;_)lqPfa?tQLP`a-C)oGBqTUm3#pCl)Es9+DKp!F+Q{dm0Iby2AX?yiP$nuzai zM^K*=cwfpgPsPkmh59o0evNlszj<5h4{*g)nueB8@AWI%3tk=o+*mV$2bFH8GC(!; z&GOz5;ogq!qH}e>iLl!cwFpeip^_v;6SKo$qi{JhxqJ85t@)duXQ!)jW90%6o{m22 zc;s8GH@fGvC25Qx@JwR&_>Gj90>hn;(|DKhLU}G{cgnlBQZyp3+O%)bKUs9VAOhy+ zv6qzz9O?r6z;O?xkg2riBMm))yY%b|aRU1J)R)E!mU^xUvzQ6_Wd z@n$-Y!;x9J2_01wx4*FGSMEz2-;fR8E$9R0d1!kya%qpR&2X+92D73;uW&x8Xu+#L z4c-}`UEtd13`0f|?=Ozx^nzgH3R7>4y$2O$rqW|~=tCu`lgWJv{|V^aSadDi0o_^v zNaOJTFB1O-%4<^7cbsF!5U@B|(imRGVeXa;42wLUk<@@+qX}acJFFDUoqFa< zF=`=}sep4)*PrUcroh4gHTp+ap9?Eo=(LXTAboWP#&Enp%#j~=o0}bS+8N>K*89|0 z0>zC7Psr9-S?OtTLUM`YE;@vbGr|oqc&C6DY<5}>O>N%Llb#3OJ3p_xZ01H6)J*&7 zY<7LfR)wFiwu(K0{vv`pTAoo@bB4}C#R9yndhV?ewn!~j+OccP&R!55NRGRy18d8! zUND~0c@e${7f)q%<@`_=b1e#wpC12#+)Qe#_f!GJNEaw${V!+}aYs{kdvk|>!+8ER zs{mSJ(tHjoBi`*h9=)HBihxlF$3{a3kWy}@vIbI|H(SFL22A{=8(^Njh!cwVI~JYdA=4B#A4&nU{(&X7G1-IvqHqm zRQpDjQdSp7_(LqQNHhnQTR&m!AovAEp4?bh*go=ZOra$aW{Tb8WCLI z29j>4V4jXFpA^$*zmpxV&RTh{q@s4(x^28t8LGHQ3vj#usT`_zVB^ZT-y9wv2K2AJ z>MUD?myB%e&c=(lqhn=*Z{HZC6j?@YMPl~|V{iP9z|ysqw2X(MQ}XO;^~-Ro;C-Ph z`?~v(wx`Qy&Ng(2!GKf z-yNjtN!rxH7uXqo$SRKx;56B!DB0ypXriJ}rz|d6JaE!aTv%{&5kA+<*PV!4zJk3| zkGOIntMv0`W~`62ZSfq9wQaRM{l47#fV?7EXJ;&Ajp5(Sk;J^T_7al6h56+|CiX3k z-7i}bJ_W;};t8F@uL5|0VM9|@1m`W=r#bfsXklv&ZUQViYa%|(dx-rI)a>h?HnMt5 zBsp2;>)tYJ?OaK9(Dz!LnXuVt%!Qq*#@o@3A+deY7{Sb4_cT+*$z@Q$xjFJKBXddL zbj8c1;R`fc4)6bAN0g;FVKaA!w;+JaZBWPw-SjG~c8PSes6k`pGIUMQ_KVptTuz_g zD7@x{^MHd?`GctrKBEQPSjKsz!Bb+uS{4-m78#=)?Pe*p#aAaT%iF!Qc!k-=XTThe z3T(*LmS-ViVAYT^YuS??!Guv*E9Z)cKaynwOx7|VTIUj}AugRuB~5e0LfN_K4RIhE zy4o3M?d+D%#p0${6Pwt_68a4|L*3$e@Z8r<#q;SlHpR|0O7t>!Ty!w>oJ-}a!j?0+ ztd9iZfh60a#DMkrS=EejA%bcuKjj0?VA?rc96~1n^b^-8aopVl4|rd$prQZw&gGw$qaUL2iPEbL*$B~o+lQOUZ?zzXxFgt!Q4SqO4TG655 z{>n$PNiW?hjxBz*NAHIESE%6kx#kXkqS9L}NiHA8-KPB07T)9negiiUm(RX}W~547 zS?f)5N`l;EdR4T7vrtE_6SGiK?HjW~BnC?Ns@q$j(_3ld&o9h0f@bL?ugqyG3LyRP z2VQ&QO8x8*C*e4$-1n+)IQ6FydFmQnG##E*)Gjs}1urreZS zsy$syxSu%gIqdt(B!I*pBpoLRLYPUyRwE??DFR5qeb>b|5zA~F zwYqGY%EN>+>m1@QDOO|KK2|KbvJCyY-;c20wQh`x3gh^o)mgJ>qsfC)mk7JBxGuiv zF}=d!6=REY@I$7W%{Hx6A7oI6~2dpy*4c!E5u9-)kgN+OMq-=vIn`l4l?b%fAb1;62^ ztH*2P3&)Y5pW0D70CzQ*pl>T##)q7ADcVt=*Oi^IA28N6nWv_YmOHu)EpWD~Wm>5D zZ5{ilU4D06*$vnk@t831FeA6eM=2z8SYW$h(*vu}2%J^@$-O zcnvc9^=}=3d4^($s1KOZ+q6d0!T&Ud8v~HNyh3pOTBpOUG2iwo_M4ztBQ=s@SFGr{ zh1mFWuA_a-hNp2wj!}uX7;h<+$?NIfM&;I$G|{Vu_hji`NLQ{RGer3e!o!@ok~8GwA`(L#^$B7b+S>FE{{1Y6%GA5xCo!ypSZ z&ht_f;i|q8gx8DvEZRuXcKW2D@gBOL(}E!8=nZQodz&k70e&R$yP%nUP9zQJa^$C` z?28S_$P0F=8Lt?nBk`-XUc06fPx1XXM(cW_PJBhFgEg+xMWM?NR{m`e5GC3EGjrVL zX(VE47L)%59vaTXLS>?4o20@Rk2?R$3edd?yE5WiFVc6S0Ph;6=@G`l5M_`CF>_0p zNZ6X83y8~h#A^ln`afhs{;H!^pZUYpL3NZTsE+#IF8IF=>+cs_{kO`TFvdI9Dzr>| zRGx;CaA!#5;!7y0PMK9QIF`iqjp^Fiyj3Q%^l5L$Bg&~1uKVzHOMoBZ_x@`;8H7fR ziSfg;3!Wp81DE;3(f67yFulG?Y9x~CZ95Ex@Rq{Qd+?JIsKefEQjL4yjI^y76h7J) zdMCZ=dP%cOg^isg0bCTOq><#5#fJ<~s)VgEeDEspCAg#|b;sOT12a5ROot&k0saCB zdrvL>oM=A1vaD`cZTh>5^iwaf9g|LeVNRRQ5~S!?rLraFuxS|Wtw#|ilR8_gCOFla z(&wqf#XpOzv)(ZV)a{up?Zm1mvRH>xaYfl;NpM!v#)Br_5@l~6$tiGfybCF@DL5~n+44;njre+U1>&rtPW>SaswuH86}@Q)QJC1>a$|v} z2j+y2`3Q9KD$6$WO3qyg04h!;-QyEOHyqXnFf~QK(ScZe?&{adwY)fI-k?xEgPNop z1mS0r9%DQPvnU&!LR~4kkRp_cL7~Du1T~;^W+(_eIX*bX&HVY&`fa1|mA3G=PB`}l z#L=_Zp81_zh;{K`e^vD6XKrrPh)~l6rej+X`d1QW&qT@a=$ry)Jj-Jy#CsHTafm;W z#KDpuurn;%On-lML$%KgFF+YA4V1zDmpS6U&7}U{IigbCUrCG~#3l<&OmL8bol!7| z$4SR2Q!7^~f_L{Mm}_@A`^5?SH6{>wyAXvb#j1XAtfRy8GUxT{*Pd>$b+Rd^1mnT@ z%j5v}ZpO06vK({nOt~Y#z!7q}M+_RP9&2=(Bj>5k54Y)JWyQtz*3YnjmME0pD%x${ z+XePl*i3dP^(6iLtkH|KL_vp`3^{Uqg*jLmHNL5gDP{1sf}<{TX&u*QI^1oFT{iNw z-a~wb6D_;?PGo19*asS;Kb@A2a^dXN+*@US^)d_JLc6+VhaB%5dVErlE&6{=4KLJrshunA)NWE=!2}< zFa)>^@t4$0XE~cS?IGLu;^4yX#rqDkSHF=^&sjvP!Ko?Sma)3fKzv~HH=|6evGGQK zW-uZQ7u@b3X0!mS>z`lOPKGLyE>Bm~q1j zABLj@6^2jG?fRh1rDvS^J#^SC*M`RT__bJYX)WHu-r3EM7z2XA89o-+1G#K_9X)T( zMM*?+LyE|ZFr6=wIJrV3>^>2=NJaO^7w&`E$7g^rQ?^@@st>V&t|C~U1SV091%=o@ zR#pAN!xU;tbURp_a2e0GFcWAxS6g+_KB~@TT)+`w=)MyD~j~KtdB7_t~e656ynwV?SXLrgqgnG=cG6BQpHrUsN zHs62L6G?GSVDpSWKwiEQ3^tHYuvU!!v5(VC`E$)R&=}k@a`%hT;ZHj0O1iW39j&X? zfa@_DL-`HDnl6r^wzj-fct&UPSZ_!82W0<@8S^d7*vj62Tpq@C*?TciNRWccR+9g3 z$*SV+;AU-aF5%+xZ_mwmSw(ObkT|Ay42lv_0l&r|A`)c-i*q0g%Q3ilG4~5N;{14{ zbm_67%UI-K=wHK{PBG>^@Y((B$+wFP-?@KL*wd`Ahe%~6=)Pp3`&2Hm91KMoMi@J=ZJg5ADpw8AULoolXrR+y23<XP{;IJp5eNkm^>Rly6oxs3ULM7;f+yS zy{AKj-)bO?%av%#7WISwrZwZ6uJ-z(@o5>eS*~|}X)aq))heo(kI*SR5VM789i58* zU={@4#NE`I(1IdFZGWR`#+Np}9IAumeGePfwG?dp3`JMG}4@TMZI7(8*sjaxx z*QFQ6e)GEA<>?QzngMZa=Q7!d0ghxO9TR+c*snIAO=v3TAi*YeVZ{p$P%y5$+?kzRd}9(nMPkuN*K*6&P}PV~gYkaAMhKcPI^ zkSRP5W)K|ni0dN|z|(^DYi=Bm58Nb-YIq5PIGMO5<{WR`!N{E*(Ra7tkE|=vK?5eg z1s)npOdTw+4ka(cG-* z*|JuVOf)vRju);ak3{U=+TXP@{aJfHAe%(}BZz&#G^R@O?a7ha)_=L?umd{@?xS+#W0 zBXxX1B4*t8jY0adlC{_`0RBKKj+L6xKv;}51OdPZ7JDuxFx#> zcL?f4oQ=ykh`Eg459cpX!DR}qu$xS|M^H+}9SjG7f29XIW&17)$z%hv;p!YjSvOrt zT^*UuJmVWe!Eu34%x5!9e!A86)oD$wO&M{b;5jRIQCNN2t#;dVHuvdq`K9sR>ZES5 zd+8~r(6;N9n%MMv$JIoqsPY$W@rWMH7YafS*jCmWyAy9~TWKIt$6HXF|5m3yQtK}y}TBtMz$USYN~6&-Nu~OikFDmHg!7 z@_!m(9X4dYcms#Dg5+E&wzzo$kV`V1Rmd+ObYC0>2 zP_I;rXB@B?n@sW;Q=Qd_K!7vGM#DxIMWxkLpT#d~=z>F6m$SWrS2q#@yPJX1V|RwD z$@D_3VY@r&O{o&?Pf41kpfeZci2!0y&;~IkM{qf<3}&^;VH)o;a03{A&BS%t@4|29 z)3RJMZn9kq3g(4#6>l`t5Mpq|A~#)r&UnPp9G!r+^r6x(UC+8Ar+J0cEZ@bM^_=kT z5+5%5lE3Dm8ByGP3&ptv<)ZdF%Q!zLw4W@~eE^v8X|te-6XkJesC2i*S*%fe18m42 zOx3;_rf~<8q`J*IEYw%?l6DplK_j+fAzKqihz63R5>zi`epr+^?i%!aDfzI&NDU&J zD$bE>ftyj*uT(hxTMW+Q#eTb4&Bf?1q&G;1R)kEmGJN%y;3QA5ohzU_NB7p;}Y> zs0>H-^U*Su=}?wyfqU4`;q*yJJj@Qb7ryDNZm7w+i(7;`4xZP>@v3tv#yVOdy|A(` z5Ez%sq?j*R@cJC1_rN_bftP&YoiSK-N4FeYQ{n3Et_JI8AAW|FTsp&V%#V6>;=f|h zQE9LuRQwUu?B4ReI1!L5#>{~{$viE|FRphvFz8K>vlq%E4!$G`vEyf==RK69__ zHW<`!9PM#}S-L>qeuP5NrVe;B>?d|}YYIR!#Q~riit!U5Pna?+s9f=C*pB<__YD>D z4DRiCuPc^G@w3Lc1HKQ;R{jA9nGEEia;dm_5j%|Ui9mnoH@N2sI6SKmUdKw5$M`f+ zFW_EQ?Wh`(5a3vS7jd%KS<-sp*cyb);BL6e;LKOPF0mNWZ8{_ZYV)%THe5x;vI@xF zkw@!tkKz1&M}H$gp8G%!;eN)hMb9D7#U0^{Wgj7fyaCfAYncnWf9p-nvU(zi3tBy5bF_My54`)8-&58$pZ06o=1puH#8f0IZ5C%*hYnKVajLjhDtzeBGg z*<;s+TQR&77uZ8-ph)P7=cg}2&Pxr2bXfD{BdqDy^HDqk1OpYfn}(^qj63fc{18p& z8-CntG8i*icueuQ9LI6YfL@X3l@%?r`lPL6%q?DrW6I}x*miMW-`U57%<8wN8r=8RpbWNCXZdQcAr+b z80dt~b{f>2H*6RUHx3 zQ4wlleLiX#JueYRfBP+i;juXAps+7L$})uFuTz%{5_1FE#@mn9+fgJN>q365I>DQ9 zI$m*UE9eAR1Fr)H_hn)+hSWQV#~XoQ02eviY3CeM$pLx?r*Z4n2wj3(Jkr()=PzRL z*0E5Co^?{k?CS&mh_YH1IBy8b&9>A};@pvBdk0#^=_fLBY#%%)w7`>U%TvrBggC2M zzM?hM1M>|syrL_U$_@@pa09~KV8iid+-<8;Z%VDj?&aZoQeg>hRFM)u)$3I-RV`f~ z27BJRQRekeVz1%#C|$7Pw0FHg?iIj zYSq04X|C0;6e@Gs%4HPGVNUsHbQLmXZs#IlpkSfFG^)&&w$-m8*?xcW2lb|>2)pm< zZ#eJhTY3QCO7(iPRGVb&oQRXG($TtA2JJ{D68jx{X87hD#GyO=52|B2QNF^B@2{Wk zOYl(0_of|NzJ1QVPbs@3^hvy&dEv+PMcCS(2P5PW|F(mYO>z+Tj65@P1Q(NhOSFHc;EB{Xio}*^3I1ie6-(TeE{UE4;kMyCUeJIdWM!CL%Qr;Vy zV-uFz*R@_MTy|ixkLwM%3C05}jQH2m_Z*e_XQ)+@M?2dTKU)J^N6*)Q4>%+EDYZM& zv|(+%l<&?^OKL^&s?LO5YI4NiCBcS>lGWA+88FR{1zLX?sq_&-dE&N%6E$Z7-kONr zmRgyYEbl1FE10R9YsJ=_aF%Js9ibZLiHJ{n2WIZquA~^+CDaKH+ZGV8U^~| z$FVB_r?(7AT*Z`1%tOrW%V_!MH<*02O9X;UA=r{gU}BtD{oL%wQR}s*{VOGBKKT6n z;mS?nOorj!LvoOl?%S2^4s`6)yvD1LamY{f$7uJ6oJy;(`7AxRWPA zF0sB~;g+G2oi!lr=mr;O+h?cB?q(5-inm-KE@)t1xdTQEf5^@cX@3^qUOPE~+-zlL zZ+y)_lssk*701Ef*BMlb*4-PgTnTfw@?6O}a8@oYJ{aauw|QrelLfrMDada@H^bo( z9r=UfQ;>8LYRtFJd+aptni(-(Cv7aHx@O?3F}5?phlScKKOZw&&e4=V#-EqWb~po$ zySdM&RI~WrW{#;XV^^38;!k#{kv;hHA~*ds@qO0a!rD=h+S^ru3Z^PMQQ|oGg*w9% zsSGS~5D$zjJ=9E@n_+xCfD60sfftWuj5nCpAQdT;M_1q)|3=`FC_Rg8oZfw8<(_~d zotUvpq*d1#EbeRvGddNIJm4K2uMK`AO(~`DA$+<))NV6WBXw4gC0>7r_zU|EP~@2} z^QZeFdfvK7_G|R9z9kzjqE`0c9L*J3i#@$RgL5Y zjQ9}JKeyyO&a{yPo6#h()=-A<_2 zMFdIXwmQ^+RWT!NWopN;e^v*p(IclmtXU!by3Cti_3jgC%Qi=5tk!n~@EK}8&zrFU zoad7$gQkOU!A2(9Sxk}mhKJ}Q89_tzuf!FaV|3z3H^1f}Bu42fqdK*B&A(VZrqA}q zw{N->Z=lF}7@_-2x(kdJpSNN3*AdBf%Kp@jk(8yS@CIsr?^msO3DQI`2<7vJ_;Otj z3<{Lcn{is`Yd!dC#oUR;{9p;J!0RwoN|2P#pg~CCi5L_oQq6@r9C)xFv5n13Mfv#~D+x5tr#$>x|ZhUt??>54}$!E3D%a+F`)$bZmHIYpf zu?ci1TjRsFtmYg-O*u4AtyZdbrb9Bm@O~xl~o2~j_X{T)>RcyI@;ShU%LaVCh>s<0JbuW$R#Bv%3{ief!}h+!u`J zw_IS7l`P$M6Mtr}IYW1VgveJXEAl-k%vLcjW@EY*-#6%Z#9-x2wa##e3{PY48^LG5 zt}=hgt}_iX)HP&oGNL9k${=ZxS%ap8&M7=%SVBTqm0dJ(>~>jXc2Fk}bD4A`3?m(n z9%Fx;1XGcw7LyzBE)TSB&BC?O)p=lFh;Ku9%hEr?rl*xjB#V7v%d7(smsT#pbxC}2>jrXiqmkmC)1So4!wj+MH^ z;}#uL5G^R*+Pj&bA?%!~Q*1ee(E4+##iNL9|UGo*C@ z&CyPW%wxT+Npi=JVDzoo`fBfl+@2enw@(b{hFswYZEI8ce{%;W!RIbs0~BbyG)AoX zM{2iWKkr@>aIswrRNJR#REvw;J?qCeS6EVaoHul=XB_Ms~7%wARKPC<(wLbOw{2675S8(tPui&sZ za2OZ-#~%13OV#0wTB@)(olDVrr#p9MrqS@sHJqUORR;gu5if{Q&C9q;2VWcV!XcJq zuYJKz3ERvkJ)LK}PaPAoOs4lMl7^a3pU$zU2oWl+sL&CI^U7-YFw{=>7puGsZ$fP9 zd`atW+j>ZcJD2=nr0D}f*i}{cNy(_qEhqbgnghW0!&8EVp6(nsuN}>zT@4l_&hkYk z`3ZnXA()gLwBAIWgstItao{m*s!IozWbEK*{lR%*CQYV{T68Vl?&`%mf#Pt&VBQMD zIpY&=te~x)I?*-)}onpB)>g~OSF8PZ<4*3Prie(Yzn+(3YfPdr$CLyH$1bK~rZBTYWJ zwVE*_*M3SBUJ?yQKu}Ml8ksxASWeDvt1bY}Tr@|UK5u9 zecwQmOT*~TPrN0mbr})O^xNYp%{d`s=fkuc&Mnatg@q%1;fXm`A>|miJmQlJq8?UU zEcMUbZW9R}Mf~q*bX@{B*2&`|j_}Q9zxEE~FqzCJE8fvclvLdlwup4K{6i70zW<2}#WdXE|AT?0(Z%CVPjGbzPJf2*!X!$Tuh)-1|Y*Pp26g|^Hu zigqt8XN)|jK2G%s0f)Cyy~pIMxGqN!pUtr~(rh*Gr#cTuP-r7jG~}1*pH4)!W;GEz z*z~8Id`n$*0%?BTh`_*KU(xDh{?20wF@@&0c2X7CpJ9Rh6C`T zE25I4B6QY^UrtB-IY$jT1Mfd7~K^ zb>eDTL&X!r$_(--F)9r5)w(V;f&u^YXQI$b!|9S*4T|u0O`!z_3sgh^ib`!nNww)H z_3ONKmx0{(m!CzFT@&P&Fz^51pZEF>r+=ENrs5Mi8waR=w>;3CcKOAh+<$}fV`b@400!9!`;h} z$diHHh!WrfK`~z@vt93xE-!^X(Ho75pr!$tL+gXB^(IXz<06BV$MLQrL)!q$9mw8# z9NQca22*=Lo>r_1EE_=Emwdnzf2HBVK0?k&9Nkvl3j{ znM<8OoleFMUIMazP|)n^{UoZuK{|olz-xXfm$F&B0Qc0=f&lS=*!X6?oLS30U-!g+ zWW&Za>e9Jp%zRCEfj0SEQpiS80@3nzj>^%*$JAfZ(xu&`lrY^OkUH6J z2H)KFvyC_>-%gv3(lK3JFQPFmg$B|A>KyWlH5uS-EM=yiXs4FiG{=NeyMHghuUM)f z3@jHmQ*8jXJRs8a9DNK_T~0U!QoLnN1eNx4BnuhT3&02FkvL`Py0;fp8v1`jA#h3} zj_Xk8{X}u8#H!xS4E+t-Z4+3Z8h9YY(7Ach?ls|So4d~SXS+nCtT}YG_fo8g`*6+| zg?bk;(C1khqqYFno1I{g#9Wl-#4c`u@%^P=DWSz$wp)ip^F=F?8LS%Ntvq#cS@#?UNDOI{`mqqGRFC`PB$yDzl!?wp=bD}teI zHe=Lrv}LkUD36U0W;Nse+iT8OdAn_XPz}gGUJ*MhYlKWZ6bF1un7&E7nSwxnLG}(YJfPw+B;*5e#~QP zxXF%w%?6dLo#(l6fh{beA=|!V6T}JEQ0C{Cq7Dqm{QX&E2p7luHv7li zK99_aW;K90uq~~se37iLOXm1Sa;0~TnL`brH^7Bgjo%uWh39~)C6Qum5*HY>Cr>i! z3?$iNyJA=bRPAw!i9jt~39zBzlNKEGC+9zj>WpJi1*?_uL0{|=4ea}O51m6JbDpc? zKJ^_QG;dvr55}*BX6m112VP!v0Y3v?!z<9fvi3U1)tlu3vjEa3V?d>|YB0sRDLzWa z%z8$-8c&CfXQ>Q_Gvu zXEhePR|XtI-9w=GWuy~2;G5OQyGmpOk;7S5QD4MKy6bOy%((j_6_z@4ZV?RQMXl?d zczfR1K!t01l2%$Z)fFd-ao{Uh(cqN*W?oVi0Yi78l^POz3WNz1I#cLz&PvGq( zQ|YbZ$hpqC>q*f8!L~ncgWJrM@Efpq{#;^@UfPtMEi-9o#Hhy;yXYF}(C089Z|1X? z%PBGdlMly$>4LbgmObYYD&wRsKf#biC!0u-;@I5>A1}kbqI@f!#NH>XgwPBZ3q7E( z^%jS0Z-f^oXGbs{i)>r`ljHB4gvJ zT%n(WBFT=iJt>NaM;5&4q$ZeT10C!Nq)!;C^jR;O{)}6NM>Gy|Qil(t+4*w*!VOTb z{{Yqtp2n0Lf^K~g@~2PC|IK45{g=x0e{Ot^#!CQ(Cg#T^lF1WVTE(R=mKD%P` z4~}K|Ao)*YHtEA6Esu?)A5_C6bZV4j!K zfVuP)RWzq0|%fQ%-_@WB}&Z&4|Puh5KZ4M0h zLQPtu)T)4Nyu`qoBX4Osab5Yx*;)qrv9%rxgq6kk=rJiM+vVsH=&g>;c3*I|>Bqci z9%0i<`}w25)7ahiSdlf=I=_1g_VRtkc#H=^(7zc|ehtC?jQN-j6!g;@qJk96=qI*N z^NalWez?O%D>(KsvOGM+a-@y<9s4mTlBwcR1%BYMKC-6lu_Cgj_{tqLNx%o+!gx## z+ArJV?L&o<@A7AZ&x}h&Xbw7m^5zR*IbzhwHEj#5*%rSn`kZWG&m|PV&1Mdh5}Lr~ zp6s`Bd*-*j+Wp;b0+Q!Z*#>y{jMbJDhWE(#`U&wwQZh@^`DaPro+(KXJc#{b)t-BhPs^WR_HRZ zJF67yUUgdT!hK%;kQSp5YYb*Z!?49@+(YAVW8X`!?2IjbC$k;thzvF0leQx{Huik{ zq)abVw;`*#mKs9LP88UCL<)6VcOMJH$KDj z9d+5HjXeelqxJ6b=JqCmE1o;I*uf&A^(wuyVFheOQm?QGtpo11b;CeL%=xGYDul{8MuVXopT0E{noO`s|3t1 zd~&PGu1U7znyw2{CuA~`7SWaC$KV#3S#*vW`sm%241V-dV&r+64!3U#ZQPEd|3eC~ zSyyL8$>2Cy0`kA8p<7m`;?s4G3^mmd{Z z%97|^G_0>El9_M`aA^Om9C-Rj$M?u7M+-}1(R~J;y7z3M#F#}f)@34@_dcv9v4BT- zQ&i=xDne@OlJF+qCtUTz2rBgi#(-kVaya`3B)*+8vjuOrbq3VYtM{5I*RLD$nmtyA zmRg>&p!YRzqx)enwAOs#6S9o8X2Fw%#&cCxlDahPXvj~w=!q)i6eFi zRF-(+NsF12=5H~REBRQ$_K<~arP$|7zzoRd!3yH`d0K>$Xv|1lRm{xhFK+WS{5V;{ z?YA;72%$;>_;4>8AuSHnVu{i3#Zu+rnzXRC25rc;yyMbZ%HEqLH7<{(O68!LL|dX2 z@KxfS(%vTkHFBq8xUxwfOnloLblOLh5Py(SoVPhhwYn)DUu-Ik{w^kY(T)g-T308d zfPu~WbeX&ylwk4*0U0oD^`rlBzs;2ngB?7dQ#D#o_nI6gv?c`{`yi*2?FPJdx^r3BOtE_M3)tHGU@ikAT*~ z6833FTr-DQRP*J&wpr}tB3`@P7g~Y%uZ4qt)+dX%`S|vFSMZyndlYWf`SRN$f#^)8 zZip|tPs@1Yr>~f0>?gjs5gcxV^M!v1Y?=F?D!CcsRUtQ@na(HzmD~_F#Pg*udlHCg zRbE9Sk@hy+R?+T+oDc^}_j(CRoRrSkPPk^6QHBp`FM1fKY$CV16YdJFNWG0rt}d6C z3_mY*5iHtqR0Ts!*$p$Rn3siyp0UW!ipJU2M>p+D%Obq}Ka722bfw+0ZpXH5+fF*R zZQC|GS+VVoZQHi(bnK4RH{agpo{f9Y9_Pmz>;GFdYgWyA5c@PSn1vfLVJ!jR+u$`| zod~!lh+>OEW<(iTjU;hh>(W#%EI37jjF|YqO=>|Q3lz7om*P(EW&PLzdjB_>gt_wa z!m_W)*6V*e+5Y#U`X3i|w6eAQUsz`lx(-^=pS;lME;Rg7mSqT_g}k654U$75kWfs1 zY0V_G%^g#2S|4nm5Iv|Q;eJmXSO?k7)?nq99Nx!|({0B&ZO%_4H8nfmX!k<`A+Jta zEB0~%^?nU6ahJ#lrF+6j;!%ZYGsX@3;vvA^ALPY|bECWRvNHyf;Z1O>x$w@_mJ`r@mu0{y7_k73r$`EfB?c*n!lVN1@U+<_vv3dYF>l zxCr;wMVdUd*wgyrgXKTXuBWeL!~5!i(2lf+a`EaGoMH@w*n+^Yy3kA(N%bSr_kq#w zO5S0Zz6D67`f=pJ3|%VOR}hSS~6b z7ECTL`~JJoUjx%Fo^AGrrj|WO&%Z&5iDuLCS-&RK>#x*j`rq`ae`h5AQ{Jm=xxswB z=*SgLxo|H@fDvIv$Oxf4$e)#zV=5Iz?{thEHu90OFgY8w-4N?I`~uokiTnlB8S>Oy zFQ1^+RL4qle!=y2yz%Dao%{Q8rKIMY++KJLALo25EG?WSUPrugW&w80DW;&Fupm_| z&971b3bx#^gVe}(o|8r=?t*4>wk+klP9^ckLFu7;dX~q+Jho|(*E(hQ}4`vh0CaJti_0}&R54u*rUKr(=6&I@^IIEuZ%G-Qk zoV4VaH=A+Gq-?3^5r%tbsPXFkQK%;L?l&^6~}>I*;Uw$4cAO(KZ9lMri_6CmCQix)~Q*N zkV;211!l$&9vA2_eW?X2P#?L@N#-xvIpc0GQ!^2O;j!{@h;k{{wvVA2czHlkizxnhlne`b=H@bPZW(`LAGx|xUfL|dgB_T`~!+<7{UM2V>uws=1%jDnqYvE?ZZsw6Lp1G;N9p?D52 zYENKwrQNXMu8{ah)KYPARI>XDzRSMSOd_=NZ?#yi*n$rVAZ#=tt}P$MRK(1So7POq zMXX->?KlSDr|~KDK&G_^HeMBMu_r{C$X}7HhNcJ;JPur>^#}_ij4`yCieS@-6Q80UKq9}o^&DNNs3}1dH(=nwkkUrMSgX1^v3c6wRhmgz{sA#U3)_rHizZ? z466cVlmJ1Gr6cYRvkeEOi^SAIdB+}8yLp7%7Ao02M0Ts}ZHjutK9Doj8K!R+yVj0C zrCKaIdC7N$>=KAG5mPAbP!2j3~b(SdLQSoJWcz&eZ0T~ka29?rPQ0(2^{bKZ)y&+XoX!=qkq*0jkMP>x)1Y&muuyDN z*^RK4F`ph&Z5fa!x1-Lc0=T^Y><4)!G;lV5ESPjqpD>{?RrFNjQMzA{CIj3^AK*Do z6_b~NiwEYJ#1%H}oK8b+R$_g@Y8>$;sXxMKpno|hpQI1C4b)O4%Hjr{!WeylJ?37; z4(EEA9Kk$;;u}UeRA%EOhZILT!-22PH5d&K0>edlNijF9zy+xaJ0*W4%t$w)7N5!T z_9w)QNKT`mOn68!W(`MBCXiu|&{l$7yYNaAt3e*Mo{N@sa$k)SlM za-CrPfH@M#HYFoU?5SFpV_c#txExH*DXMNbT1t$CB8n38!J%N}| z13}uRY1LK!2|bQ%%63jN8p>+$J#c{H>KpcJlCNp>F?5#z^y?G4SC#xIQYCc(QsrSp zTMc7n_+B^qz0tH)p1vn|k~oc3`iKPYI%nOHHl|DjqK>jPK3@-`uuIgtjNXtUn7(># z9%T%bH^}q9Npl5O#)P+iv4Tv#E|dQi(Dlo_(aqG!+0^7quj`Al;{11{Uv%P*-IwIg zut3X(R6}i55)cS@Qk~^R(2crIV}{D`P#ksODr>kj1)mll*&`|s8ZSDA1#;r!H(u2J zR#DQ0;6)uDu3X>g>(!Xw=T9>*-)id62z$Li5P%nJw?$A8x_IyAZ|_zo#6aY+S5Ym< z$a!Q>t#`D>_f_K2ED+=lHN--cEgKmwPXct*e|r9mX>t*j1GcX=y9Zx3WjZyvXP1(Z zo7*P4X}O|jNini4TR-~+`_tWYDhc_S4M%pJX>Tb?nn{i8mDHI-kTsN?s-9|Z4L116 ze}Q5saz0)f67j5+1?ADXmp=w4DZEi?){eqN-EE#?59QtMopOBFHk@p8_h?&V?0 zlBgr{Y-q(4l(|q^nyf>cV!L;WV~3^quwV@q@mFnlr3w4@Lbn*V{2-j%wN5x~vlgli@i>!jjU$74ZX*2^b%sP|< zVpw`_@P8mTO&@yZ`22PtKK}{+Y57HZcHDlGz5Uu>KKw^eoV|mgv89VAgR-fk>zA&N zrJ;?Ise_H7=imKL|0^F<{|oMtXhyz3B}7Q~>*y!tDOi4h=z`KETy!&7rj{*|YerTx zNMbspb8(}GAeg;}I;v+sM~}@ z=PgBmaBF!UoUUVIzV-mpy~M2#h~D=aRA1=V1I*r^K?T_R9*RTKPE%61^%3eSu#&DC z1CTL8dAqFub*6G8JvqA()Xrif9bpu`)D#Yr;&5=8{oo*uUt^M|k1443)*cYWr~}l+ zDu=45q@3zZRYqdPX{rWPoI{A`&A8I{jEyA#AH}SFIlo5-?h#RiGj1kEm+>r?g}~Yi zmzv{r7~vF#cC8Vt{13Z8mO6l892OQ7l{zJdOh{h@waHdl`)8%$@by&%az;6%KJRFl{*hT&dsL_cn$~$A-a8Z#(u888MN~REGC0~KH zg`<^jUd^(ExMS&}TWY7zvmv@zJp9336pYq_cTr4G!amx=Ju45xZLuZZQT4UVtJq%N zu7g}|zII>Sg8X<4?Uqk`0>UMg+`hnlVV_;cJ&kb@k8Ru%(Z!0-8ONRy(avvCoN++= zBSklS!;vKOVXtsa$X^FZH>UvTJ}|n@x_n~>Q0$*kLJs?!HQ53dN+ppY^f@Fw}9Ezna1k9D*1Dx* z<74&1{%K*xEhK~Qc>8U;b5bT>dVACPn(H`c=F1t^n_;58@36@3XeuCq1M;LXG2ZX`ny7Y5s?O0#MK9`0vt)pJ;k0 zH}<^G?)dLgz5X}50-iVez@I#jJ!U{XfE~zZx`7?2X97SEWIuIrrBc@p%(FiGm8;z} zmV;g|fyOM(rVJ(|DAJGG;A7f8?7${iU%`9hFRM@m&^q|@HYjWhXd6hOq_u)oN(Vro zEU-B^5l~HhE+#T3O<02>q>b5{b6Aiwm|pJ>Mua1%ECvT4cMRxGMo1nF4PXXjOeiCm z3f(~k%+@rDF1j#`17xdRj?MR&P-(E{c@Y~FOjAr0O!HNG2dn}3z*Njuon7b@2TR1q zftu33WMFlsPMKXRKx)I7I;0GvHU+{mq|Ssxb}tQ>-q6+qFbCrWa%;Tq25PXe&6XLy zj_ocRxZBErqKE1(dXPs|FTR%D<~WE|%q}}f3(RJp)Hc0CNv~dD2dEx}Lrb9d*`A$8 zGInQ9W*4wMqDMimJLD$CO*ZgTLsljzIoKoA1x6aO#nJ%~CxyfJ-JgM$APCqVkVFc# z7yCC(!RdTp-la3+j|kOQC#E_j!a9Q4Y^OHsdZ7-E)?nIT`L-NEH8iR9h#7#Y_dp## z3!c8h>}gXZEA5STN$o#Bm;5cP=~X8+LS#8G60s!n(i=!k3sfZ#Oj@4s78{rJx<1-E zm-d`oiV#A?bBi!@`@Af2ITtMgXm z>NN*C5`3|=%3hRw)a@)djq%E6=T-AenazvpoxC>e;JLFn7>#!k`@xiU049Cq3eC+z z>7i9h3#7yqK*6;XU$3LxKFrr)9E|6b<|xh~jkcE(N4DZG$*O#=Yvr$+`Sq{lAkHd~ zu()oCR4e+p_4SX7OwOFt&SOLllNqYet8IBMJu62v)Xu%X$|i%5%San&Qm3>&It7bU zH22HuA?eGK?zYyFTnFK-x&}}Cmh|>~lS0+lmxx|?O2~0#@a5c064nA^^muZo;YWw~ zDHn=F&YCR?l!e^8p{7ZU5QG@*;g0Vfi+%W0#ZT^`3vFd`T;1ejordbTw(R?PKi)s8 zlAkS^{@BB@m{7WDK~(b6HL6lBlu`7cO=_>KaT=`IAzjJM!Q0yY4qg||uP4~noLoO8 zvUYEeD{iftF>`J%Oemwv(Huk0EAX}`wV0qJq0I?0UoqI0D)w^vP*IZgK*i_SGkmUu zigjS=A8@pr?mqzEwlTt&)HjgGK_c&jtx3B9^XUJ+F-V-ne9O4q@1mJ6`%KJhxsSvv zRhEz?_HZ+5p~nW=K%y##v>X~{o~jSVfT#aMEZ{>W(eo5{Z)|IYH z`Ivn6S}*jfR?##y=zTMw@-F)h>9;r-yElS#B_+X)!#lh_z$XJ;x&mz68Ou5+Pu!!cw$ zQ%b{_R9*z|S?n8Mgk68<7gzki#pk&F-PsRE29jFV`KLO(B#n7P*pX#>5UH4rJ9LXV z{mI3f1_2Nr%W?o~PcLg?I!67+#{hS%@*#NaL37bEBUTunsdHhFcZ}FYsm%# z#}-NSu3ddH!;-PDmX_J)aer)+2u$-UCGI z3Un18;q#|tL#w^^lX6?m9El`d^w`zO6ap;xbC;B2c#p~_6k}1x;rBOAa(p2psXZrh z!IIC zM!u1TAdg)urpJodRXZ74bqGqH?EO~gCiljp%lQ$N;5lC|lgL>(JJOUsSiIGket^kN zl^wQ(DTCfDIU~W6zCSVEcbL3TT(02S20`*Gi^Z+n)?Lc{;Qj1qoTu&1zToMZCYSLA zt-$G&+Y?$T@aLzTFE}x6W!AB0MQKxV4Sso(s;yIVP-3_imAQj*n>S?q*_fu+#2oT` z*ej2xN0`t)xrr9*sA>T*B(>a^>Y#i>-Mbvg5g*GY1bvATI~d7%!?sChdxp>; zLf*+3GQS>|AgCagr>Rudy6<=itP-h^Y3~E201OtFIdUe-Tu@rOKpu#Q_(9l^w@m~A zyClf$D4&WRQR_2v7W|Hj$XQ5uAW_3|!m_M>*jBkfpP@INoJCm2K!4OhzLPM$o*b9x z|9q4jQy;j7nsR4=EG6+!zt=3q0xJkLpzEue)5ub6;;n`YXDTI`#9SO1CJL*ir|&c6 z$Ifu6emQ^!&o}hvMAXK#e+jSyQm}_P=_9rwE{|oq z^I(#jYk(jLN!3NPjHA1Hq5RuCy6=KgF%xOOUiE~_m@#z@L*gC`o?B)!2HgwIl8&pY zD3^RvS?fr3g;_r$^EyoXXA^DGNeKL_P;|FMK7-S2XGDyXm$&7w8LM9-TVOGiD8%!i z*ew!Fbb3rtdZcraxc5dvBVv2Dj<3=ELlk*DkHEBCf{?%zR4Aw$^Gp`e!_&P9oFBtK zZ9%odh_uEK$-u`mR#}*va`Kz;ef$G{ghjLbI0Wh%Y=mG)gb)luh*xwp_1>)O(#2l8 z!fcCLj<3bzHs^Mkjv63SK?g>r9R4*p`iz#vF0&T{iF4pU)eogH)RhcrZlIb^PrK>o z%c_G>tximzm@Xe;!y^pg#xOyZYS%D3DD!uGcv;Wg%y5WykvdpOyUQ0(W*uPSZcLMija!ooJ;bo>H zD!F*&bzn}urB0SF(^`#kE>509>B)j%MPb18T*RTDn0se5N9`1}-8v5SPRGR*xr=uN zu2qoVC?;bpDD5obR`H0ngRnNeje7O` zC+-s*)>pCc?m598VcTwB?(ipBO{?t}HR&Ti`LZ>Evc*jm>h!Vk1kc=RTHI(Wvfmpw z`7t8}?bVwzpZAjfrO`{n)>}W?^o`!w*o%}_mC%Owp;2rR-bgRM;Vf0pZ3o}RcfFyy5d`TQQNhDqbajY3H=yJLhd}$BWe*W3tb{Su z8CU49kq}-FQ&=vllErMVJd2d4Je~)jxJIy79w4@_75zdH6rDI{Mx;iZV*2E{(arX6 z0X8Sx_0ocC$BY$@PnBQ!g>vJp>x1&CvFZ;FA3H$D)~Mn*(+i1XPV|WTwNSvt-Qodn z0c^8Dw=^vkVmSBi3u>&RB0noJPf-p5>+r z>f@O-ujoMs=)u017vxjLuS7pIGa(x%K2#)p(zNTS{;=~gU`Qjpq6=k`-=~f2@+HM))d@v7tLde~8pIF_Cq=Cl+Blb=UYN;2sJ6~4fTO5H0bfas88EJWMesjE@B=)gi z*;n#leLr$HrT`*9^sF54=bv7=|C+~v36zZezh1cmzVf#{tr4EJZH_#|EtQybMX63^l zOF9Gdo_gRLVqJd+UtS7AncM}mXg(?^!Bh2NT5{9D9kicQ*w}3HCI)I zzsy*el%=#OQ5!fz9l8f(uV$`~IRfyTNfztSjrf8>qY*QSw1RhatSlKI{Yo;Ct<;Y+ z5#2oL)6ft=;#p{-yFF1l8_6lMT(4j%UWIaXX{4`(c%pTSa=uXbO|&k!_xB|T z$mD&PYD>(COA4msDH!OzsZRazX?S#S+d;i zgnIwC2dkOtaFoTbhbq>u&-$<4bpQNW|Ng@NFW-{q!G47w92^`4T#z1I4cyKR9G@PX z99+*0oZk)HPYj$rbFy<1nMVxV3~q{13>^LVJxN6jJm)ZfaWG*q4wf*vfAnYGUShIF zN@;FlT52_cN=9mGT2i7_RX8c6qUF>;?{M$*C}99S5Hf~=i2^A!R+6V{{#zGH^WSlC)`HeFe(7OFCG z1Ytz%LW5x_Aa!OH7vRZ~C&-EVQgY_((`95SqiqAyF;-{sm<+U%Q_GN0kA@$O(rf)d< zId%&$#Ne$d=bFRWIuT?L?(UPkp0;Hw2iAmb!+g8e5OQGyT!qu0mZuny=H{7m6RZof$VEQ||jOM~5V zk>-)GlxlpOvkOQ{U-+e7i;)((t;oaf2DqxLTe!C9@DY9cjldL^XGSb2BAz{J(3&oR z9AAz?f@w=WFXFNs&ZL!Cc+mS#e2>413IR^1j`LTDZ@#VvhJSgk{ac8Q42`W#?MxVi z{{H`8`7il(bNoHPz6sjWz=D{7o!iFt3{y)AWZg|S z@;_B|p`bnj{8a9zs^jxEdZ#C*-+U;Z`FpknzGV?r5C`dkc~ko+J*k2g;+I11DF|xy zAqkh}iTLAfVHUOLMS+80OUqcJ`<01Z)s}Ls2&u3GB zgf;>8re7mvyINVQR27o{{ty!fU?_tt-6`^EB!9jvwc^)V&zKH?=IMrAI$&~X2?0(Fp zliBbGepgux*&tdj{n50if}Lo(B>L2so)`F#=t*{h8&k^rT3#N8ky&ntep;S!HNUy}@eXGIah^zNGzTa`PN9e&$wXF@@{mrGG^rGsjd#o^ z_C4_@o;4S0LiwC|6zr-OIA9%6)RQL-iCom`c0nuVyZq{nq53W{6NmG6eD zst0zf?i^2i`?Vh`NbXDySZYssAUb(;`X28{DZzzjG*MM~KO6qWQ_ z89Vji74lGqY!wMfrCEQMnI6U;X!;H7;Q9LN^Wt!!rQg)0KdlC+Gk=G%`7J|QCk)jf zspU2&Fg|^M+iXq5qA|{7^PTgwFrnYWgMN?y*3T^E(bqOvf_u?I%mX??)$KW!&WXWZ zEhrE`R1{kOTa0TATudgc z;YRzZC%o{uhXFq`44owp*nk@W^h9lD{U~D9s_RNp6~JILRz~aWg1cCoAxW3&EMJj! zZtN!Ea=m^KaXhI(yRp&>Jy1raP}95B?6qa8oFoiyz(aSmeuyz;40+2Gu(~wDwkN&e zoC(X)qE+4KK9sW6csdwy?lpfgd=yo@Sq0tV=3i&<2ofT@!(2p&?ASy0rLwE6QT|=T z3vI1-i+i9>=8;T<9wAcQ|8V+An; zPM;Nct~$M$q%!A*`^qRV(7jZ5`4)?x!q&wn(EE$HcC#?>s%yCxLx#=W9W>S}M_p2W zKs(Je`R97cwev^hS%N*)HL$Re1{mPLH%agtpy1;|m8>`# z$zc34Ua~7K04O1N{5o^W^;QF11T_N3Cs=lef(mom41VT*kLkKO{AT{gJ;cCbIO+$J zWtu29X(l$4mVUt>S~!ZnvD}e!lbxS^Z*;{@0>nw5 zSO>Pj*FIHs6cGM@zK@aetVvoxm<)5uv4Hayl*8H^1>T_Ek(C$EWvF4=-jsx4z6c=h zh$mSM`pvW;{i%jP2YQ28z{N5-r4i{+JRF5dOhu@lMl`4Uo^whpPkFdT&ocxgEN&6d zvC=6HA=H?X&_1`vQs;Jrfou2-?&+jwNa#0M+87Humr3e2cBsfqvCg?XoOFA*Tl4mJJBr7>0Jg%odgf*Q~dfBVx}Lo zEy9Q@9jV&l#@W7{Qt>$6OcN7Iu(y^j@aMk`Z3~^(ei&aBUFQptLjNC*xvj0Mi=mN? zshXv!`#(;5a-y{Tms0M?pUhO0mGA4klyr2cS`Nsio+?7biiOnUL`tggqVc;&oE7y$ zv7>7@uQIsbgH(W_9FK&F%y3H5NJEXrcq-C&-p$=QKOf#U5Wab@F4P5Q<1)7vkVJM^ zF)b<0DX2CV@8!tty;-d-8CZJ!+#?cB>DWBz#$`@|m%HF-W=rUAdK{Sb^CtwSIS z@SSHngeK`Ju_anGNx}_5B*D{jDYkRU+bdep;O9gMifB%vF&$!69^oNjn5P& z_IAphOq;IBvjRh$Rlc-$Mn>D z_baR7v{PYDbxfXot@eHKsOOsx`iB3%_4Y^z;xTdppfQSnWG2HBr z4gMh5-IBi{_>%3@fG)*^bei}QY(J#cc=>3P+Sm60 zG-xeFGmO?M)t;f5@Tsy57tMBUBj+)cmHKhwKTx-#DYWcDu|wKSnX)hto*u!+gV2k9 zE~_;g=XeP{Awc`m`(wjGI?5O*4Orn?9v+NZr3vN`{fR|kCiQnU8~xZyHXJ@-(RSq{ zqaAlINjfE%lKjwOrSuO(6FI%I47>lu7^E0se6JuBMk3_R4P+R^EEy4HWO4v?f#h}S zlu+89m5-T^xwYyeL|IzWE|5X2hn+6ic_U0!wG;f1aV@CtxQ{=N?s=Yf3{rpbepLa79wgEcexrMEr#`TX&~ z6A)UeO}Pg^=b%G%l-9-(-E58MCq11QHWv(@cJ?6=aLQS>m z{aBrlFA;Fh@p(68M$Hg{UNU05cn#>g2sV!GYxa(Z2ISy&c^-!CuDSz!?w1pdO9&ix zuD#2p<WeH|&=A}ByRdJrqyTF#r1EBi)_0U297``4`p&YmZonE0L~zn1k;j=PEP zo&7pTLitr0RzYQei6M=OvO)G_vCiE17TmY%dF0Q6yXDy|@#qJBh&n5$!17FOjr_T@ zE~?gm+Od=;fA^Iav4Yq1#*!ujHo|}^UrS+D(OHQKvo7ZOgX3_*9|3b3-BDlF|2=B+ z3rHat>5XQSr`AWdc*6Wg(}AM{xyv-V5sMw;%YbnlYhf1G&1`%U{oz!qAc--$(JHqI zcDx^)ZvnYW7vP#?7|$>6&!u9JAbSw6Lp~!qALY{R2>pm9K`4DVO}0mUihC+#{D#`b zswWFwrGQ^$n$p5HQNiBa)B7CI>6njn)a{v|(kV0lt-)-U=1^;B9ad+7X#SV|C;?(@ ze~C=4>#Nc^b+sjVk{8}TgJu7kGp5LnS^ml*nlF6hf5;>iCsR{dLx;anga1AuCaY>I zqe!BDa$}GO0|kB?A0DdR76KkTFDKn6YsUuBlMuPJO=#rgPM4G=Pf~mFe>5eimCDm8 z-}IfQ_D?kR^eRRP!jh6zZRa`m*>RW4UD$egf7n6zHf=~3fk{uL5k?#!{edZ_CP*JN zp%`388KpkxpbEPJ?ttf6*G>d@|7N$(P}g3x+nn|#uePJ8pi*0CkWN&Y$@ZB*)O@eA zG0RLR&cSS&`P;NA-t>gw^t||}(PkR)TJ&&y$i|bcLt?Z$%kFHNSeTKkVH|N>n{6Ky zhc1*T`@R%lR&9Q#)|I!WHMF}%f8I6jtmj%E#I51fcm|`y0E74|?mi!K=i4b-j$Q?8 zn`C=i?#d;bBAi4`m8|}_TXv$A6@e-N93TwwW);b(CN5E_`}1J%5s992lZ9EPqYce> ztIci6R9eh?!62;;l2ASV2kGLjdwk5nJywlA`DOjYK&-5+{# z-|`O@jO4vwge8pC6&qCxZP+z^s3Z1Dk)k8E>!rw-G|A0#pn*I-by9mQ@bJ?V$w?*w z9!32db+X&$sEfP=sz^((IOBWfSVLUcg8klEpRkgk}Ld6g}Lvdz5;DJ_B;=MRU1 zk+-_8iE2dop$P~Ru-3&{80}XOjC+8)!GU2v8ct_%^{^Z>oBw(LxP|HEzY;|naRaSb zMVhEqsF73%rj=4Ch*Ln8(!6-=Z>29pABH2EK(>=={emPTw0Az0?i^sni< zSZWQkF1@mxP5oc=@y2Ua4;m#V<87D zRRsGA6PD#>iX##g78GenyZlG)*!YD0uzr-6aJC1J`#I#Ca#XaAenMt%l`jM*MxnAs)0-#E+XK@05Z7JZ8rtoQi4>Tg-+ zimJ(*ZJMkJh`W29p+3Z51fV&)*B#*eCsHzQdE@A1SW7N$gm{^<^Iy?OX&G=?{Uv5U zN^bmrJcIg<6~VaV#vW#9VH5pK=^l{JisQe#d#0uD@ChO%!BPo-Kg(EgG!0xkPUomS z&0s;5PE%JQ&#x^*WW}Rzyew|idX3)20R5mKZkZj!oLD%6h@4F^8+w@Cv~KYe@?sOx zz$0Q7VQmwN9Ce1|!YcSc#31L|Bly=mv{|wC!2Ti@)xdoFM)^PG;eT5<{38>S)x6bF z)Diz|b+SWM5F;R=!SOR*7#$QWso|^EEoz`rtB6`}kZC%yjSZV9&S|~*`Tg(%|ExVu za-clEU-f^>^WtvsULiH9OL2C(p3Huk${xwq{QNwQ6#(iC*H4f*C;;_xNKUneuBJfh z!)4*{Xd8nj_`ODFCZKp@iER5EB_G8;NwNZ>m$)iLFGk9j6F#$+DZ66S_cL%tCqdr zsX4yIm0TC`OUP_{bc;p$Wm0C264gwGLOOH+I2_A5&xG?!o_u%n+&~OF$;oYKGHRnJ zA>Em_gOyhdoTP=uO_5NIoqBrFHn6Meb*Nsq3D-G;6%rArPAY|kd^U4hZkr7sGd)OA zYjlzmt)h`JYsw6wCSl2uM;;$v&faB?&2zafQZ44PO_7N({`Y1^kq)l3{e2!hCVXqc zZAX+(H~t#v5bLi^CK}khG%Z+m(!jY()dkB4<(~rI7SbRAuJmcszlQcJbve}0AWI<1 z>Muz*2r*?4*jMi(lj+bg@Qk|+Vm3m8?j;TOU0wfFbmJXDloX65g5t?d1eIjiLDPFa zZ}rT!alv zj;<3b27YjizD5bx=`)Wv;5L6}Rj-w9L}2yoI$b~x<7s}918s*~xbtGipXlJYrL5Qo z%_+qUE*1(Uci3g~iW5Yk1~`ZeDeB4XI_u?>a{>;4-+mC6VN7z|hD4aR7Vb);eS!PY zu6G+F>=}#qwX+m&@!szFT3I+`+an}(l$b)&W$kRIbHC3F2WM+HLVGsk?+fcF-h%iQ zhB793v5w!%(|55_$KgtOf|%Zu!}t|*Z(>VvJ)R_@uF3p5i)DInp&TL^O}4R3sV!Kb zrr!rS8zHox$yCJ-Rlz;A*%jHR;6daK%eb+VF40B>`O;yN>vod)xQ0S6hFaEYf2BdR zC;)UA@&BY}k!)ZnwbyUvSIxKLD;8TbdSN*zH{~y^i56X@)EuA3XBjt*klmGNU#eI( zi*KSh@Sa~&503?Xm@a-jDY-VnUJMT-9_$j$eL!r%xJ0tUN$A?kF%1(~9}H~`3A-w6 zK)Ig@=+z#~Chfw!%xLy5wMP>=kEtXqbQM=eTwX>>*9MEP<1Tv#|1`#-D2j$LArW~C zE3P4~KJ6hHWVb+gQwxi!BHq&`R&&%0X-c4xcvX|%v$cG{d_gPvnB`tSV$JSSmKSGb zUc@OgoM7wXs0UO5Td$%AA(Y6a-ryY~^CXi7=d<*#U=4>Yp2l%A$$nwWQH_T9W5Z(CiEZqh2S(ixbdgWnn+MUHm>_ zT%d}TTb|vi+bMW~syzu9p-$kFuz?HRq}iCcqbMNjV1s?$k4#J6x5H8tTG0Pl0T|HB zxcMhDtiL*WU1_V2=dVuQ?yHlh{vYb=KU+HdQ-xKv{xZwP^ppEa0=U#s)t^Fn8DC7$ zxpE*-C5E~0iquUH?UFHur)C_o>`gHT@;4AC1ShF}y;!o~JPUm_es@ot+uQC9R78Rz znA4s!Tr6!aPWT}5cufRG^o z9Ul;j=0l7~t??_uRBE9bYVy#^jf-Kbe|srOuNt$gQ>~R`%E(HX#?&$!{bXZKy4Y-` zLdoD#V0QxV7_5R?8LPXZc*9A%V*OOr2}5I9c1sU!HNw>SZJm$K)WVFa$ynXBA!*u; zXSFfHRk&FGxAo}Tc~b`Madgf6tuB!MFm=MPN2PY*!0N13J)FDVFsdpII?JU4n18U%+)JO4E?d z-)Eb(xX>}l)#Q)Re9Ctlu7scD&}N9p9riBHj29CkxF#DOxDYZTc=gm2zbl5AoWnFr zwN~zn(n86&g_J6{MWm)VqR{~VKK3jQI6lWh^PWAWqJDG~59zxoYd|JqT*ixzZnr}< zRTaf5hK50FzJi9l`=r(*Ilvj;>YsF^si~b-FU^x*@Kic5c(MgnG_SBb7o(OA`MIX1 zx;uXwy|^Ia%-4Dq3t7;)Xa#JDy#X&_BY*57wwMQ|bxA(E!yGe))TMjd(f*zQE#sf> z)2J&zfCEXu`KcY-Ekv;x zc*R%HI54V^55-2rZK4d*p603k`27w;1Q+dn^V1kgFN~kL451zK;Lvp!@<*GA^yn-S zuZ!qiZ`Tj4aZ?{@4}z&*7OX4%{7r2RVTOU%wGzW&y+~p$_=ZslOmaZ!8oYxGz;H5R zB^FD)E?0d!J+4{e46Pei_>!K07IO=U<{0>#&YuK10!V7#^#^|KIGQ?S3-DJr5^5;$c#|rD2XYSXGPz3e=1r+^lPWX$>V`J*^|BegMsvCcmkU!a*?4&sK zNLq-ceL+*vVjEUP-|1${=f2mKQK~M=I>AbFbg-^D)Gd3xp!k$C@IQt?WLb_8vP8)L zALiaFuFfsl9!+prxGpTXyL)hVcXxM!y9Rd)F2UX1A-EIVH9&BOyLR_E-DmGUeg5)r z?|oS7_dU<5IZ9@YQIijQo4Zkq7d9!ZumOh5pq;Us_s{2tJkLvh-EUA^sJ_36qV7pM zE`q>I*>4Qg`m&bopHK!mko^cvnn?@E*6wzMKfP!mSHuon)oNfu{)!2fA9yR(NFntm zCzaOoroUr&QHVp4Ruhr~yEptmRqK5${`o3U>rM#cITFh~1Yw1Z0gfL|EY*M!LTZ0p zrE~xuD7#M<8m}@+YtoXf+m)pNU#>-5U~=KamnwmUE-UTKB026D+SHJ-gi)`v2UwEJ zXHkUyfg_q-(`gr@Pv&eFUF{ehPz2;fE33*-2Oji|&PUc2ld_6VQOuetE?n=9n(@?& zRaIPGn%zYS$~}rrNSg%ovKjADZV0RtelSm7Sd|jnRZ)d4M?F`p1nz7fm}qI%M-tLD z(X{HcsrAZ+2Kk|LB5_+i>TGlp9BT?K!i&7Sc%KF}5!eCJ_-;18+%+WGh)#=2Qsg$cAnX@rdx|iVc@P%FcGig5CmhBvGyr zLKVu>aD&cl?qu(4_v?F*8*)vR7f>ZnYK}zgRLL&;4J!imz&jof17v2 z$vjz`Qz?ZGYR$cJEeq3vKbh~nwS!3s71mOda`x_TFpCo#FVcpNt!tCYV~lEY@(DL> z7UykZJsHh1rK8fT*qbo`%%l7Ef~n31?jXHtu`Uy7;5jLZ0k1IL&=wv zEpPmMpnt-a6pQ#0Z}{oe*$X>28%fD@GU|MXEEGRDP}pUqcdT@H>a8jfdTPZc6Qt=3 ze+NUCPbhSak#DTJ>_(UA#`zYKV;3Im{@xohNp<-PpZXYaQnkM4{m+$XeqtaPCJ5J<_(JfyK$zVIo``&RQISOuerOjleLuDm0r$u$06S#*TviQ=7k?v zOXNCwaZQQ{6vv##uozw@l}ODX%_nk4_)kUOTPNmFg+Cvx%YV^2nEA%aKe*1?bP1Hd za8!=i(h&tXKHv3~S6LZO;~RY*l5Lj#_6rY^xSh`dOF$D1{DAyVqAysA4}{ zD?;E}m$0C9iBg5_mB(-q4p*yF#JP{0Mr?h4ErpJ>0v}xe?6b45^FZ5fxLM<+@g-EP z=soMIE9tlk5f7>9MAg?w188+I8zj8Cb1hlnO>(1)@L*d_`YBSGSbrsSHH0|_dx@4T znq>DzbFI9*^jo39Mud7jT6|#lOHA-cv1)-oW$Rn`mucDZR&%aUng>#b7@NdJt429S z%A3~sUZWsR-~(1V?g#gE()YAFeMc%8_lC}AtwzC^qSL-kckHmAI=&{PvvM4sH->vl zRK%Mns;f6!u)3boalK7B53K}Sar0Q>U@_8fu-dGZ<~yosi7q!m0%wnT^F?O$`%d%h zm14q2-k*ruUfY&;**+I@1e@7whaSUa3L#HAA{*~Kr!3}Lk}r{UwJ+%A-zwoO;HF5H zW|7K6ePG7Clo$e~z2^w1c0( zz<-s}zw`FRl*ofo+2vN?o)`siCO*6~8ZHDpz|NffBLE zz%bh|QyPpf{34JsIt?w^2jLSVR3Y{BAymVvfqggH{8(OyCu?dhCrNCVNlSac!-`?r zCLKF}zWm3{;7@i^GTfiyl(>p|gm{5h(8RGT;pZg9FOd%)QJ*E=z}}cfl?3W`T0iP2 z&9f^-KH&<9>;UID7sWDQEz(Gx&-Z;s@H3j@;4S3PVCM?anU#x)ZZ zEgUYI+KHMS+LJc#oRvlfCab4zo;4#pketIb6w3L&3bXzJ%}+xSDRsP|X`P_b1S0NU!PA<`#+Dh-uV zJ5b}Aw_w?XQ_zoL5o>6t5@hut6QT+Z5+%x0IpqW|dLt#dy>F-Q#4d?cJL z2veUH6dLRl^%fY+JTbMGnUnfj5kv(~Sv50jY=_rW^afV=i!(7Eu#dyC z!;$la&A-{f3k(mZ?l=vc^DARC-1uzn<+ahLA<5#fV|{*c5~N~_M&VOR4ZUIA|GMe% z4+rE+wD@8La=<;1>hFIuW%9R7{vV3?|1$d7n0#SBD}X)R-Hg%Z8dWQs75;pDU=YN# z?n0f&sVO5NAS;vd%k)@|Hm@>o@W`*IT7vWv>31x%9#;&r7N!}y-tWTBsq5E`_3O3U zsZIUvk9hgH1}Lk{N^sBn!8cE#tl!s0HXg=d$Am2C0uUhaFinXo61#mNLAR^J*WAwzXPk~9(SRb zqDeN|YL`cl4@8LP#yHJi$nE-xPPZ!^oB4F!YQ>7mhd zuAn#bL!+Lvu^~lJmSVYtVOS@BO_UV51CjZ6_a*E-9W1dn$%xOTZRWz&ikGd>wv(mq4~evUS(?^|G5mG{r;{Gz}0&45lLz1IC(| zXmZ1rZ-f;QCtxk$V_!m<3^}KmUj8y0HCU2m@Cxc*^?})^x}7R&b?39#D(Ac6^+08HYro!Pl(XVP#wFGeOU~Sc9j0C z`H6B3g-bP5*pAAbZ=`KZH2X!Q8-rd~ZP>#JYpJ^$5xYJfFN87L>l%Yv9Q*^et=^=A zpN4A*hVe0SzCWl8nuDR#6B9~-Mc!9h!xUmR-&Wt|7p-Ovs#cq=WGaJ2M2A|c9=OIr z>CP3~de(y-vJ}lV75%ae&2Xk}=t$74@LE9Vr?;0ypD44&7?YczoWyl?p40oeOs~jF zc4nLzs%`|Fkx2=$=ve2STv~OY;cbwx5G%=6m1o%0o?U12>CbN%w$oUQw4QgFa$ahM@U6bOmK%DREogjS z$jTV^O&zyj82gkh*cgL=VTyneWzG1TjE5(kordMAkG(Xc!DJgCsUX3@C4L4mB)M=g zOWnkpwrm#5x)xNF7im449s&!7u?Zjb#&FD;e@6s&)7*;$(wjvLVHm(-JCl+C6PP zcAWSAu!De7N;|RUm@c?x1XhdQHl3`OsMbCrp_8yz_#T{B_<`76?hC{tMP+s9qNbL3 zOYFnqV-89@;#$FMSo`eGkT`PNw|)ASVW*pA*oD>@t9^-Y;zTO)$Wbb>Qm*4Z{#|R_ z@=_tK1o;##YY1rdmi&t&27!klDD(8je~&GrG3pS0IS?Q zpmFSnFkgOpMmI;8y~4XByDfdn^LqWDW%r5inX^82L*)}zy5lEv<3WcuN zfDiS7OOD_2Oh(G4hz+P*?Wp|11q1eLg|o08KB{}P5Hgkq|AYg$#s|Q3t)dt)yv!PH{2o+E$*HXlI#%eE=RV!*L86Ug);{OuK zZ~BygMKGH#RD33r*>PaMr*Bf6%9j8b_yU$aQ|02;-Ra$)u=(;ltpA~E+YpEEAs>G| zEp?|2U0>=_6^Fw?IZ|7RR>D!c{~KbVqk14F8#)_p(M*IX0u9c& z-!`DL-0L9Lte0us$xs@iNxQ2z7w%0Y?rOq+zGxxi`?H{04C1MH%?ZMhti?xJN;`_x%^9E!kI)y)WIS`W3(AG(V9iPO5}jQ#i(a*%N}kEkDRAZGY}}pip)S#x z0jfV^(pV#z)y$;R7LlxryKT=${P92DtlFLNXscjDX$jQF zhO=vWWAhGvT9PeU+-s|?AErZTYf>H8BEylIb>h8O>8@osOOA9xXaJKc=@56dy%ok7#|l9Bsl69Sda>TUC3T<`QV3tX z*eet=90x-rsKJuEUVRvadO@Wh{=I>n{bOH#dH8$4$cAu6yxak0-`8cC@)=N`3gqy%4G_^6-CXuAL$2i_)p%4)tG07g%%pFU@4_|uk3@#C#+CqXb#U5rCp0BOg z{K(hy8~z*_bPYCYwye*vWHIB{j=^J(OA=wD*VS=v`1ncjBVJIlK8UJZRYZ_Qofk1t zk3Yj6i&I(IvA#Q`7ko_-^s9ZM;O?I47FpUP5+f617Ow@qK6)emwL~H;<|noUl}Aya zw<^+q(}DTByzf8nsgKI48m=k&8#zlNtRZ9E2fBT9+67545o<`gq9)l=P^1^6zMV!) zv;^&&EKHOf1Ajo*+g7!2`ED(#vC_!9_Jr9L-g0jO##*>%bn(7<`1-1Ukn`^Q4&KAY z8*2n`Z)c1Y#k|+>{;^X}dG(Mrh((*CK`TC5n{UvFyZ(^C(yip6->ZerR6+B=9m&6D z`YeWy^cz8+gXGJ|(<)5Y*DWvlYhj4k`k2pEr#b><$X$^zb&+J436 zV{N+QRUTEQSci}j*{!FrFzQ)C--76A7dn2VSmGA7R&2MJx&3rkFnI_y)!vZ(n33{X z`?!LvQEPDI2ye=H0 z^}P64k;Pm#n>>eG%I!&8mnu6f{6}H2QC7EeO}h#0S!=zj!uC@#XW426G{xOQi-|ei z>bssRsRX)2&3oN4-m_QQO9$a;Gs z;`s4Lv91XiRf;a7yLt|z^_7R2>@p$h`dym#qe=`hm>n#(iJt4u;NTpd21Dzlv)zSr z4pkz}DH|Bc<;wN5*pKMO^bA&=OW03~<*IY!Q1aIJZ`I~9y}}AJC^)Zp?&_6Ys_=2x zdyP|S!w^14L&*74Yn-G5=?OQj045qAKA^=8`7t(xQJ5IBXfx?gvf0;TVVL7>@Zecx zXymy$=s4ex@0{HDBHi*cM6>EIN8{DVTq!Q$Xp+)NLt6a)Yf@7N)Dp4K$J;IkNjYzr z0o@-^4DCqh!#UNxx5a10~>Bx5UB|3$IWT-V_Ss>VTT9bO(2dS=sA$uN+C~Ec+ z{D+O21SHR(Hb&@ut^~u8cLFKNyw}&TN91}zobDtE?s&V(rNQa=m~-fsaeVoo(0*u) z=y@s6B;ISiblrfpC8o_@y2dpQ?zX`cua6wy_c}G3Uk>bD-XS#Crd~qMH*?{(EGOx4 zLzk0(H^1(^Kpq)mwbVmE-iM=9dg{@43fZtYhi`m-#f#YTI&EpH`M!m??lgRT0U`fz zgz?0Vbc~N9!8*O!Bj6ne;cl}f^kQ^PTj%rLBV}O20z7q@8BZgy1ybrt&@1|Zn9vaNS*lwR1O?zmH{I0QA<#RUd zD}0nT-FInZ5r8y9?OCq-Uc_~*A*CnXMc@~ovD@_{@cz*CHLgALj&sLu?ai-pI^C-l zZ$)yqxIu0BE)e~7>%%Qc{E$JDr4$(^!@o5s^W}ZMA&8hZVT!v#7f`$1zN4k1CpC;J z;2?fclfoLlL1UI#^$GH`!;f^E|9-A~+Zo>6eQ{M#-LVe~zx&0UC{_`?9COiN>{}Tm zym8X5Y4R6uczXpSjfZ9dz&S}E2>|zTN zVgP+8tH}Nfhx(s1bKn0$Ge@2no9r1L=`l-8Pt`O6eN^NDhempKvT_oBj1Z>kBxPtM zoao1CC21t2=NxLqXXt1p=zK^}h0(y$RdS)2Q-lPkF zNC0gQ^2d+lP-1by0i@7z6flLr0M_zFH>ja#1IQ>q7C=YA5~aoo3MytDAQQg|OylrZ z1?`yn^K(n&3|Z_Srz8bxN&Q)m+42viihnt&f2UcYs0*Sbqx02UWwvE#rhfw7B(3zL zLhzvn+q#Ae3JKRIyUmWsqKW9#?g1?`Sao`RK$xG7L@Sb;AUO*vJr9vO1GlV z%wgVE&h?drBsSD}%sXY)kkpe)6h67M!z^)P6aF!-_+C&aBTRS<<>)aSnrSoX9vFeo zZ?-nh_^Q-Cp?%94ng;_;;%4@Y2Tl3hsqF7Ci0X|yL#Sx{QJZ+K0U64AgC%PapNcL9 z#5r?wqyn_$>#_M`e3=9}qXCtgE6KTvAJP|jG)|8YR^a=34G6{8Aj1@cv(zm$CEslFEKv>d)CX&L49{AH@h!Ygl>1!O!)kn#BcHBO zCEq-o4n~szhI}xY0gN2K+Ut$-i@fK@?UpZ(ggmx0`|e?w_h5$6iPS}(@~Esr;%p>_ zE>6eo>zZg}X#1w)+2Vz>Yd&vt<8L9Bf72f*Ycb?gpGTA7MJ<^*Z-G*!ze~MF)BYfIWE2A?sgwg^Lsf!Je6X4 zCOv{HUA0s+3a|nblHLl*_4Hp6$KpQ_$Kk`@5a-(e{~B??8H~lyKn@!TirIfwRQZ=v z`WLVvW%>_(i;}JUoWdW}>P0uq?;r)q?=ax(g5;4;g2r`G`O&LVD}kRL{B@UVgltor zgkME{)zFNiwxJ(*Uhs#U#p{R_(GoWfx#U4i>ekMC@At=Bh#n|*ILdrd!J!6`89?e1 z#JH2=w|)df4z6*>mO(?ko;#XEOwiNy$Q zoC&b@J;GCL*V@&*X2p38cv^IYlEhA40-DgltbN~Jb^J91kXq5Yz-yE1t9klN28=9y zT}$4Nwe{=C99Jvzn&@68n2W!$UHGn@v9ZD75_;^X5yE)l8E}Slkwake!@CN1vCDMc zUA4c0BMfqHvxt>izS?P0zTJE$-xA1!U_G2Wp3+rnYZ+~r%`BeCCYLyrgzCpbAQ&9@ zbwIh$mrxpo@d3>3s`58%dhE-XuNZwvxA^&>!hvK=krH9Le368bM3IP+jA=lj(~wWV zsq!;4Oq@eHxhH^()*#|by4c>wOX2xi$qFM}^4bt}hw%0z5^}Q^kzu`o0qFqhhPMxA zD1<>YCX?ILhUsbnv!+IrJAXmO+t<&45s-t;f%?_V|MOM+7bp9>ixq)(sp5jz`*x_y zHX2fJO(W8D1~$S1#9a+dgq31i#zBPQj>l;b}jf1*mvn)R+|(`Cyk;4zmDf=_82!AIDy}D-aO$mJgb0N%KX5l|!d#YHywWK@c%DV5Lrh+% zSYalcR^@0rTMektc3o6=(wjgiWFWi(L#Za7*8dK5N_MP8g9Upy_RCxJ$;`lu-VxQc zoO{4h2@Yq4%u81d-1!^w*<6z~Gz*ydY-O*QJ?wy!o@TQMg-KK;glHkJFrUBQd>E5KAUvgONIW2p}Oax1u8eI+CTjp37*l&$zhxDBCkEr_?fe~;?&SPrc zKK66%R>)@_=7$ZoxF`qE(?!NElc6%hjeYmX4DU+X*kTC12=|qGVL8!i5te1ZvwJN6vnwsc zSnT=9DpbsULDJ3qs*ote6vJxO@w9l`H1CVi7K^9hYtCzI<{0iyFtOy`b9T2cY1SEA zbJf?P3(ATXzu&|bHC)zRNGyf#eaR`@4TrF|(fz6jg4Nm+X zh8Xp?^lD6IVtie9AG_|$rRCEV+>`6H`LOfwV3$Zvo|J|xQu}a!O*!6?oR><%hv&*K zmcP7S3%xt42IH9RgS3);MT>%9iBPbmFR@hm!ysx6eeBZ+x0L2Muh1_JY^h%biP{82 zb+Kq*b2rnfQR}N>ONa?mHaw%&zYWe?pDro34WArKdo4fI?&WY&WINGI$hhwMF%6-A zxh9N3v(c=p7``f8k@_jNwim=G};oOm}|k^6TjOxZEoSAdwhA z9+UyprzxLz)Fu4TQc#!b&kto4Hkop>@ypp}HAb%>1mny+W5%Om*-WY5#u9TVz!w_Q(Ydps&#|j#2JTyGz zG_&RNSeo?{w&atd#GTYzW0xS_&HYvdH z!Gr912m1ZFF#gZv>mT;~>kz`O@|%20C0`w-WNlJ6x>g|9TTPUy^3CRIFVLS?4O)V5zqLUN=t*Q;vbsSSYR1i_>#( z!#vANh%13M2y9@(<&l#l-K5OawfqmKzv;ArdCGw2aidv44e%ZP5GZD0eo$ls^kJie zIy)%fU^0Lx!cX9mh=lUU5-ebrYL#bzDBNB+Y#=AFC3kjKAjC!>!|xBlwuYDr(yyea zf0Jzs`KxT(6hc5d0CcLipx=L={Qu)*|A*usg&qndW9J6-5hQAdOgA#v1C}4M3=9SW zmu;A@nWcYW1Jl@8`>}xJr6rb`WqV(I5ao~Nf5h`rJS#m zo0(o)S9Lp5aLBQUF>l#r3rsA%ya9|U`GJXA5oR7IIZHF4_$I^W7Ss`%A5&u$V7SqR z8G`Wv2-pvVJ>xwvSAe)Zuq%iFR+2cgg_X&k7L*GA_<+m+XlgpJD5^NtVG!ty{DC>S z)L(!PjH)#sRBMD({-r%JqW0BX33Q@W|7-mDmptx2i-k(1u|MP&`O^7|V+tyL9+ulJ zL@NTf`joymMo!O$C^>8se}i?i%9!y8e^Xu8Pyp#LQC^C*BmXM4AiO8P&&u*jT)U4= z<@oTtToWhOD>4%p5Ez0kMXn}W!BhyM_vUj8=j$9Zk!E($VB6r|wES`e&Na=$2s53G z4L4n^1tT2N-+^tTp2<+5u#!=5ns8F7uNbnP!0!VP%Mx0$+p65;RyWJfD`CFuJ(k@P zW^rBxO{CX_0Yp)8uDtY;vmn}D^Bjob7_z*UBE=mA$aG%`bpT+!x~SWAcb_2VsnnZ_ z@Q%Y=%1H79E;2Nl4T<|5Ztel>w6sjW#)}%n-x;qb0jt+AhN*9#5%^G9kL7YpiWcBJ z#P}Q8K6*V7le*?9w@7prY>(4KjlrTC%Z}iq89%1>uq5nShSF++bAdJLWLL7yHMmMNy%QKR0C>g3np zY2!!+%=!$^`Xvz@(raHkwP#^v&(wYyn5vhZ(X z2sfvEjsPF19}wK(GK%9A;gtuV^bf!|rf~{&2t=V84=5UCr4f=xkTQwlk?4^siDYof zWf97uGN3S^RU^+0ln+=BoC{Xmd6i95f{x2Mtlo~EMTr(Ol4#s{1uULK z4$UK9fELvrMKoXJ%K&PvOcv23sy*5T@&)Pz$_3gd}g$f=!wDErYEK1Nu z4W0-kH9ycDM*H>1APtu>e&e?`RA$Q4JP^4UGkJVTA-7V^!Lv?c@wQYQ6kDxaQpatXW!suvqKO#yQdf%mZkuOyDcpVhJ8kGR+0EZYv;=a_WiqM`pm1R_;X(Qp?{p-C6TDbeBnaf4(H#OKUQYg z#(Xp55@Nf{mj;o3qVj~qYhvDET5qM#5HvQgl`p};0`{6=@NOHW8fPsO8h=xQxCb->tks7~+`8jJ7Xs#@-a#wD6|sTzFuABHu-MGTU7}){eT! zwP)K9+ce{qip91svFGSY?CO7@_sqOR^ql`f(YbzqF&%@$nh#925X5z}Iv0}JTunae zCjwZ<7{F0Yu*&t$j32?*79Jme{S|lsN55-5LDLdx&sx3BZD+ADVEa<$0quU-e!#aj z{3!$JH?p46N#!QD#h$D}Q2M#j(E7*DExhN=_6yLMBB)ImO}=OE9j^v?NgC$pGvH_f!s<5P&6-%} z^)G^$hO3`O4L~se0R;0B|7}|SkKp;Q5b~ddr$1V2&Vt5{u9i-wCjZeVQjnDfQ$*)m z0^)xg!joo6%oPB0XggZvw?{E5 zp$Lw`$9r}g8FtDyYIkdqj7w3EfpMC!b`)B3;=G1E?vK;_#(m0`e(ZpNHVxBC_$y}eT`Kv z*wbF@jE@1a`|;ZEXr=1Zsr!KO5+C`7z1_q#EP?=`exfq2<|*e+19?e#z|wd`tUR0& z*OocaP7;eZ~1te#;GQ>Ai9$=4>4&^7=%U$V)!}`lqBG@cO5&Zy>X~D7V9d zpZPRm`t7_Uwo^67)UgXJfn7h?yHaAScX4@rl>5Mcjn44W_BLw_1`$*UM%5bQ^*8gO z&pN^)F+JA=qY+dXKh!|u{>IPl8k@V<*eVQ$g-t}2gB{V$D8|7zBtums0VA`85QpkB z_T}TmvxGm74F$L=yoQoKZF)!&{)D8!GZGS0Qis5=^P!(=TCOJ3~H-CPN+bVPI}O>in|Q=eQX z*sTOm<)qUR9K-~aDrFK%f1PB|!^TQ*(rg{`qN|8&5)yAKe%y?+dOCz1SVsl$gi1n| z`e_Wgbx8I#L|yDM1>7z9<}woua{&)M+Th*C9zNzXzeFK0HNo2#8;v?hFuU#Q!Kn`+ zU6Mp<4#i%g!RZXiUj|1_ER*g^zQ~AC7-Ri*26p?C7o?8T@viqPe`1H7-;}^(ZqqbV zR0@sM04kP_6ElNVG~|>JY^X9Fwmf~uqw4(@ny0LoLUtOw@(E}i8`>A7Q#GjFXej&n zJKfywL1xNmOL&RN3#z=cU3UB>%}Yj%>X7|!ZQ#^Z0Bz^wVDcr;WUuo>XH?}f`7V-7 z7vvf9+sIE}0>yv~^))I8we@L)7TK*PT)Qp2UpXc(K)=LG_YTtC=-jaHgz0S?0X|mK zGGn)@#rE@a3pex=>Xs_oKw4KvukoIXPq;;>v{Iq#rdM$7Dp`xnZ+c)H1o{LrAZv2CZ)%p@`)R%p&B-FK{_?0r5 zyl3fV%y>2;$J@We-z7snJvX`C*q>QnUmTyWFE^H!7gTnaH-|Oo3sY+YNuS9U)WubW zQE1EI@Brz(o%4$2sN7|Ua9KUBrURihseN~zC;Y^qu#_vgvEcGz7r z**HdHe&JE<;*{RE3rF-bL`xUz!pZIEkbIDKYH!HRySfL5#9R0!JOLZ3I=F>pS+cMC(wp!bDL)|x zqtcSUtIxACa_m}Na7Q%JAz~y6DTzlv`Fwt=tyujcL*UxFMppl9|K?h7>z0zd0^uy! zeY)8JlO0tS32}S>1wu3KDH-zEqds>tV13dv7TgQJWia5Lvt}ybBlI0l98L@5u_XC3 z5A8FL;($E)w&)8#`Gc2*LM8<-mWKkP0F7Y&dHyDfCIl`8VR4)*!OyogWryVI)=$ht zT>I8BJ+4k*t^4IuLitk?dM>v)dq{qO*{rY%AZ>guv!}k$1ukAE&D;(7d~4!~)9idJ zky%an0<6`um#wWP*0vC0Z|w@pNO>g>g8Uilm3vlzH_k>|y$0d5?mL8KRZd@Db|@@5 zZ+J*!$<{Z4ZS=^doQ6xIA&Q!jlr*8yvfZuj3cN9X2bO41I)}!=ILWh1WzH*aCS@_L zi*i4UU4Y^|WQh|y{Uu?jo>i~VF=D9Oc2oN2eHwOsDRU-HQ|Tak<7%-t`+~J{Yt@3x zst9BO0}J5*I0`+JNxrg8l@~+$E00HR&Uf968+?%AOMYhf6}I(Z+NI> zqN>3ZX#iPr4o{d-_E9afZM2wuxQ1y$3t(;Q3DP6T8mhye(~w)T6rDLOR>0^c;6URK zNj7&FYu$si6(6L1HJD04PNE2Q zO*Ze6)lN1^v$?#nPQdd+^sP#1vWi_+iBuW;(;cx|OurLP#ib2OrcdY(a=Y%5-rDXK zBD?O}Rm9rB}Ci7mJe+PcC4)JrX5>DrtWT~hPu@M)Bl&Z;;z zlyRa%dp<)~bPgGjZ~K0Vr#n#BYpjdY_}V-Xs&g9R%TJQwmNv`rK2Xh@x;!B~As_?H+l%Vx_xvM_VDCe9r=-60E%O$(GudXT4 zk=$cLvz+bi8%C*%+P~^J+e>16yEro$f*KV@h!n83Ck=|!G9n{FD@!e!-W zy;qm>s&m(`>d%{9;4QI@5H2!9Od+_iT6W|!LC2(ahU5Y0vyvu^<%V*j9wFU#OlkRKWpvUQe#9rlh2e&H)uTBH(61i1dv8M(C=u<*$)Rbzd ztf|)z=Ahy)v767bZpvbA1D~B%$CkcDc1i`nRnZ}0V=CKLk=b>kRoSvK)+5yL>SI?j z7N1On&`BQPb~H^Km(44LKBOqSwN^aO*CXWx)DQA?O+~}Gj}^w{(|Xqj*~UMc){>dr zeR8FpyZCG>_n3cj_BF+A{l2WEJ$ILw-m;|x&4b|ROSmY0Y)#>IEh5@0P91l)fo8ul z{#2YXHf*(;H~|f}TCGT_w%Nw00vO2@_>5TLh8hdIv{zpOK-k=F-i!|os?xcH_!l`o zkbH6}?Q_DZ2>X=Z)bwskz+RQ;T*e8b|J*_3mlTHY<`n8=W!c0VKh@&IL3j1xC;KHv zwbpJ|epI@zu*T61whOVRvl77P(4s&0>{?3K=A0Q&2zQJ)V1y0GBNDDtOAT4qp+crN z9Sc>_8n~9EqV^msFfr=9?WNm%&w+S7!cF)I-VC#pt3!HUlv~> z6!Q`IOx#j|2%*=jx&!eme5te@7dAG}hTS!7gHhz0>YYG`<<;q#|ySqax3sQX(xN71w4$LW%tz z7wrtNxz`0^A(KE(o3l> z+?zMtDv0dl5u*@U5?|8s>aBj2U0I(vxBZ>NyCwSNk5(yDd)aF4vxE6zwzJvc_^;u^ zRUUsf+JTu67Y6`ET(1OD9rglKv2oUPqv6k#6;i5#P9(^vPj=rS6g?gIgQLoZm719^J$u$q<6U8p- z8mgL>F)49x?cbcXNLLprs~5X5&L2fvsEUi<*+y_TKErTNGyp%CO^3q1s0@~4R?)U!qhSo#ED?t*CJ7i;06G3Ner?o6+ND)oyhNUPl(?9sREN->9kcY7EUdYC! ze>ZxcI%xgSuL;IF%lwsinc#6YT=ws1ZdE;SA!mSJ-xS6tvSdtHm!c1$$iTB9QpqTy+`Q=+fF zlqALdJFlCHJ97A{dLgyKN zTwb!h!zOu&ut-Uau3HuT&5Sw9P6`uJB&hNIX#P2^M7aXP;v{#iPd{PH5z~%TSEW4j zv2xA z=`{9eE!47e6d30sdOc*R#TJuc&&f`dG^P$)yZapK5QHY*OKf=8Vfq|OR)sM2J#(k0 z311(Tx6gA5tHCbM<>$POyfs9GSqiK)xPy9C)nnktpKo?$ZiBTt%4?s#WY?S=fEzY0 z$@g1EDt!`JkzRxAF3)#_48YmDyR?}z#WbwBg+Ij1x+Riq9;Xzc3> zE`d~-4_j%1o8s6U5cLmI86QHw{1qBSf1Nuawv*`B8sZ?adpYgDJJFO;e|C(4zUbk< z_o5vC8RP?@8!?C|bSx@d=+so>QlozYYhVOab5+9(5EoMoIGeMc7tKmlMtM|Wo{vB5 zN53o@5U_9vx5ds7fW`riyS2=OsaBsi*}C%NU^cF}4{V{MFp6d?qCa{86g_9Y%JmZX zOvK|~jB$+5ysJE!!?cSGyC@~^0u3-`(Pp}CvwvfQwKwlcDb#7Tkv>5>vuw*r>`c>H zy?*?9TgF^Ve57gAaN-yA1v$B%n7{A%ZAonDo?KNaZo0wyiI)_g<@y@Y@`#NE%`PE@ z7$Z8V?&F`>`w(mUAdS@iHg0ZDsxan_{V~)*3_7?pCHzC4B+=R4oKM92XuC>`rb#Nt z>d)__yq8aiA`CB5nfk}-%!BKx#@!-c=FG)gqL{=hO9Yx0-3^~YK0GEboh;?|+`FqN zYlULJ-b<6R1#un6hG}B^5^pZBKHej4S2?hJ`H(ACDH3ff2w~X9HwYBl2nS8JjF5wT z(@p(jEc7p|buSHkBZ{!Ne;8v@c&5s*t|-g4rWH*^3)=(##*rLwG7tX8Wy-<7_nMsl ze9cwpYeMnqVByeIqjh3*0&no78WAQgb%_%8#rI>vWF_j^duoHrq5xGBNwViRBJw%a z3%F|7OUug~P<%T6{ApqgquG!l{+4QneI-F~C>eh^0&4xG5itOQ`g~!5VxtP2jZw6| z=~d;RtV2cEQN;s>J>V&JVmHT7vt)=#n1rOFaTE|E=6^aF-OtF`nq{#D&8q8j4@Ls^ ztRx)i_Ut5(kQIzfT=_-!7+p0F=ZgmH=8-sp=X0NGi{SAT|D5iNp7|2j6wGfgAvZN}`7(J%ow;ues^e9mRxa01+fYRYp>l9rv)L4wT9Befw7(mCDvThx zwNGPx3LfP*dyr|}Sn8o7>VF|+H9HnDiSQf;*mlwooin>kkTfhOnZ#eMlak1g?7y;t z-}*n4eahpd&3aoW_Z>71VM)}b6A2|%gqMO9pV-v<9&K?khV6e2aBP)AU>)fM&dm{X z>~oHX<@fV}lj^mCq~k72av-jq#rU} z1KNYAV*F7yh(>Dw!Z|RJ<0Um|S>T*X2uy57W`6fX0Pemt@eSFgc)FWiLc=aN=5Z7K zQijjj+|IsqVU+r#_ubR2yZ80=;vLzW7PZe57J5S{&X!4o_T{ysp8ENH2+p9gNk(Tg zg)sVp3D%8++E-fEkB`{rvFSCj93b=6>l$!qK+UeVXVfM}_O?`{cq@bfxyX-&AkTCu* z8vALNR26*o1d?2ovAf8pS+^S4Jw61HiAj#@fRuTov(1{s7XY9=lK2a~uLf z4K}M_GEC?JO%g!R+jf|_Rp=)g&d;JO?f09;H(nj`Zy9N-?3Udu26SF$yq7e;V+2hs zRMdOOZN}%CV|FVLM-v({AMTwr^@djM@^yd#{M&aPw{K#sZr? zhi-JdxFnG(H^IMg-MECry?(03u-&^7ce$QQ)Z8(OYFkciv`}RgvE=6iSJ?0F4SdI20=I>qAASmY4x1syNH?WWNt@+yMr$O zx|_citQW|HmWx=>J6M|ksSWr1DUsKcAi%WNl0kw3(0 zynuACf8UxTjmcow1zxzkMi|a6@Mnq~r*-QZbc-}AJm*IJ6+`sXko$1Yqb|iZL6grZW%f zN0Nf4Lw7$NQ&Mf3Mqx3qsYSp^G`PkEvK-~2yRen;@2ox0l#S_i$C2nCNh6T1gh^|l zAQULH9xoTrA!uT#>2QqT&2Mw!(K6-xm9=LOp{Fs1HW2E>oUZ8!h$K;=HJOKm*H=t5 z4sW)UurkE7u}<8i>uL){5PTdd7?g5&7cRcAq@1tuXO3+Y#R{fG>}`}jr%xejGKeP7MRDg}M_~F`j@@SP%5;hunDuKw}{0=SUU{4L5p1 zh_&f*q&tSa5ep&CcHmc=p7Of+!&x>WwuOc3pSdHRiU$4I;9^5gKssg zV({?y9vO>9rqm;TfZ?dND1$_!b1Ec>^lA7#=3xueHSDW`8`8YZV#ni}7Sqg!EPx-? zJ}$1D*Bn1^XNJDn;47(Wy_$OkcSTKZMaG%E?8cVRP1WG&!6VPCTb5YHx80SNINbQP zgFkqQW=s4XtH?VcqKmm2j6E#RO7>2kFFfU)^!%1_JrOdRb1fDgoIiawXtk|krQLpI zcntuAhIeiGp8$4Wi;2kjlE0y+=YNX|B}=*|jW*05L>D?2R;wFeu%m4N=JN zLqn>eqeVnPJT_oFe7TQXnLQx>=+Y%sExKW^Aiz6XJPD#BcY9{?E&juWq*u--6eZz4 z_#wAj^thQj~|S??+MuVuAOqsd3SBeecs^H zjEa|a^1c{Z4sQG_wi7Y;&HmvIg8Oe_o9Ca{Hu?`a;djWyP;Ap;#L+rcG-Zp%lQq+d z0c{;DLdnHWqsWBhpuN)h@;|_R(fu3o9<}RAT%g&>Q@Z;^F<3HK)a%)j4ENjmuaF_OdcN+<*TqIHJq((tmGs$w zBd)2|adoZReGei3tJokrlZ_ryuWZG1jED&y5(+TUN;(Uj%`BS@B~Usi~#XL^1=)C z%*U&Rj-#rdtB5V9nRyt#l8Op#w=Agk*o~9SaUi!;r|!fCt}0U3*%G<0)~e=}!y%ff zm6U;do#fP*=nEmN3r1FAQpg&BosuxPh=hgWjoUi)GwJu+K(;-vt{4@*+9O>^2N?LC zm)jHAFnW~fEsvAJS<1D~(wW$9hhU>8>`>8Ja1`OFD6X zWzI^nEiD$14$QKLwB8vWmoODnf+u^^93MGlIANtJY=0-c#^HsYqf}AEb^@bBg%Ij@ zNciPxwj~oO93p=Z<{<+H*J|rOnr3cLMi^v#%q!e-F6-K%zp)voDA3y0UpJGt*51{#! zTe@40e<*O+?lCI}#N!Hbgh_x4geAn`k$76ZOa}$#uhO2u@CdK=BZFYI2`ukmAWeB1e6R#GdK;poPm!BF}@qUi1)1V39d0a7GM=X zaiU5QS=k(KxXN6HG@YO|uQ11m7k9i^KwiJzgxiD%BWs+d6!}4zXouE8nR|Ejv3oW} zC%$bfy_VC7X9K;xh`bhybSajE{lZU8ah||YS2vcmiESk}1t3WQw_L$q>5T%LcWDDJS--GV=YP!u22T5uPzoR#qRt^Mh>FP+z z3UQ-674^K+5Y{Ytuu##c(sbq|8J`VehtMm(-x=I9>O4n>gR5A{MB%J z9A$WRV0DJUJ%(gf={I14cE!(BE~P$%5i1|vim-q??KWqPC^1~Y;iMV&#EXH~x9m5o zohlsmXZ5~kqqMjiSba3dDmVT*6;kvameuFgT61pZ7Or1TYE`Sp*p+6NNUI{;9u=$) z>lBXqr6~EJD%xFAJ}Y8fN;Y6lz1iQ1#I%BN42r^{Qx~#p@RW<;yb+RcPnn{D)I8@D z4@ljkCmfMavb&@Ob?`sKzs-E({Ea>vOx}EjF=X;-xdL|`R8zNn0aa1hiP0JrjM$+=|wC;^k@Pn{R2P*^EW%iYSH;x1u{)L`P{P7;EI+vgtM|= zYr>_~e5sZ(($1GoH8c51|MZoFUxXce`=uAysX^) z{u;LjYAQjScc4%mT0|+`2HB6Ww=qppHMBA6A)wv#l z;!(YTeUUrg35G?AIm&qmzBH)gO$G+ub$Lv6Ur=uZ1wH~y->LwcwqwGo@R2FP9N4A9 zO<8tOwqjpi+;Z0)cahT9h(<OU$`1!>j zpo!(O)1nH%t9gsz5cpKoq*Wdr(lpfSc=k_ZmG1cxgg8`}Vy+(31I< z-n3G-rE|m^h21PFOk_116EF|Hav-caY(CldnqNVK`qK&n(9-P z{Xa=;@P&B)>e4FY z`R--EGL=5=@+nNh60^}Bzo+1L&c|2DT!Yf~JFa>}(4mt{2@6~iS!TF7V$Ivb2+0#> z&$-4Z@4_a$FZgmna0*}&@=KV$))1d2yg(%X`nRE3wBO;%!Z}{f#uyYmxk(E3{PW~` zWL!5feqrjry$_pC1*Y{B`jOeQ)02oUTR5`x-UbIJbl=LdOg9qEvQZC#*~Tm-gTL&3 zm@z4it6~NP>C5>YFXKZPnV1QKKI5#@4&I**fbTR(<+dymJ zw5=-@T9q6_tCIg64*y&pXqxz7O95Y%8qb1QQ=o+SH6v zo@3`Ni^tQ+myKN3^>m1LiG8^p?tgC)c-dRU5`>Wd4DbhU<~pr7N^FmgPON0lMlynm3P#fBR+IL0FHN|QtMXB0rEtJ1(%9P$Hq@O7q)Bvkfipd_ zZacQwrw6hys);S6psEuhwPUB35xLF#S^s(23B$_3Bg<{ILF8O~l>kOZRf$&PG! z;_COKb%?~3o@`Qd z5xGyXVf2w)HI_Yw^YD~|%c+?a5uX~cffaAnULzh;jssu;zON~t`n4~lr{+K3U3wy& zXJ6^inOye^rTcb^bUm)AP*fc$s&i={+ete+FQRRnUeyo`l#u z<3#1QwVEyvWs=GRc6qlKJ1%H-n6&5ldTadPh^)VU*jA~}7usPM#O>UFll92?0@>hw zM8|pZ)}?6XXXGE0OPTo{sh`yoXuibEmb!rtF;*+PbVg;B7nu7TG<2T;Wy$_6!(9tD z4^Bcen-;WQ`QIV^*Y@cDrvREUBj6%1DhsGGtp(G)qFkAml$uuY}SF?+}#BQDDd?k&5-W*;t+4j6;gj{$KpHdx_Un@F0@H_#<7{P@+}H8$^DJG2ADq&bn=eltdg(#)g!`+W?g4XP`Qh zG`1nDT-O`xaUF{{=}l8$CJv!|7e*gLr1gvvgb0t^ZP3Cv>KzmAFU?_c=NbI+`_IGf z=Z!ZL{fg!Q4!N$dZF1==`e6sTE-(+Tb&9O1^&1z26NAupU`DG(TO5`QUnJ+gdRy27 z@Mm8q9iu55s{-*jUCz*gSoNk5_>PYrAki^*$z)fRRiLQX;MG2vX!JW(>$A7TwR!_H z;ay1$9;AvLV!B|vBK}Zosmu3{r?rEo2PmbnG-$P(W+InWt3^sVS1d_^VPBXUCJq)Z0i9bX2=I*eBJnkFts#znQ>Fw=rtr zdZK>l(9$lEh^*Kr5ELq;zb_=NC>s|3Vj1Pc>!ny4QqU30eN*~MO0 zCe5rme?w}6)$0gLMghFwE+{c7=dPJ@z%}p6z)D0Y+&@g*%C*+_0l1R^w!H`Dy9Ly4 zp|0&=5FXoNWD|PIqTNkf;$K`F0rLzm1??6lNzk&z_&^}0wTn>xC#jEv**%^<)&!;C zF0_6xF1|SvrXy~_UukBz4D@gKHJ>7Ts`)9jBh2KxsUlRlsjE@~^)2uVYMIE`Fn5F| zPx3#_gjcPUDiG@8wVdk$*3wri%^B2PYq5~HDD;_rS!RrqkS0AB6m{3mVq@>V#+|_I zopNyG2ml!GJUc%GZim@h(|UdY+D2>2?98Oh>jx@u1L4OL6=ZBeCv2(x@llR0#NfCD zPx5*gfj8+Nexv;U5X`xezE?$FMKjE4#R~>{KL*2mqAH?Foe2c{!$~&WmtNLtOo>OX z6|^jG|#aaY6x)i{VJib;I9K8~J5!X$D@U;u=2Ca)9Z;*RQ70JA-8z z;;9x{YU{yN%Dm*#!gz^AM#+^UbNWa-h6CdtsV!~MqGMj7lP(}DS7iSh2%1#7cyFL( z|EK@6?Eh;Xw^iJS zxSq7JlDM2DOWW*bD`Bd*(_>XZNaIQW$l$taSOI-a4Za~RV;`%Bv9Y^%{I@N)Tq1_u zL~|)!WEJNhO_Blq;W_vv-*Mz7r*~;3ECy1talh6lMKg2Uf0!f={o#ys(rmYfH{xEA zi4e|$rNkC7o6I|L6;G2l6B+izIbzIp8I7n&nwUb2E zrGyB9apm}f_>&de6hm5yrpXimFy%4Io)sD5oiQ@L)tkr?!rC2` zsmlrv{;KJ84{<=+3Y#@Y^ZjR3ErzPKJiP4LlHXyPHf`BMMFBcRg8Z407wAWM;cbX<(MulajrYVPt z)^jGf5d4RZvw-Tu*Z3v|3GA~Y-)V6N2EUaN9cgah(_7q=RjFm0d*L_Ec0?<5hs8<| znMl!ZECf$*CYV8>_CJ(k1V0PYgz52nBr?&55xmtN=-UG?8M=0Ek>)B39m(i5rW>LZ zZr;Egf6P3^@qYn3qaSrq2lFjA^iWpfOOL?e#~`s!pcD6dL4OsHKit8X6v+<)aCFUC zrR&SW_eTPu@A_I35D+_j68uxZZf6)(>5LwiB8B_i0&IV84LIO^R$riy8T~&Y^IvPm zzaWDJqQ*uVp^U9A)QfO4Q{#@@#InK^zcNkJQv46lR7?znsq~RuMj|!?8H9E3k6rHZ zwA;rf``~OA?jA*mRQ#Kgsts?S^k1bc2WIS zwN}$jaokM`8EI@$PwdPETK%vD*Sd)_2{54Z%0$%4L4_;Jf%=i@k5{#pf&)~@308uk zOZjnSzV9uN$315cQl*A)ZpL)`DkBcqf7BZ{U^k|QmQ?Tgottipd*&2a=>*o$`x(ro zwK1u33{Pv8kR!0*IJeXGk7a3%)t}|RA)$U?aaUO7{-HEyjbFW2F3b+HK4=<0kteL; zJ9b~gR7y0b`8B#N5}y(V!P!bKrgJV%^L?Mv8d+~%TI(S*4D`DH1|T48n)7eQ4s;^< zq_Cn^gVW<8(0U5LE)LOaNeQy6LQc<@a( zHPa2Lnqq-bmY=P1a%oSvwo!Qzx^0}KNVrttaQPG5;>X^r_Bds61@DQ5*no(tH#`tF zK^d?S9v9ixI_Isb2dWe9gG}sm?u<*hNCfexyf1(7XOl8GfpqwfbF)T<5pX~q`R!lR4g9UJtpXG~_|Q9%|Gn<~YmMin zq2z%jh7kyxfmTnAFNZOcAz36Eb|M4Bq1T$hw!%`B-P?2uNpdu_u2}DrKmUUq9Eyi- z|DfhuFZd+zjHCT9(`jWIzs24?_tLQe-SoM96Ap%{4|4~&Y+kuL|&~gA$&os}n+$K3y;AxBBVQtl*?9NVb?!M&1cdvXs}FH}`e25X!! zhQGFNx`3)+s{>5bCKu+l)*l02ZIhspey1Qa%HXCmEVO1b@-FliGs(g6cZ7$oxh^l; zV@M|@>o>Y!9U&`yX)QnF)vG9ZiG0BpjSITcg22JBmeh@NO$%wkch8fs* z`g97nE}kKo(UZcfbO7{Y-$hMQ0t$!XqzhBtz-+aK+-1eq`7~+o8jpJJpZj53?1vPH-UbIPEauirvGW)sbS^mmw%m~}=zY<5pt3tUz^(*2c(P3iXxVp!VGWFM)2f^Rxhidw(cR)YWk$B-5}6FD#VOW*T`#d`nXYo0#gPxmwKvS@ zk?$>=-xu6)vuTivF2VT}3l7v{#kQDrXogRt0I%lR%n^)JP5j2%snRRmkCJ&0;_VgI zpJ$im@QL#;HfIWWm6N{m1-hfNNxlx_JVcYFxTRV8L0Zm7Paq6MzfHZ-zY4vVj2{}9 zX|KAT4l?vmpVO#5u2nde)4(&B&*H-5@EkcnG6zV3H@KT^-nCRJ}4{Uk~;~$m(CoYfe=N#)=AIs?$7uh)?-S&n6%PTG7Z;_iZGD%_- zbzKOPzMXD)IVLU3Gz4=8-#nK1s?^4|P08V&Pal8y(!pLaewS!ZUE$5E1YM(&%@@@yc{siti(HoZf?Iy-rPpV_8BR%A&dfdd z>38mNvG#I(UV~7<1@idL9Gw>3_O=qd@{Ua>7vIj~E#Wrj4ZecmIfXPf#UTB8= z+Fy}69L3BUQ8w|G&z27LB+D+%`ly0G%Z@byOM(D&xSZBSJI=!`aS$-*+LYY(Wm#Vt zF9l@AU)jpD=~3tGRE)>CP`}V+Sk8|ba}kn_XK(gnS_c`+jnPX_m;35id0v{^ZnZF# zD#x;w=cN3Bh{N7bY*LQo@px0ix}rK3CqIpWltyKzO?i|;+Dp1j%K(m%nd8R!WTlBq zW}+f}r{7t14FBDNhxbHs`kg6YQff;x@;gv=aUgMOpp~oE6oX$zE)+(i?@itoErTyv zdf0($+`CmFV^DbK!27@)O;ZR3A5b%KTUYxMMjKeY{T{h^QzD>v(;`4zszu^`@#mz+ z@GgBm2fflk)+{4@g4op+B}|^WL0Cqes5ANR9;L_vJ;f_m&&l>csREs$V1>RiS9}DA zcjd>P$_t)q<+$`(lg^pRo)sg~ZzG;70S7c|7$A-DJ&pinxzd2M43ncA=GDX#!#OWC z&EKN)T7(cQLPz&Ucy$zKg`;npu81aVH!kfwJQhuJ%QSQDxZKX5%9Kr+mdH`rfL32q z)YPIX$~bX;4SFqNKa)~L%8ZTPW@DYt3!Z~BH=aXDKiKVzeh@jVLuBM#M`4 zCz{$v%WGcd6nnDwKdng=IAWZ`)7=%dP?MEQo2$tTxU2*!2&R zgM`l!_W~IHM?~`~CKA7>p3o;LImsl$hA8yC%%Qfr-J?&Yqw_+i5AX$KFpJcmfa1*6 ztKrSm!P2%QW*|FcXI+mZnIp3I0YrHvdZ~$!8^unSiq2{MNBr9W&(c4lJ4Upl^HiMj zWbXYJ6kqpA9|hwn>T&aRj`lJR_TD*3A7(1m6n!$=Kjbe2U<-YtO4$ov;G`(slUj7{{7|&&%oefry^?M`Xi=)7-W-p zn9q0<-zv^6=gl86vfULn0$g_x|K$v3wEyo#v z^-TQU#8VEGFteTPNe5ogAiiTi$E$Y;-|i!X>Gb)sfL-i0qH=Qi{Vmun2Le0w4p+ zxm0Hzw5y?kM%W+0JMv0M`01U0dIdzc)((_=nbI!xlgwIV)+2Sc)K&X#TzF)@=XsvA zc#Q?hJ)dhcF5*SL)7LD;ZWZ@#!*S0Y_fhNkQiu%u@_rkimDR!g-8BNPBBS}I$0OA> z7kO1$Eh7_kg}Z)qUnh%Pil>AQCs3M6X|N-)d*^$45kw{Lk1aB=XrygEekBJI*9x!8 zxRcGEwbfSsP4VzIGm&a4aEiGwHEd%b%tE~A+FGu@JTG{S;qdw)ja0Unz$&E(LPG9U z%5d3fot#4nV2VGFR2b8iT8w;K@EMNTuSHvh1Y7D-0;Z!8R7w@X!N1*rrFYcmjX|GQ z9J-SDH&fhSYuEVXb%!}s{Gt3-6T3Obs?`oX9-GQJni?$PFjJ|-V=1%kdaF$c4vLn78o|6?;fHw&e4p za)k@5mpv#v)W<~$K%kD$&NdrUOdPaTg!3I3vz-L`3uyHRd#jJcjFiyPy>7ElZ7E~1 zFZY8-$cK}ihNsM@+1hCNciVR`!gxqLg4xIPES1hrIp>L}%L3>=GM%qcLfSzu<7(nk z%WPb%as{>Cqlx3V*gxu$ko*S>x6nSG%96Ni3wU?hp9OlN8`%1QG zQdGrhaMcnZ9Uqs?VT$;v3X=RbRxPu#oPUcFzt484Aig`_o37qnI$! z!ZrP#BD0cgA+m$6<3CgomE)SD;juF^1rF9yJT4}mhEIq>l&Xgc%+#5V;Mhkh=QIIx z88fU^6vG(HY)l&G?25Yyg3Dc4>294yl_<;ZW04-9%RD1IfSgR*V#}&vX|BRt3%>Y6 zKZQiVYaa%<*azg|x7zH9=pq)E zGcs3y6K4%XJ&qTIKJ3H45BGmwb!!-@{A2qthu+czuTVlB)~1yhL|Y~6XdeHGERnM> zV<~2)^~l>+XLWhXgZPy)1s+De1Zo_CpG`0Xx>Q3uRGP#9?*Ptnd(A6Z5f8j1xO%kI%sRw3pOojZ-O zQSYE%!(ep;=k~H-X+sX!H(QJ^ozu($QO;`?x8*U&3j%@|pF<*Q;>TNzOmta{IybP@ zwVJ!yJGO7jbk-bP)gi1KxW`=}{n#7a7z;Ry3VTA23>B(y_+#v2 z&?7iIM~Jy@cd_Ywn9zn#AjrL2&Cl_+1mCw`yU>bTYBgy#$!SiAeQMsBflbvfa6b?h zeRio&0(zoley6Bsx*$+nNBGL$+nM$ne#Yu(lzNdq>7IY2=jD(9ABrh;Kf!u5Zr**1B@*@O# zV@bgzRaE;Evg)Tq$tL1bf2Rne*`x+0K?BUjzaL=!x;^$%|BHsmGQ(}(J?~%RMt6i6O;KrXow#BP#U7}x1S5t_`Tp(uMGw?X(VDq>qU2eMbkbw&R61tqJx2`qo5RB)jxD=U5lY0VS8N z6R}Wm^x~Rzm3;7+hmuPpcplxC93D+f;iW0Y`KWF0N@ zt(TQOO$59=Y*B?M=puh1k{|@Z+V&rje75zPxHjV~zC9e!B^pYaWi8m^4-f7KmgZO@NgWvK>2pce`f_EmS(fC))Ue){ zo_6(3)06aA^D<{9`I~Ems(PW%tT?uKYIZMvGe&aFqK&YZ!Y)50$ zZa~dERVGB`cRnb{V)IaGW&0&(h22`rRnINjd+SwPnK&fx<{tbR?I80k71wTmwn<8V zo)r*|ct!UL4x@1B@dNePR(~&XW+*8_lp%P>V_CuNY};0`gX?^9DDe$Ur+9)yRcL`Q zM|ghN7ORJ5M{?(yKUQe*?wTLBUN#ji7X#{LuT7#rzYV))dbkm#UyEdy9!D_TKmuya zJYDi_qm28_-cI=73O3NzUD?V_mvKN$kkT9)CuHaU>N~=!iRyGgyrg6u(?Zp#<>MUx zLgbiQP^JB)Ns~3r#6$Dw@?I><0!f`C-N`^(2lgX>!#BU;{TwE0p2+cOk{bKr?ZQMu z!$4&k*}*&vhN%Oh69bk+<-&=T<`|9oC8#J|awEmBQO^p^B>6dw7AviWRLG?W44sZg zE0z$jr$HR3z~JuFr~BEsfz~ho61RXP;AN|_KbPCk4#l{{77u59W#ObJ%d*%aChQK^ z^HptKQXa*e_Yv=kO1w^!XMPI3)cI|EchhlURFzy{{0HvdpZ-W>>!B8_Pf*csG9;&h zqbr20gPl)G_xRF3i}rpqcjTMXHYqTOOlA(?HF16;mFtRnE%~}_X_sQZ{uuqXiOrF+ zm-YPQ+KF=H5)0Gn2#`M`{F5Ey!eLobCT;&{x5{J#0Z2fXIP~uR*-2!2oD&dG*6N$s z!?gvcHW#_BEFjs)ug#D|QfNG{zAkn%-2kMlkNiGt6vZ?BdlbT&Gf?5A_+e7C>dkNo$Z?62XunWK`6rJc2%#eb+0{c}bIb-00oE-1Y! zM+m(fW&Sa&E4pd0n2qg9A|4q-NtT+h^4_nV$Tj8U%*u!5O6EZX<#o>(e)z zT)6+0r&C~xgX3x9`T6$?Vu+0{`lf}jD2Y#Hh9p(5(OT8EFzLPS<&~-__w0+J!QNpm zr!$9+oT9Yp?|845K=~q-DS;&J`DH@b6BNZB)e3hOK4p*S8LH1V>p${DtrUi-RmVq& zZRdi=wfRdlVCt4vaFL7y!L$s{)d^CeL(X~p3uQu93qj&Uc9lkQ^+jBxs4@rLNfl{o zZi&c?O|J0g61WO7fDB=3o^nfp{p!gd7&apdXqcv>!|u^If+%hzT4Yreq!yDh9FnL` zp&#%xU!v>`A{D;MYc^r@zQYVN8g0kyns7t~N>z-t=eE62B5{R+stVx1W6f z)+=bYt<>!_Y4J}@C&Md@MK_fM^#caV>@C1^w=@l6=-`tw+!-H2hNqTjVlu!MD z#MyQ6^%tD(t=!?KH$3-bzbZnJ|AbWB5=ef00b+l+1cxNEN7{k#>ivX~Tg0A-x->L} z{Y~U20CgxI?c4Nx`R18gS`}^?_rIsie_u|sFnrSgbxHKE6}*Z?2-heyxkf?P~rA6ltwEGearB z6*o0&0eQt{Weig7Lv(74oT3zK{0WLR5E`A>*3_44bkzm7@+PwMhJl>`SOy$DdZgi{ zEG3+_D{)@yO59ljO24W@SH0hG5P1$mf2-_^%hbtSO1@%R6cuz+v_1o<|@W6rA3CCu*Dd?GZ>-QS}2>pRMkM1R6o2i)3_&+V3X)iJ&l z(e7e4R?BHwT=nLO$}Uca8^iN(O>C!wm_0R4yl5vQKSuzKrTU!Ee7-QqI<&>|!QXMN z4GTi1&K&FGc$bK{SGzm$DML2?WW%iO(<2(lm|zwZb)f z&vG2}v(weCRbI&gVhS3!z7Raxg=AV-@!bzo6GblTpx3zgg=IUev8`i;Z$}%+(Nn_= ze(h22c*Xh<>fL69QB|1FvIhw0N=@-=);FGRt_6AHY*{CAAwE>eOs>CtZpfl&s zZ;_Q&*}|DK*cW3IamjJduyN42nxI+}eQ~khup#!40t6RL{L_$fPoD7dPYW%@nq3di z^A{yaFs+bK?v44(ec-1QA&DxC@05zKp0J0jGI`g~b>o?=;%PX|`&$hEgiE3?Ev;k+ zNEbWl$T;r>mPzbIdMnZojs^rG5YeX}VdRla-1t8~gIZLg1y`dUBg33Vg>1KUngwBR z;zM3~@ioeK$(amBNcu2dDpDWcE^iUuP%@LKpHPkm>>4zEtHtd9n_d+a!$&h@XuNy} zEl~a+f$`U2Y6+Bj0gah~DR4v7L=UQcNI@Zm6ftUQYGJfrY$M)aHH~Gbti$M}tk0jr zT|rxRdCewyA-gmY`Lkv9ucn*k?~d~F7S~<;f1W1flZn8##i_r|9ie88b|fa@t?Kqz zA&Rje`~D#j0uPQwHtcszzSQBZb&qp3R3ML3#F8^iumJjj*}y~q#IgR**gY&&dt>8a zTCR-kLy396wVD}8u8(AE87B^A8{GS}^C*nJ>JS$k=UHYfqw#P*DOSfAO7SuPRo$ih zA25D+3T0*kyuK%B?1h&a)U@~1?1o*=<7O_u+Ogv>6L{K@G?Ey^Yji3i875a6kE08l zM=Q1ClGJp+@3va3`ksO_=1l^!wXW|?q^F})12)sB)sC2g{RaS_1RP4M?aEcK4XXvl zYR6<+T(BMc-3)2|oT5cM#tcb2k79#a6uU8S%>5nl{=d%7JD%$Af8ZizhU}TWlI$(n zWbZ_{xc1(&B0I_6DO+Y_uk4XzR*DEITV^Eu&i#BVpDVZe{NA6(edv$R`*~jHwa$5; zIo6uY5KG^*Pxz>En~-fjnG|a#pmOchAjzj{%lAZ#SQJg-C^2srUX2sjIgfF2+^yqD zkU=F&&bz`O`d~WE4|&=7IZ2{)RJ!@S1=HDg3sfX87DvW2gf1+Gl~*!a8l73Ez&u4| z6g8<&*SnW8`RU5Df)si=HI~}=2AdRdpTzX1Ec*EGZWOpI*a~Mg^-H(jx7iZ#s>JsE zv_6|t{wPOinK`UNRa`HcfCN3iK+R_E5mR6VGeu7kmxF9E%UM24E{*=dg>BiDlh+92 zYEun!giczm(S{7N+srLW#nYsqXIn12EM&d$sebFTlf*+v$Q=Mh{p6fw_A24cZu{ID zDl1m`c>~r#2G^C0s~ZF6MKO(Dcx~kd;(`8J#6@+I3#}p14?6I^uB6MIYo|5Efll0p z_BBeHqNv%LkXv}7?9us7F=tzDVb-ct6&qojalwDK;9(!9(#a@85?Rbn#|{ByhYYlc z8*jt#=mTRuFoblll%a^fwM^Y{PIfC(qB<}--Y_GgyLFFnbct~p=C6eCHJoYbA11kPwVw}k2;37bf;Ni=hP*;fYwdK7v*D4_30V~qu6EoG8!Xi4HLZG_&!=tOJ%UY|D=s(@w0iJ| zLD-}nC|AG%-D<`HI)s(_k8L06kQ>HYF=R4+A&Ks(%+$$Fw=?Y33G`AStEe|;<&a{% z_6}FMCmM_YMN996m5}RE_Gp>Pry~j#3f{No=P<0_Y3vI0T%$-H0#j$^B;DJO3Fpd_ z0~b$8KDKzpJZq$JO)n?AWRQ)bmxly7iS6Z}jw5q$nMLs(D@m_KpC-rK%tj&XOOMLt zGHhAxi=YC@?EE}>bRYa7i4g*2O4|~5B50o4p|=v{*WqDb+4@FWt=F6EK!4)v!k}gD z)qJ&K#aHf~=B&&lom{fI%^2E*BEj^XN~q_I?`CEgQC11?5sY=nQlwxkzc&dgJ%GeO z)&eRhmumaT%3d)_HZyI4@ zGm^#l?cYksgbf`F@(j5csxAa6SJ3*oNoO+X%&ne1IX_s4m1&-JB~Zf;OM`TR zSBEH;XF&V2w_edQZs3Q)d&LB!Dm{^4G|F;$&aVGeV^$@Owe3gzq)h5ggMf!VdL!pG z8@~v+&*o3s%5YteA$y!6VhcyNdBjxesKRM3FF4j;p7s=yAJoO^_0`xl(nz36|3rfH5vLG~PT#ivMW$WyU9CBYf?{SOp^a5#oqhMR@8l6FkO>4B>0)PkcGGhD46T>dQR zx+PEzZ>&|`KHAf*yp!iVZn)mjX1DEwhA?P&1~o@#@nF_hw)R9kOy-(hz}6ThV19Uq zc%itwz_{;>4RT?1G1E@zvN1iaJqwpG>~Pn7YRI!jcuG zZD{ig{qB|KLwcLA3&|6kviwr2p+*$B*kdx|O{9v}+v81?HWthzBW>|PwkYmu!>U}5 zZ(k3Z`!bvcX_Op&{+_Xl62gmVYJ{^(woF=m?=;yBj?Z*AjIUZGdD~yOttkK1HKrp# zcvy6|iLZ5?A?Qu9L!6p-UEY03N>Q`Khi{AA$luIWlDVB(VooY@88oTv%{nc9)>Ky@ zt>=+Dc5;m1xVnw=1D!yEOW3_~e*CmMZ~b48U{6V5Hm>&*kFh$vUdzWyK2H|SEcqn$ zc|jDVXR!Q9ujlt`M}(-wPR_URPO08AR<)dy!J0E|v*|5(#cY|pZ8JQoy%WX3AV|&_ zqkg}3C^?C}UBiH4z``jx@ALkey0lVl9etXvv|1?&>0MRDE#|G@sjWp;s7vknzC7ma z7WLg${A?PtSzW5kFTz398C3F)(lQ)AQcmY`EL5bh@WKVW;~PI&B+ybMaFMrVoj&9vY)?CAw39nbkllLRNk5(x|_D1 z+T;Dgd3;4o?8Yev0vxDK6BX(0krXNZEruv@ZJ9HYTx%l_T22tqQ^Y#R$(#+=xEf5y zvL+ng;+Tr2ul!6Pa7dnjlWj6Q;0YGF^%x<;YeKVL5A9da;u({%^g6Eh6{0KL7gfu1 z+zfqOE@8pSMPK0cZYpgBEvVr9WKie1_1t!9pz+_b5a5AiU*^f*;T{MydVsF#nogQuvc)c zJ%^R-L|3++(%1Oh6ys~|uE?=$JzLxUwj9w>Rak*6!FudEw^8`>Iw;S-x8vhkMn`rT z4y?MWtD9MvWYflE%*s03YKH!aAXQerS!P3yM2#a1^DH|nNhz0Qk@U(G%l`xdX9n&Y&02A+yjsOOLadCg0z_ z8f3vOKn^K-`Z!cLMa%}$ceAq|q>cyYhlNhg0kVHdCJ z7(HztxqXW_RJOIIDkN9TXh|fCq|x{~!vXdq6}fRwoE?Q5R4hTB%+2PagsT})y3UAi z6hinHTPa3o&(m$8cqaucSuQ?w_TP|S{AMdI)_tAE4XKWJewnr#`2)F214cpnk+0ax z4GYy5K}ZJu_mKQPmlvpMt${BOb`oWnv`~k1g%uV|oe#Bm#Z)U!@Hs9HjWMM5K_&N4 z+d#LXm6>t-LHRjt1s~hEuf6$uD%aAKX*{FeX+oEm8b7%_X!Nx|*j;LsMI!zzdp1*! zAxehPPgEeg!E)*Tt8vmLDE>B~d5l2tx;z*AnW?j8So(Yp452hi``9%n%^Y7grTSST zw{l@=RV+4M%@ZyzLiTG_fM{Mg-{-{@Q}OLG^ph~2pr2z;$t(Sr+j!lho_*TbexZDJ zy4U(*&COG2qR%qqPIc!|G5dM%IXqENnQ=~X&DNQe%3>WW(d#q*^sz>ez46KXsB6Oc zgWxurzL(x=MuX$c=&bzqbYu)I-AC1UGXB{JERf0%VW zHf>1<6-$Me*6qxKVBBkHU2bkVniu=K+G_@%gihKHIW1;h+A;F?RPmy7okwLE`u6CXrj{*Jq_kV%*EI>5KCJ4^Xen-XZyz*Z`r@ld?^Z66QWa|^&iP2a z)x(h8?uc09jG!q_2{zE@Cz4ASyR}F0q#+qCp76%UFVwP@9j7dC%*G{5l^dFyP8q-L z;D0PRdY_!bK;j_r0tM~$A#Dqja$-ZsYhn7Sn=i}^==gTdbbleCXfjU>oV!T!?X={* z3F9wJr?B_k6`wYLZrwKQZ9lV~a%(#bzvbb#M>(dK%ml7nlvnGtxW}K)ZGWG1!(_-bsF5 zZ@!iK$#=ZRbA0{7&N*;+(mia#P6x)@Pr3@2jreXmrfR53S(4ai6u!TJYJc8CR{GRR zj-x^Giu`&bk2C9FH3t?dadr(47UjC754A3P0k{Yps@hD5iivT_j3l{A|9t&(j%Y(H ziCh|e6O&?nV#x3yW&zeC)II{NH}Riei%#ff#0AHH;==lfsTCx-8A&cS>|q_qZzEpA znWr-vWFfEG#8FC7lRguob^bA$s^j&GAMQU%N(-s?Ry9}!Qwx$e9Q4c+MUdPJplhnQ z?;SJ(>XNjS!jdm;Y;RD^kuf^xH)~4flCak`zq?qWYGS&95!Qj*cUC@_1;E1hCj^C^NnOJXv4W;=x5 zv3%5F>a5Zv{`z%0S!2ul%%Pr+IR0ZDI7aj}F&!jk>!NmLT&(e?MPJG;@Ghg#4Ns$| zqmxY)5v_8>difgWQBNk|28{==L^fhQIMYC^=al#b8J)A%@KmgEywx4(aNO3Twv$Ut zH+?%x2D~c*119WnD48&znM5L^M60GTyU%YTN1s7nkoCG9v1n1R!PTmHGc1l?VnVnz z?ncC1*QWFkhTLPq*ZM>qqLMNzDI0U&p1MkIIl4^n2M4H@49ML*_nCeY+bj8=`2MNp z54%!ZCw*r)F5fh=*cu}mvFG%k`HHf%OX6{>d3b5(%|w*YDpHA!i3QTV z^x?3ZCTlc<);LkRqyEX{;{n=ZZRtuB<1JCL?Y5?*cCq^s#pQQ1u|~Vpp59azYPh1D zU5t-PN)s_Ke9`ezjOh~+pP)O6%?m1=;#&ea7W~q=micE?A4O=CD|b@mat=M>P&gmc zwM(+gTa0sXWM96!Ds)W_to6nOYrPo|?MgYi%sWoYRznXg^NtVDkJh(%i_FV&Io((i z8GFDgE`d4QN)3&WwxY32zS3c?w}I3B_D1e!%&&ns^A)4HvO`=?3^a*y(Qv(^I$jE5NWI_6IaHOJAi*x8<#E-8_eX=l!3Vc&4bDy_mPzBR0`Qv3f^df4w{p;49e7OEA}uZCUs(1k)>TLMTp&2+6T5~Z z=yNHV%_&Em2Nu;OlNv#nyVA@P<%xAb8J;FmlXCEfrQ{qZRYXCgY^euDEA$^O_)mT-dGute60+$VI!QAnT}CP zRZ?&k>R7D_y6EB)TH>PLoEUV0lERY`U6EV=5}hALv@wa`E|&{|>M*s7NE6@nI}wy5 zLT;;(VcW6RI?v@P8JV|7biZWY;ugB{a9(sGUcMsv6(qATCbIi085En4GJ-au5>GGQ zLE&ofNnWkEWKqfqqX&?3zsh^~v#%QRA$B>W9m2GlEy?t5>3AQ?G@rP&zoeX78$&Nu z#~Y9?_VTiCXw`1VanYxqj6ATNRAne094!2O#ZT-AI!1uncgu>Yhx}n zwyM$0zmna>Fv_zKO7|u7;3WMH`Naq^xs4@D8g|=YVcpV;@301@KUIy1A8?L;c;#kw z;i*EZ^X5=(I|N-peHcPk;QU&ebL_?z<8?I=)Y0fM)q7)?>+c)bu1vR|fesal#MPy~ zW2Vn#m#IauylQ~DaZPK;CO^b4;+g5}vur)X9kX}F;g?7uxuieCzg^@i{VIx&>}T#mW`{57cj{#haEm%0J;-`$ z*gZJ>+VyWH!_Fi3o|pErT&qNr<^CHdrCYpBH+Ja!GA@;>d4tLtJx!Wc~U~2ys=w&eeF%@w^{X%I6oa%G@AM!*5DRv-&m_JrHKV;y+R3exhV zG9j^pbV@sG@zgbJh3ev7C)D#-D;}Fc?x)w!C>YvuKd<_tPDq6@M>*ksN&;Fs`o^4D zG(^Tf9q-Nu*Vq7+Zs!@<==720MJ~2WeOYUgr7OAn5Nfxq@K~BGEb^KVA7p{nfSy=y zuU3==94QgH+3WgMp zr-*$ED_1Ux$YJvBoK83$bfr~2K^OOfjOpY9-m~6$GZi`INY;-nY&JEJhxVxTGT%uP z%%VPfH_kG`)M`|#<&wY3xJ0s(w9JBGg3>pr!{8C&(|Xb-nIn0e$tlXG-~hE9CvUSc zLkdNVQB1OHMCz$jB^qC_=QV=Imt_+Mgz$$26s~>^Uz3f&d3vP5dRv~@A_2Ta2h8;U zg_jtA_Y$>c<(A6?so8QYno=k6W*+iKN@jAds!ABw%SjBMG~TFg!eHo+ULv~r?6w!D z7i@{{v~{N6ZHuwq<(}o|_55`!d()fPO?b~(3XLw@WqXDF;c+@$NoG?d_^PD7q|YvJk#2`OH=)1xsd>v|1lEdho%4is3=vyO3z}Qxd%mTclUw=KU>Blqu0a zTo~a|Ym1MF4z*q6SbXtjoPV@RD7r6TV`uyEE`OlLn{1i6g+1X*4ULd~)=AJmE0?uk zD%8@SqVf*WFmFxw3sgxLmCvOx=J9L0u|&GaY1{^(mad{nV@i|Z)b$n*|LSv&bFkc) z16@!0<9UsETFjR!{ZzC>m;UuNV0lwck=bGiUkX^k^6#u*^1}+^;2cI0-|6I(+N312 z>Hc-B*4OA(ls}l8cOmsf?p4c6K zUf=Mv9(hETArO@&;0S;4~jt_5Ze`uXBd`KKhuZBVT|7({Y!8dU_6-CLX&l>FAU zf)VsguFKl+j0%hM%vXaUVa@%1*B8~ASana@BQ6H=N-w>_e&AqTIOga2{Prcw(U**p zWlLKk#U0TfRQ7fLF+&@-XnKx89TvkAAq^gsH>b|_yB3l%8()|0zD!Dvm7-C3(0-;c z;sZVn%B2zK{Tv4?;n&Qfz79RI#0gl*q>V0-a1>@2;kltc`W5G$C?l_=UPz`Z!(rZb%>w ze9nv!l4DE;Hn<1Yy!<&DxPRo#pGT^gv;-&-MQP#o`bUI>CExN_kSAnkh&nxytVk|n zF5kPM`jurL1;>gd59h|Mb5KujH02Qbc;1&oRl8}8zAqZwKYl7%5kt~%y+%g*Jd5+r zI?HULMh~W?z7(HQk3RnzGqbgUZbGc9AS#Lu51U2xGY-}1Mt#f+qxF5+SKXCX;~_3| zkuNG8&I>Da@Rii#6uN| zY`oj7X&1w_<^;88NY&04_qXh?~P5BO@;a&u%uY1>yh z9r@f%Cr|&2W?(o&a_pE*@ub}Cf;M;YY7sHy-MA;s)`K^_K>u2r+VIPsT@# zQrn>SSOpgnvRPMWPP1#1=1h-_t1adU)wSSMH*}Hayp<%9GuL>{5grwORd=0yHEl@IhGjJRwb(pg zvl90>t9NfyuyP?y)cFE}d*#fWF9yUIBoAn1Zeu7qpVOtBm1TOPdD9DL@P+Q%1=U2K zNhCJI5!p^+`b)?Iy7L%otomX_nuRaEorw01@(z$m9y7O~%8tr1GI90r`*^aqb$xf% z=UzF+SlrlopW8CSUozfLZz$i|98OYFMY5_FDtRMR67|iT9>dTvEFy?fs~{fFETiUQ^s9{2tPCQ z4h{V!qG()Rzv_#MfnJU617Y+>@n#jix>BE z?e|*jIzPU_OSq#?DN&(qc=ke|4L%DA&cW0u=E(i4BK)RK@dc9L0{f5tANAw?cwA7R znl75yg_$ysMKiw|4mVMt2|;NePW$fKV=#0D;|E`HqgX3-&gVO+cV|AlvF@8m#L2hR zUQfO%ppU5eD$$UU$!XpzQ<&G3l2D?4XCr!Bq%E8tZ1EZGdRm~Wan-UiEpppzqb~7j zp*C`my1w|bM%BYescZN8mraN+9qIijGe%CJ0W#KX{p>^JynZ z;Ghy;a7fCTZ@M?+uKROF1-3m5Rp8^5Q1tPP$G5UjDDIp(H-otu*uyjMWnZnM4*5KO z^GHs^xUX2>J@2%IK10K&D0$Oq5j^a8uQpoJ^ z=(i~Q@Ra;7taIQllYe}(cUn6obl|a?mo%>Z&UKkcf>bJQs;<5%HjCX<-3t?xU;XGt zFrP_hx?FzD-6^uQ6xCB-TF=iUcD8Y0BzB!3H`l}jglP`U&nmeWmzdEgg?^;88viD(YvCrnOSyx3LoY$GE!;6)wi&* z8Gtp>Di7qQXS(nsdeR)0o&9(3e{F3ke{M$5crDS6?wWNx1|KEX)vCNHE%f|n9&Z?* zUt4-E(|R3+_v*;UAZr=G58A2=* z3r>}xiS;v9HBQKDEc8=lHA$gq3G-nTuUT_L@F?O63?HveVvQymy$MaxWN>x}^T5K( zpk@9Ly^$$0H}UwZ7q=twl5CfLtO}N1bT7M6j5Ax5l-=2D&?}mSeR957EZ>eyab9`r zfE*26>Hc52(vO7)G5>6b3YxG~sEWNHapHtHGwq;y>5W^=Gm@7tCL1Yc8Gp7LIRka6 z8(mZm<=@BMLm78SH|VDh9p6m}Uwy8g<;Pb!m+Jhn-gztON$%5qpMw)dXUHAtqXv7V zu=r~^LQ^;uExmi1%Kcm@I8BWc2lxuU*jwB4ok4Lo?sA=C2UF+v?@vg&$P1|#act!B z`)a)*jHq}TIeIoqYB`Xu{G9zBSf& zcsm`ns6UhDB(tuqOBK&Lc7BRKQ+?l@#5&Vk>w+VL9IghH7;c&hb!Km3{6grM#_N2o zfXp>Arqb-{&1Jz7BEbO;mxREto%+mp_CiCN4_V^)2ZC?l>u}0dv1fU-gB#I2MNB!u zb_Z4DC)$vyIK%a+Ey~{~eX5~qeXn<;$(hgnS{dABs-<6B=fClSka z>MJJPxaJ-)x_+Sb9M3ytT%C@0vX)t)^X7$@ms&4-txrj>C-GxlPs@8dc2;_jTd_*D zLO=(tBedhfvjVNje(z*kt^Gmm%nBabQw_62vRkRcLieG$DZ|ibAbp?+$iYCI@ZkDpcOacXZ!Pq+CHF%-^Xuro1aze zxYr*i8q|IH1>RX#mjjBufPh!@B_{_UNM83}DN6+f-!MsKurR@z#*R%p<@tf!tMTOf zqnoU3DnhDKKvN|T#t{CTAAd~MNB?sTW6;4|JUgeItD)8PIy7lO;LWMZ8h;&&+E1;uWD?&f?7ql z4stKGcDveGp4>hA%<;M4JbYkn3;Bu^%ASZieEL zj|@G#N7sefzjhA|cgv~A<=%VOl%cCjj<+u;ch8Wb@%kAwf<;P?pJFrCJU%T`W0ZI) zrVRzV@|riEr|mLs%_>X%k*`ic35^aLkgkTo5lVly?)O>WxWl89x=bznka!Cff1@nUc74E7 zgM0S%8sr7^!OCJ!Rp0n}r`XeP7)E3h79{P3K|CL6Nt#nAlBh?j9I-z+7_^G8OO@WL z5@2`IAAAVm3qu=!h31_^S1=h8t>65TnW&VYo%h4A!~JQ>Kwa%y^<>(^TQUR%)sKSQ z>8b-qDPYSkaf{G8d*aKq<(E0yh_09DM`}AdGiu?s3lFkpf6L^Nq_?-Z+EO4CO*4wl zUscUeDgBJ#)hTq58k+kq_>~sIT)Zo9pqU=`7jw9?_(jaG1|>j9LilOc2Me?ZL$!kX z{jbx;G!V`ejw%bvKKYC_YK+!_uN#zBFH6N1`Yen&F?!axpM9ACD($BqW?5t9DWh9V zRxEzYv!_h7^d{ecsT$82_45&r_0=@VA<_3tC>?s#W1ZqX6R6*%(N$(oM;GKy713NA znF(7WOWVj)Huc>Sd&uVG)3u5xIo}`W`8sX}`O%GM7B9J<4?`#I&T?83Zp9rqn-tUW zO`jJYxMKGrpN2$6NKbu7u#BeRYlBTF+C8RZb{@)X*Km`&lC#VY^QLuEvkLhif|d6Q z_vAh>&qZGSG}2#+e%nN$lQJ=@e%i!X;GL5;zpp$=4%^Fffe~C59(WfyHz=pV&StjC z1gd9Fn+U|7qhuGM)Ux5msv@bO*4LeuoJ)PRitgqzrqyblIJvFaX}+!BNzA%+(bXrg zgjAVtc!ZaK&pmfMlEa*&W0W?wCg&{4PDyY_|AgkzN8nWLwN9tj-Hr z!Iy2xFj`m7RI;2|OQ0dOugwv_yRkTDW?Rz|&*qh1IzUL6S|;E|UCdXpOK_t#uI;2` zhA8%o(@TvlBAcPu8^mhZEqO7b1S)J)%E*xI9ETD-=^K~q@D<{pl7>{d*4J6+rEzG| zk%yl<#f&Ph#!C5c;qsokPPWmSmX`|lfQL7RVvWW{Z>w7Empm!slSZTdOuIXAPfVXm ziZ!u(<-R*O5ji0H?$$@nYp8NmIhz7$nX8`BZE{2pYnXPB*aU0tH1(nFBW>$2eMa`b zw8-k`&+}kz#Vf?Y!j^pp-@g^7`Aa`#(@F@NlBmoEUb!9)?%oB#iqrQY#G+q(MRP5~ zZ|&Vh@4%DwucSF^EjM_D?qv**%8t4f@lL2p#q%7ZUm zb7`;L>hE*Fp|f%gk77c3GC5$%CQ@;yx#GFI%07i{HHUu_J{H~cs40QgRW8qUj85J6 z7mcOfq%j)CE;$nvV(@eBkX&!x)oAPKZ+JVut<*lmEx*Rt@enKU6`70#S^(Xy>C-F1 zR+_sfC^L1{dgrFlgUGr|rtkV*zSzrZn0}7)Tf@z;n@7@>J-g4D0oWkfUo}QQH~YR* z9_1hrwZpVjmu!{k#IWJGQCUv8kQjNHHM!hT3tjUh{uf4Gy{uvJ9r3CA)g&Rd#^B02 zDyz2%xYSVbC=0YS$~O; z<6id74?DN1dTCum+EvTRt_OWJ$dWLp#z}1wbeUnwuIHdRiPe)7HbrG|b2ShnfYLrd zf$HPA$tC%L6_zit%rpJOOoKRG&&oF^paEfdsy61|3b0m0+;%_oS((m~=CwAL7EbbZ zl3%4b#Y#p-p;Ruws5bOD-UM}pr(AH{Bo4CN7~!tRRHJC4SWS+FSrgtz8`)Z;R{Zib zgnQQ1muczs^?+QdNla>RB{^l;3(%zRj(eO%P*7)WiPJS4H*P zk^PIk=QAb9flmy9-=CYX@B4%UBYR<^*MWW66*IZC$b=A+v5K-;naoquL2UsiZ=<*E zU1hAqyT(Q7!%95gG23$bb9(qtSSe<>b4-o9Q)723_qhl5D@bPsSWHk-2sKN!B(O&r z=NZXPPP2tecq&^6wMxCP_xNzSb3CzUCgYO<{>BZFnScy}#k4z8ckheLcKUlKuw5(D z?W4rauhNeo(&r%U7%;kGA#8W1PhJ%Blp?+oCZC&PIoo1}(#UT1^f{qb#)-ZsZ|0u1 zp*I^?t0t|YEKghyppBA@@4C^{M*rS~Pp6cJY16)BGkQ6mNCM#1$xFkM zp5T891wR7V|NZ^R@`D}z^Yc|Dab}7TSE#oX4gA2IYVcEtI6KklQ>2Kf1 zfqUN=?tK$`Cn(&@M=K6rfqO?^c7mF?*g>6tUjZ680a_6cm7kJ!Jk*MHs z$l#;*P#>T^KSi>4fS6dic>cC}@VdDK$Fj6_u=(xF#BhRG|N8QA);U_6L*ImX$irVD ze>4#ZoEU?@5=^14CQzWG-&O|R%g{h0cc@hxdlPF*JM-VZPY5T40Nnfk+RS|zWd93O z{^7J&uvQhe78G{e!jC7*&l(OP0gE+F3nwVVlwKX`U<2_~v^STwb8+(g-(=KLZbVuF z-W`xdZU76D|A2zOS$+Yi|E}7_ju4hvcZt55GRN&)CHW)DD7bab#Sq?w>w@~y@s7LP!JzIqDV-j z@MQq|9vbu~`Bw}qgH?-;;g>8~JIYu5d!>&!b) zZBF34lyKrTiXRKo^mO=s*zmvo5LVM2rSb+{fVvAb$PR~kCG~IAp<(GYJVEd|+1puq z{bM1->?d=&w42 zRXl^JwhSF`I&;jcokN^|F z$L%|9=Ocy3iCI{_Z-tT*`3b0zx2=5x%~Qkbjf@-5(TpvA4DSKJ|7qfL+w$ z$!7sC67XP0kN%EWZWYV_84^ zQPSSV27I0z+gXAMxrmHD6$GHqLB-({udw~GU^`Q&$ML4VbN%8N6+mHv6h!?)K=3!q z@0-JMC`E{qITW-r$J5eKFDGw+xAOrJUa+f9|EB%(WgzbC47D{zgSE5!U93T)?xw(8IupR)6T)o7FEA;nv!%J6im}!4;X&SOc~TZw z;{(tid?Q5?iJ0}DSQxj#Quu3H*vLv z+98M%98Ki=S)j5Lz{v0}s1c74_1pULZp)d=0pVPLaO7|0m1l42im2Q1_Nz#U7SNeH&>6g7DGv~U zek)j@?xNu`5G(-*2JgTenZNLUe#;*3!09(P?{)zWE|3qt19vS8F-rzwX#+L=%>V$b zO=BNZ*n+LGqXjmhfwPBg&M#hlT{Tz1t z*C^hPJg5mqpN?0>PHJt{Ch#2t3~-q!TmkC&e^bEE_62bfzE}cf8K4gBAh!A8ibyW` ziz5ErLLe?A^F{*nE+~W@6e0#!NL1Nh6e4K>HL;feIsEwt|Cv!0rtSw8@dvG@5L{v2 z6@OD0d?SUpQVBM9&JKYJp@R=*FkJET$@0sr`O9*CHeHBIY4UErF9TEu>rlYE!1Jen zRmzW+2XPU*^cc@4K@lfGWq5v81J*r*w){mAKieb3C46Ll7Y|F(At2qrt17YmZ%X){ z|Nl3=6U2DG!idmn zkXubb4d4^W?YDn{|Gw=KY6?0wpsVEkYeIxg4LFYPDy@P@*!(57BgYUG@?)Yy1M27s zIuT&B>3<{S|NBBcz8s094i_%qM(^p6kS_l;1S}-pO#ZQ)AGevoy1QV;#@XKPHyI07 zE97(PCO3iVZUO7Sw|JJT|1RyHDHkcI8N}7bwk?# z*pq{m&{rIa58M-p2b2KczYg0#RKgzy>tNXNwDG7|fHVQ_1Ro69o4;U{?T?JX{&rXq zhCfGMukQ@-pMlCR!WlT^%P;ujzwKee`^S4v15E~`2*7s$oE{D?xAPmgIbvdB{M79X zpo#cXM@L}zcM%f*H*A0yI#j=MgBXaY4+08)sGI5lG4#jyfwm>o9Wfh^iRK^;s9+25 z;l0A|#EE}R7+At)5r63S$9F$stbEvkH3~qc0A0Xi%}@|xHEba^HefgbF}9cC6E_Tb z9;6j`>|+o-htnHy(rP+Ep-K>kf0~Ws{opn64TuzwwhSm3{`)-|{TD3Ua0OyfZC+b@ zkbw+df_Zc}mkbL5^Jgy*G4;BF)!sHxfE`c(E1buA;T=!?cgGJg_chPF=L1mtZ1kg< ztriUGA5rW-8aOgWfEb+-`$AuVNL~+VN7+6giz?tE6fpQKJ z_(vxTF;z6i!UMLaPSgb0OmGql(f@&s7|Q>J zB+Lvz2SCb!cU~W61kmr@G{j8moJ+KpK&|1x&FJ9-Wn?>^`M*vLV&XzNQqwDtXBvT| z@WcTQ1jK*(F^Gu+B#I`ZKsF0Ng>QJ~z~s>pm;JeRKnk{qKtogMj}1@Q0K+{P`U>y` z_-+zDXhHvk|I1e2!aKc_8x$fB3b_QQ=YHP*M^%8$n70N{u8GKNKFkoBwzDuCMZ^^%C>9|=uSTA66PYkOI(1$?afa&(1 zPnO@j(0?o8_y%Cuxi}s+8F3frM(`&c){R6K`)~Z;nqb$;&hrK+;t5a|yrQ@+A6Jah z4-@=#vaM7_6U782Y=IwqP#}Z->4#qX!^l5NIGV(c*Ha(1Uma+@kT$^&-iP$TaLsS< zfApa)?K|eMamM0bR8t1FbpM9@*FLm>d>MHa_>d3CY4FO|midn*d_S50-!qypFNKVr z>xNBdA%Qx`!Ff^AmH$}6k0B>m2s(?KIJ#OoL62Ee0V_3EE>sx{w5_f9M`OcK@xPUN zyv>6eKIR-B8+BU$jsM%&7;#r=t_O;H0{Tqwt@(oXzl*W|vB1XpBCKok)BMK^e<@k0 zGy<4p8Ia){$0c0^)SpDo@7E?CHS;a*ZPh)%R07Tf&wQ%)N9HlBs$fRErdb~hlXLYK zIbr$w(Ea~a`$IVqxMMDTf(>jYc=i|OAeapK1M~YC`$y~EW@~&CmLxy@!h8t%Ba`QN z8!=M_(ZQyrvO$LfUZ0L8e`J2&0(ex;b&Dq05a{=Q7H>;|AhR$GXE&DOmWE~7#L^>C=|ZpmX3cy zeqY#q6sg~a*U=Af7eQpw!0D13e3>8XM{2H6Cr<>f-nLj>9}6ly4=N3hlW_YT4uO}i zi&V7t0;xbQI)Wqg`W+5|gIn!_W!OMEUSMT->1e!vheP1oMlS2ii|cQ^#@?DwqUu^~X&f)*Bj zc#JLt0q&ngYElpvh{lh>xZ`ug(c8a&xM7xGZ#W|Kad&|q_3fj#=^k=lM*STZK_hYW zF4sfwg60$?oV?UWZ)E2Z*@eUH90Fy^cEE(fgnd`2p$wiI2cPj$W&C$iJWU zpZJLK+|Op9lKVj{>6M~??NL_T@`CnSP|aP)A7Lu3e;i#xXA`|0oq za=_6O0S=L7V2{x6k;jBR%#V)l+C4-PzWNgqL8Kqu^m&M68Tk|PXXA+qI`K$I1>ir} MPLSX?pc9Vte--r#O8@`> diff --git a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/CommitBarrier.scala b/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/CommitBarrier.scala deleted file mode 100644 index 51737f34..00000000 --- a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/CommitBarrier.scala +++ /dev/null @@ -1,184 +0,0 @@ -/* scala-stm - (c) 2009-2016, Stanford University, PPL */ - -package scala.concurrent.stm - -import java.util.concurrent.TimeUnit - -object CommitBarrier { - - /** A class that describes the reason that a commit barrier member was not - * committed. Cancelled members might have been rolled back or might - * have been prevented from ever starting. - */ - sealed abstract class CancelCause - - /** The `CancelCause` used when the `addMember` call that created a member - * was from inside a transaction that later rolled back. This cancel - * cause does not necessarily imply that other members of the commit - * barrier didn't (or won't) eventually succeed. - */ - case object CreatingTxnRolledBack extends CancelCause - - /** The `CancelCause` used when some members of the commit barrier did not - * finish in time. Members may finish either by completing or by being - * cancelled. This cancel cause implies that all members were eventually - * cancelled. - */ - case object Timeout extends CancelCause - - /** The `CancelCause` used when some members of the commit barrier - * conflict with each other. Since the commit barrier can only succeed - * if all of them commit simultaneously this would lead to a deadlock, so - * the entire commit barrier is instead cancelled. This cancel cause - * implies that all members were eventually cancelled. - * - * `debugInfo` is optional information provided by the STM implementation - * to help locate the source of the avoided deadlock. If provided it - * might be one of the `Ref`s in the cycle, or it might be a `String` - * describing the cycle. - */ - case class MemberCycle(debugInfo: Any) extends CancelCause - - /** The `CancelCause` used when a member of the commit barrier cannot commit - * due to an uncaught exception (see `Txn.UncaughtExceptionCause`). This - * cancel cause implies that all members of the commit barrier rolled back. - * The exception will be rethrown to the thread running the member that - * originally generated the exception, all other members will get this - * `CancelCause`. - * - * This cancel cause will also be used if a member thread receives an - * interrupt while it is waiting for the commit barrier. - */ - case class MemberUncaughtExceptionCause(x: Throwable) extends CancelCause - - /** A `CancelCause` provided for users of commit barriers, not used by the - * STM itself. This cancel cause does not imply that other members of the - * commit barrier didn't (or won't) eventually succeed. - */ - case class UserCancel(info: Any) extends CancelCause - - /** A participant in a synchronized group commit. Each member of a commit - * barrier must arrange for either `atomic` or `cancel` to be called, - * otherwise the other members won't be able to commit. - */ - trait Member { - - /** Returns the commit barrier of which this instance is a member. */ - def commitBarrier: CommitBarrier - - /** Returns the `TxnExecutor` that will be used by `atomic`. This is - * initialized during construction to the default `TxnExecutor` - * (returned by `scala.concurrent.stm.atomic`). - */ - def executor: TxnExecutor - - /** Changes the `TxnExecutor` that will be used by `atomic`. */ - def executor_=(v: TxnExecutor) - - /** Atomically executes `body` as part of a commit barrier, ensuring - * that if the transaction commits, all actions performed by all - * members of the commit barrier appear to occur simultaneously. If - * the transaction commits then the value `v` returned by `body` is - * returned as `Right(v)`. If this member is cancelled then this method - * returns `Left(c)`, where `c` describes the first cause passed to - * the `cancel` method. If this member is not cancelled but the - * transaction is rolled back without the possibility of retry, then - * this method throws an exception the same as any other atomic block - * (see `TxnExecutor.apply`). - * - * It is not allowed to chain `orAtomic` onto this form of `atomic`, - * but you can accomplish the same effect with a nested atomic block:{{{ - * member.atomic { implicit txn => - * atomic { implicit txn => - * ... first alternative - * } orAtomic { implicit txn => - * ... second alternative - * } - * } - * }}} - * - * In the current version of ScalaSTM this method may only be used if - * there is no enclosing transaction; an STM implementation may throw - * `IllegalStateException` if there is already an active transaction on - * this thread. This restriction might be relaxed in the future if - * there is a use case for it (and a semantics for how it should work). - * - * @param underlying the `TxnExecutor` that should be used to actually - * execute the transaction, defaulting to the STM's default - * @param body the code to run atomically - * @return `Right(v)` where `v` is the result of successfully running - * `body` in an atomic block, or `Left(c)` where `c` is the - * reason for this member's cancellation - * @throws IllegalStateException if called from inside the dynamic - * scope of an existing transaction and that is not supported - * by the chosen STM implementation - */ - def atomic[Z](body: InTxn => Z): Either[CancelCause, Z] - - /** Removes this member from the commit barrier, and causes any pending - * or future calls to `this.atomic` to return a `Left`. If the commit - * barrier has already committed successfully this method throws - * `IllegalStateException`. It is safe to call this method multiple - * times. - * - * @param cause the cancel cause to return from `atomic` - * @throws IllegalStateException if the commit barrier has already - * decided to commit - */ - def cancel(cause: UserCancel) - } - - /** Constructs and returns a new `CommitBarrier` in which each member will - * wait at most `timeout` `unit` for other members of the barrier to - * become ready to commit. If timeout occurs all members will be - * cancelled with a `CancelCause` of `Timeout`. Each commit barrier may - * be used for at most one coordinated commit (it is not cyclic). - */ - @deprecated("The current CommitBarrier implementation doesn't have proper deadlock avoidance, please avoid if possible", "0.8") - def apply(timeout: Long, unit: TimeUnit = TimeUnit.MILLISECONDS): CommitBarrier = - impl.STMImpl.instance.newCommitBarrier(timeout, unit) -} - -/** A `CommitBarrier` allows multiple transactions on separate threads to - * perform a single atomic commit. All of the actions performed by all of - * the atomic blocks executed by members of the barrier will appear to - * occur as a single atomic action, even though they are spread across - * multiple threads. - * - * Commit barriers can be used to implement transactors, where actions - * taken by multiple actors should be atomic as a single unit. - * - * Because there is no ordering possible between the atomic blocks that - * make up a commit barrier, if those transactions conflict then the only - * way to avoid deadlock is to roll back all of the barrier's members. If - * you observe a cancel cause of `CommitBarrier.MemberCycle` then this has - * happened to you, and you need to run more of the logic on a single - * thread inside a single transaction. - * - * This abstraction is based on Multiverse's `CountDownCommitBarrier`, by - * Peter Veentjer. - * - * @author Nathan Bronson - */ -trait CommitBarrier { - import CommitBarrier._ - - /** Adds a new member to this coordinated commit and returns a `Member` - * instance that should be used to execute this member's atomic block. - * If the existing members of this commit barrier have already completed - * (committed or rolled back) then it is not possible to join the commit - * and this method will throw `IllegalStateException`. - * - * If a member is added from inside a transaction and that transaction is - * later rolled back, the member will be removed from the commit barrier - * (by `Member.cancel(CreatingTxnRolledBack)`), unless - * `cancelOnLocalRollback` is false. - * - * @param cancelOnLocalRollback controls whether the newly created member - * will be automatically cancelled if this call to `addMember` is - * from inside a transaction that later rolls back - * @throws IllegalStateException if this commit barrier has already been - * completed (committed or rolled back) - */ - def addMember(cancelOnLocalRollback: Boolean = true)(implicit txn: MaybeTxn): Member -} diff --git a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/InTxn.scala b/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/InTxn.scala deleted file mode 100644 index 29a2ea8b..00000000 --- a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/InTxn.scala +++ /dev/null @@ -1,14 +0,0 @@ -/* scala-stm - (c) 2009-2011, Stanford University, PPL */ - -package scala.concurrent.stm - -/** The presence of an implicit `InTxn` instance grants the caller permission - * to perform transactional reads and writes on `Ref` instances, as well as - * permission to call `object Txn` methods that require an `InTxnEnd`. - * `InTxn` instances themselves might be reused by the STM, use - * `NestingLevel.current` or `NestingLevel.root` to get a `NestingLevel` if - * you need to track an individual execution attempt. - * - * @author Nathan Bronson - */ -trait InTxn extends InTxnEnd diff --git a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/InTxnEnd.scala b/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/InTxnEnd.scala deleted file mode 100644 index e77ff675..00000000 --- a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/InTxnEnd.scala +++ /dev/null @@ -1,31 +0,0 @@ -/* scala-stm - (c) 2009-2011, Stanford University, PPL */ - -package scala.concurrent.stm - -/** The presence of an implicit `InTxnEnd` instance inside a transaction - * life-cycle handler grants permission to call methods in `object Txn` that - * locate nesting levels or register additional handlers. This functionality - * is separated from that granted by `InTxn` because `Ref` operations are not - * allowed from handlers after commit has begun. - * - * @author Nathan Bronson - */ -trait InTxnEnd extends MaybeTxn { - import Txn._ - - // The user-visible versions of these methods are in the Txn object. - - protected[stm] def status: Status - protected[stm] def rootLevel: NestingLevel - protected[stm] def currentLevel: NestingLevel - protected[stm] def rollback(cause: RollbackCause): Nothing - protected[stm] def retry(): Nothing - protected[stm] def retryFor(timeoutNanos: Long) - protected[stm] def beforeCommit(handler: InTxn => Unit) - protected[stm] def whilePreparing(handler: InTxnEnd => Unit) - protected[stm] def whileCommitting(handler: InTxnEnd => Unit) - protected[stm] def afterCommit(handler: Status => Unit) - protected[stm] def afterRollback(handler: Status => Unit) - protected[stm] def afterCompletion(handler: Status => Unit) - protected[stm] def setExternalDecider(decider: ExternalDecider) -} diff --git a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/MaybeTxn.scala b/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/MaybeTxn.scala deleted file mode 100644 index 8420c37a..00000000 --- a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/MaybeTxn.scala +++ /dev/null @@ -1,17 +0,0 @@ -/* scala-stm - (c) 2009-2011, Stanford University, PPL */ - -package scala.concurrent.stm - -object MaybeTxn { - implicit val unknown = TxnUnknown -} - -/** `MaybeTxn` allows lookup of the implicit `InTxn` instance without failing - * if the `InTxn` is not known at compile time. `implicitly[MaybeTxn]` will - * bind to an implicit `InTxn` if one is available, otherwise it will bind to - * the object `TxnUnkown`. A `MaybeTxn` of `TxnUnknown` should trigger a - * dynamically-scoped `InTxn` search using `Txn.findCurrent`. - * - * @author Nathan Bronson - */ -trait MaybeTxn diff --git a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/NestingLevel.scala b/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/NestingLevel.scala deleted file mode 100644 index 1d462d98..00000000 --- a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/NestingLevel.scala +++ /dev/null @@ -1,60 +0,0 @@ -/* scala-stm - (c) 2009-2011, Stanford University, PPL */ - -package scala.concurrent.stm - -object NestingLevel { - - /** Returns the `NestingLevel` that represents the current atomic block - * execution attempt. - */ - def current(implicit txn: InTxnEnd): NestingLevel = txn.currentLevel - - /** Returns the `NestingLevel` that represents the outermost atomic block - * that is currently being attempted. - */ - def root(implicit txn: InTxnEnd): NestingLevel = txn.rootLevel -} - -/** A `NestingLevel` instance describes a single attempt to execute an atomic - * block inside a transaction. Reads and writes performed by a transaction - * will only be made visible to other threads after (if) the root nesting - * level commits. - * - * Methods on this class may be called from any thread, and may be called - * after the corresponding execution attempt has been completed. - * - * @author Nathan Bronson - */ -trait NestingLevel { - import Txn._ - - /** Returns the `TxnExecutor` in which this attempt is executing. */ - def executor: TxnExecutor - - /** Returns the nearest enclosing nesting level, if any. */ - def parent: Option[NestingLevel] - - /** Returns the outermost enclosing nested transaction context, or this - * instance if it is the outermost nesting level. It is always true that - * `a.parent.isEmpty == (a.root == a)`. - */ - def root: NestingLevel - - /** Returns a snapshot of this nesting level's current status. The status - * may change to `Txn.RolledBack` due to the actions of a concurrent - * thread. This method may be called from any thread. - */ - def status: Status - - /** Requests that a transaction attempt be marked for rollback, possibly - * also rolling back some or all of the enclosing nesting levels. Returns - * the resulting status, which will be one of `Prepared`, `Committed` or - * `RolledBack`. Regardless of the status, this method does not throw an - * exception. - * - * Unlike `Txn.rollback(cause)`, this method may be called from any thread. - * Note that there is no facility for remotely triggering a rollback during - * the `Prepared` state, as the `ExplicitDecider` is given the final choice. - */ - def requestRollback(cause: RollbackCause): Status -} diff --git a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/PendingAtomicBlock.scala b/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/PendingAtomicBlock.scala deleted file mode 100644 index 89d7bf2e..00000000 --- a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/PendingAtomicBlock.scala +++ /dev/null @@ -1,37 +0,0 @@ -/* scala-stm - (c) 2009-2011, Stanford University, PPL */ - -package scala.concurrent.stm - -/** Instances of `PendingAtomicBlock` defer the execution of an atomic block - * until all of the alternatives can be gathered from the user. There is an - * implicit conversion in the `stm` package object from any type `A` to a - * `PendingAtomicBlock[A]`, which will kick in if there is an attempt to call - * `.orAtomic` on a value. - * - * @author Nathan Bronson - */ -class PendingAtomicBlock[A](above: => A) { - - /** See `atomic.oneOf`. */ - def orAtomic[B >: A](below: InTxn => B)(implicit mt: MaybeTxn): B = { - // Execution of Delayed.orAtomic proceeds bottom to top, with the upper - // portions being captured by-name in `above`. The actual transactional - // execution is all performed inside the top-most block (the one that - // used atomic rather than orAtomic). If a block other than the top one - // is the one that eventually succeeds, we must tunnel the value out with - // an exception because the alternatives may have a wider type. We only - // catch the exception if we are the bottom-most alternative, because - // only it is guaranteed to have been fully widened. - if (!atomic.pushAlternative(mt, below)) { - // we're not the bottom - above - } else { - // we're the bottom, this is the end of the result tunnel - try { - above - } catch { - case impl.AlternativeResult(x) => x.asInstanceOf[B] - } - } - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/Ref.scala b/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/Ref.scala deleted file mode 100644 index 7005ac04..00000000 --- a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/Ref.scala +++ /dev/null @@ -1,302 +0,0 @@ -/* scala-stm - (c) 2009-2012, Stanford University, PPL */ - -package scala.concurrent.stm - -import impl.{RefFactory, STMImpl} -import reflect.{AnyValManifest, OptManifest} - -/** `object Ref` contains factory methods that allocate an STM-managed memory - * location and return a `Ref` instance that provides access to that location. - * - * @author Nathan Bronson - */ -object Ref extends RefCompanion { - - protected def factory: RefFactory = STMImpl.instance - - /** `Ref.View` provides access to the contents of a `Ref` without requiring - * that an implicit `InTxn` be available. When called from within the - * dynamic scope of a transaction, `View`'s methods operate as part of that - * transaction. When there is no transaction active `View`'s methods are - * still atomic, but only for the duration of the method call. - * - * A mental model of `View` is that `view.foo(args)` acts like - * `atomic { implicit t => view.ref.foo(args) }`. - */ - trait View[A] extends Source.View[A] with Sink.View[A] { - - /** Returns a `Ref` that accesses the same memory location as this view. - * The returned `Ref` might be the original reference that was used to - * construct this view, or it might be a `Ref` that is equivalent - * (and `==`) to the original. - * @return a `Ref` that accesses the same memory location as this view. - */ - override def ref: Ref[A] - - /** Works like `set(v)`, but returns the old value. This is an - * atomic swap, equivalent to atomically performing a `get` - * followed by `set(v)`. - * @return the previous value held by `ref`. - */ - def swap(v: A): A - - /** Equivalent to atomically executing - * `(if (before == get) { set(after); true } else false)`, but may be more - * efficient, especially if there is no enclosing atomic block. - * @param before a value to compare against the `ref`'s contents using the - * value's `==` method. - * @param after a value to store if `before` was equal to the previous - * contents. - * @return true if `before` was equal to the previous value of the viewed - * `Ref`, false otherwise. - */ - def compareAndSet(before: A, after: A): Boolean - - /** Equivalent to atomically executing - * `(if (before eq get) { set(after); true } else false)`, but may be more - * efficient, especially if there is no enclosing atomic block. - * @param before a value to compare against the `ref`'s contents using - * reference identity equality (`eq`). - * @param after a value to store if `before` was `eq` to the previous - * contents. - * @return true if `before` was `eq` to the previous value of the viewed - * `Ref`, false otherwise. - */ - def compareAndSetIdentity[B <: A with AnyRef](before: B, after: A): Boolean - - /** Atomically replaces the value ''v'' stored in the `Ref` with - * `f`(''v''). Some `Ref` implementations may defer execution of `f` or - * call `f` multiple times to avoid transaction conflicts. - * @param f a function that is safe to call multiple times, and safe to - * call later during the enclosing atomic block, if any. - */ - def transform(f: A => A) - - /** Atomically replaces the value ''v'' stored in the `Ref` with - * `f`(''v''), returning the old value. `transform` should be preferred - * if the return value is not needed, since it gives the STM more - * flexibility to avoid transaction conflicts. - * @param f a function that is safe to call multiple times, and safe to - * call later during any enclosing atomic block. - * @return the previous value of the viewed `Ref`. - */ - def getAndTransform(f: A => A): A - - /** Atomically replaces the value ''v'' stored in the `Ref` with - * `f`(''v''), returning the new value. `transform` should be preferred - * if the return value is not needed, since it gives the STM more - * flexibility to avoid transaction conflicts. - * @param f a function that is safe to call multiple times, and safe to - * call later during any enclosing atomic block. - * @return the new value of the viewed `Ref`. - */ - def transformAndGet(f: A => A): A - - /** Atomically replaces the value ''v'' stored in the `Ref` with the first - * element of the 2-tuple returned by `f`(''v''), returning the second - * element. - * @param f a function that is safe to call multiple times. - * @return the second element of the tuple returned by `f`. - */ - def transformAndExtract[B](f: A => (A,B)): B = atomic { implicit txn => ref.transformAndExtract(f) } - - /** Atomically replaces the value ''v'' stored in the `Ref` with - * `pf`(''v'') if `pf.isDefinedAt`(''v''), returning true, otherwise - * leaves the element unchanged and returns false. `pf.apply` and - * `pf.isDefinedAt` might be invoked multiple times by the STM, and might - * be called later in any enclosing atomic block. - * @param pf a partial function that is safe to call multiple times, and - * safe to call later during any enclosing atomic block. - * @return `pf.isDefinedAt`(''v''), where ''v'' is the element held by - * this `Ref` on entry. - */ - def transformIfDefined(pf: PartialFunction[A,A]): Boolean - - /** Transforms the value stored in the `Ref` by incrementing it. - * - * '''Note: Implementations may choose to ignore the provided `Numeric[A]` - * instance if `A` is a primitive type.''' - * - * @param rhs the quantity by which to increment the value of `ref`. - */ - def += (rhs: A)(implicit num: Numeric[A]) { transform { v => num.plus(v, rhs) } } - - /** Transforms the value stored in the `Ref` by decrementing it. - * - * '''Note: Implementations may choose to ignore the provided `Numeric[A]` - * instance if `A` is a primitive type.''' - * - * @param rhs the quantity by which to decrement the value of `ref`. - */ - def -= (rhs: A)(implicit num: Numeric[A]) { transform { v => num.minus(v, rhs) } } - - /** Transforms the value stored in the `Ref` by multiplying it. - * - * '''Note: Implementations may choose to ignore the provided `Numeric[A]` - * instance if `A` is a primitive type.''' - * - * @param rhs the quantity by which to multiple the value of `ref`. - */ - def *= (rhs: A)(implicit num: Numeric[A]) { transform { v => num.times(v, rhs) } } - - /** Transforms the value stored in `ref` by performing a division on it, - * throwing away the remainder if division is not exact for instances of - * type `A`. The careful reader will note that division is actually - * provided by `Fractional[A]` or `Integral[A]`, it is not defined on - * `Numeric[A]`. To avoid compile-time ambiguity this method accepts a - * `Numeric[A]` and assumes that it can be converted at runtime into - * either a `Fractional[A]` or an `Integral[A]`. - * - * '''Note: Implementations may choose to ignore the provided `Numeric[A]` - * instance if `A` is a primitive type.''' - * - * @param rhs the quantity by which to divide the value of `ref`. - */ - def /= (rhs: A)(implicit num: Numeric[A]) { - num match { - //case numF: Fractional[A] => transform { v => numF.div(v, rhs) } - case numF: Fractional[_] => transform { v => numF.asInstanceOf[Fractional[A]].div(v, rhs) } - //case numI: Integral[A] => transform { v => numI.quot(v, rhs) } - case numI: Integral[_] => transform { v => numI.asInstanceOf[Integral[A]].quot(v, rhs) } - } - } - - // If you implement a Ref.View proxy, you should define a hashCode and - // equals that delegate to the underlying Ref or Ref.View. Ref and - // Ref.View that refer to the same memory location should be equal. - // - // override def hashCode: Int = underlying.hashCode - // override def equals(rhs: Any): Boolean = underlying == rhs - } -} - -// All of object Ref's functionality is actually in RefCompanion. The split -// allows RefCompanion to be tested independently of the globally configured -// RefFactory, without introducing an extra level of mutable indirection for -// normal uses of the companion object. - -trait RefCompanion { - - protected def factory: RefFactory - - /** Returns a `Ref` instance that manages a newly allocated memory location - * holding values of type `A`. If you have an initial value `v0` available, - * `Ref(v0)` should be preferred. - */ - def make[A]()(implicit om: OptManifest[A]): Ref[A] = (om match { - case m: ClassManifest[_] => m.newArray(0).asInstanceOf[AnyRef] match { - // these can be reordered, so long as Unit comes before AnyRef - case _: Array[Boolean] => apply(false) - case _: Array[Byte] => apply(0 : Byte) - case _: Array[Short] => apply(0 : Short) - case _: Array[Char] => apply(0 : Char) - case _: Array[Int] => apply(0 : Int) - case _: Array[Float] => apply(0 : Float) - case _: Array[Long] => apply(0 : Long) - case _: Array[Double] => apply(0 : Double) - case _: Array[Unit] => apply(()) - case _: Array[AnyRef] => factory.newRef(null.asInstanceOf[A])(m.asInstanceOf[ClassManifest[A]]) - } - case _ => factory.newRef(null.asInstanceOf[Any])(implicitly[ClassManifest[Any]]) - }).asInstanceOf[Ref[A]] - - /** Returns a `Ref` instance that manages a newly allocated memory location, - * initializing it to hold `initialValue`. The returned `Ref` is not part - * of any transaction's read or write set. - * - * Example: {{{ - * val x = Ref("initial") // creates a Ref[String] - * val list1 = Ref(Nil : List[String]) // creates a Ref[List[String]] - * val list2 = Ref[List[String]](Nil) // creates a Ref[List[String]] - * }}} - */ - def apply[A](initialValue: A)(implicit om: OptManifest[A]): Ref[A] = om match { - case m: AnyValManifest[_] => newPrimitiveRef(initialValue, m) - case m: ClassManifest[_] => factory.newRef(initialValue)(m.asInstanceOf[ClassManifest[A]]) - case _ => factory.newRef[Any](initialValue).asInstanceOf[Ref[A]] - } - - private def newPrimitiveRef[A](initialValue: A, m: AnyValManifest[_]): Ref[A] = { - (m.newArray(0).asInstanceOf[AnyRef] match { - case _: Array[Int] => apply(initialValue.asInstanceOf[Int]) - case _: Array[Boolean] => apply(initialValue.asInstanceOf[Boolean]) - case _: Array[Byte] => apply(initialValue.asInstanceOf[Byte]) - case _: Array[Short] => apply(initialValue.asInstanceOf[Short]) - case _: Array[Char] => apply(initialValue.asInstanceOf[Char]) - case _: Array[Float] => apply(initialValue.asInstanceOf[Float]) - case _: Array[Long] => apply(initialValue.asInstanceOf[Long]) - case _: Array[Double] => apply(initialValue.asInstanceOf[Double]) - case _: Array[Unit] => apply(initialValue.asInstanceOf[Unit]) - }).asInstanceOf[Ref[A]] - } - - def apply(initialValue: Boolean): Ref[Boolean] = factory.newRef(initialValue) - def apply(initialValue: Byte ): Ref[Byte] = factory.newRef(initialValue) - def apply(initialValue: Short ): Ref[Short] = factory.newRef(initialValue) - def apply(initialValue: Char ): Ref[Char] = factory.newRef(initialValue) - def apply(initialValue: Int ): Ref[Int] = factory.newRef(initialValue) - def apply(initialValue: Long ): Ref[Long] = factory.newRef(initialValue) - def apply(initialValue: Float ): Ref[Float] = factory.newRef(initialValue) - def apply(initialValue: Double ): Ref[Double] = factory.newRef(initialValue) - def apply(initialValue: Unit ): Ref[Unit] = factory.newRef(initialValue) -} - -/** Provides access to a single element of type ''A''. Accesses are - * performed as part of a ''memory transaction'' that comprises all of the - * operations of an atomic block and any nested blocks. Single-operation - * memory transactions may be performed without an explicit atomic block using - * the `Ref.View` returned from `single`. The software transactional memory - * performs concurrency control to make sure that all committed transactions - * are linearizable. Reads and writes performed by a successful transaction - * return the same values as if they were executed instantaneously at the - * transaction's commit (linearization) point. - * - * The static scope of an atomic block is defined by access to an implicit - * `InTxn` passed to the block by the STM. Atomic blocks nest, so to - * participate in an atomic block for which a `InTxn` is not conveniently - * available, just create a new atomic block using {{{ - * atomic { implicit t => - * // the body - * } - * }}} - * In the static scope of an atomic block reads and writes of a `Ref` - * are performed by `x.get` and `x.set(v)`, or more concisely by `x()` and - * `x() = v`. `x.single` returns a `Ref.View` that will dynamically resolve - * the current scope during each method call, automatically creating a - * single-operation atomic block if no transaction is active. - * - * It is possible for separate `Ref` instances to refer to the same element; - * in this case they will compare equal. (As an example, a transactional - * array class might store elements in an array and create `Ref`s on demand.) - * `Ref`s may be provided for computed values, such as the emptiness of a - * queue, to allow conditional retry and waiting on semantic properties. - * - * To perform an access outside a transaction, use the view returned by - * `single`. Each access through the returned view will act as if it was - * performed in its own single-operation transaction, dynamically nesting into - * an active atomic block as appropriate. - * - * `Ref`'s companion object contains factory methods that create `Ref` - * instances paired with a single STM-managed memory location. - * - * @author Nathan Bronson - */ -trait Ref[A] extends RefLike[A, InTxn] with Source[A] with Sink[A] { - - /** Returns a `Ref.View` that allows access to the contents of this `Ref` - * without requiring that a `InTxn` be available. Each operation on the view - * will act as if it is performed in its own "single-operation" atomic - * block, nesting into an existing transaction if one is active. - * - * A mental model of this method is that `ref.single.foo(args)` acts like - * `atomic { implicit t => ref.foo(args) }`. - */ - override def single: Ref.View[A] - - // If you implement a Ref proxy, you should define a hashCode and - // equals that delegate to the underlying Ref or Ref.View. Ref and - // Ref.View that refer to the same memory location should be equal. - // - // override def hashCode: Int = underlying.hashCode - // override def equals(rhs: Any): Boolean = underlying == rhs -} diff --git a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/RefLike.scala b/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/RefLike.scala deleted file mode 100644 index d826472c..00000000 --- a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/RefLike.scala +++ /dev/null @@ -1,119 +0,0 @@ -/* scala-stm - (c) 2009-2012, Stanford University, PPL */ - -package scala.concurrent.stm - - -/** Provides all of the operations of a `Ref[A]`, without the ability to get a - * `Ref.View`. - * - * @author Nathan Bronson - */ -trait RefLike[A, Context] extends SourceLike[A, Context] with SinkLike[A, Context] { - - // read-only operations (covariant) are in SourceLike - // write-only operations (contravariant) are in SinkLike - // read+write operations go here - - /** Works like `set(v)`, but returns the old value. - * @return the previous value of this `Ref`, as observed by `txn`. - * @throws IllegalStateException if `txn` is not active. - */ - def swap(v: A)(implicit txn: Context): A - - /** Transforms the value referenced by this `Ref` by applying the function - * `f`. Acts like `ref.set(f(ref.get))`, but the execution of `f` may be - * deferred or repeated by the STM to reduce transaction conflicts. - * @param f a function that is safe to call multiple times, and safe to - * call later during the transaction. - * @throws IllegalStateException if `txn` is not active. - */ - def transform(f: A => A)(implicit txn: Context) - - /** Transforms the value referenced by this `Ref` by applying the function - * `f`, and returns the new value. - * @param f a function that is safe to call multiple times. - * @return the new value of this `Ref` (the value returned from `f`). - * @throws IllegalStateException if `txn` is not active. - */ - def transformAndGet(f: A => A)(implicit txn: Context): A = { val z = f(get) ; set(z) ; z } - - /** Transforms the value referenced by this `Ref` by applying the function - * `f`, and returns the previous value. - * @param f a function that is safe to call multiple times. - * @return the previous value of this `Ref` (the value passed to `f`). - * @throws IllegalStateException if `txn` is not active. - */ - def getAndTransform(f: A => A)(implicit txn: Context): A = { val z = get ; set(f(z)) ; z } - - /** Transforms the value referenced by this `Ref` from ''v'' to - * `f`(''v'')`._1`, and returns `f`(''v'')`._2`. - * @param f a function that is safe to call multiple times. - * @return the second element of the pair returned by `f`. - * @throws IllegalStateException if `txn` is not active. - */ - def transformAndExtract[B](f: A => (A,B))(implicit txn: Context): B = { val p = f(get) ; set(p._1) ; p._2 } - - /** Transforms the value ''v'' referenced by this `Ref` by to - * `pf.apply`(''v''), but only if `pf.isDefinedAt`(''v''). Returns true if - * a transformation was performed, false otherwise. `pf.apply` and - * `pf.isDefinedAt` may be deferred or repeated by the STM to reduce - * transaction conflicts. - * @param pf a partial function that is safe to call multiple times, and - * safe to call later in the transaction. - * @return `pf.isDefinedAt(v)`, where `v` was the value of this `Ref` - * before transformation (if any). - * @throws IllegalStateException if `txn` is not active. - */ - def transformIfDefined(pf: PartialFunction[A,A])(implicit txn: Context): Boolean - - /** Transforms the value stored in the `Ref` by incrementing it. - * - * '''Note: Implementations may choose to ignore the provided `Numeric[A]` - * instance if `A` is a primitive type.''' - * - * @param rhs the quantity by which to increment the value of this `Ref`. - * @throws IllegalStateException if `txn` is not active. */ - def += (rhs: A)(implicit txn: Context, num: Numeric[A]) { transform { v => num.plus(v, rhs) } } - - /** Transforms the value stored in the `Ref` by decrementing it. - * - * '''Note: Implementations may choose to ignore the provided `Numeric[A]` - * instance if `A` is a primitive type.''' - * - * @param rhs the quantity by which to decrement the value of this `Ref`. - * @throws IllegalStateException if `txn` is not active. */ - def -= (rhs: A)(implicit txn: Context, num: Numeric[A]) { transform { v => num.minus(v, rhs) } } - - /** Transforms the value stored in the `Ref` by multiplying it. - * - * '''Note: Implementations may choose to ignore the provided `Numeric[A]` - * instance if `A` is a primitive type.''' - * - * @param rhs the quantity by which to multiply the value of this `Ref`. - * @throws IllegalStateException if `txn` is not active. - */ - def *= (rhs: A)(implicit txn: Context, num: Numeric[A]) { transform { v => num.times(v, rhs) } } - - /** Transforms the value stored the `Ref` by performing a division on it, - * throwing away the remainder if division is not exact for instances of - * type `A`. The careful reader will note that division is actually - * provided by `Fractional[A]` or `Integral[A]`, it is not defined on - * `Numeric[A]`. To avoid compile-time ambiguity this method accepts a - * `Numeric[A]` and assumes that it can be converted at runtime into - * either a `Fractional[A]` or an `Integral[A]`. - * - * '''Note: Implementations may choose to ignore the provided `Numeric[A]` - * instance if `A` is a primitive type.''' - * - * @param rhs the quantity by which to divide the value of this `Ref`. - * @throws IllegalStateException if `txn` is not active. - */ - def /= (rhs: A)(implicit txn: Context, num: Numeric[A]) { - num match { - //case numF: Fractional[A] => transform { v => numF.div(v, rhs) } - case numF: Fractional[_] => transform { v => numF.asInstanceOf[Fractional[A]].div(v, rhs) } - //case numI: Integral[A] => transform { v => numI.quot(v, rhs) } - case numI: Integral[_] => transform { v => numI.asInstanceOf[Integral[A]].quot(v, rhs) } - } - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/Sink.scala b/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/Sink.scala deleted file mode 100644 index 8c66daf7..00000000 --- a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/Sink.scala +++ /dev/null @@ -1,48 +0,0 @@ -/* scala-stm - (c) 2009-2011, Stanford University, PPL */ - -package scala.concurrent.stm - -object Sink { - - /** `Sink.View[+A]` consists of the contra-variant write-only operations of - * `Ref.View[A]`. - */ - trait View[-A] { - - /** Returns a `Sink` that accesses the same memory location as this view. - * The returned `Sink` might be the original reference that was used to - * construct this view, or it might be a `Sink` that is equivalent (and - * `==`) to the original. - * @return a `Sink` that accesses the same memory location as this view. - */ - def ref: Sink[A] - - /** Performs an atomic write of the value in `ref`. If an atomic block - * is active (see `Txn.findCurrent`) then the write will be performed - * as part of the transaction, otherwise it will act as if it was - * performed inside a new atomic block. Equivalent to `set(v)`. - */ - def update(v: A) { set(v) } - - /** Performs an atomic write; equivalent to `update(v)`. */ - def set(v: A) - - /** Performs an atomic write and returns true, or returns false. The - * STM implementation may choose to return false to reduce (not - * necessarily avoid) blocking. If no other threads are performing any - * transactional or atomic accesses then this method will succeed. - */ - def trySet(v: A): Boolean - } -} - -/** `Sink[+A]` consists of the contra-variant write-only operations of - * `Ref[A]`. - * - * @author Nathan Bronson - */ -trait Sink[-A] extends SinkLike[A, InTxn] { - - /** See `Ref.single`. */ - def single: Sink.View[A] -} diff --git a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/SinkLike.scala b/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/SinkLike.scala deleted file mode 100644 index 7e378ab5..00000000 --- a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/SinkLike.scala +++ /dev/null @@ -1,43 +0,0 @@ -/* scala-stm - (c) 2009-2010, Stanford University, PPL */ - -package scala.concurrent.stm - - -/** Provides all of the operations of a `Sink[A]`, without the ability to get - * a `Sink.View`. - * - * @author Nathan Bronson - */ -trait SinkLike[-A, Context] { - - /** Performs a transactional write. The new value will not be visible by - * any other threads until (and unless) `txn` successfully commits. - * Equivalent to `set(v)`. - * - * Example: {{{ - * val x = Ref(0) - * atomic { implicit t => - * ... - * x() = 10 // perform a write inside a transaction - * ... - * } - * }}} - * @param v a value to store in the `Ref`. - * @throws IllegalStateException if `txn` is not active. */ - def update(v: A)(implicit txn: Context) { set(v) } - - /** Performs a transactional write. The new value will not be visible by - * any other threads until (and unless) `txn` successfully commits. - * Equivalent to `update(v)`. - * @param v a value to store in the `Ref`. - * @throws IllegalStateException if `txn` is not active. - */ - def set(v: A)(implicit txn: Context) - - /** Performs a transactional write and returns true, or returns false. The - * STM implementation may choose to return false to reduce (not necessarily - * avoid) blocking. If no other threads are performing any transactional or - * atomic accesses then this method will succeed. - */ - def trySet(v: A)(implicit txn: Context): Boolean -} diff --git a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/Source.scala b/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/Source.scala deleted file mode 100644 index d46b9dd4..00000000 --- a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/Source.scala +++ /dev/null @@ -1,102 +0,0 @@ -/* scala-stm - (c) 2009-2012, Stanford University, PPL */ - -package scala.concurrent.stm - -import java.util.concurrent.TimeUnit -import skel.RollbackError -import concurrent.stm.Txn.RolledBack - -object Source { - - /** `Source.View[+A]` consists of the covariant read-only operations of - * `Ref.View[A]`. - */ - trait View[+A] extends TxnDebuggable { - - /** Returns a `Source` that accesses the same memory location as this view. - * The returned `Source` might be the original reference that was used to - * construct this view, or it might be a `Source` that is equivalent (and - * `==`) to the original. - * @return a `Source` that accesses the same memory location as this view. - */ - def ref: Source[A] - - /** Performs an atomic read of the value in `ref`. If an atomic block is - * active (see `Txn.findCurrent`) then the read will be performed as part - * of the transaction, otherwise it will act as if it was performed inside - * a new atomic block. Equivalent to `get`. - * @return the value of the `Ref` as observed by the current context. - */ - def apply(): A = get - - /** Performs an atomic read; equivalent to `apply()`. - * @return the value of the `Ref` as observed by the current context. - */ - def get: A - - /** Acts like `ref.getWith(f)` if there is an active transaction, otherwise - * just returns `f(get)`. - * @param f an idempotent function. - * @return the result of applying `f` to the value contained in `ref`. - */ - def getWith[Z](f: A => Z): Z - - /** Acts like `ref.relaxedGet(equiv)` if there is an active transaction, - * otherwise just returns `get`. - * @param equiv an equivalence function that returns true if a transaction - * that observed the first argument will still complete correctly, - * where the second argument is the actual value that should have been - * observed. - * @return a value of the `Ref`, not necessary consistent with the rest of - * the reads performed by the active transaction, if any. - */ - def relaxedGet(equiv: (A, A) => Boolean): A - - /** Blocks until `f(get)` is true, in a manner consistent with the current - * context. Requires that the predicate be safe to reevaluate, and that - * `f(x) == f(y)` if `x == y`. - * - * `v.await(f)` is equivalent to {{{ - * atomic { implicit t => - * if (!f(v.get)) retry - * } - * }}} - * - * If you want to wait for a predicate that involves more than one `Ref` - * then use `retry` directly. - * @param f a predicate that is safe to evaluate multiple times. - */ - def await(f: A => Boolean) - - /** Blocks until `f(get)` is true and returns true, or returns false if - * the condition does not become true within within the specified timeout. - * - * `v.tryAwait(timeout)(f)` is equivalent to {{{ - * atomic { implicit t => - * f(v.get) || { retryFor(timeout) ; false } - * } - * }}} - * - * @param f a predicate that is safe to evaluate multiple times. - * @param timeout the maximum amount of time to wait, in units of `unit`. - * @param unit the units in which the timeout is measured, defaulting to - * milliseconds. - * @return true if the predicate was satisfied, false if the wait timed - * out. - */ - def tryAwait(timeout: Long, unit: TimeUnit = TimeUnit.MILLISECONDS)(f: A => Boolean): Boolean - - def dbgStr: String = ref.dbgStr - def dbgValue: Any = ref.dbgValue - } -} - -/** `Source[+A]` consists of the covariant read-only operations of `Ref[A]`. */ -trait Source[+A] extends SourceLike[A, InTxn] with TxnDebuggable { - - /** See `Ref.single`. */ - def single: Source.View[A] - - def dbgStr: String = atomic.unrecorded({ implicit txn => "Ref(" + get + ")" }, { _.toString }) - def dbgValue: Any = atomic.unrecorded({ get(_) }, { x => x }) -} diff --git a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/SourceLike.scala b/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/SourceLike.scala deleted file mode 100644 index 57572f15..00000000 --- a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/SourceLike.scala +++ /dev/null @@ -1,79 +0,0 @@ -/* scala-stm - (c) 2009-2010, Stanford University, PPL */ - -package scala.concurrent.stm - - -/** Provides all of the operations of a `Source[A]`, without the ability to get - * a `Source.View`. - * - * @author Nathan Bronson - */ -trait SourceLike[+A, Context] { - - /** Performs a transactional read and checks that it is consistent with all - * reads already made by `txn`. Equivalent to `get`. - * - * Example: {{{ - * val x = Ref(0) - * atomic { implicit t => - * ... - * val v = x() // perform a read inside a transaction - * ... - * } - * }}} - * @param txn an active transaction. - * @return the value of the `Ref` as observed by `txn`. - * @throws IllegalStateException if `txn` is not active. - */ - def apply()(implicit txn: Context): A = get - - /** Performs a transactional read and checks that it is consistent with all - * reads already made by `txn`. Equivalent to `apply()`, which is more - * concise in many situations. - * @param txn an active transaction. - * @return the value of the `Ref` as observed by `txn`. - * @throws IllegalStateException if `txn` is not active. - */ - def get(implicit txn: Context): A - - /** Returns `f(get)`, possibly reevaluating `f` to avoid rollback if a - * conflicting change is made but the old and new values are equal after - * application of `f`. Requires that `f(x) == f(y)` if `x == y`. - * - * `getWith(f)` is equivalent to `f(relaxedGet({ f(_) == f(_) }))`, although - * perhaps more efficient. - * @param f an idempotent function. - * @return the result of applying `f` to the value contained in this `Ref`. - */ - def getWith[Z](f: A => Z)(implicit txn: Context): Z - - /** Returns the same value as `get`, but allows the caller to determine - * whether `txn` should be rolled back if another thread changes the value - * of this `Ref` before `txn` is committed. If `ref.relaxedGet(equiv)` - * returns `v0` in `txn`, another context changes `ref` to `v1`, and - * `equiv(v0, v1) == true`, then `txn` won't be required to roll back (at - * least not due to this read). If additional changes are made to `ref` - * additional calls to the equivalence function will be made, always with - * `v0` as the first parameter. - * - * `equiv` will always be invoked on the current thread. Extreme care - * should be taken if the equivalence function accesses any `Ref`s. - * - * As an example, to perform a read that will not be validated during commit - * you can use the maximally permissive equivalence function: {{{ - * val unvalidatedValue = ref.relaxedGet({ (_, _) => true }) - * }}} - * To check view serializability rather than conflict serializability for a - * read: {{{ - * val viewSerializableValue = ref.relaxedGet({ _ == _ }) - * }}} - * The `getWith` method provides related functionality. - * @param equiv an equivalence function that returns true if a transaction - * that observed the first argument will still complete correctly, - * where the second argument is the actual value that should have been - * observed. - * @return a value of the `Ref`, not necessary consistent with the rest of - * the reads performed by `txn`. - */ - def relaxedGet(equiv: (A, A) => Boolean)(implicit txn: Context): A -} diff --git a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/TArray.scala b/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/TArray.scala deleted file mode 100644 index 97f6c1f1..00000000 --- a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/TArray.scala +++ /dev/null @@ -1,94 +0,0 @@ -/* scala-stm - (c) 2009-2012, Stanford University, PPL */ - -package scala.concurrent.stm - -import scala.collection.{mutable, immutable} - -object TArray { - - /** A view that supports accesses to a `TArray` instance outside the static - * scope of a `Txn`. `TArray.View` is to `TArray` as `Ref.View` is to - * `Ref`. - */ - trait View[A] extends mutable.IndexedSeq[A] with TxnDebuggable { - /** The `TArray` from which this view was created. */ - def tarray: TArray[A] - - def length: Int - - /** Performs an atomic read of the `index`th element of `array`. If an - * atomic block is active (see `Txn.findCurrent`) then the read will be - * performed as part of the transaction, otherwise it will act as if it - * was performed inside a new atomic block. - */ - def apply(index: Int): A - - /** Performs an atomic write of the `index`th element of `array`. If an - * atomic block is active (see `Txn.findCurrent`) then the write will be - * performed as part of the transaction, otherwise it will act as if it - * was performed inside a new atomic block. - */ - def update(index: Int, v: A) - - /** Returns a sequence of `Ref.View` that are backed by the elements of - * `array`. All operations on the contained `Ref.View`s are supported. - */ - def refViews: immutable.IndexedSeq[Ref.View[A]] - } - - //////////////// factory methods - - // We don't include apply(xs: A*) because it is surprising when - // TArray[Int](1000) creates a TArray of length 1. - - /** Returns a new `TArray[A]` containing `length` copies of the default value - * for elements of type `A`. - */ - def ofDim[A : ClassManifest](length: Int): TArray[A] = impl.STMImpl.instance.newTArray[A](length) - - /** Returns a new `TArray[A]` containing the elements of `data`. */ - def apply[A : ClassManifest](data: TraversableOnce[A]): TArray[A] = impl.STMImpl.instance.newTArray[A](data) -} - -/** Bulk transactional storage, roughly equivalent to `Array[Ref[T]]` but - * potentially much more space efficient. Elements can be read and written - * directly, or the `refs` method can be used to obtain transient `Ref` - * instances backed by the elements of the `TArray`. - * - * @author Nathan Bronson - */ -trait TArray[A] extends TxnDebuggable { - - /** Returns the length of this `TArray`, which does not change. */ - def length: Int - - /** Performs a transactional read of the `index`th element of this - * transactional array. Equivalent to `refs(index).get`. - */ - def apply(index: Int)(implicit txn: InTxn): A - - /** Performs a transactional write to the `index`th element of this - * transactional array. Equivalent to `refs(index).set(v)`. - */ - def update(index: Int, v: A)(implicit txn: InTxn) - - /** Returns a `TArray.View` that allows access to the contents of this - * `TArray` without requiring that an `InTxn` be available. See `Ref.View`. - */ - def single: TArray.View[A] - - /** Returns a sequence of `Ref` instances that are backed by elements of this - * `TArray`. All operations on the contained `Ref`s are supported. - * - * As an example, the following code tests whether `a(i)` is greater than - * 10 without requiring the transaction to roll back for all writes to - * `a(i)`: {{{ - * atomic { implicit t => - * if (a.refs(i).getWith( _ > 10 )) { - * ... lots of stuff - * } - * } - * }}} - */ - def refs: immutable.IndexedSeq[Ref[A]] -} diff --git a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/TMap.scala b/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/TMap.scala deleted file mode 100644 index d14264f1..00000000 --- a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/TMap.scala +++ /dev/null @@ -1,121 +0,0 @@ -/* scala-stm - (c) 2009-2012, Stanford University, PPL */ - -package scala.concurrent.stm - -import scala.collection.{immutable, mutable, generic} -import mutable.Iterable - - -object TMap { - - object View extends generic.MutableMapFactory[TMap.View] { - - implicit def canBuildFrom[A, B]: generic.CanBuildFrom[Coll, (A, B), TMap.View[A, B]] = new MapCanBuildFrom[A, B] - - def empty[A, B] = TMap.empty[A, B].single - - override def newBuilder[A, B] = new mutable.Builder[(A, B), View[A, B]] { - private val underlying = TMap.newBuilder[A, B] - - def clear() { underlying.clear() } - def += (kv: (A, B)): this.type = { underlying += kv ; this } - def result() = underlying.result().single - } - - override def apply[A, B](kvs: (A, B)*): TMap.View[A, B] = (TMap.newBuilder[A, B] ++= kvs).result().single - } - - /** A `Map` that provides atomic execution of all of its methods. */ - trait View[A, B] extends mutable.Map[A, B] with mutable.MapLike[A, B, View[A, B]] with TxnDebuggable { - /** Returns the `TMap` perspective on this transactional map, which - * provides map functionality only inside atomic blocks. - */ - def tmap: TMap[A, B] - - def clone: TMap.View[A, B] - - /** Takes an atomic snapshot of this transactional map. */ - def snapshot: immutable.Map[A, B] - - override def empty: View[A, B] = TMap.empty[A, B].single - - override protected[this] def newBuilder: mutable.Builder[(A, B), View[A, B]] = View.newBuilder[A, B] - - override def stringPrefix = "TMap" - } - - - /** Constructs and returns a new empty `TMap`. */ - def empty[A, B]: TMap[A, B] = impl.STMImpl.instance.newTMap[A, B] - - /** Returns a builder of `TMap`. */ - def newBuilder[A, B]: mutable.Builder[(A, B), TMap[A, B]] = impl.STMImpl.instance.newTMapBuilder[A, B] - - /** Constructs and returns a new `TMap` that will contain the key/value pairs - * from `kvs`. - */ - def apply[A, B](kvs: (A, B)*): TMap[A, B] = (newBuilder[A, B] ++= kvs).result() - - - /** Allows a `TMap` in a transactional context to be used as a `Map`. */ - implicit def asMap[A, B](m: TMap[A, B])(implicit txn: InTxn): View[A, B] = m.single -} - - -/** A transactional map implementation that requires that all of its map-like - * operations be called from inside an atomic block. Rather than extending - * `Map`, an implicit conversion is provided from `TMap` to `Map` if the - * current scope is part of an atomic block (see `TMap.asMap`). - * - * The keys (with type `A`) must be immutable, or at least not modified while - * they are in the map. The `TMap` implementation assumes that it can safely - * perform key equality and hash checks outside a transaction without - * affecting atomicity. - * - * @author Nathan Bronson - */ -trait TMap[A, B] extends TxnDebuggable { - - /** Returns an instance that provides transactional map functionality without - * requiring that operations be performed inside the static scope of an - * atomic block. - */ - def single: TMap.View[A, B] - - def clone(implicit txn: InTxn): TMap[A, B] = single.clone.tmap - - // The following method work fine via the asMap mechanism, but is important - // enough that we don't want the implicit conversion to make it invisible to - // ScalaDoc or IDE auto-completion - - def snapshot: immutable.Map[A, B] = single.snapshot - - // The following methods work fine via the asMap mechanism, but are heavily - // used. We add transactional versions of them to allow overrides to get - // access to the InTxn instance without a ThreadLocal lookup. - - def isEmpty(implicit txn: InTxn): Boolean - def size(implicit txn: InTxn): Int - def foreach[U](f: ((A, B)) => U)(implicit txn: InTxn) - def contains(key: A)(implicit txn: InTxn): Boolean - def apply(key: A)(implicit txn: InTxn): B - def get(key: A)(implicit txn: InTxn): Option[B] - def update(key: A, value: B)(implicit txn: InTxn) { put(key, value) } - def put(key: A, value: B)(implicit txn: InTxn): Option[B] - def remove(key: A)(implicit txn: InTxn): Option[B] - - // The following methods return the wrong receiver when invoked via the asMap - // conversion. They are exactly the methods of mutable.Map whose return type - // is this.type. Note that there are other methods of mutable.Map that we - // allow to use the implicit mechanism, such as getOrElseUpdate(k). - - def += (kv: (A, B))(implicit txn: InTxn): this.type = { put(kv._1, kv._2) ; this } - def += (kv1: (A, B), kv2: (A, B), kvs: (A, B)*)(implicit txn: InTxn): this.type = { this += kv1 += kv2 ++= kvs } - def ++= (kvs: TraversableOnce[(A, B)])(implicit txn: InTxn): this.type = { for (kv <- kvs) this += kv ; this } - def -= (k: A)(implicit txn: InTxn): this.type = { remove(k) ; this } - def -= (k1: A, k2: A, ks: A*)(implicit txn: InTxn): this.type = { this -= k1 -= k2 --= ks } - def --= (ks: TraversableOnce[A])(implicit txn: InTxn): this.type = { for (k <- ks) this -= k ; this } - - def transform(f: (A, B) => B)(implicit txn: InTxn): this.type - def retain(p: (A, B) => Boolean)(implicit txn: InTxn): this.type -} diff --git a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/TSet.scala b/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/TSet.scala deleted file mode 100644 index eebcb582..00000000 --- a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/TSet.scala +++ /dev/null @@ -1,115 +0,0 @@ -/* scala-stm - (c) 2009-2012, Stanford University, PPL */ - -package scala.concurrent.stm - -import scala.collection.{immutable, mutable, generic} - - -object TSet { - - object View extends generic.MutableSetFactory[TSet.View] { - - implicit def canBuildFrom[A]: generic.CanBuildFrom[Coll, A, TSet.View[A]] = setCanBuildFrom[A] - - override def empty[A] = TSet.empty[A].single - - override def newBuilder[A] = new mutable.Builder[A, View[A]] { - private val underlying = TSet.newBuilder[A] - - def clear() { underlying.clear() } - def += (x: A): this.type = { underlying += x ; this } - def result() = underlying.result().single - } - - override def apply[A](xs: A*): TSet.View[A] = (TSet.newBuilder[A] ++= xs).result().single - } - - /** A `Set` that provides atomic execution of all of its methods. */ - trait View[A] extends mutable.Set[A] with mutable.SetLike[A, View[A]] with TxnDebuggable { - - /** Returns the `TSet` perspective on this transactional set, which - * provides set functionality only inside atomic blocks. - */ - def tset: TSet[A] - - def clone: TSet.View[A] - - /** Takes an atomic snapshot of this transactional set. */ - def snapshot: immutable.Set[A] - - override def empty: View[A] = TSet.empty[A].single - override def companion: generic.GenericCompanion[View] = View - override protected[this] def newBuilder: mutable.Builder[A, View[A]] = View.newBuilder[A] - - override def stringPrefix = "TSet" - } - - - /** Constructs and returns a new empty `TSet`. */ - def empty[A]: TSet[A] = impl.STMImpl.instance.newTSet[A] - - /** Returns a builder of `TSet`. */ - def newBuilder[A]: mutable.Builder[A, TSet[A]] = impl.STMImpl.instance.newTSetBuilder[A] - - /** Constructs and returns a new `TSet` that will contain the elements from - * `xs`. - */ - def apply[A](xs: A*): TSet[A] = (newBuilder[A] ++= xs).result() - - - /** Allows a `TSet` in a transactional context to be used as a `Set`. */ - implicit def asSet[A](s: TSet[A])(implicit txn: InTxn): View[A] = s.single -} - - -/** A transactional set implementation that requires that all of its set-like - * operations be called from inside an atomic block. Rather than extending - * `Set`, an implicit conversion is provided from `TSet` to `Set` if the - * current scope is part of an atomic block (see `TSet.asSet`). - * - * The elements (with type `A`) must be immutable, or at least not modified - * while they are in the set. The `TSet` implementation assumes that it can - * safely perform equality and hash checks outside a transaction without - * affecting atomicity. - * - * @author Nathan Bronson - */ -trait TSet[A] extends TxnDebuggable { - - /** Returns an instance that provides transactional set functionality without - * requiring that operations be performed inside the static scope of an - * atomic block. - */ - def single: TSet.View[A] - - def clone(implicit txn: InTxn): TSet[A] = single.clone.tset - - // Fast snapshots are one of TSet's core features, so we don't want the - // implicit conversion to hide it from ScalaDoc and IDE completion - def snapshot: immutable.Set[A] = single.snapshot - - // The following methods work fine via the asSet mechanism, but are heavily - // used. We add transactional versions of them to allow overrides. - - def isEmpty(implicit txn: InTxn): Boolean - def size(implicit txn: InTxn): Int - def foreach[U](f: A => U)(implicit txn: InTxn) - def contains(elem: A)(implicit txn: InTxn): Boolean - def apply(elem: A)(implicit txn: InTxn): Boolean = contains(elem) - def add(elem: A)(implicit txn: InTxn): Boolean - def update(elem: A, included: Boolean)(implicit txn: InTxn) { if (included) add(elem) else remove(elem) } - def remove(elem: A)(implicit txn: InTxn): Boolean - - // The following methods return the wrong receiver when invoked via the asSet - // conversion. They are exactly the methods of mutable.Set whose return type - // is this.type. - - def += (x: A)(implicit txn: InTxn): this.type = { add(x) ; this } - def += (x1: A, x2: A, xs: A*)(implicit txn: InTxn): this.type = { this += x1 += x2 ++= xs } - def ++= (xs: TraversableOnce[A])(implicit txn: InTxn): this.type = { for (x <- xs) this += x ; this } - def -= (x: A)(implicit txn: InTxn): this.type = { remove(x) ; this } - def -= (x1: A, x2: A, xs: A*)(implicit txn: InTxn): this.type = { this -= x1 -= x2 --= xs } - def --= (xs: TraversableOnce[A])(implicit txn: InTxn): this.type = { for (x <- xs) this -= x ; this } - - def retain(p: A => Boolean)(implicit txn: InTxn): this.type -} diff --git a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/Txn.scala b/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/Txn.scala deleted file mode 100644 index 5a9f0cfd..00000000 --- a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/Txn.scala +++ /dev/null @@ -1,325 +0,0 @@ -/* scala-stm - (c) 2009-2012, Stanford University, PPL */ - -package scala.concurrent.stm - -import java.util.concurrent.TimeUnit - -/** The `Txn` object provides methods that operate on the current transaction - * context. These methods are only valid within an atomic block or a - * transaction life-cycle handler, which is checked at compile time by - * requiring that an implicit `InTxn` or `InTxnEnd` be available. - * - * @author Nathan Bronson - */ -object Txn { - import impl.STMImpl - - //////////// dynamic InTxn binding - - /** Returns `Some(t)` if called from inside the static or dynamic scope of - * the transaction context `t`, `None` otherwise. If an implicit `InTxn` is - * available it may be used. - */ - def findCurrent(implicit mt: MaybeTxn): Option[InTxn] = STMImpl.instance.findCurrent - - - //////////// status - - /** The current state of an attempt to execute an atomic block. */ - sealed abstract class Status { - - /** True for `Committing`, `Committed` and `RolledBack`. */ - def decided: Boolean - - /** True for `Committed` and `RolledBack`. */ - def completed: Boolean - } - - /** The `Status` for a transaction nesting level that may perform `Ref` reads - * and writes, that is waiting for a child nesting level to complete, or - * that has been merged into an `Active` parent nesting level. - */ - case object Active extends Status { - def decided = false - def completed = false - } - - /** The `Status` for the nesting levels of a transaction that are attempting - * to commit, but for which the outcome is uncertain. - */ - case object Preparing extends Status { - def decided = false - def completed = false - } - - /** The `Status` for the nesting levels of a transaction that has - * successfully acquired all write permissions necessary to succeed, and - * that has delegated the final commit decision to an external decider. - */ - case object Prepared extends Status { - def decided = false - def completed = false - } - - /** The `Status` for the nesting levels of a transaction that has decided to - * commit, but whose `Ref` writes are not yet visible to other threads. - */ - case object Committing extends Status { - def decided = true - def completed = false - } - - /** The `Status` for the nesting levels of a transaction that has been - * committed. After-commit callbacks may still be running. - */ - case object Committed extends Status { - def decided = true - def completed = true - } - - /** The `Status` for an atomic block execution attempt that is being or that - * has been cancelled. None of the `Ref` writes made during this nesting - * level or in any child nesting level will ever be visible to other - * threads. The atomic block will be automatically retried if `cause` is a - * `TransientRollbackCause`, unless STM-specific retry thresholds are - * exceeded. - */ - case class RolledBack(cause: RollbackCause) extends Status { - def decided = true - def completed = true - } - - - /** A record of the reason that a atomic block execution attempt was rolled - * back. - */ - sealed abstract class RollbackCause - - /** `RollbackCause`s for which the failure is transient and another attempt - * should be made to execute the underlying atomic block. - */ - sealed abstract class TransientRollbackCause extends RollbackCause - - /** `RollbackCause`s for which the failure is permanent and no attempt should - * be made to retry the underlying atomic block. - */ - sealed abstract class PermanentRollbackCause extends RollbackCause - - /** The `RollbackCause` for a `NestingLevel` whose optimistic execution was - * invalid, and that should be retried. The specific situations in which an - * optimistic failure can occur are specific to the STM algorithm, but may - * include: - * - the STM detected that the value returned by a previous read in this - * nesting level is no longer valid; - * - a cyclic dependency has occurred and this nesting level must be rolled - * back to avoid deadlock; - * - a transaction with a higher priority wanted to write to a `Ref` written - * by this transaction; - * - the STM decided to switch execution strategies for this atomic block; - * or - * - no apparent reason (*). - * - * (*) - Some STMs perform validation, conflict detection and deadlock cycle - * breaking using algorithms that are conservative approximations. This - * means that any particular attempt to execute an atomic block might fail - * spuriously. - * - * @param category an STM-specific label for the reason behind this - * optimistic failure. The set of possible categories is - * bounded. - * @param trigger the specific object that led to the optimistic failure, - * if it is available, otherwise `None`. - */ - case class OptimisticFailureCause(category: Symbol, trigger: Option[Any]) extends TransientRollbackCause - - /** The `RollbackCause` for an atomic block execution attempt that ended with - * a call to `retry` or `retryFor`. The atomic block will be retried after - * some memory location read in the previous attempt has changed. - */ - case class ExplicitRetryCause(timeoutNanos: Option[Long]) extends TransientRollbackCause - - /** The `RollbackCause` for an atomic block that should not be restarted - * because it threw an exception. The exception might have been thrown from - * the body of the atomic block or from a handler invoked before the commit - * decision. Exceptions used for control flow are not included (see - * `TxnExecutor.isControlFlow`). - * - * Scala's STM discards `Ref` writes performed by atomic blocks that throw - * an exception. This is referred to as "failure atomicity". In a system - * that uses exceptions for error cleanup this design tends to preserve the - * invariants of shared data structures, which is a good thing. If a system - * uses exceptions for control flow, however, this design may lead to - * unexpected behavior. The `TxnExecutor` object's `isControlFlow` method - * is used to distinguish exceptions representing control flow transfers - * from those used to represent error conditions. See - * `TxnExecutor.transformDefault` to change the default rules. - */ - case class UncaughtExceptionCause(x: Throwable) extends PermanentRollbackCause - - /** The `RollbackCause` of a successfully completed `atomic.unrecorded` - * block. See `TxnExecutor.unrecorded`. - */ - case class UnrecordedTxnCause[Z](z: Z) extends PermanentRollbackCause - - /** Returns the status of the current nesting level of the current - * transaction, equivalent to `NestingLevel.current.status`. - */ - def status(implicit txn: InTxnEnd): Status = txn.status - - - //////////// explicit retry and rollback - - // These are methods of the Txn object because it is generally only correct - // to call them inside the static context of an atomic block. If they were - // methods on the InTxn instance, then users might expect to be able to call - // them from any thread. Methods to add life-cycle callbacks are also object - // methods for the same reason. - - /** Rolls back the current nesting level for modular blocking. It will be - * retried, but only after some memory location observed by this transaction - * has been changed. If any alternatives to this atomic block were provided - * via `orAtomic` or `atomic.oneOf`, then the alternative will be tried - * before blocking. - * @throws IllegalStateException if the transaction is not active. - */ - def retry(implicit txn: InTxn): Nothing = txn.retry() - - /** Causes the transaction to roll back and retry using modular blocking with - * a timeout, or returns immediately if the timeout has already expired. - * The STM keeps track of the total amount of blocking that has occurred - * during modular blocking; this time is apportioned among the calls to - * `View.tryAwait` and `retryFor` that are part of the current attempt. - * `retryFor(0)` is a no-op. - * - * Returns only if the timeout has expired. - * @param timeout the maximum amount of time that this `retryFor` should - * block, in units of `unit`. - * @param unit the units in which to measure `timeout`, by default - * milliseconds. - */ - def retryFor(timeout: Long, unit: TimeUnit = TimeUnit.MILLISECONDS)(implicit txn: InTxn) { - txn.retryFor(unit.toNanos(timeout)) - } - - /** Causes the current nesting level to be rolled back due to the specified - * `cause`. This method may only be called by the thread executing the - * transaction; obtain a `NestingLevel` instance `n` and call - * `n.requestRollback(cause)` if you wish to doom a transaction from another - * thread. - * @throws IllegalStateException if the current transaction has already - * decided to commit. - */ - def rollback(cause: RollbackCause)(implicit txn: InTxnEnd): Nothing = txn.rollback(cause) - - - //////////// life-cycle callbacks - - /** Arranges for `handler` to be executed as late as possible while the root - * nesting level of the current transaction is still `Active`, unless the - * current nesting level is rolled back. Reads, writes and additional - * nested transactions may be performed inside the handler. Details: - * - it is possible that after `handler` is run the transaction might still - * be rolled back; - * - it is okay to call `beforeCommit` from inside `handler`, the - * reentrantly added handler will be included in this before-commit phase; - * and - * - before-commit handlers will be executed in their registration order. - */ - def beforeCommit(handler: InTxn => Unit)(implicit txn: InTxn) { txn.beforeCommit(handler) } - - /** (rare) Arranges for `handler` to be called after the `Ref` reads and - * writes have been checked for serializability, but before the decision has - * been made to commit or roll back. While-preparing handlers can lead to - * scalability problems, because while this transaction is in the - * `Preparing` state it might obstruct other transactions. Details: - * - the handler must not access any `Ref`s, even using `Ref.single`; - * - handlers will be executed in their registration order; and - * - handlers may be registered while the transaction is active, or from a - * while-preparing callback during the `Preparing` phase. - */ - def whilePreparing(handler: InTxnEnd => Unit)(implicit txn: InTxnEnd) { txn.whilePreparing(handler) } - - /** (rare) Arranges for `handler` to be called after (if) it has been decided - * that the current transaction will commit, but before the writes made by - * the transaction have become available to other threads. While-committing - * handlers can lead to scalability problems, because while this transaction - * is in the `Committing` state it might obstruct other transactions. - * Details: - * - the handler must not access any `Ref`s, even using `Ref.single`; - * - handlers will be executed in their registration order; and - * - handlers may be registered so long as the current transaction status is - * not `RolledBack` or `Committed`. - */ - def whileCommitting(handler: InTxnEnd => Unit)(implicit txn: InTxnEnd) { txn.whileCommitting(handler) } - - /** Arranges for `handler` to be executed as soon as possible after the - * current transaction is committed, if this nesting level is part of the - * overall transaction commit. Details: - * - no transaction will be active while the handler is run, but it may - * access `Ref`s using a new top-level atomic block or `.single`; - * - the handler runs after all internal locks have been released, so any - * values read or written in the transaction might already have been - * changed by another thread before the handler is executed; - * - handlers will be executed in their registration order; and - * - handlers may be registered so long as the current transaction status is - * not `RolledBack` or `Committed`. - */ - def afterCommit(handler: Status => Unit)(implicit txn: InTxnEnd) { txn.afterCommit(handler) } - - /** Arranges for `handler` to be executed as soon as possible after the - * current nesting level is rolled back, or runs the handler immediately if - * the current nesting level's status is already `RolledBack`. Details: - * - the handler will be executed during any partial rollback that includes - * the current nesting level; - * - the handler will be run before any additional attempts to execute the - * atomic block; - * - handlers will be run in the reverse of their registration order; and - * - handlers may be registered so long as the current transaction status is - * not `Committed`. - */ - def afterRollback(handler: Status => Unit)(implicit txn: InTxnEnd) { txn.afterRollback(handler) } - - /** Arranges for `handler` to be called as both an after-commit and - * after-rollback handler. - * - * Equivalent to: {{{ - * afterRollback(handler) - * afterCommit(handler) - * }}} - */ - def afterCompletion(handler: Status => Unit)(implicit txn: InTxnEnd) { txn.afterCompletion(handler) } - - - /** An `ExternalDecider` is given the final control over the decision of - * whether or not to commit a transaction, which allows two-phase commit to - * be integrated with a single non-transactional resource. `shouldCommit` - * will only be called if a `InTxn` has successfully called all of its - * before-commit handlers, acquired all necessary write locks, validated all - * of its reads and called all of its while-preparing handlers. The decider - * may then attempt a non-transactional operation whose outcome is - * uncertain, and based on the outcome may directly cause the transaction to - * commit or roll back. - */ - trait ExternalDecider { - /** Should return true if the end-of-life transaction `txn` should commit, - * false if it should roll back. `Txn.rollback` may also be used to - * initiate a rollback if that is more convenient. Called while the - * status is `Prepared`. This method may not access any `Ref`s, even via - * `Ref.single`. - */ - def shouldCommit(implicit txn: InTxnEnd): Boolean - } - - /** (rare) Delegates final decision of the outcome of the transaction to - * `decider` if the current nesting level participates in the top-level - * commit. This method can succeed with at most one value per top-level - * transaction. - * @throws IllegalStateException if the current transaction's status is not - * `Active` or `Preparing` - * @throws IllegalArgumentException if `setExternalDecider(d)` was - * previously called in this transaction, `d != decider`, and the - * nesting level from which `setExternalDecider(d)` was called has not - * rolled back. - */ - def setExternalDecider(decider: ExternalDecider)(implicit txn: InTxnEnd) { txn.setExternalDecider(decider) } -} diff --git a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/TxnDebuggable.scala b/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/TxnDebuggable.scala deleted file mode 100644 index bee92f7a..00000000 --- a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/TxnDebuggable.scala +++ /dev/null @@ -1,62 +0,0 @@ -/* scala-stm - (c) 2009-2012, Stanford University, PPL */ - -package scala.concurrent.stm - -/** This trait implements methods that can be used to examine the content of - * transactional data structures in a debugger with minimal modification to - * the behavior of the program. Normal transactional reads would add to an - * atomic block's read set, which could reduce the number of valid program - * execution orders. `dbgStr` and `dbgValue` perform transactional reads, - * but then erase them from the enclosing transaction (if any). - * - * You can use these methods from an IDE debugger manually, by watching - * `x.dbgStr` or `x.dbgValue` rather than `x`. - * - * If you use Eclipse, you can make this method the default view by going to - * ''Window->Preferences->Java[+]->Debug[+]->Detail Formatters'' and - * entering the code snippet `dbgStr()` (or `dbgValue()`) for instances of - * `scala.concurrent.stm.TxnDebuggable`. - * - * If you use IntelliJ IDEA, go to - * ''File->Settings...->Debugger->Data Type Renderers'' and create a new - * renderer for `scala.concurrent.stm.TxnDebuggable` that uses - * `dbgStr()` for rendering and `dbgValue()` for node expansion. - * - * @author Nathan Bronson - */ -trait TxnDebuggable { - - /** Returns a string representation of the transactional value in this - * instance for debugging convenience. The `Ref` reads (and writes) - * performed while constructing the result will be discarded before - * returning. This method works fine outside a transaction. - * - * If this method is called from within a transaction that is already - * doomed (status `Txn.Rolledback`), a string describing the reason - * for the outer transaction's rollback will be returned. - */ - def dbgStr: String - - /** Returns some value that is suitable for examination in a debugger, - * or returns a `Txn.RollbackCause` if called from inside a doomed atomic - * block. - */ - def dbgValue: Any - - /** Helper function for generating `dbgStr` of a transactional type that - * can produce an iterable view. - */ - private[stm] def mkStringPrefix(typeName: String, values: Iterable[_], unabbrevLen: Int = 1000): String = { - val buf = new StringBuilder(typeName + "[size=" + values.size + "](") - val iter = values.iterator - while (iter.hasNext && buf.length < unabbrevLen - 1) { - buf.append(iter.next()) - if (iter.hasNext) - buf.append(", ") - } - if (iter.hasNext) - buf.append("...") - buf.append(")") - buf.toString() - } -} \ No newline at end of file diff --git a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/TxnExecutor.scala b/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/TxnExecutor.scala deleted file mode 100644 index 4750c1d8..00000000 --- a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/TxnExecutor.scala +++ /dev/null @@ -1,226 +0,0 @@ -/* scala-stm - (c) 2009-2012, Stanford University, PPL */ - -package scala.concurrent.stm - -import java.util.concurrent.TimeUnit -import concurrent.stm.Txn.RollbackCause - - -/** `object TxnExecutor` manages the system-wide default `TxnExecutor`. */ -object TxnExecutor { - @volatile private var _default: TxnExecutor = impl.STMImpl.instance - - /** Returns the default `TxnExecutor`. */ - def defaultAtomic: TxnExecutor = _default - - /** Atomically replaces the default `TxnExecutor` with `f(defaultAtomic)`. */ - def transformDefault(f: TxnExecutor => TxnExecutor) { - synchronized { _default = f(_default) } - } - - val DefaultPostDecisionExceptionHandler = { (status: Txn.Status, x: Throwable) => - throw x - } -} - -/** A `TxnExecutor` is responsible for executing atomic blocks transactionally - * using a set of configuration parameters. Configuration changes are made by - * constructing a new `TxnExecutor` using `withConfig` or `withHint`. The - * new executor may be used immediately, saved and used multiple times, or - * registered as the new system-wide default using - * `TxnExecutor.transformDefault`. - * - * @author Nathan Bronson - */ -trait TxnExecutor { - - //////// functionality - - /** Executes `block` one or more times until an atomic execution is achieved, - * buffering and/or locking writes so they are not visible until success. - * - * @param block code to execute atomically - * @tparam Z the return type of the atomic block - * @return the value returned from `block` after a successful optimistic - * concurrency attempt - */ - def apply[Z](block: InTxn => Z)(implicit mt: MaybeTxn): Z - - /** Atomically executes a transaction that is composed from `blocks` by - * joining with a left-biased `orAtomic` operator. The following two - * examples are equivalent. Using `orAtomic`: - * {{{ - * atomic { implicit t => - * // body A - * } orAtomic { implicit t => - * // body B - * } ... - * }}} - * Using `oneOf`: - * {{{ - * atomic.oneOf( { implicit t: InTxn => - * // body A - * }, { implicit t: InTxn => - * // body B - * } ) - * }}} - * - * The first block will be attempted in an optimistic transaction until it - * either succeeds, fails with no retry possible (in which case the causing - * exception will be rethrown), or performs a call to `retry`. If a retry - * is requested, then the next block will be attempted in the same fashion. - * If all blocks are explicitly retried then execution resumes at the first - * block, but only after another context has changed some value read by one - * of the attempts. - * - * The left-biasing of the `orAtomic` composition guarantees that if the - * first block does not call `retry`, no other blocks will be executed. - */ - def oneOf[Z](blocks: (InTxn => Z)*)(implicit mt: MaybeTxn): Z - - /** Performs a computation in a transaction and returns the result, but - * always rolls back the transaction. No writes performed by `block` will - * be committed or exposed to other threads. This may be useful for - * heuristic decisions or for debugging, as for the various `dbgStr` - * implementations. - * - * '''The caller is responsible for correctness:''' It is a code smell - * if ''Z'' is a type that is constructed from Ref`, `TMap`, `TSet`, ..... - * - * If this method is executed inside an outer transaction that has status - * `Txn.RolledBack` then `block` can't complete. The default behavior - * (if `outerFailure` is null) in that case is to immediately roll back - * the outer transaction. If a non-null `outerFailure` handler has been - * provided, however, it allow this method to return. This is useful when - * the unrecorded transaction is being used for debugging or logging. - * - * `atomic.unrecorded { implicit txn => code }` is roughly equivalent to - * the following, except that the rollback cause used will be - * `Txn.UnrecordedTxnCause`: {{{ - * case class Tunnel(z: Z) extends Exception {} - * try { - * atomic.withControlFlowRecognizer({ - * case Tunnel(_) => false - * }) { implicit txn => - * throw Tunnel(code) - * } - * } catch { - * case Tunnel(z) => z - * } - * }}} - */ - def unrecorded[Z](block: InTxn => Z, outerFailure: (RollbackCause => Z) = null)(implicit mt: MaybeTxn): Z - - /** (rare) Associates an alternative atomic block with the current thread. - * The next call to `apply` will consider `block` to be an alternative. - * Multiple alternatives may be associated before calling `apply`. Returns - * true if this is the first pushed alternative, false otherwise. This - * method is not usually called directly. Alternative atomic blocks are - * only attempted if the previous alternatives call `retry`. - * - * Note that it is not required that `pushAlternative` be called on the same - * instance of `TxnExecutor` as `apply`, just that they have been derived - * from the same original executor. - */ - def pushAlternative[Z](mt: MaybeTxn, block: InTxn => Z): Boolean - - /** Atomically compares and sets two `Ref`s, probably more efficiently then - * the corresponding transaction. Equivalent to {{{ - * atomic { implicit t => - * a() == a0 && b() == b0 && { a() = a1 ; b() = b1 ; true } - * } - * }}} - */ - def compareAndSet[A, B](a: Ref[A], a0: A, a1: A, b: Ref[B], b0: B, b1: B): Boolean - - /** Atomically compares and sets two `Ref`s using identity comparison, - * probably more efficiently then the corresponding transaction. Equivalent - * to {{{ - * atomic { implicit t => - * val f = (a() eq a0) && (b() eq b0) - * if (f && (a0 ne a1)) - * a() = a1 - * if (f && (b0 ne b1)) - * b() = b1 - * f - * } - * }}} - */ - def compareAndSetIdentity[A <: AnyRef, B <: AnyRef](a: Ref[A], a0: A, a1: A, b: Ref[B], b0: B, b1: B): Boolean - - //////// configuration - - /** Returns `Some(t)` if `t` is the retry timeout in nanoseconds used by - * this `TxnExecutor`, or `None` otherwise. If the retry timeout is - * `Some(t)` and an atomic block executed by the returned executor blocks - * with `retry` or `retryFor` for more than `t` nanoseconds the retry will - * be cancelled with an `InterruptedException`. - * - * The retry timeout has essentially the same effect as replacing calls to - * `retry` with - * `{ retryFor(timeout, NANOS) ; throw new InterruptedException }`. - * Alternately, `retryFor(timeout)` has roughly the same effect as {{{ - * try { - * atomic.withRetryTimeout(timeout) { implicit txn => retry } - * } catch { - * case _: InterruptedException => - * } - * }}} - */ - def retryTimeoutNanos: Option[Long] - - /** Returns a `TxnExecutor` that is identical to this one, except that it has - * a `retryTimeout` of `timeoutNanos`. - */ - def withRetryTimeoutNanos(timeoutNanos: Option[Long]): TxnExecutor - - /** Returns a `TxnExecutor` that is identical to this one except that it has - * the specified retry timeout. The default time unit is milliseconds. If - * the retry timeout expires the retry will be cancelled with an - * `InterruptedException`. - */ - def withRetryTimeout(timeout: Long, unit: TimeUnit = TimeUnit.MILLISECONDS): TxnExecutor = - withRetryTimeoutNanos(Some(unit.toNanos(timeout))) - - /** Returns true if `x` should be treated as a transfer of control, rather - * than an error. Atomic blocks that end with an uncaught control flow - * exception are committed, while atomic blocks that end with an uncaught - * error exception are rolled back. - * - * All implementations of this method must return true for instances that - * implement `scala.util.control.ControlThrowable`. - */ - def isControlFlow(x: Throwable): Boolean - - /** Returns a `TxnExecutor e` that is identical to this one, except that - * `e.isControlFlow(x)` will return `pf(x)` if `pf.isDefined(x)`. For - * exceptions for which `pf` is not defined the decision will be deferred to - * the previous implementation. - * - * This function may be combined with `TxnExecutor.transformDefault` to add - * system-wide recognition of a control-transfer exception that does not - * extend `scala.util.control.ControlThrowable`. For example, to modify the - * default behavior of all `TxnExecutor.isControlFlow` calls to accept - * `DSLNonLocalControlTransferException`: {{{ - * TxnExecutor.transformDefault { e => - * e.withControlFlowRecognizer { - * case _: DSLNonLocalControlTransferException => true - * } - * } - * }}} - */ - def withControlFlowRecognizer(pf: PartialFunction[Throwable, Boolean]): TxnExecutor - - /** Returns a function that records, reports or discards exceptions that were - * thrown from a while-committing, after-commit or after-rollback life-cycle - * callback. - */ - def postDecisionFailureHandler: (Txn.Status, Throwable) => Unit - - /** Returns a `TxnExecutor e` that is identical to this one, except that - * `e.postDecisionFailureHandler` will return `handler`. This function may - * be called from inside a function passed to `TxnExecutor.transformDefault` - * to change the system-wide post-decision failure handler. - */ - def withPostDecisionFailureHandler(handler: (Txn.Status, Throwable) => Unit): TxnExecutor -} diff --git a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/TxnLocal.scala b/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/TxnLocal.scala deleted file mode 100644 index 31d2b392..00000000 --- a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/TxnLocal.scala +++ /dev/null @@ -1,79 +0,0 @@ -/* scala-stm - (c) 2009-2012, Stanford University, PPL */ - -package scala.concurrent.stm - - -object TxnLocal { - /** Returns a new transaction-local that holds values of type `A`. One - * `TxnLocal` instance holds a separate value for each transaction in which - * it has been accessed. The value associated with a particular atomic - * block is created on demand, and discarded at the same time that the - * atomic block's after-completion handlers are invoked. `TxnLocal` has a - * similar relationship to transactions as `ThreadLocal` has to threads. - * - * There are two ways to specify the initial value that will be used if the - * first access inside a transaction is not a `set`. If no `InTxn` context - * is needed to compute the initial value then the by-name parameter `init` - * is the most convenient. Because this is the first parameter, you can - * omit the parameter name. To construct a `TxnLocal` with a default value - * of `aValue`, simply {{{ - * val tl = TxnLocal(aValue) - * }}} - * If computing the initial value requires access to `Ref`s, then it is - * better to use the `initialValue` parameter, which lets you write {{{ - * val tl = TxnLocal(initialValue = { implicit txn => - * // Ref reads or writes, or handler registration - * }) - * }}} - * - * Unlike `Ref`s, `TxnLocal`s can be read or written from inside - * while-preparing or while-committing callbacks, with two conditions: if - * the first access is from one of these callbacks then no `beforeCommit` - * parameter can be present; and if the first access is from one of these - * callbacks and it is not a write then you must use the `init` - * initialization method. - * - * This factory method also accepts parameters that correspond to `Txn`'s - * transaction life-cycle handlers. These handlers will be registered in any - * transaction that reads or writes the returned `TxnLocal`. They are - * roughly - * - `beforeCommit` - the last time that `Ref`s can be read or written; - * - `whilePreparing` - the last time that the transaction can be rolled - * back; - * - `whileCommitting` - actions that should be atomic with respect to the - * transaction (keep them fast to avoid scalability issues); - * - `afterCommit` - called at some time after commit; - * - `afterRollback` - called at some time after rollback of the nesting - * level in which the `TxnLocal` was first accessed; and - * - `afterCompletion` - called either after commit or after rollback. - * - * The value stored in a `TxnLocal` is subject to partial rollback: initial - * value computations and writes from a nested atomic block will be - * discarded if the block is rolled back. - */ - def apply[A](init: => A = null.asInstanceOf[A], - initialValue: InTxn => A = null, - beforeCommit: InTxn => Unit = null, - whilePreparing: InTxnEnd => Unit = null, - whileCommitting: InTxnEnd => Unit = null, - afterCommit: A => Unit = null, - afterRollback: Txn.Status => Unit = null, - afterCompletion: Txn.Status => Unit = null): TxnLocal[A] = { - impl.STMImpl.instance.newTxnLocal( - init, initialValue, beforeCommit, whilePreparing, whileCommitting, afterCommit, afterRollback, afterCompletion) - } -} - -/** `TxnLocal[A]` holds an instance of `A` that is local to an atomic block. - * See the factory method in the companion object for information about the - * life-cycle. - * - * @author Nathan Bronson - */ -trait TxnLocal[A] extends RefLike[A, InTxnEnd] { - - /** Returns true if a value is already associated with this `TxnLocal` in the - * current transactional context, false otherwise. - */ - def isInitialized(implicit txn: InTxnEnd): Boolean -} diff --git a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/TxnUnknown.scala b/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/TxnUnknown.scala deleted file mode 100644 index 8d0cc559..00000000 --- a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/TxnUnknown.scala +++ /dev/null @@ -1,11 +0,0 @@ -/* scala-stm - (c) 2009-2010, Stanford University, PPL */ - -package scala.concurrent.stm - -/** An object that represents the absence of a statically-bound current - * transaction. - * @see scala.concurrent.stm.MaybeTxn - * - * @author Nathan Bronson - */ -object TxnUnknown extends MaybeTxn diff --git a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/ccstm/AccessHistory.scala b/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/ccstm/AccessHistory.scala deleted file mode 100644 index bfc3340c..00000000 --- a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/ccstm/AccessHistory.scala +++ /dev/null @@ -1,745 +0,0 @@ -/* scala-stm - (c) 2009-2012, Stanford University, PPL */ - -package scala.concurrent.stm -package ccstm - -import annotation.tailrec - -private[ccstm] object AccessHistory { - - /** The operations provided by the read set functionality of an - * `AccessHistory`. - */ - trait ReadSet { - protected def readCount: Int - protected def readHandle(i: Int): Handle[_] - protected def readVersion(i: Int): CCSTM.Version - protected def recordRead(handle: Handle[_], version: CCSTM.Version) - protected def readLocate(index: Int): AccessHistory.UndoLog - } - - /** The operations provided by the pessimistic read set functionality of an - * `AccessHistory`. - */ - trait BargeSet { - protected def bargeCount: Int - protected def bargeHandle(i: Int): Handle[_] - protected def recordBarge(handle: Handle[_]) - } - - /** The operations provided by the write buffer functionality of an - * `AccessHistory`. - */ - trait WriteBuffer { - protected def writeCount: Int - protected def getWriteHandle(i: Int): Handle[_] - protected def getWriteSpecValue[T](i: Int): T - protected def wasWriteFreshOwner(i: Int): Boolean - protected def findWrite(handle: Handle[_]): Int - protected def stableGet[T](handle: Handle[T]): T - protected def put[T](handle: Handle[T], freshOwner: Boolean, value: T) - protected def writeAppend[T](handle: Handle[T], freshOwner: Boolean, v: T) - protected def writeUpdate[T](i: Int, v: T) - protected def swap[T](handle: Handle[T], freshOwner: Boolean, value: T): T - protected def compareAndSetIdentity[T, R <: T with AnyRef]( - handle: Handle[T], freshOwner: Boolean, before: R, after: T): Boolean - protected def getAndTransform[T](handle: Handle[T], freshOwner: Boolean, func: T => T): T - protected def transformAndGet[T](handle: Handle[T], freshOwner: Boolean, func: T => T): T - protected def transformAndExtract[T,V](handle: Handle[T], freshOwner: Boolean, func: T => (T,V)): V - protected def getAndAdd(handle: Handle[Int], freshOwner: Boolean, delta: Int): Int - } - - /** Holds the write buffer undo log for a particular nesting level. This is - * exposed as an abstract class so that the different parts of the STM that - * have per-nesting level objects can share a single instance. - */ - abstract class UndoLog { - def parUndo: UndoLog - - var minRetryTimeoutNanos = Long.MaxValue - var consumedRetryDelta = 0L - var prevReadCount = 0 - var prevBargeCount = 0 - var prevWriteThreshold = 0 - - def addRetryTimeoutNanos(timeoutNanos: Long) { - minRetryTimeoutNanos = math.min(minRetryTimeoutNanos, timeoutNanos) - } - - /** Returns the sum of the timeouts of the retries that have timed out. - * Included levels are this one, parents of this one, levels that have - * been merged into an included level, and levels that were ended with a - * permanent rollback and whose parent was included. - */ - @tailrec final def consumedRetryTotal(accum: Long = 0L): Long = { - val z = accum + consumedRetryDelta - if (parUndo == null) z else parUndo.consumedRetryTotal(z) - } - - @tailrec final def readLocate(index: Int): UndoLog = { - if (index >= prevReadCount) this else parUndo.readLocate(index) - } - - private var _logSize = 0 - private var _indices: Array[Int] = null - private var _prevValues: Array[AnyRef] = null - - def logWrite(i: Int, v: AnyRef) { - if (_indices == null || _logSize == _indices.length) - grow() - _indices(_logSize) = i - _prevValues(_logSize) = v - _logSize += 1 - } - - private def grow() { - if (_logSize == 0) { - _indices = new Array[Int](16) - _prevValues = new Array[AnyRef](16) - } else { - _indices = copyTo(_indices, new Array[Int](_indices.length * 2)) - _prevValues = copyTo(_prevValues, new Array[AnyRef](_prevValues.length * 2)) - } - } - - private def copyTo[A](src: Array[A], dst: Array[A]): Array[A] = { - System.arraycopy(src, 0, dst, 0, src.length) - dst - } - - def undoWrites(hist: AccessHistory) { - // it is important to apply in reverse order - var i = _logSize - 1 - while (i >= 0) { - hist.setSpecValue(_indices(i), _prevValues(i)) - i -= 1 - } - } - } -} - -/** `AccessHistory` includes the read set and the write buffer for all - * transaction levels that have not been rolled back. The read set is a - * linear log that contains duplicates, rollback consists of truncating the - * read log. The write buffer is a hash table in which the entries are - * addressed by index, rather than by Java reference. Indices are allocated - * sequentially, so a high-water mark (_wUndoThreshold) can differentiate - * between entries that can be discarded on a partial rollback and those that - * need to be reverted to a previous value. An undo log is maintained for - * writes to entries from enclosing nesting levels, but it is expected that - * common usage will be handled mostly using the high-water mark. - * - * It is intended that this class can be extended by the actual `InTxn` - * implementation to reduce levels of indirection during barriers. This is a - * bit clumsy, and results in verbose method names to differentiate between - * overlapping operations. Please look away as the sausage is made. To help - * tame the mess the read set and write buffer interfaces are separated into - * traits housed in the companion object. This doesn't actually increase - * modularity, but serves as compile-time-checked documentation. - * - * @author Nathan Bronson - */ -private[ccstm] abstract class AccessHistory extends AccessHistory.ReadSet with AccessHistory.BargeSet with AccessHistory.WriteBuffer { - - protected def undoLog: AccessHistory.UndoLog - - protected def checkpointAccessHistory(reusedReadThreshold: Int) { - checkpointReadSet(reusedReadThreshold) - checkpointBargeSet() - checkpointWriteBuffer() - } - - protected def mergeAccessHistory() { - // nested commit - if (Stats.nested != null) - recordMerge() - - mergeRetryTimeout() - mergeWriteBuffer() - } - - private def recordMerge() { - Stats.nested.commits += 1 - } - - /** Releases locks for discarded handles */ - protected def rollbackAccessHistory(slot: CCSTM.Slot, cause: Txn.RollbackCause) { - // nested or top-level rollback - if (Stats.top != null) - recordRollback(cause) - - if (!cause.isInstanceOf[Txn.ExplicitRetryCause]) { - rollbackReadSet() - rollbackBargeSet(slot) - } - rollbackRetryTimeout(cause) - rollbackWriteBuffer(slot) - } - - private def recordRollback(cause: Txn.RollbackCause) { - val stat = if (undoLog.parUndo == null) Stats.top else Stats.nested - stat.rollbackReadSet += (readCount - undoLog.prevReadCount) - stat.rollbackBargeSet += (bargeCount - undoLog.prevBargeCount) - stat.rollbackWriteSet += (writeCount - undoLog.prevWriteThreshold) - cause match { - case Txn.ExplicitRetryCause(_) => stat.explicitRetries += 1 - case Txn.OptimisticFailureCause(tag, _) => stat.optimisticRetries += tag - case Txn.UncaughtExceptionCause(x) => stat.failures += x.getClass - case Txn.UnrecordedTxnCause(_) => stat.unrecordedTxns += 1 - } - } - - /** Does not release locks */ - protected def resetAccessHistory() { - if (Stats.top != null) - recordTopLevelCommit() - - resetReadSet() - resetBargeSet() - resetWriteBuffer() - } - - private def recordTopLevelCommit() { - // top-level commit - val top = Stats.top - top.commitReadSet += readCount - top.commitBargeSet += bargeCount - top.commitWriteSet += writeCount - top.commits += 1 - } - - /** Clears the read set and barge set, returning a `RetrySet` that holds the - * values that were removed. Releases any ownership held by the barge set. - */ - protected def takeRetrySet(slot: CCSTM.Slot): RetrySet = { - // barge entries were copied to the read set by addLatestWritesAsReads - var i = 0 - while (i < _bCount) { - rollbackHandle(_bHandles(i), slot) - i += 1 - } - resetBargeSet() - - val accum = new RetrySetBuilder - i = 0 - while (i < _rCount) { - accum += (_rHandles(i), _rVersions(i)) - i += 1 - } - resetReadSet() - accum.result() - } - - - //////////// retry timeout - - private def mergeRetryTimeout() { - // nested commit - val u = undoLog - val p = u.parUndo - p.addRetryTimeoutNanos(u.minRetryTimeoutNanos) - p.consumedRetryDelta += u.consumedRetryDelta - } - - private def rollbackRetryTimeout(cause: Txn.RollbackCause) { - cause match { - case Txn.ExplicitRetryCause(timeoutNanos) => { - if (!timeoutNanos.isEmpty) - undoLog.addRetryTimeoutNanos(timeoutNanos.get) - if (undoLog.parUndo != null) - undoLog.parUndo.addRetryTimeoutNanos(undoLog.minRetryTimeoutNanos) - } - case _: Txn.PermanentRollbackCause => { - if (undoLog.parUndo != null) - undoLog.parUndo.consumedRetryDelta += undoLog.consumedRetryDelta - } - case _ => - } - } - - //////////// read set - - private final val InitialReadCapacity = 1024 - private final val MaxRetainedReadCapacity = 8 * InitialReadCapacity - - private var _rCount = 0 - private var _rHandles: Array[Handle[_]] = null - private var _rVersions: Array[CCSTM.Version] = null - allocateReadSet() - - protected def readCount = _rCount - protected def readHandle(i: Int): Handle[_] = _rHandles(i) - protected def readVersion(i: Int): CCSTM.Version = _rVersions(i) - - protected def recordRead(handle: Handle[_], version: CCSTM.Version) { - val i = _rCount - if (i == _rHandles.length) - growReadSet() - _rHandles(i) = handle - _rVersions(i) = version - _rCount = i + 1 - } - - private def growReadSet() { - _rHandles = copyTo(_rHandles, new Array[Handle[_]](_rHandles.length * 2)) - _rVersions = copyTo(_rVersions, new Array[CCSTM.Version](_rVersions.length * 2)) - } - - private def copyTo[A](src: Array[A], dst: Array[A]): Array[A] = { - System.arraycopy(src, 0, dst, 0, src.length) - dst - } - - private def checkpointReadSet(reusedReadThreshold: Int) { - undoLog.prevReadCount = if (reusedReadThreshold >= 0) reusedReadThreshold else _rCount - } - - private def rollbackReadSet() { - val n = undoLog.prevReadCount - var i = n - while (i < _rCount) { - _rHandles(i) = null - i += 1 - } - _rCount = n - } - - private def resetReadSet() { - if (_rHandles.length > MaxRetainedReadCapacity) { - // avoid staying very large - allocateReadSet() - } else { - // allow GC of old handles - var i = 0 - while (i < _rCount) { - _rHandles(i) = null - i += 1 - } - } - _rCount = 0 - } - - private def allocateReadSet() { - _rHandles = new Array[Handle[_]](InitialReadCapacity) - _rVersions = new Array[CCSTM.Version](InitialReadCapacity) - } - - protected def readLocate(index: Int): AccessHistory.UndoLog = undoLog.readLocate(index) - - - //////////// pessimistic read buffer - - private final val InitialBargeCapacity = 1024 - private final val MaxRetainedBargeCapacity = 8 * InitialBargeCapacity - - private var _bCount = 0 - private var _bHandles: Array[Handle[_]] = null - allocateBargeSet() - - protected def bargeCount = _bCount - protected def bargeHandle(i: Int): Handle[_] = _bHandles(i) - - protected def recordBarge(handle: Handle[_]) { - val i = _bCount - if (i == _bHandles.length) - growBargeSet() - _bHandles(i) = handle - _bCount = i + 1 - } - - private def growBargeSet() { - _bHandles = copyTo(_bHandles, new Array[Handle[_]](_bHandles.length * 2)) - } - - private def checkpointBargeSet() { - undoLog.prevBargeCount = _bCount - } - - private def rollbackBargeSet(slot: CCSTM.Slot) { - val n = undoLog.prevBargeCount - var i = n - while (i < _bCount) { - rollbackHandle(_bHandles(i), slot) - _bHandles(i) = null - i += 1 - } - _bCount = n - } - - private def resetBargeSet() { - if (_bCount > 0) - resetBargeSetNonEmpty() - } - - private def resetBargeSetNonEmpty() { - if (_bHandles.length > MaxRetainedBargeCapacity) { - // avoid staying very large - allocateBargeSet() - } else { - // allow GC of old handles - var i = 0 - while (i < _bCount) { - _bHandles(i) = null - i += 1 - } - } - _bCount = 0 - } - - private def allocateBargeSet() { - _bHandles = new Array[Handle[_]](InitialBargeCapacity) - } - - - //////////// write buffer - - private final val InitialWriteCapacity = 8 - private final val MinAllocatedWriteCapacity = 512 - private final val MaxRetainedWriteCapacity = 8 * MinAllocatedWriteCapacity - - // This write buffer implementation uses chaining, but instead of storing the - // buckets in objects, they are packed into the arrays bucketAnys and - // bucketInts. Pointers to a bucket are represented as a 0-based int, with - // -1 representing nil. The dispatch array holds the entry index for the - // beginning of a bucket chain. - // - // When a nested context is created with push(), the current number of - // allocated buckets is recorded in undoThreshold. Any changes to the - // speculative value for a bucket with an index less than this threshold are - // logged to allow partial rollback. Buckets with an index greater than the - // undoThreshold can be discarded during rollback. This means that despite - // nesting, each key is stored at most once in the write buffer. - - /** The maximum index for which undo entries are required. */ - private var _wUndoThreshold = 0 - - private var _wCount = 0 - private var _wCapacity = InitialWriteCapacity - private var _wAnys: Array[AnyRef] = null - private var _wInts: Array[Int] = null - private var _wDispatch: Array[Int] = null - allocateWriteBuffer() - - private def allocateWriteBuffer() { - _wAnys = new Array[AnyRef](bucketAnysLen(MinAllocatedWriteCapacity)) - _wInts = new Array[Int](bucketIntsLen(MinAllocatedWriteCapacity)) - _wDispatch = new Array[Int](MinAllocatedWriteCapacity) - java.util.Arrays.fill(_wDispatch, 0, InitialWriteCapacity, -1) - } - - private def refI(i: Int) = 3 * i - private def specValueI(i: Int) = 3 * i + 1 - private def handleI(i: Int) = 3 * i + 2 - private def offsetI(i: Int) = 2 * i - private def nextI(i: Int) = 2 * i + 1 // bits 31..1 are the next, bit 0 is set iff freshOwner - - private def bucketAnysLen(c: Int) = 3 * (maxSizeForCap(c) + 1) - private def bucketIntsLen(c: Int) = 2 * (maxSizeForCap(c) + 1) - - private def maxSizeForCap(c: Int) = c - c / 4 - private def shouldGrow(s: Int, c: Int): Boolean = s > maxSizeForCap(c) - private def shouldGrow: Boolean = shouldGrow(_wCount, _wCapacity) - private def shouldShrink(s: Int, c: Int): Boolean = c > InitialWriteCapacity && !shouldGrow(s, c / 4) - private def shouldShrink: Boolean = shouldShrink(_wCount, _wCapacity) - - //////// accessors - - private def getRef(i: Int) = _wAnys(refI(i)) - final protected def getWriteHandle(i: Int) = _wAnys(handleI(i)).asInstanceOf[Handle[_]] - final protected def getWriteSpecValue[T](i: Int) = _wAnys(specValueI(i)).asInstanceOf[T] - private def getOffset(i: Int) = _wInts(offsetI(i)) - private def getNext(i: Int): Int = _wInts(nextI(i)) >> 1 - final protected def wasWriteFreshOwner(i: Int): Boolean = (_wInts(nextI(i)) & 1) != 0 - - private def setRef(i: Int, r: AnyRef) { _wAnys(refI(i)) = r } - private def setHandle(i: Int, h: Handle[_]) { _wAnys(handleI(i)) = h } - final private[AccessHistory] def setSpecValue[T](i: Int, v: T) { _wAnys(specValueI(i)) = v.asInstanceOf[AnyRef] } - private def setOffset(i: Int, o: Int) { _wInts(offsetI(i)) = o } - private def setNextAndFreshOwner(i: Int, n: Int, freshOwner: Boolean) { _wInts(nextI(i)) = (n << 1) | (if (freshOwner) 1 else 0) } - private def setNext(i: Int, n: Int) { _wInts(nextI(i)) = (n << 1) | (_wInts(nextI(i)) & 1) } - private def setFreshOwner(i: Int, freshOwner: Boolean) { setNextAndFreshOwner(i, getNext(i), freshOwner) } - - //////// bulk access - - protected def writeCount = _wCount - - //////// reads - - /** Reads a handle that is owned by this InTxnImpl family. */ - protected def stableGet[T](handle: Handle[T]): T = { - val i = findWrite(handle) - if (i >= 0) { - // hit - getWriteSpecValue[T](i) - } else { - // miss (due to shared metadata) - handle.data - } - } - - protected def findWrite(handle: Handle[_]): Int = { - val base = handle.base - val offset = handle.offset - find(base, offset, computeSlot(base, offset)) - } - - private def computeSlot(base: AnyRef, offset: Int): Int = { - if (_wCapacity == InitialWriteCapacity) 0 else CCSTM.hash(base, offset) & (_wCapacity - 1) - } - - private def find(base: AnyRef, offset: Int, slot: Int): Int = { - var i = _wDispatch(slot) - while (i >= 0 && ((base ne getRef(i)) || offset != getOffset(i))) - i = getNext(i) - i - } - - //////// writes - - protected def put[T](handle: Handle[T], freshOwner: Boolean, value: T) { - val base = handle.base - val offset = handle.offset - val slot = computeSlot(base, offset) - val i = find(base, offset, slot) - if (i >= 0) { - //assert(!freshOwner) - // hit, update an existing entry, optionally with undo - if (i < _wUndoThreshold) - undoLog.logWrite(i, getWriteSpecValue(i)) - setSpecValue(i, value) - } else { - // miss, create a new entry - append(base, offset, handle, freshOwner, value, slot) - } - } - - protected def swap[T](handle: Handle[T], freshOwner: Boolean, value: T): T = { - val i = findOrAllocate(handle, freshOwner) - val before = getWriteSpecValue[T](i) - setSpecValue(i, value) - return before - } - - protected def compareAndSetIdentity[T, R <: T with AnyRef]( - handle: Handle[T], freshOwner: Boolean, before: R, after: T): Boolean = { - val i = findOrAllocate(handle, freshOwner) - val v0 = getWriteSpecValue[T](i) - if (before eq v0.asInstanceOf[AnyRef]) { - setSpecValue(i, after) - return true - } else { - return false - } - } - - protected def getAndTransform[T](handle: Handle[T], freshOwner: Boolean, func: T => T): T = { - val i = findOrAllocate(handle, freshOwner) - val before = getWriteSpecValue[T](i) - setSpecValue(i, func(before)) - return before - } - - protected def transformAndGet[T](handle: Handle[T], freshOwner: Boolean, func: T => T): T = { - val i = findOrAllocate(handle, freshOwner) - val after = func(getWriteSpecValue[T](i)) - setSpecValue(i, after) - return after - } - - protected def transformAndExtract[T,V](handle: Handle[T], freshOwner: Boolean, func: T => (T,V)): V = { - val i = findOrAllocate(handle, freshOwner) - val pair = func(getWriteSpecValue[T](i)) - setSpecValue(i, pair._1) - return pair._2 - } - - protected def getAndAdd(handle: Handle[Int], freshOwner: Boolean, delta: Int): Int = { - val i = findOrAllocate(handle, freshOwner) - val before = getWriteSpecValue[Int](i) - setSpecValue(i, before + delta) - return before - } - - protected def writeAppend[T](handle: Handle[T], freshOwner: Boolean, value: T) { - val base = handle.base - val offset = handle.offset - val slot = computeSlot(base, offset) - append(base, offset, handle, freshOwner, value, slot) - } - - protected def writeUpdate[T](i: Int, value: T) { - if (i < _wUndoThreshold) - undoLog.logWrite(i, getWriteSpecValue(i)) - setSpecValue(i, value) - } - - private def findOrAllocate(handle: Handle[_], freshOwner: Boolean): Int = { - val base = handle.base - val offset = handle.offset - val slot = computeSlot(base, offset) - if (!freshOwner) { - val i = find(base, offset, slot) - if (i >= 0) { - // hit, undo log entry is required to capture the potential reads that - // won't be recorded in this nested txn's read set - if (i < _wUndoThreshold) - undoLog.logWrite(i, getWriteSpecValue(i)) - return i - } - } - - // miss, create a new entry using the existing data value - return append(base, offset, handle, freshOwner, handle.data, slot) - } - - private def append(base: AnyRef, offset: Int, handle: Handle[_], freshOwner: Boolean, value: Any, slot: Int): Int = { - val i = _wCount - setRef(i, base) - setSpecValue(i, value) - setHandle(i, handle) - setOffset(i, offset) - setNextAndFreshOwner(i, _wDispatch(slot), freshOwner) - _wDispatch(slot) = i - _wCount = i + 1 - - if (shouldGrow) - grow() - - // grow() relinks the buckets but doesn't move them, so i is still valid - return i - } - - private def grow() { - // adjust capacity - _wCapacity *= 2 - if (_wCapacity > _wDispatch.length) { - // we actually need to reallocate - _wAnys = copyTo(_wAnys, new Array[AnyRef](bucketAnysLen(_wCapacity))) - _wInts = copyTo(_wInts, new Array[Int](bucketIntsLen(_wCapacity))) - _wDispatch = new Array[Int](_wCapacity) - } - rebuildDispatch() - } - - private def rebuildDispatch() { - java.util.Arrays.fill(_wDispatch, 0, _wCapacity, -1) - - var i = 0 - while (i < _wCount) { - val slot = computeSlot(getRef(i), getOffset(i)) - setNext(i, _wDispatch(slot)) - _wDispatch(slot) = i - i += 1 - } - } - - //////// nesting management and visitation - - private def checkpointWriteBuffer() { - undoLog.prevWriteThreshold = _wUndoThreshold - _wUndoThreshold = _wCount - } - - private def mergeWriteBuffer() { - _wUndoThreshold = undoLog.prevWriteThreshold - } - - private def rollbackWriteBuffer(slot: CCSTM.Slot) { - // restore the specValue-s modified in pre-existing write buffer entries - undoLog.undoWrites(this) - - var i = _wCount - 1 - val e = _wUndoThreshold - val completeRelink = i >= 2 * e // faster to reprocess remaining entries? - while (i >= e) { - // unlock - if (wasWriteFreshOwner(i)) - rollbackHandle(getWriteHandle(i), slot) - - // unlink - if (!completeRelink) { - _wDispatch(computeSlot(getRef(i), getOffset(i))) = getNext(i) - } - - // discard references to aid GC - setRef(i, null) - setSpecValue(i, null) - setHandle(i, null) - - i -= 1 - } - _wCount = e - - if (completeRelink) { - while (shouldShrink) - _wCapacity /= 2 - rebuildDispatch() - } - - // revert to previous context - _wUndoThreshold = undoLog.prevWriteThreshold - } - - protected def rollbackHandle(h: Handle[_], slot: CCSTM.Slot) { rollbackHandle(h, slot, h.meta) } - - protected def rollbackHandle(h: Handle[_], slot: CCSTM.Slot, m0: CCSTM.Meta) { - // we must use CAS because there can be concurrent pendingWaiter adds - // and concurrent "helpers" that release the lock - var m = m0 - while (CCSTM.owner(m) == slot && !h.metaCAS(m, CCSTM.withRollback(m))) - m = h.meta - } - - private def resetWriteBuffer() { - if (_wCount > 0) - resetWriteBufferNonEmpty() - } - - private def resetWriteBufferNonEmpty() { - if (_wDispatch.length > MaxRetainedWriteCapacity) { - allocateWriteBuffer() - } else { - val n = bucketAnysLen(_wCount) - var i = 0 - while (i < n) { - // discard references to aid GC - _wAnys(i) = null - i += 1 - } - i = 0 - while (i < InitialWriteCapacity) { - _wDispatch(i) = -1 - i += 1 - } - //java.util.Arrays.fill(_wAnys, 0, bucketAnysLen(_wCount), null) - //java.util.Arrays.fill(_wDispatch, 0, InitialWriteCapacity, -1) - } - _wCount = 0 - _wCapacity = InitialWriteCapacity - } - - protected def addLatestWritesAsReads(convertToBarge: Boolean) { - // we need to capture the version numbers from barges - var i = undoLog.prevBargeCount - while (i < _bCount) { - val h = _bHandles(i) - recordRead(h, CCSTM.version(h.meta)) - i += 1 - } - - i = _wUndoThreshold - while (i < _wCount) { - val h = getWriteHandle(i) - // we only need one entry in the read set per meta - if (wasWriteFreshOwner(i)) { - recordRead(h, CCSTM.version(h.meta)) - if (convertToBarge) { - setFreshOwner(i, false) - recordBarge(h) - } - } - i += 1 - } - } -} - diff --git a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/ccstm/CCSTM.scala b/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/ccstm/CCSTM.scala deleted file mode 100644 index bbe125eb..00000000 --- a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/ccstm/CCSTM.scala +++ /dev/null @@ -1,325 +0,0 @@ -/* scala-stm - (c) 2009-2012, Stanford University, PPL */ - -package scala.concurrent.stm -package ccstm - -import java.util.concurrent.TimeUnit - -private[ccstm] object CCSTM extends GV6 { - - /** The number of times to spin tightly when waiting for a condition to - * become true. - */ - val SpinCount = System.getProperty("ccstm.spin", "100").toInt - - /** The number of times to spin tightly when waiting for another thread to - * perform work that we can also perform. - */ - val StealSpinCount = System.getProperty("ccstm.steal.spin", "10").toInt - - /** The number of times to spin with intervening calls to - * `Thread.yield` when waiting for a condition to become true. - * These spins will occur after the `SpinCount` spins. After - * `SpinCount + YieldCount` spins have been performed, the - * waiting thread will be blocked on a Java mutex. - */ - val YieldCount = System.getProperty("ccstm.yield", "2").toInt - - /** The number of optimistic failures to tolerate before switching to - * pessimistic reads for recently modified memory locations. Set to zero to - * always use pessimistic reads for memory locations modified since the - * beginning of the first transaction attempt. - */ - val BargeRecentThreshold = System.getProperty("ccstm.barge.recent.threshold", "3").toInt - - /** The number of optimistic failures to tolerate before switching to - * pessimistic reads for all reads. Set to zero to always use pessimistic - * reads. - */ - val BargeAllThreshold = System.getProperty("ccstm.barge.all.threshold", "30").toInt - - /** `slotManager` maps slot number to root `TxnLevelImpl`. */ - val slotManager = new TxnSlotManager[TxnLevelImpl](2048, 2) - val wakeupManager = new WakeupManager // default size - - /** Hashes `base` with `offset`. */ - def hash(base: AnyRef, offset: Int): Int = hash(base) ^ (0x40108097 * offset) - - /** Hashes `base` using its identity hash code. */ - def hash(base: AnyRef): Int = { - val h = System.identityHashCode(base) - // multiplying by -127 is recommended by java.util.IdentityHashMap - h - (h << 7) - } - - //////////////// Metadata bit packing - - // metadata bits are: - // 63 = locked for change - // 62 = pending wakeups - // 51..61 = owner slot - // 0..50 = version - type Meta = Long - type Slot = Int - type Version = Long - - /** The slot number used when a memory location has not been reserved or - * locked for writing. - */ - def unownedSlot: Slot = 0 - - /** The slot number used by non-transactional code that reserves or locks - * a location for writing. - */ - def nonTxnSlot: Slot = 1 - - def txnLocalMeta: Meta = withChanging(withVersion(0L, (1L << 51) - 2)) - - // TODO: clean up the following mess - - def owner(m: Meta): Slot = (m >> 51).asInstanceOf[Int] & 2047 - def version(m: Meta): Version = (m & ((1L << 51) - 1)) - def pendingWakeups(m: Meta): Boolean = (m & (1L << 62)) != 0 - def changing(m: Meta): Boolean = m < 0 - - // masks off owner and pendingWakeups - def changingAndVersion(m: Meta) = m & ((1L << 63) | ((1L << 51) - 1)) - def ownerAndVersion(m: Meta) = m & ((2047L << 51) | ((1L << 51) - 1)) - - def withOwner(m: Meta, o: Slot): Meta = (m & ~(2047L << 51)) | (o.asInstanceOf[Long] << 51) - def withUnowned(m: Meta): Meta = withOwner(m, unownedSlot) - def withVersion(m: Meta, ver: Version) = (m & ~((1L << 51) - 1)) | ver - - /** It is not allowed to set PendingWakeups if Changing. */ - def withPendingWakeups(m: Meta): Meta = m | (1L << 62) - def withChanging(m: Meta): Meta = m | (1L << 63) - def withUnchanging(m: Meta): Meta = m & ~(1L << 63) - - /** Clears all of the bits except the version. */ - def withCommit(m: Meta, ver: Version) = ver - - /** Includes withUnowned and withUnchanging. */ - def withRollback(m: Meta) = withUnowned(withUnchanging(m)) - -// //////////////// Version continuity between separate Refs -// -// private def CryptMask = 31 -// private val crypts = Array.tabulate(CryptMask + 1)(_ => new AtomicLong) -// -// def embalm(identity: Int, handle: Handle[_]) { -// val crypt = crypts(identity & CryptMask) -// val v = version(handle.meta) -// var old = crypt.get -// while (v > old && !crypt.compareAndSet(old, v)) -// old = crypt.get -// } -// -// def resurrect(identity: Int, handle: Handle[_]) { -// val v0 = crypts(identity & CryptMask).get -// if (!handle.metaCAS(0L, withVersion(0L, v0))) { -// throw new IllegalStateException("Refs may only be resurrected into an old identity before use") -// } -// handle.meta = withVersion(0L, v0) -// } - - //////////////// lock release helping - - def stealHandle(handle: Handle[_], m0: Meta, owningRoot: TxnLevelImpl) { - - // We can definitely make forward progress below at the expense of a - // couple of extra CAS, so it is not useful for us to do a big spin with - // yields. - var spins = 0 - do { - val m = handle.meta - if (ownerAndVersion(m) != ownerAndVersion(m0)) - return // no steal needed - - spins += 1 - } while (spins < StealSpinCount) - - // If owningRoot has been doomed it might be a while before it releases its - // lock on the handle. Slot numbers are reused, however, so we have to - // manage a reference count on the slot while we steal the handle. This is - // expensive, which is why we just spun. - - val owningSlot = owner(m0) - val o = slotManager.beginLookup(owningSlot) - try { - if (o ne owningRoot) - return // owningRoot unregistered itself, so it has already released all locks - - while (true) { - val m = handle.meta - if (ownerAndVersion(m) != ownerAndVersion(m0) || handle.metaCAS(m, withRollback(m))) - return // no longer locked, or steal succeeded - } - } finally { - slotManager.endLookup(owningSlot, o) - } - } - - //////////////// lock waiting - - /** Once `handle.meta` has been unlocked since a time it had - * value `m0`, the method will return. It might return sooner, - * but an attempt is made to do the right thing. If `currentTxn` - * is non-null, `currentTxn.requireActive` will be called before - * blocking and `currentTxn.resolveWriteWriteConflict` will be - * called before waiting for a transaction. - */ - @throws(classOf[InterruptedException]) - def weakAwaitUnowned(handle: Handle[_], m0: Meta, currentTxn: TxnLevelImpl) { - if (owner(m0) == nonTxnSlot) - weakAwaitNonTxnUnowned(handle, m0, currentTxn) - else - weakAwaitTxnUnowned(handle, m0, currentTxn) - } - - @throws(classOf[InterruptedException]) - private def weakAwaitNonTxnUnowned(handle: Handle[_], m0: Meta, currentTxn: TxnLevelImpl) { - // Non-transaction owners only set the changing bit for a short time (no - // user code and no loops), so we just wait them out. Previously we used - // the wakeup mechanism, but that requires all non-txn lock releases to use - // CAS. - - var spins = 0 - while (true) { - spins += 1 - if (spins > SpinCount) { - if (Thread.interrupted) - throw new InterruptedException - Thread.`yield` - } - - val m = handle.meta - if (ownerAndVersion(m) != ownerAndVersion(m0)) - return - - if (null != currentTxn) - currentTxn.requireActive() - } - } - - @throws(classOf[InterruptedException]) - private def weakAwaitTxnUnowned(handle: Handle[_], m0: Meta, currentTxn: TxnLevelImpl) { - if (null == currentTxn) { - // Spin a bit, but only from a non-txn context. If this is a txn context - // We need to roll ourself back ASAP if that is the proper resolution. - var spins = 0 - while (spins < SpinCount + YieldCount) { - spins += 1 - if (spins > SpinCount) - Thread.`yield` - - val m = handle.meta - if (ownerAndVersion(m) != ownerAndVersion(m0)) - return - - if (null != currentTxn) - currentTxn.requireActive() - } - } - - // to wait for a txn owner, we track down the InTxnImpl and wait on it - val owningSlot = owner(m0) - val owningRoot = slotManager.beginLookup(owningSlot) - try { - if (null != owningRoot && owningSlot == owner(handle.meta)) { - if (!owningRoot.status.completed) { - if (null != currentTxn) - currentTxn.txn.resolveWriteWriteConflict(owningRoot, handle) -// else if (owningRoot.txn == InTxnImpl.get) { -// // We are in an escaped context and are waiting for a txn that is -// // attached to this thread. Big trouble! -// assert(false) // CCSTM on top of scala-stm doesn't have escaped contexts, this shouldn't happen -// owningRoot.requestRollback( -// Txn.OptimisticFailureCause('conflicting_reentrant_nontxn_write, Some(handle))) -// } - - owningRoot.awaitCompleted(currentTxn, handle) - if (currentTxn != null) - currentTxn.requireActive() - } - - // we've already got the beginLookup, so no need to do a standalone - // stealHandle - var m = 0L - do { - m = handle.meta - assert(ownerAndVersion(m) != ownerAndVersion(m0) || owningRoot.status.isInstanceOf[Txn.RolledBack]) - } while (ownerAndVersion(m) == ownerAndVersion(m0) && !handle.metaCAS(m, withRollback(m))) - - // no longer locked, or steal succeeded - } - } finally { - slotManager.endLookup(owningSlot, owningRoot) - } - } -} - -/** The reference STM implementation for `scala.concurrent.stm`. CCSTM is a - * library-only STM based on the SwissTM algorithm, extended to reduce the - * overhead of non-transactional accesses, allow partial rollback, and include - * modular blocking and composition operators `retry` and `orAtomic`. - * - * During construction the system property "ccstm.stats" is checked. If it is - * "true" or "1" (actually if it starts with any of the characters 't', 'T', - * 'y', 'Y', or '1') then statistics are recorded while the program runs and - * printed to `Console` during JVM shutdown. - * - * Statistics are tracked separately for top-level transactions and true - * nested transactions. Many nested atomic blocks can be merged into the - * top-level transaction by CCSTM for efficiency; these are not reported as - * nested. - * - * Reported statistics are either counts or exponential histograms. For - * histograms `sum` is the sum of the samples, `count` is the number of - * transactions for which the statistic was non-zero, `avg` is `sum/count` - * and the histogram reports in brackets the number of samples that had a - * value of 1, 2..3, 4..7, 8..15, and so on. - * - * Counters: - * - `commits` -- committed transactions - * - `alternatives` -- alternatives provided to `atomic`, one sample per call - * to `atomic` - * - `retrySet` -- memory locations watched while performing modular - * blocking, one sample per top-level blocking event - * - `retryWaitElapsed` -- milliseconds elapsed during modular blocking, one - * sample per top-level blocking event - * - `explicitRetries` -- explicit retries using `retry`, `retryFor`, - * `Ref.View.await` or `Ref.View.tryAwait` - * - `unrecordedTxns` -- rollbacks that were to erase a successful use of - * `atomic.unrecorded` - * - `optimisticRetries` -- rollbacks that were automatically retried, one - * line per `OptimisticFailureCause.category` - * - `failures` -- rollbacks that were not retried, one line for each type of - * exception in `UncaughtExceptionCause` - * - `blockingAcquires` -- internal locks that could not be acquired - * immediately - * - `commitReadSet` -- optimistic `Ref` reads, one sample per committed - * top-level transaction - * - `commitBargeSet` -- locations read pessimistically, one sample per - * committed top-level transaction - * - `commitWriteSet` -- locations written, one sample per committed - * top-level transaction - * - `rollbackReadSet` -- optimistic `Ref` reads, one sample per transaction - * that was rolled back - * - `rollbackBargeSet` -- locations read pessimistically, one sample per - * transaction that was rolled back - * - `rollbackWriteSet` -- locations written pessimistically, one sample per - * transaction that was rolled back - * - * Read and write set counts for a nested transaction are merged into its - * parent if it commits, they are not counted separately during the nested - * commit. - * - * @author Nathan Bronson - */ -class CCSTM extends CCSTMExecutor with impl.STMImpl with CCSTMRefs.Factory { - def findCurrent(implicit mt: MaybeTxn): Option[InTxn] = Option(InTxnImpl.currentOrNull) - def dynCurrentOrNull: InTxn = InTxnImpl.dynCurrentOrNull - - def newCommitBarrier(timeout: Long, unit: TimeUnit): CommitBarrier = - new CommitBarrierImpl(unit.toNanos(timeout)) -} diff --git a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/ccstm/CCSTMExecutor.scala b/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/ccstm/CCSTMExecutor.scala deleted file mode 100644 index 0124e774..00000000 --- a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/ccstm/CCSTMExecutor.scala +++ /dev/null @@ -1,104 +0,0 @@ -/* scala-stm - (c) 2009-2012, Stanford University, PPL */ - -package scala.concurrent.stm -package ccstm - -import scala.util.control.ControlThrowable - -private[ccstm] object CCSTMExecutor { - val DefaultControlFlowTest = { x: Throwable => x.isInstanceOf[ControlThrowable] } - - val DefaultPostDecisionFailureHandler = { (status: Txn.Status, x: Throwable) => - new Exception("status=" + status, x).printStackTrace() - } -} - -private[ccstm] case class CCSTMExecutor private ( - retryTimeoutNanos: Option[Long], - controlFlowTest: Throwable => Boolean, - postDecisionFailureHandler: (Txn.Status, Throwable) => Unit - ) extends TxnExecutor { - - def this() = this(None, CCSTMExecutor.DefaultControlFlowTest, CCSTMExecutor.DefaultPostDecisionFailureHandler) - - def apply[Z](block: InTxn => Z)(implicit mt: MaybeTxn): Z = InTxnImpl().atomic(this, block) - - def oneOf[Z](blocks: (InTxn => Z)*)(implicit mt: MaybeTxn): Z = InTxnImpl().atomicOneOf(this, blocks) - - def unrecorded[Z](block: InTxn => Z, outerFailure: Txn.RollbackCause => Z)(implicit mt: MaybeTxn) = { - InTxnImpl().unrecorded(this, block, outerFailure) - } - - def pushAlternative[Z](mt: MaybeTxn, block: (InTxn) => Z): Boolean = InTxnImpl().pushAlternative(block) - - def compareAndSet[A, B](a: Ref[A], a0: A, a1: A, b: Ref[B], b0: B, b1: B): Boolean = { - val ah = a.asInstanceOf[Handle.Provider[A]].handle - val bh = b.asInstanceOf[Handle.Provider[B]].handle - InTxnImpl.dynCurrentOrNull match { - case null => NonTxn.transform2[A, B, Boolean](ah, bh, { (av, bv) => if (a0 == av && b0 == bv) (a1, b1, true) else (av, bv, false) }) - case txn => a0 == txn.get(ah) && b0 == txn.get(bh) && { txn.set(ah, a1) ; txn.set(bh, b1) ; true } - } - } - - def compareAndSetIdentity[A <: AnyRef, B <: AnyRef](a: Ref[A], a0: A, a1: A, b: Ref[B], b0: B, b1: B): Boolean = { - val aRead = a0 eq a1 - val bRead = b0 eq b1 - if (aRead && bRead) - cci(a, a0, b, b0) - else if (aRead) - ccasi(a, a0, b, b0, b1) - else if (bRead) - ccasi(b, b0, a, a0, a1) - else - dcasi(a, a0, a1, b, b0, b1) - } - - private def cci[A <: AnyRef, B <: AnyRef](a: Ref[A], a0: A, b: Ref[B], b0: B): Boolean = { - val ah = a.asInstanceOf[Handle.Provider[A]].handle - val bh = b.asInstanceOf[Handle.Provider[B]].handle - InTxnImpl.dynCurrentOrNull match { - case null => NonTxn.cci(ah, a0, bh, b0) - case txn => (a0 eq txn.get(ah)) && (b0 eq txn.get(bh)) - } - } - - private def ccasi[A <: AnyRef, B <: AnyRef](a: Ref[A], a0: A, b: Ref[B], b0: B, b1: B): Boolean = { - val ah = a.asInstanceOf[Handle.Provider[A]].handle - val bh = b.asInstanceOf[Handle.Provider[B]].handle - InTxnImpl.dynCurrentOrNull match { - case null => NonTxn.ccasi(ah, a0, bh, b0, b1) - case txn => (a0 eq txn.get(ah)) && (b0 eq txn.get(bh)) && { txn.set(bh, b1) ; true } - } - } - - private def dcasi[A <: AnyRef, B <: AnyRef](a: Ref[A], a0: A, a1: A, b: Ref[B], b0: B, b1: B): Boolean = { - val ah = a.asInstanceOf[Handle.Provider[A]].handle - val bh = b.asInstanceOf[Handle.Provider[B]].handle - InTxnImpl.dynCurrentOrNull match { - case null => NonTxn.transform2[A, B, Boolean](ah, bh, { (av, bv) => if ((a0 eq av) && (b0 eq bv)) (a1, b1, true) else (av, bv, false) }) - case txn => (a0 eq txn.get(ah)) && (b0 eq txn.get(bh)) && { txn.set(ah, a1) ; txn.set(bh, b1) ; true } - } - } - - def withRetryTimeoutNanos(timeout: Option[Long]): TxnExecutor = copy(retryTimeoutNanos = timeout) - - def isControlFlow(x: Throwable): Boolean = controlFlowTest(x) - - def withControlFlowRecognizer(pf: PartialFunction[Throwable, Boolean]): TxnExecutor = { - copy(controlFlowTest = { x: Throwable => if (pf.isDefinedAt(x)) pf(x) else controlFlowTest(x) }) - } - - def withPostDecisionFailureHandler(handler: (Txn.Status, Throwable) => Unit): TxnExecutor = { - copy(postDecisionFailureHandler = handler) - } - - override def toString: String = { - ("CCSTMExecutor@" + hashCode.toHexString + - "(retryTimeoutNanos=" + retryTimeoutNanos + - ", controlFlowTest=" + - (if (controlFlowTest eq CCSTMExecutor.DefaultControlFlowTest) "default" else controlFlowTest) + - ", postDecisionFailureHandler=" + - (if (postDecisionFailureHandler eq CCSTMExecutor.DefaultPostDecisionFailureHandler) "default" else postDecisionFailureHandler) + - ")") - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/ccstm/CCSTMRefs.scala b/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/ccstm/CCSTMRefs.scala deleted file mode 100644 index 3360bdb1..00000000 --- a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/ccstm/CCSTMRefs.scala +++ /dev/null @@ -1,133 +0,0 @@ -/* scala-stm - (c) 2009-2012, Stanford University, PPL */ - -package scala.concurrent.stm -package ccstm - -import java.util.concurrent.atomic.AtomicLongFieldUpdater - -private[ccstm] object CCSTMRefs { - - trait Factory extends impl.RefFactory { - def newRef(v0: Boolean): Ref[Boolean] = new BooleanRef(v0) - def newRef(v0: Byte): Ref[Byte] = new ByteRef(v0) - def newRef(v0: Short): Ref[Short] = new ShortRef(v0) - def newRef(v0: Char): Ref[Char] = new CharRef(v0) - def newRef(v0: Int): Ref[Int] = new IntRef(v0) - def newRef(v0: Float): Ref[Float] = new FloatRef(v0) - def newRef(v0: Long): Ref[Long] = new LongRef(v0) - def newRef(v0: Double): Ref[Double] = new DoubleRef(v0) - def newRef(v0: Unit): Ref[Unit] = new GenericRef(v0) - def newRef[T : ClassManifest](v0: T): Ref[T] = new GenericRef(v0) - - def newTxnLocal[A](init: => A, - initialValue: InTxn => A, - beforeCommit: InTxn => Unit, - whilePreparing: InTxnEnd => Unit, - whileCommitting: InTxnEnd => Unit, - afterCommit: A => Unit, - afterRollback: Txn.Status => Unit, - afterCompletion: Txn.Status => Unit): TxnLocal[A] = new TxnLocalImpl( - init, initialValue, beforeCommit, whilePreparing, whileCommitting, afterCommit, afterRollback, afterCompletion) - - def newTArray[A: ClassManifest](length: Int): TArray[A] = new TArrayImpl[A](length) - def newTArray[A: ClassManifest](xs: TraversableOnce[A]): TArray[A] = new TArrayImpl[A](xs) - - def newTMap[A, B]: TMap[A, B] = skel.HashTrieTMap.empty[A, B] - def newTMapBuilder[A, B] = skel.HashTrieTMap.newBuilder[A, B] - - def newTSet[A]: TSet[A] = skel.HashTrieTSet.empty[A] - def newTSetBuilder[A] = skel.HashTrieTSet.newBuilder[A] - } - - private abstract class BaseRef[A] extends Handle[A] with RefOps[A] with ViewOps[A] { - def handle: Handle[A] = this - def single: Ref.View[A] = this - def ref: Ref[A] = this - def base: AnyRef = this - def metaOffset: Int = 0 - def offset: Int = 0 - - override def dbgStr: String = super[RefOps].dbgStr - override def dbgValue: Any = super[RefOps].dbgValue - } - - // Every call to AtomicLongFieldUpdater checks the receiver's type with - // receiver.getClass().isInstanceOf(declaringClass). This means that there - // is a substantial performance benefit to putting the meta field in the - // concrete leaf classes instead of the abstract base class. - - private val booleanUpdater = (new BooleanRef(false)).newMetaUpdater - private val byteUpdater = (new ByteRef(0 : Byte)).newMetaUpdater - private val shortUpdater = (new ShortRef(0 : Short)).newMetaUpdater - private val charUpdater = (new CharRef(0 : Char)).newMetaUpdater - private val intUpdater = (new IntRef(0 : Int)).newMetaUpdater - private val floatUpdater = (new FloatRef(0 : Float)).newMetaUpdater - private val longUpdater = (new LongRef(0 : Long)).newMetaUpdater - private val doubleUpdater = (new DoubleRef(0 : Double)).newMetaUpdater - private val genericUpdater = (new GenericRef("")).newMetaUpdater - - private class BooleanRef(@volatile var data: Boolean) extends BaseRef[Boolean] { - @volatile var meta = 0L - def metaCAS(m0: Long, m1: Long) = booleanUpdater.compareAndSet(this, m0, m1) - def newMetaUpdater = AtomicLongFieldUpdater.newUpdater(classOf[BooleanRef], "meta") - } - - private class ByteRef(@volatile var data: Byte) extends BaseRef[Byte] { - @volatile var meta = 0L - def metaCAS(m0: Long, m1: Long) = byteUpdater.compareAndSet(this, m0, m1) - def newMetaUpdater = AtomicLongFieldUpdater.newUpdater(classOf[ByteRef], "meta") - } - - private class ShortRef(@volatile var data: Short) extends BaseRef[Short] { - @volatile var meta = 0L - def metaCAS(m0: Long, m1: Long) = shortUpdater.compareAndSet(this, m0, m1) - def newMetaUpdater = AtomicLongFieldUpdater.newUpdater(classOf[ShortRef], "meta") - } - - private class CharRef(@volatile var data: Char) extends BaseRef[Char] { - @volatile var meta = 0L - def metaCAS(m0: Long, m1: Long) = charUpdater.compareAndSet(this, m0, m1) - def newMetaUpdater = AtomicLongFieldUpdater.newUpdater(classOf[CharRef], "meta") - } - - private class IntRef(@volatile var data: Int) extends BaseRef[Int] { - @volatile var meta = 0L - def metaCAS(m0: Long, m1: Long) = intUpdater.compareAndSet(this, m0, m1) - def newMetaUpdater = AtomicLongFieldUpdater.newUpdater(classOf[IntRef], "meta") - - override def += (rhs: Int)(implicit num: Numeric[Int]) { incr(rhs) } - override def -= (rhs: Int)(implicit num: Numeric[Int]) { incr(-rhs) } - private def incr(delta: Int) { - if (delta != 0) { - InTxnImpl.dynCurrentOrNull match { - case null => NonTxn.getAndAdd(handle, delta) - case txn => txn.getAndAdd(handle, delta) - } - } - } - } - - private class FloatRef(@volatile var data: Float) extends BaseRef[Float] { - @volatile var meta = 0L - def metaCAS(m0: Long, m1: Long) = floatUpdater.compareAndSet(this, m0, m1) - def newMetaUpdater = AtomicLongFieldUpdater.newUpdater(classOf[FloatRef], "meta") - } - - private class LongRef(@volatile var data: Long) extends BaseRef[Long] { - @volatile var meta = 0L - def metaCAS(m0: Long, m1: Long) = longUpdater.compareAndSet(this, m0, m1) - def newMetaUpdater = AtomicLongFieldUpdater.newUpdater(classOf[LongRef], "meta") - } - - private class DoubleRef(@volatile var data: Double) extends BaseRef[Double] { - @volatile var meta = 0L - def metaCAS(m0: Long, m1: Long) = doubleUpdater.compareAndSet(this, m0, m1) - def newMetaUpdater = AtomicLongFieldUpdater.newUpdater(classOf[DoubleRef], "meta") - } - - private class GenericRef[A](@volatile var data: A) extends BaseRef[A] { - @volatile var meta = 0L - def metaCAS(m0: Long, m1: Long) = genericUpdater.compareAndSet(this, m0, m1) - def newMetaUpdater = AtomicLongFieldUpdater.newUpdater(classOf[GenericRef[_]], "meta") - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/ccstm/CommitBarrierImpl.scala b/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/ccstm/CommitBarrierImpl.scala deleted file mode 100644 index 7b690c88..00000000 --- a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/ccstm/CommitBarrierImpl.scala +++ /dev/null @@ -1,233 +0,0 @@ -/* scala-stm - (c) 2009-2012, Stanford University, PPL */ - -package scala.concurrent.stm -package ccstm - -import java.util.concurrent.TimeUnit - -private[ccstm] object CommitBarrierImpl { - object MemberCancelException extends Exception - - sealed abstract class State - case object Active extends State - case object MemberWaiting extends State - case class Cancelled(cause: CommitBarrier.CancelCause) extends State - case object Committed extends State -} - -private[ccstm] class CommitBarrierImpl(timeoutNanos: Long) extends CommitBarrier { - import CommitBarrier._ - import CommitBarrierImpl._ - import WakeupManager.blocking - - private val lock = new Object - - /** The number of non-cancelled members. */ - private var activeCount = 0 - - /** The number of members pending a commit decision. */ - private var waitingCount = 0 - - /** If non-empty, all present and future members have been cancelled. */ - private var groupState: State = Active - - class MemberImpl(var executor: TxnExecutor) extends Member with Txn.ExternalDecider { - - @volatile private var state: State = Active - @volatile private var target: NestingLevel = null - - def commitBarrier = CommitBarrierImpl.this - - def atomic[Z](body: InTxn => Z): Either[CancelCause, Z] = { - try { - executor { implicit txn => - if (state != Active) { - Txn.rollback(Txn.UncaughtExceptionCause(MemberCancelException)) - } - Txn.setExternalDecider(this) - txn.asInstanceOf[InTxnImpl].commitBarrier = commitBarrier - target = NestingLevel.current - Right(body(txn)) - } - } catch { - case x: Throwable => { - state match { - case Active => { - // txn rolled back before involving external decider, all - // members must be rolled back - cancelAll(MemberUncaughtExceptionCause(x)) - throw x - } - case MemberWaiting => { - // interrupt during ExternalDecider, all already cancelled - assert(x.isInstanceOf[InterruptedException]) - assert(groupState.isInstanceOf[Cancelled]) - throw x - } - case Cancelled(cause) => { - // barrier state already updated - Left(cause) - } - case Committed => { - // control flow exception as part of group commit, tricky! - throw x - } - } - } - } finally { - target = null - } - } - - private def markCancelled(cause: CancelCause, isLocal: Boolean) { - val firstCause = groupState match { - case c: Cancelled => c - case _ => Cancelled(cause) - } - - state match { - case Active => { - state = firstCause - activeCount -= 1 - checkBarrierCommit_nl() - } - case MemberWaiting => { - state = firstCause - activeCount -= 1 - waitingCount -= 1 - if (!isLocal) { - // this member should exit its external decider - lock.notifyAll() - } - } - case Cancelled(_) => {} - case Committed => { - throw new IllegalStateException("can't cancel member after commit") - } - } - } - - private[CommitBarrierImpl] def cancelImpl(cause: CancelCause) { - lock.synchronized { - markCancelled(cause, false) - } - val t = target - if (t != null) { - t.requestRollback(Txn.UncaughtExceptionCause(MemberCancelException)) - t.asInstanceOf[TxnLevelImpl].awaitCompleted(null, "CommitBarrier cancel") - } - } - - def cancel(cause: UserCancel) { - cancelImpl(cause) - } - - def shouldCommit(implicit txn: InTxnEnd): Boolean = { - var cause = lock.synchronized { shouldCommit_nl() } - if (cause != null) - txn.rollback(cause) - true - } - - private def shouldCommit_nl(): Txn.RollbackCause = { - if (state == Active) { - state = MemberWaiting - waitingCount += 1 - checkBarrierCommit_nl() - } - - var t0 = 0L - - (while (true) { - // cancelImpl is a no-op if we're already cancelled - groupState match { - case Cancelled(cause) => markCancelled(cause, true) - case Committed if state == MemberWaiting => { - state = Committed - return null - } - case _ => {} - } - - state match { - case Cancelled(_) => return Txn.UncaughtExceptionCause(MemberCancelException) - case MemberWaiting => {} - case _ => throw new Error("impossible state " + state) - } - - // wait - try { - if (timeoutNanos < Long.MaxValue) { - val now = System.nanoTime() - if (t0 == 0) { - t0 = now - } - - val remaining = (t0 + timeoutNanos) - now - if (remaining <= 0) { - cancelAll(Timeout) - markCancelled(Timeout, true) - return Txn.UncaughtExceptionCause(MemberCancelException) - } else { - val millis = TimeUnit.NANOSECONDS.toMillis(remaining) - val nanos = remaining - TimeUnit.MILLISECONDS.toNanos(millis) - blocking { lock.wait(millis, nanos.asInstanceOf[Int]) } - } - } else { - blocking { lock.wait() } - } - } catch { - case x: InterruptedException => { - // don't cancel ourself so we can throw InterruptedException - cancelAll(MemberUncaughtExceptionCause(x)) - return Txn.UncaughtExceptionCause(x) - } - } - }).asInstanceOf[Nothing] - } - } - - private def checkBarrierCommit_nl() { - groupState match { - case Active => { - if (activeCount == waitingCount && activeCount > 0) { - groupState = Committed - lock.notifyAll() - } - } - case _ => {} - } - } - - private[ccstm] def cancelAll(cause: CancelCause) { - lock.synchronized { - groupState match { - case Active => { - groupState = Cancelled(cause) - lock.notifyAll() - } - case Cancelled(_) => {} - case _ => throw new Error("impossible groupState " + groupState) - } - } - } - - def addMember(cancelOnLocalRollback: Boolean)(implicit txn: MaybeTxn): Member = { - lock.synchronized { - groupState match { - case Cancelled(_) => throw new IllegalStateException("commit barrier has already rolled back") - case Committed => throw new IllegalStateException("commit barrier has already committed") - case _ => activeCount += 1 - } - } - - val m = new MemberImpl(atomic) - - if (cancelOnLocalRollback) { - for (txn <- Txn.findCurrent) - Txn.afterRollback({ _ => m.cancelImpl(CreatingTxnRolledBack) })(txn) - } - - m - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/ccstm/Counter.scala b/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/ccstm/Counter.scala deleted file mode 100644 index 6e85a736..00000000 --- a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/ccstm/Counter.scala +++ /dev/null @@ -1,52 +0,0 @@ -/* scala-stm - (c) 2009-2011, Stanford University, PPL */ - -package scala.concurrent.stm.ccstm - -import java.util.concurrent.atomic.AtomicLong -import scala.annotation.tailrec - -/** A counter with a linearizable increment operator and adaptive contention - * avoidance. Reading the counter with `apply()` is not linearizable (unless - * the only delta passed to += is 1) and is not optimized. - */ -private[ccstm] class Counter extends { - private final val MaxStripes = 64 - - // this doesn't need to be volatile because when we grow it we retain all of - // the old AtomicLong-s - private var _stripes = Array(new AtomicLong) - - private def grow() { - synchronized { - if (_stripes.length < MaxStripes) { - val repl = new Array[AtomicLong](_stripes.length * 2) - System.arraycopy(_stripes, 0, repl, 0, _stripes.length) - var i = _stripes.length - while (i < repl.length) { - repl(i) = new AtomicLong - i += 1 - } - _stripes = repl - } - } - } - - def += (delta: Int) { - if (delta != 0) - incr(delta) - } - - @tailrec private def incr(delta: Int) { - val s = _stripes - val i = CCSTM.hash(Thread.currentThread) & (s.length - 1) - val prev = s(i).get - if (!s(i).compareAndSet(prev, prev + delta)) { - grow() - incr(delta) - } - } - - def apply(): Long = _stripes.foldLeft(0L)( _ + _.get ) - - override def toString = apply().toString -} diff --git a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/ccstm/GV6.scala b/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/ccstm/GV6.scala deleted file mode 100644 index 261cca27..00000000 --- a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/ccstm/GV6.scala +++ /dev/null @@ -1,139 +0,0 @@ -/* scala-stm - (c) 2009-2011, Stanford University, PPL */ - -package scala.concurrent.stm -package ccstm - -import java.util.concurrent.atomic.AtomicLong - - -private[ccstm] trait GV6 { - - /** The global timestamp. We use TL2's GV6 scheme to avoid the need to - * increment this during every transactional commit. Non-transactional - * writes are even more conservative, incrementing the global version only - * when it lags the local version by a (configurable) fixed amount. This - * helps reduce contention (especially when there are many non-transactional - * writes), but it means we must always validate transactions that are not - * read-only. To help reduce the spurious revalidations caused by GV6, we - * adaptively adjust the ratio of silent commits. Spurious revalidations - * can also be triggered by silent non-txn run ahead, so we use bit 0 of the - * version to differentiate the type of the most recent write, 0 for non-txn - * and 1 for txn. - */ - val globalVersion = new AtomicLong(1) - - private val silentCommitRatioMin = System.getProperty("ccstm.gv6.min", "1").toInt - private val silentCommitRatioMax = - System.getProperty("ccstm.gv6.max", (Runtime.getRuntime.availableProcessors min 16).toString).toInt - - /** The approximate ratio of the number of commits to the number of - * increments of `globalVersion`, as in TL2's GV6 scheme. If - * greater than one, the actual choice to advance or not is made with a - * random number generator. - */ - private var silentCommitRatio = - (Runtime.getRuntime.availableProcessors / 2) max silentCommitRatioMin min silentCommitRatioMax - - private var silentCommitCutoff = intRangeFraction(silentCommitRatio) - - private val silentCommitRand = skel.SimpleRandom - - /** The maximum value of `nonTxnWriteVersion - globalVersion` that - * will be allowed before a non-transactional store attempts to increase - * `globalVersion`. Any value larger than zero admits the - * possibility that a non-transactional write will leave a version number - * that forces revalidation of a transaction that discovers it (like a - * silently-committed txn under GV6). Larger values can help amortize the - * cost of updating the counter. This is double the "ccstm.nontxn.runahead" - * property because we reserve bit 0 to record the txn state of the last - * writer. - */ - private val nonTxnSilentRunAhead = 2 * System.getProperty("ccstm.nontxn.runahead", "32").toInt - - /** If `x` is a signed integer evenly chosen from a uniform distribution - * between Integer.MIN_VALUE and Integer.MAX_VALUE, then the test - * `(x <= intRangeFraction(r))` will succeed `1.0 / r` of the time. - */ - private def intRangeFraction(r: Int) = ((1 << 31) + ((1L << 32) / r) - 1).asInstanceOf[Int] - - /** Returns a value that is greater than `prevVersion` and greater - * than the value of `globalVersion` on entry. May increase - * `globalVersion`. - */ - def nonTxnWriteVersion(prevVersion: Long): Long = { - val g = globalVersion.get - val result = (math.max(g, prevVersion) + 2) & ~1L - if (result > g + nonTxnSilentRunAhead) { - globalVersion.compareAndSet(g, prevVersion + 1) - } - result - } - - /** Returns a version to use for reading in a new transaction. */ - def freshReadVersion: Long = globalVersion.get - - /** Guarantees that `globalVersion.get` is ≥ - * `minRV`, and returns `globalVersion.get`. This form of - * `freshReadVersion` is used when the read version of a transaction needs - * to be advanced by revalidating. - */ - def freshReadVersion(minRV: Long): Long = { - // A call to this method corresponds to an mid-txn revalidation, which is - // relatively costly. If minRV is odd then the revalidation is due to a - // silent commit, so consider adjusting the silent commit ratio. We only - // do this 1/64 of the time, though. - if ((minRV & 127) == 1) { - reduceRevalidateProbability() - } - - (while (true) { - val g = globalVersion.get - if (g >= minRV) { - return g - } - if (globalVersion.compareAndSet(g, minRV)) { - return minRV - } - }).asInstanceOf[Nothing] - } - - /** Returns a value that is greater than `globalVersion.get` and greater than - * `readVersion`, possibly increasing `globalVersion`. - */ - def freshCommitVersion(readVersion: Long): Long = { - val cutoff = silentCommitCutoff - val install = cutoff == Int.MaxValue || silentCommitRand.nextInt <= cutoff - - val gvSnap = globalVersion.get - val result = (math.max(readVersion, gvSnap) + 1) | 1L - - // if we fail to install with a CAS, 1/128 prob of adjusting - // silentCommitRatio - if (install && - !globalVersion.compareAndSet(gvSnap, result) && - (result & 254) == 0) - reduceContentionProbability() - - result - } - - private def reduceRevalidateProbability() { - // increment the commit version on more commits, so reduce the ratio - val r = silentCommitRatio - if (r > silentCommitRatioMin) { - silentCommitRatio = r - 1 - silentCommitCutoff = intRangeFraction(r - 1) - //System.err.println("reduced ratio to " + (r - 1)) - } - } - - private def reduceContentionProbability() { - // increment the commit version on fewer commits, so reduce the ratio - val r = silentCommitRatio - if (r < silentCommitRatioMax) { - silentCommitRatio = r + 1 - silentCommitCutoff = intRangeFraction(r + 1) - //System.err.println("increased ratio to " + (r + 1)) - } - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/ccstm/Handle.scala b/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/ccstm/Handle.scala deleted file mode 100644 index 232ce648..00000000 --- a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/ccstm/Handle.scala +++ /dev/null @@ -1,52 +0,0 @@ -/* scala-stm - (c) 2009-2010, Stanford University, PPL */ - -package scala.concurrent.stm -package ccstm - - -private[ccstm] object Handle { - - /** A `Handle.Provider` has a single associated handle. */ - trait Provider[T] { - def handle: Handle[T] - - override def hashCode: Int = { - val h = handle - CCSTM.hash(h.base, h.offset) - } - - override def equals(rhs: Any): Boolean = { - (this eq rhs.asInstanceOf[AnyRef]) || (rhs match { - case r: Handle.Provider[_] => { - val h1 = handle - val h2 = r.handle - (h1.base eq h2.base) && (h1.offset == h2.offset) - } - case r: Ref[_] => r equals this - case v: Ref.View[_] => v equals this - case _ => false - }) - } - } -} - -/** A `Handle` defines the operations that must be available for a particular - * memory location in order for it to be managed by CCSTM. The identity of - * the location is determined by `base` and `offset`, with `base` be used only - * in comparisons using `eq` or `ne` (no methods of `base` will ever be - * invoked). Metadata is identified by `base` and `metaOffset` (the assumption - * made during blocking is that a write to a handle's `meta` may affect the - * `meta` read by any handle with the same `base` and `metaOffset`). - * - * @author Nathan Bronson - */ -private[ccstm] abstract class Handle[T] { - def meta: Long - def meta_=(v: Long) - def metaCAS(before: Long, after: Long): Boolean - def base: AnyRef - def offset: Int - def metaOffset: Int - def data: T - def data_=(v: T) -} diff --git a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/ccstm/InTxnImpl.scala b/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/ccstm/InTxnImpl.scala deleted file mode 100644 index 3c3d43c7..00000000 --- a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/ccstm/InTxnImpl.scala +++ /dev/null @@ -1,914 +0,0 @@ -/* scala-stm - (c) 2009-2014, Stanford University, PPL */ - -package scala.concurrent.stm -package ccstm - - -private[ccstm] object InTxnImpl extends ThreadLocal[InTxnImpl] { - - override def initialValue = new InTxnImpl - - def apply()(implicit mt: MaybeTxn): InTxnImpl = mt match { - case x: InTxnImpl => x - case _ => get // this will create one - } - - private def active(txn: InTxnImpl): InTxnImpl = if (txn.internalCurrentLevel != null) txn else null - - def dynCurrentOrNull: InTxnImpl = active(get) - - def currentOrNull(implicit mt: MaybeTxn) = active(apply()) -} - -private[stm] object RewindUnrecordedTxnError extends Error { - override def fillInStackTrace(): Throwable = this -} - -/** In CCSTM there is one `InTxnImpl` per thread, and it is reused across all - * transactions. - * - * @author Nathan Bronson - */ -private[ccstm] class InTxnImpl extends InTxnRefOps { - import CCSTM._ - import Txn._ - import skel.RollbackError - - //////////// pre-transaction state - - private var _alternatives: List[InTxn => Any] = Nil - - - //////////// per-attempt history - - /** Subsumption dramatically reduces the overhead of nesting, but it doesn't - * allow partial rollback. If we find out that partial rollback was needed - * then we disable subsumption and rerun the parent. - */ - private var _subsumptionAllowed = true - - /** The total amount of modular blocking time performed on this thread since - * the last top-level commit or top-level permanent rollback. - */ - private var _cumulativeBlockingNanos = 0L - - //////////////// per-transaction state - - /** A read will barge if `_barding && version(meta) >= _bargeVersion`. */ - protected var _barging: Boolean = false - protected var _bargeVersion: Version = 0 - - /** Non-negative values are assigned slots, negative values are the bitwise - * complement of the last used slot value. - */ - protected var _slot: Slot = ~0 - - private var _currentLevel: TxnLevelImpl = null - - private var _pendingFailure: Throwable = null - - /** This is the outer-most level that contains any subsumption, or null if - * there is no subsumption taking place. - */ - private var _subsumptionParent: TxnLevelImpl = null - - /** Higher wins. Currently priority doesn't change throughout the lifetime - * of a rootLevel. It would be okay for it to monotonically increase, so - * long as there is no change of the current txn's priority between the - * priority check on conflict and any subsequent waiting that occurs. - */ - private var _priority: Int = 0 - - /** The read version of this transaction. It is guaranteed that all values - * read by this transaction have a version number less than or equal to this - * value, and that any transaction whose writes conflict with this - * transaction will label those writes with a version number greater than - * this value. The read version must never be greater than - * `globalVersion.get`, must never decrease, and each time it is - * changed the read set must be revalidated. Lazily assigned. - */ - private var _readVersion: Version = 0 - - /** The commit barrier in which this transaction is participating. */ - var commitBarrier: CommitBarrierImpl = null - - //////////// value-like operations - - def status: Status = _currentLevel.statusAsCurrent - - def currentLevel: NestingLevel = { - if (_subsumptionParent != null) { - _subsumptionAllowed = false - _subsumptionParent.forceRollback(OptimisticFailureCause('restart_to_materialize_current_level, None)) - throw RollbackError - } - _currentLevel - } - - override def toString = { - ("InTxnImpl@" + hashCode.toHexString + "(" + - (if (_currentLevel == null) "Detached" else status.toString) + - ", slot=" + _slot + - ", subsumptionAllowed=" + _subsumptionAllowed + - ", priority=" + _priority + - ", readCount=" + readCount + - ", bargeCount=" + bargeCount + - ", writeCount=" + writeCount + - ", readVersion=0x" + _readVersion.toHexString + - (if (_barging) ", bargingVersion=0x" + _bargeVersion.toHexString else "") + - ", cumulativeBlockingNanos=" + _cumulativeBlockingNanos + - ", commitBarrier=" + commitBarrier + - ")") - } - - - //////////// methods for use by other CCSTM components - - protected def undoLog: TxnLevelImpl = _currentLevel - - protected def internalCurrentLevel: TxnLevelImpl = _currentLevel - - /** After this method returns, either the current transaction will have been - * rolled back, or it is safe to wait for `currentOwner` to be `Committed` - * or doomed. - */ - def resolveWriteWriteConflict(owningRoot: TxnLevelImpl, contended: AnyRef) { - // if write is not allowed, throw an exception of some sort - requireActive() - - // TODO: boost our priority if we have written? - - // This test is _almost_ symmetric. Tie goes to neither. - if (this._priority <= owningRoot.txn._priority) { - resolveAsWWLoser(owningRoot, contended, false, 'owner_has_priority) - } else { - // This will resolve the conflict regardless of whether it succeeds or fails. - val s = owningRoot.requestRollback(OptimisticFailureCause('steal_by_higher_priority, Some(contended))) - if (s == Preparing || s == Committing) { - // owner can't be remotely canceled - val msg = if (s == Preparing) 'owner_is_preparing else 'owner_is_committing - resolveAsWWLoser(owningRoot, contended, true, msg) - } - } - } - - private def resolveAsWWLoser(owningRoot: TxnLevelImpl, contended: AnyRef, ownerIsCommitting: Boolean, msg: Symbol) { - if (!shouldWaitAsWWLoser(owningRoot, ownerIsCommitting)) { - // The failed write is in the current nesting level, so we only need to - // invalidate one nested atomic block. Nothing will get better for us - // until the current owner completes or this txn has a higher priority, - // however. - _currentLevel.forceRollback(OptimisticFailureCause(msg, Some(contended))) - throw RollbackError - } - } - - private def shouldWaitAsWWLoser(owningRoot: TxnLevelImpl, ownerIsCommitting: Boolean): Boolean = { - // If we haven't performed any writes or taken any pessimistic locks, there - // is no point in not waiting. - if (writeCount == 0 && bargeCount == 0 && !writeResourcesPresent) - return true - - // If the current owner is in the process of committing then we should - // wait, because we can't succeed until their commit is done. This means - // that regardless of priority all of this txn's retries are just useless - // spins. This is especially important in the case of external resources - // that perform I/O during commit. No deadlock is possible because a - // committing txn already has all of the ownership it needs. - if (ownerIsCommitting) - return true - - // CommitBarrier-s have the ability to create priority inversion during - // waiting, because a low-priority member can delay the completion of - // the group even if the rest is composed of high-priority transactions - // (or prepared transactions, that have infinite effective priority). - // Although it seems tempting to try to add extra conditions under which - // it is okay to wait, those conditions would need to hold during the - // entire wait duration so they are not practical. - if (commitBarrier != null) - return false - - // We know that priority <= currentOwner.priority, because we're the loser. - // If the priorities match exactly (unlikely but possible) then we can't - // have both losers wait or we will get a deadlock. - if (_priority == owningRoot.txn._priority) - return false - - // Now we're in heuristic territory, waiting or rolling back are both - // reasonable choices. Waiting might reduce rollbacks, but it increases - // the number of thread sleep/wakeup transitions, each of which is - // expensive. Our heuristic is to wait only if we are barging, which - // indicates that we are having trouble making forward progress using - // just blind optimism. Also, since barging transactions prevent (some) - // conflicting writes, this choice means we minimize the chance that a - // doomed transaction blocks somebody that will be able to commit. - return _barging - } - - - //////////// pre-txn state manipulation - - def pushAlternative(block: InTxn => Any): Boolean = { - val z = _alternatives.isEmpty - _alternatives ::= block - z - } - - private def takeAlternatives(): List[InTxn => Any] = { - val z = _alternatives - _alternatives = Nil - z - } - - - //////////// high-level atomic block operations - - @throws(classOf[InterruptedException]) - protected[stm] def retry(): Nothing = { - val timeout = _currentLevel.minEnclosingRetryTimeout() - if (timeout == Long.MaxValue) - rollback(ExplicitRetryCause(None)) - - val consumed = _currentLevel.consumedRetryTotal() - if (_cumulativeBlockingNanos < timeout + consumed) - rollback(ExplicitRetryCause(Some(timeout + consumed))) - - _currentLevel.consumedRetryDelta += timeout - throw new InterruptedException - } - - @throws(classOf[InterruptedException]) - protected[stm] def retryFor(timeoutNanos: Long) { - val effectiveTimeout = _currentLevel.minEnclosingRetryTimeout() - if (effectiveTimeout < timeoutNanos) - retry() // timeout imposed by TxnExecutor is tighter than this one - - val consumed = _currentLevel.consumedRetryTotal() - if (_cumulativeBlockingNanos < timeoutNanos + consumed) - rollback(ExplicitRetryCause(Some(timeoutNanos + consumed))) - - _currentLevel.consumedRetryDelta += timeoutNanos - } - - @throws(classOf[InterruptedException]) - def atomic[Z](exec: TxnExecutor, block: InTxn => Z): Z = { - if (!_alternatives.isEmpty) - atomicWithAlternatives(exec, block) - else { - if (_currentLevel == null) - topLevelAtomicImpl(exec, block) - else - nestedAtomicImpl(exec, block) - } - } - - @throws(classOf[InterruptedException]) - def atomicOneOf[Z](exec: TxnExecutor, blocks: Seq[InTxn => Z]): Z = { - if (!_alternatives.isEmpty) - throw new IllegalStateException("atomic.oneOf can't be mixed with orAtomic") - val b = blocks.toList - atomicImpl(exec, b.head, b.tail) - } - - @throws(classOf[InterruptedException]) - def unrecorded[Z](exec: TxnExecutor, block: InTxn => Z, outerFailure: RollbackCause => Z): Z = { - if (!_alternatives.isEmpty) - throw new IllegalStateException("atomic.unrecorded can't be mixed with orAtomic") - var z: Z = null.asInstanceOf[Z] - try { - atomicImpl(exec, { implicit txn => - z = block(txn) - Txn.rollback(Txn.UnrecordedTxnCause(z)) - }, Nil) - } catch { - case RewindUnrecordedTxnError => z - case RollbackError if outerFailure != null => { - outerFailure(_currentLevel.statusAsCurrent.asInstanceOf[RolledBack].cause) - } - } - } - - def rollback(cause: RollbackCause): Nothing = { - // We need to grab the version numbers from writes and pessimistic reads - // before the status is set to rollback, because as soon as the top-level - // txn is marked rollback other threads can steal ownership. This is - // harmless if some other type of rollback occurs. - if (isExplicitRetry(cause)) - addLatestWritesAsReads(_barging) - - _currentLevel.forceRollback(cause) - throw RollbackError - } - - - //////////// per-block logic (includes reexecution loops) - - @throws(classOf[InterruptedException]) - private def awaitRetry(timeoutNanos: Long) { - assert(_slot >= 0) - val rs = takeRetrySet(_slot) - detach() - val f = _pendingFailure - if (f != null) { - _pendingFailure = null - throw f - } - // Note that awaitRetry might throw an InterruptedException that cancels - // the retry forever. - val remaining = timeoutNanos - (if (timeoutNanos == Long.MaxValue) 0 else _cumulativeBlockingNanos) - assert(remaining > 0) - _cumulativeBlockingNanos += rs.awaitRetry(remaining) - } - - private def isExplicitRetry(status: Status): Boolean = isExplicitRetry(status.asInstanceOf[RolledBack].cause) - - private def isExplicitRetry(cause: RollbackCause): Boolean = cause.isInstanceOf[ExplicitRetryCause] - - private def clearAttemptHistory() { - _subsumptionAllowed = true - _cumulativeBlockingNanos = 0L - commitBarrier = null - } - - //// nested, no alternatives - - private def nestedAtomicImpl[Z](exec: TxnExecutor, block: InTxn => Z): Z = { - if (_subsumptionAllowed && (exec == _currentLevel.executor)) - subsumedNestedAtomicImpl(block) - else - trueNestedAtomicImpl(exec, block) - } - - private def subsumedNestedAtomicImpl[Z](block: InTxn => Z): Z = { - val outermost = _subsumptionParent == null - if (outermost) - _subsumptionParent = _currentLevel - try { - try { - block(this) - } catch { - case x if x != RollbackError && !_currentLevel.executor.isControlFlow(x) => { - // partial rollback is required, but we can't do it here - _subsumptionAllowed = false - _currentLevel.forceRollback(OptimisticFailureCause('restart_to_enable_partial_rollback, Some(x))) - throw RollbackError - } - } - } finally { - if (outermost) - _subsumptionParent = null - } - } - - private def trueNestedAtomicImpl[Z](exec: TxnExecutor, block: InTxn => Z): Z = { - var prevFailures = 0 - (while (true) { - // fail back to parent if it has been rolled back - _currentLevel.requireActive() - - val level = new TxnLevelImpl(this, exec, _currentLevel, false) - try { - return nestedAttempt(prevFailures, level, block, -1) - } catch { - case RollbackError => - } - // we are only here if it is a transient rollback or an explicit retry - val cause = level.status.asInstanceOf[RolledBack].cause - if (isExplicitRetry(cause)) { - // Reads are still in access history. Retry the parent, which will - // treat the reads as its own. The cause holds the timeout, if any. - _currentLevel.forceRollback(cause) - throw RollbackError - } - prevFailures += 1 // transient rollback, retry - }).asInstanceOf[Nothing] - } - - //// top-level, no alternatives - - @throws(classOf[InterruptedException]) - private def topLevelAtomicImpl[Z](exec: TxnExecutor, block: InTxn => Z): Z = { - clearAttemptHistory() - var prevFailures = 0 - (while (true) { - var level = new TxnLevelImpl(this, exec, null, false) - try { - // successful attempt or permanent rollback either returns a Z or - // throws an exception != RollbackError - return topLevelAttempt(prevFailures, level, block) - } catch { - case RollbackError => - } - // we are only here if it is a transient rollback or an explicit retry - if (isExplicitRetry(level.status)) { - val timeout = level.minRetryTimeoutNanos - level = null // help the GC while waiting - awaitRetry(timeout) - prevFailures = 0 - } else { - prevFailures += 1 // transient rollback, retry - } - }).asInstanceOf[Nothing] - } - - //// nested or top-level, with alternatives - - @throws(classOf[InterruptedException]) - private def atomicWithAlternatives(exec: TxnExecutor, block: InTxn => Any): Nothing = { - val z = atomicImpl(exec, block, takeAlternatives()) - throw new impl.AlternativeResult(z) - } - - /** If parent level has status `RolledBack`, throws RollbackError. On - * commit, returns a Z or throws an exception other than `RollbackError`. - * On permanent rollback, throws an exception other than `RollbackError`. - * On nested explicit retry, throws `RollbackError` and sets the parent - * level's status to `RolledBack(ExplicitRetryCause(_))`. All other cases - * result in a retry within the method. - */ - @throws(classOf[InterruptedException]) - private def atomicImpl[Z](exec: TxnExecutor, block: InTxn => Z, alternatives: List[InTxn => Z]): Z = { - if (Stats.top != null) - recordAlternatives(alternatives) - - if (_currentLevel == null) - clearAttemptHistory() - - var reusedReadThreshold = -1 - var minRetryTimeout = Long.MaxValue - (while (true) { - var level: TxnLevelImpl = null - var prevFailures = 0 - while (level == null) { - // fail back to parent if it has been rolled back - if (_currentLevel != null) - _currentLevel.requireActive() - - // phantom attempts reuse reads from the previous one - val phantom = reusedReadThreshold >= 0 - level = new TxnLevelImpl(this, exec, _currentLevel, phantom) - level.minRetryTimeoutNanos = minRetryTimeout - try { - // successful attempt or permanent rollback either returns a Z or - // throws an exception != RollbackError - val b = if (phantom) { (_: InTxn) => atomicImpl(exec, alternatives.head, alternatives.tail) } else block - if (_currentLevel != null) - return nestedAttempt(prevFailures, level, b, reusedReadThreshold) - else - return topLevelAttempt(prevFailures, level, b) - } catch { - case RollbackError => - } - // we are only here if it is a transient rollback or an explicit retry - if (!isExplicitRetry(level.status)) { - // transient rollback, retry (not as a phantom) - prevFailures += 1 - reusedReadThreshold = -1 - level = null - } - // else explicit retry, exit the loop - } - - // The attempt ended in an explicit retry. If there are alternatives - // then we run a phantom attempt that reuses the read from the last real - // attempt on the block. Phantom attempts can also end in explicit retry - // (if all of the alternatives triggered retry), in which case we treat - // them the same as a regular block with no alternatives. - val phantom = reusedReadThreshold >= 0 - minRetryTimeout = level.minRetryTimeoutNanos - if (!phantom && !alternatives.isEmpty) { - // rerun a phantom - reusedReadThreshold = level.prevReadCount - } else { - level = null - - // no more alternatives, reads are still in access history - if (_currentLevel != null) { - // retry the parent, which will treat the reads as its own - _currentLevel.forceRollback(ExplicitRetryCause(None)) - throw RollbackError - } - - // top-level retry after waiting for something to change - awaitRetry(minRetryTimeout) - minRetryTimeout = Long.MaxValue - - // rerun the real block, now that the await has completed - reusedReadThreshold = -1 - } - }).asInstanceOf[Nothing] - } - - private def recordAlternatives(alternatives: List[_]) { - (if (_currentLevel == null) Stats.top else Stats.nested).alternatives += alternatives.size - } - - //////////// per-attempt logic - - /** On commit, either returns a Z or throws the control-flow exception from - * the committed attempted; on rollback, throws an exception on a permanent - * rollback or `RollbackError` on a transient rollback. - */ - private def nestedAttempt[Z](prevFailures: Int, level: TxnLevelImpl, block: InTxn => Z, reusedReadThreshold: Int): Z = { - nestedBegin(level, reusedReadThreshold) - checkBarging(prevFailures) - try { - runBlock(block) - } finally { - rethrowFromStatus(nestedComplete()) - } - } - - @throws(classOf[InterruptedException]) - private def topLevelAttempt[Z](prevFailures: Int, level: TxnLevelImpl, block: InTxn => Z): Z = { - topLevelBegin(level) - checkBarging(prevFailures) - try { - runBlock(block) - } finally { - rethrowFromStatus(topLevelComplete()) - } - } - - private def checkBarging(prevFailures: Int) { - // once we start barging we will use the original read version - if (prevFailures == 0) - _bargeVersion = _readVersion - - if (prevFailures == BargeAllThreshold) - _bargeVersion = 0L - - _barging = prevFailures >= BargeRecentThreshold - } - - private def nestedBegin(child: TxnLevelImpl, reusedReadThreshold: Int) { - // link to child races with remote rollback. pushIfActive detects the race - // and returns false - if (!_currentLevel.pushIfActive(child)) { - child.forceRollback(this.status.asInstanceOf[RolledBack].cause) - throw RollbackError - } - - // successfully begun - _currentLevel = child - checkpointCallbacks() - checkpointAccessHistory(reusedReadThreshold) - } - - @throws(classOf[InterruptedException]) - private def topLevelBegin(child: TxnLevelImpl) { - if (_slot < 0) { - _priority = skel.SimpleRandom.nextInt() - _slot = slotManager.assign(child, ~_slot) - _readVersion = freshReadVersion - } - // else we must be a top-level alternative - _currentLevel = child - } - - private def runBlock[Z](block: InTxn => Z): Z = { - try { - block(this) - } catch { - case x if x != RollbackError && !_currentLevel.executor.isControlFlow(x) => { - _currentLevel.forceRollback(UncaughtExceptionCause(x)) - null.asInstanceOf[Z] - } - } - } - - private def rethrowFromStatus(status: Status) { - status match { - case rb: RolledBack => { - rb.cause match { - case UncaughtExceptionCause(x) => throw x - case _: UnrecordedTxnCause[_] => throw RewindUnrecordedTxnError - case _: TransientRollbackCause => throw RollbackError - } - } - case _ => - } - } - - //////////// completion - - private def nestedComplete(): Status = { - val child = _currentLevel - if (child.attemptMerge()) { - // child was successfully merged - mergeAccessHistory() - _currentLevel = child.parUndo - Committed - } else { - val s = this.status - - // callbacks must be last, because they might throw an exception - rollbackAccessHistory(_slot, s.asInstanceOf[RolledBack].cause) - val handlers = rollbackCallbacks() - _currentLevel = child.parUndo - if (handlers != null) - fireAfterCompletionAndThrow(handlers, child.executor, s, null) - s - } - } - - //// top-level completion - - private def topLevelComplete(): Status = { - if (attemptTopLevelComplete()) { - finishTopLevelCommit() - Committed - } else { - val s = this.status - val c = s.asInstanceOf[RolledBack].cause - if (isExplicitRetry(c)) - finishTopLevelRetry(s, c) - else - finishTopLevelRollback(s, c) - s - } - } - - private def finishTopLevelCommit() { - resetAccessHistory() - val handlers = resetCallbacks() - val exec = _currentLevel.executor - detach() - - val f = _pendingFailure - _pendingFailure = null - fireAfterCompletionAndThrow(handlers, exec, Committed, f) - } - - private def finishTopLevelRollback(s: Status, c: RollbackCause) { - rollbackAccessHistory(_slot, c) - val handlers = rollbackCallbacks() - val exec = _currentLevel.executor - detach() - - val f = _pendingFailure - _pendingFailure = null - fireAfterCompletionAndThrow(handlers, exec, s, f) - } - - private def finishTopLevelRetry(s: Status, c: RollbackCause) { - rollbackAccessHistory(_slot, c) - val handlers = rollbackCallbacks() - - // don't detach, but we do need to give up the current level - val exec = _currentLevel.executor - _currentLevel = null - assert(writeCount == 0) - - if (handlers != null) - _pendingFailure = fireAfterCompletion(handlers, exec, s, _pendingFailure) - - if (_pendingFailure != null) { - // scuttle the retry - takeRetrySet(_slot) - val f = _pendingFailure - _pendingFailure = null - throw f - } - } - - private def detach() { - //assert(_slot >= 0 && readCount == 0 && bargeCount == 0 && writeCount == 0) - slotManager.release(_slot) - _slot = ~_slot - _currentLevel = null - } - - private def attemptTopLevelComplete(): Boolean = { - val root = _currentLevel - - fireBeforeCommitCallbacks() - - // Read-only transactions are easy to commit, because all of the reads - // are already guaranteed to be consistent. We still have to release the - // barging locks, though. - if (writeCount == 0 && !writeResourcesPresent) { - if (bargeCount > 0) - releaseBargeLocks() - return root.tryActiveToCommitted() - } - - if (!root.tryActiveToPreparing() || !acquireLocks()) - return false - - // this is our linearization point - val cv = freshCommitVersion(_readVersion) - - // if the reads are still valid, then they were valid at the linearization - // point - if (!revalidateImpl()) - return false - - fireWhilePreparingCallbacks() - - if (externalDecider != null) { - // external decider doesn't have to content with cancel by other threads - if (!root.tryPreparingToPrepared() || !consultExternalDecider()) - return false - - root.setCommitting() - } else { - // attempt to decide commit - if (!root.tryPreparingToCommitting()) - return false - } - - _pendingFailure = fireWhileCommittingCallbacks(_currentLevel.executor) - commitWrites(cv) - root.setCommitted() - - return true - } - - private def releaseBargeLocks() { - var i = bargeCount - 1 - while (i >= 0) { - rollbackHandle(bargeHandle(i), _slot) - i -= 1 - } - } - - private def acquireLocks(): Boolean = { - var i = writeCount - 1 - while (i >= 0) { - // acquireLock is inlined to reduce the call depth from TxnExecutor.apply - val handle = getWriteHandle(i) - var m = 0L - do { - m = handle.meta - if (owner(m) != _slot && m != txnLocalMeta) - return false - // we have to use CAS to guard against remote steal - } while (!changing(m) && !handle.metaCAS(m, withChanging(m))) - i -= 1 - } - return true - } - - private def consultExternalDecider(): Boolean = { - try { - if (!externalDecider.shouldCommit(this)) - _currentLevel.forceRollback(OptimisticFailureCause('external_decision, None)) - } catch { - case x: Throwable => _currentLevel.forceRollback(UncaughtExceptionCause(x)) - } - this.status eq Prepared - } - - private def commitWrites(cv: Long) { - var wakeups = 0L - var i = writeCount - 1 - while (i >= 0) { - val handle = getWriteHandle(i).asInstanceOf[Handle[Any]] - - val m = handle.meta - if (pendingWakeups(m)) - wakeups |= wakeupManager.prepareToTrigger(handle) - - //assert(owner(m) == _slot) - - val v = getWriteSpecValue[Any](i) - - // release the lock, clear the PW bit, and update the version, but only - // if this was the entry that actually acquired ownership - if (wasWriteFreshOwner(i)) { - // putting the data store in both sides allows the volatile writes to - // be coalesced - handle.data = v - handle.meta = withCommit(m, cv) - } else { - handle.data = v - } - - // because we release when we find the original owner, it is important - // that we traverse in reverse order. There are no duplicates - i -= 1 - } - - // We still have ownership (but not exclusive) for pessimistic reads, and - // we still have exclusive ownership of pessimistic reads that turned into - // writes (or that share metadata with writes). We rollback the vlock for - // the former and commit the vlock for the later. - i = bargeCount - 1 - while (i >= 0) { - val handle = bargeHandle(i) - val m = handle.meta - - if (changing(m)) { - // a handle sharing this base and metaOffset must also be present in - // the write buffer, so we should bump the version number - handle.meta = withCommit(m, cv) - } else { - // this was only a pessimistic read, no need to bump the version - rollbackHandle(handle, _slot, m) - } - - i -= 1 - } - - // unblock anybody waiting on a value change - if (wakeups != 0L) - wakeupManager.trigger(wakeups) - } - - //////////// validation - - /** Returns true if valid. */ - private def revalidateImpl(): Boolean = { - // we check the oldest reads first, so that we roll back all intervening - // invalid nesting levels - var i = 0 - while (i < readCount) { - val h = readHandle(i) - val problem = checkRead(h, readVersion(i)) - if (problem != null) { - readLocate(i).asInstanceOf[NestingLevel].requestRollback(OptimisticFailureCause(problem, Some(h))) - return false - } - i += 1 - } - fireWhileValidating() - - !this.status.isInstanceOf[RolledBack] - } - - /** Returns the name of the problem on failure, null on success. */ - private def checkRead(handle: Handle[_], ver: CCSTM.Version): Symbol = { - (while (true) { - val m1 = handle.meta - if (!changing(m1) || owner(m1) == _slot) { - if (version(m1) != ver) - return 'stale_read - // okay - return null - } else if (owner(m1) == nonTxnSlot) { - // non-txn updates don't set changing unless they will install a new - // value, so we are the only party that can yield - return 'read_vs_nontxn_write - } else { - // Either this txn or the owning txn must roll back. We choose to - // give precedence to the owning txn, as it is the writer and is - // trying to commit. There's a bit of trickiness since o may not be - // the owning transaction, it may be a new txn that reused the same - // slot. If the actual owning txn committed then the version - // number will have changed, which we will detect on the next pass - // (because we aren't incrementing i, so we will revisit this - // entry). If it rolled back then we don't have to roll back, so - // looking at o to make the decision doesn't affect correctness - // (although it might result in an unnecessary rollback). If the - // owner slot is the same but the changing bit is not set (or if - // the owner txn is null) then we are definitely observing a reused - // slot and we can avoid the spurious rollback. - val o = slotManager.lookup(owner(m1)) - if (null != o) { - val s = o.status - val m2 = handle.meta - if (changing(m2) && owner(m2) == owner(m1)) { - if (!s.isInstanceOf[RolledBack]) - return 'read_vs_pending_commit - - stealHandle(handle, m2, o) - } - } - } - // try again - }).asInstanceOf[Nothing] - } - - - //////////// implementations of InTnRefOps abstract operations - - override def requireActive() { - val cur = _currentLevel - if (cur == null) - throw new IllegalStateException("no active transaction") - cur.requireActive() - } - - protected def isNewerThanReadVersion(version: Version): Boolean = version > _readVersion - - /** On return, the read version will have been the global version at some - * point during the call, the read version will be >= minReadVersion, and - * all reads will have been validated against the new read version. Throws - * `RollbackError` if invalid. - */ - protected def revalidate(minReadVersion: Version) { - _readVersion = freshReadVersion(minReadVersion) - if (!revalidateImpl()) - throw RollbackError - } - - protected def forceRollback(cause: RollbackCause) { - _currentLevel.forceRollback(cause) - } - - @throws(classOf[InterruptedException]) - protected def weakAwaitUnowned(handle: Handle[_], m0: Meta) { - CCSTM.weakAwaitUnowned(handle, m0, _currentLevel) - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/ccstm/InTxnRefOps.scala b/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/ccstm/InTxnRefOps.scala deleted file mode 100644 index 733eb611..00000000 --- a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/ccstm/InTxnRefOps.scala +++ /dev/null @@ -1,430 +0,0 @@ -/* scala-stm - (c) 2009-2012, Stanford University, PPL */ - -package scala.concurrent.stm -package ccstm - -import skel._ - - -private[ccstm] abstract class InTxnRefOps extends AccessHistory with AbstractInTxn { - import CCSTM._ - import Txn._ - - //////// abstract txn state - - protected def _barging: Boolean - protected def _bargeVersion: Version - protected def _slot: Slot - - //////// abstract methods - - protected def isNewerThanReadVersion(version: Version): Boolean - - protected def revalidate(minNewReadVersion: Version) - - protected def forceRollback(cause: RollbackCause) - - protected def weakAwaitUnowned(handle: Handle[_], m0: Meta) - - //////// lock management - similar to NonTxn but we also check for remote rollback - - /** Calls revalidate(version) if version > _readVersion. */ - private def revalidateIfRequired(version: Version) { - if (isNewerThanReadVersion(version)) - revalidate(version) - } - - /** Returns the pre-acquisition metadata. */ - @throws(classOf[InterruptedException]) - private def acquireOwnership(handle: Handle[_]): Meta = { - var m = handle.meta - if (owner(m) == _slot) - return m - (while (true) { - if (owner(m) != unownedSlot) - weakAwaitUnowned(handle, m) - else if (handle.metaCAS(m, withOwner(m, _slot))) - return m - m = handle.meta - }).asInstanceOf[Nothing] - } - - private def tryAcquireOwnership(handle: Handle[_], m0: Meta): Boolean = { - owner(m0) == unownedSlot && handle.metaCAS(m0, withOwner(m0, _slot)) - } - - //////// barrier implementations - - @throws(classOf[InterruptedException]) - def get[T](handle: Handle[T]): T = { - requireActive() - - var m1 = handle.meta - if (owner(m1) == _slot) { - // Self-owned. This particular base+offset might not be in the write - // buffer, but it's definitely not in anybody else's. - return stableGet(handle) - } - - if (readShouldBarge(m1)) - return bargingRead(handle) - - var m0 = 0L - var value: T = null.asInstanceOf[T] - do { - m0 = m1 - while (changing(m0)) { - weakAwaitUnowned(handle, m0) - m0 = handle.meta - } - revalidateIfRequired(version(m0)) - value = handle.data - m1 = handle.meta - } while (changingAndVersion(m0) != changingAndVersion(m1)) - - // Stable read. The second read of handle.meta is required for - // opacity, and it also enables the read-only commit optimization. - recordRead(handle, version(m1)) - return value - } - - private def readShouldBarge(meta: Meta): Boolean = { - _barging && version(meta) >= _bargeVersion - } - - @throws(classOf[InterruptedException]) - private def bargingRead[T](handle: Handle[T]): T = { - val mPrev = acquireOwnership(handle) - recordBarge(handle) - revalidateIfRequired(version(mPrev)) - return handle.data - } - - @throws(classOf[InterruptedException]) - def getWith[T,Z](handle: Handle[T], f: T => Z): Z = { - if (_barging && version(handle.meta) >= _bargeVersion) - return f(get(handle)) - - requireActive() - val u = unrecordedRead(handle) - val result = f(u.value) - if (!u.recorded) { - val callback = new Function[NestingLevel, Unit] { - var _latestRead = u - - def apply(level: NestingLevel) { - if (!isValid) - level.requestRollback(OptimisticFailureCause('invalid_getWith, Some(handle))) - } - - private def isValid: Boolean = { - if (_latestRead == null || _latestRead.stillValid) - return true - - val m1 = handle.meta - if (owner(m1) == _slot) { - // We know that our original read did not come from the write - // buffer, because !u.recorded. That means that to redo this - // read we should go to handle.data, which has the most recent - // value from which we should read. - _latestRead = null - return (result == f(handle.data)) - } - - // reread, and see if that changes the result - _latestRead = unrecordedRead(handle) - - return (result == f(_latestRead.value)) - } - } - - // It is safe to skip calling callback.valid() here, because we - // have made no calls into the txn that might have resulted in it - // moving its virtual snapshot forward. This means that the - // unrecorded read that initialized u is consistent with all of the - // reads performed so far. - whileValidating(callback) - } - - return result - } - - @throws(classOf[InterruptedException]) - def relaxedGet[T](handle: Handle[T], equiv: (T, T) => Boolean): T = { - if (_barging && version(handle.meta) >= _bargeVersion) - return get(handle) - - requireActive() - val u = unrecordedRead(handle) - val snapshot = u.value - if (!u.recorded) { - val callback = new Function[NestingLevel, Unit] { - var _latestRead = u - - def apply(level: NestingLevel) { - if (!isValid) - level.requestRollback(OptimisticFailureCause('invalid_relaxed_get, Some(handle))) - } - - private def isValid: Boolean = { - if (_latestRead == null || _latestRead.stillValid) - return true - - val m1 = handle.meta - if (owner(m1) == _slot) { - // We know that our original read did not come from the write - // buffer, because !u.recorded. That means that to redo this - // read we should go to handle.data, which has the most recent - // value from which we should read. - _latestRead = null - return equiv(snapshot, handle.data) - } - - // reread, and see if that changes the result - _latestRead = unrecordedRead(handle) - - return equiv(snapshot, _latestRead.value) - } - } - - // It is safe to skip calling callback.valid() here, because we - // have made no calls into the txn that might have resulted in it - // moving its virtual snapshot forward. This means that the - // unrecorded read that initialized u is consistent with all of the - // reads performed so far. - whileValidating(callback) - } - - return snapshot - } - - @throws(classOf[InterruptedException]) - def unrecordedRead[T](handle: Handle[T]): UnrecordedRead[T] = { - // unrecorded read might be needed to update validation state of getWith or - // relaxedGet during the Preparing stage - requireNotDecided() - - var m1 = handle.meta - var v: T = null.asInstanceOf[T] - val rec = (if (owner(m1) == _slot) { - v = stableGet(handle) - true - } else { - var m0 = 0L - do { - m0 = m1 - while (changing(m0)) { - if (status != Active) { - // can't wait - forceRollback(OptimisticFailureCause('late_invalid_unrecordedRead, Some(handle))) - throw RollbackError - } - weakAwaitUnowned(handle, m0) - m0 = handle.meta - } - if (isNewerThanReadVersion(version(m0))) { - if (status != Active) { - // can't wait - forceRollback(OptimisticFailureCause('late_invalid_unrecordedRead, Some(handle))) - throw RollbackError - } - revalidate(version(m0)) - } - v = handle.data - m1 = handle.meta - } while (changingAndVersion(m0) != changingAndVersion(m1)) - false - }) - - new UnrecordedRead[T] { - def value: T = v - def stillValid = { - val m = handle.meta - version(m) == version(m1) && (!changing(m) || owner(m) == _slot) - } - def recorded = rec - } - } - - private def freshOwner(mPrev: Meta) = owner(mPrev) == unownedSlot - - @throws(classOf[InterruptedException]) - def set[T](handle: Handle[T], v: T) { - requireActive() - val mPrev = acquireOwnership(handle) - val f = freshOwner(mPrev) - put(handle, f, v) - - // This might not be a blind write, because meta might be shared with other - // values that are subsequently read by the transaction. We don't need to - // record a read set entry, however, because nobody can modify it after we - // grab ownership. This means it suffices to check against _readVersion. - // We must put something in the buffer before calling revalidate in case we - // roll back, so that the ownership gets released. - // - // If not f, then this was already self-owned. This particular base+offset - // might not be in the write buffer, but it's definitely not in anybody - // else's. - if (f) - revalidateIfRequired(version(mPrev)) - } - - @throws(classOf[InterruptedException]) - def swap[T](handle: Handle[T], v: T): T = { - requireActive() - val mPrev = acquireOwnership(handle) - val f = freshOwner(mPrev) - val v0 = swap(handle, f, v) - if (f) - revalidateIfRequired(version(mPrev)) - v0 - } - - def trySet[T](handle: Handle[T], v: T): Boolean = { - requireActive() - - val m0 = handle.meta - if (owner(m0) == _slot) { - put(handle, false, v) - return true - } - - if (!tryAcquireOwnership(handle, m0)) - return false - put(handle, true, v) - revalidateIfRequired(version(m0)) - return true - } - - @throws(classOf[InterruptedException]) - def compareAndSet[T](handle: Handle[T], before: T, after: T): Boolean = { - transformIfDefined(handle, new PartialFunction[T,T] { - def isDefinedAt(v: T): Boolean = before == v - def apply(v: T): T = after - }) - } - - @throws(classOf[InterruptedException]) - def compareAndSetIdentity[T, R <: T with AnyRef](handle: Handle[T], before: R, after: T): Boolean = { - // make a heuristic guess based on a racy read of the value - if (before eq handle.data.asInstanceOf[AnyRef]) - acquiringCASI(handle, before, after) - else - unrecordedCASI(handle, before, after) - } - - @throws(classOf[InterruptedException]) - private def acquiringCASI[T, R <: T with AnyRef](handle: Handle[T], before: R, after: T): Boolean = { - requireActive() - val mPrev = acquireOwnership(handle) - val f = freshOwner(mPrev) - val z = compareAndSetIdentity(handle, f, before, after) - if (f) - revalidateIfRequired(version(mPrev)) - z - } - - @throws(classOf[InterruptedException]) - private def unrecordedCASI[T, R <: T with AnyRef](handle: Handle[T], before: R, after: T): Boolean = { - transformIfDefined(handle, new PartialFunction[T,T] { - def isDefinedAt(v: T): Boolean = (before eq v.asInstanceOf[AnyRef]) - def apply(v: T): T = after - }) - } - - @throws(classOf[InterruptedException]) - def getAndTransform[T](handle: Handle[T], func: T => T): T = { - requireActive() - val mPrev = acquireOwnership(handle) - val f = freshOwner(mPrev) - val v0 = getAndTransform(handle, f, func) - if (f) - revalidateIfRequired(version(mPrev)) - v0 - } - - @throws(classOf[InterruptedException]) - def transformAndGet[T](handle: Handle[T], func: T => T): T = { - requireActive() - val mPrev = acquireOwnership(handle) - val f = freshOwner(mPrev) - val v1 = transformAndGet(handle, f, func) - if (f) - revalidateIfRequired(version(mPrev)) - v1 - } - - @throws(classOf[InterruptedException]) - def transformAndExtract[T,V](handle: Handle[T], func: T => (T,V)): V = { - requireActive() - val mPrev = acquireOwnership(handle) - val f = freshOwner(mPrev) - val v1 = transformAndExtract(handle, f, func) - if (f) - revalidateIfRequired(version(mPrev)) - v1 - } - - @throws(classOf[InterruptedException]) - def transformIfDefined[T](handle: Handle[T], pf: PartialFunction[T,T]): Boolean = { - requireActive() - val u = unrecordedRead(handle) - if (!pf.isDefinedAt(u.value)) { - // make sure it stays undefined - if (!u.recorded) { - val callback = new Function[NestingLevel, Unit] { - var _latestRead = u - - def apply(level: NestingLevel) { - if (!isValid) - level.requestRollback(OptimisticFailureCause('invalid_getWith, Some(handle))) - } - - private def isValid: Boolean = { - if (!_latestRead.stillValid) { - // if defined after reread then return false==invalid - _latestRead = unrecordedRead(handle) - !pf.isDefinedAt(_latestRead.value) - } else { - true - } - } - } - whileValidating(callback) - } - false - } else { - val v = get(handle) - if (!u.stillValid && !pf.isDefinedAt(v)) { - // value changed after unrecordedRead - false - } else { - // still defined, do the actual getAndTransform - set(handle, pf(v)) - true - } - } - } - - @throws(classOf[InterruptedException]) - def getAndAdd(handle: Handle[Int], delta: Int): Int = { - requireActive() - val mPrev = acquireOwnership(handle) - val f = freshOwner(mPrev) - val v0 = getAndAdd(handle, f, delta) - if (f) - revalidateIfRequired(version(mPrev)) - v0 - } - - //////////// TxnLocal stuff - - // We store transactional local values in the write buffer by pretending - // that they are proper handles, but their data and metadata aren't actually - // backed by anything. - - def txnLocalFind(local: TxnLocalImpl[_]): Int = findWrite(local) - def txnLocalGet[T](index: Int): T = getWriteSpecValue[T](index) - def txnLocalInsert[T](local: TxnLocalImpl[T], v: T) { writeAppend(local, false, v) } - def txnLocalUpdate[T](index: Int, v: T) { writeUpdate(index, v) } -} diff --git a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/ccstm/NonTxn.scala b/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/ccstm/NonTxn.scala deleted file mode 100644 index ff5c41c3..00000000 --- a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/ccstm/NonTxn.scala +++ /dev/null @@ -1,594 +0,0 @@ -/* scala-stm - (c) 2009-2012, Stanford University, PPL */ - -package scala.concurrent.stm -package ccstm - -import annotation.tailrec - - -/** The object that contains the code for non-transactional read and write - * barriers. - * - * @author Nathan Bronson - */ -private[ccstm] object NonTxn { - import CCSTM._ - - //////////////// lock waiting - - @throws(classOf[InterruptedException]) - private def weakAwaitUnowned(handle: Handle[_], m0: Meta) { - CCSTM.weakAwaitUnowned(handle, m0, null) - } - - //////////////// value waiting - - @throws(classOf[InterruptedException]) - private def weakAwaitNewVersion(handle: Handle[_], m0: Meta) { - // spin a bit - var m = 0L - var spins = 0 - do { - val m = handle.meta - if (version(m) != version(m0)) - return - - spins += 1 - if (spins > SpinCount) - Thread.`yield` - } while (spins < SpinCount + YieldCount) - - weakNoSpinAwaitNewVersion(handle, m) - } - - @throws(classOf[InterruptedException]) - private def weakNoSpinAwaitNewVersion(handle: Handle[_], m0: Meta) { - val event = wakeupManager.subscribe - event.addSource(handle) - do { - val m = handle.meta - if (version(m) != version(m0) || changing(m)) { - // observed new version, or likely new version (after unlock) - return - } - - // not changing, so okay to set PW bit - if (pendingWakeups(m) || handle.metaCAS(m, withPendingWakeups(m))) { - // after the block, things will have changed with reasonably high - // likelihood (spurious wakeups are okay) - event.await - return - } - } while (!event.triggered) - } - - //////////////// value waiting with timeout - - @throws(classOf[InterruptedException]) - private def weakAwaitNewVersion(handle: Handle[_], m0: Meta, nanoDeadline: Long): Boolean = { - // spin a bit - var m = 0L - var spins = 0 - do { - val m = handle.meta - if (version(m) != version(m0)) - return true - - spins += 1 - if (spins > SpinCount) { - if (System.nanoTime >= nanoDeadline) - return false - Thread.`yield` - } - } while (spins < SpinCount + YieldCount) - - if (changing(m)) { - // ignore deadline for this, it should be fast - weakAwaitUnowned(handle, m) - return true - } else { - return weakNoSpinAwaitNewVersion(handle, m, nanoDeadline) - } - } - - @throws(classOf[InterruptedException]) - private def weakNoSpinAwaitNewVersion(handle: Handle[_], m0: Meta, nanoDeadline: Long): Boolean = { - val event = wakeupManager.subscribe - event.addSource(handle) - do { - val m = handle.meta - if (version(m) != version(m0) || changing(m)) { - // observed new version, or likely new version (after unlock) - return true - } - - // not changing, so okay to set PW bit - if (pendingWakeups(m) || handle.metaCAS(m, withPendingWakeups(m))) { - // after the block, things will have changed with reasonably high - // likelihood (spurious wakeups are okay) - return event.tryAwaitUntil(nanoDeadline) - } - } while (!event.triggered) - return true - } - - //////////////// lock acquisition - - @throws(classOf[InterruptedException]) - private def acquireLock(handle: Handle[_], exclusive: Boolean): Meta = { - var m0 = 0L - var m1 = 0L - do { - m0 = handle.meta - while (owner(m0) != unownedSlot) { - weakAwaitUnowned(handle, m0) - m0 = handle.meta - } - val mOwned = withOwner(m0, nonTxnSlot) - m1 = if (exclusive) withChanging(mOwned) else mOwned - } while (!handle.metaCAS(m0, m1)) - m1 - } - - /** Returns 0L on failure. */ - private def tryAcquireExclusiveLock(handle: Handle[_]): Meta = { - val m0 = handle.meta - if (owner(m0) != unownedSlot) return 0L - - val m1 = withChanging(withOwner(m0, nonTxnSlot)) - - if (!handle.metaCAS(m0, m1)) return 0L - - return m1 - } - - private def upgradeLock(handle: Handle[_], m0: Meta): Meta = { - var before = m0 - if (!handle.metaCAS(before, withChanging(before))) { - // must have been a concurrent set of pendingWakeups - before = withPendingWakeups(before) - handle.meta = withChanging(before) - } - withChanging(before) - } - - private def commitUpdate[T](handle: Handle[T], m0: Meta, newData: T) { - val newVersion = CCSTM.nonTxnWriteVersion(version(m0)) - handle.data = newData - releaseLock(handle, m0, newVersion) - } - - private def discardLock(handle: Handle[_], m0: Meta) { - releaseLock(handle, m0, version(m0)) - } - - private def releaseLock(handle: Handle[_], m0: Meta, newVersion: Version) { - handle.meta = withCommit(m0, newVersion) - - if (pendingWakeups(m0)) - triggerWakeups(handle) - } - - private def triggerWakeups(handle: Handle[_]) { - wakeupManager.trigger(wakeupManager.prepareToTrigger(handle)) - } - - //////////////// public interface - - @throws(classOf[InterruptedException]) - def get[T](handle: Handle[T]): T = { - var tries = 0 - var m0 = 0L - while (tries < 100) { - m0 = handle.meta - if (changing(m0)) { - weakAwaitUnowned(handle, m0) - } else { - val v = handle.data - val m1 = handle.meta - if (changingAndVersion(m0) == changingAndVersion(m1)) { - return v - } - } - tries += 1 - } - return lockedGet(handle) - } - - @throws(classOf[InterruptedException]) - private def lockedGet[T](handle: Handle[T]): T = { - val m0 = acquireLock(handle, false) - val z = handle.data - discardLock(handle, m0) - z - } - - @throws(classOf[InterruptedException]) - def await[T](handle: Handle[T], pred: T => Boolean) { - while (true) { - val m0 = handle.meta - if (changing(m0)) { - weakAwaitUnowned(handle, m0) - } else { - val v = handle.data - val m1 = handle.meta - if (changingAndVersion(m0) == changingAndVersion(m1)) { - // stable read of v - if (pred(v)) { - // success! - return - } - - // wait for a new version - weakAwaitNewVersion(handle, m1) - } - } - } - } - - def tryAwait[T](handle: Handle[T], pred: T => Boolean, timeoutNanos: Long): Boolean = { - var begin = 0L - (while (true) { - val m0 = handle.meta - if (changing(m0)) { - if (begin == 0L) - begin = System.nanoTime - weakAwaitUnowned(handle, m0) - } else { - val v = handle.data - val m1 = handle.meta - if (changingAndVersion(m0) == changingAndVersion(m1)) { - // stable read of v - if (pred(v)) - return true - - // no need for base time with zero timeout - if (timeoutNanos <= 0) - return false - - // wait for a new version - if (begin == 0L) - begin = System.nanoTime - if (!weakAwaitNewVersion(handle, m1, begin + timeoutNanos)) - return false - } - } - }).asInstanceOf[Nothing] - } - - @throws(classOf[InterruptedException]) - def set[T](handle: Handle[T], v: T) { - val m0 = acquireLock(handle, true) - commitUpdate(handle, m0, v) - } - - @throws(classOf[InterruptedException]) - def swap[T](handle: Handle[T], v: T): T = { - val m0 = acquireLock(handle, true) - val z = handle.data - commitUpdate(handle, m0, v) - z - } - - def trySet[T](handle: Handle[T], v: T): Boolean = { - val m0 = tryAcquireExclusiveLock(handle) - if (m0 == 0L) { - false - } else { - commitUpdate(handle, m0, v) - true - } - } - - @throws(classOf[InterruptedException]) - def compareAndSet[T](handle: Handle[T], before: T, after: T): Boolean = { - // Try to acquire ownership. If we can get it easily then we hold the lock - // while evaluating before == handle.data, otherwise we try to perform an - // invisible read to determine if the CAS will succeed, only waiting for - // the lock if the CAS might go ahead. - val m0 = handle.meta - if (owner(m0) != unownedSlot) { - return invisibleCAS(handle, before, after) - } - val m1 = withOwner(m0, nonTxnSlot) - if (!handle.metaCAS(m0, m1)) { - return invisibleCAS(handle, before, after) - } - - var success = false - try { - if (before == handle.data) { - success = true - val m2 = upgradeLock(handle, m1) - commitUpdate(handle, m2, after) - } - success - } finally { - if (!success) - discardLock(handle, m1) - } - } - - @throws(classOf[InterruptedException]) - private def invisibleCAS[T](handle: Handle[T], before: T, after: T): Boolean = { - // this is the code from get, inlined so that we have access to the version - // number as well with no boxing - var m0 = 0L - var m1 = 0L - var v: T = null.asInstanceOf[T] - do { - m0 = handle.meta - while (changing(m0)) { - weakAwaitUnowned(handle, m0) - m0 = handle.meta - } - v = handle.data - m1 = handle.meta - } while (changingAndVersion(m0) != changingAndVersion(m1)) - - // invisible failure? - if (!(before == v)) return false - - // don't go directly to changing, because we can't run user code - // (before.equals) there - val m2 = acquireLock(handle, false) - var success = false - try { - if (version(m2) == version(m1) || before == handle.data) { - success = true - val m3 = upgradeLock(handle, m2) - commitUpdate(handle, m3, after) - } - success - } finally { - if (!success) - discardLock(handle, m2) - } - } - - @throws(classOf[InterruptedException]) - def compareAndSetIdentity[T, R <: AnyRef with T](handle: Handle[T], before: R, after: T): Boolean = { - // try to acquire exclusive ownership - val m0 = handle.meta - if (owner(m0) != unownedSlot) { - return invisibleCASI(handle, before, after) - } - val m1 = withChanging(withOwner(m0, nonTxnSlot)) - if (!handle.metaCAS(m0, m1)) { - return invisibleCASI(handle, before, after) - } - - if (before eq handle.data.asInstanceOf[AnyRef]) { - commitUpdate(handle, m1, after) - true - } else { - discardLock(handle, m1) - false - } - } - - @throws(classOf[InterruptedException]) - private def invisibleCASI[T, R <: T with AnyRef](handle: Handle[T], before: R, after: T): Boolean = { - if (before eq get(handle).asInstanceOf[AnyRef]) { - // CASI is different than CAS, because we don't have to invoke user code to - // perform the comparison - val m0 = acquireLock(handle, true) - if (before eq handle.data.asInstanceOf[AnyRef]) { - commitUpdate(handle, m0, after) - true - } else { - discardLock(handle, m0) - false - } - } else { - // invisible failure - false - } - } - - @throws(classOf[InterruptedException]) - def getAndTransform[T](handle: Handle[T], f: T => T): T = { - getAndTransformImpl(handle, f, acquireLock(handle, false)) - } - - private def getAndTransformImpl[T](handle: Handle[T], f: T => T, m0: Meta): T = { - val v0 = handle.data - val repl = try { f(v0) } catch { case x: Throwable => discardLock(handle, m0) ; throw x } - val m1 = upgradeLock(handle, m0) - commitUpdate(handle, m1, repl) - v0 - } - - @throws(classOf[InterruptedException]) - def transformAndGet[T](handle: Handle[T], f: T => T): T = { - transformAndGetImpl(handle, f, acquireLock(handle, false)) - } - - private def transformAndGetImpl[T](handle: Handle[T], f: T => T, m0: Meta): T = { - val repl = try { f(handle.data) } catch { case x: Throwable => discardLock(handle, m0) ; throw x } - val m1 = upgradeLock(handle, m0) - commitUpdate(handle, m1, repl) - repl - } - - @throws(classOf[InterruptedException]) - def transformAndExtract[T,V](handle: Handle[T], f: T => (T,V)): V = { - val m0 = acquireLock(handle, false) - val pair = try { f(handle.data) } catch { case x: Throwable => discardLock(handle, m0) ; throw x } - val m1 = upgradeLock(handle, m0) - commitUpdate(handle, m1, pair._1) - pair._2 - } - - @throws(classOf[InterruptedException]) - def transformIfDefined[T](handle: Handle[T], pf: PartialFunction[T,T]): Boolean = { - if (pf.isDefinedAt(get(handle))) { - val m0 = acquireLock(handle, false) - val v = handle.data - if (try { pf.isDefinedAt(v) } catch { case x: Throwable => discardLock(handle, m0) ; throw x }) { - val repl = try { pf(v) } catch { case x: Throwable => discardLock(handle, m0) ; throw x } - val m1 = upgradeLock(handle, m0) - commitUpdate(handle, m1, repl) - true - } else { - discardLock(handle, m0) - false - } - } else { - // invisible failure - false - } - } - - //////////////// multi-handle ops - - @throws(classOf[InterruptedException]) - def transform2[A, B, Z](handleA: Handle[A], handleB: Handle[B], f: (A, B) => (A, B, Z)): Z = { - var mA0: Long = 0L - var mB0: Long = 0L - var tries = 0 - do { - mA0 = acquireLock(handleA, true) - mB0 = tryAcquireExclusiveLock(handleB) - if (mB0 == 0) { - // tryAcquire failed - discardLock(handleA, mA0) - mA0 = 0 - - // did it fail because the handles are equal? - if (handleA == handleB) - return fallbackTransform2(handleA, handleB, f) - - // try it in the opposite direction - mB0 = acquireLock(handleB, true) - mA0 = tryAcquireExclusiveLock(handleA) - - if (mA0 == 0) { - // tryAcquire failed - discardLock(handleB, mB0) - mB0 = 0 - - tries += 1 - if (tries > 10) - return fallbackTransform2(handleA, handleB, f) - } - } - } while (mB0 == 0) - - val (a, b, z) = try { - f(handleA.data, handleB.data) - } catch { - case x: Throwable => { - discardLock(handleA, mA0) - discardLock(handleB, mB0) - throw x - } - } - - handleA.data = a - handleB.data = b - - val wv = CCSTM.nonTxnWriteVersion(math.max(version(mA0), version(mB0))) - releaseLock(handleA, mA0, wv) - releaseLock(handleB, mB0, wv) - return z - } - - @throws(classOf[InterruptedException]) - private def fallbackTransform2[A, B, Z](handleA: Handle[A], handleB: Handle[B], f: (A, B) => (A, B, Z)): Z = { - atomic { t => - val txn = t.asInstanceOf[InTxnImpl] - val a0 = txn.get(handleA) - val b0 = txn.get(handleB) - val (a1, b1, z) = f(a0, b0) - txn.set(handleA, a1) - txn.set(handleB, b1) - z - } - } - - @throws(classOf[InterruptedException]) - def ccasi[A <: AnyRef, B <: AnyRef](handleA: Handle[A], a0: A, handleB: Handle[B], b0: B, b1: B): Boolean = { - var tries = 0 - while (tries < 10) { - // acquire exclusive ownership of B, then decide - val mB0 = acquireLock(handleB, true) - if (b0 ne handleB.data.asInstanceOf[AnyRef]) { - // b doesn't match - discardLock(handleB, mB0) - return false - } - - var mA0 = handleA.meta - while (!changing(mA0)) { - // attempt a stable read of A - val a = handleA.data - val mA1 = handleA.meta - if (changingAndVersion(mA0) != changingAndVersion(mA1)) { - // read of A was unstable, but we don't need to block right now - mA0 = mA1 - } else { - // we can definitely complete the CCASI - if (a eq a0) { - // a0 and b0 both match - commitUpdate(handleB, mB0, b1) - return true - } else { - // a0 doesn't match - discardLock(handleB, mB0) - return false - } - } - } - - // release our lock before waiting for A - discardLock(handleB, mB0) - weakAwaitUnowned(handleA, mA0) - - tries += 1 - } - - // fall back on a transaction - return atomic { t => - val txn = t.asInstanceOf[InTxnImpl] - (txn.get(handleA) eq a0) && (txn.get(handleB) eq b0) && { txn.set(handleB, b1) ; true } - } - } - - @throws(classOf[InterruptedException]) - def cci[A <: AnyRef, B <: AnyRef](handleA: Handle[A], a0: A, handleB: Handle[B], b0: B): Boolean = { - var tries = 0 - while (tries < 10) { - val mA0 = handleA.meta - val mB0 = handleB.meta - if (!changing(mA0) && !changing(mB0)) { - val b = handleB.data - val a = handleA.data - val mA1 = handleA.meta - val mB1 = handleB.meta - if (changingAndVersion(mA0) == changingAndVersion(mA1) && changingAndVersion(mB0) == changingAndVersion(mB1)) - return (a0 eq a) && (b0 eq b) - } - if (changing(mA0)) - weakAwaitUnowned(handleA, mA0) - if (changing(mB0)) - weakAwaitUnowned(handleB, mB0) - - tries += 1 - } - - // fall back on a transaction - return atomic { t => - val txn = t.asInstanceOf[InTxnImpl] - (txn.get(handleA) eq a0) && (txn.get(handleB) eq b0) - } - } - - @throws(classOf[InterruptedException]) - def getAndAdd(handle: Handle[Int], delta: Int): Int = { - val m0 = acquireLock(handle, true) - val v0 = handle.data - commitUpdate(handle, m0, v0 + delta) - v0 - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/ccstm/RefOps.scala b/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/ccstm/RefOps.scala deleted file mode 100644 index f81b7a5d..00000000 --- a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/ccstm/RefOps.scala +++ /dev/null @@ -1,47 +0,0 @@ -/* scala-stm - (c) 2009-2012, Stanford University, PPL */ - -package scala.concurrent.stm -package ccstm - -/** The default implementation of `Ref`'s operations in CCSTM. */ -private[ccstm] trait RefOps[T] extends Ref[T] with Handle.Provider[T] { - - private def impl(implicit txn: InTxn): InTxnImpl = txn.asInstanceOf[InTxnImpl] - - /** Override this to provide the handle that this `RefOps` uses. */ - def handle: Handle[T] - - //////////////// Source stuff - - override def apply()(implicit txn: InTxn): T = impl.get(handle) - def get(implicit txn: InTxn): T = impl.get(handle) - def getWith[Z](f: (T) => Z)(implicit txn: InTxn): Z = impl.getWith(handle, f) - def relaxedGet(equiv: (T, T) => Boolean)(implicit txn: InTxn): T = impl.relaxedGet(handle, equiv) - - //////////////// Sink stuff - - - override def update(v: T)(implicit txn: InTxn) { impl.set(handle, v) } - def set(v: T)(implicit txn: InTxn) { impl.set(handle, v) } - def trySet(v: T)(implicit txn: InTxn): Boolean = impl.trySet(handle, v) - - //////////////// Ref stuff - - def swap(v: T)(implicit txn: InTxn): T = impl.swap(handle, v) - - def transform(f: T => T)(implicit txn: InTxn) { - // only sub-types of Ref actually perform deferral, the base implementation - // evaluates f immediately - impl.getAndTransform(handle, f) - } - - override def transformAndGet(f: T => T)(implicit txn: InTxn): T = impl.transformAndGet(handle, f) - - override def getAndTransform(f: T => T)(implicit txn: InTxn): T = impl.getAndTransform(handle, f) - - override def transformAndExtract[V](f: T => (T,V))(implicit txn: InTxn): V = impl.transformAndExtract(handle, f) - - def transformIfDefined(pf: PartialFunction[T,T])(implicit txn: InTxn): Boolean = { - impl.transformIfDefined(handle, pf) - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/ccstm/RetrySet.scala b/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/ccstm/RetrySet.scala deleted file mode 100644 index f5ac6281..00000000 --- a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/ccstm/RetrySet.scala +++ /dev/null @@ -1,107 +0,0 @@ -/* scala-stm - (c) 2009-2012, Stanford University, PPL */ - -package scala.concurrent.stm.ccstm - -import annotation.tailrec -import java.util.concurrent.TimeUnit - -/** A retry set representation. */ -private[ccstm] class RetrySet(val size: Int, - handles: Array[Handle[_]], - versions: Array[CCSTM.Version]) { - import CCSTM._ - - /** Returns the number of nanoseconds of blocking that was performed. */ - @throws(classOf[InterruptedException]) - def awaitRetry(timeoutNanos: Long): Long = { - if (size == 0 && timeoutNanos == Long.MaxValue) - throw new IllegalStateException("explicit retries cannot succeed because cumulative read set is empty") - - val begin = System.nanoTime - - val d = begin + timeoutNanos - val deadline = if (d < 0) Long.MaxValue else d // handle arithmetic overflow - - val timeoutExceeded = !attemptAwait(deadline) - - val actualElapsed = System.nanoTime - begin - - if (Stats.top != null) { - Stats.top.retrySet += size - val millis = TimeUnit.NANOSECONDS.toMillis(actualElapsed) - Stats.top.retryWaitElapsed += millis.asInstanceOf[Int] - } - - // to cause the proper retryFor to wake up we need to present an illusion - // that we didn't block for too long - // - // reportedElapsed = min(now, deadline) - begin - // reportedElapsed = min(now - begin, deadline - begin) - math.min(actualElapsed, deadline - begin) - } - - /** Returns true if something changed, false if the deadline was reached. */ - @throws(classOf[InterruptedException]) - private def attemptAwait(nanoDeadline: Long): Boolean = { - // Spin a few times, counting one spin per read set element - var spins = 0 - while (size > 0 && spins < SpinCount + YieldCount) { - if (changed) - return true - spins += size - if (spins > SpinCount) { - Thread.`yield` - if (nanoDeadline != Long.MaxValue && System.nanoTime > nanoDeadline) - return false - } - } - - return blockingAttemptAwait(nanoDeadline) - } - - @throws(classOf[InterruptedException]) - @tailrec - private def blockingAttemptAwait(nanoDeadline: Long, - event: WakeupManager.Event = wakeupManager.subscribe, - i: Int = size - 1): Boolean = { - if (i < 0) { - // event has been completed, time to block - if (!event.tryAwaitUntil(nanoDeadline)) - false // timed out - else - changed || blockingAttemptAwait(nanoDeadline) // event fired - } else { - // still building the event - val h = handles(i) - if (!event.addSource(h)) - changed || blockingAttemptAwait(nanoDeadline) // event fired - else if (!addPendingWakeup(h, versions(i))) - true // direct evidence of change - else - blockingAttemptAwait(nanoDeadline, event, i - 1) // keep building - } - } - - @tailrec - private def addPendingWakeup(handle: Handle[_], ver: CCSTM.Version): Boolean = { - val m = handle.meta - if (changing(m) || version(m) != ver) - false // handle has already changed - else if (pendingWakeups(m) || handle.metaCAS(m, withPendingWakeups(m))) - true // already has pending wakeup, or CAS to add it was successful - else - addPendingWakeup(handle, ver) // try again - } - - private def changed: Boolean = { - var i = size - 1 - while (i >= 0) { - val m = handles(i).meta - if (changing(m) || version(m) != versions(i)) - return true - i -= 1 - } - return false - } - -} diff --git a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/ccstm/RetrySetBuilder.scala b/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/ccstm/RetrySetBuilder.scala deleted file mode 100644 index 4c087b1d..00000000 --- a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/ccstm/RetrySetBuilder.scala +++ /dev/null @@ -1,80 +0,0 @@ -/* scala-stm - (c) 2009-2011, Stanford University, PPL */ - -package scala.concurrent.stm.ccstm - -import annotation.tailrec - - -/** This is basically a specialized builder for a map from `Handle` to - * `Version`. - * - * @author Nathan Bronson - */ -private[ccstm] final class RetrySetBuilder { - private var _size = 0 - private var _handles = new Array[Handle[_]](maxSizeForCap(InitialCap) + 1) - private var _versions = new Array[CCSTM.Version](maxSizeForCap(InitialCap) + 1) - private var _next = new Array[Int](maxSizeForCap(InitialCap) + 1) - private var _dispatch = new Array[Int](InitialCap) - - private final val InitialCap = 16 - private def maxSizeForCap(cap: Int) = cap - (cap / 4) - - def size = _size - - def += (handle: Handle[_], version: CCSTM.Version) { - val slot = CCSTM.hash(handle.base, handle.offset) & (_dispatch.length - 1) - addImpl(slot, _dispatch(slot), handle, version) - } - - @tailrec - private def addImpl(slot: Int, i: Int, handle: Handle[_], version: CCSTM.Version) { - if (i == 0) - append(slot, handle, version) - else if (!hEq(_handles(i - 1), handle)) - addImpl(slot, _next(i - 1), handle, version) - // else it is a duplicate - } - - private def append(slot: Int, handle: Handle[_], version: CCSTM.Version) { - val i = _size + 1 - _size = i - _handles(i - 1) = handle - _versions(i - 1) = version - _next(i - 1) = _dispatch(slot) - _dispatch(slot) = i - if (_size > maxSizeForCap(_dispatch.length)) - grow() - } - - private def grow() { - // store the current contents - val s = _size - val hh = _handles - val vv = _versions - - // reallocate - _size = 0 - val c = _dispatch.length * 2 - _handles = new Array[Handle[_]](maxSizeForCap(c) + 1) - _versions = new Array[CCSTM.Version](maxSizeForCap(c) + 1) - _next = new Array[Int](maxSizeForCap(c) + 1) - _dispatch = new Array[Int](c) - - // reinsert the current contents - var i = 0 - while (i < s) { - val h = hh(i) - append(CCSTM.hash(h.base, h.offset) & (c - 1), h, vv(i)) - i += 1 - } - } - - private def hEq(a: Handle[_], b: Handle[_]) = (a eq b) || ((a.base eq b.base) && (a.offset == b.offset)) - - def result(): RetrySet = { - _dispatch = null - _next = null - new RetrySet(_size, _handles, _versions) - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/ccstm/Stats.scala b/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/ccstm/Stats.scala deleted file mode 100644 index 1005bc63..00000000 --- a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/ccstm/Stats.scala +++ /dev/null @@ -1,131 +0,0 @@ -/* scala-stm - (c) 2009-2012, Stanford University, PPL */ - -package scala.concurrent.stm.ccstm - -import collection.mutable.ArrayBuffer - -private[ccstm] object Stats { - - val Enabled = "yYtT1".indexOf((System.getProperty("ccstm.stats", "") + "0").charAt(0)) >= 0 - - class LazyCounterMap[A] { - import scala.collection.JavaConversions._ - - private val _counters = new java.util.concurrent.ConcurrentHashMap[A, Counter] - - def += (k: A) { - var v = _counters.get(k) - if (v == null) { - _counters.putIfAbsent(k, new Counter) - v = _counters.get(k) - } - v += 1 - } - - def toStr(k: A): String = k.toString - - def contents: Seq[(String, Long)] = { - val aa = _counters.entrySet.toSeq map { e => (toStr(e.getKey) -> e.getValue.apply()) } - aa sortBy { -_._2 } - } - } - - class Histo(numBuckets: Int) { - private val _sum = new Counter - private val _buckets = Array.tabulate(numBuckets) { _ => new Counter } - - def += (value: Int) { - if (value != 0) { - _sum += value - _buckets(bucketFor(value)) += 1 - } - } - - protected def bucketFor(value: Int): Int = { - if (value < 0 || value >= _buckets.length) - _buckets.length - 1 - else - value - } - - def contents: Seq[Long] = { - val snap = _buckets map { _.apply() } - snap.take(1 + snap.lastIndexWhere { _ != 0L }) - } - - override def toString = { - val s = _sum() - val c = contents - val count = c.foldLeft(0L)( _ + _ ) - val avg = if (count == 0) 0.0 else s * 1.0 / count - "sum= %-10d count= %-8d avg= %-5.1f [%s]".format(s, count, avg, c.mkString(" ")) - } - } - - class ExponentialHisto extends Histo(32) { - override protected def bucketFor(value: Int): Int = { - var v = value >>> 1 - var i = 0 - while (v != 0) { - v >>>= 1 - i += 1 - } - i - } - } - - class Level(isTop: Boolean) { - val commits = new Counter - val alternatives = new Histo(10) - val retrySet = if (isTop) new ExponentialHisto else null - val retryWaitElapsed = if (isTop) new ExponentialHisto else null - val explicitRetries = new Counter - val unrecordedTxns = new Counter - val optimisticRetries = new LazyCounterMap[Symbol] - val failures = new LazyCounterMap[Class[_]] { override def toStr(k: Class[_]) = k.getSimpleName } - val blockingAcquires = new Counter - val commitReadSet = if (isTop) new ExponentialHisto else null - val commitBargeSet = if (isTop) new ExponentialHisto else null - val commitWriteSet = if (isTop) new ExponentialHisto else null - val rollbackReadSet = new ExponentialHisto - val rollbackBargeSet = new ExponentialHisto - val rollbackWriteSet = new ExponentialHisto - - def contents: Seq[String] = { - val buf = new ArrayBuffer[String] - for (f <- getClass.getDeclaredFields) { - val name = f.getName - val value = getClass.getDeclaredMethod(name).invoke(this) - value match { - case null => - case c: Counter => buf += "%17s= %d".format(name, c()) - case m: LazyCounterMap[_] => { - for ((k, v) <- m.contents) - buf += "%17s: %7d %s".format(name, v, k) - } - case h: Histo => buf += "%17s: %s".format(name, h) - } - } - buf.result - } - - def mkString(prefix: String): String = { - prefix + ("-" * 64) + "\n" + contents.map( prefix + _ ).mkString("\n") - } - } - - val top = if (Enabled) new Level(true) else null - val nested = if (Enabled) new Level(false) else null - registerShutdownHook() - - private def registerShutdownHook() { - if (top != null) - Runtime.getRuntime.addShutdownHook(new Thread("shutdown stats printer") { - override def run() { println(Stats) } - }) - } - - override def toString() = { - top.mkString("CCSTM: top: ") + "\n" + nested.mkString("CCSTM: nested: ") - } -} \ No newline at end of file diff --git a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/ccstm/TArrayImpl.scala b/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/ccstm/TArrayImpl.scala deleted file mode 100644 index 32fc2db7..00000000 --- a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/ccstm/TArrayImpl.scala +++ /dev/null @@ -1,99 +0,0 @@ -/* scala-stm - (c) 2009-2012, Stanford University, PPL */ - -package scala.concurrent.stm -package ccstm - -import skel.AtomicArray -import java.util.concurrent.atomic.AtomicLongArray -import scala.reflect.ClassManifest -import scala.collection._ - - -private[ccstm] class TArrayImpl[A](private val values: AtomicArray[A])(implicit m: ClassManifest[A]) extends TArray[A] with TArray.View[A] { - import TArray._ - - def this(length0: Int)(implicit m: ClassManifest[A]) = this(AtomicArray[A](length0)) - - def this(data0: TraversableOnce[A])(implicit m: ClassManifest[A]) = this(AtomicArray[A](data0)) - - val length = values.length - - //////////////// TArray - - def single: View[A] = this - - def apply(index: Int)(implicit txn: InTxn) = getRef(index).get - - def update(index: Int, v: A)(implicit txn: InTxn) = getRef(index).set(v) - - /** Returns a sequence that will produce transient `Ref` instances that are - * backed by elements of this `TArray`. This allows use of all of `Ref`'s - * functionality for reading, writing, and transforming elements. - */ - def refs: immutable.IndexedSeq[Ref[A]] = new immutable.IndexedSeq[Ref[A]] { - def length: Int = TArrayImpl.this.length - def apply(index0: Int): Ref[A] = getRef(index0) - } - - //////////////// TArray.View - - def tarray = TArrayImpl.this - - def apply(index: Int): A = getRef(index).single.get - - def update(index: Int, v: A) = getRef(index).single.set(v) - - def refViews: immutable.IndexedSeq[Ref.View[A]] = new immutable.IndexedSeq[Ref.View[A]] { - def length = tarray.length - def apply(index: Int) = getRef(index).single - } - - /////////////// TxnDebuggable - - def dbgStr: String = atomic.unrecorded({ _ => mkStringPrefix("TArray", single) }, { _.toString }) - - def dbgValue: Any = atomic.unrecorded({ _ => toArray }, { x => x }) - - /////////////// Internal implementation - - private val metaIndexMask = { - // We use min(length, nextPowerOfTwo(6 + length/16)) metadata elements. - // The mask is always nextPowerOfTwo(6 + length/16) - 1, even if that is - // too large. - val n = 6 + length / 16 - var m = 7 - while (m < n - 1) - m = (m << 1) + 1 - m - } - - private val metaValues = new AtomicLongArray(math.min(metaIndexMask + 1, length)) - - private def getRef(index: Int): Ref[A] = { - if (index < 0 || index >= length) - throw new ArrayIndexOutOfBoundsException(index) - - new Handle[A] with RefOps[A] with ViewOps[A] { - def handle: Handle[A] = this - def single: Ref.View[A] = this - def ref: Ref[A] = this - - def meta = metaValues.get(metaOffset) - def meta_=(v: Long) { metaValues.set(metaOffset, v) } - def metaCAS(before: Long, after: Long) = metaValues.compareAndSet(metaOffset, before, after) - def base = TArrayImpl.this - def offset = index - def metaOffset = index & metaIndexMask - def data = values(index) - def data_=(v: A) { values(index) = v } - - override def dbgStr: String = super[RefOps].dbgStr - override def dbgValue: Any = super[RefOps].dbgValue - - override def toString = { - "TArray@" + Integer.toHexString(System.identityHashCode(TArrayImpl.this)) + "(" + index + ")" - } - } - } -} - diff --git a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/ccstm/TxnLevelImpl.scala b/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/ccstm/TxnLevelImpl.scala deleted file mode 100644 index 9ad2a685..00000000 --- a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/ccstm/TxnLevelImpl.scala +++ /dev/null @@ -1,291 +0,0 @@ -/* scala-stm - (c) 2009-2012, Stanford University, PPL */ - -package scala.concurrent.stm -package ccstm - -import scala.annotation.tailrec -import java.util.concurrent.atomic.AtomicReferenceFieldUpdater -import skel.{AbstractNestingLevel, RollbackError} - -private[ccstm] object TxnLevelImpl { - - private val stateUpdater = new TxnLevelImpl(null, null, null, false).newStateUpdater - - /** Maps blocked `InTxnImpl` that are members of a commit barrier to the - * `TxnLevelImpl` instance on which they are waiting. All of the values - * in this map must be notified when a new link in a (potential) deadlock - * chain is formed. - */ - @volatile private var _blockedBarrierMembers = Map.empty[InTxnImpl, TxnLevelImpl] - - def notifyBlockedBarrierMembers() { - val m = _blockedBarrierMembers - if (!m.isEmpty) { - for (v <- m.values) - v.synchronized { v.notifyAll() } - } - } - - def addBlockedBarrierMember(waiter: InTxnImpl, monitor: TxnLevelImpl) { - synchronized { - _blockedBarrierMembers += (waiter -> monitor) - } - } - - def removeBlockedBarrierMember(waiter: InTxnImpl) { - synchronized { - _blockedBarrierMembers -= waiter - } - } -} - -/** `TxnLevelImpl` bundles the data and behaviors from `AccessHistory.UndoLog` - * and `AbstractNestingLevel`, and adds handling of the nesting level status. - * - * @author Nathan Bronson - */ -private[ccstm] class TxnLevelImpl(val txn: InTxnImpl, - val executor: TxnExecutor, - val parUndo: TxnLevelImpl, - val phantom: Boolean) - extends AccessHistory.UndoLog with AbstractNestingLevel { - import TxnLevelImpl._ - import WakeupManager.blocking - - // this is the first non-hidden parent - val parLevel: AbstractNestingLevel = if (parUndo == null || !parUndo.phantom) parUndo else parUndo.parLevel - - val root: AbstractNestingLevel = if (parLevel == null) this else parLevel.root - - /** The transaction attempt on which this transaction is blocked, if any. - * Only set for roots. - */ - @volatile private var _blockedBy: TxnLevelImpl = null - - /** To make `requireActive` more efficient we store the raw state of - * `Txn.Active` as null. If the raw state is a `TxnLevelImpl`, then that - * indicates that this nesting level is an ancestor of `txn.currentLevel`; - * this is reported as a status of `Txn.Active`. The raw state can also be - * the interned string value "merged" to indicate that the status is now in - * lock-step with the parent. - */ - @volatile private var _state: AnyRef = null - - private def newStateUpdater: AtomicReferenceFieldUpdater[TxnLevelImpl, AnyRef] = { - AtomicReferenceFieldUpdater.newUpdater(classOf[TxnLevelImpl], classOf[AnyRef], "_state") - } - - /** True if anybody is waiting for `status.completed`. */ - @volatile private var _waiters = false - - @tailrec final def minEnclosingRetryTimeout(accum: Long = Long.MaxValue): Long = { - val z = math.min(accum, executor.retryTimeoutNanos.getOrElse(Long.MaxValue)) - if (parUndo == null) z else parUndo.minEnclosingRetryTimeout(z) - } - - @tailrec final def status: Txn.Status = { - val raw = _state - if (raw == null) - Txn.Active // we encode active as null to make requireActive checks smaller - else if (raw eq "merged") - parUndo.status - else if (raw.isInstanceOf[TxnLevelImpl]) - Txn.Active // child is active - else - raw.asInstanceOf[Txn.Status] - } - - def setCommitting() { - _state = Txn.Committing - } - - def setCommitted() { - _state = Txn.Committed - notifyCompleted() - } - - def tryActiveToCommitted(): Boolean = { - val f = stateUpdater.compareAndSet(this, null, Txn.Committed) - if (f) - notifyCompleted() - f - } - - def tryActiveToPreparing(): Boolean = { - val f = stateUpdater.compareAndSet(this, null, Txn.Preparing) - if (f && txn.commitBarrier != null) - notifyBlockedBarrierMembers() - f - } - - def tryPreparingToPrepared(): Boolean = stateUpdater.compareAndSet(this, Txn.Preparing, Txn.Prepared) - - def tryPreparingToCommitting(): Boolean = stateUpdater.compareAndSet(this, Txn.Preparing, Txn.Committing) - - /** Equivalent to `status` if this level is the current level, otherwise - * the result is undefined. - */ - def statusAsCurrent: Txn.Status = { - val raw = _state - if (raw == null) - Txn.Active - else - raw.asInstanceOf[Txn.Status] - } - - private def notifyCompleted() { - if (_waiters) - synchronized { notifyAll() } - } - - // We are looking for a chain of blockedBy txns that ends in a Prepared txn, - // and the beginning and the end of the chain have the same non-null commit - // barrier. This is made a bit tricky because the deadlock chain might not - // form from either end, some of the links might not be commit barrier - // members, and one of the steps to building the chain might not be a call to - // blockedBy. - // - // Our design places responsibility for checking on the beginning (Active) end - // of the chain, and places responsibility for waking up threads that might - // need to check on any thread that might complete a chain. - - @tailrec private def hasMemberCycle(cb: CommitBarrierImpl, src: TxnLevelImpl): Boolean = { - if (src._state.isInstanceOf[Txn.RolledBack]) - false - else { - val next = src._blockedBy - if (next == null) - src.txn.commitBarrier == cb - else - hasMemberCycle(cb, next) - } - } - - private def isRolledBack: Boolean = _state.isInstanceOf[Txn.RolledBack] - - /** Blocks until `status.completed`, possibly returning early if `waiter` - * has been rolled back. - */ - @throws(classOf[InterruptedException]) - def awaitCompleted(waiter: TxnLevelImpl, debugInfo: Any) { - assert(parUndo == null) - - _waiters = true - - if (Stats.top != null) - Stats.top.blockingAcquires += 1 - - if (waiter != null) { - val cb = waiter.txn.commitBarrier - try { - waiter._blockedBy = this - notifyBlockedBarrierMembers() - if (cb != null) - addBlockedBarrierMember(waiter.txn, this) - - synchronized { - if (!status.completed && !waiter.isRolledBack) { - blocking { - // We would not have to check that the waiter has been stolen from - // except that when there is a commit barrier the thief might also be - // the txn on which we are blocked - while (!status.completed && !waiter.isRolledBack) { - if (cb != null && hasMemberCycle(cb, waiter)) - cb.cancelAll(CommitBarrier.MemberCycle(debugInfo)) - wait() - } - } - } - } - - } finally { - if (cb != null) - removeBlockedBarrierMember(waiter.txn) - waiter._blockedBy = null - } - } else { - synchronized { - if (!status.completed) - blocking { while (!status.completed) wait() } - } - } - } - - - def requireActive() { - if (_state != null) - slowRequireActive() - } - - private def slowRequireActive() { - status match { - case Txn.RolledBack(_) => throw RollbackError - case s => throw new IllegalStateException(s.toString) - } - } - - def pushIfActive(child: TxnLevelImpl): Boolean = { - stateUpdater.compareAndSet(this, null, child) - } - - def attemptMerge(): Boolean = { - // First we need to set the current state to forwarding. Regardless of - // whether or not this fails we still need to unlink the parent. - val f = (_state == null) && stateUpdater.compareAndSet(this, null, "merged") - - // We must use CAS to unlink ourselves from our parent, because we race - // with remote cancels. - if (parUndo._state eq this) - stateUpdater.compareAndSet(parUndo, this, null) - - f - } - - /** Must be called from the transaction's thread. */ - def forceRollback(cause: Txn.RollbackCause) { - val s = rollbackImpl(Txn.RolledBack(cause)) - assert(s.isInstanceOf[Txn.RolledBack]) - } - - def requestRollback(cause: Txn.RollbackCause): Txn.Status = { - if (cause.isInstanceOf[Txn.ExplicitRetryCause]) - throw new IllegalArgumentException("explicit retry is not available via requestRollback") - rollbackImpl(Txn.RolledBack(cause)) - } - - // this is tailrec for retries, but not when we forward to child - private def rollbackImpl(rb: Txn.RolledBack): Txn.Status = { - val raw = _state - if (raw == null || canAttemptLocalRollback(raw)) { - // normal case - if (stateUpdater.compareAndSet(this, raw, rb)) { - notifyCompleted() - rb - } else - rollbackImpl(rb) // retry - } else if (raw eq "merged") { - // we are now taking our status from our parent - parUndo.rollbackImpl(rb) - } else if (raw.isInstanceOf[TxnLevelImpl]) { - // roll back the child first, then retry - raw.asInstanceOf[TxnLevelImpl].rollbackImpl(rb) - rollbackImpl(rb) - } else { - // request denied - raw.asInstanceOf[Txn.Status] - } - } - - private def canAttemptLocalRollback(raw: AnyRef): Boolean = raw match { - case Txn.Prepared => InTxnImpl.get eq txn // remote cancel is not allowed while preparing - case s: Txn.Status => !s.decided - case ch: TxnLevelImpl => ch.rolledBackOrMerged - case _ => false - } - - private def rolledBackOrMerged = _state match { - case "merged" => true - case Txn.RolledBack(_) => true - case _ => false - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/ccstm/TxnLocalImpl.scala b/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/ccstm/TxnLocalImpl.scala deleted file mode 100644 index 6dc59bad..00000000 --- a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/ccstm/TxnLocalImpl.scala +++ /dev/null @@ -1,109 +0,0 @@ -/* scala-stm - (c) 2009-2012, Stanford University, PPL */ - -package scala.concurrent.stm -package ccstm - -// TxnLocalImpl - -private[ccstm] class TxnLocalImpl[A](init: => A, - initialValue: InTxn => A, - beforeCommit: InTxn => Unit, - whilePreparing: InTxnEnd => Unit, - whileCommitting: InTxnEnd => Unit, - afterCommit: A => Unit, - afterRollback: Txn.Status => Unit, - afterCompletion: Txn.Status => Unit) extends Handle[A] with TxnLocal[A] { - - //////// stateless Handle - - def meta: Long = CCSTM.txnLocalMeta - def meta_=(v: Long) = throw new Error - def metaCAS(before: Long, after: Long): Boolean = throw new Error - def base: AnyRef = this - def offset: Int = 0 - def metaOffset: Int = 0 - def data: A = throw new Error - def data_=(v: A) {} - - - //////// TxnLocal - - def isInitialized(implicit txn: InTxnEnd): Boolean = { - txn.asInstanceOf[InTxnImpl].txnLocalFind(this) >= 0 - } - - //////// SourceLike - - def get(implicit txn: InTxnEnd): A = { - val impl = txn.asInstanceOf[InTxnImpl] - val i = impl.txnLocalFind(this) - if (i >= 0) - impl.txnLocalGet[A](i) - else - initialize(impl) - } - - private def initialize(impl: InTxnImpl): A = { - if (initialValue != null || beforeCommit != null) - impl.requireActive() - - val v = if (initialValue != null) initialValue(impl) else init - impl.txnLocalInsert(this, v) - - registerCallbacks(impl) - - v - } - - private def registerCallbacks(impl: InTxnImpl) { - // need to do afterRollback and afterCompletion first so that if there is a - // remote txn cancel we've got them in place - if (afterRollback != null) - impl.afterRollback(afterRollback) - if (afterCompletion != null) - impl.afterCompletion(afterCompletion) - - if (beforeCommit != null) - impl.beforeCommit(beforeCommit) - if (whilePreparing != null) - impl.whilePreparing(whilePreparing) - if (whileCommitting != null) - impl.whileCommitting(whileCommitting) - if (afterCommit != null) { - impl.whileCommitting { _ => - val finalValue = impl.txnLocalGet[A](impl.txnLocalFind(this)) - impl.afterCommit { _ => afterCommit(finalValue) } - } - } - } - - def getWith[Z](f: (A) => Z)(implicit txn: InTxnEnd): Z = f(get) - - def relaxedGet(equiv: (A, A) => Boolean)(implicit txn: InTxnEnd): A = get - - //////// SinkLike - - def set(v: A)(implicit txn: InTxnEnd) = { - val impl = txn.asInstanceOf[InTxnImpl] - val i = impl.txnLocalFind(this) - if (i >= 0) - impl.txnLocalUpdate(i, v) - else { - impl.txnLocalInsert(this, v) - registerCallbacks(impl) - } - } - - def trySet(v: A)(implicit txn: InTxnEnd): Boolean = { set(v) ; true } - - //////// RefLike - - def swap(v: A)(implicit txn: InTxnEnd): A = { val z = get ; set(v) ; z } - - def transform(f: (A) => A)(implicit txn: InTxnEnd) { set(f(get)) } - - def transformIfDefined(pf: PartialFunction[A, A])(implicit txn: InTxnEnd): Boolean = { - val v0 = get - pf.isDefinedAt(v0) && { set(pf(v0)) ; true } - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/ccstm/TxnSlotManager.scala b/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/ccstm/TxnSlotManager.scala deleted file mode 100644 index 42bd0a5b..00000000 --- a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/ccstm/TxnSlotManager.scala +++ /dev/null @@ -1,109 +0,0 @@ -/* scala-stm - (c) 2009-2011, Stanford University, PPL */ - -package scala.concurrent.stm -package ccstm - - -import java.util.concurrent.atomic.AtomicReferenceArray - - -private case class SlotLock(txn: AnyRef, refCount: Int) - -/** This class manages a mapping from active transaction to a bounded integral - * range, so that transaction identities to be packed into some of the bits of - * an integral value. - * - * @author Nathan Bronson - */ -private[ccstm] final class TxnSlotManager[T <: AnyRef](range: Int, reservedSlots: Int) { - - assert(range >= 16 & (range & (range - 1)) == 0) - assert(range >= reservedSlots + 16) - - private def nextSlot(tries: Int) = { - ((skel.SimpleRandom.nextInt << 4) | ((-tries >> 1) & 0xf)) & (range - 1) - } - - /** CAS on the entries manages the actual acquisition. Entries are either - * transactions, or SlotLock objects. - */ - private val slots = new AtomicReferenceArray[AnyRef](range) - - @throws(classOf[InterruptedException]) - def assign(txn: T, slotHint: Int): Int = { - // We advance to the next slot number after the hint, wrapping around in a - // 64 byte space. This avoids rollback from late steals, but keeps us in - // a cache line we already own. - var s = ((slotHint & ~0xf) | ((slotHint + 1) & 0xf)) & (range - 1) - - var tries = 0 - while (s < reservedSlots || slots.get(s) != null || !slots.compareAndSet(s, null, txn)) { - s = nextSlot(tries) - tries += 1 - if (tries > 100) { - if (Thread.interrupted) - throw new InterruptedException - Thread.`yield` - } - } - s - } - - /** Returns the slot associated with `slot` at some instant. The - * returned value may be obsolete before this method returns. - */ - def lookup(slot:Int): T = unwrap(slots.get(slot)) - - private def unwrap(e: AnyRef): T = { - e match { - case SlotLock(txn, _) => txn.asInstanceOf[T] - case txn => txn.asInstanceOf[T] - } - } - - /** A non-racy version of `lookup`, that must be paired with - * `endLookup`. - */ - def beginLookup(slot: Int): T = { - var e: AnyRef = null - do { - e = slots.get(slot) - } while (e != null && !slots.compareAndSet(slot, e, locked(e))) - unwrap(e) - } - - private def locked(e: AnyRef): AnyRef = { - e match { - case SlotLock(txn, rc) => SlotLock(txn, rc + 1) - case txn => SlotLock(txn, 1) - } - } - - def endLookup(slot: Int, observed: T) { - if (null != observed) release(slot) - } - - def release(slot: Int) { - var e: AnyRef = null - do { - e = slots.get(slot) - } while (!slots.compareAndSet(slot, e, unlocked(e))) - } - - private def unlocked(e: AnyRef): AnyRef = { - e match { - case SlotLock(txn, 1) => txn - case SlotLock(txn, rc) => SlotLock(txn, rc - 1) - case txn => null - } - } - -// def assertAllReleased() { -// for (i <- 0 until range) { -// val e = slots.get(i) -// if (null != e) { -// assert(false, i + " -> " + e) -// } -// } -// } -} diff --git a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/ccstm/UnrecordedRead.scala b/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/ccstm/UnrecordedRead.scala deleted file mode 100644 index c49a29b1..00000000 --- a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/ccstm/UnrecordedRead.scala +++ /dev/null @@ -1,58 +0,0 @@ -/* scala-stm - (c) 2009-2010, Stanford University, PPL */ - -package scala.concurrent.stm.ccstm - - -/** Holds the result of an unrecorded read, which may be used to avoid - * transaction conflicts, or to detect ABA changes when performing - * single-operation transactions. `ReleasableRead`s provide a - * related functionality. - * - * When an unrecorded read is performed in a transaction, the caller is - * responsible for guaranteeing that the transaction's behavior is correct, - * even if the read becomes invalid prior to commit. Unrecorded reads may be - * useful for heuristic decisions that can tolerate inconsistent or stale - * data, for methods that register transaction handlers to perform - * validation at a semantic level, or for optimistically traversing linked - * data structures while tolerating mutations to earlier links. When used in - * combination with transaction resource callbacks, it is important to - * consider the case that the unrecorded read is already invalid before it is - * returned to the requester. - * - * Writes by the same transaction that performed the unrecorded read are - * '''not''' considered to invalidate the read. - * - * When called from a non-transactional context the returned instance can be - * used to determine if a value has remained unchanged for a particular - * interval, which may be useful to detect ABA situations. - * - * @author Nathan Bronson - */ -private[ccstm] trait UnrecordedRead[+T] { - - /** Returns the value observed by this `UnrecordedRead`, regardless of - * whether it is still valid. - */ - def value: T - - /** Returns true if definitely no writes have been performed by a context - * other than the one that performed this unrecorded read. - */ - def stillValid: Boolean - - /** Returns true if the unrecorded read was performed in a transaction, and - * the source of this read is known to be in the transaction's read or write - * set, in which case `stillValid` will definitely be true at the - * transaction's commit (linearization) point if the transaction commits. - * Returns false for non-transactional unrecorded reads. This method is for - * optimization purposes only, a false result does not guarantee that the - * read is not in the transaction's read or write set. If this method - * returns true for an `UnrecordedRead` instance it will always - * return true. - * @return true if the caller may assume that `stillValid` will - * be true for this `UnrecordedRead` if the bound transaction - * is successfully committed. - */ - def recorded: Boolean -} - diff --git a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/ccstm/ViewOps.scala b/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/ccstm/ViewOps.scala deleted file mode 100644 index 857191c9..00000000 --- a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/ccstm/ViewOps.scala +++ /dev/null @@ -1,74 +0,0 @@ -/* scala-stm - (c) 2009-2012, Stanford University, PPL */ - -package scala.concurrent.stm -package ccstm - -import java.util.concurrent.TimeUnit - -/** The default implementation of `Ref.View`'s operations in CCSTM. */ -private[ccstm] trait ViewOps[T] extends Ref.View[T] with Handle.Provider[T] { - - def handle: Handle[T] - - def get: T = InTxnImpl.dynCurrentOrNull match { - case null => NonTxn.get(handle) - case txn => txn.get(handle) - } - def getWith[Z](f: T => Z): Z = InTxnImpl.dynCurrentOrNull match { - case null => f(NonTxn.get(handle)) - case txn => txn.getWith(handle, f) - } - def relaxedGet(equiv: (T, T) => Boolean): T = InTxnImpl.dynCurrentOrNull match { - case null => NonTxn.get(handle) - case txn => txn.relaxedGet(handle, equiv) - } - def await(f: T => Boolean): Unit = InTxnImpl.dynCurrentOrNull match { - case null => NonTxn.await(handle, f) - case txn => if (!f(txn.get(handle))) Txn.retry(txn) - } - def tryAwait(timeout: Long, unit: TimeUnit)(f: T => Boolean): Boolean = InTxnImpl.dynCurrentOrNull match { - case null => NonTxn.tryAwait(handle, f, unit.toNanos(timeout)) - case txn => f(txn.get(handle)) || { Txn.retryFor(timeout, unit)(txn) ; false } - } - def set(v: T): Unit = InTxnImpl.dynCurrentOrNull match { - case null => NonTxn.set(handle, v) - case txn => txn.set(handle, v) - } - def trySet(v: T): Boolean = InTxnImpl.dynCurrentOrNull match { - case null => NonTxn.trySet(handle, v) - case txn => txn.trySet(handle, v) - } - def swap(v: T): T = InTxnImpl.dynCurrentOrNull match { - case null => NonTxn.swap(handle, v) - case txn => txn.swap(handle, v) - } - def compareAndSet(before: T, after: T): Boolean = InTxnImpl.dynCurrentOrNull match { - case null => NonTxn.compareAndSet(handle, before, after) - case txn => txn.compareAndSet(handle, before, after) - } - def compareAndSetIdentity[R <: AnyRef with T](before: R, after: T): Boolean = InTxnImpl.dynCurrentOrNull match { - case null => NonTxn.compareAndSetIdentity(handle, before, after) - case txn => txn.compareAndSetIdentity(handle, before, after) - } - def transform(f: T => T): Unit = InTxnImpl.dynCurrentOrNull match { - case null => NonTxn.transformAndGet(handle, f) - case txn => txn.transformAndGet(handle, f) - } - def getAndTransform(f: T => T): T = InTxnImpl.dynCurrentOrNull match { - case null => NonTxn.getAndTransform(handle, f) - case txn => txn.getAndTransform(handle, f) - } - def transformAndGet(f: T => T): T = InTxnImpl.dynCurrentOrNull match { - case null => NonTxn.transformAndGet(handle, f) - case txn => txn.transformAndGet(handle, f) - } - override def transformAndExtract[V](f: T => (T,V)): V = InTxnImpl.dynCurrentOrNull match { - case null => NonTxn.transformAndExtract(handle, f) - case txn => txn.transformAndExtract(handle, f) - } - - def transformIfDefined(pf: PartialFunction[T,T]): Boolean = InTxnImpl.dynCurrentOrNull match { - case null => NonTxn.transformIfDefined(handle, pf) - case txn => txn.transformIfDefined(handle, pf) - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/ccstm/WakeupManager.scala b/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/ccstm/WakeupManager.scala deleted file mode 100644 index 4a6e426b..00000000 --- a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/ccstm/WakeupManager.scala +++ /dev/null @@ -1,191 +0,0 @@ -/* scala-stm - (c) 2009-2012, Stanford University, PPL */ - -package scala.concurrent.stm.ccstm - - -import java.util.concurrent.atomic.{AtomicReferenceArray, AtomicLongArray} -import java.util.concurrent.locks.AbstractQueuedSynchronizer -import java.lang.reflect.{InvocationTargetException, Method} - -object WakeupManager { - trait Event { - def triggered: Boolean - - /** Returns false if triggered. */ - def addSource(handle: Handle[_]): Boolean - - @throws(classOf[InterruptedException]) - def await() - - /** Use a nanoDeadline of `Long.MaxValue` to wait forever. */ - @throws(classOf[InterruptedException]) - def tryAwaitUntil(nanoDeadline: Long): Boolean - } - - // TODO: remove WakeupManager.blocking once we no longer compile for 2.9 - // This is a hack so that we can use the new scala.concurrent.BlockContext - // (available in Scala >= 2.10) while still compiling for 2.9. Although - // there is a bit of overhead, we are careful to only pay it when we are - // actually about to park the thread (which is quite expensive on its own). - - val blockingMethod: Method = { - try { - Class.forName("scala.concurrent.package").getMethod("blocking", classOf[Function0[_]]) - } catch { - case _: ClassNotFoundException => null - case _: NoSuchMethodException => null - } - } - - /** Returns `body()`, cooperating with 2.10's fork-join system. */ - def blocking[A](body: => A): A = { - if (blockingMethod != null) { - try { - blockingMethod.invoke(null, (body _).asInstanceOf[Function0[_]]).asInstanceOf[A] - } catch { - case x: InvocationTargetException => throw x.getTargetException - } - } else { - body - } - } -} - -/** Provides a service that extends the paradigm of wait+notifyAll to allow - * bulk wait and bulk notification; also does not require that the waiter and - * the notifier share an object reference. There is a chance of a false - * positive. - * - *@author Nathan Bronson - */ -private[ccstm] final class WakeupManager(numChannels: Int, numSources: Int) { - import CCSTM.hash - import WakeupManager.blocking - - def this() = this(64, 512) - - assert(numChannels > 0 && numChannels <= 64 && (numChannels & (numChannels - 1)) == 0) - assert(numSources > 0 && (numSources & (numSources - 1)) == 0) - - // To reduce false sharing. Assume 64 byte cache lines and 4 byte pointers. - private final val ChannelSpacing = 16 - - private val pending = new AtomicLongArray(numSources) - private val events = new AtomicReferenceArray[EventImpl](numChannels * ChannelSpacing) - - /** The returned value must later be passed to `trigger`. - * Multiple return values may be passed to a single invocation of - * `trigger` by merging them with bitwise-OR. - */ - def prepareToTrigger(handle: Handle[_]): Long = { - val i = hash(handle.base, handle.metaOffset) & (numSources - 1) - var z = 0L - do { - z = pending.get(i) - } while (z != 0L && !pending.compareAndSet(i, z, 0L)) - z - } - - /** Completes the wakeups started by `prepareToTrigger`. If a - * thread completes `e = subscribe; e.addSource(r,o)` prior to - * a call to `prepareToTrigger(r,o)` call whose return value is - * included in `wakeups`, then any pending call to - * `e.await` will return now and any future calls will return - * immediately. - */ - def trigger(wakeups: Long) { - var channel = 0 - var w = wakeups - while (w != 0) { - val s = java.lang.Long.numberOfTrailingZeros(w) - w >>>= s - channel += s - trigger(channel) - w >>>= 1 - channel += 1 - } - } - - private def trigger(channel: Int) { - val i = channel * ChannelSpacing - val e = events.get(i) - if (e != null) { - e.trigger() - events.compareAndSet(i, e, null) - } - } - - /** See `trigger`. */ - def subscribe: WakeupManager.Event = { - // Picking the waiter's identity using the thread hash means that there is - // a possibility that we will get repeated interference with another thread - // in a per-program-run way, but it minimizes saturation of the pending - // wakeups, which is quite important. - subscribe(hash(Thread.currentThread) & (numChannels - 1)) - } - - private def subscribe(channel: Int): EventImpl = { - val i = channel * ChannelSpacing - (while (true) { - val existing = events.get(i) - if (existing != null && !existing.triggered) - return existing - val fresh = new EventImpl(channel) - if (events.compareAndSet(i, existing, fresh)) - return fresh - }).asInstanceOf[Nothing] - } - - class EventImpl(channel: Int) extends AbstractQueuedSynchronizer() with WakeupManager.Event { - private val mask = 1L << channel - - setState(1) - - //// adapted from CountDown.Sync - - override def tryAcquireShared(acquires: Int): Int = if (getState == 0) 1 else -1 - - override def tryReleaseShared(releases: Int): Boolean = getState == 1 && compareAndSetState(1, 0) - - //// Event - - def triggered = getState == 0 - - /** Returns false if triggered. */ - def addSource(handle: Handle[_]): Boolean = { - if (triggered) { - false - } else { - val i = hash(handle.base, handle.metaOffset) & (numSources - 1) - var p = pending.get(i) - while((p & mask) == 0 && !pending.compareAndSet(i, p, p | mask)) { - if (triggered) - return false - p = pending.get(i) - } - true - } - } - - @throws(classOf[InterruptedException]) - def await() { - val f = tryAwaitUntil(Long.MaxValue) - assert(f) - } - - @throws(classOf[InterruptedException]) - def tryAwaitUntil(nanoDeadline: Long): Boolean = { - if (triggered) { - true - } else if (nanoDeadline == Long.MaxValue) { - blocking { acquireSharedInterruptibly(1) } - true - } else { - val remaining = nanoDeadline - System.nanoTime - remaining > 0 && blocking { tryAcquireSharedNanos(1, remaining) } - } - } - - private[WakeupManager] def trigger() { releaseShared(1) } - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/impl/AlternativeResult.scala b/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/impl/AlternativeResult.scala deleted file mode 100644 index 81479e40..00000000 --- a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/impl/AlternativeResult.scala +++ /dev/null @@ -1,9 +0,0 @@ -/* scala-stm - (c) 2009-2011, Stanford University, PPL */ - -package scala.concurrent.stm -package impl - -import util.control.ControlThrowable - -/** See `PendingAtomicBlock` */ -private[stm] case class AlternativeResult(value: Any) extends ControlThrowable diff --git a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/impl/RefFactory.scala b/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/impl/RefFactory.scala deleted file mode 100644 index 18a91dd3..00000000 --- a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/impl/RefFactory.scala +++ /dev/null @@ -1,42 +0,0 @@ -/* scala-stm - (c) 2009-2010, Stanford University, PPL */ - -package scala.concurrent.stm -package impl - -import scala.collection.mutable.Builder - -/** `RefFactory` is responsible for creating concrete `Ref` instances. */ -trait RefFactory { - def newRef(v0: Boolean): Ref[Boolean] - def newRef(v0: Byte): Ref[Byte] - def newRef(v0: Short): Ref[Short] - def newRef(v0: Char): Ref[Char] - def newRef(v0: Int): Ref[Int] - def newRef(v0: Float): Ref[Float] - def newRef(v0: Long): Ref[Long] - def newRef(v0: Double): Ref[Double] - def newRef(v0: Unit): Ref[Unit] - - /** `T` will not be one of the primitive types (for which a `newRef` - * specialization exists). - */ - def newRef[A : ClassManifest](v0: A): Ref[A] - - def newTxnLocal[A](init: => A, - initialValue: InTxn => A, - beforeCommit: InTxn => Unit, - whilePreparing: InTxnEnd => Unit, - whileCommitting: InTxnEnd => Unit, - afterCommit: A => Unit, - afterRollback: Txn.Status => Unit, - afterCompletion: Txn.Status => Unit): TxnLocal[A] - - def newTArray[A : ClassManifest](length: Int): TArray[A] - def newTArray[A : ClassManifest](xs: TraversableOnce[A]): TArray[A] - - def newTMap[A, B]: TMap[A, B] - def newTMapBuilder[A, B]: Builder[(A, B), TMap[A, B]] - - def newTSet[A]: TSet[A] - def newTSetBuilder[A]: Builder[A, TSet[A]] -} diff --git a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/impl/STMImpl.scala b/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/impl/STMImpl.scala deleted file mode 100644 index e1ab8701..00000000 --- a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/impl/STMImpl.scala +++ /dev/null @@ -1,135 +0,0 @@ -/* scala-stm - (c) 2009-2012, Stanford University, PPL */ - -package scala.concurrent.stm -package impl - -import java.util.concurrent.TimeUnit - -private[impl] object STMImplHolder { - var instance: STMImpl = STMImpl.createInstance() -} - -/** `STMImpl` gathers all of the functionality required to plug an STM - * implementation into `scala.concurrent.stm`. Only one implementation can - * be selected, because `Ref`s and atomic blocks from different STM - * implementations are not compatible. `STMImpl.instance` returns the - * `STMImpl` instance that has been selected for this program execution. - * - * There are two ways to explicitly select the `STMImpl` instance: - * - * 1. set the JVM system property "scala.stm.impl" to the name of a class - * that implements `STMImpl`; or - * - * 2. arrange for `STMImpl.select` or `STMImpl.trySelect` to be called - * before any `Ref`s are constructed and before any atomic blocks are - * executed. - * - * Setting the JVM system property "scala.stm.impl" is equivalent to making a - * call to `STMImpl.select(System.getProperty("scala.stm.impl"))` before any - * other `STMImpl` selections. - * - * If there is no explicitly selected `STMImpl` instance and the classpath - * contains a class `scala.concurrent.stm.impl.DefaultFactory` that extends - * `scala.concurrent.stm.impl.STMImpl.Factory`, then an instance of that - * class will be instantiated and used to generate the `STMImpl` instance. - * ScalaSTM implementations are encouraged to implement `DefaultFactory` so - * that if a user includes the implementation's JAR file, it will be - * automatically selected. - * - * If no explicit selection has been made and there is no definition of - * `scala.concurrent.stm.impl.DefaultFactory` present in the classpath, then - * ScalaSTM will fall back to the reference implementation - * "scala.concurrent.stm.ccstm.CCSTM". - * - * @author Nathan Bronson - */ -object STMImpl { - trait Factory { - def createInstance(): STMImpl - } - - /** Returns the instance of `STMImpl` that should be used to implement all - * ScalaSTM functionality. Calling this method forces the implementation - * to be chosen if it has not already been selected. - */ - def instance: STMImpl = STMImplHolder.instance - - // We duplicate the implementation of select() to avoid the need to - // instantiate an STM that we won't end up using - - /** If no `STMImpl` instance has yet been selected, installs an instance of - * `Class.forName(implClassName)` as the system-wide STM implementation. - * Returns true if `implClassName` was newly or previously selected, or - * returns false if another STM implementation was chosen. - */ - def trySelect(implClassName: String): Boolean = { - explicitChoice = implClassName - instance.getClass.getName == implClassName - } - - /** Installs `Class.forName(implClassName)` as the system-wide STM - * implementation if no `STMImpl` has yet been chosen, or verifies that - * `implClassName` was previously selected, throwing - * `IllegalStateException` if a different STM implementation has already - * been selected - */ - def select(implClassName: String) { - if (!trySelect(implClassName)) { - throw new IllegalStateException( - "unable to select STMImpl class " + implClassName + ", " + instance + " already installed"); - } - } - - /** Installs `impl` as the system-wide STM implementation if no `STMImpl` - * has yet been chosen, or verifies that `impl` is equal to the previously - * selected instance, throwing `IllegalStateException` if an STM - * implementation has already been selected and `impl != instance` - */ - def select(impl: STMImpl) { - explicitChoice = impl - if (impl != instance) { - throw new IllegalStateException( - "unable to select STMImpl " + impl + ", " + instance + " already installed"); - } - } - - - /** May be a String class name, an STMImpl, or null */ - @volatile private var explicitChoice: AnyRef = null - - private[impl] def createInstance(): STMImpl = { - var choice: AnyRef = System.getProperty("scala.stm.impl") - - if (choice == null) - choice = explicitChoice - - if (choice == null) { - choice = (try { - val fc = Class.forName("scala.concurrent.stm.impl.DefaultFactory") - fc.newInstance().asInstanceOf[STMImpl.Factory].createInstance() - } catch { - case _: ClassNotFoundException => "scala.concurrent.stm.ccstm.CCSTM" - }) - } - - choice match { - case s: String => Class.forName(s).newInstance().asInstanceOf[STMImpl] - case i: STMImpl => i - } - } -} - -/** `STMImpl` gathers all of the functionality required to plug an STM - * implementation into `scala.concurrent.stm`. See the `STMImpl` companion - * object for information on controlling which `STMImpl` is selected at run - * time. - * - * @author Nathan Bronson - */ -trait STMImpl extends RefFactory with TxnContext with TxnExecutor { - - /** Returns a new commit barrier suitable for coordinating commits by this - * STM implementation. - */ - def newCommitBarrier(timeout: Long, unit: TimeUnit): CommitBarrier -} diff --git a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/impl/TxnContext.scala b/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/impl/TxnContext.scala deleted file mode 100644 index 87970084..00000000 --- a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/impl/TxnContext.scala +++ /dev/null @@ -1,24 +0,0 @@ -/* scala-stm - (c) 2009-2010, Stanford University, PPL */ - -package scala.concurrent.stm -package impl - -/** `TxnContext` captures the implementation-specific functionality of locating - * the `InTxn` dynamically bound to the current `Thread`. Users should use the - * lookup methods provided by `object Txn`. - * - * @author Nathan Bronson - */ -trait TxnContext { - - /** Returns `Some(txn)` if `txn` is the `InTxn` active or in the process of - * committing on the current thread, `None` otherwise. - */ - def findCurrent(implicit mt: MaybeTxn): Option[InTxn] - - /** Returns the current `InTxn` instance if it is active or in the process of - * committing on the current thread, `null` otherwise. Always performs a - * dynamic lookup. - */ - def dynCurrentOrNull: InTxn -} diff --git a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/japi/STM.scala b/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/japi/STM.scala deleted file mode 100644 index 0261581d..00000000 --- a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/japi/STM.scala +++ /dev/null @@ -1,188 +0,0 @@ -/* scala-stm - (c) 2009-2014, Stanford University, PPL */ - -package scala.concurrent.stm.japi - -import java.util.concurrent.{ Callable, TimeUnit } -import java.util.{ List ⇒ JList, Map ⇒ JMap, Set ⇒ JSet } -import scala.collection.JavaConversions -import scala.concurrent.stm -import scala.concurrent.stm._ - -private[japi] object STMHelpers { - // The anonymous classes generated by Scala 2.8.2 from inside a method with - // a type parameter are not digestible by Java, so hide them here to make - // sure they won't be included by: - // - // static import scala.concurrent.stm.japi.STM.*; - // - // Also, scala.Function1 is difficult to use from Java because Java won't - // automatically wire up all of the mix-in methods. A better option would - // be scala.runtime.AbstractFunction1, but there is no guarantee that the - // interface won't change (and Scala 2.8.2's version is not usable from - // Java). Instead, we define STM.Transformer that is basically just a - // Function1[A,A]. - - implicit def callableToAtomicBlock[A <: AnyRef](f: Callable[A]): (InTxn => A) = { _ => f.call } - - implicit def transformerToFunction[A <: AnyRef](f: STM.Transformer[A]): (A => A) = { f(_) } -} - -/** - * Java-friendly API for ScalaSTM. - * These methods can also be statically imported. - */ -object STM { - import STMHelpers._ - - /** - * Create a Ref with an initial value. Return a `Ref.View`, which does not - * require implicit transactions. - * @param initialValue the initial value for the newly created `Ref.View` - * @return a new `Ref.View` - */ - def newRef[A](initialValue: A): Ref.View[A] = Ref(initialValue).single - - /** - * Create an empty TMap. Return a `TMap.View`, which does not require - * implicit transactions. See newMap for included java conversion. - * @return a new, empty `TMap.View` - */ - def newTMap[A, B](): TMap.View[A, B] = TMap.empty[A, B].single - - /** - * Create an empty TMap. Return a `java.util.Map` view of this TMap. - * @return a new, empty `TMap.View` wrapped as a `java.util.Map`. - */ - def newMap[A, B](): JMap[A, B] = JavaConversions.mutableMapAsJavaMap(newTMap[A, B]) - - /** - * Create an empty TSet. Return a `TSet.View`, which does not require - * implicit transactions. See newSet for included java conversion. - * @return a new, empty `TSet.View` - */ - def newTSet[A](): TSet.View[A] = TSet.empty[A].single - - /** - * Create an empty TSet. Return a `java.util.Set` view of this TSet. - * @return a new, empty `TSet.View` wrapped as a `java.util.Set`. - */ - def newSet[A](): JSet[A] = JavaConversions.mutableSetAsJavaSet(newTSet[A]) - - /** - * Create a TArray containing `length` elements. Return a `TArray.View`, - * which does not require implicit transactions. See newList for included - * java conversion. - * @param length the length of the `TArray.View` to be created - * @return a new `TArray.View` containing `length` elements (initially null) - */ - def newTArray[A <: AnyRef](length: Int): TArray.View[A] = TArray.ofDim[AnyRef](length).asInstanceOf[TArray[A]].single - - /** - * Create an empty TArray. Return a `java.util.List` view of this Array. - * @param length the length of the `TArray.View` to be created - * @return a new, empty `TArray.View` wrapped as a `java.util.List`. - */ - def newArrayAsList[A <: AnyRef](length: Int): JList[A] = JavaConversions.mutableSeqAsJavaList(newTArray[A](length)) - - /** - * Atomic block that takes a `Runnable`. - * @param runnable the `Runnable` to run within a transaction - */ - def atomic(runnable: Runnable): Unit = stm.atomic { txn ⇒ runnable.run } - - /** - * Atomic block that takes a `Callable`. - * @param callable the `Callable` to run within a transaction - * @return the value returned by the `Callable` - */ - def atomic[A <: AnyRef](callable: Callable[A]): A = stm.atomic(callable) - - /** - * Causes the enclosing transaction to back up and wait until one - * of the `Ref`s touched by this transaction has changed. - * @throws IllegalStateException if not in a transaction - */ - def retry(): Unit = Txn.findCurrent match { - case Some(txn) => Txn.retry(txn) - case None => throw new IllegalStateException("retry outside atomic") - } - - /** - * Like `retry`, but limits the total amount of blocking. This method - * only returns normally when the timeout has expired. - */ - def retryFor(timeoutMillis: Long): Unit = Txn.findCurrent match { - case Some(txn) => Txn.retryFor(timeoutMillis)(txn) - case None => throw new IllegalStateException("retry outside atomic") - } - - abstract class Transformer[A <: AnyRef] { - def apply(v: A): A - } - - /** - * Transform the value stored by `ref` by applying the function `f`. - * @param ref the `Ref.View` to be transformed - * @param f the function to be applied - */ - def transform[A <: AnyRef](ref: Ref.View[A], f: Transformer[A]): Unit = ref.transform(f) - - /** - * Transform the value stored by `ref` by applying the function `f` and - * return the old value. - * @param ref the `Ref.View` to be transformed - * @param f the function to be applied - * @return the old value of `ref` - */ - def getAndTransform[A <: AnyRef](ref: Ref.View[A], f: Transformer[A]): A = ref.getAndTransform(f) - - /** - * Transform the value stored by `ref` by applying the function `f` and - * return the new value. - * @param ref the `Ref.View` to be transformed - * @param f the function to be applied - * @return the new value of `ref` - */ - def transformAndGet[A <: AnyRef](ref: Ref.View[A], f: Transformer[A]): A = ref.transformAndGet(f) - - /** - * Increment the `java.lang.Integer` value of a `Ref.View`. - * @param ref the `Ref.View` to be incremented - * @param delta the amount to increment - */ - def increment(ref: Ref.View[java.lang.Integer], delta: Int): Unit = ref.transform { v ⇒ v.intValue + delta } - - /** - * Increment the `java.lang.Long` value of a `Ref.View`. - * @param ref the `Ref.View` to be incremented - * @param delta the amount to increment - */ - def increment(ref: Ref.View[java.lang.Long], delta: Long): Unit = ref.transform { v ⇒ v.longValue + delta } - - private def activeTxn = Txn.findCurrent match { - case Some(txn) => txn - case None => throw new IllegalStateException("not in a transaction") - } - - /** - * Add a task to run after the current transaction has committed. - * @param task the `Runnable` task to run after transaction commit - * @throws IllegalStateException if called from outside a transaction - */ - def afterCommit(task: Runnable): Unit = Txn.afterCommit(status ⇒ task.run)(activeTxn) - - /** - * Add a task to run after the current transaction has rolled back. - * @param task the `Runnable` task to run after transaction rollback - * @throws IllegalStateException if called from outside a transaction - */ - def afterRollback(task: Runnable): Unit = Txn.afterRollback(status ⇒ task.run)(activeTxn) - - /** - * Add a task to run after the current transaction has either rolled back - * or committed. - * @param task the `Runnable` task to run after transaction completion - * @throws IllegalStateException if called from outside a transaction - */ - def afterCompletion(task: Runnable): Unit = Txn.afterCompletion(status ⇒ task.run)(activeTxn) -} diff --git a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/package.scala b/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/package.scala deleted file mode 100644 index b118e3f1..00000000 --- a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/package.scala +++ /dev/null @@ -1,24 +0,0 @@ -/* scala-stm - (c) 2009-2012, Stanford University, PPL */ - -package scala.concurrent - -import java.util.concurrent.TimeUnit - -package object stm { - - /** Atomically executes atomic blocks using the default `TxnExecutor`. See - * `TxnExecutor.apply`. - */ - def atomic: scala.concurrent.stm.TxnExecutor = scala.concurrent.stm.TxnExecutor.defaultAtomic - - /** Equivalent to `Txn.retry`. */ - def retry(implicit txn: scala.concurrent.stm.InTxn): Nothing = scala.concurrent.stm.Txn.retry - - /** Equivalent to `Txn.retryFor(timeout, unit)`. */ - def retryFor(timeout: Long, unit: TimeUnit = TimeUnit.MILLISECONDS)(implicit txn: scala.concurrent.stm.InTxn) { - scala.concurrent.stm.Txn.retryFor(timeout, unit) - } - - /** This is the first half of the machinery for implementing `orAtomic`. */ - implicit def wrapChainedAtomic[A](lhs: => A) = new scala.concurrent.stm.PendingAtomicBlock(lhs) -} diff --git a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/skel/AbstractInTxn.scala b/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/skel/AbstractInTxn.scala deleted file mode 100644 index d3bcc27d..00000000 --- a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/skel/AbstractInTxn.scala +++ /dev/null @@ -1,262 +0,0 @@ -/* scala-stm - (c) 2009-2012, Stanford University, PPL */ - -package scala.concurrent.stm -package skel - -import annotation.tailrec - -private[stm] trait AbstractInTxn extends InTxn { - import Txn._ - - /** This is different from `currentLevel` so that `InTxn` instances can - * assume that the return value from `topLevel` is not exposed to the user. - */ - protected def internalCurrentLevel: AbstractNestingLevel - - //////////// implementation of functionality for the InTxn implementer - - protected def requireActive() { - internalCurrentLevel.status match { - case Active => - case RolledBack(_) => throw RollbackError - case s => throw new IllegalStateException(s.toString) - } - } - - protected def requireNotDecided() { - internalCurrentLevel.status match { - case s if !s.decided => - case RolledBack(_) => throw RollbackError - case s => throw new IllegalStateException(s.toString) - } - } - - protected def requireNotCompleted() { - internalCurrentLevel.status match { - case s if !s.completed => - case RolledBack(_) => throw RollbackError - case s => throw new IllegalStateException(s.toString) - } - } - - private var _decider: ExternalDecider = null - protected def externalDecider = _decider - - /** Set to true if any callbacks are registered. */ - private var _callbacksPresent = false - - private val _beforeCommitList = new CallbackList[InTxn] - private val _whileValidatingList = new CallbackList[NestingLevel] - private val _whilePreparingList = new CallbackList[InTxnEnd] - private val _whileCommittingList = new CallbackList[InTxnEnd] - private val _afterCommitList = new CallbackList[Status] - private val _afterRollbackList = new CallbackList[Status] - - /** Returns true if there are while-preparing handlers, while-committing - * handlers, or an external decider. - */ - protected def writeResourcesPresent: Boolean = _callbacksPresent && writeResourcesPresentImpl - - private def writeResourcesPresentImpl: Boolean = { - !_whilePreparingList.isEmpty || !_whileCommittingList.isEmpty || externalDecider != null - } - - protected def fireBeforeCommitCallbacks() { - if (_callbacksPresent) - _beforeCommitList.fire(internalCurrentLevel, this) - } - - protected def fireWhilePreparingCallbacks() { - if (_callbacksPresent && !_whilePreparingList.isEmpty) - _whilePreparingList.fire(internalCurrentLevel, this) - } - - protected def fireWhileCommittingCallbacks(exec: TxnExecutor): Throwable = { - if (_callbacksPresent && !_whileCommittingList.isEmpty) - fireWhileCommittingCallbacksImpl(exec) - else - null - } - - private def fireWhileCommittingCallbacksImpl(exec: TxnExecutor): Throwable = { - var failure: Throwable = null - var i = 0 - while (i < _whileCommittingList.size) { - failure = firePostDecision(_whileCommittingList(i), this, exec, Txn.Committing, failure) - i += 1 - } - failure - } - - protected def fireAfterCompletionAndThrow(handlers: Array[Status => Unit], exec: TxnExecutor, s: Status, pendingFailure: Throwable) { - val f = if (handlers != null) fireAfterCompletion(handlers, exec, s, pendingFailure) else pendingFailure - if (f != null) - throw f - } - - protected def fireAfterCompletion(handlers: Array[Status => Unit], exec: TxnExecutor, s: Status, f0: Throwable): Throwable = { - var failure = f0 - var i = 0 - val inOrder = s eq Committed - var j = if (inOrder) 0 else handlers.length - 1 - var dj = if (inOrder) 1 else -1 - while (i < handlers.length) { - failure = firePostDecision(handlers(j), s, exec, s, failure) - i += 1 - j += dj - } - failure - } - - private def firePostDecision[A](handler: A => Unit, arg: A, exec: TxnExecutor, s: Status, f: Throwable): Throwable = { - try { - handler(arg) - f - } catch { - case x: Throwable => { - try { - exec.postDecisionFailureHandler(s, x) - f - } catch { - case xx: Throwable => xx - } - } - } - } - - protected def checkpointCallbacks() { - if (_callbacksPresent) - checkpointCallbacksImpl() - } - - private def checkpointCallbacksImpl() { - val level = internalCurrentLevel - level._beforeCommitSize = _beforeCommitList.size - level._whileValidatingSize = _whileValidatingList.size - level._whilePreparingSize = _whilePreparingList.size - level._whileCommittingSize = _whileCommittingList.size - level._afterCommitSize = _afterCommitList.size - level._afterRollbackSize = _afterRollbackList.size - } - - /** Returns the discarded `afterRollbackList` entries, or null if none */ - protected def rollbackCallbacks(): Array[Status => Unit] = { - if (!_callbacksPresent) null else rollbackCallbacksImpl() - } - - private def rollbackCallbacksImpl(): Array[Status => Unit] = { - val level = internalCurrentLevel - _beforeCommitList.size = level._beforeCommitSize - _whileValidatingList.size = level._whileValidatingSize - _whilePreparingList.size = level._whilePreparingSize - _whileCommittingList.size = level._whileCommittingSize - _afterCommitList.size = level._afterCommitSize - _afterRollbackList.truncate(level._afterRollbackSize) - } - - /** Returns the discarded `afterCommitList` entries, or null if none. */ - protected def resetCallbacks(): Array[Status => Unit] = { - if (!_callbacksPresent) null else resetCallbacksImpl() - } - - private def resetCallbacksImpl(): Array[Status => Unit] = { - _beforeCommitList.size = 0 - _whileValidatingList.size = 0 - _whilePreparingList.size = 0 - _whileCommittingList.size = 0 - _afterRollbackList.size = 0 - _afterCommitList.truncate(0) - } - - protected def fireWhileValidating() { - val n = _whileValidatingList.size - if (n > 0) - fireWhileValidating(n - 1, internalCurrentLevel) - } - - @tailrec private def fireWhileValidating(i: Int, level: AbstractNestingLevel) { - if (i >= 0) { - if (i < level._whileValidatingSize) - fireWhileValidating(i, level.parLevel) - else if (level.status.isInstanceOf[Txn.RolledBack]) - fireWhileValidating(level._whileValidatingSize - 1, level.parLevel) // skip the rest at this level - else { - try { - _whileValidatingList(i)(level) - } catch { - case x: Throwable => level.requestRollback(UncaughtExceptionCause(x)) - } - fireWhileValidating(i - 1, level) - } - } - } - - //////////// implementation of functionality for the InTxn user - - override def rootLevel: AbstractNestingLevel = internalCurrentLevel.root - - def beforeCommit(handler: InTxn => Unit) { - requireActive() - _callbacksPresent = true - _beforeCommitList += handler - } - - def whileValidating(handler: NestingLevel => Unit) { - requireActive() - _callbacksPresent = true - _whileValidatingList += handler - } - - def whilePreparing(handler: InTxnEnd => Unit) { - requireNotDecided() - _callbacksPresent = true - _whilePreparingList += handler - } - - def whileCommitting(handler: InTxnEnd => Unit) { - requireNotCompleted() - _callbacksPresent = true - _whileCommittingList += handler - } - - def afterCommit(handler: Status => Unit) { - requireNotCompleted() - _callbacksPresent = true - _afterCommitList += handler - } - - def afterRollback(handler: Status => Unit) { - try { - requireNotCompleted() - } catch { - case RollbackError => { - handler(internalCurrentLevel.status) - throw RollbackError - } - } - _callbacksPresent = true - _afterRollbackList += handler - } - - def afterCompletion(handler: Status => Unit) { - afterRollback(handler) - _afterCommitList += handler - } - - def setExternalDecider(decider: ExternalDecider) { - if (status.decided) - throw new IllegalArgumentException("can't set ExternalDecider after decision, status = " + status) - - if (_decider != null) { - if (_decider != decider) - throw new IllegalArgumentException("can't set two different ExternalDecider-s in the same top-level atomic block") - } else { - _decider = decider - // the decider should be unregistered after either rollback or commit - afterCompletion { status => - assert(_decider eq decider) - _decider = null - } - } - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/skel/AbstractNestingLevel.scala b/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/skel/AbstractNestingLevel.scala deleted file mode 100644 index 85f0c5d4..00000000 --- a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/skel/AbstractNestingLevel.scala +++ /dev/null @@ -1,21 +0,0 @@ -/* scala-stm - (c) 2009-2010, Stanford University, PPL */ - -package scala.concurrent.stm -package skel - -private[stm] trait AbstractNestingLevel extends NestingLevel { - import Txn._ - - def txn: AbstractInTxn - def parLevel: AbstractNestingLevel - override def root: AbstractNestingLevel - - def parent: Option[NestingLevel] = Option(parLevel) - - private[skel] var _beforeCommitSize = 0 - private[skel] var _whileValidatingSize = 0 - private[skel] var _whilePreparingSize = 0 - private[skel] var _whileCommittingSize = 0 - private[skel] var _afterCommitSize = 0 - private[skel] var _afterRollbackSize = 0 -} diff --git a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/skel/AtomicArray.scala b/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/skel/AtomicArray.scala deleted file mode 100644 index d688afbe..00000000 --- a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/skel/AtomicArray.scala +++ /dev/null @@ -1,272 +0,0 @@ -/* scala-stm - (c) 2009-2014, Stanford University, PPL */ - -package scala.concurrent.stm.skel - -import scala.collection.generic.CanBuildFrom -import scala.collection.mutable.{WrappedArray, Builder, ArrayLike, IndexedSeq} -import java.util.concurrent.atomic._ -import annotation.tailrec - - -/** `AtomicArray` implements a fixed-length indexed sequence where reads and - * writes have volatile semantics. In addition, it adds an atomic swap - * operation (`swap`) and an atomic compare-and-swap (`compareAndSet`). - * The collection is backed by one of the Java atomic array classes, with the - * best match chosen at construction time using a manifest. - * - * Instances of `AtomicArray[T]` are backed by `AtomicIntegerArray` if `T` is - * a primitive of at most 32 bits (smaller values are padded rather than - * packed). `AtomicArray[Long]` and `AtomicArray[Double]` are backed by - * `AtomicLongArray`. All other instances of `AtomicArray[T]` are backed by - * `AtomicReferenceArray` (except for `AtomicArray[Unit]`). Floats and - * doubles are stored using their raw bit representation. - * - * This class is used in the implementation of the reference STM - * implementation, but it is standalone and may be generally useful. - * - * @author Nathan Bronson - */ -abstract class AtomicArray[T] extends IndexedSeq[T] with ArrayLike[T, AtomicArray[T]] { - - // We choose to store Boolean-s (and other small primitives) each in their - // own Int. This wastes space. Another option would be to pack values into - // the elements of the underlying AtomicIntegerArray. This would save space, - // but would require a compareAndSet loop to implement update, which adds - // complexity and would require some sort of back-off scheme to avoid - // live-lock. A third option would be to use sun.misc.Unsafe directly, in - // which case volatile reads and writes of byte-sized memory locations can be - // performed directly. compareAndSet of bytes would have to be emulated by - // integer-sized CAS. - - override protected[this] def thisCollection: AtomicArray[T] = this - override protected[this] def toCollection(repr: AtomicArray[T]): AtomicArray[T] = repr - - /** The length of the array */ - def length: Int - - /** The element at given index, with volatile read semantics */ - def apply(index: Int): T - - /** Update element at given index, with volatile write semantics */ - def update(index: Int, elem: T) - - /** Atomic swap of the element at index */ - def swap(index: Int, elem: T): T - - /** Returns true iff previous value was expected, elem installed */ - def compareAndSet(index: Int, expected: T, elem: T): Boolean - - /** Retries compareAndSet until success, using f, then returns the old value */ - @tailrec - final def getAndTransform(index: Int)(f: T => T): T = { - val before = apply(index) - if (compareAndSet(index, before, f(before))) before else getAndTransform(index)(f) - } - - override def stringPrefix = "AtomicArray" - - /** Clones this object, including the underlying Array. */ - override def clone: AtomicArray[T] = { - val b = newBuilder - b.sizeHint(length) - b ++= this - b.result() - } - - override def newBuilder: AtomicArrayBuilder[T] = throw new AbstractMethodError -} - -object AtomicArray { - - def apply[T](size: Int)(implicit m: ClassManifest[T]): AtomicArray[T] = { - (m.newArray(0).asInstanceOf[AnyRef] match { - case x: Array[Boolean] => new ofBoolean(size) - case x: Array[Byte] => new ofByte(size) - case x: Array[Short] => new ofShort(size) - case x: Array[Char] => new ofChar(size) - case x: Array[Int] => new ofInt(size) - case x: Array[Float] => new ofFloat(size) - case x: Array[Long] => new ofLong(size) - case x: Array[Double] => new ofDouble(size) - case x: Array[Unit] => new ofUnit(size) - case x: Array[AnyRef] => new ofRef[AnyRef](size) - }).asInstanceOf[AtomicArray[T]] - } - - def apply(elems: Array[Boolean]) = new ofBoolean(new AtomicIntegerArray(elems map {if(_) 1 else 0})) - def apply(elems: Array[Byte]) = new ofByte( new AtomicIntegerArray(elems map {_.toInt})) - def apply(elems: Array[Short]) = new ofShort( new AtomicIntegerArray(elems map {_.toInt})) - def apply(elems: Array[Char]) = new ofChar( new AtomicIntegerArray(elems map {_.toInt})) - def apply(elems: Array[Int]) = new ofInt( new AtomicIntegerArray(elems)) - def apply(elems: Array[Float]) = new ofFloat( new AtomicIntegerArray(elems map {java.lang.Float.floatToRawIntBits(_)})) - def apply(elems: Array[Long]) = new ofLong( new AtomicLongArray(elems)) - def apply(elems: Array[Double]) = new ofDouble( new AtomicLongArray(elems map {java.lang.Double.doubleToRawLongBits(_)})) - def apply(elems: Array[Unit]) = new ofUnit( elems.length) - def apply[T <: AnyRef](elems: Array[T]) = - new ofRef((new AtomicReferenceArray(elems.asInstanceOf[Array[AnyRef]])).asInstanceOf[AtomicReferenceArray[T]]) - - def apply[T](elems: TraversableOnce[T])(implicit m: ClassManifest[T]): AtomicArray[T] = { - val array: AnyRef = (elems match { - case w: WrappedArray[_] => w.array // we're going to copy out regardless, no need to duplicate right now - case _ => elems.toArray - }) - val result = (array match { - case x: Array[Boolean] => apply(x) - case x: Array[Byte] => apply(x) - case x: Array[Short] => apply(x) - case x: Array[Char] => apply(x) - case x: Array[Int] => apply(x) - case x: Array[Float] => apply(x) - case x: Array[Long] => apply(x) - case x: Array[Double] => apply(x) - case x: Array[Unit] => apply(x) - case x: Array[AnyRef] => apply(x) - }) - result.asInstanceOf[AtomicArray[T]] - } - - - implicit def canBuildFrom[T](implicit m: ClassManifest[T]): CanBuildFrom[AtomicArray[_], T, AtomicArray[T]] = { - new CanBuildFrom[AtomicArray[_], T, AtomicArray[T]] { - def apply(from: AtomicArray[_]): Builder[T, AtomicArray[T]] = { - val b = AtomicArrayBuilder of m - b.sizeHint(from.length) - b - } - def apply(): Builder[T, AtomicArray[T]] = AtomicArrayBuilder of m - } - } - - - final class ofBoolean(elems: AtomicIntegerArray) extends AtomicArray[Boolean] { - def this(size: Int) = this(new AtomicIntegerArray(size)) - - private def decode(v: Int) = v != 0 - private def encode(elem: Boolean) = if (elem) 1 else 0 - - def length = elems.length - def apply(index: Int) = decode(elems.get(index)) - def update(index: Int, elem: Boolean): Unit = elems.set(index, encode(elem)) - def swap(index: Int, elem: Boolean) = decode(elems.getAndSet(index, encode(elem))) - def compareAndSet(index: Int, expected: Boolean, elem: Boolean) = - elems.compareAndSet(index, encode(expected), encode(elem)) - override def newBuilder = new AtomicArrayBuilder.ofBoolean - } - - final class ofByte(elems: AtomicIntegerArray) extends AtomicArray[Byte] { - def this(size: Int) = this(new AtomicIntegerArray(size)) - - def length = elems.length - def apply(index: Int) = elems.get(index).toByte - def update(index: Int, elem: Byte): Unit = elems.set(index, elem) - def swap(index: Int, elem: Byte) = elems.getAndSet(index, elem).toByte - def compareAndSet(index: Int, expected: Byte, elem: Byte) = - elems.compareAndSet(index, expected, elem) - override def newBuilder = new AtomicArrayBuilder.ofByte - } - - final class ofShort(elems: AtomicIntegerArray) extends AtomicArray[Short] { - def this(size: Int) = this(new AtomicIntegerArray(size)) - - def length = elems.length - def apply(index: Int) = elems.get(index).toShort - def update(index: Int, elem: Short): Unit = elems.set(index, elem) - def swap(index: Int, elem: Short) = elems.getAndSet(index, elem).toShort - def compareAndSet(index: Int, expected: Short, elem: Short) = - elems.compareAndSet(index, expected, elem) - override def newBuilder = new AtomicArrayBuilder.ofShort - } - - final class ofChar(elems: AtomicIntegerArray) extends AtomicArray[Char] { - def this(size: Int) = this(new AtomicIntegerArray(size)) - - def length = elems.length - def apply(index: Int) = elems.get(index).toChar - def update(index: Int, elem: Char): Unit = elems.set(index, elem) - def swap(index: Int, elem: Char) = elems.getAndSet(index, elem).toChar - def compareAndSet(index: Int, expected: Char, elem: Char) = - elems.compareAndSet(index, expected, elem) - override def newBuilder = new AtomicArrayBuilder.ofChar - } - - final class ofInt(elems: AtomicIntegerArray) extends AtomicArray[Int] { - def this(size: Int) = this(new AtomicIntegerArray(size)) - - def length = elems.length - def apply(index: Int) = elems.get(index) - def update(index: Int, elem: Int): Unit = elems.set(index, elem) - def swap(index: Int, elem: Int) = elems.getAndSet(index, elem) - def compareAndSet(index: Int, expected: Int, elem: Int) = - elems.compareAndSet(index, expected, elem) - override def newBuilder = new AtomicArrayBuilder.ofInt - } - - final class ofFloat(elems: AtomicIntegerArray) extends AtomicArray[Float] { - def this(size: Int) = this(new AtomicIntegerArray(size)) - - private def decode(v: Int) = java.lang.Float.intBitsToFloat(v) - private def encode(elem: Float) = java.lang.Float.floatToRawIntBits(elem) - - def length = elems.length - def apply(index: Int) = decode(elems.get(index)) - def update(index: Int, elem: Float): Unit = elems.set(index, encode(elem)) - def swap(index: Int, elem: Float) = decode(elems.getAndSet(index, encode(elem))) - def compareAndSet(index: Int, expected: Float, elem: Float) = - elems.compareAndSet(index, encode(expected), encode(elem)) - override def newBuilder = new AtomicArrayBuilder.ofFloat - } - - final class ofLong(elems: AtomicLongArray) extends AtomicArray[Long] { - def this(size: Int) = this(new AtomicLongArray(size)) - - def length = elems.length - def apply(index: Int) = elems.get(index) - def update(index: Int, elem: Long): Unit = elems.set(index, elem) - def swap(index: Int, elem: Long) = elems.getAndSet(index, elem) - def compareAndSet(index: Int, expected: Long, elem: Long) = - elems.compareAndSet(index, expected, elem) - override def newBuilder = new AtomicArrayBuilder.ofLong - } - - final class ofDouble(elems: AtomicLongArray) extends AtomicArray[Double] { - def this(size: Int) = this(new AtomicLongArray(size)) - - private def decode(v: Long) = java.lang.Double.longBitsToDouble(v) - private def encode(elem: Double) = java.lang.Double.doubleToRawLongBits(elem) - - def length = elems.length - def apply(index: Int) = decode(elems.get(index)) - def update(index: Int, elem: Double): Unit = elems.set(index, encode(elem)) - def swap(index: Int, elem: Double) = decode(elems.getAndSet(index, encode(elem))) - def compareAndSet(index: Int, expected: Double, elem: Double) = - elems.compareAndSet(index, encode(expected), encode(elem)) - override def newBuilder = new AtomicArrayBuilder.ofDouble - } - - final class ofUnit(val length: Int) extends AtomicArray[Unit] { - private val dummy = new AtomicReference[Unit](()) - - private def ref(index: Int): AtomicReference[Unit] = { - if (index < 0 || index >= length) - throw new IndexOutOfBoundsException - dummy - } - - def apply(index: Int) = ref(index).get - def update(index: Int, elem: Unit): Unit = ref(index).set(elem) - def swap(index: Int, elem: Unit) = ref(index).getAndSet(elem) - def compareAndSet(index: Int, expected: Unit, elem: Unit) = ref(index).compareAndSet(expected, elem) - override def newBuilder = new AtomicArrayBuilder.ofUnit - } - - final class ofRef[T <: AnyRef](elems: AtomicReferenceArray[T]) extends AtomicArray[T] { - def this(size: Int) = this(new AtomicReferenceArray[T](size)) - - def length = elems.length - def apply(index: Int) = elems.get(index) - def update(index: Int, elem: T): Unit = elems.set(index, elem) - def swap(index: Int, elem: T) = elems.getAndSet(index, elem) - def compareAndSet(index: Int, expected: T, elem: T) = elems.compareAndSet(index, expected, elem) - override def newBuilder = new AtomicArrayBuilder.ofRef[T] - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/skel/AtomicArrayBuilder.scala b/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/skel/AtomicArrayBuilder.scala deleted file mode 100644 index b3eedf1e..00000000 --- a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/skel/AtomicArrayBuilder.scala +++ /dev/null @@ -1,240 +0,0 @@ -/* scala-stm - (c) 2009-2011, Stanford University, PPL */ - -package scala.concurrent.stm.skel - -import scala.collection.mutable.Builder -import java.util.concurrent.atomic.{AtomicReferenceArray, AtomicLongArray, AtomicIntegerArray} - -trait AtomicArrayBuilder[A] extends Builder[A, AtomicArray[A]] - -object AtomicArrayBuilder { - def of[T](m: ClassManifest[T]): Builder[T, AtomicArray[T]] = { - (m.newArray(0).asInstanceOf[AnyRef] match { - case x: Array[Boolean] => new ofBoolean - case x: Array[Byte] => new ofByte - case x: Array[Short] => new ofShort - case x: Array[Char] => new ofChar - case x: Array[Int] => new ofInt - case x: Array[Float] => new ofFloat - case x: Array[Long] => new ofLong - case x: Array[Double] => new ofDouble - case x: Array[Unit] => new ofUnit - case x: Array[AnyRef] => new ofRef[AnyRef] - }).asInstanceOf[AtomicArrayBuilder[T]] - } - - private val EmptyIntArray = new Array[Int](0) - private val EmptyLongArray = new Array[Long](0) - private val EmptyRefArray = new Array[AnyRef](0) - - abstract class IntBacked[T] extends AtomicArrayBuilder[T] { - protected var elems = EmptyIntArray - protected var size: Int = 0 - - protected def setCapacity(newCap: Int) { - if (newCap != elems.length) { - val newElems = new Array[Int](newCap) - if (size > 0) Array.copy(elems, 0, newElems, 0, size) - elems = newElems - } - } - - override def sizeHint(sizeHint: Int) { - if (elems.length < sizeHint) setCapacity(sizeHint) - } - - protected def ensureSpace() { - val cap = elems.length - if (size == cap) setCapacity(if (cap == 0) 16 else cap * 2) - } - - def clear() { - size = 0 - } - } - - abstract class LongBacked[T] extends AtomicArrayBuilder[T] { - protected var elems = EmptyLongArray - protected var size: Int = 0 - - protected def setCapacity(newCap: Int) { - if (newCap != elems.length) { - val newElems = new Array[Long](newCap) - if (size > 0) Array.copy(elems, 0, newElems, 0, size) - elems = newElems - } - } - - override def sizeHint(sizeHint: Int) { - if (elems.length < sizeHint) setCapacity(sizeHint) - } - - protected def ensureSpace() { - val cap = elems.length - if (size == cap) setCapacity(if (cap == 0) 16 else cap * 2) - } - - def clear() { - size = 0 - } - } - - - class ofBoolean extends IntBacked[Boolean] { - def +=(elem: Boolean): this.type = { - ensureSpace() - elems(size) = if (elem) 1 else 0 - size += 1 - this - } - - def result(): AtomicArray[Boolean] = { - setCapacity(size) - new AtomicArray.ofBoolean(new AtomicIntegerArray(elems)) - } - } - - class ofByte extends IntBacked[Byte] { - def +=(elem: Byte): this.type = { - ensureSpace() - elems(size) = elem - size += 1 - this - } - - def result(): AtomicArray[Byte] = { - setCapacity(size) - new AtomicArray.ofByte(new AtomicIntegerArray(elems)) - } - } - - class ofShort extends IntBacked[Short] { - def +=(elem: Short): this.type = { - ensureSpace() - elems(size) = elem - size += 1 - this - } - - def result(): AtomicArray[Short] = { - setCapacity(size) - new AtomicArray.ofShort(new AtomicIntegerArray(elems)) - } - } - - class ofChar extends IntBacked[Char] { - def +=(elem: Char): this.type = { - ensureSpace() - elems(size) = elem - size += 1 - this - } - - def result(): AtomicArray[Char] = { - setCapacity(size) - new AtomicArray.ofChar(new AtomicIntegerArray(elems)) - } - } - - class ofInt extends IntBacked[Int] { - def +=(elem: Int): this.type = { - ensureSpace() - elems(size) = elem - size += 1 - this - } - - def result(): AtomicArray[Int] = { - setCapacity(size) - new AtomicArray.ofInt(new AtomicIntegerArray(elems)) - } - } - - class ofFloat extends IntBacked[Float] { - def +=(elem: Float): this.type = { - ensureSpace() - elems(size) = java.lang.Float.floatToRawIntBits(elem) - size += 1 - this - } - - def result(): AtomicArray[Float] = { - setCapacity(size) - new AtomicArray.ofFloat(new AtomicIntegerArray(elems)) - } - } - - class ofLong extends LongBacked[Long] { - def +=(elem: Long): this.type = { - ensureSpace() - elems(size) = elem - size += 1 - this - } - - def result(): AtomicArray[Long] = { - setCapacity(size) - new AtomicArray.ofLong(new AtomicLongArray(elems)) - } - } - - class ofDouble extends LongBacked[Double] { - def +=(elem: Double): this.type = { - ensureSpace() - elems(size) = java.lang.Double.doubleToRawLongBits(elem) - size += 1 - this - } - - def result(): AtomicArray[Double] = { - setCapacity(size) - new AtomicArray.ofDouble(new AtomicLongArray(elems)) - } - } - - class ofUnit extends AtomicArrayBuilder[Unit] { - protected var size = 0 - - def clear(): Unit = { size = 0 } - def +=(elem: Unit): this.type = { size += 1; this } - def result(): AtomicArray[Unit] = new AtomicArray.ofUnit(size) - } - - class ofRef[T <: AnyRef] extends AtomicArrayBuilder[T] { - protected var elems = EmptyRefArray - protected var size: Int = 0 - - protected def setCapacity(newCap: Int) { - if (newCap != elems.length) { - val newElems = new Array[AnyRef](newCap) - if (size > 0) Array.copy(elems, 0, newElems, 0, size) - elems = newElems - } - } - - override def sizeHint(sizeHint: Int) { - if (elems.length < sizeHint) setCapacity(sizeHint) - } - - protected def ensureSpace() { - val cap = elems.length - if (size == cap) setCapacity(if (cap == 0) 16 else cap * 2) - } - - def clear() { - size = 0 - } - - def +=(elem: T): this.type = { - ensureSpace() - elems(size) = elem - size += 1 - this - } - - def result(): AtomicArray[T] = { - setCapacity(size) - new AtomicArray.ofRef(new AtomicReferenceArray[AnyRef](elems).asInstanceOf[AtomicReferenceArray[T]]) - } - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/skel/CallbackList.scala b/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/skel/CallbackList.scala deleted file mode 100644 index 3bf48111..00000000 --- a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/skel/CallbackList.scala +++ /dev/null @@ -1,96 +0,0 @@ -/* scala-stm - (c) 2009-2012, Stanford University, PPL */ - -package scala.concurrent.stm -package skel - -import annotation.tailrec - - -private[stm] class CallbackList[A] { - - private final val InitialCapacity = 128 - private final val MaxEmptyCapacity = 8192 - - private var _size = 0 - private var _data = new Array[A => Unit](InitialCapacity) - - def isEmpty: Boolean = _size == 0 - - def size: Int = _size - - def size_= (newSize: Int) { - if (newSize != _size) - changeSize(newSize) - } - - private def changeSize(newSize: Int) { - if (newSize < 0 || newSize > _size) - throw new IllegalArgumentException - - if (newSize == 0 && _data.length > MaxEmptyCapacity) { - // reallocate if the array is too big, so that a single large txn doesn't - // permanently increase the memory footprint of this thread - reset() - } else { - java.util.Arrays.fill(_data.asInstanceOf[Array[AnyRef]], newSize, _size, null) - _size = newSize - } - } - - private def reset() { - _data = new Array[A => Unit](InitialCapacity) - _size = 0 - } - - def += (handler: A => Unit) { - if (_size == _data.length) - grow - _data(_size) = handler - _size += 1 - } - - private def grow() { - val a = new Array[A => Unit](_data.length * 2) - System.arraycopy(_data, 0, a, 0, _data.length) - _data = a - } - - def apply(i: Int): (A => Unit) = _data(i) - - def fire(level: NestingLevel, arg: A) { - if (_size > 0) - fire(level, arg, 0) - } - - @tailrec private def fire(level: NestingLevel, arg: A, i: Int) { - if (i < _size && shouldFire(level)) { - try { - _data(i)(arg) - } catch { - case x: Throwable => { - val s = level.requestRollback(Txn.UncaughtExceptionCause(x)) - assert(s.isInstanceOf[Txn.RolledBack]) - } - } - fire(level, arg, i + 1) - } - } - - private def shouldFire(level: NestingLevel): Boolean = !level.status.isInstanceOf[Txn.RolledBack] - - /** Sets the size of this callback list to `newSize`, and returns a the - * discarded handlers. - */ - def truncate(newSize: Int): Array[A => Unit] = { - if (_size == newSize) { - // nothing to do - null - } else { - // copy - val z = new Array[A => Unit](_size - newSize) - System.arraycopy(_data, newSize, z, 0, z.length) - size = newSize - z - } - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/skel/HashTrieTMap.scala b/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/skel/HashTrieTMap.scala deleted file mode 100644 index b43ceac2..00000000 --- a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/skel/HashTrieTMap.scala +++ /dev/null @@ -1,73 +0,0 @@ -/* scala-stm - (c) 2009-2011, Stanford University, PPL */ - -package scala.concurrent.stm -package skel - -import scala.collection.mutable.Builder - -private[stm] object HashTrieTMap { - - def empty[A, B]: TMap[A, B] = new HashTrieTMap(Ref(TxnHashTrie.emptyMapNode[A, B]).single) - - def newBuilder[A, B] = new Builder[(A, B), TMap[A, B]] { - var root = TxnHashTrie.emptyMapBuildingNode[A, B] - - def clear() { root = TxnHashTrie.emptyMapBuildingNode[A, B] } - - def += (kv: (A, B)): this.type = { root = TxnHashTrie.buildingPut(root, kv._1, kv._2) ; this } - - def result(): TMap[A, B] = { - val r = root - root = null - new HashTrieTMap(Ref(r.endBuild).single) - } - } -} - -private[skel] class HashTrieTMap[A, B] private (root0: Ref.View[TxnHashTrie.Node[A, B]] - ) extends TxnHashTrie[A, B](root0) with TMapViaClone[A, B] { - - //// construction - - override def empty: TMap.View[A, B] = new HashTrieTMap(Ref(TxnHashTrie.emptyMapNode[A, B]).single) - override def clone(): HashTrieTMap[A, B] = new HashTrieTMap(cloneRoot) - - //// TMap.View aggregates - - override def isEmpty: Boolean = singleIsEmpty - override def size: Int = singleSize - override def iterator: Iterator[(A, B)] = mapIterator - override def keysIterator: Iterator[A] = mapKeyIterator - override def valuesIterator: Iterator[B] = mapValueIterator - override def foreach[U](f: ((A, B)) => U) { singleMapForeach(f) } - - override def clear() { root() = TxnHashTrie.emptyMapNode[A, B] } - - //// TMap.View per-element - - override def contains(key: A): Boolean = singleContains(key) - override def apply(key: A): B = singleGetOrThrow(key) - def get(key: A): Option[B] = singleGet(key) - - override def put(key: A, value: B): Option[B] = singlePut(key, value) - override def update(key: A, value: B) { singlePut(key, value) } - override def += (kv: (A, B)): this.type = { singlePut(kv._1, kv._2) ; this } - - override def remove(key: A): Option[B] = singleRemove(key) - override def -= (key: A): this.type = { singleRemove(key) ; this } - - //// optimized TMap versions - - def isEmpty(implicit txn: InTxn): Boolean = txnIsEmpty - def size(implicit txn: InTxn): Int = singleSize - def foreach[U](f: ((A, B)) => U)(implicit txn: InTxn) = txnMapForeach(f) - - def contains(key: A)(implicit txn: InTxn): Boolean = txnContains(key) - def apply(key: A)(implicit txn: InTxn): B = txnGetOrThrow(key) - def get(key: A)(implicit txn: InTxn): Option[B] = txnGet(key) - def put(key: A, value: B)(implicit txn: InTxn): Option[B] = txnPut(key, value) - def remove(key: A)(implicit txn: InTxn): Option[B] = txnRemove(key) - - def transform(f: (A, B) => B)(implicit txn: InTxn): this.type = { single transform f ; this } - def retain(p: (A, B) => Boolean)(implicit txn: InTxn): this.type = { single retain p ; this } -} diff --git a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/skel/HashTrieTSet.scala b/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/skel/HashTrieTSet.scala deleted file mode 100644 index d54668b7..00000000 --- a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/skel/HashTrieTSet.scala +++ /dev/null @@ -1,64 +0,0 @@ -/* scala-stm - (c) 2009-2010, Stanford University, PPL */ - -package scala.concurrent.stm -package skel - -import scala.collection.mutable.Builder - -private[stm] object HashTrieTSet { - - def empty[A]: TSet[A] = new HashTrieTSet(Ref(TxnHashTrie.emptySetNode[A]).single) - - def newBuilder[A] = new Builder[A, TSet[A]] { - var root = TxnHashTrie.emptySetBuildingNode[A] - - def clear() { root = TxnHashTrie.emptySetBuildingNode[A] } - - def += (elem: A): this.type = { root = TxnHashTrie.buildingAdd(root, elem) ; this } - - def result(): TSet[A] = { - val r = root - root = null - new HashTrieTSet(Ref(r.endBuild).single) - } - } -} - -private[skel] class HashTrieTSet[A] private (root0: Ref.View[TxnHashTrie.SetNode[A]] - ) extends TxnHashTrie[A, AnyRef](root0) with TSetViaClone[A] { - - //// construction - - override def empty: TSet.View[A] = new HashTrieTSet(Ref(TxnHashTrie.emptySetNode[A]).single) - override def clone(): HashTrieTSet[A] = new HashTrieTSet(cloneRoot) - - //// TSet.View aggregates - - override def isEmpty: Boolean = singleIsEmpty - override def size: Int = singleSize - override def iterator: Iterator[A] = setIterator - override def foreach[U](f: A => U) { singleSetForeach(f) } - override def clear() { root() = TxnHashTrie.emptySetNode[A] } - - //// TSet.View per-element - - def contains(elem: A): Boolean = singleContains(elem) - - override def add(elem: A): Boolean = singlePut(elem, null).isEmpty - def += (elem: A): this.type = { singlePut(elem, null) ; this } - - override def remove(elem: A): Boolean = !singleRemove(elem).isEmpty - def -= (elem: A): this.type = { singleRemove(elem) ; this } - - //// optimized TSet versions - - def isEmpty(implicit txn: InTxn): Boolean = txnIsEmpty - def size(implicit txn: InTxn): Int = singleSize - def foreach[U](f: A => U)(implicit txn: InTxn) { txnSetForeach(f) } - - def contains(elem: A)(implicit txn: InTxn): Boolean = txnContains(elem) - def add(elem: A)(implicit txn: InTxn): Boolean = txnPut(elem, null ).isEmpty - def remove(elem: A)(implicit txn: InTxn): Boolean = !txnRemove(elem).isEmpty - - def retain(p: (A) => Boolean)(implicit txn: InTxn): this.type = { single retain p ; this } -} diff --git a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/skel/RollbackError.scala b/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/skel/RollbackError.scala deleted file mode 100644 index 91b70f1a..00000000 --- a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/skel/RollbackError.scala +++ /dev/null @@ -1,16 +0,0 @@ -/* scala-stm - (c) 2009-2010, Stanford University, PPL */ - -package scala.concurrent.stm.skel - -import util.control.ControlThrowable - - -/** A reusable exception instance, thrown by CCSTM when a transaction is doomed - * and should not continue executing. User code should either rethrow this - * exception or not catch it. - * - * @author Nathan Bronson - */ -private[stm] object RollbackError extends Error with ControlThrowable { - override def fillInStackTrace(): Throwable = this -} diff --git a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/skel/SimpleRandom.scala b/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/skel/SimpleRandom.scala deleted file mode 100644 index 4c66d4c8..00000000 --- a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/skel/SimpleRandom.scala +++ /dev/null @@ -1,120 +0,0 @@ -/* scala-stm - (c) 2009-2011, Stanford University, PPL */ - -package scala.concurrent.stm.skel - - -/** A random number generator that focuses on speed and lack of inter-thread - * interference, rather than on the quality of the numbers returned. The - * `object SimpleRandom` is striped internally to reduce - * contention when accessed from multiple threads. The `class - * SimpleRandom` should only be used by a single thread. - *

- * The constants in this 64-bit linear congruential random number generator - * are from http://nuclear.llnl.gov/CNP/rng/rngman/node4.html. - * - * @author Nathan Bronson - */ -object SimpleRandom { - // 64 byte cache lines are typical, so there are 8 slots per cache line. - // This means that the probability that any two threads have false sharing is - // p = 8 / #slots. If there are n processors, each of which is running 1 - // thread, then the probability that no other threads have false sharing with - // the current thread is (1-p)^(n-1). If p is small, that is about - // 1 - (n-1)p, which is pretty close to 1 - np. If we want the probability - // of false conflict for a thread to be less than k, then we need np < k, or - // p < k/n, or 8/Slots < k/n, or #slots > 8n/k. If we let k = 1/8, then we - // get #slots=64*n. - private val mask = { - val min = 64 * Runtime.getRuntime.availableProcessors - var slots = 1 - while (slots < min) slots *= 2 - slots - 1 - } - - private val states = Array.tabulate(mask + 1)({ _ * 0x123456789abcdefL }) - - /** Returns a random value chosen from a uniform distribution of all valid - * `Int`s. - */ - def nextInt(): Int = { - val id = (Thread.currentThread.getId.asInstanceOf[Int] * 13) & mask - - val next = step(states(id)) - states(id) = next - - extract(next) - } - - /** Returns a random value chosen from a uniform distribution of the - * non-negative integers less than `n`, or throws `IllegalArgumentException` - * if `n` is negative or zero. - */ - def nextInt(n: Int): Int = { - if (n <= 0) - throw new IllegalArgumentException - - var x = -1 - while (x == -1) x = tryClamp(nextInt(), n) - x - } - - private def step(x: Long) = x * 2862933555777941757L + 3037000493L - - private def extract(x: Long) = (x >> 30).asInstanceOf[Int] - - /** r is the random, returns -1 on failure. */ - private def tryClamp(r: Int, n: Int): Int = { - // get a positive number - val x = r & Int.MaxValue - - if ((n & -n) == n) { - // for powers of two, we use high bits instead of low bits - ((x.toLong * n) >> 31).toInt - } else { - val z = x % n - if (x - z + (n - 1) < 0) { - // x is bigger than floor(MAX_INT/n)*n, so we are not getting an even - // distribution. Try again. - -1 - } else { - z - } - } - } -} - -/** An clonable unsynchronized random number generator that uses the same - * algorithm as the concurrent `object SimpleRandom`. The caller must ensure - * that each `SimpleRandom` instance is used from only one thread at a time. - * - * @author Nathan Bronson - */ -class SimpleRandom private (private var _state: Long, dummy: Boolean) { - import SimpleRandom._ - - def this(seed: Int) = this(SimpleRandom.step(SimpleRandom.step(seed)), false) - def this() = this(System.identityHashCode(Thread.currentThread)) - - override def clone = new SimpleRandom(_state, false) - - /** Returns a random value chosen from a uniform distribution of all valid - * `Int`s. - */ - def nextInt(): Int = { - _state = step(_state) - extract(_state) - } - - /** Returns a random value chosen from a uniform distribution of the - * non-negative integers less than `n`, or throws `IllegalArgumentException` - * if `n` is negative or zero. - */ - def nextInt(n: Int): Int = { - if (n <= 0) - throw new IllegalArgumentException - - var x = -1 - while (x == -1) x = tryClamp(nextInt(), n) - x - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/skel/StubInTxn.scala b/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/skel/StubInTxn.scala deleted file mode 100644 index 5565ec24..00000000 --- a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/skel/StubInTxn.scala +++ /dev/null @@ -1,23 +0,0 @@ -/* scala-stm - (c) 2009-2011, Stanford University, PPL */ - -package scala.concurrent.stm -package skel - -class StubInTxn extends InTxn { - import concurrent.stm.Txn._ - - def executor: TxnExecutor = throw new AbstractMethodError - def status: Status = throw new AbstractMethodError - def rootLevel: NestingLevel = throw new AbstractMethodError - def currentLevel: NestingLevel = throw new AbstractMethodError - def rollback(cause: RollbackCause): Nothing = throw new AbstractMethodError - def retry(): Nothing = throw new AbstractMethodError - def retryFor(timeoutNanos: Long) { throw new AbstractMethodError } - def beforeCommit(handler: InTxn => Unit) = throw new AbstractMethodError - def whilePreparing(handler: InTxnEnd => Unit) = throw new AbstractMethodError - def whileCommitting(handler: InTxnEnd => Unit) = throw new AbstractMethodError - def afterCommit(handler: Status => Unit) = throw new AbstractMethodError - def afterRollback(handler: Status => Unit) = throw new AbstractMethodError - def afterCompletion(handler: Status => Unit) = throw new AbstractMethodError - def setExternalDecider(decider: ExternalDecider) = throw new AbstractMethodError -} diff --git a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/skel/StubSTMImpl.scala b/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/skel/StubSTMImpl.scala deleted file mode 100644 index 5683e95e..00000000 --- a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/skel/StubSTMImpl.scala +++ /dev/null @@ -1,66 +0,0 @@ -/* scala-stm - (c) 2009-2012, Stanford University, PPL */ - -package scala.concurrent.stm -package skel - -import java.lang.Throwable -import scala.collection.mutable.Builder -import java.util.concurrent.TimeUnit - -class StubSTMImpl extends impl.STMImpl { - - //////// RefFactory - - def newRef(v0: Boolean): Ref[Boolean] = throw new AbstractMethodError - def newRef(v0: Byte): Ref[Byte] = throw new AbstractMethodError - def newRef(v0: Short): Ref[Short] = throw new AbstractMethodError - def newRef(v0: Char): Ref[Char] = throw new AbstractMethodError - def newRef(v0: Int): Ref[Int] = throw new AbstractMethodError - def newRef(v0: Float): Ref[Float] = throw new AbstractMethodError - def newRef(v0: Long): Ref[Long] = throw new AbstractMethodError - def newRef(v0: Double): Ref[Double] = throw new AbstractMethodError - def newRef(v0: Unit): Ref[Unit] = throw new AbstractMethodError - def newRef[A : ClassManifest](v0: A): Ref[A] = throw new AbstractMethodError - - def newTxnLocal[A](init: => A, - initialValue: InTxn => A, - beforeCommit: InTxn => Unit, - whilePreparing: InTxnEnd => Unit, - whileCommitting: InTxnEnd => Unit, - afterCommit: A => Unit, - afterRollback: Txn.Status => Unit, - afterCompletion: Txn.Status => Unit): TxnLocal[A] = throw new AbstractMethodError - - def newTArray[A : ClassManifest](length: Int): TArray[A] = throw new AbstractMethodError - def newTArray[A : ClassManifest](xs: TraversableOnce[A]): TArray[A] = throw new AbstractMethodError - - def newTMap[A, B]: TMap[A, B] = throw new AbstractMethodError - def newTMapBuilder[A, B]: Builder[(A, B), TMap[A, B]] = throw new AbstractMethodError - - def newTSet[A]: TSet[A] = throw new AbstractMethodError - def newTSetBuilder[A]: Builder[A, TSet[A]] = throw new AbstractMethodError - - //////// TxnContext - - def findCurrent(implicit mt: MaybeTxn): Option[InTxn] = throw new AbstractMethodError - def dynCurrentOrNull: InTxn = throw new AbstractMethodError - - //////// TxnExecutor - - def apply[Z](block: InTxn => Z)(implicit mt: MaybeTxn): Z = throw new AbstractMethodError - def oneOf[Z](blocks: (InTxn => Z)*)(implicit mt: MaybeTxn): Z = throw new AbstractMethodError - def unrecorded[Z](block: InTxn => Z, outerFailure: Txn.RollbackCause => Z)(implicit mt: MaybeTxn): Z = throw new AbstractMethodError - def pushAlternative[Z](mt: MaybeTxn, block: InTxn => Z): Boolean = throw new AbstractMethodError - def compareAndSet[A, B](a: Ref[A], a0: A, a1: A, b: Ref[B], b0: B, b1: B): Boolean = throw new AbstractMethodError - def compareAndSetIdentity[A <: AnyRef, B <: AnyRef](a: Ref[A], a0: A, a1: A, b: Ref[B], b0: B, b1: B): Boolean = throw new AbstractMethodError - def retryTimeoutNanos: Option[Long] = throw new AbstractMethodError - def withRetryTimeoutNanos(timeout: Option[Long]): TxnExecutor = throw new AbstractMethodError - def isControlFlow(x: Throwable): Boolean = throw new AbstractMethodError - def withControlFlowRecognizer(pf: PartialFunction[Throwable, Boolean]): TxnExecutor = throw new AbstractMethodError - def postDecisionFailureHandler: (Txn.Status, Throwable) => Unit = throw new AbstractMethodError - def withPostDecisionFailureHandler(handler: (Txn.Status, Throwable) => Unit): TxnExecutor = throw new AbstractMethodError - - //////// STMImpl - - def newCommitBarrier(timeout: Long, unit: TimeUnit): CommitBarrier = throw new AbstractMethodError -} diff --git a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/skel/TMapViaClone.scala b/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/skel/TMapViaClone.scala deleted file mode 100644 index 63a15636..00000000 --- a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/skel/TMapViaClone.scala +++ /dev/null @@ -1,87 +0,0 @@ -/* scala-stm - (c) 2009-2012, Stanford University, PPL */ - -package scala.concurrent.stm -package skel - -import scala.collection.{immutable, mutable} - -private[stm] object TMapViaClone { - class FrozenMutableMap[A, B](self: mutable.Map[A, B]) extends immutable.Map[A, B] { - override def isEmpty: Boolean = self.isEmpty - override def size: Int = self.size - def get(key: A): Option[B] = self.get(key) - def iterator: Iterator[(A, B)] = self.iterator - override def foreach[U](f: ((A, B)) => U) { self foreach f } - def + [B1 >: B](kv: (A, B1)): immutable.Map[A, B1] = - new FrozenMutableMap(self.clone().asInstanceOf[mutable.Map[A, B1]] += kv) - def - (k: A): immutable.Map[A, B] = new FrozenMutableMap(self.clone() -= k) - } -} - -/** Provides an implementation for the bulk of the functionality of `TMap` and - * `TMap.View` by making extensive use of `clone()`. Assumes that the - * underlying implementation of `clone()` is O(1). - * - * @author Nathan Bronson - */ -private[stm] trait TMapViaClone[A, B] extends TMap.View[A, B] with TMap[A, B] { - import TMapViaClone._ - - // Implementations may be able to do better. - override def snapshot: immutable.Map[A, B] = new FrozenMutableMap(clone()) - - def tmap: TMap[A, B] = this - def single: TMap.View[A, B] = this - - /** Something like `"TMap[size=1]((1 -> 10))"`, stopping after 1K chars */ - def dbgStr: String = atomic.unrecorded({ txn => - mkStringPrefix("TMap", single.view.map { kv => kv._1 + " -> " + kv._2 }) - }, { _.toString }) - - /** Returns an array of key/value pairs, since that is likely to be the - * easiest to examine in a debugger. Also, this avoids problems with - * relying on copy-on-write after discarding `Ref` writes. - */ - def dbgValue: Any = atomic.unrecorded({ _ => toArray }, { x => x }) - - //////////// builder functionality (from mutable.MapLike via TMap.View) - - override protected[this] def newBuilder: TMap.View[A, B] = empty - - override def result(): TMap.View[A, B] = this - - - //////////// construction of new TMaps - - // A cheap clone means that mutable.MapLike's implementations of +, ++, - // -, and -- are all pretty reasonable. - - override def clone: TMap.View[A, B] - - //////////// atomic compound ops - - override def getOrElseUpdate(key: A, op: => B): B = { - single.get(key) getOrElse { - atomic { implicit txn => - tmap.get(key) getOrElse { val v = op ; tmap.put(key, v) ; v } - } - } - } - - override def transform(f: (A, B) => B): this.type = { - atomic { implicit txn => - for (kv <- tmap) - tmap.update(kv._1, f(kv._1, kv._2)) - } - this - } - - override def retain(p: (A, B) => Boolean): this.type = { - atomic { implicit txn => - for (kv <- tmap) - if (!p(kv._1, kv._2)) - tmap -= kv._1 - } - this - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/skel/TSetViaClone.scala b/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/skel/TSetViaClone.scala deleted file mode 100644 index 2178aaf0..00000000 --- a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/skel/TSetViaClone.scala +++ /dev/null @@ -1,67 +0,0 @@ -/* scala-stm - (c) 2009-2012, Stanford University, PPL */ - -package scala.concurrent.stm -package skel - -import scala.collection.{immutable, mutable} - -private[stm] object TSetViaClone { - class FrozenMutableSet[A](self: mutable.Set[A]) extends immutable.Set[A] { - override def isEmpty: Boolean = self.isEmpty - override def size: Int = self.size - def contains(key: A): Boolean = self.contains(key) - def iterator: Iterator[(A)] = self.iterator - override def foreach[U](f: A => U) { self foreach f } - def + (x: A): immutable.Set[A] = new FrozenMutableSet(self.clone() += x) - def - (x: A): immutable.Set[A] = new FrozenMutableSet(self.clone() -= x) - } -} - -/** Provides an implementation for the bulk of the functionality of `TSet` and - * `TSet.View` by making extensive use of `clone()`. Assumes that the - * underlying implementation of `clone()` is O(1). - * - * @author Nathan Bronson - */ -private[stm] trait TSetViaClone[A] extends TSet.View[A] with TSet[A] { - import TSetViaClone._ - - // Implementations may be able to do better. - override def snapshot: immutable.Set[A] = new FrozenMutableSet(clone()) - - def tset: TSet[A] = this - def single: TSet.View[A] = this - - /** Something like `"TSet[size=3](3, 1, 10)"`, stopping after 1K chars */ - def dbgStr: String = atomic.unrecorded({ _ => mkStringPrefix("TSet", single) }, { _.toString }) - - /** Returns an array of elements, since that is likely to be the - * easiest to examine in a debugger. Also, this avoids problems with - * relying on copy-on-write after discarding `Ref` writes. - */ - def dbgValue: Any = atomic.unrecorded({ _ => toArray[Any] }, { x => x }) - - //////////// builder functionality (from mutable.SetLike via TSet.View) - - override protected[this] def newBuilder: TSet.View[A] = empty - - override def result(): TSet.View[A] = this - - - //////////// construction of new TSets - - // A cheap clone() means that mutable.SetLike's implementations of +, ++, - // -, and -- are all pretty reasonable. - - override def clone: TSet.View[A] - - //////////// atomic compound ops - - override def retain(p: A => Boolean) { - atomic { implicit txn => - for (x <- tset) - if (!p(x)) - tset -= x - } - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/skel/TxnHashTrie.scala b/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/skel/TxnHashTrie.scala deleted file mode 100644 index 12fc7cf1..00000000 --- a/benchmarks/scala-stm/scala-stm-library/src/main/scala/scala/concurrent/stm/skel/TxnHashTrie.scala +++ /dev/null @@ -1,840 +0,0 @@ -/* scala-stm - (c) 2009-2011, Stanford University, PPL */ - -package scala.concurrent.stm -package skel - -import annotation.tailrec - -/** `TxnHashTrie` implements a transactional mutable hash trie using Ref-s, - * with lazy cloning to allow efficient snapshots. Fundamental operations are - * provided for hash tries representing either sets or maps, both of which are - * represented as a Ref.View[Node[A, B]]. If the initial empty leaf is - * `emptySetValue` then no values can be stored in the hash trie, and - * operations that take or return values will expect and produce null. - * - * @author Nathan Bronson - */ -private[skel] object TxnHashTrie { - - final val LogBF = 4 - final val BF = 16 - - // It would seem that the leaf copying is inefficient when compared to a tree - // that allows more sharing, but a back-of-the-envelope calculation indicates - // that the crossover point for the total bytes allocates to construct an - // immutable node holding N elements is about 12. Even at N=32 the total - // bytes required by this Leaf implementation is only about 2/3 more than an - // ideal balanced tree, and those bytes are accessed in a more cache friendly - // fashion. - final val MaxLeafCapacity = 14 - - def keyHash[A](key: A): Int = if (key == null) 0 else mixBits(key.##) - - def mixBits(h: Int) = { - // make sure any bit change results in a change in the bottom LogBF bits - val s = LogBF - val x = h ^ (h >>> (s * 3)) ^ (h >>> (s * 6)) - x ^ (x >>> s) ^ (x >>> (s * 2)) - } - - def indexFor(shift: Int, hash: Int) = (hash >>> shift) & (BF - 1) - - //////// shared instances - - val emptyLeaf = new Leaf[Any, Unit](Array.empty[Int], Array.empty[AnyRef]) - - //////// publicly-visible stuff - - sealed abstract class Node[A, B] { - def cappedSize(cap: Int): Int - def txnIsEmpty(implicit txn: InTxn): Boolean - def keyForeach[U](f: A => U) - def mapForeach[U](f: ((A, B)) => U) - def keyIterator: Iterator[A] - def valueIterator: Iterator[B] - def mapIterator: Iterator[(A, B)] - } - - sealed trait BuildingNode[A, B] { - def endBuild: Node[A, B] - } - - type SetNode[A] = Node[A, AnyRef] - type SetBuildingNode[A] = BuildingNode[A, AnyRef] - - /** If used by a Set, values will be null. */ - final class Leaf[A, B](val hashes: Array[Int], - val kvs: Array[AnyRef]) extends Node[A, B] with BuildingNode[A, B] { - - def endBuild = this - - def cappedSize(cap: Int): Int = hashes.length - def txnIsEmpty(implicit txn: InTxn) = hashes.length == 0 - - def getKey(i: Int): A = kvs(2 * i).asInstanceOf[A] - def setKey(i: Int, k: A) { kvs(2 * i) = k.asInstanceOf[AnyRef] } - - def getValue(i: Int): B = kvs(2 * i + 1).asInstanceOf[B] - def setValue(i: Int, v: B) { kvs(2 * i + 1) = v.asInstanceOf[AnyRef] } - - def getKeyValue(i: Int): (A, B) = (getKey(i), getValue(i)) - - def contains(hash: Int, key: A): Boolean = find(hash, key) >= 0 - - def get(hash: Int, key: A): Option[B] = { - val i = find(hash, key) - if (i < 0) - None - else - Some(getValue(i)) - } - - def get(i: Int): Option[B] = { - if (i < 0) - None - else - Some(getValue(i)) - } - - def find(hash: Int, key: A): Int = { - var i = hashes.length - while (i > 0) { - i -= 1 - val h = hashes(i) - if (h == hash && keyEqual(key.asInstanceOf[AnyRef], kvs(2 * i))) - return i - if (h < hash) - return ~(i + 1) - } - return ~0 - } - - private def keyEqual(lhs: AnyRef, rhs: AnyRef): Boolean = { - if (lhs eq rhs) - true - else if (lhs == null || rhs == null) - false - else if (lhs.getClass eq rhs.getClass) { - if (lhs.isInstanceOf[java.lang.Integer]) - true // we know the hashes match, and hashCode() = value for ints - else if (lhs.isInstanceOf[java.lang.Long]) - lhs.asInstanceOf[java.lang.Long].longValue == rhs.asInstanceOf[java.lang.Long].longValue - else - lhs.equals(rhs) - } else - runtime.BoxesRunTime.equals2(lhs, rhs) - } - - def noChange[B](i: Int, value: B): Boolean = { - i >= 0 && (kvs(2 * i + 1) eq value.asInstanceOf[AnyRef]) - } - - def withPut(gen: Long, shift: Int, hash: Int, key: A, value: B, i: Int, contended: Boolean): Node[A, B] = { - if (i < 0) - withInsert(~i, hash, key, value).splitIfNeeded(gen, shift, contended: Boolean) - else - withUpdate(i, value) - } - - def withBuildingPut(shift: Int, hash: Int, key: A, value: B, i: Int): BuildingNode[A, B] = { - if (i < 0) - withInsert(~i, hash, key, value).buildingSplitIfNeeded(shift) - else - withUpdate(i, value) - } - - private def withUpdate(i: Int, value: B): Leaf[A, B] = { - // reuse hashes - val nkvs = kvs.clone - nkvs(2 * i + 1) = value.asInstanceOf[AnyRef] - new Leaf[A, B](hashes, nkvs) - } - - private def withInsert(i: Int, hash: Int, key: A, value: B): Leaf[A, B] = { - val z = newLeaf(hashes.length + 1) - val j = hashes.length - i - - System.arraycopy(hashes, 0, z.hashes, 0, i) - System.arraycopy(hashes, i, z.hashes, i + 1, j) - z.hashes(i) = hash - - System.arraycopy(kvs, 0, z.kvs, 0, 2 * i) - System.arraycopy(kvs, 2 * i, z.kvs, 2 * i + 2, 2 * j) - z.setKey(i, key) - z.setValue(i, value) - - z - } - - def withRemove(i: Int): Leaf[A, B] = { - if (i < 0) - this - else { - val z = newLeaf(hashes.length - 1) - if (z.hashes.length > 0) { - val j = z.hashes.length - i - - System.arraycopy(hashes, 0, z.hashes, 0, i) - System.arraycopy(hashes, i + 1, z.hashes, i, j) - - System.arraycopy(kvs, 0, z.kvs, 0, 2 * i) - System.arraycopy(kvs, 2 * i + 2, z.kvs, 2 * i, 2 * j) - } - z - } - } - - def splitIfNeeded(gen: Long, shift: Int, contended: Boolean): Node[A, B] = { - if (!shouldSplit(contended)) this else split(gen, shift) - } - - def buildingSplitIfNeeded(shift: Int): BuildingNode[A, B] = if (!shouldSplit(false)) this else buildingSplit(shift) - - def shouldSplit(contended: Boolean): Boolean = { - // if the hash function is bad we might be oversize but unsplittable - (contended || hashes.length > MaxLeafCapacity) && hashes(hashes.length - 1) != hashes(0) - } - - def split(gen: Long, shift: Int): Branch[A, B] = { - val children = new Array[Node[A, B]](BF) - splitInto(shift, children) - - // class manifests for classes that have type parameters are a bit - // convoluted to construct, so it is better to do it only once per split - implicit val cm = implicitly[ClassManifest[Node[A, B]]] - - val refs = new Array[Ref.View[Node[A, B]]](BF) - var i = 0 - while (i < BF) { - refs(i) = Ref(children(i)).single - i += 1 - } - new Branch[A, B](gen, false, refs) - } - - def buildingSplit(shift: Int): BuildingBranch[A, B] = { - val children = new Array[BuildingNode[A, B]](BF) - splitInto(shift, children) - new BuildingBranch[A, B](children) - } - - private def splitInto[L >: Leaf[A, B]](shift: Int, children: Array[L]) { - val sizes = new Array[Int](BF) - var i = 0 - while (i < hashes.length) { - sizes(indexFor(shift, hashes(i))) += 1 - i += 1 - } - i = 0 - while (i < BF) { - children(i) = newLeaf(sizes(i)) - i += 1 - } - i = hashes.length - 1 - while (i >= 0) { - val slot = indexFor(shift, hashes(i)) - sizes(slot) -= 1 - val pos = sizes(slot) - val dst = children(slot).asInstanceOf[Leaf[A, B]] - dst.hashes(pos) = hashes(i) - dst.setKey(pos, getKey(i)) - dst.setValue(pos, getValue(i)) - - // If the hashes were very poorly distributed one leaf might get - // everything. We could resplit now, but it doesn't seem to be worth - // it. If we wait until the next insert we can never get more than - // 32 / LogBF extra. - //// if (pos == 0 && dst.shouldSplit) - //// children(slot).value = dst.split(gen, shift + LogBF) - i -= 1 - } - } - - private def newLeaf(n: Int): Leaf[A, B] = { - if (n == 0) - emptyLeaf.asInstanceOf[Leaf[A, B]] - else - new Leaf[A, B](new Array[Int](n), new Array[AnyRef](2 * n)) - } - - def keyForeach[U](f: A => U) { - var i = 0 - while (i < hashes.length) { - f(getKey(i)) - i += 1 - } - } - - def mapForeach[U](f: ((A, B)) => U) { - var i = 0 - while (i < hashes.length) { - f(getKeyValue(i)) - i += 1 - } - } - - def keyIterator: Iterator[A] = new Iterator[A] { - var pos = 0 - def hasNext = pos < hashes.length - def next: A = { val z = getKey(pos) ; pos += 1 ; z } - } - - def valueIterator: Iterator[B] = new Iterator[B] { - var pos = 0 - def hasNext = pos < hashes.length - def next: B = { val z = getValue(pos) ; pos += 1 ; z } - } - - def mapIterator: Iterator[(A, B)] = new Iterator[(A,B)] { - var pos = 0 - def hasNext = pos < hashes.length - def next: (A, B) = { val z = getKeyValue(pos) ; pos += 1 ; z } - } - } - - class BuildingBranch[A, B](val children: Array[BuildingNode[A, B]]) extends BuildingNode[A, B] { - def endBuild: Node[A, B] = { - val refs = new Array[Ref.View[Node[A, B]]](BF) - var i = 0 - while (i < BF) { - refs(i) = Ref(children(i).endBuild).single - i += 1 - } - new Branch(0L, false, refs) - } - } - - class Branch[A, B](val gen: Long, val frozen: Boolean, val children: Array[Ref.View[Node[A, B]]]) extends Node[A, B] { - // size may only be called on a frozen branch, so we can cache the result - private var _cachedSize = -1 - - def cappedSize(cap: Int): Int = { - val n0 = _cachedSize - if (n0 >= 0) { - n0 - } else { - var n = 0 - var i = 0 - while (i < BF && n < cap) { - n += children(i)().cappedSize(cap - n) - i += 1 - } - if (n < cap) - _cachedSize = n // everybody tried their hardest - n - } - } - - def txnIsEmpty(implicit txn: InTxn): Boolean = { - var i = 0 - while (i < BF) { - val c = children(i).ref.get - if (!c.txnIsEmpty) - return false - i += 1 - } - return true - } - - def withFreeze: Branch[A, B] = new Branch(gen, true, children) - - def clone(newGen: Long): Branch[A, B] = { - val cc = children.clone - var i = 0 - while (i < cc.length) { - cc(i) = Ref(cc(i)()).single - i += 1 - } - new Branch[A, B](newGen, false, cc) - } - - def keyForeach[U](f: A => U) { - var i = 0 - while (i < BF) { - children(i)().keyForeach(f) - i += 1 - } - } - - def mapForeach[U](f: ((A, B)) => U) { - var i = 0 - while (i < BF) { - children(i)().mapForeach(f) - i += 1 - } - } - - private abstract class Iter[Z] extends Iterator[Z] { - - def childIter(c: Node[A, B]): Iterator[Z] - - private var pos = -1 - private var iter: Iterator[Z] = null - advance() - - @tailrec private def advance(): Boolean = { - if (pos == BF - 1) { - iter = null - false - } else { - pos += 1 - val c = children(pos)() - if (c eq emptyLeaf) - advance() // keep looking, nothing is here - else { - iter = childIter(c) - iter.hasNext || advance() // keep looking if we got a dud - } - } - } - - def hasNext = iter != null && iter.hasNext - - def next: Z = { - val z = iter.next - if (!iter.hasNext) - advance() - z - } - } - - def keyIterator: Iterator[A] = new Iter[A] { - def childIter(c: Node[A, B]) = c.keyIterator - } - - def valueIterator: Iterator[B] = new Iter[B] { - def childIter(c: Node[A, B]) = c.valueIterator - } - - def mapIterator: Iterator[(A, B)] = new Iter[(A,B)] { - def childIter(c: Node[A, B]) = c.mapIterator - } - } - - //////////////// construction - - def emptySetNode[A]: SetNode[A] = emptyLeaf.asInstanceOf[SetNode[A]] - def emptyMapNode[A, B]: Node[A, B] = emptyLeaf.asInstanceOf[Node[A, B]] - - def emptySetBuildingNode[A]: SetBuildingNode[A] = emptyLeaf.asInstanceOf[SetBuildingNode[A]] - def emptyMapBuildingNode[A, B]: BuildingNode[A, B] = emptyLeaf.asInstanceOf[BuildingNode[A, B]] - - def buildingAdd[A](root: SetBuildingNode[A], x: A): SetBuildingNode[A] = buildingPut(root, 0, keyHash(x), x, null) - def buildingPut[A, B](root: BuildingNode[A, B], k: A, v: B): BuildingNode[A, B] = buildingPut(root, 0, keyHash(k), k, v) - - private def buildingPut[A, B](current: BuildingNode[A, B], shift: Int, hash: Int, key: A, value: B): BuildingNode[A, B] = { - current match { - case leaf: Leaf[A, B] => { - val i = leaf.find(hash, key) - if (leaf.noChange(i, value)) leaf else leaf.withBuildingPut(shift, hash, key, value, i) - } - case branch: BuildingBranch[A, B] => { - val i = indexFor(shift, hash) - branch.children(i) = buildingPut(branch.children(i), shift + LogBF, hash, key, value) - branch - } - } - } -} - -private[skel] abstract class TxnHashTrie[A, B](protected var root: Ref.View[TxnHashTrie.Node[A, B]]) { - import TxnHashTrie._ - - //////////////// txn contention tracking - - private final val pct = 10000 - private final val contentionThreshold = 1 * pct - private var contentionEstimate = 0 - - private def recordNoContention() { - if (SimpleRandom.nextInt(32) == 0) { - val e = contentionEstimate - contentionEstimate = e - (e >> 4) // this is 15/16, applied every 32nd time, so about 99.8% - } - } - - private def recordContention() { - val e = contentionEstimate - contentionEstimate = e + ((100 * pct - e) >> 9) // 100 * pct is the max - } - - private def isContended = contentionEstimate > contentionThreshold - - //////////////// whole-trie operations - - protected def frozenRoot: Node[A, B] = { - root() match { - case leaf: Leaf[A, B] => leaf // leaf is already immutable - case branch: Branch[A, B] if branch.frozen => branch - case branch: Branch[A, B] => { - // If this CAS fails it means someone else already installed a frozen - // branch, and we can benefit from their work. - val b = branch.withFreeze - root.compareAndSetIdentity(branch, b) - b - } - } - } - - protected def cloneRoot: Ref.View[Node[A, B]] = Ref(frozenRoot).single - - protected def setIterator: Iterator[A] = frozenRoot.keyIterator - - protected def mapIterator: Iterator[(A, B)] = frozenRoot.mapIterator - protected def mapKeyIterator: Iterator[A] = frozenRoot.keyIterator - protected def mapValueIterator: Iterator[B] = frozenRoot.valueIterator - - //////////////// whole-trie operations on Ref.View - - protected def singleIsEmpty: Boolean = impl.STMImpl.instance.dynCurrentOrNull match { - case null => frozenRoot.cappedSize(1) == 0 - case txn => txnIsEmpty(txn) - } - - protected def singleSize: Int = frozenRoot.cappedSize(Int.MaxValue) - - protected def singleSetForeach[U](f: A => U) { - // don't freeze the root if we use .single in a txn - impl.STMImpl.instance.dynCurrentOrNull match { - case null => frozenRoot.keyForeach(f) - case txn => txnSetForeach(f)(txn) - } - } - - protected def singleMapForeach[U](f: ((A, B)) => U) { - impl.STMImpl.instance.dynCurrentOrNull match { - case null => frozenRoot.mapForeach(f) - case txn => txnMapForeach(f)(txn) - } - } - - //////// single-key operations for Ref.View - - protected def singleContains(key: A): Boolean = singleContains(null, root, 0, keyHash(key), key) - - @tailrec private def singleContains(rootNode: Node[A, B], n: Ref.View[Node[A, B]], shift: Int, hash: Int, key: A): Boolean = { - n() match { - case leaf: Leaf[A, B] => { - if (shift != 0 && (rootNode ne root())) - singleContains(null, root, 0, hash, key) - else - leaf.contains(hash, key) - } - case branch: Branch[A, B] => { - val rn = if (shift == 0) branch else rootNode - singleContains(rn, branch.children(indexFor(shift, hash)), shift + LogBF, hash, key) - } - } - } - - protected def singleGetOrThrow(key: A): B = singleGetOrThrow(null, root, 0, keyHash(key), key) - - @tailrec private def singleGetOrThrow(rootNode: Node[A, B], n: Ref.View[Node[A, B]], shift: Int, hash: Int, key: A): B = { - n() match { - case leaf: Leaf[A, B] => { - if (shift != 0 && (rootNode ne root())) - singleGetOrThrow(null, root, 0, hash, key) - else { - val i = leaf.find(hash, key) - if (i < 0) - throw new NoSuchElementException("key not found: " + key) - leaf.getValue(i) - } - } - case branch: Branch[A, B] => { - val rn = if (shift == 0) branch else rootNode - singleGetOrThrow(rn, branch.children(indexFor(shift, hash)), shift + LogBF, hash, key) - } - } - } - - protected def singleGet(key: A): Option[B] = singleGet(null, root, 0, keyHash(key), key) - - @tailrec private def singleGet(rootNode: Node[A, B], n: Ref.View[Node[A, B]], shift: Int, hash: Int, key: A): Option[B] = { - n() match { - case leaf: Leaf[A, B] => { - if (shift != 0 && (rootNode ne root())) - singleGet(null, root, 0, hash, key) - else - leaf.get(hash, key) - } - case branch: Branch[A, B] => { - val rn = if (shift == 0) branch else rootNode - singleGet(rn, branch.children(indexFor(shift, hash)), shift + LogBF, hash, key) - } - } - } - - protected def singlePut(key: A, value: B): Option[B] = singleRootPut(keyHash(key), key, value, 0) - - @tailrec private def singleRootPut(hash: Int, key: A, value: B, failures: Int): Option[B] = { - if (failures < 10) { - root() match { - case leaf: Leaf[A, B] => { - val i = leaf.find(hash, key) - if (leaf.noChange(i, value) || root.compareAndSetIdentity(leaf, leaf.withPut(0L, 0, hash, key, value, i, false))) - leaf.get(i) // success, read from old leaf - else - singleRootPut(hash, key, value, failures + 1) - } - case branch: Branch[A, B] => { - val b = if (!branch.frozen) branch else singleUnshare(branch.gen + 1, root, branch) - if (b != null) - singleChildPut(b, b.children(indexFor(0, hash)), LogBF, hash, key, value, 0) - else - singleRootPut(hash, key, value, failures + 1) - } - } - } else - failingPut(hash, key, value) - } - - private def singleUnshare(rootGen: Long, current: Ref.View[Node[A, B]], branch: Branch[A, B]): Branch[A, B] = { - val b = branch.clone(rootGen) - if (current.compareAndSetIdentity(branch, b)) b else null - } - - private def failingPut(hash: Int, key: A, value: B): Option[B] = { - // running in a transaction guarantees that CAS won't fail - atomic { implicit txn => txnRootPut(hash, key, value) } - } - - @tailrec private def singleChildPut(rootNode: Branch[A, B], - current: Ref.View[Node[A, B]], - shift: Int, - hash: Int, - key: A, - value: B, - failures: Int): Option[B] = { - if (failures < 10) { - current() match { - case leaf: Leaf[A, B] => { - val i = leaf.find(hash, key) - if (leaf.noChange(i, value) || atomic.compareAndSetIdentity( - root.ref, rootNode, rootNode, current.ref, - leaf, leaf.withPut(rootNode.gen, shift, hash, key, value, i, failures > 0))) - leaf.get(i) // success - else if (root() ne rootNode) - failingPut(hash, key, value) // root retry - else - singleChildPut(rootNode, current, shift, hash, key, value, failures + 1) // local retry - } - case branch: Branch[A, B] => { - val b = if (branch.gen == rootNode.gen) branch else singleUnshare(rootNode.gen, current, branch) - if (b != null) - singleChildPut(rootNode, b.children(indexFor(shift, hash)), shift + LogBF, hash, key, value, failures) - else - singleChildPut(rootNode, current, shift, hash, key, value, failures + 1) // failure, try again - } - } - } else - failingPut(hash, key, value) - } - - protected def singleRemove(key: A): Option[B] = singleRootRemove(keyHash(key), key, 0) - - @tailrec private def singleRootRemove(hash: Int, key: A, failures: Int): Option[B] = { - if (failures < 10) { - root() match { - case leaf: Leaf[A, B] => { - val i = leaf.find(hash, key) - if (i < 0 || root.compareAndSetIdentity(leaf, leaf.withRemove(i))) - leaf.get(i) // success, read from old leaf - else - singleRootRemove(hash, key, failures + 1) - } - case branch: Branch[A, B] => { - val i = indexFor(0, hash) - if (branch.frozen && !singleContains(branch, branch.children(i), LogBF, hash, key)) - None - else { - val b = if (!branch.frozen) branch else singleUnshare(branch.gen + 1, root, branch) - if (b != null) - singleChildRemove(b, b.children(i), LogBF, hash, key, (b ne branch), 0) - else - singleRootRemove(hash, key, failures + 1) - } - } - } - } else - failingRemove(hash, key) - } - - private def failingRemove(hash: Int, key: A): Option[B] = { - // running in a transaction guarantees that CAS won't fail - atomic { implicit txn => txnRootRemove(hash, key) } - } - - @tailrec private def singleChildRemove(rootNode: Branch[A, B], - current: Ref.View[Node[A, B]], - shift: Int, - hash: Int, - key: A, - checked: Boolean, - failures: Int): Option[B] = { - if (failures < 10) { - current() match { - case leaf: Leaf[A, B] => { - val i = leaf.find(hash, key) - if (i < 0) - None // no change, key wasn't present - else if (atomic.compareAndSetIdentity(root.ref, rootNode, rootNode, current.ref, leaf, leaf.withRemove(i))) - leaf.get(i) // success - else if (root() ne rootNode) - failingRemove(hash, key) // root retry - else - singleChildRemove(rootNode, current, shift, hash, key, checked, failures + 1) // local retry - } - case branch: Branch[A, B] => { - val i = indexFor(shift, hash) - if (!checked && branch.gen != rootNode.gen && !singleContains(rootNode, branch.children(i), shift + LogBF, hash, key)) - None // child is absent - else { - val b = if (branch.gen == rootNode.gen) branch else singleUnshare(rootNode.gen, current, branch) - if (b != null) - singleChildRemove(rootNode, b.children(i), shift + LogBF, hash, key, checked || (b ne branch), failures) - else - singleChildRemove(rootNode, current, shift, hash, key, checked, failures + 1) - } - } - } - } else - failingRemove(hash, key) - } - - - //////////////// whole-trie operations when an InTxn is available - - // visitation doesn't need to freeze the root, because we know that the - // entire visit is part of an atomic block - - protected def txnIsEmpty(implicit txn: InTxn): Boolean = root().txnIsEmpty - - protected def txnSetForeach[U](f: A => U)(implicit txn: InTxn) { root().keyForeach(f) } - - protected def txnMapForeach[U](f: ((A, B)) => U)(implicit txn: InTxn) { root().mapForeach(f) } - - //////////////// per-key operations when an InTxn is available - - protected def txnContains(key: A)(implicit txn: InTxn): Boolean = txnContains(root.ref, 0, keyHash(key), key)(txn) - - @tailrec private def txnContains(n: Ref[Node[A, B]], shift: Int, hash: Int, key: A)(implicit txn: InTxn): Boolean = { - n() match { - case leaf: Leaf[A, B] => leaf.contains(hash, key) - case branch: Branch[A, B] => txnContains(branch.children(indexFor(shift, hash)).ref, shift + LogBF, hash, key)(txn) - } - } - - protected def txnGetOrThrow(key: A)(implicit txn: InTxn): B = txnGetOrThrow(root.ref, 0, keyHash(key), key)(txn) - - @tailrec private def txnGetOrThrow(n: Ref[Node[A, B]], shift: Int, hash: Int, key: A)(implicit txn: InTxn): B = { - n() match { - case leaf: Leaf[A, B] => { - val i = leaf.find(hash, key) - if (i < 0) - throw new NoSuchElementException("key not found: " + key) - leaf.getValue(i) - } - case branch: Branch[A, B] => txnGetOrThrow(branch.children(indexFor(shift, hash)).ref, shift + LogBF, hash, key)(txn) - } - } - - protected def txnGet(key: A)(implicit txn: InTxn): Option[B] = txnGet(root.ref, 0, keyHash(key), key)(txn) - - @tailrec private def txnGet(n: Ref[Node[A, B]], shift: Int, hash: Int, key: A)(implicit txn: InTxn): Option[B] = { - n() match { - case leaf: Leaf[A, B] => leaf.get(hash, key) - case branch: Branch[A, B] => txnGet(branch.children(indexFor(shift, hash)).ref, shift + LogBF, hash, key)(txn) - } - } - - protected def txnPut(key: A, value: B)(implicit txn: InTxn): Option[B] = txnRootPut(keyHash(key), key, value)(txn) - - private def txnRootPut(hash: Int, key: A, value: B)(implicit txn: InTxn): Option[B] = { - root() match { - case leaf: Leaf[A, B] => { - val i = leaf.find(hash, key) - if (!leaf.noChange(i, value)) - set(root.ref, leaf.withPut(0L, 0, hash, key, value, i, isContended)) - leaf.get(i) - } - case branch: Branch[A, B] => { - val b = if (!branch.frozen) branch else txnUnshare(branch.gen + 1, root.ref, branch) - txnChildPut(b.gen, b.children(indexFor(0, hash)).ref, LogBF, hash, key, value)(txn) - } - } - } - - private def set(ref: Ref[Node[A, B]], node: Node[A, B])(implicit txn: InTxn) { - if (!ref.trySet(node)) { - recordContention() - ref() = node - } else - recordNoContention() - } - - private def txnUnshare(rootGen: Long, current: Ref[Node[A, B]], branch: Branch[A, B])(implicit txn: InTxn): Branch[A, B] = { - val b = branch.clone(rootGen) - current() = b - b - } - - @tailrec private def txnChildPut(rootGen: Long, current: Ref[Node[A, B]], shift: Int, hash: Int, key: A, value: B - )(implicit txn: InTxn): Option[B] = { - current() match { - case leaf: Leaf[A, B] => { - val i = leaf.find(hash, key) - if (!leaf.noChange(i, value)) - set(current, leaf.withPut(rootGen, shift, hash, key, value, i, isContended)) - leaf.get(i) - } - case branch: Branch[A, B] => { - val b = if (branch.gen == rootGen) branch else txnUnshare(rootGen, current, branch) - txnChildPut(rootGen, b.children(indexFor(shift, hash)).ref, shift + LogBF, hash, key, value)(txn) - } - } - } - - protected def txnRemove(key: A)(implicit txn: InTxn): Option[B] = txnRootRemove(keyHash(key), key)(txn) - - private def txnRootRemove(hash: Int, key: A)(implicit txn: InTxn): Option[B] = { - root() match { - case leaf: Leaf[A, B] => { - val i = leaf.find(hash, key) - if (i >= 0) - set(root.ref, leaf.withRemove(i)) - leaf.get(i) - } - case branch: Branch[A, B] => { - val i = indexFor(0, hash) - if (branch.frozen && !txnContains(branch.children(i).ref, LogBF, hash, key)) - None - else { - val b = if (!branch.frozen) branch else txnUnshare(branch.gen + 1, root.ref, branch) - txnChildRemove(b.gen, b.children(i).ref, LogBF, hash, key, (b ne branch))(txn) - } - } - } - } - - @tailrec private def txnChildRemove(rootGen: Long, current: Ref[Node[A, B]], shift: Int, hash: Int, key: A, checked: Boolean - )(implicit txn: InTxn): Option[B] = { - current() match { - case leaf: Leaf[A, B] => { - val i = leaf.find(hash, key) - if (i >= 0) - set(current, leaf.withRemove(i)) - leaf.get(i) - } - case branch: Branch[A, B] => { - val i = indexFor(shift, hash) - if (!checked && branch.gen != rootGen && !txnContains(branch.children(i).ref, shift + LogBF, hash, key)) - None // child is absent - else { - val b = if (branch.gen == rootGen) branch else txnUnshare(rootGen, current, branch) - txnChildRemove(rootGen, b.children(i).ref, shift + LogBF, hash, key, checked || (b ne branch))(txn) - } - } - } - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/src/test/java/scala/concurrent/stm/JavaAPITests.java b/benchmarks/scala-stm/scala-stm-library/src/test/java/scala/concurrent/stm/JavaAPITests.java deleted file mode 100644 index 029deeed..00000000 --- a/benchmarks/scala-stm/scala-stm-library/src/test/java/scala/concurrent/stm/JavaAPITests.java +++ /dev/null @@ -1,176 +0,0 @@ -/* scala-stm - (c) 2009-2012, Stanford University, PPL */ - -package scala.concurrent.stm; - -import static org.junit.Assert.*; -import org.junit.Test; - -import static scala.concurrent.stm.japi.STM.*; - -import java.util.concurrent.Callable; - -import java.util.Map; -import java.util.Set; -import java.util.List; - -public class JavaAPITests { - @Test - public void createIntegerRef() { - Ref.View ref = newRef(0); - int unboxed = ref.get(); - assertEquals(0, unboxed); - } - - @Test - public void atomicWithRunnable() { - final Ref.View ref = newRef(0); - atomic(new Runnable() { - public void run() { - ref.set(10); - } - }); - int value = ref.get(); - assertEquals(10, value); - } - - @Test - public void atomicWithCallable() { - final Ref.View ref = newRef(0); - int oldValue = atomic(new Callable() { - public Integer call() { - return ref.swap(10); - } - }); - assertEquals(0, oldValue); - int newValue = ref.get(); - assertEquals(10, newValue); - } - - @Test(expected = TestException.class) - public void failingTransaction() { - final Ref.View ref = newRef(0); - try { - atomic(new Runnable() { - public void run() { - ref.set(10); - throw new TestException(); - } - }); - } catch (TestException e) { - int value = ref.get(); - assertEquals(0, value); - throw e; - } - } - - @Test - public void transformInteger() { - Ref.View ref = newRef(0); - transform(ref, new Transformer() { - public Integer apply(Integer i) { - return i + 10; - } - }); - int value = ref.get(); - assertEquals(10, value); - } - - @Test - public void getAndTransformInteger() { - Ref.View ref = newRef(0); - int value = getAndTransform(ref, new Transformer() { - public Integer apply(Integer i) { - return i + 10; - } - }); - assertEquals(0, value); - } - - @Test - public void transformAndGetInteger() { - Ref.View ref = newRef(0); - int value = transformAndGet(ref, new Transformer() { - public Integer apply(Integer i) { - return i + 10; - } - }); - assertEquals(10, value); - } - - @Test - public void incrementInteger() { - Ref.View ref = newRef(0); - increment(ref, 10); - int value = ref.get(); - assertEquals(10, value); - } - - @Test - public void incrementLong() { - Ref.View ref = newRef(0L); - increment(ref, 10L); - long value = ref.get(); - assertEquals(10L, value); - } - - @Test - public void createAndUseTMap() { - Map map = newMap(); - map.put(1, "one"); - map.put(2, "two"); - assertEquals("one", map.get(1)); - assertEquals("two", map.get(2)); - assertTrue(map.containsKey(2)); - map.remove(2); - assertFalse(map.containsKey(2)); - } - - @Test(expected = TestException.class) - public void failingTMapTransaction() { - final Map map = newMap(); - try { - atomic(new Runnable() { - public void run() { - map.put(1, "one"); - map.put(2, "two"); - assertTrue(map.containsKey(1)); - assertTrue(map.containsKey(2)); - throw new TestException(); - } - }); - } catch (TestException e) { - assertFalse(map.containsKey(1)); - assertFalse(map.containsKey(2)); - throw e; - } - } - - @Test - public void createAndUseTSet() { - Set set = newSet(); - set.add("one"); - set.add("two"); - assertTrue(set.contains("one")); - assertTrue(set.contains("two")); - assertEquals(2, set.size()); - set.add("one"); - assertEquals(2, set.size()); - set.remove("two"); - assertFalse(set.contains("two")); - assertEquals(1, set.size()); - } - - @Test - public void createAndUseTArray() { - List list = newArrayAsList(3); - assertEquals(null, list.get(0)); - assertEquals(null, list.get(1)); - assertEquals(null, list.get(2)); - list.set(0, "zero"); - list.set(1, "one"); - list.set(2, "two"); - assertEquals("zero", list.get(0)); - assertEquals("one", list.get(1)); - assertEquals("two", list.get(2)); - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/src/test/java/scala/concurrent/stm/TestException.java b/benchmarks/scala-stm/scala-stm-library/src/test/java/scala/concurrent/stm/TestException.java deleted file mode 100644 index 0b91928d..00000000 --- a/benchmarks/scala-stm/scala-stm-library/src/test/java/scala/concurrent/stm/TestException.java +++ /dev/null @@ -1,9 +0,0 @@ -/* scala-stm - (c) 2009-2012, Stanford University, PPL */ - -package scala.concurrent.stm; - -public class TestException extends RuntimeException { - public TestException() { - super("Expected failure"); - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/CallbackSuite.scala b/benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/CallbackSuite.scala deleted file mode 100644 index 5b0eef7d..00000000 --- a/benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/CallbackSuite.scala +++ /dev/null @@ -1,582 +0,0 @@ -/* scala-stm - (c) 2009-2012, Stanford University, PPL */ - -package scala.concurrent.stm - -import org.scalatest.FunSuite -import java.util.concurrent.CountDownLatch - - -class CallbackSuite extends FunSuite { - - class UserException extends Exception - - test("many callbacks") { - var n = 0 - val x = Ref(0) - atomic { implicit t => - x() = 1 - for (i <- 0 until 10000) - Txn.afterCommit { _ => n += 1 } - } - assert(n === 10000) - assert(x.single() === 1) - } - - test("beforeCommit upgrade on read-only commit") { - val x = Ref(0) - var ran = false - atomic { implicit t => - assert(x() === 0) - Txn.beforeCommit { _ => - assert(!ran) - x() = 1 - ran = true - } - } - assert(ran) - assert(x.single() === 1) - } - - test("retry in beforeCommit") { - val n = 50 - val x = Ref(0) - val b = Array.tabulate(n) { _ => new CountDownLatch(1) } - val t = new Thread("trigger") { - override def run() { - for (i <- 0 until n) { - b(i).await() - Thread.sleep(5) - x.single() += 1 - } - } - } - var tries = 0 - t.start() - val y = Ref(0) - atomic { implicit t => - tries += 1 - y() = 1 - Txn.beforeCommit { implicit t => - if (x() < n) { - for (i <- 0 until math.min(n, tries)) - b(i).countDown() - retry - } - } - } - assert(tries >= n) - } - - test("exception in beforeCommit") { - val x = Ref[Option[String]](Some("abc")) - intercept[NoSuchElementException] { - atomic { implicit t => - x() = None - Txn.beforeCommit { _ => println(x().get) } - } - } - } - - test("surviving beforeCommit") { - val x = Ref(1) - val y = Ref(2) - val z = Ref(3) - var a = false - var aa = false - var ab = false - var b = false - var ba = false - var bb = false - var bc = false - atomic { implicit t => - Txn.beforeCommit { _ => assert(!a) ; a = true } - atomic { implicit t => - Txn.beforeCommit { _ => assert(!aa) ; aa = true } - x += 1 - if (x() != 0) - retry - } orAtomic { implicit t => - Txn.beforeCommit { _ => assert(!ab) ; ab = true } - y += 1 - if (y() != 0) - retry - } - z += 8 - } orAtomic { implicit t => - Txn.beforeCommit { _ => assert(!b && !ba && !bb && !bc) ; b = true } - atomic { implicit t => - Txn.beforeCommit { _ => assert(!ba) ; ba = true } - z += 1 - if (x() != 0) - retry - } orAtomic { implicit t => - Txn.beforeCommit { _ => assert(!bb) ; bb = true } - x += 1 - if (x() != 0) - retry - } orAtomic { implicit t => - Txn.beforeCommit { _ => assert(b) ; assert(!bc) ; bc = true } - if (x() + y() + z() == 0) - retry - } - z += 16 - } - assert(!a) - assert(!aa) - assert(!ab) - assert(b) - assert(!ba) - assert(!bb) - assert(bc) - assert(x.single() == 1) - assert(y.single() == 2) - assert(z.single() == 19) - } - - test("afterRollback on commit") { - atomic { implicit t => - Txn.afterRollback { _ => assert(false) } - } - } - - test("afterRollback on rollback") { - val x = Ref(10) - var ran = false - atomic { implicit t => - Txn.afterRollback { _ => - assert(!ran) - ran = true - } - if (x() == 10) { - val adversary = new Thread { - override def run() { - x.single.transform(_ + 1) - } - } - adversary.start() - adversary.join() - x() - assert(false) - } - } - assert(ran) - } - - test("afterCommit runs a txn") { - var ran = false - val x = Ref(0) - atomic { implicit t => - x() = 1 - Txn.afterCommit { _ => - atomic { implicit t => - assert(!ran) - ran = true - assert(x() === 1) - x() = 2 - } - } - } - assert(ran) - assert(x.single() === 2) - } - - test("afterCommit doesn't access txn") { - var ran = false - val x = Ref(0) - atomic { implicit t => - x() = 1 - Txn.afterCommit { _ => - intercept[IllegalStateException] { - assert(!ran) - ran = true - x() = 2 - } - } - } - assert(ran) - assert(x.single() === 1) - } - - test("beforeCommit during beforeCommit") { - val handler = new Function1[InTxn, Unit] { - var count = 0 - - def apply(txn: InTxn) { - if (txn eq null) { - // this is the after-atomic check - assert(count === 1000) - } else { - count += 1 - if (count < 1000) - Txn.beforeCommit(this)(txn) - } - } - } - val x = Ref(0) - atomic { implicit t => - x += 1 - Txn.beforeCommit(handler) - } - handler(null) - } - - test("beforeCommit termination") { - val x = Ref(0) - var a = false - intercept[UserException] { - atomic { implicit t => - assert(x() === 0) - Txn.beforeCommit { _ => - assert(!a) - a = true - throw new UserException - } - x += 2 - Txn.beforeCommit { _ => - assert(false) - } - } - } - assert(a) - } - - test("manual optimistic retry") { - var tries = 0 - val x = Ref(0) - atomic { implicit t => - assert(x() === 0) - x += tries - tries += 1 - if (tries < 100) - Txn.rollback(Txn.OptimisticFailureCause('manual_failure, None)) - } - assert(x.single() === 99) - assert(tries === 100) - } - - test("manual optimistic retry during beforeCommit") { - var tries = 0 - val x = Ref(0) - atomic { implicit t => - assert(x() === 0) - x += tries - tries += 1 - Txn.beforeCommit { implicit t => - if (tries < 100) - Txn.rollback(Txn.OptimisticFailureCause('manual_failure, None)) - } - } - assert(x.single() === 99) - assert(tries === 100) - } - - test("whilePreparing") { - var i = 0 - var observed = -1 - val x = Ref(0) - atomic { implicit txn => - i += 1 - x() = i - Txn.whilePreparing { _ => - observed = i - if (i < 4) Txn.rollback(Txn.OptimisticFailureCause('test, None)) - } - } - assert(x.single() == 4) - assert(observed == 4) - assert(i == 4) - } - - test("whilePreparing throws exception") { - intercept[UserException] { - atomic { implicit txn => - Txn.whilePreparing { _ => throw new UserException } - } - } - } - - test("whileCommitting") { - var count = 0 - val x = Ref(0) - atomic { implicit txn => - x() = 1 - Txn.whileCommitting { _ => count += 1 } - } - assert(x.single() == 1) - assert(count == 1) - } - - test("whileCommitting without any accesses") { - var count = 0 - atomic { implicit txn => - Txn.whileCommitting { _ => count += 1 } - } - assert(count == 1) - } - - test("whileCommitting ordering", Slow) { - val numThreads = 10 - val numPutsPerThread = 100000 - val startingGate = new java.util.concurrent.CountDownLatch(1) - val active = Ref(numThreads) - val failure = Ref(null : Throwable) - - val x = Ref(0) - val notifier = new scala.concurrent.forkjoin.LinkedTransferQueue[Int]() - val EOF = -1 - - for (i <- 1 to numThreads) { - (new Thread { - override def run() { - try { - startingGate.await() - for (i <- 1 to numPutsPerThread) { - atomic { implicit txn => - x() = x() + 1 - val y = x() - Txn.whileCommitting { _ => - if ((i & 127) == 0) // try to perturb the timing - Thread.`yield`() - notifier.put(y) - } - } - } - } catch { - case xx: Throwable => failure.single() = xx - } - if (active.single.transformAndGet( _ - 1 ) == 0) - notifier.put(EOF) - } - }).start() - } - - startingGate.countDown() - for (expected <- 1 to numThreads * numPutsPerThread) - assert(expected === notifier.take()) - assert(EOF === notifier.take()) - - if (failure.single() != null) - throw failure.single() - } - - test("accepting external decider") { - val x = Ref(0) - atomic { implicit txn => - x() = 1 - Txn.setExternalDecider(new Txn.ExternalDecider { - def shouldCommit(implicit txn: InTxnEnd): Boolean = { - assert(txn.status == Txn.Prepared) - true - } - }) - } - assert(x.single() === 1) - } - - test("valid duplicate external decider") { - val x = Ref(0) - atomic { implicit txn => - x() = 1 - val d = new Txn.ExternalDecider { - def shouldCommit(implicit txn: InTxnEnd): Boolean = { - assert(txn.status == Txn.Prepared) - true - } - } - assert(d == d) - Txn.setExternalDecider(d) - Txn.setExternalDecider(d) - } - assert(x.single() === 1) - } - - test("invalid duplicate external decider") { - val x = Ref(0) - intercept[IllegalArgumentException] { - atomic { implicit txn => - x() = 1 - val d1 = new Txn.ExternalDecider { def shouldCommit(implicit txn: InTxnEnd): Boolean = true } - val d2 = new Txn.ExternalDecider { def shouldCommit(implicit txn: InTxnEnd): Boolean = true } - assert(d1 != d2) - Txn.setExternalDecider(d1) - Txn.setExternalDecider(d2) - } - } - assert(x.single() === 0) - } - - test("transient reject external decider") { - val x = Ref(0) - var tries = 0 - atomic { implicit txn => - tries += 1 - x() = tries - Txn.setExternalDecider(new Txn.ExternalDecider { - def shouldCommit(implicit txn: InTxnEnd): Boolean = { - assert(txn.status == Txn.Prepared) - tries == 3 - } - }) - } - assert(tries === 3) - assert(x.single() === 3) - } - - test("nested external deciders") { - val x = Ref(0) - var which = 0 - atomic { implicit txn => - atomic { implicit txn => - Txn.setExternalDecider(new Txn.ExternalDecider { - def shouldCommit(implicit txn: InTxnEnd): Boolean = { which = 1 ; true } - }) - if (x.swap(1) == 0) - retry - } orAtomic { implicit txn => - Txn.setExternalDecider(new Txn.ExternalDecider { - def shouldCommit(implicit txn: InTxnEnd): Boolean = { which = 2 ; true } - }) - if (x.swap(2) == 0) - retry - } orAtomic { implicit txn => - Txn.setExternalDecider(new Txn.ExternalDecider { - def shouldCommit(implicit txn: InTxnEnd): Boolean = { which = 3 ; true } - }) - x.swap(3) - } - } - assert(which === 3) - assert(x.single() === 3) - } - - test("external decider throws exception") { - var tries = 0 - val x = Ref(0) - intercept[UserException] { - atomic { implicit txn => - tries += 1 - x() = 1 - Txn.setExternalDecider(new Txn.ExternalDecider { - def shouldCommit(implicit txn: InTxnEnd): Boolean = throw new UserException - }) - } - } - assert(tries === 1) - assert(x.single() === 0) - } - - test("rethrown exception from whileCommitting handler") { - val x = Ref(0) - intercept[UserException] { - val customAtomic = atomic.withPostDecisionFailureHandler { (status, failure) => throw failure } - customAtomic { implicit txn => - Txn.whileCommitting { _ => throw new UserException } - x() = 1 - } - } - assert(x.single() === 1) - } - - test("swallowed exception from whileCommitting handler") { - var swallowed: Throwable = null - val x = Ref(0) - val customAtomic = atomic.withPostDecisionFailureHandler { (status, failure) => - assert(swallowed === null) - assert(status == Txn.Committing) - swallowed = failure - } - customAtomic { implicit txn => - Txn.whileCommitting { _ => throw new UserException } - x() = 1 - } - assert(x.single() === 1) - assert(swallowed.isInstanceOf[UserException]) - } - - test("rethrown exception from afterCommit handler") { - val x = Ref(0) - intercept[UserException] { - val customAtomic = atomic.withPostDecisionFailureHandler { (status, failure) => throw failure } - customAtomic { implicit txn => - Txn.afterCommit { _ => throw new UserException } - x() = 1 - } - } - assert(x.single() === 1) - } - - test("swallowed exception from afterCommit handler") { - var swallowed: Throwable = null - val x = Ref(0) - val customAtomic = atomic.withPostDecisionFailureHandler { (status, failure) => - assert(swallowed === null) - assert(status == Txn.Committed) - swallowed = failure - } - customAtomic { implicit txn => - Txn.afterCommit { _ => throw new UserException } - x() = 1 - } - assert(x.single() === 1) - assert(swallowed.isInstanceOf[UserException]) - } - - test("rethrown exception from afterRollback handler") { - val x = Ref(0) - intercept[UserException] { - val customAtomic = atomic.withPostDecisionFailureHandler { (status, failure) => throw failure } - customAtomic { implicit txn => - Txn.afterRollback { _ => throw new UserException } - x() = 1 - throw new InterruptedException - } - } - assert(x.single() === 0) - } - - test("swallowed exception from afterRollback handler") { - var swallowed: Throwable = null - val x = Ref(0) - val customAtomic = atomic.withPostDecisionFailureHandler { (status, failure) => - assert(swallowed === null) - assert(status.isInstanceOf[Txn.RolledBack]) - swallowed = failure - } - intercept[InterruptedException] { - customAtomic { implicit txn => - Txn.afterRollback { _ => throw new UserException } - x() = 1 - throw new InterruptedException - } - } - assert(x.single() === 0) - assert(swallowed.isInstanceOf[UserException]) - } - - test("rethrow afterRollback exception cancels retry") { - val x = Ref(0) - intercept[UserException] { - val customAtomic = atomic.withPostDecisionFailureHandler { (status, failure) => throw failure } - customAtomic { implicit txn => - Txn.afterRollback { _ => throw new UserException } - if (x() == 0) - retry - } - } - assert(x.single() === 0) - } - - test("UserException as control flow") { - val x = Ref(0) - intercept[UserException] { - val customAtomic = atomic.withControlFlowRecognizer { - case x: UserException => true - } - customAtomic { implicit txn => - x() = 1 - throw new UserException - } - } - assert(x.single() === 1) - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/CommitBarrierSuite.scala b/benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/CommitBarrierSuite.scala deleted file mode 100644 index d28abaae..00000000 --- a/benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/CommitBarrierSuite.scala +++ /dev/null @@ -1,447 +0,0 @@ -/* scala-stm - (c) 2009-2016, Stanford University, PPL */ - -package scala.concurrent.stm - -import org.scalatest.FunSuite -import skel.SimpleRandom -import java.util.concurrent.TimeUnit -import concurrent.forkjoin.LinkedTransferQueue -import util.control.Breaks - -class CommitBarrierSuite extends FunSuite { - - test("single member commit") { - val x = Ref(0) - val cb = CommitBarrier(Long.MaxValue) - val m = cb.addMember() - val z = m.atomic { implicit t => - x() = x() + 1 - "result" - } - assert(z === Right("result")) - assert(x.single() === 1) - } - - test("single member cancel") { - val x = Ref(0) - val cb = CommitBarrier(60000) - val m = cb.addMember() - val z = m.atomic { implicit t => - m.cancel(CommitBarrier.UserCancel("cancel")) - x() = x() + 1 - "result" - } - assert(z === Left(CommitBarrier.UserCancel("cancel"))) - assert(x.single() === 0) - - // commit barrier can still be used - val m2 = cb.addMember() - val z2 = m2.atomic { implicit t => - x() = x() + 1 - "result2" - } - assert(z2 === Right("result2")) - assert(x.single() === 1) - } - - test("single member failure") { - val x = Ref(0) - val cb = CommitBarrier(60000) - val m = cb.addMember() - intercept[Exception] { - m.atomic { implicit t => - x() = x() + 1 - throw new Exception - } - } - assert(x.single() === 0) - - // commit barrier is now dead - intercept[IllegalStateException] { - cb.addMember() - } - } - - test("override executor") { - val x = Ref(0) - val cb = CommitBarrier(60000) - val m = cb.addMember() - m.executor = m.executor.withRetryTimeout(10) - intercept[InterruptedException] { - m.atomic { implicit txn => - if (x() == 0) - retry - x() = 10 - } - } - assert(x.single() === 0) - - // commit barrier is now dead - intercept[IllegalStateException] { - cb.addMember() - } - } - - def parRun(n: Int)(body: Int => Unit) { - // the CountDownLatch is not strictly necessary, but increases the chance - // of truly concurrent execution - val startingGate = new java.util.concurrent.CountDownLatch(1) - - val failure = Ref(null : Throwable) - - val threads = new Array[Thread](n) - for (i <- 0 until n) { - threads(i) = new Thread() { - override def run() { - startingGate.await() - try { - body(i) - } catch { - case x : Throwable => failure.single() = x - } - } - } - threads(i).start() - } - - startingGate.countDown() - - for (t <- threads) { - while (t.isAlive && failure.single() == null) { - t.join(10) - } - } - - if (failure.single() != null) { - throw failure.single() - } - } - - def runStress(barrierSize: Int, - barrierCount: Int, - check: Boolean = true, - failurePct: Int = 0): Long = { - val refs = Array.tabulate(barrierSize) { _ => Ref(0) } - val cbs = Array.tabulate(barrierCount) { _ => CommitBarrier(60000) } - val members = Array.tabulate(barrierCount, barrierSize) { (i, _) => cbs(i).addMember() } - val t0 = System.nanoTime - parRun(barrierSize + (if (check) 1 else 0)) { j => - val rand = new SimpleRandom() - if (j == barrierSize) { - // we are the cpu-hogging observer - var prev = 0 - var samples = 0 - while (prev < barrierCount) { - val x = refs(rand.nextInt(barrierSize)).single() - assert(x >= prev) - prev = x - samples += 1 - if ((samples % 137) == 0) { - // give single-threaded machines a fighting chance - Thread.`yield`() - } - } - } else { - // we are a member - for (m <- members) { - // failurePct/2 out of 100% -> cancel before atomic - // failurePct/2 out of 100% -> cancel inside atomic - val p = rand.nextInt(200) - if (p < failurePct) - m(j).cancel(CommitBarrier.UserCancel("early")) - - m(j).atomic { implicit txn => - assert(p >= failurePct) - if (p < failurePct * 2) - m(j).cancel(CommitBarrier.UserCancel("late, inside")) - refs(j) += 1 - } - } - } - } - System.nanoTime - t0 - } - - test("stress 2") { - runStress(2, 10000) - } - - test("stress 10") { - runStress(10, 500) - } - - test("stress 400") { - runStress(400, 10) - } - - test("partial success 2") { - runStress(2, 10000, false, 25) - } - - test("partial success 400") { - runStress(400, 10, false, 75) - } - - test("perf 2") { - val count = 20000 - val elapsed = runStress(2, count, false) - println("commit barrier, 2 threads, " + (elapsed / count) + " nanos/barrier") - } - - test("perf 10") { - val count = 2000 - val elapsed = runStress(10, count, false) - println("commit barrier, 10 threads, " + (elapsed / count) + " nanos/barrier") - } - - test("timeout") { - val refs = Array.tabulate(2) { _ => Ref(0) } - val cb = CommitBarrier(100, TimeUnit.MILLISECONDS) - val members = Array.tabulate(2) { _ => cb.addMember() } - val t0 = System.currentTimeMillis - val elapsed = Array(0L, 0L) - parRun(2) { i => - try { - val z = members(i).atomic { implicit txn => - refs(i)() = 1 - if (i == 1) Thread.sleep(200) - } - assert(z === Left(CommitBarrier.Timeout)) - assert(refs(i).single() === 0) - } finally { - elapsed(i) = System.currentTimeMillis - t0 - } - } - assert(elapsed(0) >= 100 && elapsed(0) < 150, elapsed.toList) - assert(elapsed(1) >= 200, elapsed.toList) - } - - test("interrupt") { - val refs = Array.tabulate(2) { _ => Ref(0) } - val cb = CommitBarrier(60000) - val members = Array.tabulate(2) { _ => cb.addMember() } - val target = new LinkedTransferQueue[Thread]() - parRun(3) { i => - if (i == 0) { - // thread 0 is slow - val z = members(i).atomic { implicit txn => - refs(i)() = 1 - Thread.sleep(100) - "result" - } - assert(z.isLeft) - assert(z.left.get.isInstanceOf[CommitBarrier.MemberUncaughtExceptionCause]) - assert(z.left.get.asInstanceOf[CommitBarrier.MemberUncaughtExceptionCause].x.isInstanceOf[InterruptedException]) - assert(refs(i).single() === 0) - } else if (i == 1) { - // thread 1 must wait and receives the interrupt - intercept[InterruptedException] { - members(i).atomic { implicit txn => - refs(i)() = 1 - target.put(Thread.currentThread()) - } - } - } else { - target.take().interrupt() - } - } - } - - test("control flow exception") { - val slower = Ref(0) - val ref = Ref(0) - val cb = CommitBarrier(60000) - val b = new Breaks() - - b.breakable { - while (true) { - val m = cb.addMember() - new Thread() { - override def run() { - Thread.sleep(100) - m.atomic { implicit txn => - slower() = slower() + 1 - } - } - }.start() - cb.addMember().atomic { implicit txn => - ref() = ref() + 1 - b.break - } - } - } - - assert(slower.single() === 1) - assert(ref.single() === 1) - } - - def doCycle(cycleSize: Int) { - val refs = Array.tabulate(cycleSize) { _ => Ref(0) } - val cb = CommitBarrier(60000) - val members = Array.tabulate(cycleSize) { _ => cb.addMember() } - parRun(cycleSize) { i => - val z = members(i).atomic { implicit txn => - refs(i) += 1 - refs((i + 1) % cycleSize) += 1 - } - assert(z.isLeft) - assert(z.left.get.isInstanceOf[CommitBarrier.MemberCycle]) - } - } - - test("cycle 2 x 1000") { - for (i <- 0 until 1000) - doCycle(2) - } - - test("cycle 3 x 1000") { - for (i <- 0 until 1000) - doCycle(3) - } - - test("cycle 1000 x 3") { - for (i <- 0 until 3) - doCycle(1000) - } - - test("auto-cancel") { - for (reps <- 0 until 1000) { - val cb = CommitBarrier(60000) - var i = 0 - val commits = new java.util.concurrent.atomic.AtomicInteger(0) - val x = Ref(0) - val y = Ref(0) - val z = cb.addMember().atomic { implicit txn => - x() = 1 - val m = cb.addMember() - i += 1 - val t = new Thread() { - override def run() { - m.atomic { implicit txn => - y() = i - txn.afterCommit { _ => commits.incrementAndGet() } - } - } - } - t.start() - txn.afterCommit { _ => t.join() } - if (i < 10) - Txn.rollback(Txn.OptimisticFailureCause('test, None)) - "hello" - } - assert(z === Right("hello")) - assert(commits.get() === 1) - assert(x.single() === 1) - assert(y.single() === 10) - } - } - - test("no auto-cancel") { - val x = Ref(0) - val cb = CommitBarrier(60000) - var t: Thread = null - val outer = cb.addMember() - outer.atomic { implicit txn => - val inner = cb.addMember(false) - t = new Thread() { - override def run() { - inner.atomic { implicit txn => - x() = x() + 1 - } - } - } - t.start() - - outer.cancel(CommitBarrier.UserCancel("cancel outer")) - } - t.join() - assert(x.single() === 1) - } - - test("embedded orAtomic") { - val x = Ref(0) - val y = Ref(0) - val z = CommitBarrier(60000).addMember().atomic { implicit txn => - atomic { implicit txn => - y() = 1 - if (x() == 0) - retry - "first" - } orAtomic { implicit txn => - x() = 1 - if (y() == 1) - retry - "second" - } - } - assert(z === Right("second")) - assert(x.single() === 1) - assert(y.single() === 0) - } - - test("recursive") { - val commits = Ref(0).single - def body(m: CommitBarrier.Member, depth: Int)(implicit txn: InTxn) { - if (depth < 8) { - for (m <- Array.tabulate(2) { _ => m.commitBarrier.addMember() }) { - new Thread() { - override def run() { - m.atomic { implicit txn => - body(m, depth + 1) - Txn.afterCommit { _ => commits += 1 } - } - } - }.start() - } - } - } - val m = CommitBarrier(60000).addMember() - m.atomic { implicit txn => body(m, 0) } - - // by sleeping and then awaiting we can (probabilistically) catch both - // too few and too many commits - Thread.sleep(100) - commits.await { _ == 510 } - } - - test("multi-barrier deadlock cycle") { - for (tries <- 0 to 100) { - val a1 = Ref(0) - val a2 = Ref(0) - - val cb1 = CommitBarrier(1000) - val cb1m1 = cb1.addMember() - val cb1m2 = cb1.addMember() - val cb2 = CommitBarrier(1000) - val cb2m1 = cb2.addMember() - val cb2m2 = cb2.addMember() - - val t1 = new Thread() { - override def run() { - cb1m1.atomic { implicit txn => a1() = a1() + 1 } - } - } - val t2 = new Thread() { - override def run() { - cb1m2.atomic { implicit txn => a2() = a2() + 1 } - } - } - val t3 = new Thread() { - override def run() { - cb2m1.atomic { implicit txn => a1() = a1() + 1 } - } - } - val t4 = new Thread() { - override def run() { - cb2m2.atomic { implicit txn => a2() = a2() + 1 } - } - } - - t1.start(); t2.start(); t3.start(); t4.start() - t1.join(); t2.join(); t3.join(); t4.join() - - assert(a1.single() == 2); - assert(a2.single() == 2); - } - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/ContentionSuite.scala b/benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/ContentionSuite.scala deleted file mode 100644 index fd04b338..00000000 --- a/benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/ContentionSuite.scala +++ /dev/null @@ -1,170 +0,0 @@ -/* scala-stm - (c) 2009-2011, Stanford University, PPL */ - -package scala.concurrent.stm - -import org.scalatest.FunSuite -import skel.SimpleRandom - -class ContentionSuite extends FunSuite { - // probability that two txns of size M touch the same element out of N - // (M substantially less than N) is about 1 - (1 - M/N)^M - - var count = 0 - for (numRefs <- List(1000, 100000)) { - for (readPct <- List(80)) { - for (numThreads <- List(4, 32)) { - for (txnSize <- List(8, 64, 16)) { - for (nested <- List(false, true)) { - val opsPerThread = 20000000 / numThreads - val numReads = opsPerThread * readPct / 100 - val numWrites = opsPerThread - numReads - val name = "%d refs, %d %% read, %d threads, %d ops/txn, nested=%s".format( - numRefs, readPct, numThreads, txnSize, nested) - if (count < 4) { - test("small " + name) { - runTest(numRefs, numReads / 10, numWrites / 10, numThreads, txnSize, nested, "small " + name) - } - } - test(name, Slow) { - runTest(numRefs, numReads, numWrites, numThreads, txnSize, nested, name) - } - count += 1 - } - } - } - } - } - - /** Runs one thread per element of `txnSizes`. */ - def runTest(numRefs: Int, numReads: Int, numWrites: Int, numThreads: Int, txnSize: Int, nested: Boolean, name: String) { - val values = (0 until 37) map { i => "foo" + i } - - val refs = Array.tabulate(numRefs) { _ => Ref(values(0)) } - - val threads = for (t <- 0 until numThreads) yield new Thread { - override def run { - var rand = new SimpleRandom(hashCode) - var i = 0 - while (i < numReads + numWrites) { - val body: (InTxn => SimpleRandom) = { implicit txn => - val r = rand.clone - var j = 0 - while (j < txnSize) { - val key = r.nextInt(numRefs) - val pct = r.nextInt(numReads + numWrites) - if (pct < numReads) - refs(key)() - else - refs(key)() = values(r.nextInt(values.length)) - j += 1 - } - if (r.nextInt(100) < 10) { - Txn.whilePreparing { _ => } - Txn.whileCommitting { _ => } - Txn.setExternalDecider(new Txn.ExternalDecider { def shouldCommit(implicit txn: InTxnEnd) = true }) - } - r - } - if (!nested) - rand = atomic(body) - else { - rand = atomic { implicit txn => - atomic(body) orAtomic { implicit txn => throw new Error("execution should not reach here") } - } - } - i += txnSize - } - } - } - - val begin = System.currentTimeMillis - for (t <- threads) t.start() - for (t <- threads) t.join() - val elapsed = System.currentTimeMillis - begin - - val nanosPerOp = elapsed * 1000000L / ((numReads + numWrites) * 1L * numThreads) - printf("ContentionSuite: %s, %d nanos/op aggregate throughput\n", name, nanosPerOp) - } - - test("starving elder small") { runElderTest(8, 10) } - test("starving elder large", Slow) { runElderTest(32, 100) } - - def runElderTest(writerCount: Int, numElders: Int) { - val writersStarted = Ref(0) // elder can't run until all writers are started - val refs = Array.tabulate(1000) { i => Ref(i.toString) } - val eldersLeft = Ref(numElders) // writers end after all elders are done - - val writers = for(i <- 0 until writerCount) yield new Thread("writer " + i) { - override def run { - writersStarted.single += 1 - - val rand = new skel.SimpleRandom - while (true) { - val a = refs(rand.nextInt(refs.length)) - val b = refs(rand.nextInt(refs.length)) - val pct = rand.nextInt(100) - if (pct < 70) { - // swap in a txn - atomic { implicit txn => - if (eldersLeft() == 0) - return - - a() = b.swap(a()) - } - } else { - if (eldersLeft.single() == 0) - return - - // swap using DCAS or DCASI - var done = false - while (!done) { - val a0 = a.single() - val b0 = b.single() - if (pct < 85) - done = atomic.compareAndSet(a, a0, b0, b, b0, a0) - else - done = atomic.compareAndSetIdentity(a, a0, b0, b, b0, a0) - } - } - } - } - } - - for (w <- writers) w.start() - - while (eldersLeft.single() > 0) { - var tries = 0 - val sum = atomic { implicit txn => - tries += 1 - if (writersStarted() < writerCount) - retry - refs.foldLeft(0) { _ + _.get.toInt } - } - val n = refs.length - assert(sum === n * (n - 1) / 2) - eldersLeft.single -= 1 - println("elder ran " + tries + " times") - } - - for (w <- writers) w.join() - } - - test("colliding trySet") { - val x = Ref(0) - val total = Ref(0) - val threads = for (t <- 0 until 10) yield new Thread { - override def run { - var failures = 0 - for (i <- 0 until 1000000) { - if (!x.single.trySet(t)) - failures += 1 - } - total.single += failures - } - } - for (t <- threads) t.start - for (t <- threads) t.join - assert(total.single() > 0) - println(total.single() + " rejected trySet-s") - } -} \ No newline at end of file diff --git a/benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/FlipperSuite.scala b/benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/FlipperSuite.scala deleted file mode 100644 index 3be9592f..00000000 --- a/benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/FlipperSuite.scala +++ /dev/null @@ -1,282 +0,0 @@ -/* scala-stm - (c) 2009-2012, Stanford University, PPL */ - -package scala.concurrent.stm - -import java.util.concurrent.CyclicBarrier -import org.scalatest.FunSuite - - -/** Flipper is derived from a test originally used for the ATLAS HTM prototype. - * - * @author Nathan Bronson - */ -class FlipperSuite extends FunSuite { - val DEFAULT_SYNC_COUNT = 3 - val DEFAULT_TRANS_COUNT = 100 - val DEFAULT_INSTR_COUNT = 100 - val DEFAULT_THREAD_COUNT = 4 - val DEFAULT_WORD_COUNT = 4096 - val DEFAULT_FLIP_PROB = 0.5f - val DEFAULT_REF_ARRAY_FACTORY = { (n: Int) => (Array.tabulate[Ref[Int]](n) { _ => Ref(0) }) : IndexedSeq[Ref[Int]] } - val DEFAULT_MASKED_READER = { (r: Ref[Int], m: Int) => r.single() & m } - - val TARRAY_REF_ARRAY_FACTORY = { (n: Int) => TArray.ofDim[Int](n).refs } - - val GET_WITH_MASKED_READER = { (r: Ref[Int], m: Int) => r.single.getWith( _ & m ) } - val RELAXED_GET_MASKED_READER = { (r: Ref[Int], m: Int) => - r.single.relaxedGet({ (seen, correct) => (seen & m) == (correct & m) }) & m - } - val TRANSFORM_IF_DEFINED_MASKED_READER = { (r: Ref[Int], m: Int) => - val f = r.single.transformIfDefined { case v if (v & m) != 0 => v } - if (f) m else 0 - } - - test("small flipper test") { - Config( - DEFAULT_SYNC_COUNT, - DEFAULT_TRANS_COUNT / 2, - DEFAULT_INSTR_COUNT / 2, - DEFAULT_THREAD_COUNT, - DEFAULT_WORD_COUNT / 2, - DEFAULT_FLIP_PROB, - 0, - DEFAULT_REF_ARRAY_FACTORY, - DEFAULT_MASKED_READER).runTest() - } - - test("small flipper test using getWith") { - Config( - DEFAULT_SYNC_COUNT, - DEFAULT_TRANS_COUNT / 2, - DEFAULT_INSTR_COUNT / 2, - DEFAULT_THREAD_COUNT, - DEFAULT_WORD_COUNT / 2, - DEFAULT_FLIP_PROB, - 0, - DEFAULT_REF_ARRAY_FACTORY, - GET_WITH_MASKED_READER).runTest() - } - - test("small flipper test using relaxedGet") { - Config( - DEFAULT_SYNC_COUNT, - DEFAULT_TRANS_COUNT / 2, - DEFAULT_INSTR_COUNT / 2, - DEFAULT_THREAD_COUNT, - DEFAULT_WORD_COUNT / 2, - DEFAULT_FLIP_PROB, - 0, - DEFAULT_REF_ARRAY_FACTORY, - RELAXED_GET_MASKED_READER).runTest() - } - - test("small flipper test reading using transformIfDefined") { - Config( - DEFAULT_SYNC_COUNT, - DEFAULT_TRANS_COUNT / 2, - DEFAULT_INSTR_COUNT / 2, - DEFAULT_THREAD_COUNT, - DEFAULT_WORD_COUNT / 2, - DEFAULT_FLIP_PROB, - 0, - DEFAULT_REF_ARRAY_FACTORY, - TRANSFORM_IF_DEFINED_MASKED_READER).runTest() - } - - test("default flipper test", Slow) { - Config( - DEFAULT_SYNC_COUNT, - DEFAULT_TRANS_COUNT, - DEFAULT_INSTR_COUNT, - DEFAULT_THREAD_COUNT, - DEFAULT_WORD_COUNT, - DEFAULT_FLIP_PROB, - 0, - DEFAULT_REF_ARRAY_FACTORY, - DEFAULT_MASKED_READER).runTest() - } - - test("small flipper test w/TArray") { - Config( - DEFAULT_SYNC_COUNT, - DEFAULT_TRANS_COUNT / 2, - DEFAULT_INSTR_COUNT / 2, - DEFAULT_THREAD_COUNT, - DEFAULT_WORD_COUNT / 2, - DEFAULT_FLIP_PROB, - 0, - TARRAY_REF_ARRAY_FACTORY, - DEFAULT_MASKED_READER).runTest() - } - - test("default flipper test w/TArray", Slow) { - Config( - DEFAULT_SYNC_COUNT, - DEFAULT_TRANS_COUNT, - DEFAULT_INSTR_COUNT, - DEFAULT_THREAD_COUNT, - DEFAULT_WORD_COUNT, - DEFAULT_FLIP_PROB, - 0, - TARRAY_REF_ARRAY_FACTORY, - DEFAULT_MASKED_READER).runTest() - } - - test("random flipper test", Slow) { - for (i <- 0 until 1) { - Config( - DEFAULT_SYNC_COUNT, - DEFAULT_TRANS_COUNT, - DEFAULT_INSTR_COUNT, - DEFAULT_THREAD_COUNT, - DEFAULT_WORD_COUNT, - DEFAULT_FLIP_PROB, - System.currentTimeMillis + System.nanoTime, - DEFAULT_REF_ARRAY_FACTORY, - DEFAULT_MASKED_READER).runTest() - } - } - - case class Config(syncCount: Int, - transCount: Int, - instrCount: Int, - threadCount: Int, - wordCount: Int, - flipProb: Float, - randSeed: Long, - refArrayFactory: Int => IndexedSeq[Ref[Int]], - maskedReader: (Ref[Int], Int) => Int) { - - private val len = syncCount*transCount*instrCount*threadCount - private val rand = new java.util.Random(randSeed) - val R = Array.tabulate(len)({ _ => rand.nextInt(wordCount) }) - val F = Array.tabulate(len)({ _ => rand.nextDouble() < flipProb }) - - def index(id: Int, sync: Int, trans: Int, instr: Int) = { - ((id*syncCount+sync)*transCount+trans)*instrCount+instr - } - - def runTest() { - println(this) - - print("computing sequentially...") - Console.flush() - - val P = Array.tabulate[Ref[Boolean]](len)({ _ => Ref(false) }) - val expected = computeSequential(this, P) - - print("\ncomputing in parallel with transactions...") - Console.flush() - - val actual = computeParallelTxn(this, P) - - println() - for (i <- 0 until expected.length) { - assert(expected(i).single.get === actual(i).single.get) - } - } - } - - abstract class FlipperTask(val config: Config, - val A: IndexedSeq[Ref[Int]], - val P: Array[Ref[Boolean]], - val computeP: Boolean, - val id: Int, - val sync: Int) extends (() => Unit) { - def doWork(task: => Unit) - - def maskedRead(ref: Ref[Int], mask: Int): Int = config.maskedReader(ref, mask) - def read[T](ref: Ref[T]): T - def write[T](ref: Ref[T], v: T) - - def apply() { - val mask = 1 << id - for (trans <- 0 until config.transCount) { - doWork { - for (instr <- 0 until config.instrCount) { - val i = config.index(id, sync, trans, instr) - val target = config.R(i) - val p = maskedRead(A(target), mask) != 0 - if (computeP) { - write(P(i), p) - } - else { - assert(read(P(i)) === p) - } - if (config.F(i)) { - // do some work before storing to A, to increase probability of a conflict - var h = i - var j = 0 - while (j < 10000) { - h |= 1+((h >>> 1)^(h*13)) - j += 1 - } - if (h == i) println("?") - write(A(target), read(A(target)) ^ mask) - } - } - } - //println("thread " + id + " transaction " + trans + " completed (" + computeP + ")") - } - } - } - - def computeSequential(config: Config, P: Array[Ref[Boolean]]): Array[Ref[Int]] = { - val A = Array.tabulate[Ref[Int]](config.wordCount) { _ => Ref(0) } - for (sync <- 0 until config.syncCount) { - for (thread <- 0 until config.threadCount) { - (new FlipperTask(config, A, P, true, thread, sync) { - def read[T](ref: Ref[T]): T = ref.single() - def write[T](ref: Ref[T], v: T) { ref.single() = v } - def doWork(task: => Unit) { task } - })() - } - } - A - } - - def computeParallelTxn(config: Config, P: Array[Ref[Boolean]]): IndexedSeq[Ref[Int]] = { - val A = config.refArrayFactory(config.wordCount) - for (sync <- 0 until config.syncCount) { - val tasks = (for (thread <- 0 until config.threadCount) yield { - new FlipperTask(config, A, P, false, thread, sync) { - implicit var txn: InTxn = null - - def read[T](ref: Ref[T]): T = ref() - def write[T](ref: Ref[T], v: T) { ref() = v } - def doWork(task: => Unit) { - atomic { t => - txn = t - task - } - txn = null - } - } - }) - parallelRun(tasks) - } - A - } - - private def parallelRun(tasks: Iterable[() => Unit]) { - val barrier = new CyclicBarrier(tasks.size) - var failure: Throwable = null - val threads = for (task <- tasks.toList) yield new Thread { - override def run() { - barrier.await - try { - task() - } catch { - case x: Throwable => { - x.printStackTrace() - failure = x - } - } - } - } - for (t <- threads) t.start() - for (t <- threads) t.join() - if (null != failure) - throw failure - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/HistogramSuite.scala b/benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/HistogramSuite.scala deleted file mode 100644 index b3486f2d..00000000 --- a/benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/HistogramSuite.scala +++ /dev/null @@ -1,120 +0,0 @@ -/* scala-stm - (c) 2009-2010, Stanford University, PPL */ - -package scala.concurrent.stm - -import java.util.concurrent.CyclicBarrier -import org.scalatest.{FunSuite, Tag} - - -class HistogramSuite extends FunSuite { - - for ((opsPerTest, name, slow) <- List((10000, "10K", false), - (1000000, "1M", true))) { - for (buckets <- List(1, 30, 10000)) { - for (threads <- List(1, 2, 4, 8, 16, 32, 64, 128, 256, 512) if (threads <= 2*Runtime.getRuntime.availableProcessors)) { - for (useTArray <- List(false, true)) { - val str = ("" + buckets + " buckets, " + threads + " threads, " + - (if (useTArray) "TArray[Int]" else "Array[Ref[Int]]")) - addTest("single-op-txn, " + str + ", " + name, Slow) { - histogram(buckets, threads, opsPerTest / threads, useTArray, 100, 1) - } - - for ((accesses, slow2) <- List((1, true), (3, false), (100, true))) { - addTest("txn, " + str + ", " + accesses + " incr per txn, " + name, Slow) { - histogram(buckets, threads, opsPerTest / threads, useTArray, 0, accesses) - } - val g = if (slow || slow2) List[Tag](Slow) else List.empty[Tag] - addTest("mix, " + str + ", " + accesses + " incr per txn " + name, g:_*) { - histogram(buckets, threads, opsPerTest / threads, useTArray, 50, accesses) - } - } - } - } - } - } - - private def addTest(name: String, tags: Tag*)(block: => Unit) { test(name, tags:_*)(block) } - - def histogram(bucketCount: Int, - workerCount: Int, - samplesPerWorker: Int, - useTArray: Boolean, - singlePct: Int, - samplesPerTxn: Int) { - - val buckets: IndexedSeq[Ref[Int]] = (if (useTArray) { - TArray.ofDim[Int](bucketCount).refs - } else { - Array.tabulate(bucketCount)({ _ => Ref(0)}) - }) - val threads = new Array[Thread](workerCount) - val barrier = new CyclicBarrier(workerCount, new Runnable { - var start = 0L - def run { - val now = System.nanoTime - if (start == 0) { - start = now - } else { - val elapsed = now - start - println("hist(" + bucketCount + "," + workerCount + "," + samplesPerWorker + "," + - useTArray + "," + singlePct + - "," + samplesPerTxn + ") total_elapsed=" + elapsed + " nanos, throughput=" + - (samplesPerWorker * workerCount * 1000000000L) / elapsed + " ops/sec, per_thread_latency=" + - elapsed / samplesPerWorker + " nanos/op, avg_arrival=" + - elapsed / (samplesPerWorker * workerCount) + " nanos/op") - } - } - }) - - for (worker <- 0 until workerCount) { - val work = new Runnable { - def run { - barrier.await - var i = 0 - while (i < samplesPerWorker) { - if (math.abs(hash(i, worker) % 100) < singlePct) { - if ((i % 2) == 0) { - buckets(math.abs(hash(worker, i) % bucketCount)).single.transform(_ + 1) - } else { - val nt = buckets(math.abs(hash(worker, i) % bucketCount)).single - var x = nt() - while (!nt.compareAndSet(x, x + 1)) x = nt() - } - i += 1 - } else { - atomic { implicit t => - var j = 0 - while (j < samplesPerTxn && i + j < samplesPerWorker) { - val tv = buckets(math.abs(hash(worker, i + j) % bucketCount)) - //tv.getAndTransform(_ + 1) - tv() = tv() + 1 - //tv() = tv.bind.readForWrite + 1 - j += 1 - } - } - i += samplesPerTxn - } - } - barrier.await - } - } - if (worker < workerCount - 1) { - threads(worker) = new Thread(work, "worker " + worker) - threads(worker).start - } else { - work.run - } - } - - for (worker <- 0 until workerCount - 1) threads(worker).join - - val sum = buckets.map(_.single.get).reduceLeft(_+_) - assert(samplesPerWorker * workerCount === sum) - } - - private def hash(i: Int, j: Int) = { - var h = i * 37 + j * 101 - h ^= (h >>> 20) ^ (h >>> 12) - h ^ (h >>> 7) ^ (h >>> 4) - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/InterruptSuite.scala b/benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/InterruptSuite.scala deleted file mode 100644 index 8ab8f320..00000000 --- a/benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/InterruptSuite.scala +++ /dev/null @@ -1,133 +0,0 @@ -/* scala-stm - (c) 2009-2016, Stanford University, PPL */ - -package scala.concurrent.stm - -import org.scalatest.{Tag, FunSuite} -import skel.SimpleRandom -import java.util.concurrent.atomic.AtomicInteger - -/** Verifies that blocking STM operations can be interrupted. */ -class InterruptSuite extends FunSuite { - - - test("txn retry arriving interrupt") { - delayedInterrupt(100) - val x = Ref(0) - intercept[InterruptedException] { - atomic { implicit txn => - if (x() == 0) retry - } - } - } - - test("txn retry pending interrupt") { - Thread.currentThread.interrupt() - val x = Ref(0) - intercept[InterruptedException] { - atomic { implicit txn => - if (x() == 0) retry - } - } - } - - test("single await arriving interrupt") { - delayedInterrupt(100) - val x = Ref(0) - intercept[InterruptedException] { - x.single.await( _ != 0 ) - } - } - - test("single await pending interrupt") { - Thread.currentThread.interrupt() - val x = Ref(0) - intercept[InterruptedException] { - x.single.await( _ != 0 ) - } - } - - test("random interrupts during contention") { - val refs = Array.tabulate(100)( _ => Ref(0) ) - val txnInterrupts = new AtomicInteger - val nonTxnInterrupts = new AtomicInteger - var failure = null : Throwable - lazy val threads: Array[Thread] = Array.tabulate[Thread](10)( _ => new Thread { - override def run() { - try { - for (i <- 0 until 10000) { - try { - atomic { implicit txn => - for (r <- refs) r() = r() + 1 - } - } catch { - case x: InterruptedException => txnInterrupts.incrementAndGet - } - for (r <- refs) { - try { - r.single += 1 - } catch { - case x: InterruptedException => nonTxnInterrupts.incrementAndGet - } - } - threads(SimpleRandom.nextInt(threads.length)).interrupt() - } - } catch { - case x: Throwable => failure = x - } - } - }) - for (t <- threads) t.start() - for (t <- threads) t.join() - if (failure != null) - throw failure - println(txnInterrupts.get + " txn rollbacks, " + nonTxnInterrupts.get + " non-txn interrupts") - } - - //////// machinery for InterruptSuite - - private val pendingInterrupts = new ThreadLocal[List[Thread]] { override def initialValue = Nil } - - override protected def test(testName: String, testTags: Tag*)(f: => Any)(implicit pos: org.scalactic.source.Position): Unit = { - super.test(testName, testTags: _*) { - // we have to use another thread, because sbt overrides .interrupt() on - // its worker threads - var failure = null : Throwable - val t = new Thread { - override def run() { - try { - f - } catch { - case x: Throwable => failure = x - } finally { - while (!pendingInterrupts.get.isEmpty) { - try { - pendingInterrupts.get.head.join() - pendingInterrupts.set(pendingInterrupts.get.tail) - } catch { - case _: Throwable => - } - } - Thread.interrupted - } - } - } - t.start() - t.join() - if (failure != null) - throw failure - } - } - - private def delayedInterrupt(delay: Long) { delayedInterrupt(Thread.currentThread, delay) } - - private def delayedInterrupt(target: Thread, delay: Long) { - val t = new Thread { - override def run() { - Thread.sleep(delay) - target.interrupt() - } - } - pendingInterrupts.set(t :: pendingInterrupts.get) - t.start() - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/IsolatedRefSuite.scala b/benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/IsolatedRefSuite.scala deleted file mode 100644 index 69930e73..00000000 --- a/benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/IsolatedRefSuite.scala +++ /dev/null @@ -1,644 +0,0 @@ -/* scala-stm - (c) 2009-2014, Stanford University, PPL */ - -package scala.concurrent.stm - -import org.scalatest.FunSuite -import java.util.concurrent.TimeUnit - - -/** Performs single-threaded tests of `Ref`. */ -class IsolatedRefSuite extends FunSuite { - - // Ref factories produces Ref from an initial value - - object PrimitiveIntFactory extends (Int => Ref[Int]) { - def apply(v0: Int) = Ref(v0) - override def toString() = "Primitive" - } - - class KnownGenericFactory[A : ClassManifest] extends (A => Ref[A]) { - def apply(v0: A) = Ref(v0) - override def toString() = "KnownGeneric" - } - - class UnknownGenericFactory[A] extends (A => Ref[A]) { - def apply(v0: A) = Ref(v0) - override def toString() = "UnknownGeneric" - } - - class ArrayElementFactory[A : ClassManifest] extends (A => Ref[A]) { - def apply(v0: A) = { - val ref = TArray.ofDim[A](10).refs(5) - ref.single() = v0 - ref - } - override def toString() = "ArrayElement" - } - - - // This implements Ref.View, but requires a surrounding InTxn context and - // forwards to Ref's methods. - class DynamicView[A](val ref: Ref[A]) extends Ref.View[A] { - implicit def txn = Txn.findCurrent.get - - def get: A = ref.get - def getWith[Z](f: A => Z): Z = ref.getWith(f) - def relaxedGet(equiv: (A, A) => Boolean): A = ref.relaxedGet(equiv) - def await(f: A => Boolean) { if (!f(get)) retry } - def tryAwait(timeout: Long, unit: TimeUnit)(f: A => Boolean): Boolean = f(get) || { retryFor(timeout, unit) ; false } - def set(v: A) { ref.set(v) } - def trySet(v: A) = ref.trySet(v) - def swap(v: A): A = ref.swap(v) - def compareAndSet(before: A, after: A): Boolean = { - if (get == before) { set(after) ; true } else false - } - def compareAndSetIdentity[B <: A with AnyRef](before: B, after: A): Boolean = { - if (before eq get.asInstanceOf[AnyRef]) { set(after) ; true } else false - } - def transform(f: A => A) { ref.transform(f) } - def getAndTransform(f: A => A): A = ref.getAndTransform(f) - def transformAndGet(f: A => A): A = ref.transformAndGet(f) - override def transformAndExtract[B](f: A => (A,B)): B = ref.transformAndExtract(f) - def transformIfDefined(pf: PartialFunction[A, A]): Boolean = ref.transformIfDefined(pf) - - override def +=(rhs: A)(implicit num: Numeric[A]) { ref += rhs } - override def -=(rhs: A)(implicit num: Numeric[A]) { ref -= rhs } - override def *=(rhs: A)(implicit num: Numeric[A]) { ref *= rhs } - override def /=(rhs: A)(implicit num: Numeric[A]) { ref /= rhs } - - override def hashCode: Int = ref.hashCode - override def equals(rhs: Any): Boolean = ref == rhs - } - - abstract class TestingView[A](innerDepth: Int, val ref: Ref[A]) extends Ref.View[A] { - private def wrap[Z](block: => Z): Z = nest(innerDepth, block) - private def nest[Z](d: Int, block: => Z): Z = { - if (d == 0) - block - else - atomic { implicit txn => nest(d - 1, block) } - } - - protected def view: Ref.View[A] - - def get: A = wrap { view.get } - def getWith[Z](f: A => Z): Z = wrap { view.getWith(f) } - def relaxedGet(equiv: (A, A) => Boolean): A = wrap { view.relaxedGet(equiv) } - def await(f: (A) => Boolean) { wrap { view.await(f) } } - def tryAwait(timeout: Long, unit: TimeUnit)(f: (A) => Boolean): Boolean = wrap { view.tryAwait(timeout, unit)(f) } - def set(v: A) { wrap { view.set(v) } } - def trySet(v: A) = wrap { view.trySet(v) } - def swap(v: A): A = wrap { view.swap(v) } - def compareAndSet(before: A, after: A): Boolean = wrap { view.compareAndSet(before, after) } - def compareAndSetIdentity[B <: A with AnyRef](before: B, after: A): Boolean = wrap { view.compareAndSetIdentity(before, after) } - def transform(f: A => A) { wrap { view.transform(f) } } - def getAndTransform(f: A => A): A = wrap { view.getAndTransform(f) } - def transformAndGet(f: A => A): A = wrap { view.transformAndGet(f) } - override def transformAndExtract[B](f: A => (A,B)): B = wrap { view.transformAndExtract(f) } - def transformIfDefined(pf: PartialFunction[A, A]): Boolean = wrap { view.transformIfDefined(pf) } - - override def +=(rhs: A)(implicit num: Numeric[A]) { wrap { view += rhs } } - override def -=(rhs: A)(implicit num: Numeric[A]) { wrap { view -= rhs } } - override def *=(rhs: A)(implicit num: Numeric[A]) { wrap { view *= rhs } } - override def /=(rhs: A)(implicit num: Numeric[A]) { wrap { view /= rhs } } - - override def hashCode: Int = ref.hashCode - override def equals(rhs: Any): Boolean = ref == rhs - } - - trait ViewFactory { - def apply[A](ref: Ref[A], innerDepth: Int): Ref.View[A] - } - - object SingleAccess extends ViewFactory { - def apply[A](ref: Ref[A], innerDepth: Int): Ref.View[A] = new TestingView[A](innerDepth, ref) { - protected def view = ref.single - } - override def toString = "Single" - } - - object RefAccess extends ViewFactory { - def apply[A](ref: Ref[A], innerDepth: Int): Ref.View[A] = new TestingView[A](innerDepth, ref) { - protected val view = new DynamicView[A](ref) - } - override def toString = "Ref" - } - - // The test environment is determined by - // outerLevels: the number of atomic block nesting levels that surround - // the entire test; - // innerLevels: the number of atomic block nesting levels that surround - // the individual operations of the test; - // refFactory: Ref[Int] can be created with or without the appropriate - // manifest, or via the overloaded Ref.apply(Int); and - // viewFactory: one of FreshSingleAccess, ReuseSingleAccess, or RefAccess - // (which requires outerLevels + innerLevels > 0). - // - // Now we enumerate the environments, generating a set of tests for each - // configuration. - - private def createTests[A : ClassManifest](name: String, v0: A)(block: (() => Ref.View[A]) => Unit) { - test(name) { - for (outerLevels <- 0 until 2; - innerLevels <- 0 until 2; - refFactory <- List(new KnownGenericFactory[A], new UnknownGenericFactory[A], new ArrayElementFactory[A]); - viewFactory <- List(SingleAccess, RefAccess) - if !(innerLevels + outerLevels == 0 && viewFactory == RefAccess)) { - val current = "outer=" + outerLevels + ", inner=" + innerLevels + ", " + refFactory + ", " + viewFactory - try { - val ref = refFactory(v0) - def getView = viewFactory(ref, innerLevels) - nest(outerLevels) { block(getView _) } - } catch { - case x: Throwable => { - println(name + " failed for " + current) - fail(current + ": " + name + " failure", x) - } - } - } - } - } - - test("primitive factory and ClassManifest generic produce same type") { - // this cuts down on the proliferation of tests - val g = new KnownGenericFactory[Int] - assert(PrimitiveIntFactory(10).getClass === g(10).getClass) - } - - private def nest(depth: Int)(block: => Unit) { - if (depth == 0) - block - else - atomic { implicit txn => nest(depth - 1)(block) } - } - - createTests("get and set", 1) { view => - for (i <- 1 until 10) { - assert(view()() === i) - view()() = view()() + 1 - } - assert(view()() === 10) - } - - createTests("get and trySet", 1) { view => - for (i <- 1 until 10) { - assert(view()() === i) - val f = view().trySet(view()() + 1) - assert(f) // trySet shouldn't fail in the absence of contention - } - assert(view()() === 10) - } - - createTests("compareAndSet", 1) { view => - for (i <- 1 until 10) { - assert(view()() === i) - assert(!view().compareAndSet(0, -1)) - assert(view().compareAndSet(i, i + 1)) - assert(!view().compareAndSet(i, i + 1)) - } - assert(view()() === 10) - } - - createTests("swap", 1) { view => - for (i <- 1 until 10) { - assert(view().swap(i + 1) === i) - } - assert(view()() === 10) - } - - createTests("set + swap", 1) { view => - for (i <- 1 until 10) { - view()() = -1 - assert(view().swap(i + 1) === -1) - } - assert(view()() === 10) - } - - createTests("transform", 1) { view => - for (i <- 1 until 10) { - assert(view()() === i) - view().transform(_ + 1) - } - assert(view()() === 10) - } - - createTests("getAndTransform", 1) { view => - for (i <- 1 until 10) { - assert(view()() === i) - assert(view().getAndTransform(_ + 1) === i) - } - assert(view()() === 10) - } - - createTests("transformAndGet", 1) { view => - for (i <- 1 until 10) { - assert(view()() === i) - assert(view().transformAndGet(_ + 1) === i + 1) - } - assert(view()() === 10) - } - - createTests("transformAndExtract", 1) { view => - for (i <- 1 until 10) { - assert(view()() === i) - assert(view().transformAndExtract { i => (i+1, ""+i) } === ""+i) - } - assert(view()() === 10) - } - - createTests("transformIfDefined", 1) { view => - for (i <- 1 until 10) { - assert(view()() === i) - assert(!(view().transformIfDefined { - case 0 => -1 - })) - assert(view().transformIfDefined { - case x if x > 0 => { - assert(x === i) - x + 1 - } - }) - } - assert(view()() === 10) - } - - createTests("+= 1", 1) { view => - for (i <- 1 until 10) { - assert(view()() === i) - view() += 1 - } - assert(view()() === 10) - } - - createTests("-= -1", 1) { view => - for (i <- 1 until 10) { - assert(view()() === i) - view() -= -1 - } - assert(view()() === 10) - } - - createTests("*= 2", 1) { view => - for (i <- 1 until 10) { - view() *= 2 - } - assert(view()() === 512) - } - - createTests("getWith", 1) { view => - assert(view().getWith(_ * 10) === 10) - } - - createTests("write ; getWith", 1) { view => - view()() = 2 - assert(view().getWith(_ * 10) === 20) - } - - createTests("getWith ; write", 1) { view => - assert(view().getWith(_ * 10) === 10) - view()() = 2 - } - - createTests("relaxedGet", 10) { view => - assert(view().relaxedGet( _ == _ ) === 10) - } - - createTests("write ; relaxedGet", 10) { view => - view()() = 20 - assert(view().relaxedGet( _ == _ ) === 20) - } - - createTests("relaxedGet ; write", 10) { view => - assert(view().relaxedGet( _ == _ ) === 10) - view()() = 20 - } - - createTests("initially true await", 10) { view => - view().await( _ == 10 ) - } - - createTests("initially true tryAwait", 10) { view => - assert(view().tryAwait(10000)( _ == 10 )) - } - - createTests("false tryAwait with a zero timeout", 10) { view => - assert(!view().tryAwait(0)( _ == 20 )) - } - - class UserException extends Exception - - createTests("excepting transform", 1) { view => - intercept[UserException] { - view().transform(v => throw new UserException) - } - assert(view().get === 1) - view().transform(_ + 1) - assert(view().get === 2) - } - - createTests("excepting transformIfDefined", 1) { view => - intercept[UserException] { - view().transformIfDefined { - case v if v > 0 => throw new UserException - case v => v * 100 - } - } - assert(view().get === 1) - view().transform(_ + 1) - assert(view().get === 2) - } - - class AngryEquals(val polarity: Boolean) { - override def equals(rhs: Any): Boolean = { - if (this eq rhs.asInstanceOf[AnyRef]) - true - else { - // equal polarities actively repel - if (rhs.asInstanceOf[AngryEquals].polarity == polarity) - throw new UserException - false - } - } - } - - createTests(".equals not involved in get and set", new AngryEquals(true)) { view => - assert(view().get ne null) - view()() = new AngryEquals(true) - } - - createTests("excepting compareAndSet", new AngryEquals(true)) { view => - val prev = view()() - intercept[UserException] { - view().compareAndSet(new AngryEquals(true), new AngryEquals(true)) - } - assert(!view().compareAndSet(new AngryEquals(false), new AngryEquals(true))) - val repl = new AngryEquals(false) - assert(view().compareAndSet(prev, repl)) - assert(view().get === repl) - } - - createTests("compareAndSetIdentity", "orig") { view => - assert(!view().compareAndSetIdentity(new String("orig"), "equal")) - assert(view().compareAndSetIdentity("orig", "eq")) - assert(view().get === "eq") - } - - createTests("-= -1 long", Int.MaxValue + 1L) { view => - for (i <- 1L until 10L) { - assert(view()() === Int.MaxValue + i) - view() -= -1 - } - assert(view()() === Int.MaxValue + 10L) - } - - createTests("/=", 11) { view => - view() /= 2 - assert(view()() === 5) - } - - createTests("/= double", 11.0) { view => - view() /= 2 - assert(view()() === 5.5) - } - - createTests("/= float", 11.0f) { view => - view() /= 2 - assert(view()() === 5.5f) - } - - createTests("BigInt ops", BigInt("1234")) { view => - view() += 1 - assert(view()().toString === "1235") - view() -= 2 - assert(view()().toString === "1233") - view() *= 3 - assert(view()().toString === "3699") - view() /= 4 - assert(view()().toString === "924") - } - - createTests("BigDecimal ops", BigDecimal("1234")) { view => - view() += 1 - assert(view()().toString === "1235") - view() -= 2 - assert(view()().toString === "1233") - view() *= 3 - assert(view()().toString === "3699") - view() /= 4 - assert(view()().toString === "924.75") - } - - createTests("TxnDebuggable", 10) { view => - assert(view().dbgStr === "Ref(10)") - assert(view().dbgValue === 10) - view()() = 11 - assert(view().dbgStr === "Ref(11)") - assert(view().dbgValue === 11) - } - - private def perTypeTests[A : ClassManifest](v0: A, v1: A) { - val name = v0.asInstanceOf[AnyRef].getClass.getSimpleName - - createTests(name + " simple get+set", v0) { view => - assert(view()() === v0) - view()() = v1 - assert(view()() === v1) - } - - createTests(name + " Ref equality", v0) { view => - assert(view().asInstanceOf[Any] == view()) - assert(view().ref.asInstanceOf[Any] == view()) - assert(view().asInstanceOf[Any] == view().ref) - assert(view().ref.asInstanceOf[Any] == view().ref) - assert(view().ref.single.asInstanceOf[Any] == view()) - assert(view().asInstanceOf[Any] != Ref(v0)) - assert(view().asInstanceOf[Any] != "abc") - } - - test(name + " TArray Ref equality") { - val a = TArray(Seq(v0)) - assert(a.refs(0).asInstanceOf[Any] == a.refs(0)) - assert(a.single.refViews(0).asInstanceOf[Any] == a.refs(0)) - assert(a.single.refViews(0).ref.asInstanceOf[Any] == a.refs(0)) - assert(a.single.refViews(0).asInstanceOf[Any] == a.single.refViews(0)) - assert(a.refs(0).asInstanceOf[Any] == a.refs(0).single) - assert(a.single.tarray.refs(0).asInstanceOf[Any] == a.refs(0).single) - assert(a.refs(0).asInstanceOf[Any] != "abc") - } - - test(name + " TArray Ref inequality between arrays") { - val a = TArray(Seq(v0)) - val b = TArray(Seq(v1)) - assert(b.refs(0).asInstanceOf[Any] != a.refs(0)) - assert(b.single.refViews(0).asInstanceOf[Any] != a.refs(0)) - assert(b.single.refViews(0).ref.asInstanceOf[Any] != a.refs(0)) - assert(b.single.refViews(0).asInstanceOf[Any] != a.single.refViews(0)) - assert(b.refs(0).asInstanceOf[Any] != a.refs(0).single) - assert(b.single.tarray.refs(0).asInstanceOf[Any] != a.refs(0).single) - } - } - - perTypeTests(false, true) - perTypeTests(1 : Byte, 2 : Byte) - perTypeTests(1 : Short, 2 : Short) - perTypeTests('1', '2') - perTypeTests(1, 2) - perTypeTests(1.0f, 2.0f) - perTypeTests(1L, 2L) - perTypeTests(1.0, 2.0) - perTypeTests((), ()) - perTypeTests("1", "2") - - test("TArray Ref inequality between indices") { - val a = TArray.ofDim[Int](1000) - println(a.refs(0)) - for (i <- 1 until 1000) { - assert(a.refs(i).asInstanceOf[Any] != a.refs(0)) - assert(a.single.refViews(i).asInstanceOf[Any] != a.refs(0)) - assert(a.single.refViews(i).ref.asInstanceOf[Any] != a.refs(0)) - assert(a.single.refViews(i).asInstanceOf[Any] != a.single.refViews(0)) - assert(a.refs(i).asInstanceOf[Any] != a.refs(0).single) - assert(a.single.tarray.refs(i).asInstanceOf[Any] != a.refs(0).single) - } - } - - test("TArray index checking") { - val a = TArray.ofDim[String](10) - for (i <- List(-1, 10, Int.MinValue, Int.MaxValue)) { - intercept[ArrayIndexOutOfBoundsException] { a.single(i) } - intercept[ArrayIndexOutOfBoundsException] { a.single(i) = "abc" } - intercept[ArrayIndexOutOfBoundsException] { a.single.refViews(i) } - intercept[ArrayIndexOutOfBoundsException] { a.refs(i) } - intercept[ArrayIndexOutOfBoundsException] { atomic { implicit txn => a(i) } } - intercept[ArrayIndexOutOfBoundsException] { atomic { implicit txn => a(i) = "abc" } } - } - } - - test("TArray length") { - val a = TArray.ofDim[String](10) - assert(a.length === 10) - assert(a.single.length === 10) - assert(a.refs.length === 10) - assert(a.single.refViews.length === 10) - - val b = TArray.ofDim[String](0) - assert(b.single.isEmpty) - } - - test("TArray TxnDebuggable") { - val a = TArray.ofDim[String](3) - a.single(0) = "zero" - a.refs(1).single() = "one" - atomic { implicit txn => a(2) = "two" } - - assert(a.dbgStr === "TArray[size=3](zero, one, two)") - val aa = a.dbgValue.asInstanceOf[Array[String]] - assert(aa.length === 3) - assert(aa(0) === "zero") - assert(aa(1) === "one") - assert(aa(2) === "two") - } - - class ProxyRef[A](underlying: Ref[A]) extends Ref[A] { - override def single = throw new AbstractMethodError - def get(implicit txn: InTxn) = throw new AbstractMethodError - def getWith[Z](f: (A) => Z)(implicit txn: InTxn) = throw new AbstractMethodError - def relaxedGet(equiv: (A, A) => Boolean)(implicit txn: InTxn) = throw new AbstractMethodError - def set(v: A)(implicit txn: InTxn) { throw new AbstractMethodError } - def trySet(v: A)(implicit txn: InTxn) = throw new AbstractMethodError - def swap(v: A)(implicit txn: InTxn) = throw new AbstractMethodError - def transform(f: (A) => A)(implicit txn: InTxn) { throw new AbstractMethodError } - def transformIfDefined(pf: PartialFunction[A, A])(implicit txn: InTxn) = throw new AbstractMethodError - - override def hashCode = underlying.hashCode - override def equals(rhs: Any) = underlying.equals(rhs) - } - - test("proxy Ref equality") { - val lhs = Ref(10) - val rhs = new ProxyRef(lhs) - assert(lhs == rhs) - assert(rhs == lhs) - assert(rhs == rhs) - assert(rhs != Ref(5)) - assert(Ref(5) != rhs) - } - - test("TxnExecutor.compareAndSet") { - val x = Ref("abc") - val y = Ref("10") - assert(!atomic.compareAndSet(x, "abc", "def", y, "11", "20")) - assert(x.single() === "abc") - assert(y.single() === "10") - assert(!atomic.compareAndSet(x, "ABC", "def", y, "10", "20")) - assert(x.single() === "abc") - assert(y.single() === "10") - assert(atomic.compareAndSet(x, "abc", "def", y, 10.toString, "20")) - assert(x.single() === "def") - assert(y.single() === "20") - } - - test("TxnExecutor.compareAndSet non-txn exhaustive") { - for (x0 <- List("abc", "ABC") ; x1 <- List("abc", "ABC") ; y0 <- List("def", "DEF") ; y1 <- List("def", "DEF")) { - val x = Ref("abc") - val y = Ref("def") - val f = atomic.compareAndSet(x, x0, x1, y, y0, y1) - if (f) { - assert(x0 === "abc") - assert(y0 === "def") - assert(x.single() === x1) - assert(y.single() === y1) - } else { - assert(x0 != "abc" || y0 != "def") - } - } - } - - test("TxnExecutor.compareAndSet txn exhaustive") { - for (x0 <- List("abc", "ABC") ; x1 <- List("abc", "ABC") ; y0 <- List("def", "DEF") ; y1 <- List("def", "DEF")) { - val x = Ref("abc") - val y = Ref("def") - val f = atomic { implicit txn => atomic.compareAndSet(x, x0, x1, y, y0, y1) } - if (f) { - assert(x0 === "abc") - assert(y0 === "def") - assert(x.single() === x1) - assert(y.single() === y1) - } else { - assert(x0 != "abc" || y0 != "def") - } - } - } - - test("TxnExecutor.compareAndSetIdentity non-txn exhaustive") { - for (x0 <- List("abc", "ABC") ; x1 <- List("abc", "ABC") ; y0 <- List("def", "DEF") ; y1 <- List("def", "DEF")) { - val x = Ref("abc") - val y = Ref("def") - val f = atomic.compareAndSetIdentity(x, x0, x1, y, y0, y1) - if (f) { - assert(x0 === "abc") - assert(y0 === "def") - assert(x.single() === x1) - assert(y.single() === y1) - } else { - assert(x0 != "abc" || y0 != "def") - } - } - } - - test("TxnExecutor.compareAndSetIdentity txn exhaustive") { - for (x0 <- List("abc", "ABC") ; x1 <- List("abc", "ABC") ; y0 <- List("def", "DEF") ; y1 <- List("def", "DEF")) { - val x = Ref("abc") - val y = Ref("def") - val f = atomic { implicit txn => atomic.compareAndSetIdentity(x, x0, x1, y, y0, y1) } - if (f) { - assert(x0 === "abc") - assert(y0 === "def") - assert(x.single() === x1) - assert(y.single() === y1) - } else { - assert(x0 != "abc" || y0 != "def") - } - } - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/JavaAPISuite.scala b/benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/JavaAPISuite.scala deleted file mode 100644 index ef53960d..00000000 --- a/benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/JavaAPISuite.scala +++ /dev/null @@ -1,7 +0,0 @@ -/* scala-stm - (c) 2009-2012, Stanford University, PPL */ - -package scala.concurrent.stm - -import org.scalatest.junit.JUnitWrapperSuite - -class JavaAPISuite extends JUnitWrapperSuite("scala.concurrent.stm.JavaAPITests", Thread.currentThread.getContextClassLoader) diff --git a/benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/MaybeTxnSuite.scala b/benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/MaybeTxnSuite.scala deleted file mode 100644 index a5a82a92..00000000 --- a/benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/MaybeTxnSuite.scala +++ /dev/null @@ -1,90 +0,0 @@ -/* scala-stm - (c) 2009-2010, Stanford University, PPL */ - -package scala.concurrent.stm - -import org.scalatest.FunSuite - -class MaybeTxnSuite extends FunSuite { - test("implicit InTxn match") { - implicit val txn: InTxn = new skel.StubInTxn - - assert(implicitly[MaybeTxn] eq txn) - } - - test("implicit TxnUnknown match") { - assert(implicitly[MaybeTxn] eq TxnUnknown) - } - - test("TxnUnknown is found") { - assert(context eq TxnUnknown) - } - - test("InTxn is found") { - atomic { t0 => - implicit val t = t0 - assert(context eq t) - } - atomic { implicit t => - assert(context eq t) - } - } - - private def context(implicit mt: MaybeTxn) = mt - - test("Static nesting lookup") { - val x = Ref(10) - atomic { implicit t => - assert(x() === 10) - x() = 11 - atomic { implicit t => - assert(x() === 11) - x() = 12 - atomic { implicit t => - assert(x() === 12) - x() = 13 - } - assert(x() === 13) - } - assert(x() === 13) - } - assert(x.single() === 13) - } - - test("Dynamic nesting lookup") { - val x = Ref(10) - val xs = x.single - def loop(expected: Int) { - atomic { implicit t => - assert(x() === expected) - assert(xs() === expected) - x() = expected + 1 - if (expected < 100) - loop(expected + 1) - assert(x() === 101) - } - } - loop(10) - assert(xs() === 101) - assert(x.single() === 101) - } - - test("Static vs dynamic lookup") { - implicit var t0: InTxn = null - val n0 = atomic { t => - t0 = t - assert(Txn.findCurrent === Some(t)) - assert(impl.STMImpl.instance.findCurrent === Some(t)) - NestingLevel.root - } - assert(n0.status === Txn.Committed) - assert(Txn.findCurrent === None) - assert(impl.STMImpl.instance.findCurrent === None) - atomic { t => - assert(NestingLevel.current(t) != n0) - assert(NestingLevel.root(t).status === Txn.Active) - assert(Txn.status === Txn.Active) - assert(Txn.findCurrent === Some(t)) - assert(impl.STMImpl.instance.findCurrent === Some(t)) - } - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/RelaxedValidationSuite.scala b/benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/RelaxedValidationSuite.scala deleted file mode 100644 index 5c321ffc..00000000 --- a/benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/RelaxedValidationSuite.scala +++ /dev/null @@ -1,184 +0,0 @@ -/* scala-stm - (c) 2009-2011, Stanford University, PPL */ - -package scala.concurrent.stm - -import org.scalatest.FunSuite -import java.util.concurrent.CountDownLatch - - -/** Tests of the relaxed validation methods `getWith` and `relaxedGet` in - * multi-threaded contexts. Single-threaded tests are found in - * `IsolatedRefSuite` and more multi-threaded tests are embedded in - * `FlipperSuite`. - */ -class RelaxedValidationSuite extends FunSuite { - - test("self-write vs getWith") { - val x = Ref(0) - atomic { implicit txn => - assert(x.getWith { _ & 1 } === 0) - x() = 1 - } - assert(x.single() === 1) - } - - test("self-write vs getWith with interference") { - val x = Ref(0) - val b1 = new CountDownLatch(1) - val b2 = new CountDownLatch(1) - - (new Thread { override def run { - b1.await() - x.single() = 2 - b2.countDown() - } }).start - - atomic { implicit txn => - assert(x.getWith { _ & 1 } === 0) - b1.countDown() - b2.await() - assert(x.swap(1) === 2) - } - assert(x.single() === 1) - } - - test("getWith multiple revalidations") { - val x = Ref("abc") - - // sleep is okay for this test because all interleavings should pass - - (new Thread { - override def run { - for (i <- 0 until 10) { - Thread.sleep(10) - x.single.transform { _ + "X" } - } - x.single() = "" - } - }).start - - assert(atomic { implicit txn => - for (i <- 0 until 10) { - x.getWith { _.take(3) } - Thread.sleep(15) - } - x.getWith { _.take(3) } - } === "") - } - - test("self-write vs failing transformIfDefined") { - val x = Ref(0) - atomic { implicit txn => - assert(!x.transformIfDefined { - case 1 => 2 - }) - x() = 1 - } - assert(x.single() === 1) - } - - test("self-write vs failing transformIfDefined with interference") { - val x = Ref(0) - val b1 = new CountDownLatch(1) - val b2 = new CountDownLatch(1) - - (new Thread { override def run { - b1.await() - x.single() = 2 - b2.countDown() - } }).start - - atomic { implicit txn => - assert(!x.transformIfDefined { - case v if (v & 1) != 0 => v - }) - b1.countDown() - b2.await() - assert(x.swap(1) === 2) - } - assert(x.single() === 1) - } - - test("self-write vs relaxedGet") { - val x = Ref(0) - atomic { implicit txn => - assert(x.relaxedGet( _ == _ ) === 0) - x() = 1 - } - assert(x.single() === 1) - } - - test("self-write vs relaxedGet with interference") { - val x = Ref(0) - val b1 = new CountDownLatch(1) - val b2 = new CountDownLatch(1) - - (new Thread { override def run { - b1.await() - x.single() = 2 - b2.countDown() - } }).start - - atomic { implicit txn => - assert(x.relaxedGet({ (seen, correct) => (seen & 1) == (correct & 1) }) === 0) - b1.countDown() - b2.await() - assert(x.swap(1) === 2) - } - assert(x.single() === 1) - } - - test("relaxedGet multiple accepting revalidations") { - val x = Ref("abc") - - // sleep is okay for this test because all interleavings should pass - - (new Thread { - override def run { - for (i <- 0 until 10) { - Thread.sleep(10) - x.single.transform { _ + "X" } - } - x.single() = "" - } - }).start - - val (first, last) = atomic { implicit txn => - val first = x.relaxedGet( (_, _) => true ) - for (i <- 0 until 10) { - x.relaxedGet( (_, _) => true ) - Thread.sleep(15) - } - (first, x.relaxedGet( (_, _) => true )) - } - assert(first === "abc") - assert(last === "") - } - - test("relaxedGet multiple ending with equality check") { - val x = Ref("abc") - - // sleep is okay for this test because all interleavings should pass - - (new Thread { - override def run { - for (i <- 0 until 10) { - Thread.sleep(10) - x.single.transform { _ + "X" } - } - x.single() = "" - } - }).start - - val (first, last) = atomic { implicit txn => - val first = x.relaxedGet( _.isEmpty == _.isEmpty ) - for (i <- 0 until 10) { - x.relaxedGet( _.isEmpty == _.isEmpty ) - Thread.sleep(15) - } - (first, x.relaxedGet( _ == _ )) - } - assert(first === "") - assert(last === "") - } -} \ No newline at end of file diff --git a/benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/RetrySuite.scala b/benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/RetrySuite.scala deleted file mode 100644 index e464f536..00000000 --- a/benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/RetrySuite.scala +++ /dev/null @@ -1,520 +0,0 @@ -/* scala-stm - (c) 2009-2012, Stanford University, PPL */ - -package scala.concurrent.stm - -import org.scalatest.FunSuite -import java.util.concurrent.{ CountDownLatch, TimeUnit } - -/** Contains extended tests of `retry`, `retryFor` and `tryAwait`. Some basic - * tests are included in `TxnSuite`. - */ -class RetrySuite extends FunSuite { - - def timingAssert(ok: Boolean) { - if (!ok) { - val x = new Exception("timing-sensitive check failed, continuing") - x.printStackTrace() - } - } - - test("retry set accumulation across alternatives") { - val x = Ref(false) - val b = new CountDownLatch(1) - - // this prevents the test from deadlocking - new Thread("trigger") { - override def run { - b.await() - Thread.sleep(10) - x.single() = true - } - } start - - atomic { implicit t => - // The following txn and its alternative decode the value of x that was - // observed, without x being a part of the current read set. - val f = atomic { implicit t => - atomic { implicit t => - // this txn encodes the read of x in its retry state - if (!x()) retry - } - true - } orAtomic { implicit t => - false - } - if (!f) { - // we've correctly observed x() == false, now arrange for true - b.countDown() - retry - } - } - } - - test("tryAwait is conservative") { - val x = Ref(10) - val t0 = System.currentTimeMillis - assert(!x.single.tryAwait(100)( _ == 0 )) - val elapsed = System.currentTimeMillis - t0 - assert(elapsed >= 100) - println("tryAwait(.., 100) took " + elapsed + " millis") - } - - test("tryAwait in atomic is conservative") { - val x = Ref(10) - val t0 = System.currentTimeMillis - val f = atomic { implicit txn => x.single.tryAwait(100)( _ == 0 ) } - assert(!f) - val elapsed = System.currentTimeMillis - t0 - assert(elapsed >= 100) - println("tryAwait(.., 100) inside atomic took " + elapsed + " millis") - } - - test("retryFor is conservative") { - val x = Ref(false) - val t0 = System.currentTimeMillis - val s = atomic { implicit txn => - if (!x()) retryFor(100) - "timeout" - } - assert(s === "timeout") - val elapsed = System.currentTimeMillis - t0 - assert(elapsed >= 100) - println("retryFor(100) took " + elapsed + " millis") - } - - test("retryFor earliest is first") { - val x = Ref(false) - val s = atomic { implicit txn => - if (!x()) retryFor(100) - "first" - } orAtomic { implicit txn => - if (!x()) retryFor(200) - "second" - } - assert(s === "first") - } - - test("retryFor earliest is second") { - val x = Ref(false) - val s = atomic { implicit txn => - if (!x()) retryFor(300) - "first" - } orAtomic { implicit txn => - if (!x()) retryFor(100) - "second" - } - assert(s === "second") - } - - test("retryFor earliest is first nested") { - val x = Ref(false) - val s = atomic { implicit txn => - atomic { implicit txn => - if (!x()) retryFor(100) - "first" - } orAtomic { implicit txn => - if (!x()) retryFor(200) - "second" - } - } - assert(s === "first") - } - - test("retryFor earliest is second nested") { - val x = Ref(false) - val s = atomic { implicit txn => - atomic { implicit txn => - if (!x()) retryFor(300) - "first" - } orAtomic { implicit txn => - if (!x()) retryFor(100) - "second" - } - } - assert(s === "second") - } - - test("retryFor only is first") { - val x = Ref(false) - val s = atomic { implicit txn => - if (!x()) retryFor(100) - "first" - } orAtomic { implicit txn => - if (!x()) retry - "second" - } - assert(s === "first") - } - - test("retryFor only is second") { - val x = Ref(false) - val s = atomic { implicit txn => - if (!x()) retry - "first" - } orAtomic { implicit txn => - if (!x()) retryFor(100) - "second" - } - assert(s === "second") - } - - test("retryFor ladder") { - val buf = new StringBuilder - val x = Ref(0) - atomic { implicit txn => - buf += 'a' - retryFor(1) - buf += 'b' - retryFor(1) - buf += 'c' - retryFor(0) - buf += 'd' - retryFor(1) - buf += 'e' - retryFor(1) - buf += 'f' - } orAtomic { implicit txn => - if (x() == 0) retry - } - assert(buf.toString === "aababcdabcdeabcdef") - } - - test("late start retryFor") { - val x = Ref(0) - val b = new CountDownLatch(1) - val begin = System.currentTimeMillis - var lastRetryForElapsed = 0L - - (new Thread { override def run { - b.await() - x.single() = 1 - } }).start - - val buf = new StringBuilder - atomic { implicit txn => - buf += 'a' - b.countDown() - if (x() == 0) retry - buf += 'b' - val t = System.currentTimeMillis - retryFor(200) - lastRetryForElapsed = System.currentTimeMillis - t - buf += 'c' - } - val elapsed = System.currentTimeMillis - begin - println("late start retryFor(200) inside atomic took " + elapsed + " millis") - assert(elapsed >= 200) - assert(lastRetryForElapsed < 100) // should be ~0 - assert(buf.toString === "aababc") - } - - test("expired start retryFor") { - val x = Ref(0) - val begin = System.currentTimeMillis - var totalRetryForElapsed = 0L - - (new Thread { override def run { - Thread.sleep(200) ; - x.single() = 1 - } }).start - - val buf = new StringBuilder - atomic { implicit txn => - buf += 'a' - if (x() == 0) retry - buf += 'b' - val t = System.currentTimeMillis - retryFor(100) - totalRetryForElapsed += System.currentTimeMillis - t - buf += 'c' - } - val elapsed = System.currentTimeMillis - begin - println("expired(200) start retryFor(100) inside atomic took " + elapsed + " millis") - assert(elapsed >= 200) - assert(totalRetryForElapsed < 100) // should be ~0 - assert(buf.toString === "aabc") - } - - test("retryFor as sleep") { - val begin = System.currentTimeMillis - atomic { implicit txn => retryFor(100) } - val elapsed = System.currentTimeMillis - begin - println("retryFor(100) as sleep took " + elapsed + " millis") - assert(elapsed >= 100) - } - - ///////////// CURSOR - - test("second retryFor has shorter timeout") { - val x = Ref(0) - val b1 = new CountDownLatch(1) - val b2 = new CountDownLatch(1) - - (new Thread { - override def run { - b1.await() - Thread.sleep(10) - x.single() = 1 - b2.await() - Thread.sleep(100) - x.single += 1 - } - }).start - atomic { implicit txn => - x() = x() + 10 - if (x() == 10) { - b1.countDown() - retryFor(200) - } else if (x() == 11) { - b2.countDown() - retryFor(50) - } - } - assert(x.single() === 11) - x.single.await( _ == 12 ) - } - - test("retryFor via View await") { - val x = Ref(0) - (new Thread { - override def run { - Thread.sleep(50) - x.single() = 1 - Thread.sleep(100) - x.single += 1 - } - }).start - atomic { implicit txn => - x() = x() + 10 - x.single.await( _ == 11 ) - assert(!x.single.tryAwait(50)( _ == 12 )) - } - assert(x.single() === 11) - x.single.await( _ == 12 ) - } - - test("skipped retryFor deadline is retained") { - val begin = System.currentTimeMillis - atomic { implicit txn => - val f = atomic { implicit txn => - retryFor(50) - false - } orAtomic { implicit txn => - true - } - if (f) - retryFor(1000) - } - val elapsed = System.currentTimeMillis - begin - assert(elapsed < 500) - } - - test("concatenated failing tryAwait") { - val begin = System.currentTimeMillis - val x = Ref(0) - atomic { implicit txn => - x.single.tryAwait(50)( _ != 0 ) - x.single.tryAwait(50)( _ != 0 ) - x.single.tryAwait(50)( _ != 0 ) - } - val elapsed = System.currentTimeMillis - begin - assert(elapsed > 150) - timingAssert(elapsed < 200) - } - - test("barging retry") { - // the code to trigger barging is CCSTM-specific, but this test should pass regardless - var tries = 0 - val x = Ref(0) - val y = Ref(0) - val z = Ref(0) - val b = new CountDownLatch(1) - - (new Thread { override def run { - b.await() - Thread.sleep(10) - x.single() = 1 - y.single() = 1 - } }).start - - atomic { implicit txn => - z() = 2 - atomic { implicit txn => - NestingLevel.current - tries += 1 - if (tries < 50) - Txn.rollback(Txn.OptimisticFailureCause('test, None)) - b.countDown() - - z() = 3 - x() - if (y.swap(2) != 1) - retry - } - } - } - - test("retry with many pessimistic reads") { - // the code to trigger barging is CCSTM-specific, but this test should pass regardless - val b = new CountDownLatch(1) - var tries = 0 - val refs = Array.tabulate(10000) { _ => Ref(0) } - - (new Thread { override def run { - b.await() - Thread.sleep(10) - refs(500).single() = 1 - } }).start - - atomic { implicit txn => - tries += 1 - if (tries < 50) - Txn.rollback(Txn.OptimisticFailureCause('test, None)) - - val sum = refs.foldLeft(0)( _ + _.get ) - b.countDown() - if (sum == 0) - retry - } - } - - test("retry with many accesses to TArray") { - // the code to trigger barging is CCSTM-specific, but this test should pass regardless - val b = new CountDownLatch(1) - var tries = 0 - val refs = TArray.ofDim[Int](10000).refs - - (new Thread { override def run { - b.await() - Thread.sleep(10) - refs(500).single() = 1 - } }).start - - atomic { implicit txn => - tries += 1 - if (tries < 50) - Txn.rollback(Txn.OptimisticFailureCause('test, None)) - - for (r <- refs.take(500)) - r *= 2 - val sum = refs.foldLeft(0)( _ + _.get ) - b.countDown() - if (sum == 0) - retry - } - } - - test("futile retry should fail") { - val x = true - intercept[IllegalStateException] { - atomic { implicit txn => - if (x) - retry - } - } - } - - test("withRetryTimeout") { - val x = Ref(0) - val t0 = System.currentTimeMillis - intercept[InterruptedException] { - atomic.withRetryTimeout(100000, TimeUnit.MICROSECONDS) { implicit txn => - if (x() == 0) - retry - } - } - val elapsed = System.currentTimeMillis - t0 - assert(elapsed >= 100) - timingAssert(elapsed < 150) - } - - test("retryFor wins over withRetryTimeout") { - val x = Ref(0) - val t0 = System.currentTimeMillis - val f = atomic.withRetryTimeout(100) { implicit txn => - if (x() == 0) { - retryFor(100) - true - } else - false - } - assert(f) - val elapsed = System.currentTimeMillis - t0 - assert(elapsed >= 100) - timingAssert(elapsed < 150) - } - - test("withRetryTimeout applies to retryFor") { - val x = Ref(0) - val t0 = System.currentTimeMillis - intercept[InterruptedException] { - atomic.withRetryTimeout(100) { implicit txn => - if (x() == 0) - retryFor(101) - assert(false) - } - } - val elapsed = System.currentTimeMillis - t0 - assert(elapsed >= 100) - timingAssert(elapsed < 150) - } - - test("nested global withRetryTimeout") { - val orig = TxnExecutor.defaultAtomic - try { - TxnExecutor.transformDefault( _.withRetryTimeout(100) ) - val x = Ref(0) - val t0 = System.currentTimeMillis - intercept[InterruptedException] { - atomic { implicit txn => - atomic { implicit txn => - atomic { implicit txn => - if (x() == 0) - retry - assert(false) - } - } - } - } - val elapsed = System.currentTimeMillis - t0 - println(elapsed) - assert(elapsed >= 100) - timingAssert(elapsed < 150) - } finally { - TxnExecutor.transformDefault( _ => orig ) - } - } - - test("tighter timeout wins") { - val t0 = System.currentTimeMillis - intercept[InterruptedException] { - atomic.withRetryTimeout(100) { implicit txn => - atomic.withRetryTimeout(1000) { implicit txn => - retry - } - } - } - val elapsed = System.currentTimeMillis - t0 - assert(elapsed >= 100) - timingAssert(elapsed < 150) - } - - test("non-timeout elapsed") { - val x = Ref(0) - (new Thread { override def run { - Thread.sleep(100) - x.single() = 1 - } }).start - intercept[InterruptedException] { - atomic { implicit txn => - atomic.withRetryTimeout(200) { implicit txn => - if (x() == 0) - retry - } - atomic.withRetryTimeout(50) { implicit txn => - retryFor(51) - } - } - } - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/Slow.scala b/benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/Slow.scala deleted file mode 100644 index 7b5e1b14..00000000 --- a/benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/Slow.scala +++ /dev/null @@ -1,7 +0,0 @@ -/* scala-stm - (c) 2009-2010, Stanford University, PPL */ - -package scala.concurrent.stm - -import org.scalatest.Tag - -object Slow extends Tag("slow") diff --git a/benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/TMapSuite.scala b/benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/TMapSuite.scala deleted file mode 100644 index 622f258e..00000000 --- a/benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/TMapSuite.scala +++ /dev/null @@ -1,680 +0,0 @@ -/* scala-stm - (c) 2009-2012, Stanford University, PPL */ - -package scala.concurrent.stm - -import org.scalatest.FunSuite -import scala.util.Random -import scala.collection.mutable -import skel.SimpleRandom - -class TMapSuite extends FunSuite { - - private def value(k: Int) = "x" + k - private def kvRange(b: Int, e: Int) = (b until e) map { i => (i -> value(i)) } - - test("number equality trickiness") { - assert(TMap(10L -> "").single contains 10) - //assert(TMap(10 -> "").single contains 10L) - assert(TMap[Number, String]((10L: Number) -> "").single contains 10) - assert(TMap[Number, String]((10: Number) -> "").single contains 10L) - assert(TMap[Any, String](10L -> "").single contains 10) - assert(TMap[Any, String](10 -> "").single contains 10L) - assert(TMap[AnyRef, String](10L.asInstanceOf[AnyRef] -> "").single contains 10.asInstanceOf[AnyRef]) - assert(TMap[AnyRef, String](10.asInstanceOf[AnyRef] -> "").single contains 10L.asInstanceOf[AnyRef]) - } - - test("character equality trickiness") { - assert(TMap('*' -> "").single contains 42) - assert(TMap((42: Byte) -> "").single contains '*') - assert(TMap[Any, String]('*' -> "").single contains (42: Short)) - assert(TMap[Any, String](42L -> "").single contains '*') - assert(TMap[AnyRef, String]('*'.asInstanceOf[AnyRef] -> "").single contains 42.0.asInstanceOf[AnyRef]) - assert(TMap[AnyRef, String](42.0f.asInstanceOf[AnyRef] -> "").single contains '*'.asInstanceOf[AnyRef]) - } - - case class BadHash(k: Int) { - override def hashCode = if (k > 500) k / 5 else 0 - } - - test("correct despite poor hash function") { - val mut = TMap(((0 until 1000) map { i => (BadHash(i) -> i) }): _*).single - for (i <- -500 until 1500) - assert(mut.get(BadHash(i)) === (if (i >= 0 && i < 1000) Some(i) else None)) - } - - test("clone captures correct atomic writes") { - val mut = TMap(kvRange(0, 100): _*) - val z = atomic { implicit txn => - mut ++= kvRange(100, 200) - val z = mut.clone.single - mut ++= kvRange(200, 300) - z - } - assert(z.size === 200) - for (i <- 0 until 200) - assert(z(i) === value(i)) - } - - test("clone doesn't include discarded writes") { - val mut = TMap(kvRange(0, 100): _*) - val z = atomic { implicit txn => - atomic { implicit txn => - mut ++= kvRange(100, 200) - if ("likely".## != 0) - retry - } orAtomic { implicit txn => - mut ++= kvRange(200, 300) - } - val z = mut.clone.single - atomic { implicit txn => - mut ++= kvRange(300, 400) - if ("likely".## != 0) - retry - } orAtomic { implicit txn => - mut ++= kvRange(400, 500) - } - z - } - assert(z.size === 200) - for (i <- 0 until 100) - assert(z(i) === value(i)) - for (i <- 200 until 300) - assert(z(i) === value(i)) - } - - test("clone is transactional") { - val mut = TMap(kvRange(0, 100): _*) - val z = atomic { implicit txn => - atomic { implicit txn => - mut ++= kvRange(100, 105) - if ("likely".## != 0) - retry - } orAtomic { implicit txn => - mut ++= kvRange(200, 205) - } - val z = mut.clone.single - atomic { implicit txn => - z ++= kvRange(300, 305) - if ("likely".## != 0) - retry - } orAtomic { implicit txn => - z ++= kvRange(400, 405) - } - z - } - assert(z.size === 110) - for (i <- 0 until 100) - assert(z(i) === value(i)) - for (i <- 200 until 205) - assert(z(i) === value(i)) - for (i <- 400 until 405) - assert(z(i) === value(i)) - } - - test("random sequential") { - randomTest(1500) - } - - test("more random sequential", Slow) { - randomTest(30000) - } - - def randomTest(total: Int) { - val rand = new Random() - - def nextKey(): String = "key" + (rand.nextInt() >>> rand.nextInt()) - def nextValue(): Int = if (rand.nextInt(10) == 0) 0 else rand.nextInt() - - var mut = TMap.empty[String, Int].single - val base = mutable.Map.empty[String, Int] - - for (i <- 0 until total) { - val pct = rand.nextInt(250) - val k = nextKey() - val v = nextValue() - if (pct < 15) { - assert(base.get(k) === mut.get(k)) - } else if (pct < 20) { - val a = try { Some(base(k)) } catch { case _: NoSuchElementException => None } - val b = try { Some(mut(k)) } catch { case _: NoSuchElementException => None } - assert(a === b) - } else if (pct < 35) { - assert(base.put(k, v) === mut.put(k, v)) - } else if (pct < 40) { - base(k) = v - mut(k) = v - } else if (pct < 45) { - assert(base.contains(k) === mut.contains(k)) - } else if (pct < 55) { - assert(base.remove(k) === mut.remove(k)) - } else if (pct < 60) { - for (j <- 0 until (i / (total / 20))) { - if (!base.isEmpty) { - val k1 = base.iterator.next()._1 - assert(base.remove(k1) === mut.remove(k1)) - } - } - } else if (pct < 63) { - mut = mut.clone - } else if (pct < 66) { - assert(base.toMap === mut.snapshot) - } else if (pct < 69) { - assert(base.isEmpty === mut.isEmpty) - } else if (pct < 72) { - assert(base.size === mut.size) - } else if (pct < 77) { - assert(base eq (base += (k -> v))) - assert(mut eq (mut += (k -> v))) - } else if (pct < 80) { - val kv2 = (nextKey -> nextValue) - val kv3 = (nextKey -> nextValue) - assert(base eq (base += ((k -> v), kv2, kv3))) - assert(mut eq (mut += ((k -> v), kv2, kv3))) - } else if (pct < 82) { - val kv2 = (nextKey -> nextValue) - val kv3 = (nextKey -> nextValue) - assert(base eq (base ++= Array((k -> v), kv2, kv3))) - assert(mut eq (mut ++= Array((k -> v), kv2, kv3))) - } else if (pct < 83) { - assert(mut eq (mut ++= Nil)) - } else if (pct < 88) { - assert(base eq (base -= k)) - assert(mut eq (mut -= k)) - } else if (pct < 91) { - val k2 = nextKey() - val k3 = nextKey() - assert(base eq (base -= (k, k2, k3))) - assert(mut eq (mut -= (k, k2, k3))) - } else if (pct < 93) { - val k2 = nextKey() - val k3 = nextKey() - assert(base eq (base --= Array(k, k2, k3))) - assert(mut eq (mut --= Array(k, k2, k3))) - } else if (pct < 94) { - assert(mut eq (mut --= Nil)) - } else if (pct < 95) { - mut = TMap(mut.toArray: _*).single - } else if (pct < 96) { - mut = TMap.empty[String, Int].single ++= mut - } else if (pct < 97) { - val m2 = mutable.Map.empty[String, Int] - for (kv <- mut) { m2 += kv } - assert(base === m2) - } else if (pct < 98) { - val m2 = mutable.Map.empty[String, Int] - for (kv <- mut.iterator) { m2 += kv } - assert(base === m2) - } else if (pct < 115) { - assert(base.get(k) === atomic { implicit t => mut.tmap.get(k) }) - } else if (pct < 120) { - val a = try { Some(base(k)) } catch { case _: NoSuchElementException => None } - val b = try { Some(atomic { implicit t => mut.tmap(k) }) } catch { case _: NoSuchElementException => None } - assert(a === b) - } else if (pct < 135) { - assert(base.put(k, v) === atomic { implicit t => mut.tmap.put(k, v) }) - } else if (pct < 140) { - base(k) = v - atomic { implicit t => mut.tmap(k) = v } - } else if (pct < 145) { - assert(base.contains(k) === atomic { implicit t => mut.tmap.contains(k) }) - } else if (pct < 155) { - assert(base.remove(k) === atomic { implicit t => mut.tmap.remove(k) }) - } else if (pct < 160) { - for (j <- 0 until (i / (total / 20))) { - if (!base.isEmpty) { - val k1 = base.iterator.next()._1 - assert(base.remove(k1) === atomic { implicit t => mut.tmap.remove(k1) }) - } - } - } else if (pct < 163) { - mut = atomic { implicit t => mut.tmap.clone.single } - } else if (pct < 166) { - assert(base.toMap === atomic { implicit t => mut.tmap.snapshot }) - } else if (pct < 169) { - assert(base.isEmpty === atomic { implicit t => mut.tmap.isEmpty }) - } else if (pct < 172) { - assert(base.size === atomic { implicit t => mut.tmap.size }) - } else if (pct < 177) { - assert(base eq (base += (k -> v))) - assert(mut.tmap eq atomic { implicit t => mut.tmap += (k -> v) }) - } else if (pct < 180) { - val kv2 = (nextKey -> nextValue) - val kv3 = (nextKey -> nextValue) - assert(base eq (base += ((k -> v), kv2, kv3))) - assert(mut.tmap eq atomic { implicit t => mut.tmap += ((k -> v), kv2, kv3) }) - } else if (pct < 182) { - val kv2 = (nextKey -> nextValue) - val kv3 = (nextKey -> nextValue) - assert(base eq (base ++= Array((k -> v), kv2, kv3))) - assert(mut.tmap eq atomic { implicit t => mut.tmap ++= Array((k -> v), kv2, kv3) }) - } else if (pct < 183) { - assert(mut.tmap eq atomic { implicit t => mut.tmap ++= Nil }) - } else if (pct < 188) { - assert(base eq (base -= k)) - assert(mut.tmap eq atomic { implicit t => mut.tmap -= k }) - } else if (pct < 191) { - val k2 = nextKey() - val k3 = nextKey() - assert(base eq (base -= (k, k2, k3))) - assert(mut.tmap eq atomic { implicit t => mut.tmap -= (k, k2, k3) }) - } else if (pct < 193) { - val k2 = nextKey() - val k3 = nextKey() - assert(base eq (base --= Array(k, k2, k3))) - assert(mut.tmap eq atomic { implicit t => mut.tmap --= Array(k, k2, k3) }) - } else if (pct < 194) { - assert(mut.tmap eq atomic { implicit t => mut.tmap --= Nil }) - } else if (pct < 195) { - mut = atomic { implicit t => TMap(mut.tmap.toArray: _*).single } - } else if (pct < 196) { - mut = atomic { implicit t => TMap.empty[String, Int] ++= mut.tmap }.single - } else if (pct < 197) { - atomic { implicit t => - val m2 = mutable.Map.empty[String, Int] - for (kv <- mut.tmap) { m2 += kv } - assert(base === m2) - } - } else if (pct < 198) { - atomic { implicit t => - val m2 = mutable.Map.empty[String, Int] - for (kv <- mut.tmap.iterator) { m2 += kv } - assert(base === m2) - } - } else if (pct < 200) { - var b = base.toMap - var s = mut.snapshot - assert(b.iterator.toMap === s.iterator.toMap) - while (!b.isEmpty) { - if (rand.nextInt(100) < 75) { - val k = b.keysIterator.next() - assert(b(k) === s(k)) - b -= k - s -= k - assert(b.size === s.size) - } else { - val kv = (nextKey -> nextValue) - b += kv - s += kv - } - } - assert(b.isEmpty === s.isEmpty) - val kv = (nextKey -> nextValue) - b += kv - s += kv - assert(b === s) - } else if (pct < 208) { - val cutoff = rand.nextInt() - assert(base eq (base.retain { (k, v) => v < cutoff })) - assert(mut eq (mut.retain { (k, v) => v < cutoff })) - } else if (pct < 211) { - val cutoff = rand.nextInt() - assert(base eq (base.retain { (k, v) => v < cutoff })) - assert(mut.tmap eq atomic { implicit txn => mut.tmap.retain { (k, v) => v < cutoff } }) - } else if (pct < 214) { - val k = nextKey() - val v = nextValue() - var bf = false - var mf = false - assert(base.getOrElseUpdate(k, { bf = true ; v }) === mut.getOrElseUpdate(k, { mf = true ; v })) - assert(bf === mf) - } else if (pct < 217) { - val k = nextKey() - val v = nextValue() - var bf = false - var mf = false - assert(base.getOrElseUpdate(k, { bf = true ; v }) === atomic { implicit txn => mut.getOrElseUpdate(k, { mf = true ; v }) }) - assert(bf === mf) - } else if (pct < 220) { - assert(base eq (base.transform { (k, v) => v + 1 })) - assert(mut eq (mut.transform { (k, v) => v + 1 })) - } else if (pct < 223) { - assert(base eq (base.transform { (k, v) => v + 1 })) - assert(mut.tmap eq atomic { implicit txn => mut.tmap.transform { (k, v) => v + 1 } }) - } else if (pct < 225) { - val b2 = base map { kv => (kv._1 -> kv._2 * 1L) } - val m2 = mut map { kv => (kv._1 -> kv._2 * 1L) } - assert(b2 === m2) - assert(m2 eq m2.tmap.single) - mut = m2 map { kv => (kv._1 -> kv._2.asInstanceOf[Int]) } - } else if (pct < 227) { - mut = TMap.View.empty[String, Int] ++ mut - } else if (pct < 229) { - mut = atomic { implicit txn => mut.tmap.empty ++ mut.tmap } - } else if (pct < 231) { - val b = TMap.View.newBuilder[String, Int] - b ++= mut - b.clear() - b ++= mut - mut = b.result() - } else if (pct < 233) { - mut = (atomic { implicit txn => - val b = TMap.newBuilder[String, Int] - b ++= mut.tmap - b.clear() - b ++= mut.tmap - b.result() - }).single - } - } - } - - test("tmap clear") { - val m = TMap(1 -> "one", 2 -> "two") - atomic { implicit txn => m.clear() } - assert(m.single.size === 0) - assert(!m.single.iterator.hasNext) - for (e <- m.single) { assert(false) } - } - - test("view clear") { - val m = TMap(1 -> "one", 2 -> "two") - m.single.clear() - assert(m.single.size === 0) - assert(!m.single.iterator.hasNext) - for (e <- m.single) { assert(false) } - } - - test("null key") { - val m = TMap((null : AnyRef) -> "abc", "def" -> "ghi") - assert(m.single.size === 2) - assert(m.single(null) === "abc") - assert(m.single.remove(null) === Some("abc")) - assert(m.single.size === 1) - assert(m.single.put(null, "jkl") === None) - assert(m.single.size === 2) - assert(m.single.get(null) === Some("jkl")) - } - - test("null value") { - val m = TMap("abc" -> null, "def" -> "ghi") - assert(m.single.size === 2) - assert(m.single.get("abc") === Some(null)) - assert(m.single.remove("abc") === Some(null)) - assert(m.single.size === 1) - assert(m.single.put("jkl", null) === None) - assert(m.single.size === 2) - assert(m.single.contains("jkl")) - } - - test("view builder magic") { - val fwd = TMap.View(1 -> "one", 2 -> "two") - val rev = fwd map { kv => (kv._2 -> kv._1) } - val rev2: TMap.View[String, Int] = rev - assert(rev === Map("one" -> 1, "two" -> 2)) - } - - test("iterator crossing a txn boundary") { - val kvs = (0 until 100) map { i => ((i % 37) -> ("x" + i)) } - val m = TMap(kvs: _*) - val iter = atomic { implicit txn => m.iterator } - assert(iter.toMap === kvs.toMap) - } - - test("iterator after many removes") { - val m = TMap.View.empty[Int, Int] - for (i <- 0 until 100000) - m(i) = i - for (i <- 0 until 100000) - m -= i - assert(!m.iterator.hasNext) - for (e <- m) { assert(false) } - atomic { implicit txn => assert(m.tmap.isEmpty) } - atomic { implicit txn => assert(m.tmap.size === 0) } - assert(m.isEmpty) - assert(m.size === 0) - } - - test("view snapshot foreach") { - val kvs = (0 until 100) map { i => (i -> ("x" + (i % 37))) } - val m = TMap(kvs: _*) - var n = 0 - for ((k, v) <- m.single.snapshot) n += k - assert(n === 4950) - } - - test("txn snapshot foreach") { - val kvs = (0 until 100) map { i => (i -> ("x" + (i % 37))) } - val m = TMap(kvs: _*) - var n = 0 - for ((k, v) <- atomic { implicit txn => m.snapshot }) n += k - assert(n === 4950) - } - - test("contention") { - val values = (0 until 37) map { i => "foo" + i } - for (pass <- 0 until 2) { - val numThreads = 8 - val m = TMap.empty[Int, String] - val threads = for (t <- 0 until numThreads) yield new Thread { - override def run() { - var rand = new SimpleRandom(t) - var i = 0 - while (i < 1000000) { - if (rand.nextInt(2) == 0) { - var j = 0 - while (j < 64) { - val key = rand.nextInt(1 << 11) - val pct = rand.nextInt(100) - if (pct < 33) - m.single.contains(key) - else if (pct < 33) - m.single.put(key, values(rand.nextInt(values.length))) - else - m.single.remove(key) - j += 1 - } - } else { - rand = atomic { implicit txn => - val r = rand.clone - var j = 0 - while (j < 64) { - val key = r.nextInt(1 << 11) - val pct = r.nextInt(100) - if (pct < 33) - m.contains(key) - else if (pct < 33) - m.put(key, values(r.nextInt(values.length))) - else - m.remove(key) - j += 1 - } - r - } - } - i += 64 - } - } - } - - val begin = System.currentTimeMillis - for (t <- threads) t.start() - for (t <- threads) t.join() - val elapsed = System.currentTimeMillis - begin - - println("TMap: contended: " + numThreads + " threads, total throughput was " + (elapsed / numThreads) + " nanos/op") - } - } - - test("atomicity violation") { - // This test makes sure that the copy-on-write snapshot mechanism can't - // expose the intermediate state of a txn to a non-txn get. - val m = TMap(kvRange(0, 1000): _*).single - m(0) = "okay" - val failed = Ref(-1).single - val threads = Array.tabulate(2) { _ => - new Thread { - override def run() { - val r = new SimpleRandom - for (i <- 0 until 100000) { - if (r.nextInt(2) == 0) { - if (m(0) != "okay") { - failed() = i - return - } - } else { - atomic { implicit txn => - m(0) = "should be isolated" - m.snapshot - m(0) = "okay" - } - } - } - } - } - } - for (t <- threads) t.start() - for (t <- threads) t.join() - assert(failed() === -1) - } - - //////// perf stuff - - private def now = System.currentTimeMillis - - test("sequential non-txn read performance", Slow) { - for (pass <- 0 until 4) { - for (size <- List(10, 100, 1000, 100000)) { - val m = TMap(kvRange(0, size): _*).single - val t0 = now - var i = 0 - var k = 0 - while (i < 1000000) { - assert(m.contains(k) == (k < size)) - i += 1 - k = if (k == 2 * size - 1) 0 else k + 1 - } - val elapsed = now - t0 - println("TMap: non-txn read: " + size + " keys/map -> " + elapsed + " nanos/contain") - } - } - } - - test("sequential non-txn append performance", Slow) { - for (pass <- 0 until 2) { - for (size <- List(10, 100, 1000, 100000)) { - val src = kvRange(0, size).toArray - val t0 = now - var outer = 0 - while (outer < 1000000) { - TMap.empty[Int, String].single ++= src - outer += size - } - val elapsed = now - t0 - println("TMap: non-txn append: " + size + " keys/map -> " + elapsed + " nanos/added-key") - } - } - } - - test("sequential non-txn update performance", Slow) { - val values = (0 until 37) map { "x" + _ } - for (pass <- 0 until 2) { - for (size <- List(10, 100, 1000, 100000)) { - val m = TMap(kvRange(0, size): _*).single - val t0 = now - var i = 0 - while (i < 1000000) { - val prev = m.put(i % size, values(i % values.length)) - assert(!prev.isEmpty) - i += 1 - } - val elapsed = now - t0 - println("TMap: non-txn update: " + size + " keys/map -> " + elapsed + " nanos/put") - } - } - } - - test("sequential non-txn put/remove mix performance", Slow) { - val values = (0 until 37) map { "x" + _ } - val rand = new skel.SimpleRandom - for (pass <- 0 until 4) { - for (size <- List(10, 100, 1000, 100000)) { - val m = TMap(kvRange(0, size): _*).single - val t0 = now - var i = 0 - while (i < 1000000) { - val r = rand.nextInt() - val k = math.abs(r % size) - if (r > 0) - m.put(k, values(i % values.length)) - else - m.remove(k) - i += 1 - } - val elapsed = now - t0 - println("TMap: non-txn put/remove: " + size + " keys/map -> " + elapsed + " nanos/op") - } - } - } - - test("sequential txn read performance", Slow) { - for (txnSize <- List(2, 10, 1000)) { - for (pass <- 0 until 2) { - for (size <- List(10, 100, 1000, 100000)) { - val m = TMap(kvRange(0, size): _*).single - val t0 = now - for (ii <- 0 until 1000000 by txnSize) { - atomic { implicit txn => - var i = ii - while (i < ii + txnSize) { - val k = i % (2 * size) - assert(m.contains(k) == (k < size)) - i += 1 - } - } - } - val elapsed = now - t0 - println("TMap: txn read: " + txnSize + " accesses/txn: " + size + " keys/map -> " + elapsed + " nanos/op") - } - } - } - } - - test("sequential txn put/remove mix performance", Slow) { - val values = (0 until 37) map { "x" + _ } - val rand = new skel.SimpleRandom - for (txnSize <- List(2, 10, 1000)) { - for (pass <- 0 until 2) { - for (size <- List(10, 100, 1000, 100000)) { - val m = TMap(kvRange(0, size): _*).single - val t0 = now - for (ii <- 0 until 1000000 by txnSize) { - atomic { implicit txn => - var i = ii - while (i < ii + txnSize) { - val r = rand.nextInt() - val k = math.abs(r % size) - if (r > 0) - m.put(k, values(i % values.length)) - else - m.remove(k) - i += 1 - } - } - } - val elapsed = now - t0 - println("TMap: txn put/remove: " + txnSize + " accesses/txn: " + size + " keys/map -> " + elapsed + " nanos/op") - } - } - } - } - - test("TxnDebuggable") { - val m1 = TMap[Int, Int]() - val m2 = TMap(1 -> "one") - val m3 = TMap(1 -> "one", 2 -> "two").single - val m4 = TMap(kvRange(0, 10000): _*).single - - assert(m1.dbgStr === "TMap[size=0]()") - assert(m2.dbgStr === "TMap[size=1](1 -> one)") - assert(m3.dbgStr == "TMap[size=2](1 -> one, 2 -> two)" || - m3.dbgStr == "TMap[size=2](2 -> two, 1 -> one)") - assert(m4.dbgStr.startsWith("TMap[size=10000](")) - assert(m4.dbgStr.length >= 1000) - assert(m4.dbgStr.length < 1100) - - assert(m1.dbgValue.asInstanceOf[Array[_]].length === 0) - assert(m2.dbgValue.asInstanceOf[Array[_]].length === 1) - assert(m3.dbgValue.asInstanceOf[Array[_]].length === 2) - assert(m4.dbgValue.asInstanceOf[Array[_]].length === 10000) - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/TSetSuite.scala b/benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/TSetSuite.scala deleted file mode 100644 index e6a3e451..00000000 --- a/benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/TSetSuite.scala +++ /dev/null @@ -1,421 +0,0 @@ -/* scala-stm - (c) 2009-2012, Stanford University, PPL */ - -package scala.concurrent.stm - -import org.scalatest.FunSuite -import scala.util.Random -import scala.collection.mutable - -class TSetSuite extends FunSuite { - - test("number equality trickiness") { - assert(TSet(10L).single contains 10) - //assert(TSet(10).single contains 10L) - assert(TSet[Number](10L).single contains 10) - assert(TSet[Number](10).single contains 10L) - assert(TSet[Any](10L).single contains 10) - assert(TSet[Any](10).single contains 10L) - assert(TSet[AnyRef](10L.asInstanceOf[AnyRef]).single contains 10.asInstanceOf[AnyRef]) - assert(TSet[AnyRef](10.asInstanceOf[AnyRef]).single contains 10L.asInstanceOf[AnyRef]) - } - - test("character equality trickiness") { - assert(TSet('*').single contains 42) - assert(TSet(42: Byte).single contains '*') - assert(TSet[Any]('*').single contains (42: Short)) - assert(TSet[Any](42L).single contains '*') - assert(TSet[AnyRef]('*'.asInstanceOf[AnyRef]).single contains 42.0.asInstanceOf[AnyRef]) - assert(TSet[AnyRef](42.0f.asInstanceOf[AnyRef]).single contains '*'.asInstanceOf[AnyRef]) - } - - case class BadHash(k: Int) { - override def hashCode = if (k > 500) k / 5 else 0 - } - - test("correct despite poor hash function") { - val mut = TSet(((0 until 1000) map { i => BadHash(i) }): _*).single - for (i <- -500 until 1500) - assert(mut(BadHash(i)) === (i >= 0 && i < 1000)) - } - - test("clone captures correct atomic writes") { - val mut = TSet((0 until 100): _*) - val z = atomic { implicit txn => - mut ++= (100 until 200) - val z = mut.clone.single - mut ++= (200 until 300) - z - } - assert(z.size === 200) - for (i <- 0 until 200) - assert(z.contains(i)) - } - - test("clone doesn't include discarded writes") { - val mut = TSet((0 until 100): _*) - val z = atomic { implicit txn => - atomic { implicit txn => - mut ++= (100 until 200) - if ("likely".## != 0) - retry - } orAtomic { implicit txn => - mut ++= (200 until 300) - } - val z = mut.clone.single - atomic { implicit txn => - mut ++= (300 until 400) - if ("likely".## != 0) - retry - } orAtomic { implicit txn => - mut ++= (400 until 500) - } - z - } - assert(z.size === 200) - for (i <- 0 until 100) - assert(z.contains(i)) - for (i <- 200 until 300) - assert(z.contains(i)) - } - - test("clone is transactional") { - val mut = TSet((0 until 100): _*) - val z = atomic { implicit txn => - atomic { implicit txn => - mut ++= (100 until 105) - if ("likely".## != 0) - retry - } orAtomic { implicit txn => - mut ++= (200 until 205) - } - val z = mut.clone.single - atomic { implicit txn => - z ++= (300 until 305) - if ("likely".## != 0) - retry - } orAtomic { implicit txn => - z ++= (400 until 405) - } - z - } - assert(z.size === 110) - for (i <- 0 until 100) - assert(z.contains(i)) - for (i <- 200 until 205) - assert(z.contains(i)) - for (i <- 400 until 405) - assert(z.contains(i)) - } - - - test("random sequential") { - randomTest(1500) - } - - test("more random sequential", Slow) { - randomTest(30000) - } - - def randomTest(total: Int) { - val rand = new Random() - - def nextKey(): String = "key" + (rand.nextInt() >>> rand.nextInt()) - - var mut = TSet.empty[String].single - val base = mutable.Set.empty[String] - - for (i <- 0 until total) { - val pct = rand.nextInt(250) - val k = nextKey - if (pct < 15) { - assert(base.contains(k) === mut.contains(k)) - } else if (pct < 20) { - assert(base(k) === mut(k)) - } else if (pct < 35) { - assert(base.add(k) === mut.add(k)) - } else if (pct < 40) { - val v = rand.nextBoolean - base(k) = v - mut(k) = v - } else if (pct < 55) { - assert(base.remove(k) === mut.remove(k)) - } else if (pct < 60) { - for (j <- 0 until (i / (total / 20))) { - if (!base.isEmpty) { - val k1 = base.iterator.next - assert(base.remove(k1) === mut.remove(k1)) - } - } - } else if (pct < 63) { - mut = mut.clone - } else if (pct < 66) { - assert(base.toSet === mut.snapshot) - } else if (pct < 69) { - assert(base.isEmpty === mut.isEmpty) - } else if (pct < 72) { - assert(base.size === mut.size) - } else if (pct < 77) { - assert(base eq (base += k)) - assert(mut eq (mut += k)) - } else if (pct < 80) { - val k2 = nextKey - val k3 = nextKey - assert(base eq (base += (k, k2, k3))) - assert(mut eq (mut += (k, k2, k3))) - } else if (pct < 83) { - val k2 = nextKey - val k3 = nextKey - assert(base eq (base ++= Array(k, k2, k3))) - assert(mut eq (mut ++= Array(k, k2, k3))) - } else if (pct < 82) { - assert(mut eq (mut ++= Nil)) - } else if (pct < 88) { - assert(base eq (base -= k)) - assert(mut eq (mut -= k)) - } else if (pct < 91) { - val k2 = nextKey - val k3 = nextKey - assert(base eq (base -= (k, k2, k3))) - assert(mut eq (mut -= (k, k2, k3))) - } else if (pct < 93) { - val k2 = nextKey - val k3 = nextKey - assert(base eq (base --= Array(k, k2, k3))) - assert(mut eq (mut --= Array(k, k2, k3))) - } else if (pct < 94) { - assert(mut eq (mut --= Nil)) - } else if (pct < 95) { - mut = TSet(mut.toArray: _*).single - } else if (pct < 96) { - mut = TSet.empty[String].single ++= mut - } else if (pct < 97) { - val s2 = mutable.Set.empty[String] - for (k <- mut) { s2 += k } - assert(base === s2) - } else if (pct < 98) { - val s2 = mutable.Set.empty[String] - for (k <- mut.iterator) { s2 += k } - assert(base === s2) - } else if (pct < 115) { - assert(base.contains(k) === atomic { implicit txn => mut.tset.contains(k) }) - } else if (pct < 120) { - assert(base(k) === atomic { implicit txn => mut.tset(k) }) - } else if (pct < 135) { - assert(base.add(k) === atomic { implicit txn => mut.tset.add(k) }) - } else if (pct < 140) { - val v = rand.nextBoolean - base(k) = v - atomic { implicit txn => mut.tset(k) = v } - } else if (pct < 155) { - assert(base.remove(k) === atomic { implicit txn => mut.tset.remove(k) }) - } else if (pct < 160) { - for (j <- 0 until (i / (total / 20))) { - if (!base.isEmpty) { - val k1 = base.iterator.next - assert(base.remove(k1) === atomic { implicit txn => mut.tset.remove(k1) }) - } - } - } else if (pct < 163) { - mut = atomic { implicit txn => mut.tset.clone.single } - } else if (pct < 166) { - assert(base.toSet === atomic { implicit txn => mut.tset.snapshot }) - } else if (pct < 169) { - assert(base.isEmpty === atomic { implicit txn => mut.tset.isEmpty }) - } else if (pct < 172) { - assert(base.size === atomic { implicit txn => mut.tset.size }) - } else if (pct < 177) { - assert(base eq (base += k)) - assert(mut.tset eq atomic { implicit txn => mut.tset += k }) - } else if (pct < 180) { - val k2 = nextKey - val k3 = nextKey - assert(base eq (base += (k, k2, k3))) - assert(mut.tset eq atomic { implicit txn => mut.tset += (k, k2, k3) }) - } else if (pct < 182) { - val k2 = nextKey - val k3 = nextKey - assert(base eq (base ++= Array(k, k2, k3))) - assert(mut.tset eq atomic { implicit txn => mut.tset ++= Array(k, k2, k3) }) - } else if (pct < 183) { - assert(mut.tset eq atomic { implicit txn => mut.tset ++= Nil }) - } else if (pct < 188) { - assert(base eq (base -= k)) - assert(mut.tset eq atomic { implicit txn => mut.tset -= k }) - } else if (pct < 191) { - val k2 = nextKey - val k3 = nextKey - assert(base eq (base -= (k, k2, k3))) - assert(mut.tset eq atomic { implicit txn => mut.tset -= (k, k2, k3) }) - } else if (pct < 193) { - val k2 = nextKey - val k3 = nextKey - assert(base eq (base --= Array(k, k2, k3))) - assert(mut.tset eq atomic { implicit txn => mut.tset --= Array(k, k2, k3) }) - } else if (pct < 194) { - assert(mut.tset eq atomic { implicit txn => mut.tset --= Nil }) - } else if (pct < 195) { - mut = atomic { implicit txn => TSet(mut.tset.toArray: _*).single } - } else if (pct < 196) { - mut = atomic { implicit txn => TSet.empty[String] ++= mut.tset }.single - } else if (pct < 197) { - atomic { implicit txn => - val s2 = mutable.Set.empty[String] - for (k <- mut.tset) { s2 += k } - assert(base === s2) - } - } else if (pct < 198) { - atomic { implicit txn => - val s2 = mutable.Set.empty[String] - for (k <- mut.tset.iterator) { s2 += k } - assert(base === s2) - } - } else if (pct < 200) { - var b = base.toSet - var s = mut.snapshot - assert(b.iterator.toSet === s.iterator.toSet) - while (!b.isEmpty) { - if (rand.nextInt(100) < 75) { - val k = b.iterator.next - assert(b(k) === s(k)) - b -= k - s -= k - assert(b.size === s.size) - } else { - val k = nextKey - b += k - s += k - } - } - assert(b.isEmpty === s.isEmpty) - val k = nextKey - b += k - s += k - assert(b === s) - } else if (pct < 208) { - val cutoff = nextKey - base.retain { v => v < cutoff } - mut.retain { v => v < cutoff } - } else if (pct < 211) { - val cutoff = nextKey - base.retain { v => v < cutoff } - atomic { implicit txn => mut.tset.retain { v => v < cutoff } } - } else if (pct < 214) { - val b2 = base map { v => v.substring(3).toInt } - val m2 = mut map { v => v.substring(3).toInt } - assert(b2 === m2) - assert(m2 eq m2.tset.single) - mut = m2 map { v => "key" + v } - } else if (pct < 217) { - mut = TSet.View.empty[String] ++ mut - } else if (pct < 219) { - mut = atomic { implicit txn => mut.tset.empty ++ mut.tset } - } else if (pct < 221) { - val b = TSet.View.newBuilder[String] - b ++= mut - b.clear() - b ++= mut - mut = b.result - } else if (pct < 223) { - mut = (atomic { implicit txn => - val b = TSet.newBuilder[String] - b ++= mut.tset - b.clear() - b ++= mut.tset - b.result - }).single - } - } - } - - test("tset clear") { - val s = TSet(1, 2) - atomic { implicit txn => s.clear() } - assert(s.single.isEmpty) - assert(s.single.size === 0) - assert(!s.single.iterator.hasNext) - for (e <- s.single) { assert(false) } - } - - test("view clear") { - val s = TSet(1, 2) - s.single.clear() - assert(s.single.size === 0) - assert(!s.single.iterator.hasNext) - for (e <- s.single) { assert(false) } - } - - test("null entry") { - val s = TSet("abc", "def", (null: AnyRef)) - assert(s.single.size === 3) - assert(s.single(null)) - assert(s.single.remove(null)) - assert(s.single.size === 2) - assert(!s.single(null)) - assert(s.single.add(null)) - assert(s.single.size === 3) - } - - test("view builder magic") { - val s0 = TSet.View(1, 2, 3) - val s1 = s0 map { "x" + _ } - val s2: TSet.View[String] = s1 - assert(s1 === Set("x1", "x2", "x3")) - } - - test("iterator crossing a txn boundary") { - val ks = (0 until 100) map { i => "x" + (i % 37) } - val s = TSet(ks: _*) - val iter = atomic { implicit txn => s.iterator } - assert(iter.toSet === ks.toSet) - } - - test("iterator after many removes") { - val s = TSet.View.empty[Int] - for (i <- 0 until 100000) - s += i - for (i <- 0 until 100000) - s -= i - assert(!s.iterator.hasNext) - for (e <- s) { assert(false) } - atomic { implicit txn => assert(s.tset.isEmpty) } - atomic { implicit txn => assert(s.tset.size === 0) } - assert(s.isEmpty) - assert(s.size === 0) - } - - test("view snapshot foreach") { - val ks = (0 until 100) - val s = TSet(ks: _*) - var n = 0 - for (k <- s.single.snapshot) n += k - assert(n === 4950) - } - - test("txn snapshot foreach") { - val ks = (0 until 100) - val s = TSet(ks: _*) - var n = 0 - for (k <- atomic { implicit txn => s.snapshot }) n += k - assert(n === 4950) - } - - test("TxnDebuggable") { - val s1 = TSet[Int]() - val s2 = TSet(1) - val s3 = TSet(1, 2).single - val s4 = TSet((0 until 10000): _*).single - - assert(s1.dbgStr === "TSet[size=0]()") - assert(s2.dbgStr === "TSet[size=1](1)") - assert(s3.dbgStr == "TSet[size=2](1, 2)" || - s3.dbgStr == "TSet[size=2](2, 1)") - assert(s4.dbgStr.startsWith("TSet[size=10000](")) - assert(s4.dbgStr.length >= 1000) - assert(s4.dbgStr.length < 1100) - - assert(s1.dbgValue.asInstanceOf[Array[_]].length === 0) - assert(s2.dbgValue.asInstanceOf[Array[_]].length === 1) - assert(s3.dbgValue.asInstanceOf[Array[_]].length === 2) - assert(s4.dbgValue.asInstanceOf[Array[_]].length === 10000) - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/TokenRingSuite.scala b/benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/TokenRingSuite.scala deleted file mode 100644 index 9ff7ce44..00000000 --- a/benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/TokenRingSuite.scala +++ /dev/null @@ -1,85 +0,0 @@ -/* scala-stm - (c) 2009-2010, Stanford University, PPL */ - -package scala.concurrent.stm - -import java.util.concurrent.CyclicBarrier -import org.scalatest.FunSuite - - -/** This test uses the transactional retry mechanism to pass a token around a - * ring of threads. When there are two threads this is a ping-pong test. A - * separate `Ref` is used for each handoff. - * - * @author Nathan Bronson - */ -class TokenRingSuite extends FunSuite { - test("small non-txn threesome") { tokenRing(3, 10000, false, false) } - test("small txn threesome") { tokenRing(3, 1000, true, false) } - test("small txn threesome reading via write") { tokenRing(3, 1000, true, true) } - - test("non-txn ping-pong", Slow) { tokenRing(2, 1000000, false, false) } - test("non-txn threesome", Slow) { tokenRing(3, 1000000, false, false) } - test("non-txn large ring", Slow) { tokenRing(32, 10000, false, false) } - test("txn ping-pong", Slow) { tokenRing(2, 100000, true, false) } - test("txn threesome", Slow) { tokenRing(3, 100000, true, false) } - test("txn large ring", Slow) { tokenRing(32, 10000, true, false) } - test("txn ping-pong reading via write", Slow) { tokenRing(2, 100000, true, true) } - test("txn threesome reading via write", Slow) { tokenRing(3, 100000, true, true) } - test("txn large ring reading via write", Slow) { tokenRing(32, 10000, true, true) } - - def tokenRing(ringSize: Int, handoffsPerThread: Int, useTxns: Boolean, useSwap: Boolean) { - val ready = Array.tabulate(ringSize)(i => Ref(i == 0)) - val threads = new Array[Thread](ringSize - 1) - val barrier = new CyclicBarrier(ringSize, new Runnable { - var start = 0L - def run { - val now = System.currentTimeMillis - if (start == 0) { - start = now - } else { - val elapsed = now - start - val handoffs = handoffsPerThread * ringSize - println("tokenRing(" + ringSize + "," + handoffsPerThread + "," + useTxns + - ") total_elapsed=" + elapsed + " msec, throughput=" + - (handoffs * 1000L) / elapsed + " handoffs/sec, latency=" + - (elapsed * 1000000L) / handoffs + " nanos/handoff") - } - } - }) - - for (index <- 0 until ringSize) { - val work = new Runnable { - def run { - val next = (index + 1) % ringSize - barrier.await - for (h <- 0 until handoffsPerThread) { - if (!useTxns) { - ready(index).single await { _ == true } - ready(index).single() = false - ready(next).single() = true - } else { - atomic { implicit t => - if (!useSwap) { - if (ready(index).get == false) retry - ready(index)() = false - } else { - if (ready(index).swap(false) == false) retry - } - ready(next)() = true - } - } - } - barrier.await - } - } - if (index < ringSize - 1) { - threads(index) = new Thread(work, "worker " + index) - threads(index).start - } else { - work.run - } - } - - for (t <- threads) t.join - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/TxnLocalSuite.scala b/benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/TxnLocalSuite.scala deleted file mode 100644 index 9cf14bb1..00000000 --- a/benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/TxnLocalSuite.scala +++ /dev/null @@ -1,332 +0,0 @@ -/* scala-stm - (c) 2009-2012, Stanford University, PPL */ - -package scala.concurrent.stm - -import org.scalatest.FunSuite - - -class TxnLocalSuite extends FunSuite { - test("default initial value") { - val tl = TxnLocal[String]() - atomic { implicit txn => - assert(tl() === null) - tl() = "hello" - } - atomic { implicit txn => - assert(tl() === null) - } - atomic { implicit txn => - tl() = "transient" - } - atomic { implicit txn => - assert(tl() === null) - tl() = "world" - } - } - - test("initialize with init") { - val tl = TxnLocal("hello") - for (i <- 0 until 100) { - atomic { implicit txn => - assert(tl() === "hello") - tl() = "goodbye" - } - } - } - - test("initialize with initialValue") { - val tl = TxnLocal[Int]( - initialValue = { txn => txn.rootLevel.## } - ) - atomic { implicit txn => - assert(tl() === txn.rootLevel.##) - } - atomic { implicit txn => - assert(tl() === txn.rootLevel.##) - } - } - - test("initialValue overrides init") { - val x = Ref("abc") - val tl = TxnLocal("hello", initialValue = { implicit txn => x() }) - for (i <- 0 until 100) { - atomic { implicit txn => - assert(tl() === "abc") - tl() = "goodbye" - } - } - } - - test("use in afterCompletion handler") { - val tl = TxnLocal("default") - atomic { implicit txn => - Txn.afterCompletion { status => - atomic { implicit txn => - assert(tl() === "default") - } - } - tl() = "set once" - Txn.afterCompletion { status => - atomic { implicit txn => - assert(tl() === "default") - } - } - } - } - - test("partial rollback restores previous value") { - val tl = TxnLocal("default") - atomic { implicit txn => - tl() = "outer" - intercept[RuntimeException] { - atomic { implicit txn => - assert(tl.swap("inner") === "outer") - throw new RuntimeException - } - } - assert(tl() === "outer") - } - } - - test("partial rollback triggers new initialization") { - val x = Ref(0) - val tl = TxnLocal( { x.single() } ) - atomic { implicit txn => - x() = 1 - assert(!tl.isInitialized) - intercept[RuntimeException] { - atomic { implicit txn => - assert(!tl.isInitialized) - x() = 2 - assert(tl() === 2) - assert(tl.isInitialized) - throw new RuntimeException - } - } - assert(!tl.isInitialized) - assert(tl() === 1) - assert(tl.isInitialized) - } - } - - test("all RefLike operations") { - val tl = TxnLocal(init = 10) - atomic { implicit txn => - assert(tl.get === 10) - assert(tl() === 10) - assert(tl.getWith( _ + 5 ) === 15) - assert(tl.relaxedGet( _ == _ ) === 10) - tl.set(15) - assert(tl() === 15) - tl() = 20 - assert(tl() === 20) - assert(tl.trySet(25)) - assert(tl() === 25) - assert(tl.swap(30) === 25) - tl.transform( _ + 7 ) - assert(tl() === 37) - assert(tl.transformIfDefined { - case x if x > 20 => x + 1 - }) - assert(tl() === 38) - assert(!tl.transformIfDefined { - case x if x < 20 => x + 1 - }) - } - } - - test("first init in whilePreparing handler") { - val tl = TxnLocal(10) - atomic { implicit txn => - Txn.whilePreparing { implicit txn => - assert(tl() == 10) - tl() = 20 - } - Txn.whilePreparing { implicit txn => - assert(tl() == 20) - } - } - } - - test("first initialValue in beforeCommit handler") { - val tl = TxnLocal(initialValue = { _ => 10 }) - atomic { implicit txn => - Txn.beforeCommit { implicit txn => - assert(tl() == 10) - tl() = 20 - } - Txn.beforeCommit { implicit txn => - assert(tl() == 20) - } - } - } - - test("first initialValue in whilePreparing handler") { - val tl = TxnLocal(initialValue = { _ => 10 }) - val x = Ref("abc") - intercept[IllegalStateException] { - atomic { implicit txn => - x() = "def" - Txn.whilePreparing { implicit txn => - assert(tl() == 10) - tl() = 20 - } - } - } - assert(x.single() === "abc") - } - - test("first initialValue in whileCommitting handler") { - val tl = TxnLocal(initialValue = { _ => 10 }) - var failure: Throwable = null - val handler = { (s: Txn.Status, x: Throwable) => failure = x } - val x = Ref("abc") - atomic.withPostDecisionFailureHandler(handler) { implicit txn => - x() = "def" - Txn.whileCommitting { implicit txn => - assert(tl() == 10) - tl() = 20 - } - } - assert(x.single() === "def") - assert(failure != null && failure.isInstanceOf[IllegalStateException]) - } - - test("auto-register beforeCommit") { - val x = Ref(0) - lazy val tl: TxnLocal[Int] = TxnLocal(10, beforeCommit = { implicit txn => - assert(Txn.status === Txn.Active) - x() = tl() - }) - atomic { implicit txn => - tl() = 20 - } - assert(x.single() === 20) - } - - test("auto-register whilePreparing") { - var result: Int = 0 - lazy val tl: TxnLocal[Int] = TxnLocal(10, whilePreparing = { implicit txn => - assert(Txn.status === Txn.Preparing) - assert(result === 0) - tl += 10 - result = tl() - }) - atomic { implicit txn => - tl() = 20 - } - assert(result === 30) - } - - test("auto-register whileCommitting") { - var result: Int = 0 - lazy val tl: TxnLocal[Int] = TxnLocal(10, whileCommitting = { implicit txn => - assert(Txn.status === Txn.Committing) - assert(result === 0) - tl += 10 - result = tl() - }) - atomic { implicit txn => - tl() = 20 - } - assert(result === 30) - } - - test("auto-register afterCommit") { - var result: Int = 0 - val tl = TxnLocal(10, afterCommit = { (v: Int) => result = v }) - atomic { implicit txn => - tl() = 20 - } - assert(result === 20) - } - - test("auto-register afterRollback") { - var result: Txn.Status = null - val tl = TxnLocal(10, afterRollback = { result = _ }) - intercept[ArrayIndexOutOfBoundsException] { - atomic { implicit txn => - tl() = 20 - throw new ArrayIndexOutOfBoundsException(-1) - } - } - assert(result != null && result.isInstanceOf[Txn.RolledBack]) - } - - test("auto-register afterCompletion - commit") { - var result: Txn.Status = null - val tl = TxnLocal(10, afterCompletion = { result = _ }) - atomic { implicit txn => - tl() = 20 - } - assert(result === Txn.Committed) - } - - test("auto-register afterCompletion - rollback") { - var result: Txn.Status = null - val tl = TxnLocal(10, afterCompletion = { result = _ }) - intercept[ArrayIndexOutOfBoundsException] { - atomic { implicit txn => - tl() = 20 - throw new ArrayIndexOutOfBoundsException(-1) - } - } - assert(result != null && result.isInstanceOf[Txn.RolledBack]) - } - - test("auto-register everything") { - var ran = Set.empty[String] - val tl = TxnLocal( - init = "init", - initialValue = { implicit txn => ran += "initialValue" ; "initialValue" }, - beforeCommit = { implicit txn => assert(txn.status === Txn.Active) ; ran += "beforeCommit" }, - whilePreparing = { implicit txn => assert(txn.status === Txn.Preparing) ; ran += "whilePreparing" }, - whileCommitting = { implicit txn => assert(txn.status === Txn.Committing) ; ran += "whileCommitting" }, - afterCommit = { (v: String) => assert(v === "initialValue") ; ran += "afterCommit" }, - afterRollback = { status => assert(false) }, - afterCompletion = { status => assert(status === Txn.Committed) ; ran += "afterCompletion" } - ) - atomic { implicit txn => - assert(tl() === "initialValue") - } - assert(ran === Set("initialValue", "beforeCommit", "whilePreparing", "whileCommitting", "afterCommit", "afterCompletion")) - } - - test("isolation") { - val barrier = new java.util.concurrent.CyclicBarrier(2) - val tl = TxnLocal("init") - var failure: Throwable = null - new Thread { - override def run() { - try { - atomic { implicit txn => - barrier.await - assert(tl() === "init") - barrier.await - tl() = "thread" - barrier.await - assert(tl() === "thread") - barrier.await - } - } catch { - case x: Throwable => failure = x - } - barrier.await - } - }.start() - - atomic { implicit txn => - barrier.await - assert(tl() === "init") - barrier.await - tl() = "main" - barrier.await - assert(tl() === "main") - barrier.await - } - barrier.await - - if (failure != null) - throw failure - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/TxnSuite.scala b/benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/TxnSuite.scala deleted file mode 100644 index cab54dc4..00000000 --- a/benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/TxnSuite.scala +++ /dev/null @@ -1,640 +0,0 @@ -/* scala-stm - (c) 2009-2012, Stanford University, PPL */ - -package scala.concurrent.stm - -import org.scalatest.FunSuite -import java.util.concurrent.CountDownLatch - - -class TxnSuite extends FunSuite { - - test("empty transaction") { - atomic { implicit t => - () // do nothing - } - } - - test("atomic function") { - val answer = atomic { implicit t => - 42 - } - assert(Integer.parseInt(answer.toString, 13) === 6*9) - } - - test("large transaction") { - val refs = Array.tabulate(10000) { i => Ref(i) } - atomic { implicit txn => - for (r <- refs) - r() = r() + 1 - } - } - - test("duplicate view with old access") { - val x = Ref(1) - atomic { implicit t => - val b1 = x.single - assert(b1.get === 1) - val b2 = x.single - assert(b2.get === 1) - b1() = 2 - assert(b1.get === 2) - assert(b2.get === 2) - b2() = 3 - assert(b1.get === 3) - assert(b2.get === 3) - } - assert(x.single.get === 3) - } - - class UserException extends Exception - - test("failure atomicity") { - val x = Ref(1) - intercept[UserException] { - atomic { implicit t => - x() = 2 - throw new UserException - } - } - assert(x.single.get === 1) - } - - test("non-local return") { - val x = Ref(1) - val y = nonLocalReturnHelper(x) - assert(x.single.get === 2) - assert(y === 2) - } - - def nonLocalReturnHelper(x: Ref[Int]): Int = { - atomic { implicit t => - x() = x() + 1 - return x() - } - -1 - } - - test("strings") { - atomic.toString - atomic.withRetryTimeout(100).toString - atomic { implicit txn => txn.toString } - atomic { implicit txn => NestingLevel.root.toString } - } - - test("basic retry") { - val x = Ref(0) - val y = Ref(false) - val b = new CountDownLatch(1) - new Thread { - override def run() { - b.await() - Thread.sleep(10) - y.single() = true - x.single() = 1 - } - }.start() - - atomic { implicit txn => - b.countDown() - if (x() == 0) - retry - } - assert(y.single()) - } - - test("nested retry") { - val x = Ref(0) - val y = Ref(false) - val b = new CountDownLatch(1) - new Thread { - override def run() { - b.await() - Thread.sleep(10) - y.single() = true - x.single() = 1 - } - }.start() - - atomic { implicit txn => - atomic { implicit txn => - // this will cause the nesting to materialize - NestingLevel.current - - b.countDown() - if (x() == 0) - retry - } - } - assert(y.single()) - } - - test("simple orAtomic") { - val x = Ref(0) - val f = atomic { implicit txn => - if (x() == 0) - retry - false - } orAtomic { implicit txn => - true - } - assert(f) - } - - test("single atomic.oneOf") { - val x = Ref("zero") - atomic.oneOf({ implicit txn => - x() = "one" - }) - assert(x.single() === "one") - } - - test("atomic.oneOf") { - val refs = Array(Ref(false), Ref(false), Ref(false)) - for (w <- 0 until 3) { - new Thread("wakeup") { - override def run() { - Thread.sleep(200) - refs(w).single() = true - } - }.start() - oneOfExpect(refs, w, Array(0)) - } - } - - test("nested atomic.oneOf") { - val refs = Array(Ref(false), Ref(false), Ref(false)) - for (w <- 0 until 3) { - new Thread("wakeup") { - override def run() { - Thread.sleep(200) - refs(w).single() = true - } - }.start() - val retries = Array(0) - atomic { implicit txn => oneOfExpect(refs, w, retries) } - } - } - - test("alternative atomic.oneOf") { - val a = Ref(0) - val refs = Array(Ref(false), Ref(false), Ref(false)) - for (w <- 0 until 3) { - new Thread("wakeup") { - override def run() { - Thread.sleep(200) - refs(w).single() = true - } - }.start() - val retries = Array(0) - val f = atomic { implicit txn => - if (a() == 0) - retry - false - } orAtomic { implicit txn => - oneOfExpect(refs, w, retries) - true - } - assert(f) - } - } - - private def oneOfExpect(refs: Array[Ref[Boolean]], which: Int, sleeps: Array[Int]) { - val result = Ref(-1) - atomic.oneOf( - { t: InTxn => implicit val txn = t; result() = 0 ; if (!refs(0)()) retry }, - { t: InTxn => implicit val txn = t; if (refs(1)()) result() = 1 else retry }, - { t: InTxn => implicit val txn = t; if (refs(2)()) result() = 2 else retry }, - { t: InTxn => implicit val txn = t; sleeps(0) += 1 ; retry } - ) - refs(which).single() = false - assert(result.single.get === which) - if (sleeps(0) != 0) - assert(sleeps(0) === 1) - } - - test("orAtomic w/ exception") { - intercept[UserException] { - atomic { implicit t => - if ("likely".hashCode != 0) - retry - } orAtomic { implicit t => - throw new UserException - } - } - } - - test("Atomic.orAtomic") { - val x = Ref(1) - def a() = { - atomic { implicit t => - if (x() > 1) true else retry - } orAtomic { implicit t => - false - } - } - assert(a() === false) - x.single() = 2 - assert(a() === true) - } - - test("simple nesting") { - val x = Ref(10) - atomic { implicit t => - x += 1 - atomic { implicit t => - assert(x.get === 11) - x += 2 - } - assert(x.get === 13) - } - assert(x.single.get === 13) - } - - test("partial rollback") { - val x = Ref("none") - atomic { implicit t => - x() = "outer" - try { - atomic { implicit t => - x() = "inner" - throw new UserException - } - } catch { - case _: UserException => - } - } - assert(x.single() === "outer") - } - - test("partial rollback of transform") { - val x = Ref("none") - atomic { implicit t => - x() = "outer" - try { - atomic { implicit t => - x.transform { _ + "inner" } - throw new UserException - } - } catch { - case _: UserException => - } - } - assert(x.single() === "outer") - } - - test("partial rollback due to invalid read") { - val x = Ref(0) - val y = Ref(0) - - (new Thread { override def run() { Thread.sleep(100) ; y.single() = 1 } }).start() - - atomic { implicit t => - x() - atomic { implicit t => - y() - Thread.sleep(200) - y() - } orAtomic { implicit t => - throw new Error("should not be run") - } - } orAtomic { implicit t => - throw new Error("should not be run") - } - } - - test("View in txn") { - val x = Ref(10) - val xs = x.single - atomic { implicit t => - x += 1 - assert(x() === 11) - assert(xs() === 11) - xs += 1 - assert(x() === 12) - assert(xs() === 12) - x.single += 1 - assert(x() === 13) - assert(xs() === 13) - assert(x.single() === 13) - x.single() = 14 - assert(x() === 14) - } - } - - test("currentLevel during nesting") { - // this test is _tricky_, because an assertion failure inside the atomic - // block might cause a restart that expands any subsumption - val (n0, n1, n2) = atomic { implicit t => - val (n1, n2) = atomic { implicit t => - val n2 = atomic { implicit t => - NestingLevel.current - } - (NestingLevel.current, n2) - } - (NestingLevel.current, n1, n2) - } - assert(n2.parent.get eq n1) - assert(n2.root eq n0) - assert(n1.parent.get eq n0) - assert(n1.root eq n0) - assert(n0.parent.isEmpty) - } - - test("persistent rollback") { - val x = Ref(0) - var okay = true - intercept[UserException] { - atomic { implicit txn => - x() = 1 - try { - Txn.rollback(Txn.UncaughtExceptionCause(new UserException())) - } catch { - case _: Throwable => // swallow - } - x() - okay = false - } - } - assert(okay) - } - - test("persistent rollback via exception") { - val x = Ref(0) - intercept[UserException] { - atomic { implicit txn => - x() = 1 - try { - Txn.rollback(Txn.UncaughtExceptionCause(new UserException())) - } catch { - case _: Throwable => // swallow - } - throw new InterruptedException // this should be swallowed - } - } - } - - test("many multi-level reads") { - val refs = Array.tabulate(10000) { _ => Ref(0) } - atomic { implicit txn => - for (r <- refs) r() = 1 - val f = atomic { implicit txn => - for (r <- refs) r() = 2 - if (refs(0)() != 0) - retry - false - } orAtomic { implicit txn => - true - } - assert(f) - } - for (r <- refs) - assert(r.single() === 1) - } - - test("partial rollback of invalid read") { - val x = Ref(0) - var xtries = 0 - val y = Ref(0) - var ytries = 0 - - (new Thread { override def run() { Thread.sleep(100) ; y.single() = 1 } }).start() - - atomic { implicit txn => - xtries += 1 - x += 1 - atomic { implicit txn => - ytries += 1 - y() - Thread.sleep(200) - y() - } orAtomic { implicit txn => - throw new Error("should not be run") - } - } - - // We can't assert, because different STMs might do different things. - // For CCSTM it should be 1, 2 - println("xtries = " + xtries + ", ytries = " + ytries) - } - - test("await") { - val x = Ref(0) - - new Thread { - override def run() { - Thread.sleep(50) - x.single() = 1 - Thread.sleep(50) - x.single() = 2 - } - }.start() - - x.single.await( _ == 2 ) - assert(x.single() === 2) - } - - test("remote cancel") { - val x = Ref(0) - - val finished = atomic { implicit txn => - x += 1 - NestingLevel.current - } - assert(x.single() === 1) - - for (i <- 0 until 100) { - intercept[UserException] { - atomic { implicit txn => - val active = NestingLevel.current - new Thread { - override def run() { - val cause = Txn.UncaughtExceptionCause(new UserException) - assert(finished.requestRollback(cause) === Txn.Committed) - assert(active.requestRollback(cause) == Txn.RolledBack(cause)) - } - }.start() - - while (true) - x() = x() + 1 - } - } - assert(x.single() === 1) - } - } - - test("remote cancel of root") { - val x = Ref(0) - - val finished = atomic { implicit txn => - x += 1 - NestingLevel.current - } - assert(x.single() === 1) - - for (i <- 0 until 100) { - intercept[UserException] { - atomic { implicit txn => - // this is to force true nesting for CCSTM, but the test should pass for any STM - atomic { implicit txn => NestingLevel.current } - - val active = NestingLevel.current - new Thread { - override def run() { - Thread.`yield`() - Thread.`yield`() - val cause = Txn.UncaughtExceptionCause(new UserException) - assert(finished.requestRollback(cause) === Txn.Committed) - assert(active.requestRollback(cause) == Txn.RolledBack(cause)) - } - }.start() - - while (true) - atomic { implicit txn => x += 1 } - } - } - assert(x.single() === 1) - } - } - - test("remote cancel of child") { - val x = Ref(0) - - for (i <- 0 until 100) { - intercept[UserException] { - atomic { implicit txn => - atomic { implicit txn => - val active = NestingLevel.current - new Thread { - override def run() { - Thread.`yield`() - Thread.`yield`() - val cause = Txn.UncaughtExceptionCause(new UserException) - assert(active.requestRollback(cause) == Txn.RolledBack(cause)) - } - }.start() - - while (true) - x() = x() + 1 - } - } - } - assert(x.single() === 0) - } - } - - test("toString") { - (atomic { implicit txn => - txn.toString - txn - }).toString - (atomic { implicit txn => - NestingLevel.current.toString - NestingLevel.current - }).toString - } - - test("many simultaneous Txns", Slow) { - // CCSTM supports 2046 simultaneous transactions - val threads = Array.tabulate(2500) { _ => new Thread { - override def run() { atomic { implicit txn => Thread.sleep(1000) } } - }} - val begin = System.currentTimeMillis - for (t <- threads) t.start() - for (t <- threads) t.join() - val elapsed = System.currentTimeMillis - begin - println(threads.length + " empty sleep(1000) txns took " + elapsed + " millis") - } - - perfTest("uncontended R+W txn perf") { (x, y) => - var i = 0 - while (i < 5) { - i += 1 - atomic { implicit t => - assert(x() == "abc") - x() = "def" - } - atomic { implicit t => - assert(x() == "def") - x() = "abc" - } - } - } - - for (depth <- List(0, 1, 2, 8)) { - perfTest("uncontended R+W txn perf: nesting depth " + depth) { (x, y) => - var i = 0 - while (i < 5) { - i += 1 - nested(depth) { implicit t => - assert(x() == "abc") - x() = "def" - } - nested(depth) { implicit t => - assert(x() == "def") - x() = "abc" - } - } - } - } - - perfTest("uncontended R+R txn perf") { (x, y) => - var i = 0 - while (i < 10) { - i += 1 - atomic { implicit t => - assert(x() == "abc") - assert(y() == 10) - } - } - } - - for (depth <- List(0, 1, 2, 8)) { - perfTest("uncontended R+R txn perf: nesting depth " + depth) { (x, y) => - var i = 0 - while (i < 10) { - i += 1 - nested(depth) { implicit t => - assert(x() == "abc") - assert(y() == 10) - } - } - } - } - -// for (i <- 0 until 50) { -// perfTest("uncontended R+R txn perf: nesting depth 8, take " + i) { (x, y) => -// var i = 0 -// while (i < 10) { -// i += 1 -// nested(8) { implicit t => -// assert(x() == "abc") -// assert(y() == 10) -// } -// } -// } -// } - - private def nested(depth: Int)(body: InTxn => Unit) { - atomic { implicit txn => - if (depth == 0) - body(txn) - else - nested(depth - 1)(body) - } - } - - private def perfTest(name: String)(runTen: (Ref[String], Ref[Int]) => Unit) { - test(name, Slow) { - val x = Ref("abc") - val y = Ref(10) - var best = java.lang.Long.MAX_VALUE - for (pass <- 0 until 50000) { - val begin = System.nanoTime - runTen(x, y) - val elapsed = System.nanoTime - begin - best = best min elapsed - } - println(name + ": best was " + (best / 10.0) + " nanos/txn") - } - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/UnrecordedTxnSuite.scala b/benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/UnrecordedTxnSuite.scala deleted file mode 100644 index 657f7a2e..00000000 --- a/benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/UnrecordedTxnSuite.scala +++ /dev/null @@ -1,154 +0,0 @@ -/* scala-stm - (c) 2009-2012, Stanford University, PPL */ - -package scala.concurrent.stm - -import org.scalatest.FunSuite -import java.util.concurrent.CountDownLatch - - -class UnrecordedTxnSuite extends FunSuite { - - test("fixed unrecorded txn") { - val z = atomic.unrecorded { implicit txn => "foo" } - assert(z === "foo") - } - - test("nested fixed unrecorded txn") { - val x = Ref(0) - val z = atomic { implicit txn => - x() = 1 - atomic.unrecorded { implicit txn => "foo" } - } - assert(z === "foo") - } - - test("writing unrecorded txn") { - val x = Ref(0) - val z = atomic.unrecorded { implicit txn => - x() = 1 - "foo" - } - assert(z === "foo") - assert(x.single() === 0) - } - - test("nested unrecorded txn") { - val x = Ref(0) - val z = atomic.unrecorded { implicit txn => - x += 1 - atomic.unrecorded { implicit txn => - x += 1 - atomic.unrecorded { implicit txn => - x += 1 - atomic.unrecorded { implicit txn => - x += 1 - atomic.unrecorded { implicit txn => - x += 1 - atomic.unrecorded { implicit txn => - x += 1 - atomic.unrecorded { implicit txn => - x() - } - } - } - } - } - } - } - assert(z === 6) - assert(x.single() === 0) - } - - test("nested new write unrecorded txn") { - val x = Ref(0) - val z = atomic { implicit txn => - atomic.unrecorded { implicit txn => - x() = 1 - "foo" - } - } - assert(x.single() === 0) - assert(z === "foo") - } - - test("nested update unrecorded txn") { - val x = Ref(0) - val z = atomic { implicit txn => - x() = 1 - atomic.unrecorded { implicit txn => - x() = 2 - "foo" - } - } - assert(x.single() === 1) - assert(z === "foo") - } - - test("nested preceding unrecorded txn") { - val x = Ref(0) - val z = atomic { implicit txn => - val z = atomic.unrecorded { implicit txn => - x() = 2 - "foo" - } - x() = 1 - z - } - assert(x.single() === 1) - assert(z === "foo") - } - - test("read set emptied") { - val b = new CountDownLatch(1) - val e = new CountDownLatch(1) - - val x = Ref(0) - - new Thread { - override def run() { - b.await() - x.single() = 1 - e.countDown() - } - }.start() - - var tries = 0 - val (z1, z2) = atomic { implicit txn => - tries += 1 - val z1 = atomic.unrecorded { implicit txn => x() } - b.countDown() - e.await() - (z1, x()) - } - - assert(z1 === 0) - assert(z2 === 1) - assert(tries === 1) - } - - class TestException extends Exception - - test("outerFailure handler") { - - val x = Ref(0) - - var z: Any = null - intercept[TestException] { - atomic { implicit txn => - val level = NestingLevel.root - val done = new CountDownLatch(1) - new Thread { - override def run() { - level.requestRollback(Txn.UncaughtExceptionCause(new TestException)) - done.countDown() - } - }.start() - done.await() - - z = atomic.unrecorded({ implicit txn => x() }, { cause => cause }) - } - } - - assert(z.isInstanceOf[Txn.UncaughtExceptionCause]) - } -} \ No newline at end of file diff --git a/benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/WriteSkewSuite.scala b/benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/WriteSkewSuite.scala deleted file mode 100644 index 3ea13135..00000000 --- a/benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/WriteSkewSuite.scala +++ /dev/null @@ -1,61 +0,0 @@ -/* scala-stm - (c) 2009-2016, Stanford University, PPL */ - -package scala.concurrent.stm - -import org.scalatest.FunSuite - - -class WriteSkewSuite extends FunSuite { - val IncrCount = 1000000 - - test("write skew test 1K") { runTest(1000) } - test("write skew test 1M", Slow) { runTest(1000000) } - - def runTest(incrCount: Int) { - // Two threads, each of which increments its own Ref if the other Ref is - // even. Neither thread should ever observe that both Refs are odd. - // MVCC STMs will require the addition of something like Clojure's "ensure" - // or SQL's "select for update" to avoid the write skew. - val refs = Array(Ref(0), Ref(0)) - val threads = new Array[Thread](2) - - @volatile var failure: Throwable = null - for (id <- 0 to 1) { - threads(id) = new Thread("write skew #" + id) { - val self = refs(id) - val other = refs(1 - id) - - override def run { - try { - for (i <- 0 until incrCount) { - if (null != failure) - return - atomic { implicit t => - if ((other() % 2) != 0) { - if ((self() % 2) != 0) - fail("refs=" + refs.map(_.get)) - retry - } - self() = self() + 1 - } - } - } catch { - case x: Throwable => { - if (null == failure) - failure = x - } - } - } - } - } - - val begin = System.currentTimeMillis - for (t <- threads) t.start - for (t <- threads) t.join - - if (null != failure) - throw failure - val elapsed = System.currentTimeMillis - begin - println("writeSkew(" + (2 * incrCount) + "): " + elapsed + " millis total") - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/examples/BasicSyntax.scala b/benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/examples/BasicSyntax.scala deleted file mode 100644 index 89380a42..00000000 --- a/benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/examples/BasicSyntax.scala +++ /dev/null @@ -1,49 +0,0 @@ -/* scala-stm - (c) 2009-2010, Stanford University, PPL */ - -package scala.concurrent.stm -package examples - -object BasicSyntax { - case class Point(x: Int, y: Int) - val origin = Point(0, 0) - - val top = Ref(origin) - val bottom = Ref(origin) - val left = Ref(origin) - val right = Ref(origin) - - def updateExtremes(p: Point) { - atomic { implicit txn => - if (p.x < left().x) - left() = p - if (p.x > right().x) - right() = p - if (p.y < top().y) - top() = p - if (p.y > bottom().y) - bottom() = p - } - } - - def alternatives { - val z = atomic { implicit txn => - if (!(left().x < -100)) - retry - "left" - } orAtomic { implicit txn => - if (!(right().x > +100)) - retry - "right" - } orAtomic { implicit txn => - if (!(top().y < -100)) - retry - "top" - } orAtomic { implicit txn => - if (!(bottom().y > +100)) - retry - "bottom" - } - println("first out was " + z) - } - -} diff --git a/benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/examples/ConcurrentIntList.scala b/benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/examples/ConcurrentIntList.scala deleted file mode 100644 index 121c8203..00000000 --- a/benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/examples/ConcurrentIntList.scala +++ /dev/null @@ -1,80 +0,0 @@ -/* scala-stm - (c) 2009-2010, Stanford University, PPL */ - -package scala.concurrent.stm.examples - -import scala.concurrent.stm._ - -class ConcurrentIntList { - private class Node(val elem: Int, prev0: Node, next0: Node) { - val isHeader = prev0 == null - val prev = Ref(if (isHeader) this else prev0) - val next = Ref(if (isHeader) this else next0) - } - - private val header = new Node(-1, null, null) - - def addLast(elem: Int) { - atomic { implicit txn => - val p = header.prev() - val newNode = new Node(elem, p, header) - p.next() = newNode - header.prev() = newNode - } - } - - def addLast(e1: Int, e2: Int, elems: Int*) { - atomic { implicit txn => - addLast(e1) - addLast(e2) - elems foreach { addLast(_) } - } - } - - //def isEmpty = atomic { implicit t => header.next() == header } - def isEmpty = header.next.single() == header - - def removeFirst(): Int = atomic { implicit txn => - val n = header.next() - if (n == header) - retry - val nn = n.next() - header.next() = nn - nn.prev() = header - n.elem - } - - def maybeRemoveFirst(): Option[Int] = { - atomic { implicit txn => - Some(removeFirst()) - } orAtomic { implicit txn => - None - } - } - - override def toString: String = { - atomic { implicit txn => - val buf = new StringBuilder("ConcurrentIntList(") - var n = header.next() - while (n != header) { - buf ++= n.elem.toString - n = n.next() - if (n != header) buf ++= "," - } - buf ++= ")" toString - } - } -} - -object ConcurrentIntList { - def select(stacks: ConcurrentIntList*): (ConcurrentIntList, Int) = { - atomic { implicit txn => - for (s <- stacks) { - s.maybeRemoveFirst() match { - case Some(e) => return (s, e) - case None => - } - } - retry - } - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/examples/DiningPhilosophers.scala b/benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/examples/DiningPhilosophers.scala deleted file mode 100644 index e4e6e777..00000000 --- a/benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/examples/DiningPhilosophers.scala +++ /dev/null @@ -1,57 +0,0 @@ -/* scala-stm - (c) 2009-2010, Stanford University, PPL */ - -package scala.concurrent.stm -package examples - -/** See http://en.wikipedia.org/wiki/Dining_philosophers_problem - * The STM solution is particularly straightforward because we can - * simultaneously pick up two forks. - */ -object DiningPhilosophers { - - class Fork { - val inUse = Ref(false) - } - - class PhilosopherThread(meals: Int, left: Fork, right: Fork) extends Thread { - override def run() { - for (m <- 0 until meals) { - // THINK - pickUpBothForks() - // EAT - putDown(left) - putDown(right) - } - } - - def pickUpBothForks() { - atomic { implicit txn => - if (left.inUse() || right.inUse()) - retry - left.inUse() = true - right.inUse() = true - } - } - - def putDown(f: Fork) { - f.inUse.single() = false - } - } - - def time(tableSize: Int, meals: Int): Long = { - val forks = Array.tabulate(tableSize) { _ => new Fork } - val threads = Array.tabulate(tableSize) { i => new PhilosopherThread(meals, forks(i), forks((i + 1) % tableSize)) } - val start = System.currentTimeMillis - for (t <- threads) t.start() - for (t <- threads) t.join() - System.currentTimeMillis - start - } - - def main(args: Array[String]) { - val meals = 100000 - for (p <- 0 until 3) { - val elapsed = time(5, meals) - printf("%3.1f usec/meal\n", (elapsed * 1000.0) / meals) - } - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/examples/IndexedMap.scala b/benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/examples/IndexedMap.scala deleted file mode 100644 index 329a4dbb..00000000 --- a/benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/examples/IndexedMap.scala +++ /dev/null @@ -1,152 +0,0 @@ -/* scala-stm - (c) 2009-2010, Stanford University, PPL */ - -package scala.concurrent.stm -package examples - -import util.Random - -class IndexedMap[A, B] { - - private class Index[C](view: (A, B) => Iterable[C]) extends (C => Map[A, B]) { - val mapping = TMap.empty[C, Map[A, B]] - - def apply(derived: C) = mapping.single.getOrElse(derived, Map.empty[A, B]) - - def += (kv: (A, B))(implicit txn: InTxn) { - for (c <- view(kv._1, kv._2)) - mapping(c) = apply(c) + kv - } - - def -= (kv: (A, B))(implicit txn: InTxn) { - for (c <- view(kv._1, kv._2)) { - val after = mapping(c) - kv._1 - if (after.isEmpty) - mapping -= c - else - mapping(c) = after - } - } - } - - private val contents = TMap.empty[A, B] - private val indices = Ref(List.empty[Index[_]]) - - def addIndex[C](view: (A, B) => Iterable[C]): (C => Map[A, B]) = atomic { implicit txn => - val index = new Index(view) - indices() = index :: indices() - contents foreach { index += _ } - index - } - - def get(key: A): Option[B] = contents.single.get(key) - - def put(key: A, value: B): Option[B] = atomic { implicit txn => - val prev = contents.put(key, value) - for (p <- prev; i <- indices()) - i -= (key -> p) - for (i <- indices()) - i += (key -> value) - prev - } - - def remove(key: A): Option[B] = atomic { implicit txn => - val prev = contents.remove(key) - for (p <- prev; i <- indices()) - i -= (key -> p) - prev - } -} - -object IndexedMap { - - case class User(id: Int, name: String, likes: Set[String]) - - val users = new IndexedMap[Int, User] - val byName = users.addIndex { (id, u) => Some(u.name) } - val byLike = users.addIndex { (id, u) => u.likes } - - //////// data - - val topBabyNames = Array( - "Ethan", "Isabella", "Jacob", "Olivia", "Noah", "Sophia", "Logan", "Emma", "Liam", "Ava", "Aiden", "Abigail", - "Mason", "Chloe", "Jackson", "Madison", "Jack", "Ella", "Jayden", "Addison", "Ryan", "Emily", "Matthew", "Lily", - "Lucas", "Mia", "Michael", "Avery", "Alexander", "Grace", "Nathan", "Hannah") - - val languages = Array("scala", "java", "C++", "haskell", "clojure", "python", "ruby", "pascal", "perl") - val sports = Array("climbing", "cycling", "hiking", "football", "baseball", "underwater hockey") - - val numIDs = 1000 - - //////// operations - - def pick[A](a: Array[A])(implicit rand: Random) = a(rand.nextInt(a.length)) - - def newName(id: Int)(implicit rand: Random) { - atomic { implicit txn => - val before = users.get(id).getOrElse(User(id, "John Doe", Set.empty)) - val after = before copy (name = pick(topBabyNames)) - users.put(id, after) - } - } - - def newLikes(id: Int)(implicit rand: Random) { - atomic { implicit txn => - val before = users.get(id).getOrElse(User(id, "John Doe", Set.empty)) - val after = before copy (likes = Set(pick(languages), pick(sports))) - users.put(id, after) - } - } - - def randomOp(implicit rand: Random) { - val pct = rand.nextInt(100) - if (pct < 10) { - // query by ID - users.get(rand.nextInt(numIDs)) - } else if (pct < 50) { - // query by name - byName(pick(topBabyNames)) - } else if (pct < 70) { - // query by sport - byLike(pick(sports)) - } else if (pct < 90) { - // query by language - byLike(pick(languages)) - } else if (pct < 95) { - newName(rand.nextInt(numIDs)) - } else { - newLikes(rand.nextInt(numIDs)) - } - } - - def populate() { - implicit val rand = new Random - for (id <- 0 until numIDs) { - newName(id) - newLikes(id) - } - } - - def run(numThreads: Int, opsPerThread: Int): Long = { - val threads = Array.tabulate(numThreads) { _ => - new Thread() { - override def run { - implicit val rand = new Random - for (i <- 0 until opsPerThread) randomOp - } - } - } - val begin = System.currentTimeMillis - for (t <- threads) t.start - for (t <- threads) t.join - System.currentTimeMillis - begin - } - - def main(args: Array[String]) { - populate() - - for (pass <- 0 until 3; tc <- List(1, 2, 4, 8)) { - val elapsed = run(tc, 1000000 / tc) - printf("%d thread: %4.2f usec/op total throughput (90%% read)\n", tc, elapsed * 0.001) - } - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/examples/RealityShowPhilosophers.scala b/benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/examples/RealityShowPhilosophers.scala deleted file mode 100644 index ddafb821..00000000 --- a/benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/examples/RealityShowPhilosophers.scala +++ /dev/null @@ -1,92 +0,0 @@ -/* scala-stm - (c) 2009-2011, Stanford University, PPL */ - -package scala.concurrent.stm -package examples - -import annotation.tailrec - -/** This extends a solution to the dining philosopher's problem to include an - * outside perspective that occasionally examines everything that is - * happening. - */ -object RealityShowPhilosophers { - - class Fork { - val owner = Ref(None : Option[String]) - } - - class PhilosopherThread(val name: String, val meals: Int, left: Fork, right: Fork) extends Thread { - val mealsEaten = Ref(0) - - override def run() { - for (m <- 0 until meals) { - // thinking - atomic { implicit txn => - if (!(left.owner().isEmpty && right.owner().isEmpty)) - retry - left.owner() = Some(name) - right.owner() = Some(name) - } - // eating - atomic { implicit txn => - mealsEaten += 1 - left.owner() = None - right.owner() = None - } - } - } - - def done = mealsEaten.single() == meals - - override def toString = { - "%s is %5.2f%% done".format(name, mealsEaten.single() * 100.0 / meals) - } - } - - class CameraThread(intervalMilli: Int, forks: Seq[Fork], philosophers: Seq[PhilosopherThread]) extends Thread { - - @tailrec final override def run() { - Thread.sleep(intervalMilli) - val (str, done) = image - println(str) - if (!done) - run() - } - - /** We want to print exactly one image of the final state, so we check - * completion at the same time as building the image. - */ - def image: (String, Boolean) = atomic { implicit txn => - val buf = new StringBuilder - for (i <- 0 until forks.length) - buf ++= "fork %d is owned by %s\n".format(i, forks(i).owner.single()) - var done = true - for (p <- philosophers) { - buf ++= p.toString += '\n' - done &&= p.done - } - (buf.toString, done) - } - } - - def time(names: Seq[String], meals: Int): Long = { - val forks = Array.tabulate(names.size) { _ => new Fork } - val pthreads = Array.tabulate(names.size) { i => new PhilosopherThread(names(i), meals, forks(i), forks((i + 1) % forks.length)) } - val camera = new CameraThread(1000 / 60, forks, pthreads) - val start = System.currentTimeMillis - camera.start() - for (t <- pthreads) t.start() - for (t <- pthreads) t.join() - val elapsed = System.currentTimeMillis - start - camera.join() - elapsed - } - - def main(args: Array[String]) { - val meals = 100000 - for (p <- 0 until 3) { - val elapsed = time(List("Aristotle", "Hippocrates", "Plato", "Pythagoras", "Socrates"), meals) - printf("%3.1f usec/meal\n", (elapsed * 1000.0) / meals) - } - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/examples/SyntaxCheatSheet.scala b/benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/examples/SyntaxCheatSheet.scala deleted file mode 100644 index a82a618d..00000000 --- a/benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/examples/SyntaxCheatSheet.scala +++ /dev/null @@ -1,39 +0,0 @@ -/* scala-stm - (c) 2009-2010, Stanford University, PPL */ - -package scala.concurrent.stm.examples - -object SyntaxCheatSheet { - import scala.concurrent.stm._ - - val x = Ref(0) // allocate a Ref[Int] - val y = Ref.make[String]() // type-specific default - val z = x.single // Ref.View[Int] - - atomic { implicit txn => - val i = x() // read - y() = "x was " + i // write - val eq = atomic { implicit txn => // nested atomic - x() == z() // both Ref and Ref.View can be used inside atomic - } - assert(eq) - y.set(y.get + ", long-form access") - } - - // only Ref.View can be used outside atomic - println("y was '" + y.single() + "'") - println("z was " + z()) - - atomic { implicit txn => - y() = y() + ", first alternative" - if (x getWith { _ > 0 }) // read via a function - retry // try alternatives or block - } orAtomic { implicit txn => - y() = y() + ", second alternative" - } - - val prev = z.swap(10) // atomic swap - val success = z.compareAndSet(10, 11) // atomic compare-and-set - z.transform { _ max 20 } // atomic transformation - val pre = y.single.getAndTransform { _.toUpperCase } - val post = y.single.transformAndGet { _.filterNot { _ == ' ' } } -} diff --git a/benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/impl/RefFactorySuite.scala b/benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/impl/RefFactorySuite.scala deleted file mode 100644 index 78ac392f..00000000 --- a/benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/impl/RefFactorySuite.scala +++ /dev/null @@ -1,145 +0,0 @@ -/* scala-stm - (c) 2009-2010, Stanford University, PPL */ - -package scala.concurrent.stm -package impl - -import org.scalatest.FunSuite -import java.lang.String - -class RefFactorySuite extends FunSuite { - - private case class Fact(expected: String) extends skel.StubSTMImpl with RefFactory { - - private def called(w: String) = { - assert(w === expected) - null - } - - override def newRef(v0: Boolean): Ref[Boolean] = called("Boolean") - override def newRef(v0: Byte): Ref[Byte] = called("Byte") - override def newRef(v0: Short): Ref[Short] = called("Short") - override def newRef(v0: Char): Ref[Char] = called("Char") - override def newRef(v0: Int): Ref[Int] = called("Int") - override def newRef(v0: Float): Ref[Float] = called("Float") - override def newRef(v0: Long): Ref[Long] = called("Long") - override def newRef(v0: Double): Ref[Double] = called("Double") - override def newRef(v0: Unit): Ref[Unit] = called("Unit") - override def newRef[T](v0: T)(implicit m: ClassManifest[T]): Ref[T] = called("Any") - } - - object TestRef extends RefCompanion { - var factory: RefFactory = null - } - - test("signature specialization") { - TestRef.factory = Fact("Boolean") - TestRef(false) - - TestRef.factory = Fact("Byte") - TestRef(0 : Byte) - - TestRef.factory = Fact("Short") - TestRef(0 : Short) - - TestRef.factory = Fact("Char") - TestRef(0 : Char) - - TestRef.factory = Fact("Int") - TestRef(0 : Int) - - TestRef.factory = Fact("Float") - TestRef(0 : Float) - - TestRef.factory = Fact("Long") - TestRef(0 : Long) - - TestRef.factory = Fact("Double") - TestRef(0 : Double) - - TestRef.factory = Fact("Unit") - TestRef(()) - - TestRef.factory = Fact("Any") - TestRef("abc") - TestRef(null) - TestRef(0.asInstanceOf[AnyRef]) - val x: Any = 0 - TestRef(x) - } - - test("missing manifest TestRef.apply") { - TestRef.factory = Fact("Any") - - def go[T](x: T) = TestRef(x) - - go(123) - go(1.23) - go(null) - go("abc") - } - - test("dynamic specialization") { - def go[T : ClassManifest](v0: T, which: String) { - TestRef.factory = Fact(which) - TestRef(v0) - } - - go(false, "Boolean") - go(0 : Byte, "Byte") - go(0 : Short, "Short") - go(0 : Char, "Char") - go(0 : Int, "Int") - go(0 : Float, "Float") - go(0 : Long, "Long") - go(0 : Double, "Double") - go((), "Unit") - go("abc", "Any") - go(null, "Any") - go(0.asInstanceOf[AnyRef], "Any") - val x: Any = 0 - go(x, "Any") - } - - test("default value specialization") { - def go[T : ClassManifest](default: T, which: String) { - TestRef.factory = Fact(which) - TestRef.make[T]() - //assert(x.single() == default) - } - - go(false, "Boolean") - go(0 : Byte, "Byte") - go(0 : Short, "Short") - go(0 : Char, "Char") - go(0 : Int, "Int") - go(0 : Float, "Float") - go(0 : Long, "Long") - go(0 : Double, "Double") - go((), "Unit") - go[String](null, "Any") - go[AnyRef](null, "Any") - go[Null](null, "Any") - go[Any](null, "Any") - } - - test("missing manifest TestRef.make") { - TestRef.factory = Fact("Any") - - def go[T]() = TestRef.make[T]() - - go[Boolean]() - go[Byte]() - go[Short]() - go[Char]() - go[Int]() - go[Float]() - go[Long]() - go[Double]() - go[Unit]() - go[String]() - go[AnyRef]() - go[Null]() - go[Any]() - } - -} diff --git a/benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/skel/AtomicArraySuite.scala b/benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/skel/AtomicArraySuite.scala deleted file mode 100644 index 130e4f09..00000000 --- a/benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/skel/AtomicArraySuite.scala +++ /dev/null @@ -1,133 +0,0 @@ -/* scala-stm - (c) 2009-2014, Stanford University, PPL */ - -package scala.concurrent.stm -package skel - -import org.scalatest.FunSuite - -class AtomicArraySuite extends FunSuite { - - test("Unit") { - runIsolatedTest(List((), (), ())) - } - - test("Boolean") { - runIsolatedTest(List(false, true, false, true)) - } - - test("Byte") { - runIsolatedTest(Array(0 : Byte, 1 : Byte, 2 : Byte)) - } - - test("Short") { - runIsolatedTest(List(0 : Short, 1 : Short, 2 : Short)) - } - - test("Char") { - runIsolatedTest("abcdefg".toSeq) - } - - test("Int") { - runIsolatedTest(100 until 200) - } - - test("Float") { - runIsolatedTest((20 to 30) map { _ * 0.1f }) - } - - test("Long") { - runIsolatedTest((100 until 200) map { _ - 100L * Int.MaxValue }) - } - - test("Double") { - runIsolatedTest((10 until 20) map { math.exp(_) }) - } - - test("AnyRef") { - runIsolatedTest((10 until 20) map { i => ("x" + i) : AnyRef }) - } - - test("Any") { - runIsolatedTest[Any]((10 until 20) map { i => i : Any }) - } - - def runIsolatedTest[A](values: Seq[A])(implicit am: ClassManifest[A]) { - val singleton = AtomicArray[A](1) - if (am != implicitly[ClassManifest[Unit]]) - assert(singleton(0) === am.newArray(1)(0)) - - val aa = AtomicArray(values) - for (i <- 0 until aa.length) - assert(values(i) === aa(i)) - for (i <- 0 until aa.length) - aa(i) = values(aa.length - 1 - i) - for (i <- 0 until aa.length) - assert(aa(i) === values(aa.length - 1 - i)) - for (i <- 0 until aa.length) { - if (aa(i) == values(0)) { - assert(aa.compareAndSet(i, values(0), values(i))) - assert(aa(i) === values(i)) - } else { - assert(!aa.compareAndSet(i, values(0), values(i))) - assert(aa(i) === values(aa.length - 1 - i)) - } - } - for (i <- 0 until aa.length) - assert(aa(i) === aa.getAndTransform(i)( v => v )) - for (i <- 0 until aa.length) { - val prev = aa(i) - assert(aa.swap(i, values(i)) === prev) - } - - intercept[IndexOutOfBoundsException] { - aa(-1) - } - intercept[IndexOutOfBoundsException] { - aa(-1) = aa(0) - } - intercept[IndexOutOfBoundsException] { - aa(aa.length) - } - intercept[IndexOutOfBoundsException] { - aa(aa.length) = aa(0) - } - intercept[IndexOutOfBoundsException] { - aa.compareAndSet(-1, aa(0), aa(0)) - } - intercept[IndexOutOfBoundsException] { - aa.compareAndSet(aa.length, aa(0), aa(0)) - } - intercept[IndexOutOfBoundsException] { - aa(Int.MinValue) - } - intercept[IndexOutOfBoundsException] { - aa(Int.MaxValue) - } - - val copy = aa.clone - for (i <- 0 until aa.length) - assert(copy(i) === aa(i)) - - val str0 = aa map { _.toString } - val str: AtomicArray[String] = str0 - for (i <- 0 until aa.length) - assert(aa(i).toString === str(i)) - - val seq0 = aa.toList - for (i <- 0 until aa.length) - assert(aa(i) == seq0(i)) - - val seq1 = aa.iterator.toList - for (i <- 0 until aa.length) - assert(aa(i) == seq1(i)) - - val bb = aa ++ seq0 - assert(bb.length === aa.length * 2) - for (i <- 0 until aa.length) { - assert(aa(i) === bb(i)) - assert(aa(i) === bb(i + aa.length)) - } - - assert(aa.toString.startsWith("AtomicArray")) - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/skel/SimpleRandomSuite.scala b/benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/skel/SimpleRandomSuite.scala deleted file mode 100644 index 91ceb5af..00000000 --- a/benchmarks/scala-stm/scala-stm-library/src/test/scala/scala/concurrent/stm/skel/SimpleRandomSuite.scala +++ /dev/null @@ -1,65 +0,0 @@ -/* scala-stm - (c) 2009-2011, Stanford University, PPL */ - -package scala.concurrent.stm -package skel - -import org.scalatest.FunSuite - -class SimpleRandomSuite extends FunSuite { - - test("nextInt") { - val f = new SimpleRandom - val rand = new scala.util.Random - var s = 0 - for (i <- 0 until 100000) { - s |= SimpleRandom.nextInt - s |= f.nextInt - } - assert(s != 0) - } - - test("nextInt(n) in range") { - val f = new SimpleRandom - val rand = new scala.util.Random - for (i <- 0 until 100000) { - val n = rand.nextInt(Int.MaxValue - 1) + 1 - val gr = SimpleRandom.nextInt(n) - assert(gr >= 0 && gr < n) - val lr = f.nextInt(n) - assert(lr >= 0 && lr < n) - } - } - - test("clone") { - val f1 = new SimpleRandom - for (i <- 0 until 1000) - f1.nextInt - val f2 = f1.clone - for (i <- 0 until 1000) - assert(f1.nextInt(9999) === f2.nextInt(9999)) - } - - test("seeded") { - val f1 = new SimpleRandom(100) - val f2 = new SimpleRandom(100) - for (i <- 0 until 1000) - assert(f1.nextInt === f2.nextInt) - } - - test("global SimpleRandom distribution") { - val buckets = new Array[Int](100) - for (i <- 0 until 100000) - buckets(SimpleRandom.nextInt(buckets.length)) += 1 - for (b <- buckets) - assert(b > 0) - } - - test("local SimpleRandom distribution") { - val f = new SimpleRandom - val buckets = new Array[Int](100) - for (i <- 0 until 100000) - buckets(f.nextInt(buckets.length)) += 1 - for (b <- buckets) - assert(b > 0) - } -} \ No newline at end of file diff --git a/benchmarks/scala-stm/scala-stm-library/src/test/scala/stmbench7/scalastm/AssemblyImpl.scala b/benchmarks/scala-stm/scala-stm-library/src/test/scala/stmbench7/scalastm/AssemblyImpl.scala deleted file mode 100644 index d790edd4..00000000 --- a/benchmarks/scala-stm/scala-stm-library/src/test/scala/stmbench7/scalastm/AssemblyImpl.scala +++ /dev/null @@ -1,21 +0,0 @@ -/* scala-stm - (c) 2009-2011, Stanford University, PPL */ - -package stmbench7.scalastm - -import scala.concurrent.stm._ -import stmbench7.core._ - -abstract class AssemblyImpl(id: Int, typ: String, buildDate: Int, module0: Module, superAssembly0: ComplexAssembly - ) extends DesignObjImpl(id, typ, buildDate) with Assembly { - - private val module = Ref(module0).single - private val superAssembly = Ref(superAssembly0).single - - def getSuperAssembly = superAssembly() - def getModule = module() - - def clearPointers() { - superAssembly() = null - module() = null - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/src/test/scala/stmbench7/scalastm/AtomicPartImpl.scala b/benchmarks/scala-stm/scala-stm-library/src/test/scala/stmbench7/scalastm/AtomicPartImpl.scala deleted file mode 100644 index 24fa8cc5..00000000 --- a/benchmarks/scala-stm/scala-stm-library/src/test/scala/stmbench7/scalastm/AtomicPartImpl.scala +++ /dev/null @@ -1,46 +0,0 @@ -/* scala-stm - (c) 2009-2011, Stanford University, PPL */ - -package stmbench7.scalastm - -import scala.concurrent.stm._ -import stmbench7.core._ -import stmbench7.impl.core.ConnectionImpl - -class AtomicPartImpl(id0: Int, typ0: String, bd0: Int, x0: Int, y0: Int) extends DesignObjImpl(id0, typ0, bd0) with AtomicPart { - val x = Ref(x0) - val y = Ref(y0) - val partOf = Ref(null : CompositePart).single - val from = TSet.empty[Connection].single // this is the equivant of SmallSetImpl - val to = TSet.empty[Connection].single - - def connectTo(dest: AtomicPart, typ: String, length: Int) { - val c = new ConnectionImpl(this, dest, typ, length) - to += c - dest.addConnectionFromOtherPart(c.getReversed) - } - def addConnectionFromOtherPart(c: Connection) { from += c } - def setCompositePart(po: CompositePart) { partOf() = po } - def getNumToConnections = to.size - def getToConnections = new ImmutableSetImpl[Connection](to) - def getFromConnections = new ImmutableSetImpl[Connection](from) - def getPartOf = partOf() - def swapXY() { - atomic { implicit t => - y() = x.swap(y()) - } - } - def getX = x.single() - def getY = y.single() - def clearPointers() { - atomic { implicit t => - x() = 0 - y() = 0 - to.clear() - from.clear() - partOf() = null - } - } - - // Comparable[AtomicPart] - def compareTo(rhs: AtomicPart) = getId - rhs.getId // subtraction is faithful to reference impl -} diff --git a/benchmarks/scala-stm/scala-stm-library/src/test/scala/stmbench7/scalastm/BaseAssemblyImpl.scala b/benchmarks/scala-stm/scala-stm-library/src/test/scala/stmbench7/scalastm/BaseAssemblyImpl.scala deleted file mode 100644 index 09330be6..00000000 --- a/benchmarks/scala-stm/scala-stm-library/src/test/scala/stmbench7/scalastm/BaseAssemblyImpl.scala +++ /dev/null @@ -1,32 +0,0 @@ -/* scala-stm - (c) 2009-2011, Stanford University, PPL */ - -package stmbench7.scalastm - -import scala.concurrent.stm._ -import stmbench7.core._ - -class BaseAssemblyImpl(id: Int, typ: String, buildDate: Int, module: Module, superAssembly: ComplexAssembly - ) extends AssemblyImpl(id, typ, buildDate, module, superAssembly) with BaseAssembly { - - val components = Ref(List.empty[CompositePart]).single // the original BagImpl was just an ArrayList - - def addComponent(component: CompositePart) { - components.transform(component :: _) - component.addAssembly(this) - } - - def removeComponent(component: CompositePart) = { - val f = components transformIfDefined { - case x if x contains component => x filterNot { _ == component } - } - if (f) component.removeAssembly(this) - f - } - - def getComponents = new ImmutableSeqImpl[CompositePart](components()) - - override def clearPointers() { - super.clearPointers() - components() = null - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/src/test/scala/stmbench7/scalastm/ComplexAssemblyImpl.scala b/benchmarks/scala-stm/scala-stm-library/src/test/scala/stmbench7/scalastm/ComplexAssemblyImpl.scala deleted file mode 100644 index ce6834eb..00000000 --- a/benchmarks/scala-stm/scala-stm-library/src/test/scala/stmbench7/scalastm/ComplexAssemblyImpl.scala +++ /dev/null @@ -1,32 +0,0 @@ -/* scala-stm - (c) 2009-2011, Stanford University, PPL */ - -package stmbench7.scalastm - -import scala.concurrent.stm._ -import stmbench7.core._ -import stmbench7.Parameters - -class ComplexAssemblyImpl(id: Int, typ: String, buildDate: Int, module: Module, superAssembly: ComplexAssembly - ) extends AssemblyImpl(id, typ, buildDate, module, superAssembly) with ComplexAssembly { - - val subAssemblies = TSet.empty[Assembly].single - val level = if (superAssembly == null) Parameters.NumAssmLevels else superAssembly.getLevel - 1 - - def addSubAssembly(assembly: Assembly) = { - if(assembly.isInstanceOf[BaseAssembly] && level != 2) - throw new RuntimeError("ComplexAssembly.addAssembly: BaseAssembly at wrong level!"); - - subAssemblies.add(assembly) - } - - def removeSubAssembly(assembly: Assembly) = subAssemblies.remove(assembly) - - def getSubAssemblies = new ImmutableSetImpl[Assembly](subAssemblies) - - def getLevel = level.asInstanceOf[Short] - - override def clearPointers() { - super.clearPointers() - subAssemblies.clear() - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/src/test/scala/stmbench7/scalastm/CompositePartImpl.scala b/benchmarks/scala-stm/scala-stm-library/src/test/scala/stmbench7/scalastm/CompositePartImpl.scala deleted file mode 100644 index 9ee21881..00000000 --- a/benchmarks/scala-stm/scala-stm-library/src/test/scala/stmbench7/scalastm/CompositePartImpl.scala +++ /dev/null @@ -1,47 +0,0 @@ -/* scala-stm - (c) 2009-2011, Stanford University, PPL */ - -package stmbench7.scalastm - -import scala.concurrent.stm._ -import stmbench7.core._ -import stmbench7.backend.BackendFactory - -class CompositePartImpl(id: Int, typ: String, buildDate: Int, documentation0: Document - ) extends DesignObjImpl(id, typ, buildDate) with CompositePart { - val documentation = Ref(documentation0).single - val usedIn = Ref(List.empty[BaseAssembly]).single - val parts = Ref(BackendFactory.instance.createLargeSet[AtomicPart]).single - val rootPart = Ref(null : AtomicPart).single - documentation0.setPart(this) - - def addAssembly(assembly: BaseAssembly) { usedIn.transform(assembly :: _) } - - def addPart(part: AtomicPart) = { - val f = parts().add(part) - if (f) { - part.setCompositePart(this) - if(rootPart() == null) rootPart() = part - } - f - } - - def getRootPart = rootPart() - def setRootPart(part: AtomicPart) { rootPart() = part } - - def getDocumentation = documentation() - - def getParts = parts() - - def removeAssembly(assembly: BaseAssembly ) { - usedIn.transform { _.filterNot(_ == assembly) } - } - - def getUsedIn = new ImmutableSeqImpl[BaseAssembly](usedIn()) - - def clearPointers() { - documentation() = null - parts() = null - usedIn() = null - rootPart() = null - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/src/test/scala/stmbench7/scalastm/DesignObjImpl.scala b/benchmarks/scala-stm/scala-stm-library/src/test/scala/stmbench7/scalastm/DesignObjImpl.scala deleted file mode 100644 index a8aff59c..00000000 --- a/benchmarks/scala-stm/scala-stm-library/src/test/scala/stmbench7/scalastm/DesignObjImpl.scala +++ /dev/null @@ -1,16 +0,0 @@ -/* scala-stm - (c) 2009-2011, Stanford University, PPL */ - -package stmbench7.scalastm - -import scala.concurrent.stm._ -import stmbench7.core._ - -class DesignObjImpl(id: Int, typ: String, buildDate0: Int) extends DesignObj { - val bd = Ref(buildDate0).single - - def getId = id - def getType = typ - def getBuildDate = bd() - def updateBuildDate() { if (bd() % 2 == 0) bd -= 1 else bd += 1 } - def nullOperation() {} -} diff --git a/benchmarks/scala-stm/scala-stm-library/src/test/scala/stmbench7/scalastm/DocumentImpl.scala b/benchmarks/scala-stm/scala-stm-library/src/test/scala/stmbench7/scalastm/DocumentImpl.scala deleted file mode 100644 index 9325f3ee..00000000 --- a/benchmarks/scala-stm/scala-stm-library/src/test/scala/stmbench7/scalastm/DocumentImpl.scala +++ /dev/null @@ -1,34 +0,0 @@ -/* scala-stm - (c) 2009-2011, Stanford University, PPL */ - -package stmbench7.scalastm - -import scala.annotation.tailrec -import scala.concurrent.stm._ -import stmbench7.core._ - -class DocumentImpl(id: Int, title: String, text0: String) extends Document { - val text = Ref(text0).single - val part = Ref(null : CompositePart).single - - def getDocumentId = id - def getTitle = title - - def getCompositePart = part() - def setPart(v: CompositePart) { part() = v } - - def nullOperation() {} - - def getText = text() - def searchText(symbol: Char): Int = searchText(text(), symbol, 0, 0) - @tailrec private def searchText(s: String, c: Char, pos: Int, n: Int): Int = { - val i = s.indexOf(c, pos) - if (i < 0) n else searchText(s, c, i + 1, n + 1) - } - def replaceText(from: String, to: String) = { - val f = text transformIfDefined { - case s if s.startsWith(from) => s.replaceFirst(from, to) - } - if (f) 1 else 0 - } - def textBeginsWith(prefix: String) = text().startsWith(prefix) -} diff --git a/benchmarks/scala-stm/scala-stm-library/src/test/scala/stmbench7/scalastm/IdPoolImpl.scala b/benchmarks/scala-stm/scala-stm-library/src/test/scala/stmbench7/scalastm/IdPoolImpl.scala deleted file mode 100644 index c1e43b03..00000000 --- a/benchmarks/scala-stm/scala-stm-library/src/test/scala/stmbench7/scalastm/IdPoolImpl.scala +++ /dev/null @@ -1,22 +0,0 @@ -/* scala-stm - (c) 2009-2011, Stanford University, PPL */ - -package stmbench7.scalastm - -import scala.concurrent.stm._ -import stmbench7.core._ -import stmbench7.backend.IdPool - -object IdPoolImpl { - class BoxedList(n: Int) extends IdPool { - val underlying = Ref(List.range(1, n + 1)).single - - def putUnusedId(id: Int) { underlying.transform(id :: _) } - - def getId = { - underlying.getAndTransform(_.drop(1)) match { - case head :: _ => head - case _ => throw new OperationFailedException - } - } - } -} \ No newline at end of file diff --git a/benchmarks/scala-stm/scala-stm-library/src/test/scala/stmbench7/scalastm/ImmutableSeqImpl.scala b/benchmarks/scala-stm/scala-stm-library/src/test/scala/stmbench7/scalastm/ImmutableSeqImpl.scala deleted file mode 100644 index e9f4e1a4..00000000 --- a/benchmarks/scala-stm/scala-stm-library/src/test/scala/stmbench7/scalastm/ImmutableSeqImpl.scala +++ /dev/null @@ -1,13 +0,0 @@ -/* scala-stm - (c) 2009-2012, Stanford University, PPL */ - -package stmbench7.scalastm - -import scala.collection.JavaConversions -import stmbench7.backend.ImmutableCollection - -class ImmutableSeqImpl[A](contents: Seq[A]) extends ImmutableCollection[A] { - override def clone = this - def contains(element: A) = contents.contains(element) - def size = contents.size - def iterator = JavaConversions.asJavaIterator(contents.iterator) -} diff --git a/benchmarks/scala-stm/scala-stm-library/src/test/scala/stmbench7/scalastm/ImmutableSetImpl.scala b/benchmarks/scala-stm/scala-stm-library/src/test/scala/stmbench7/scalastm/ImmutableSetImpl.scala deleted file mode 100644 index 8cd68cfd..00000000 --- a/benchmarks/scala-stm/scala-stm-library/src/test/scala/stmbench7/scalastm/ImmutableSetImpl.scala +++ /dev/null @@ -1,15 +0,0 @@ -/* scala-stm - (c) 2009-2012, Stanford University, PPL */ - -package stmbench7.scalastm - -import scala.collection.JavaConversions -import scala.concurrent.stm._ -import stmbench7.backend.ImmutableCollection - -/** Read-only wrapper */ -class ImmutableSetImpl[A](contents: TSet.View[A], shared: Boolean = true) extends ImmutableCollection[A] { - override def clone: ImmutableSetImpl[A] = if (!shared) this else new ImmutableSetImpl(contents.clone(), false) - def contains(element: A) = contents.contains(element) - def size = contents.size - def iterator = JavaConversions.asJavaIterator(contents.iterator) -} diff --git a/benchmarks/scala-stm/scala-stm-library/src/test/scala/stmbench7/scalastm/IndexImpl.scala b/benchmarks/scala-stm/scala-stm-library/src/test/scala/stmbench7/scalastm/IndexImpl.scala deleted file mode 100644 index 3efd4b08..00000000 --- a/benchmarks/scala-stm/scala-stm-library/src/test/scala/stmbench7/scalastm/IndexImpl.scala +++ /dev/null @@ -1,46 +0,0 @@ -/* scala-stm - (c) 2009-2012, Stanford University, PPL */ - -package stmbench7.scalastm - -import scala.annotation._ -import scala.collection.immutable.TreeMap -import scala.collection.mutable.ArrayBuffer -import scala.collection.JavaConversions -import scala.concurrent.stm._ -import stmbench7.backend.Index - -object IndexImpl { - class BoxedImmutable[A <: Comparable[A], B] extends Index[A,B] { - // needed for 2.8, harmless in 2.9 - implicit val order = new Ordering[A] { - def compare(lhs: A, rhs: A) = lhs compareTo rhs - } - - val underlying = Ref(TreeMap.empty[A,B]).single - - def get(key: A) = underlying().getOrElse(key, null.asInstanceOf[B]) - - def put(key: A, value: B) { underlying.transform(_ + (key -> value)) } - - def putIfAbsent(key: A, value: B): B = { - underlying.getAndTransform({ m => if (m.contains(key)) m else m + (key -> value) }).getOrElse(key, null.asInstanceOf[B]) - } - - def remove(key: A) = underlying transformIfDefined { - case m if m.contains(key) => m - key - } - - def iterator = makeValuesIterator(underlying()) - - def getKeys = JavaConversions.setAsJavaSet(underlying().keySet) - - def getRange(minKey: A, maxKey: A) = new java.lang.Iterable[B] { - val range = underlying().range(minKey, maxKey) - def iterator = makeValuesIterator(range) - } - - private def makeValuesIterator(m: TreeMap[A, B]) = { - JavaConversions.asJavaIterator(m.values.iterator) - } - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/src/test/scala/stmbench7/scalastm/LargeSetImpl.scala b/benchmarks/scala-stm/scala-stm-library/src/test/scala/stmbench7/scalastm/LargeSetImpl.scala deleted file mode 100644 index 56bb62f7..00000000 --- a/benchmarks/scala-stm/scala-stm-library/src/test/scala/stmbench7/scalastm/LargeSetImpl.scala +++ /dev/null @@ -1,19 +0,0 @@ -/* scala-stm - (c) 2009-2012, Stanford University, PPL */ - -package stmbench7.scalastm - -import scala.collection.JavaConversions -import scala.concurrent.stm._ -import stmbench7.backend.LargeSet - -// LargeSetImpl - -class LargeSetImpl[A <: Comparable[A]] extends LargeSet[A] { - val underlying = TMap.empty[A,Unit].single - - def add(e: A) = underlying.put(e, ()).isEmpty - def remove(e: A) = !underlying.remove(e).isEmpty - def contains(e: A) = underlying.contains(e) - def size = underlying.size - def iterator = JavaConversions.asJavaIterator(underlying.keysIterator) -} diff --git a/benchmarks/scala-stm/scala-stm-library/src/test/scala/stmbench7/scalastm/ManualImpl.scala b/benchmarks/scala-stm/scala-stm-library/src/test/scala/stmbench7/scalastm/ManualImpl.scala deleted file mode 100644 index 3edbbdab..00000000 --- a/benchmarks/scala-stm/scala-stm-library/src/test/scala/stmbench7/scalastm/ManualImpl.scala +++ /dev/null @@ -1,40 +0,0 @@ -/* scala-stm - (c) 2009-2011, Stanford University, PPL */ - -package stmbench7.scalastm - -import scala.concurrent.stm._ -import scala.collection.immutable.WrappedString -import scala.annotation.tailrec -import stmbench7.core._ - -class ManualImpl(id: Int, title0: String, text0: String) extends Manual { - val title = Ref(title0).single - val text = Ref(text0).single - val module = Ref(null : Module).single - - def getId = id - def getTitle = title() - def getText = text() - def getModule = module() - - def setModule(v: Module) { module() = v } - - def countOccurences(ch: Char): Int = countOccurrences(ch) - def countOccurrences(ch: Char): Int = countOccurrences(text(), ch, 0, 0) - @tailrec private def countOccurrences(s: String, c: Char, pos: Int, n: Int): Int = { - val i = s.indexOf(c, pos) - if (i < 0) n else countOccurrences(s, c, i + 1, n + 1) - } - - def checkFirstLastCharTheSame = { - val t = text() - if (t.charAt(0) == t.charAt(t.length - 1)) 1 else 0 - } - - def startsWith(ch: Char) = text().charAt(0) == ch - - def replaceChar(from: Char, to: Char) = { - text.transform(_.replace(from, to)) - countOccurences(to) - } -} diff --git a/benchmarks/scala-stm/scala-stm-library/src/test/scala/stmbench7/scalastm/ModuleImpl.scala b/benchmarks/scala-stm/scala-stm-library/src/test/scala/stmbench7/scalastm/ModuleImpl.scala deleted file mode 100644 index 7ccac29c..00000000 --- a/benchmarks/scala-stm/scala-stm-library/src/test/scala/stmbench7/scalastm/ModuleImpl.scala +++ /dev/null @@ -1,18 +0,0 @@ -/* scala-stm - (c) 2009-2011, Stanford University, PPL */ - -package stmbench7.scalastm - -import scala.concurrent.stm._ -import stmbench7.core._ - -class ModuleImpl(id: Int, typ: String, buildDate: Int, man: Manual - ) extends DesignObjImpl(id, typ, buildDate) with Module { - - val designRoot = Ref(null : ComplexAssembly).single - - man.setModule(this) - - def setDesignRoot(v: ComplexAssembly ) { designRoot() = v } - def getDesignRoot = designRoot() - def getManual = man -} diff --git a/benchmarks/scala-stm/scala-stm-library/src/test/scala/stmbench7/scalastm/ScalaSTMInitializer.scala b/benchmarks/scala-stm/scala-stm-library/src/test/scala/stmbench7/scalastm/ScalaSTMInitializer.scala deleted file mode 100644 index aea0a5c5..00000000 --- a/benchmarks/scala-stm/scala-stm-library/src/test/scala/stmbench7/scalastm/ScalaSTMInitializer.scala +++ /dev/null @@ -1,76 +0,0 @@ -/* scala-stm - (c) 2009-2011, Stanford University, PPL */ - -package stmbench7.scalastm - -import scala.concurrent.stm._ -import stmbench7.backend._ -import stmbench7.core._ -import stmbench7.impl.core.ConnectionImpl -import stmbench7._ - -class ScalaSTMInitializer extends SynchMethodInitializer { - def createOperationExecutorFactory() = new OperationExecutorFactory { - - val timestamp = Ref(0) - - def createOperationExecutor(op: Operation) = new OperationExecutor { - var lastTS = 0 - - def execute(): Int = { - atomic { implicit t => - val z = op.performOperation() - if (Parameters.sequentialReplayEnabled) { - timestamp += 1 - lastTS = timestamp() - } - z - } - } - - def getLastOperationTimestamp = lastTS - } - } - - def createBackendFactory() = new BackendFactory { - - // a couple hundred, not ordered, except for huge numbers of discarded - // sets with exactly 1 element - def createLargeSet[E <: Comparable[E]](): LargeSet[E] = new LargeSetImpl[E] - - // ordered - def createIndex[K <: Comparable[K],V](): Index[K,V] = new IndexImpl.BoxedImmutable[K,V] - - def createIdPool(maxNumberOfIds: Int): IdPool = new IdPoolImpl.BoxedList(maxNumberOfIds) - } - - def createDesignObjFactory() = new DesignObjFactory { - - def createAtomicPart(id: Int, typ: String, bd: Int, x: Int, y: Int) = - new AtomicPartImpl(id, typ, bd, x, y) - - def createConnection(from: AtomicPart, to: AtomicPart, typ: String, length: Int) = - new ConnectionImpl(from, to, typ, length) - - def createBaseAssembly(id: Int, typ: String, buildDate: Int, module: Module, superAssembly: ComplexAssembly) = - new BaseAssemblyImpl(id, typ, buildDate, module, superAssembly) - - def createComplexAssembly(id: Int, typ: String, buildDate: Int, module: Module, superAssembly: ComplexAssembly) = - new ComplexAssemblyImpl(id, typ, buildDate, module, superAssembly) - - def createCompositePart(id: Int, typ: String, buildDate: Int, documentation: Document) = - new CompositePartImpl(id, typ, buildDate, documentation) - - def createDocument(id: Int, title: String, text: String) = - new DocumentImpl(id, title, text) - - def createManual(id: Int, title: String, text: String) = - new ManualImpl(id, title, text) - - def createModule(id: Int, typ: String, buildDate: Int, man: Manual) = - new ModuleImpl(id, typ, buildDate, man) - } - - def createThreadFactory() = new stmbench7.ThreadFactory { - def createThread(body: Runnable) = new Thread(body) - } -} \ No newline at end of file From 2dd2d2238672a083fa59ccaaa05c0109a5aab958 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lubom=C3=ADr=20Bulej?= Date: Fri, 24 May 2024 16:05:16 +0200 Subject: [PATCH 8/9] Depend on external scala-stm and a slightly modified stmbench7 This will allow updating the benchmarks to use Scala 2.13+ --- build.sbt | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/build.sbt b/build.sbt index 1a025309..571aad67 100644 --- a/build.sbt +++ b/build.sbt @@ -450,13 +450,14 @@ lazy val scalaStdlibBenchmarks = (project in file("benchmarks/scala-stdlib")) lazy val scalaStmBenchmarks = (project in file("benchmarks/scala-stm")) .settings( name := "scala-stm", - commonSettingsScala212 + commonSettingsScala212, + libraryDependencies := Seq( + "org.scala-stm" %% "scala-stm" % "0.8" + ) ) .dependsOn( renaissanceCore % "provided", - RootProject( - uri("benchmarks/scala-stm/scala-stm-library") - ) % "compile->compile;compile->test" + RootProject(uri("benchmarks/scala-stm/stmbench7")) ) val finagleVersion = "22.12.0" From 7ef5424a6b4c468de78eb5da9305ef73129f309c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lubom=C3=ADr=20Bulej?= Date: Sun, 26 May 2024 17:18:27 +0200 Subject: [PATCH 9/9] Bump scala-stm to version 0.11.1 --- build.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.sbt b/build.sbt index 571aad67..ac183ea6 100644 --- a/build.sbt +++ b/build.sbt @@ -452,7 +452,7 @@ lazy val scalaStmBenchmarks = (project in file("benchmarks/scala-stm")) name := "scala-stm", commonSettingsScala212, libraryDependencies := Seq( - "org.scala-stm" %% "scala-stm" % "0.8" + "org.scala-stm" %% "scala-stm" % "0.11.1" ) ) .dependsOn(