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 99124e90..00000000 Binary files a/benchmarks/scala-stm/scala-stm-library/lib/deuceAgent-1.3.0.jar and /dev/null differ 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/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/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 39874f71..00000000 Binary files a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/stmbench7-VELOX-1.2.tgz and /dev/null differ 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 9d9c2eec..00000000 Binary files a/benchmarks/scala-stm/scala-stm-library/lib/stmbench7-VELOX-1.2.jar and /dev/null differ 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/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 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..edae77b8 --- /dev/null +++ b/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/AssemblyImpl.scala @@ -0,0 +1,30 @@ +/* scala-stm - (c) 2009-2011, Stanford University, PPL */ + +package stmbench7.scalastm + +import scala.concurrent.stm.Ref + +import stmbench7.core.Assembly +import stmbench7.core.ComplexAssembly +import stmbench7.core.Module + +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 + + override def getSuperAssembly: ComplexAssembly = superAssembly() + override def getModule: Module = module() + + 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 new file mode 100644 index 00000000..bd5f5480 --- /dev/null +++ b/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/AtomicPartImpl.scala @@ -0,0 +1,58 @@ +/* scala-stm - (c) 2009-2011, Stanford University, PPL */ + +package stmbench7.scalastm + +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 { + + 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) + } + + 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()) + } + } + override def getX: Int = x.single() + override def getY: Int = y.single() + + override def clearPointers(): Unit = { + atomic { implicit t => + x() = 0 + y() = 0 + to.clear() + from.clear() + partOf() = null + } + } + + // Comparable[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 new file mode 100644 index 00000000..850e542d --- /dev/null +++ b/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/BaseAssemblyImpl.scala @@ -0,0 +1,43 @@ +/* scala-stm - (c) 2009-2011, Stanford University, PPL */ + +package stmbench7.scalastm + +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, + typ: String, + buildDate: Int, + module: Module, + superAssembly: ComplexAssembly +) extends AssemblyImpl(id, typ, buildDate, module, superAssembly) + with BaseAssembly { + + private val components = + Ref(List.empty[CompositePart]).single // the original BagImpl was just an ArrayList + + override def addComponent(component: CompositePart): Unit = { + components.transform(component :: _) + component.addAssembly(this) + } + + override def removeComponent(component: CompositePart): Boolean = { + val f = components transformIfDefined { + case x if x contains component => x filterNot { _ == component } + } + if (f) component.removeAssembly(this) + f + } + + override def getComponents = new ImmutableSeqImpl[CompositePart](components()) + + 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 new file mode 100644 index 00000000..99306215 --- /dev/null +++ b/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/ComplexAssemblyImpl.scala @@ -0,0 +1,45 @@ +/* scala-stm - (c) 2009-2011, Stanford University, PPL */ + +package stmbench7.scalastm + +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, + typ: String, + buildDate: Int, + module: Module, + superAssembly: ComplexAssembly +) extends AssemblyImpl(id, typ, buildDate, module, superAssembly) + with ComplexAssembly { + + private val subAssemblies = TSet.empty[Assembly].single + + private val level = + if (superAssembly == null) Parameters.NumAssmLevels else superAssembly.getLevel - 1 + + override def addSubAssembly(assembly: Assembly): Boolean = { + if (assembly.isInstanceOf[BaseAssembly] && level != 2) + throw new RuntimeError("ComplexAssembly.addAssembly: BaseAssembly at wrong level!"); + + subAssemblies.add(assembly) + } + + override def removeSubAssembly(assembly: Assembly): Boolean = subAssemblies.remove(assembly) + + override def getSubAssemblies = new ImmutableSetImpl[Assembly](subAssemblies) + + override def getLevel: Short = level.asInstanceOf[Short] + + 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 new file mode 100644 index 00000000..8192aa59 --- /dev/null +++ b/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/CompositePartImpl.scala @@ -0,0 +1,55 @@ +/* scala-stm - (c) 2009-2011, Stanford University, PPL */ + +package stmbench7.scalastm + +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 { + + 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) + + override def addAssembly(assembly: BaseAssembly): Unit = { usedIn.transform(assembly :: _) } + + override def addPart(part: AtomicPart): Boolean = { + val f = parts().add(part) + if (f) { + part.setCompositePart(this) + if (rootPart() == null) rootPart() = part + } + f + } + + override def getRootPart: AtomicPart = rootPart() + override def setRootPart(part: AtomicPart): Unit = { rootPart() = part } + + override def getDocumentation: Document = documentation() + + override def getParts: LargeSet[AtomicPart] = parts() + + override def removeAssembly(assembly: BaseAssembly): Unit = { + usedIn.transform { _.filterNot(_ == assembly) } + } + + override def getUsedIn = new ImmutableSeqImpl[BaseAssembly](usedIn()) + + override def clearPointers(): Unit = { + 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..426fd98a --- /dev/null +++ b/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/DesignObjImpl.scala @@ -0,0 +1,17 @@ +/* scala-stm - (c) 2009-2011, Stanford University, PPL */ + +package stmbench7.scalastm + +import scala.concurrent.stm.Ref + +import stmbench7.core.DesignObj + +class DesignObjImpl(id: Int, typ: String, buildDate0: Int) extends DesignObj { + private val bd = Ref(buildDate0).single + + 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 new file mode 100644 index 00000000..bb210ad6 --- /dev/null +++ b/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/DocumentImpl.scala @@ -0,0 +1,40 @@ +/* scala-stm - (c) 2009-2011, Stanford University, PPL */ + +package stmbench7.scalastm + +import scala.annotation.tailrec + +import scala.concurrent.stm.Ref + +import stmbench7.core.CompositePart +import stmbench7.core.Document + +class DocumentImpl(id: Int, title: String, text0: String) extends Document { + private val text = Ref(text0).single + private val part = Ref(null: CompositePart).single + + override def getDocumentId: Int = id + override def getTitle: String = title + + override def getCompositePart: CompositePart = part() + override def setPart(v: CompositePart): Unit = { part() = v } + + override def nullOperation(): Unit = {} + + 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) + } + + 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 + } + + override def textBeginsWith(prefix: String): Boolean = text().startsWith(prefix) +} diff --git a/benchmarks/scala-stm/scala-stm-library/src/test/scala/stmbench7/scalastm/IdPoolImpl.scala b/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/IdPoolImpl.scala similarity index 56% rename from benchmarks/scala-stm/scala-stm-library/src/test/scala/stmbench7/scalastm/IdPoolImpl.scala rename to benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/IdPoolImpl.scala index c1e43b03..144954a6 100644 --- a/benchmarks/scala-stm/scala-stm-library/src/test/scala/stmbench7/scalastm/IdPoolImpl.scala +++ b/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/IdPoolImpl.scala @@ -2,21 +2,23 @@ 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 - - def putUnusedId(id: Int) { underlying.transform(id :: _) } + private val underlying = Ref(List.range(1, n + 1)).single + + 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 } } } -} \ 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..2d95f8e4 --- /dev/null +++ b/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/ImmutableSeqImpl.scala @@ -0,0 +1,16 @@ +/* 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: 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 new file mode 100644 index 00000000..a350d560 --- /dev/null +++ b/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/ImmutableSetImpl.scala @@ -0,0 +1,23 @@ +/* scala-stm - (c) 2009-2012, Stanford University, PPL */ + +package stmbench7.scalastm + +import scala.collection.JavaConversions + +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: ImmutableCollection[A] = + if (!shared) this else new ImmutableSetImpl(contents.clone(), false) + + 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 new file mode 100644 index 00000000..88fb9ee2 --- /dev/null +++ b/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/IndexImpl.scala @@ -0,0 +1,50 @@ +/* scala-stm - (c) 2009-2012, Stanford University, PPL */ + +package stmbench7.scalastm + +import scala.collection.JavaConversions +import scala.collection.immutable.TreeMap + +import scala.concurrent.stm.Ref + +import stmbench7.backend.Index + +object IndexImpl { + + class BoxedImmutable[K <: Comparable[K], V] extends Index[K, V] { + // needed for 2.8, harmless in 2.9 + implicit val order: Ordering[K] = (lhs: K, rhs: K) => lhs compareTo rhs + + private val underlying = Ref(TreeMap.empty[K, V]).single + + override def get(key: K): V = underlying().getOrElse(key, null.asInstanceOf[V]) + + override def put(key: K, value: V): Unit = { underlying.transform(_ + (key -> value)) } + + override def putIfAbsent(key: K, value: V): V = { + underlying + .getAndTransform({ m => if (m.contains(key)) m else m + (key -> value) }) + .getOrElse(key, null.asInstanceOf[V]) + } + + override def remove(key: K): Boolean = + underlying transformIfDefined { + case m if m.contains(key) => m - key + } + + override def iterator: java.util.Iterator[V] = makeValuesIterator(underlying()) + + override def getKeys: java.lang.Iterable[K] = + JavaConversions.setAsJavaSet(underlying().keySet) + + 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[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 new file mode 100644 index 00000000..614c4265 --- /dev/null +++ b/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/LargeSetImpl.scala @@ -0,0 +1,21 @@ +/* scala-stm - (c) 2009-2012, Stanford University, PPL */ + +package stmbench7.scalastm + +import scala.collection.JavaConversions + +import scala.concurrent.stm.TMap + +import stmbench7.backend.LargeSet + +class LargeSetImpl[A <: Comparable[A]] extends LargeSet[A] { + 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 + + 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 new file mode 100644 index 00000000..b34fc8e7 --- /dev/null +++ b/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/ManualImpl.scala @@ -0,0 +1,42 @@ +/* scala-stm - (c) 2009-2011, Stanford University, PPL */ + +package stmbench7.scalastm + +import scala.annotation.tailrec + +import scala.concurrent.stm.Ref + +import stmbench7.core.Manual +import stmbench7.core.Module + +class ManualImpl(id: Int, title0: String, text0: String) extends Manual { + private val title = Ref(title0).single + private val text = Ref(text0).single + private val module = Ref(null: Module).single + + override def getId: Int = id + override def getTitle: String = title() + override def getText: String = text() + override def getModule: Module = module() + + override def setModule(v: Module): Unit = { module() = v } + + 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) + } + + override def checkFirstLastCharTheSame: Int = { + val t = text() + if (t.charAt(0) == t.charAt(t.length - 1)) 1 else 0 + } + + override def startsWith(ch: Char): Boolean = text().charAt(0) == ch + + 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 new file mode 100644 index 00000000..4bc462cc --- /dev/null +++ b/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/ModuleImpl.scala @@ -0,0 +1,22 @@ +/* scala-stm - (c) 2009-2011, Stanford University, PPL */ + +package stmbench7.scalastm + +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 { + + private val designRoot = Ref(null: ComplexAssembly).single + + man.setModule(this) + + 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 new file mode 100644 index 00000000..16aad7d8 --- /dev/null +++ b/benchmarks/scala-stm/src/main/scala/stmbench7/scalastm/ScalaSTMInitializer.scala @@ -0,0 +1,107 @@ +/* scala-stm - (c) 2009-2011, Stanford University, PPL */ + +package stmbench7.scalastm + +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 + +class ScalaSTMInitializer extends SynchMethodInitializer { + + def createOperationExecutorFactory(): OperationExecutorFactory = + new OperationExecutorFactory { + + private val timestamp = Ref(0) + + def createOperationExecutor(op: Operation): OperationExecutor = + new OperationExecutor { + private var lastTS = 0 + + def execute(): Int = { + atomic { implicit t => + val z = op.performOperation() + if (Parameters.sequentialReplayEnabled) { + timestamp += 1 + lastTS = timestamp() + } + z + } + } + + def getLastOperationTimestamp: Int = lastTS + } + } + + def createBackendFactory(): BackendFactory = + 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(): DesignObjFactory = + 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(): ThreadFactory = + (body: Runnable) => new Thread(body) +} 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/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/BenchThread.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/BenchThread.java similarity index 90% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/BenchThread.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/BenchThread.java index 8da09477..94713e3d 100644 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/BenchThread.java +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/BenchThread.java @@ -20,7 +20,7 @@ public class BenchThread implements Runnable { protected double[] operationCDF; protected OperationExecutor[] operations; protected final short myThreadNum; - protected final int countOfOperations; + protected final int countOfOperations; public int[] successfulOperations, failedOperations; public int[][] operationsTTC, operationsHighTTCLog; @@ -57,7 +57,7 @@ public BenchThread(Setup setup, double[] operationCDF, short myThreadNum, int co failedOperations = new int[numOfOperations]; operations = new OperationExecutor[numOfOperations]; this.myThreadNum = myThreadNum; - this.countOfOperations = countOfOperations; + this.countOfOperations = countOfOperations; createOperations(setup); @@ -70,19 +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."); + throw new RuntimeException("This ctor is no longer allowed."); } public void run() { - int i = 0; - int iteration = 0; - while (!stop && iteration < countOfOperations) { - iteration++; + int opIndex = 0; + while (!stop && opIndex < countOfOperations) { + opIndex++; //if (i++ > 55) continue; - int operationNumber = getNextOperationNumber(iteration); + int operationNumber = getNextOperationNumber(opIndex); - OperationType type = OperationId.values()[operationNumber].getType(); - // System.out.println(iteration + ": " + operationNumber + ", " + type); + // OperationType type = OperationId.values()[operationNumber].getType(); //if( (type != OperationType.SHORT_TRAVERSAL) ) continue; // (type != OperationType.SHORT_TRAVERSAL_RO) && // (type != OperationType.OPERATION) ) @@ -163,7 +161,7 @@ protected void createOperations(Setup setup) { protected int getNextOperationNumber(int iteration) { // double whichOperation = ThreadRandom.nextDouble(); - double whichOperation = (iteration % 20) / 20.0; + double whichOperation = (iteration % 20) / 20.0; int operationNumber = 0; while (whichOperation >= operationCDF[operationNumber]) operationNumber++; diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/Benchmark.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/Benchmark.java similarity index 98% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/Benchmark.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/Benchmark.java index 8f35d51a..f5421728 100644 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/Benchmark.java +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/Benchmark.java @@ -72,7 +72,7 @@ public static void main(String[] args) throws InterruptedException { private Setup setup, setupClone; private double elapsedTime; private int countOfOperations; - + private Benchmark(String[] args) throws BenchmarkParametersException, InterruptedException { printHeader(); @@ -130,7 +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 if(currentArg.equals("-c")) countOfOperations = Integer.parseInt(optionValue); else throw new BenchmarkParametersException("Invalid option: " + currentArg); } } @@ -263,7 +263,7 @@ private void generateOperationCDF() { operationsRatio /= sumRatios; structuralModificationsRatio /= sumRatios; - for (OperationType type : OperationType.values()) type.count = 0; + for (OperationType type : OperationType.values()) type.count = 0; OperationId[] operations = OperationId.values(); for(OperationId operation : operations) operation.getType().count++; @@ -301,7 +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())); + // System.out.println(Arrays.stream(operationCDF).boxed().collect(java.util.stream.Collectors.toList())); } private void setupStructures() throws InterruptedException { @@ -352,10 +352,10 @@ private void start() throws InterruptedException { for(Thread thread : threads) thread.start(); - // Note: we require the threads to execute the specified number of operations. + // Renaissance: 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(); @@ -516,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/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/ImplParameters.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/ImplParameters.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/ImplParameters.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/ImplParameters.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/OperationExecutor.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/OperationExecutor.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/OperationExecutor.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/OperationExecutor.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/OperationExecutorFactory.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/OperationExecutorFactory.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/OperationExecutorFactory.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/OperationExecutorFactory.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/OperationId.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/OperationId.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/OperationId.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/OperationId.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/OperationType.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/OperationType.java similarity index 97% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/OperationType.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/OperationType.java index 983d8c69..4079ce5c 100644 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/OperationType.java +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/OperationType.java @@ -14,7 +14,6 @@ public enum OperationType { /** * Some helper fields to make life easier. - * Lord... */ public int count = 0; public double probability = 0; diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/Parameters.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/Parameters.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/Parameters.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/Parameters.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/Setup.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/Setup.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/Setup.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/Setup.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/SynchMethodInitializer.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/SynchMethodInitializer.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/SynchMethodInitializer.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/SynchMethodInitializer.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/ThreadFactory.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/ThreadFactory.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/ThreadFactory.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/ThreadFactory.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/ThreadRandom.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/ThreadRandom.java similarity index 98% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/ThreadRandom.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/ThreadRandom.java index ba226c8f..ce7df7fd 100644 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/ThreadRandom.java +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/ThreadRandom.java @@ -88,9 +88,9 @@ public static double nextDouble() { public static void reset() { if(phase != Phase.INIT) { - System.out.println("Warning, cannot reset!"); + 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/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/annotations/Atomic.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/annotations/Atomic.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/annotations/Atomic.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/annotations/Atomic.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/annotations/ContainedInAtomic.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/annotations/ContainedInAtomic.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/annotations/ContainedInAtomic.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/annotations/ContainedInAtomic.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/annotations/Immutable.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/annotations/Immutable.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/annotations/Immutable.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/annotations/Immutable.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/annotations/NonAtomic.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/annotations/NonAtomic.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/annotations/NonAtomic.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/annotations/NonAtomic.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/annotations/ReadOnly.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/annotations/ReadOnly.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/annotations/ReadOnly.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/annotations/ReadOnly.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/annotations/ThreadLocal.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/annotations/ThreadLocal.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/annotations/ThreadLocal.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/annotations/ThreadLocal.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/annotations/Transactional.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/annotations/Transactional.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/annotations/Transactional.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/annotations/Transactional.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/annotations/Update.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/annotations/Update.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/annotations/Update.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/annotations/Update.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/backend/BackendFactory.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/backend/BackendFactory.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/backend/BackendFactory.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/backend/BackendFactory.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/backend/IdPool.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/backend/IdPool.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/backend/IdPool.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/backend/IdPool.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/backend/ImmutableCollection.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/backend/ImmutableCollection.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/backend/ImmutableCollection.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/backend/ImmutableCollection.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/backend/Index.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/backend/Index.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/backend/Index.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/backend/Index.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/backend/LargeSet.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/backend/LargeSet.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/backend/LargeSet.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/backend/LargeSet.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/Assembly.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/Assembly.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/Assembly.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/Assembly.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/AssemblyBuilder.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/AssemblyBuilder.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/AssemblyBuilder.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/AssemblyBuilder.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/AtomicPart.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/AtomicPart.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/AtomicPart.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/AtomicPart.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/AtomicPartBuilder.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/AtomicPartBuilder.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/AtomicPartBuilder.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/AtomicPartBuilder.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/BaseAssembly.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/BaseAssembly.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/BaseAssembly.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/BaseAssembly.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/ComplexAssembly.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/ComplexAssembly.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/ComplexAssembly.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/ComplexAssembly.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/CompositePart.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/CompositePart.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/CompositePart.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/CompositePart.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/CompositePartBuilder.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/CompositePartBuilder.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/CompositePartBuilder.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/CompositePartBuilder.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/Connection.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/Connection.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/Connection.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/Connection.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/DesignObj.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/DesignObj.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/DesignObj.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/DesignObj.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/DesignObjBuilder.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/DesignObjBuilder.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/DesignObjBuilder.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/DesignObjBuilder.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/DesignObjFactory.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/DesignObjFactory.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/DesignObjFactory.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/DesignObjFactory.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/Document.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/Document.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/Document.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/Document.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/DocumentBuilder.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/DocumentBuilder.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/DocumentBuilder.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/DocumentBuilder.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/Manual.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/Manual.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/Manual.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/Manual.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/ManualBuilder.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/ManualBuilder.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/ManualBuilder.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/ManualBuilder.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/Module.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/Module.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/Module.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/Module.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/ModuleBuilder.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/ModuleBuilder.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/ModuleBuilder.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/ModuleBuilder.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/Operation.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/Operation.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/Operation.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/Operation.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/OperationFailedException.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/OperationFailedException.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/OperationFailedException.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/OperationFailedException.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/RuntimeError.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/RuntimeError.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/core/RuntimeError.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/core/RuntimeError.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/correctness/invariants/AssemblyTest.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/correctness/invariants/AssemblyTest.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/correctness/invariants/AssemblyTest.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/correctness/invariants/AssemblyTest.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/correctness/invariants/AtomicPartTest.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/correctness/invariants/AtomicPartTest.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/correctness/invariants/AtomicPartTest.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/correctness/invariants/AtomicPartTest.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/correctness/invariants/BaseAssemblyTest.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/correctness/invariants/BaseAssemblyTest.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/correctness/invariants/BaseAssemblyTest.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/correctness/invariants/BaseAssemblyTest.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/correctness/invariants/CheckInvariantsOperation.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/correctness/invariants/CheckInvariantsOperation.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/correctness/invariants/CheckInvariantsOperation.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/correctness/invariants/CheckInvariantsOperation.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/correctness/invariants/ComplexAssemblyTest.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/correctness/invariants/ComplexAssemblyTest.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/correctness/invariants/ComplexAssemblyTest.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/correctness/invariants/ComplexAssemblyTest.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/correctness/invariants/CompositePartTest.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/correctness/invariants/CompositePartTest.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/correctness/invariants/CompositePartTest.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/correctness/invariants/CompositePartTest.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/correctness/invariants/ConnectionTest.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/correctness/invariants/ConnectionTest.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/correctness/invariants/ConnectionTest.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/correctness/invariants/ConnectionTest.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/correctness/invariants/DesignObjTest.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/correctness/invariants/DesignObjTest.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/correctness/invariants/DesignObjTest.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/correctness/invariants/DesignObjTest.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/correctness/invariants/DocumentationTest.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/correctness/invariants/DocumentationTest.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/correctness/invariants/DocumentationTest.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/correctness/invariants/DocumentationTest.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/correctness/invariants/IndexTest.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/correctness/invariants/IndexTest.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/correctness/invariants/IndexTest.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/correctness/invariants/IndexTest.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/correctness/invariants/InvariantTest.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/correctness/invariants/InvariantTest.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/correctness/invariants/InvariantTest.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/correctness/invariants/InvariantTest.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/correctness/invariants/ManualTest.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/correctness/invariants/ManualTest.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/correctness/invariants/ManualTest.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/correctness/invariants/ManualTest.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/correctness/invariants/ModuleTest.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/correctness/invariants/ModuleTest.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/correctness/invariants/ModuleTest.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/correctness/invariants/ModuleTest.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/correctness/invariants/TraversedObjects.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/correctness/invariants/TraversedObjects.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/correctness/invariants/TraversedObjects.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/correctness/invariants/TraversedObjects.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/correctness/opacity/SequentialReplayThread.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/correctness/opacity/SequentialReplayThread.java similarity index 90% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/correctness/opacity/SequentialReplayThread.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/correctness/opacity/SequentialReplayThread.java index 825e9717..b0017e65 100644 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/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/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/correctness/opacity/StructureComparisonOperation.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/correctness/opacity/StructureComparisonOperation.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/correctness/opacity/StructureComparisonOperation.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/correctness/opacity/StructureComparisonOperation.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/DefaultOperationExecutor.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/DefaultOperationExecutor.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/DefaultOperationExecutor.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/DefaultOperationExecutor.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/DefaultOperationExecutorFactory.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/DefaultOperationExecutorFactory.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/DefaultOperationExecutorFactory.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/DefaultOperationExecutorFactory.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/DefaultThreadFactory.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/DefaultThreadFactory.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/DefaultThreadFactory.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/DefaultThreadFactory.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/NoSynchronizationInitializer.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/NoSynchronizationInitializer.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/NoSynchronizationInitializer.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/NoSynchronizationInitializer.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/backend/BackendFactoryImpl.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/backend/BackendFactoryImpl.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/backend/BackendFactoryImpl.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/backend/BackendFactoryImpl.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/backend/BagImpl.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/backend/BagImpl.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/backend/BagImpl.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/backend/BagImpl.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/backend/IdPoolImpl.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/backend/IdPoolImpl.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/backend/IdPoolImpl.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/backend/IdPoolImpl.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/backend/ImmutableViewImpl.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/backend/ImmutableViewImpl.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/backend/ImmutableViewImpl.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/backend/ImmutableViewImpl.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/backend/LargeSetImpl.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/backend/LargeSetImpl.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/backend/LargeSetImpl.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/backend/LargeSetImpl.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/backend/SmallSetImpl.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/backend/SmallSetImpl.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/backend/SmallSetImpl.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/backend/SmallSetImpl.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/backend/TreeMapIndex.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/backend/TreeMapIndex.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/backend/TreeMapIndex.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/backend/TreeMapIndex.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/core/AssemblyImpl.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/core/AssemblyImpl.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/core/AssemblyImpl.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/core/AssemblyImpl.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/core/AtomicPartImpl.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/core/AtomicPartImpl.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/core/AtomicPartImpl.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/core/AtomicPartImpl.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/core/BaseAssemblyImpl.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/core/BaseAssemblyImpl.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/core/BaseAssemblyImpl.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/core/BaseAssemblyImpl.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/core/ComplexAssemblyImpl.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/core/ComplexAssemblyImpl.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/core/ComplexAssemblyImpl.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/core/ComplexAssemblyImpl.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/core/CompositePartImpl.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/core/CompositePartImpl.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/core/CompositePartImpl.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/core/CompositePartImpl.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/core/ConnectionImpl.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/core/ConnectionImpl.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/core/ConnectionImpl.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/core/ConnectionImpl.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/core/DesignObjFactoryImpl.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/core/DesignObjFactoryImpl.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/core/DesignObjFactoryImpl.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/core/DesignObjFactoryImpl.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/core/DesignObjImpl.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/core/DesignObjImpl.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/core/DesignObjImpl.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/core/DesignObjImpl.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/core/DocumentImpl.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/core/DocumentImpl.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/core/DocumentImpl.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/core/DocumentImpl.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/core/ManualImpl.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/core/ManualImpl.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/core/ManualImpl.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/core/ManualImpl.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/core/ModuleImpl.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/core/ModuleImpl.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/impl/core/ModuleImpl.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/impl/core/ModuleImpl.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/locking/CGLockingInitializer.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/locking/CGLockingInitializer.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/locking/CGLockingInitializer.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/locking/CGLockingInitializer.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/locking/CGLockingOperationExecutor.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/locking/CGLockingOperationExecutor.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/locking/CGLockingOperationExecutor.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/locking/CGLockingOperationExecutor.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/locking/CGLockingOperationExecutorFactory.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/locking/CGLockingOperationExecutorFactory.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/locking/CGLockingOperationExecutorFactory.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/locking/CGLockingOperationExecutorFactory.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/locking/MGLockingComplexAssemblyImpl.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/locking/MGLockingComplexAssemblyImpl.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/locking/MGLockingComplexAssemblyImpl.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/locking/MGLockingComplexAssemblyImpl.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/locking/MGLockingDesignObjFactory.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/locking/MGLockingDesignObjFactory.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/locking/MGLockingDesignObjFactory.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/locking/MGLockingDesignObjFactory.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/locking/MGLockingInitializer.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/locking/MGLockingInitializer.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/locking/MGLockingInitializer.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/locking/MGLockingInitializer.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/locking/MGLockingOperationExecutor.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/locking/MGLockingOperationExecutor.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/locking/MGLockingOperationExecutor.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/locking/MGLockingOperationExecutor.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/locking/MGLockingOperationExecutorFactory.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/locking/MGLockingOperationExecutorFactory.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/locking/MGLockingOperationExecutorFactory.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/locking/MGLockingOperationExecutorFactory.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/BaseOperation.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/BaseOperation.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/BaseOperation.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/BaseOperation.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Operation10.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Operation10.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Operation10.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Operation10.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Operation11.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Operation11.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Operation11.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Operation11.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Operation12.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Operation12.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Operation12.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Operation12.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Operation13.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Operation13.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Operation13.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Operation13.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Operation14.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Operation14.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Operation14.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Operation14.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Operation15.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Operation15.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Operation15.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Operation15.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Operation6.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Operation6.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Operation6.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Operation6.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Operation7.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Operation7.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Operation7.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Operation7.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Operation8.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Operation8.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Operation8.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Operation8.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Operation9.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Operation9.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Operation9.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Operation9.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Query1.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Query1.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Query1.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Query1.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Query2.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Query2.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Query2.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Query2.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Query3.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Query3.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Query3.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Query3.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Query4.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Query4.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Query4.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Query4.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Query5.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Query5.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Query5.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Query5.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Query6.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Query6.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Query6.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Query6.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Query7.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Query7.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Query7.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Query7.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/SetupDataStructure.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/SetupDataStructure.java similarity index 95% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/SetupDataStructure.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/SetupDataStructure.java index a4e5eec1..57d7c207 100644 --- a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/SetupDataStructure.java +++ b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/SetupDataStructure.java @@ -32,7 +32,7 @@ public int performOperation() throws OperationFailedException { CompositePartBuilder compositePartBuilder = setup.getCompositePartBuilder(); for(int i = 0; i < Parameters.InitialTotalCompParts; i++) { - // Removed, because of too much output. + // Renaissance: Removed, because of too much output. // System.err.print("Component " + (i+1) + " of " + Parameters.InitialTotalCompParts + "\r"); try { designLibrary[i] = compositePartBuilder.createAndRegisterCompositePart(); @@ -53,7 +53,7 @@ public int performOperation() throws OperationFailedException { int i = 1; for(BaseAssembly baseAssembly : setup.getBaseAssemblyIdIndex()) { - // Removed, because of too much output. + // 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++) { diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/ShortTraversal1.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/ShortTraversal1.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/ShortTraversal1.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/ShortTraversal1.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/ShortTraversal10.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/ShortTraversal10.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/ShortTraversal10.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/ShortTraversal10.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/ShortTraversal2.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/ShortTraversal2.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/ShortTraversal2.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/ShortTraversal2.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/ShortTraversal6.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/ShortTraversal6.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/ShortTraversal6.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/ShortTraversal6.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/ShortTraversal7.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/ShortTraversal7.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/ShortTraversal7.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/ShortTraversal7.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/ShortTraversal8.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/ShortTraversal8.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/ShortTraversal8.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/ShortTraversal8.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/ShortTraversal9.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/ShortTraversal9.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/ShortTraversal9.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/ShortTraversal9.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/StructuralModification1.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/StructuralModification1.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/StructuralModification1.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/StructuralModification1.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/StructuralModification2.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/StructuralModification2.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/StructuralModification2.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/StructuralModification2.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/StructuralModification3.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/StructuralModification3.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/StructuralModification3.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/StructuralModification3.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/StructuralModification4.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/StructuralModification4.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/StructuralModification4.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/StructuralModification4.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/StructuralModification5.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/StructuralModification5.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/StructuralModification5.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/StructuralModification5.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/StructuralModification6.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/StructuralModification6.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/StructuralModification6.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/StructuralModification6.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/StructuralModification7.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/StructuralModification7.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/StructuralModification7.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/StructuralModification7.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/StructuralModification8.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/StructuralModification8.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/StructuralModification8.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/StructuralModification8.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Traversal1.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Traversal1.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Traversal1.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Traversal1.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Traversal2a.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Traversal2a.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Traversal2a.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Traversal2a.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Traversal2b.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Traversal2b.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Traversal2b.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Traversal2b.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Traversal2c.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Traversal2c.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Traversal2c.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Traversal2c.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Traversal3a.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Traversal3a.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Traversal3a.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Traversal3a.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Traversal3b.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Traversal3b.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Traversal3b.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Traversal3b.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Traversal3c.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Traversal3c.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Traversal3c.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Traversal3c.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Traversal4.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Traversal4.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Traversal4.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Traversal4.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Traversal5.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Traversal5.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Traversal5.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Traversal5.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Traversal6.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Traversal6.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Traversal6.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Traversal6.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Traversal7.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Traversal7.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Traversal7.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Traversal7.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Traversal8.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Traversal8.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Traversal8.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Traversal8.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Traversal9.java b/benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Traversal9.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/operations/Traversal9.java rename to benchmarks/scala-stm/stmbench7/src/main/java/stmbench7/operations/Traversal9.java diff --git a/benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/test/backend/IndexTest.java b/benchmarks/scala-stm/stmbench7/src/test/java/stmbench7/test/backend/IndexTest.java similarity index 100% rename from benchmarks/scala-stm/scala-stm-library/lib/sb7-java-v1.2/src/stmbench7/test/backend/IndexTest.java rename to benchmarks/scala-stm/stmbench7/src/test/java/stmbench7/test/backend/IndexTest.java diff --git a/build.sbt b/build.sbt index 1a025309..ac183ea6 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.11.1" + ) ) .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"