From f29e08554eaba9869217c74e94064166596aa0c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Antonio=20Bre=C3=B1a=20Moral?= Date: Mon, 28 Dec 2020 17:29:09 +0100 Subject: [PATCH 01/34] Minor change to create the branch for issue #765 --- src/main/java/ev3dev/sensors/Battery.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/main/java/ev3dev/sensors/Battery.java b/src/main/java/ev3dev/sensors/Battery.java index 55c0c225..331b41e0 100644 --- a/src/main/java/ev3dev/sensors/Battery.java +++ b/src/main/java/ev3dev/sensors/Battery.java @@ -5,8 +5,7 @@ import ev3dev.hardware.EV3DevPlatform; import ev3dev.utils.Sysfs; import lejos.hardware.Power; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import lombok.extern.slf4j.Slf4j; /** * The class Battery interacts with EV3Dev to get information about battery used. @@ -15,10 +14,9 @@ * @see https://www.kernel.org/doc/Documentation/power/power_supply_class.txt * @see https://github.com/ev3dev/ev3dev-lang/blob/develop/wrapper-specification.md#direct-attribute-mappings-5 */ +@Slf4j public class Battery extends EV3DevDevice implements Power { - private static final Logger LOGGER = LoggerFactory.getLogger(Battery.class); - private final String BATTERY; private final String BATTERY_EV3; private final String BATTERY_PISTORMS; From 89fc2eced49eecfcd72ee4cd636178d69cc59e5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Antonio=20Bre=C3=B1a=20Moral?= Date: Mon, 28 Dec 2020 17:31:05 +0100 Subject: [PATCH 02/34] First try to execute Github action in any commit --- .github/workflows/build.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 7b24f244..18b073cc 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -5,9 +5,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout source code - uses: actions/checkout@v1 - with: - ref: master + uses: actions/checkout@v2 - name: Set up JDK 11 uses: actions/setup-java@v1 with: From c7ffa25b26c5c5af9d280638997a9df37079acdd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Antonio=20Bre=C3=B1a=20Moral?= Date: Mon, 28 Dec 2020 17:39:37 +0100 Subject: [PATCH 03/34] Removing Travis support --- .travis.yml | 23 ----------------------- README.md | 3 +-- 2 files changed, 1 insertion(+), 25 deletions(-) delete mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 1d00785f..00000000 --- a/.travis.yml +++ /dev/null @@ -1,23 +0,0 @@ -sudo: required -language: java -jdk: - - openjdk11 -before_install: - - chmod +x gradlew -services: - - docker -cache: - directories: - - .autoconf - - $HOME/.m2 - - docker -notifications: - email: - on_success: always - on_failure: always - recipients: - - bren@juanantonio.info -script: - - ./gradlew test checkstyleMain -after_success: - - bash <(curl -s https://codecov.io/bash) diff --git a/README.md b/README.md index 312bc5bb..a75227ad 100644 --- a/README.md +++ b/README.md @@ -4,8 +4,7 @@ & the [LeJOS](http://www.lejos.org/) way. [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](/LICENSE) -[![Travis CI](https://travis-ci.org/ev3dev-lang-java/ev3dev-lang-java.svg?branch=develop)](https://travis-ci.org/ev3dev-lang-java/ev3dev-lang-java) - +![Java CI](https://github.com/ev3dev-lang-java/ev3dev-lang-java/workflows/Java%20CI/badge.svg) ![ScreenShot](https://raw.githubusercontent.com/jabrena/ev3dev-lang-java/master/docs/images/theThreeAmigos.jpg) # How to test? From 904ce524efbfaa4a5017251a2dc1adbf161cf66f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Antonio=20Bre=C3=B1a=20Moral?= Date: Mon, 28 Dec 2020 17:52:33 +0100 Subject: [PATCH 04/34] Adding codecov support (First try) --- .github/workflows/build.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 18b073cc..491f54ad 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -12,3 +12,5 @@ jobs: java-version: 11 - name: Build with Gradle run: ./gradlew test checkstyleMain + - name: Checkout source code + uses: codecov/codecov-action@v1 From 756ea1a535cdb8819f7d6fbd87e0e9fb13f41ca6 Mon Sep 17 00:00:00 2001 From: dwalend Date: Mon, 28 Dec 2020 12:32:47 -0500 Subject: [PATCH 05/34] Battery with DataChannelReaders --- src/main/java/ev3dev/sensors/Battery.java | 60 +++++++++++-------- .../ev3dev/utils/DataChannelRereader.java | 12 ++-- 2 files changed, 41 insertions(+), 31 deletions(-) diff --git a/src/main/java/ev3dev/sensors/Battery.java b/src/main/java/ev3dev/sensors/Battery.java index 55c0c225..c786f6d6 100644 --- a/src/main/java/ev3dev/sensors/Battery.java +++ b/src/main/java/ev3dev/sensors/Battery.java @@ -3,11 +3,14 @@ import ev3dev.hardware.EV3DevDevice; import ev3dev.hardware.EV3DevFileSystem; import ev3dev.hardware.EV3DevPlatform; -import ev3dev.utils.Sysfs; +import ev3dev.utils.DataChannelRereader; import lejos.hardware.Power; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.io.Closeable; +import java.io.IOException; + /** * The class Battery interacts with EV3Dev to get information about battery used. * @@ -15,21 +18,12 @@ * @see https://www.kernel.org/doc/Documentation/power/power_supply_class.txt * @see https://github.com/ev3dev/ev3dev-lang/blob/develop/wrapper-specification.md#direct-attribute-mappings-5 */ -public class Battery extends EV3DevDevice implements Power { +public class Battery extends EV3DevDevice implements Power, Closeable { private static final Logger LOGGER = LoggerFactory.getLogger(Battery.class); - private final String BATTERY; - private final String BATTERY_EV3; - private final String BATTERY_PISTORMS; - private final String BATTERY_BRICKPI; - private final String BATTERY_BRICKPI3; - - private String BATTERY_PATH; - private final String VOLTAGE = "voltage_now"; - private final String CURRENT = "current_now"; - - private String BATTERY_PATH_LOCAL = ""; + private final DataChannelRereader voltageRereader; + private final DataChannelRereader currentRereader; private static Battery instance; @@ -51,28 +45,37 @@ private Battery() { LOGGER.debug("Init sensor"); - BATTERY = ev3DevProperties.getProperty("battery"); - BATTERY_EV3 = ev3DevProperties.getProperty("ev3.battery"); - BATTERY_PISTORMS = ev3DevProperties.getProperty("pistorms.battery"); - BATTERY_BRICKPI = ev3DevProperties.getProperty("brickpi.battery"); - BATTERY_BRICKPI3 = ev3DevProperties.getProperty("brickpi3.battery"); + String battery = ev3DevProperties.getProperty("battery"); + String batteryEv3 = ev3DevProperties.getProperty("ev3.battery"); + String batteryPistorms = ev3DevProperties.getProperty("pistorms.battery"); + String batteryBrickpi = ev3DevProperties.getProperty("brickpi.battery"); + String batteryBrickpi3 = ev3DevProperties.getProperty("brickpi3.battery"); //TODO Create separator variable for the whole project - BATTERY_PATH = EV3DevFileSystem.getRootPath() + "/" + BATTERY; + String batteryPath = EV3DevFileSystem.getRootPath() + "/" + battery; + String batteryPathLocal = ""; if (CURRENT_PLATFORM.equals(EV3DevPlatform.EV3BRICK)) { - BATTERY_PATH_LOCAL += BATTERY_PATH + "/" + BATTERY_EV3; + batteryPathLocal += batteryPath + "/" + batteryEv3; } else if (CURRENT_PLATFORM.equals(EV3DevPlatform.PISTORMS)) { - BATTERY_PATH_LOCAL += BATTERY_PATH + "/" + BATTERY_PISTORMS; + batteryPathLocal += batteryPath + "/" + batteryPistorms; } else if (CURRENT_PLATFORM.equals(EV3DevPlatform.BRICKPI)) { - BATTERY_PATH_LOCAL += BATTERY_PATH + "/" + BATTERY_BRICKPI; + batteryPathLocal += batteryPath + "/" + batteryBrickpi; } else if (CURRENT_PLATFORM.equals(EV3DevPlatform.BRICKPI3)) { - BATTERY_PATH_LOCAL += BATTERY_PATH + "/" + BATTERY_BRICKPI3; + batteryPathLocal += batteryPath + "/" + batteryBrickpi3; } + String voltage = "voltage_now"; + voltageRereader = new DataChannelRereader(batteryPathLocal + "/" + voltage); + String current = "current_now"; + currentRereader = new DataChannelRereader(batteryPath + "/" + batteryEv3 + "/" + current); + } + + public int getVoltageMicroVolts() { + return Integer.parseInt(voltageRereader.readString()); } @Override public int getVoltageMilliVolt() { - return (int) Sysfs.readFloat(BATTERY_PATH_LOCAL + "/" + VOLTAGE) / 1000; + return getVoltageMicroVolts() / 1000; } /** @@ -81,7 +84,7 @@ public int getVoltageMilliVolt() { * @return voltage */ public float getVoltage() { - return Sysfs.readFloat(BATTERY_PATH_LOCAL + "/" + VOLTAGE) / 1000000; + return getVoltageMicroVolts() / 1000000f; } //TODO Review output @@ -94,7 +97,7 @@ public float getVoltage() { */ public float getBatteryCurrent() { if (CURRENT_PLATFORM.equals(EV3DevPlatform.EV3BRICK)) { - return Sysfs.readFloat(BATTERY_PATH + "/" + BATTERY_EV3 + "/" + CURRENT); + return Float.parseFloat(currentRereader.readString()); } else { LOGGER.warn("This method is not available for {} & {}", EV3DevPlatform.PISTORMS, EV3DevPlatform.BRICKPI); return -1f; @@ -107,4 +110,9 @@ public float getMotorCurrent() { throw new UnsupportedOperationException("This feature is not implemented"); } + @Override + public void close() throws IOException { + voltageRereader.close(); + currentRereader.close(); + } } diff --git a/src/main/java/ev3dev/utils/DataChannelRereader.java b/src/main/java/ev3dev/utils/DataChannelRereader.java index 2ba369f6..291c035c 100644 --- a/src/main/java/ev3dev/utils/DataChannelRereader.java +++ b/src/main/java/ev3dev/utils/DataChannelRereader.java @@ -25,21 +25,23 @@ public class DataChannelRereader implements Closeable { * * @param path path to the file to reread * @param bufferLength length of the buffer to hold the structure - * @throws IOException when things go wrong */ - public DataChannelRereader(Path path, int bufferLength) throws IOException { + public DataChannelRereader(Path path, int bufferLength) { this.path = path; this.byteBuffer = ByteBuffer.allocate(bufferLength); - this.channel = FileChannel.open(path); + try { + this.channel = FileChannel.open(path); + } catch (IOException e) { + throw new RuntimeException("Problem opening path: " + path, e); + } } /** * Create a DataChannelRereader for pathString with the default 32-byte buffer. * * @param pathString Path to the file to reread - * @throws IOException when things go wrong */ - public DataChannelRereader(String pathString) throws IOException { + public DataChannelRereader(String pathString) { this(Paths.get(pathString),32); } From 5abe18bf698984e1e703fa2672c15af6e7be28cf Mon Sep 17 00:00:00 2001 From: dwalend Date: Mon, 28 Dec 2020 23:04:48 -0500 Subject: [PATCH 06/34] DataChannelRewriter to show --- .../ev3dev/utils/DataChannelRewriter.java | 76 +++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 src/main/java/ev3dev/utils/DataChannelRewriter.java diff --git a/src/main/java/ev3dev/utils/DataChannelRewriter.java b/src/main/java/ev3dev/utils/DataChannelRewriter.java new file mode 100644 index 00000000..20ed1761 --- /dev/null +++ b/src/main/java/ev3dev/utils/DataChannelRewriter.java @@ -0,0 +1,76 @@ +package ev3dev.utils; + +import java.io.Closeable; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.channels.FileChannel; +import java.nio.charset.StandardCharsets; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardOpenOption; + +/** + * Writer of streams that can rewrite the same channel for structured data of + * known length. The focus of this class is on performance. + * + * @author David Walend + */ +public class DataChannelRewriter implements Closeable { + + private final Path path; + private final ByteBuffer byteBuffer; + private final FileChannel channel; + + /** + * Create a DataChannelRewriter for path with a bufferLength byte buffer + * + * @param path path to the file to reread + * @param bufferLength length of the buffer to hold the structure + */ + public DataChannelRewriter(Path path, int bufferLength) { + this.path = path; + this.byteBuffer = ByteBuffer.allocate(bufferLength); + try { + this.channel = FileChannel.open(path, StandardOpenOption.WRITE); + } catch (IOException e) { + throw new RuntimeException("While opeing " + path,e); + } + } + + /** + * Create a DataChannelRewriter for pathString with the default 32-byte buffer. + * + * @param pathString Path to the file to reread + */ + public DataChannelRewriter(String pathString) { + this(Paths.get(pathString),32); + } + + /** + * @param string to write. A new line character + */ + public void writeString(String string) { + try { + byteBuffer.clear(); + byteBuffer.put(string.getBytes(StandardCharsets.UTF_8)); + byteBuffer.put(((byte)'\n')); + byteBuffer.flip(); + channel.position(0); + channel.write(byteBuffer); + channel.truncate(byteBuffer.position()); + channel.force(false); + } catch (IOException e) { + throw new RuntimeException("Problem reading path: " + path, e); + } + } + + public Path getPath() { + return path; + } + + @Override + public void close() throws IOException { + channel.close(); + } +} + From 84e52428b40b2315665272fb2f8787e7b0b57ebb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Antonio=20Bre=C3=B1a=20Moral?= Date: Wed, 30 Dec 2020 13:11:03 +0100 Subject: [PATCH 07/34] Adding a test to review the concurrency support --- .../DataChannelRereaderConcurrencyTest.java | 166 ++++++++++++++++++ 1 file changed, 166 insertions(+) create mode 100644 src/test/java/ev3dev/utils/DataChannelRereaderConcurrencyTest.java diff --git a/src/test/java/ev3dev/utils/DataChannelRereaderConcurrencyTest.java b/src/test/java/ev3dev/utils/DataChannelRereaderConcurrencyTest.java new file mode 100644 index 00000000..1c0fdeca --- /dev/null +++ b/src/test/java/ev3dev/utils/DataChannelRereaderConcurrencyTest.java @@ -0,0 +1,166 @@ +package ev3dev.utils; + +import java.io.File; +import java.util.concurrent.CompletableFuture; +import java.util.stream.IntStream; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.junit.Before; +import org.junit.Test; + +import static org.assertj.core.api.BDDAssertions.then; +import static org.junit.Assert.assertTrue; + +@Slf4j +public class DataChannelRereaderConcurrencyTest { + + final String fileName = "./pairs.txt"; + final String fileName2 = "./odds.txt"; + final Integer limit = 100; + + @Before + @SneakyThrows + public void createFiles() { + new File(fileName).createNewFile(); + new File(fileName2).createNewFile(); + } + + @Test + public void given_multiple_DataChannelRereader_when_execute_concurrently_then_Ok() { + + CompletableFuture request1 = asyncWriteFile(true); + CompletableFuture request2 = asyncWriteFile(false); + CompletableFuture request3 = asyncReadFile(true); + CompletableFuture request4 = asyncReadFile(false); + CompletableFuture request5 = asyncReadFile2(true); + CompletableFuture request6 = asyncReadFile2(false); + + CompletableFuture combinedFuture = CompletableFuture.allOf( + request1, + request2, + request3, + request4, + request5, + request6); + + combinedFuture.join(); + + assertTrue(request1.isDone()); + assertTrue(request2.isDone()); + assertTrue(request3.isDone()); + assertTrue(request4.isDone()); + assertTrue(request5.isDone()); + assertTrue(request6.isDone()); + + System.out.println(request1.join()); + System.out.println(request2.join()); + System.out.println(request3.join()); + System.out.println(request4.join()); + System.out.println(request5.join()); + System.out.println(request6.join()); + + //System.out.println(count); + + System.out.println("End"); + } + + private void readFile(String file, Boolean flag) { + Integer value = Sysfs.readInteger(file); + if (flag) { + then(value % 2 == 0).isTrue(); + } else { + then(value % 2 != 0).isTrue(); + } + } + + private void readFile2(String file, Boolean flag) { + DataChannelRereader dataChannelRereader = new DataChannelRereader(file); + Integer value = Integer.parseInt(dataChannelRereader.readString()); + if (flag) { + then(value % 2 == 0).isTrue(); + } else { + then(value % 2 != 0).isTrue(); + } + } + + private CompletableFuture asyncReadFile(boolean flag) { + CompletableFuture cf1 = CompletableFuture.supplyAsync(() -> { + IntStream + .rangeClosed(1, limit) + .forEach(i -> { + if (flag) { + readFile(fileName, flag); + } else { + readFile(fileName2, flag); + } + }); + return "Ok asyncReadFile"; + }) + .handle((input, exception) -> { + if (exception != null) { + LOGGER.warn(exception.getLocalizedMessage(), exception); + return "Ko asyncReadFile"; + } + return input; + }); + return cf1; + } + + private CompletableFuture asyncReadFile2(boolean flag) { + CompletableFuture cf = CompletableFuture.supplyAsync(() -> { + IntStream + .rangeClosed(1, limit) + .forEach(i -> { + if (flag) { + readFile2(fileName, flag); + } else { + readFile2(fileName2, flag); + } + }); + return "Ok asyncReadFile2"; + }) + .handle((input, exception) -> { + if (exception != null) { + LOGGER.warn(exception.getLocalizedMessage(), exception); + return "Ko asyncReadFile2"; + } + return input; + }); + return cf; + } + + private void writeFile(String file, String value) { + Sysfs.writeString(file, value); + } + + private CompletableFuture asyncWriteFile(boolean flag) { + CompletableFuture cf = CompletableFuture.supplyAsync(() -> { + IntStream + .rangeClosed(1, limit) + .filter(i -> { + if (flag) { + return i % 2 == 0; + } else { + return i % 2 != 0; + } + }) + .forEach(i -> { + if (flag) { + writeFile(fileName, String.valueOf(i)); + } else { + writeFile(fileName2, String.valueOf(i)); + } + }); + return "Ok asyncWriteFile"; + }) + .handle((input, exception) -> { + if (exception != null) { + LOGGER.warn(exception.getLocalizedMessage(), exception); + return "Ko asyncWriteFile"; + } + return input; + }); + + return cf; + } +} From 97ab5d52f9964dad0e6ede77f94dedd3f95fd5e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Antonio=20Bre=C3=B1a=20Moral?= Date: Wed, 30 Dec 2020 13:22:30 +0100 Subject: [PATCH 08/34] Adding a new test with another scenario --- .../DataChannelRereaderConcurrencyTest.java | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/src/test/java/ev3dev/utils/DataChannelRereaderConcurrencyTest.java b/src/test/java/ev3dev/utils/DataChannelRereaderConcurrencyTest.java index 1c0fdeca..ad639d30 100644 --- a/src/test/java/ev3dev/utils/DataChannelRereaderConcurrencyTest.java +++ b/src/test/java/ev3dev/utils/DataChannelRereaderConcurrencyTest.java @@ -25,6 +25,15 @@ public void createFiles() { new File(fileName2).createNewFile(); } + /** + * Writer1 -> pairs.txt + * Reader1 <- pairs.txt + * Reader2 <- pairs.txt + * + * Writer1 -> odds.txt + * Reader1 <- odds.txt + * Reader2 <- odds.txt + */ @Test public void given_multiple_DataChannelRereader_when_execute_concurrently_then_Ok() { @@ -163,4 +172,41 @@ private CompletableFuture asyncWriteFile(boolean flag) { return cf; } + + /** + * Writer1 -> pairs.txt + * Reader1 <- pairs.txt + * + * Writer1 -> odds.txt + * Reader1 <- odds.txt + */ + @Test + public void given_multiple_DataChannelRereader_when_execute_concurrently_then_Ok2() { + + CompletableFuture request1 = asyncWriteFile(true); + CompletableFuture request2 = asyncWriteFile(false); + CompletableFuture request3 = asyncReadFile(true); + CompletableFuture request4 = asyncReadFile(false); + + CompletableFuture combinedFuture = CompletableFuture.allOf( + request1, + request2, + request3, + request4); + + combinedFuture.join(); + + assertTrue(request1.isDone()); + assertTrue(request2.isDone()); + assertTrue(request3.isDone()); + assertTrue(request4.isDone()); + + System.out.println(request1.join()); + System.out.println(request2.join()); + System.out.println(request3.join()); + System.out.println(request4.join()); + //System.out.println(count); + + System.out.println("End"); + } } From b66641701c649c08b2cbda21ff3bb88deceeee1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Antonio=20Bre=C3=B1a=20Moral?= Date: Wed, 30 Dec 2020 15:40:03 +0100 Subject: [PATCH 09/34] Decoupled tests to cover both versions. --- .../ev3dev/utils/DataChannelRereader2.java | 117 ++++++++++ src/main/java/ev3dev/utils/Sysfs2.java | 152 +++++++++++++ .../DataChannelRereader2ConcurrencyTest.java | 208 ++++++++++++++++++ .../DataChannelRereaderConcurrencyTest.java | 46 ++-- 4 files changed, 498 insertions(+), 25 deletions(-) create mode 100644 src/main/java/ev3dev/utils/DataChannelRereader2.java create mode 100644 src/main/java/ev3dev/utils/Sysfs2.java create mode 100644 src/test/java/ev3dev/utils/DataChannelRereader2ConcurrencyTest.java diff --git a/src/main/java/ev3dev/utils/DataChannelRereader2.java b/src/main/java/ev3dev/utils/DataChannelRereader2.java new file mode 100644 index 00000000..61ab4878 --- /dev/null +++ b/src/main/java/ev3dev/utils/DataChannelRereader2.java @@ -0,0 +1,117 @@ +package ev3dev.utils; + +import java.io.Closeable; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.channels.FileChannel; +import java.nio.charset.StandardCharsets; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardOpenOption; + +/** + * Reader of streams that can reread the same channel for structured data of + * known length. The focus of this class is on performance. + * + *

Because of its specialization to ev3dev sysfs attributes, it is able + * to read at most 4096 bytes. + * + *

Objects of this class are safe to use from multiple threads when used in + * a standard manner, see documentation of individual methods for details. + * + *

Note: this class contains a static ThreadLocal<ByteBuffer>. + * This may cause problems with massive and long-lived thread pools. + * + * @author David Walend + */ +public class DataChannelRereader2 implements Closeable { + /** + * Thread-local buffer for reading data from sysfs. + * + *

Each NIO read() needs a pre-allocated buffer into which + * data are stored. This makes the code utilizing it responsible + * for buffer management. Here it is solved by keeping around + * a generously sized buffer (4096 = memory page size). + * By making the buffer thread-local, we avoid data races + * on buffer contents. The buffer can also be made static, + * as there is little benefit to keeping it local to class instances. + */ + private static final ThreadLocal byteBuffer = + ThreadLocal.withInitial(() -> ByteBuffer.allocate(4096)); + + /** + * Real file path, primarily for logging purposes. + */ + private final Path path; + + /** + * NIO channel opened for the path. + */ + private final FileChannel channel; + + /** + * Create a DataChannelRereader for the specified path. + * + * @param path path to the file to reread + */ + public DataChannelRereader2(Path path) { + this.path = path; + try { + this.channel = FileChannel.open(path, StandardOpenOption.READ); + } catch (IOException e) { + throw new RuntimeException("Problem opening path: " + path, e); + } + } + + /** + * Create a DataChannelRereader for the specified path. + * + * @param pathString path to the file to reread + */ + public DataChannelRereader2(String pathString) { + this(Paths.get(pathString)); + } + + /** + * Read the current file contents and return them as a string. + * + *

You can safely call this function from multiple threads in parallel. + * However, you must not call this function in parallel with close() or + * after close() was called. + * + * @return String contents of the file without a trailing newline. + */ + public String readString() { + try { + // prepare the thread-local buffer + ByteBuffer buffer = byteBuffer.get(); + buffer.clear(); + + // try to do the read + // only one try, as: + // - value >0 indicates success + // - value =0 does not tell us much, as there's a possibility of reading an empty attribute + // - value <0 indicates failure + int n = channel.read(buffer, 0); + if (n == -1) { + throw new IOException("Premature end of file " + path); + } + + // strip trailing newline & return data as a string + // rationale: ev3dev sysfs often appends \n, but this breaks parseFloat/parseInt/... + byte[] bytes = buffer.array(); + if (n > 0 && bytes[n - 1] == '\n') { + return new String(bytes, 0, n - 1, StandardCharsets.UTF_8); + } else { + return new String(bytes, 0, n, StandardCharsets.UTF_8); + } + } catch (IOException e) { + throw new RuntimeException("Problem reading path: " + path, e); + } + } + + @Override + public void close() throws IOException { + channel.close(); + } +} diff --git a/src/main/java/ev3dev/utils/Sysfs2.java b/src/main/java/ev3dev/utils/Sysfs2.java new file mode 100644 index 00000000..341126f2 --- /dev/null +++ b/src/main/java/ev3dev/utils/Sysfs2.java @@ -0,0 +1,152 @@ +package ev3dev.utils; + +import java.io.File; +import java.io.IOException; +import java.io.PrintWriter; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardOpenOption; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import lombok.extern.slf4j.Slf4j; + +/** + * The class responsible to interact with Sysfs on EV3Dev + * + * @author Juan Antonio Breña Moral + * @author David Walend + * + */ +@Slf4j +public class Sysfs2 { + + /** + * Write a value in a file. + * + * @param filePath File path + * @param value value to write + * @return A boolean value if the operation was written or not. + */ + public static boolean writeString(final String filePath, final String value) { + if (LOGGER.isTraceEnabled()) { + LOGGER.trace("echo " + value + " > " + filePath); + } + try { + final File file = new File(filePath); + if (file.canWrite()) { + //TODO Review if it possible to improve + PrintWriter out = new PrintWriter(file); + out.println(value); + out.flush(); + out.close(); + //TODO Review + } else { + LOGGER.error("File: '{}' without write permissions.", filePath); + return false; + } + } catch (IOException e) { + LOGGER.error(e.getLocalizedMessage(), e); + return false; + } + return true; + } + + public static boolean writeInteger(final String filePath, final int value) { + return writeString(filePath, new StringBuilder().append(value).toString()); + } + + /** + * Read an Attribute in the Sysfs with containing String values + * + * @param filePath path + * @return value from attribute + */ + public static String readString(final String filePath) { + if (LOGGER.isTraceEnabled()) { + LOGGER.trace("cat " + filePath); + } + try { + try (DataChannelRereader2 rereader = new DataChannelRereader2(filePath)) { + String result = rereader.readString(); + if (LOGGER.isTraceEnabled()) { + LOGGER.trace("value: {}", result); + } + return result; + } + } catch (IOException e) { + LOGGER.error(e.getLocalizedMessage(), e); + throw new RuntimeException("Problem reading path: " + filePath, e); + } + } + + /** + * Read an Attribute in the Sysfs with containing Integer values + * + * @param filePath path + * @return value from attribute + */ + public static int readInteger(final String filePath) { + return Integer.parseInt(readString(filePath)); + } + + /** + * Read an Attribute in the Sysfs with containing Float values + * + * @param filePath path + * @return value from attribute + */ + public static float readFloat(final String filePath) { + return Float.parseFloat(readString(filePath)); + } + + /** + * Retrieve the elements contained in a path + * + * @param filePath path + * @return an List with options from a path + */ + public static List getElements(final String filePath) { + final File f = new File(filePath); + if (existPath(filePath) && (f.listFiles().length > 0)) { + return new ArrayList<>(Arrays.asList(f.listFiles())); + } else { + throw new RuntimeException("The path doesn't exist: " + filePath); + } + } + + /** + * This method is used to detect folders in /sys/class/ + * + * @param filePath path + * @return boolean + */ + public static boolean existPath(final String filePath) { + if (LOGGER.isTraceEnabled()) { + LOGGER.trace("ls " + filePath); + } + final File f = new File(filePath); + return f.exists() && f.isDirectory(); + } + + public static boolean existFile(Path pathToFind) { + return Files.exists(pathToFind); + } + + /** + * Method to write bytes in a path + * + * @param path path + * @param value value to write + * @return Result + */ + public static boolean writeBytes(final String path, final byte[] value) { + try { + Files.write(Paths.get(path), value, StandardOpenOption.WRITE); + } catch (IOException e) { + throw new RuntimeException("Unable to draw the LCD", e); + } + return true; + } +} diff --git a/src/test/java/ev3dev/utils/DataChannelRereader2ConcurrencyTest.java b/src/test/java/ev3dev/utils/DataChannelRereader2ConcurrencyTest.java new file mode 100644 index 00000000..9797c264 --- /dev/null +++ b/src/test/java/ev3dev/utils/DataChannelRereader2ConcurrencyTest.java @@ -0,0 +1,208 @@ +package ev3dev.utils; + +import java.io.File; +import java.util.concurrent.CompletableFuture; +import java.util.stream.IntStream; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.junit.Before; +import org.junit.Test; + +import static org.assertj.core.api.BDDAssertions.then; + +@Slf4j +public class DataChannelRereader2ConcurrencyTest { + + final String fileName = "./pairs.txt"; + final String fileName2 = "./odds.txt"; + final Integer limit = 1000; + + @Before + @SneakyThrows + public void createFiles() { + new File(fileName).createNewFile(); + new File(fileName2).createNewFile(); + } + + /** + * Writer1 -> pairs.txt + * Reader1 <- pairs.txt + * Reader2 <- pairs.txt + * + * Writer1 -> odds.txt + * Reader1 <- odds.txt + * Reader2 <- odds.txt + */ + @Test + public void given_multiple_DataChannelRereader_when_execute_concurrently_then_Ok() { + + CompletableFuture request1 = asyncWriteFile(true); + CompletableFuture request2 = asyncWriteFile(false); + CompletableFuture request3 = asyncReadFile(true); + CompletableFuture request4 = asyncReadFile(false); + CompletableFuture request5 = asyncReadFile2(true); + CompletableFuture request6 = asyncReadFile2(false); + + CompletableFuture combinedFuture = CompletableFuture.allOf( + request1, + request2, + request3, + request4, + request5, + request6); + + combinedFuture.join(); + + then(request1.isDone()).isTrue(); + then(request2.isDone()).isTrue(); + then(request3.isDone()).isTrue(); + then(request4.isDone()).isTrue(); + then(request5.isDone()).isTrue(); + then(request6.isDone()).isTrue(); + + then(request1.join()).isEqualTo("Ok asyncWriteFile"); + then(request2.join()).isEqualTo("Ok asyncWriteFile"); + then(request3.join()).isEqualTo("Ok asyncReadFile"); + then(request4.join()).isEqualTo("Ok asyncReadFile"); + then(request5.join()).isEqualTo("Ok asyncReadFile2"); + then(request6.join()).isEqualTo("Ok asyncReadFile2"); + + System.out.println("End"); + } + + private void readFile(String file, Boolean flag) { + Integer value = Sysfs2.readInteger(file); + if (flag) { + then(value % 2 == 0).isTrue(); + } else { + then(value % 2 != 0).isTrue(); + } + } + + private void readFile2(String file, Boolean flag) { + DataChannelRereader2 dataChannelRereader = new DataChannelRereader2(file); + Integer value = Integer.parseInt(dataChannelRereader.readString()); + if (flag) { + then(value % 2 == 0).isTrue(); + } else { + then(value % 2 != 0).isTrue(); + } + } + + private CompletableFuture asyncReadFile(boolean flag) { + CompletableFuture cf1 = CompletableFuture.supplyAsync(() -> { + IntStream + .rangeClosed(1, limit) + .forEach(i -> { + if (flag) { + readFile(fileName, flag); + } else { + readFile(fileName2, flag); + } + }); + return "Ok asyncReadFile"; + }) + .handle((input, exception) -> { + if (exception != null) { + LOGGER.warn(exception.getLocalizedMessage(), exception); + return "Ko asyncReadFile"; + } + return input; + }); + return cf1; + } + + private CompletableFuture asyncReadFile2(boolean flag) { + CompletableFuture cf = CompletableFuture.supplyAsync(() -> { + IntStream + .rangeClosed(1, limit) + .forEach(i -> { + if (flag) { + readFile2(fileName, flag); + } else { + readFile2(fileName2, flag); + } + }); + return "Ok asyncReadFile2"; + }) + .handle((input, exception) -> { + if (exception != null) { + LOGGER.warn(exception.getLocalizedMessage(), exception); + return "Ko asyncReadFile2"; + } + return input; + }); + return cf; + } + + private void writeFile(String file, String value) { + Sysfs2.writeString(file, value); + } + + private CompletableFuture asyncWriteFile(boolean flag) { + CompletableFuture cf = CompletableFuture.supplyAsync(() -> { + IntStream + .rangeClosed(1, limit) + .filter(i -> { + if (flag) { + return i % 2 == 0; + } else { + return i % 2 != 0; + } + }) + .forEach(i -> { + if (flag) { + writeFile(fileName, String.valueOf(i)); + } else { + writeFile(fileName2, String.valueOf(i)); + } + }); + return "Ok asyncWriteFile"; + }) + .handle((input, exception) -> { + if (exception != null) { + LOGGER.warn(exception.getLocalizedMessage(), exception); + return "Ko asyncWriteFile"; + } + return input; + }); + + return cf; + } + + /** + * Writer1 -> pairs.txt + * Reader1 <- pairs.txt + * + * Writer1 -> odds.txt + * Reader1 <- odds.txt + */ + @Test + public void given_multiple_DataChannelRereader_when_execute_concurrently_then_Ok2() { + + CompletableFuture request1 = asyncWriteFile(true); + CompletableFuture request2 = asyncWriteFile(false); + CompletableFuture request3 = asyncReadFile(true); + CompletableFuture request4 = asyncReadFile(false); + + CompletableFuture combinedFuture = CompletableFuture.allOf( + request1, + request2, + request3, + request4); + + combinedFuture.join(); + + then(request1.isDone()).isTrue(); + then(request2.isDone()).isTrue(); + then(request3.isDone()).isTrue(); + then(request4.isDone()).isTrue(); + + then(request1.join()).isEqualTo("Ok asyncWriteFile"); + then(request2.join()).isEqualTo("Ok asyncWriteFile"); + then(request3.join()).isEqualTo("Ok asyncReadFile"); + then(request4.join()).isEqualTo("Ok asyncReadFile"); + + System.out.println("End"); + } +} diff --git a/src/test/java/ev3dev/utils/DataChannelRereaderConcurrencyTest.java b/src/test/java/ev3dev/utils/DataChannelRereaderConcurrencyTest.java index ad639d30..011fff8b 100644 --- a/src/test/java/ev3dev/utils/DataChannelRereaderConcurrencyTest.java +++ b/src/test/java/ev3dev/utils/DataChannelRereaderConcurrencyTest.java @@ -9,14 +9,13 @@ import org.junit.Test; import static org.assertj.core.api.BDDAssertions.then; -import static org.junit.Assert.assertTrue; @Slf4j public class DataChannelRereaderConcurrencyTest { final String fileName = "./pairs.txt"; final String fileName2 = "./odds.txt"; - final Integer limit = 100; + final Integer limit = 1000; @Before @SneakyThrows @@ -54,21 +53,19 @@ public void given_multiple_DataChannelRereader_when_execute_concurrently_then_Ok combinedFuture.join(); - assertTrue(request1.isDone()); - assertTrue(request2.isDone()); - assertTrue(request3.isDone()); - assertTrue(request4.isDone()); - assertTrue(request5.isDone()); - assertTrue(request6.isDone()); + then(request1.isDone()).isTrue(); + then(request2.isDone()).isTrue(); + then(request3.isDone()).isTrue(); + then(request4.isDone()).isTrue(); + then(request5.isDone()).isTrue(); + then(request6.isDone()).isTrue(); - System.out.println(request1.join()); - System.out.println(request2.join()); - System.out.println(request3.join()); - System.out.println(request4.join()); - System.out.println(request5.join()); - System.out.println(request6.join()); - - //System.out.println(count); + then(request1.join()).isEqualTo("Ok asyncWriteFile"); + then(request2.join()).isEqualTo("Ok asyncWriteFile"); + then(request3.join()).isEqualTo("Ok asyncReadFile"); + then(request4.join()).isEqualTo("Ok asyncReadFile"); + then(request5.join()).isEqualTo("Ok asyncReadFile2"); + then(request6.join()).isEqualTo("Ok asyncReadFile2"); System.out.println("End"); } @@ -196,16 +193,15 @@ public void given_multiple_DataChannelRereader_when_execute_concurrently_then_Ok combinedFuture.join(); - assertTrue(request1.isDone()); - assertTrue(request2.isDone()); - assertTrue(request3.isDone()); - assertTrue(request4.isDone()); + then(request1.isDone()).isTrue(); + then(request2.isDone()).isTrue(); + then(request3.isDone()).isTrue(); + then(request4.isDone()).isTrue(); - System.out.println(request1.join()); - System.out.println(request2.join()); - System.out.println(request3.join()); - System.out.println(request4.join()); - //System.out.println(count); + then(request1.join()).isEqualTo("Ok asyncWriteFile"); + then(request2.join()).isEqualTo("Ok asyncWriteFile"); + then(request3.join()).isEqualTo("Ok asyncReadFile"); + then(request4.join()).isEqualTo("Ok asyncReadFile"); System.out.println("End"); } From fb90a1430632ee113884b0cee851324095724510 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Antonio=20Bre=C3=B1a=20Moral?= Date: Wed, 30 Dec 2020 15:51:19 +0100 Subject: [PATCH 10/34] Testing the old version --- src/main/java/ev3dev/utils/SysfsOld.java | 148 ++++++++++++++++++ .../DataChannelRereader3ConcurrencyTest.java | 129 +++++++++++++++ 2 files changed, 277 insertions(+) create mode 100644 src/main/java/ev3dev/utils/SysfsOld.java create mode 100644 src/test/java/ev3dev/utils/DataChannelRereader3ConcurrencyTest.java diff --git a/src/main/java/ev3dev/utils/SysfsOld.java b/src/main/java/ev3dev/utils/SysfsOld.java new file mode 100644 index 00000000..eaedf56d --- /dev/null +++ b/src/main/java/ev3dev/utils/SysfsOld.java @@ -0,0 +1,148 @@ +package ev3dev.utils; + +import org.slf4j.Logger; + +import java.io.File; +import java.io.IOException; +import java.io.PrintWriter; +import java.nio.charset.Charset; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardOpenOption; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * The class responsible to interact with Sysfs on EV3Dev + * + * @author Juan Antonio Breña Moral + */ +public class SysfsOld { + + private static final Logger log = org.slf4j.LoggerFactory.getLogger(SysfsOld.class); + + /** + * Write a value in a file. + * + * @param filePath File path + * @param value value to write + * @return A boolean value if the operation was written or not. + */ + public static boolean writeString(final String filePath, final String value) { + if (log.isTraceEnabled()) { + log.trace("echo " + value + " > " + filePath); + } + try { + final File file = new File(filePath); + if (file.canWrite()) { + //TODO Review if it possible to improve + PrintWriter out = new PrintWriter(file); + out.println(value); + out.flush(); + out.close(); + //TODO Review + } else { + log.error("File: '{}' without write permissions.", filePath); + return false; + } + } catch (IOException e) { + log.error(e.getLocalizedMessage(), e); + return false; + } + return true; + } + + public static boolean writeInteger(final String filePath, final int value) { + return writeString(filePath, new StringBuilder().append(value).toString()); + } + + /** + * Read an Attribute in the Sysfs with containing String values + * + * @param filePath path + * @return value from attribute + */ + public static String readString(final String filePath) { + if (log.isTraceEnabled()) { + log.trace("cat " + filePath); + } + try { + final Path path = Paths.get(filePath); + if (existFile(path) && Files.isReadable(path)) { + final String result = Files.readAllLines(path, Charset.forName("UTF-8")).get(0); + if (log.isTraceEnabled()) { + log.trace("value: {}", result); + } + return result; + } + throw new IOException("Problem reading path: " + filePath); + } catch (IOException e) { + log.error(e.getLocalizedMessage(), e); + throw new RuntimeException("Problem reading path: " + filePath, e); + } + } + + /** + * Read an Attribute in the Sysfs with containing Integer values + * + * @param filePath path + * @return value from attribute + */ + public static int readInteger(final String filePath) { + return Integer.parseInt(readString(filePath)); + } + + public static float readFloat(final String filePath) { + return Float.parseFloat(readString(filePath)); + } + + /** + * @param filePath path + * @return an List with options from a path + */ + public static List getElements(final String filePath) { + final File f = new File(filePath); + if (existPath(filePath) && (f.listFiles().length > 0)) { + return new ArrayList<>(Arrays.asList(f.listFiles())); + } else { + throw new RuntimeException("The path doesn't exist: " + filePath); + } + } + + /** + * This method is used to detect folders in /sys/class/ + * + * @param filePath path + * @return boolean + */ + public static boolean existPath(final String filePath) { + if (log.isTraceEnabled()) { + log.trace("ls " + filePath); + } + final File f = new File(filePath); + return f.exists() && f.isDirectory(); + } + + public static boolean existFile(Path pathToFind) { + return Files.exists(pathToFind); + } + + /** + * Method to write bytes in a path + * + * @param path path + * @param value value to write + * @return Result + */ + public static boolean writeBytes(final String path, final byte[] value) { + try { + Files.write(Paths.get(path), value, StandardOpenOption.WRITE); + } catch (IOException e) { + throw new RuntimeException("Unable to draw the LCD", e); + } + return true; + } + +} diff --git a/src/test/java/ev3dev/utils/DataChannelRereader3ConcurrencyTest.java b/src/test/java/ev3dev/utils/DataChannelRereader3ConcurrencyTest.java new file mode 100644 index 00000000..6ca05fc7 --- /dev/null +++ b/src/test/java/ev3dev/utils/DataChannelRereader3ConcurrencyTest.java @@ -0,0 +1,129 @@ +package ev3dev.utils; + +import java.io.File; +import java.util.concurrent.CompletableFuture; +import java.util.stream.IntStream; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.junit.Before; +import org.junit.Test; + +import static org.assertj.core.api.BDDAssertions.then; + +@Slf4j +public class DataChannelRereader3ConcurrencyTest { + + final String fileName = "./pairs.txt"; + final String fileName2 = "./odds.txt"; + final Integer limit = 1000; + + @Before + @SneakyThrows + public void createFiles() { + new File(fileName).createNewFile(); + new File(fileName2).createNewFile(); + } + + private void readFile(String file, Boolean flag) { + Integer value = SysfsOld.readInteger(file); + if (flag) { + then(value % 2 == 0).isTrue(); + } else { + then(value % 2 != 0).isTrue(); + } + } + + private CompletableFuture asyncReadFile(boolean flag) { + CompletableFuture cf1 = CompletableFuture.supplyAsync(() -> { + IntStream + .rangeClosed(1, limit) + .forEach(i -> { + if (flag) { + readFile(fileName, flag); + } else { + readFile(fileName2, flag); + } + }); + return "Ok asyncReadFile"; + }) + .handle((input, exception) -> { + if (exception != null) { + LOGGER.warn(exception.getLocalizedMessage(), exception); + return "Ko asyncReadFile"; + } + return input; + }); + return cf1; + } + + private void writeFile(String file, String value) { + SysfsOld.writeString(file, value); + } + + private CompletableFuture asyncWriteFile(boolean flag) { + CompletableFuture cf = CompletableFuture.supplyAsync(() -> { + IntStream + .rangeClosed(1, limit) + .filter(i -> { + if (flag) { + return i % 2 == 0; + } else { + return i % 2 != 0; + } + }) + .forEach(i -> { + if (flag) { + writeFile(fileName, String.valueOf(i)); + } else { + writeFile(fileName2, String.valueOf(i)); + } + }); + return "Ok asyncWriteFile"; + }) + .handle((input, exception) -> { + if (exception != null) { + LOGGER.warn(exception.getLocalizedMessage(), exception); + return "Ko asyncWriteFile"; + } + return input; + }); + + return cf; + } + + /** + * Writer1 -> pairs.txt + * Reader1 <- pairs.txt + * + * Writer1 -> odds.txt + * Reader1 <- odds.txt + */ + @Test + public void given_multiple_SysfsOld_when_execute_concurrently_then_Ok2() { + + CompletableFuture request1 = asyncWriteFile(true); + CompletableFuture request2 = asyncWriteFile(false); + CompletableFuture request3 = asyncReadFile(true); + CompletableFuture request4 = asyncReadFile(false); + + CompletableFuture combinedFuture = CompletableFuture.allOf( + request1, + request2, + request3, + request4); + + combinedFuture.join(); + + then(request1.isDone()).isTrue(); + then(request2.isDone()).isTrue(); + then(request3.isDone()).isTrue(); + then(request4.isDone()).isTrue(); + + then(request1.join()).isEqualTo("Ok asyncWriteFile"); + then(request2.join()).isEqualTo("Ok asyncWriteFile"); + then(request3.join()).isEqualTo("Ok asyncReadFile"); + then(request4.join()).isEqualTo("Ok asyncReadFile"); + + System.out.println("End"); + } +} From d9b7e613f193fc10596a4331da49b48628be3758 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Antonio=20Bre=C3=B1a=20Moral?= Date: Wed, 30 Dec 2020 15:59:02 +0100 Subject: [PATCH 11/34] Adding a new test to verify one Writer & one Reader concurrently. --- .../DataChannelRereader3ConcurrencyTest.java | 28 ++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/src/test/java/ev3dev/utils/DataChannelRereader3ConcurrencyTest.java b/src/test/java/ev3dev/utils/DataChannelRereader3ConcurrencyTest.java index 6ca05fc7..96bbfb86 100644 --- a/src/test/java/ev3dev/utils/DataChannelRereader3ConcurrencyTest.java +++ b/src/test/java/ev3dev/utils/DataChannelRereader3ConcurrencyTest.java @@ -99,7 +99,7 @@ private CompletableFuture asyncWriteFile(boolean flag) { * Reader1 <- odds.txt */ @Test - public void given_multiple_SysfsOld_when_execute_concurrently_then_Ok2() { + public void given_multiple_SysfsOld_when_execute_concurrently_then_Ok() { CompletableFuture request1 = asyncWriteFile(true); CompletableFuture request2 = asyncWriteFile(false); @@ -126,4 +126,30 @@ public void given_multiple_SysfsOld_when_execute_concurrently_then_Ok2() { System.out.println("End"); } + + /** + * Writer1 -> pairs.txt + * Reader1 <- pairs.txt + * + */ + @Test + public void given_multiple_SysfsOld_when_execute_concurrently_then_Ok2() { + + CompletableFuture request1 = asyncWriteFile(true); + CompletableFuture request3 = asyncReadFile(true); + + CompletableFuture combinedFuture = CompletableFuture.allOf( + request1, + request3); + + combinedFuture.join(); + + then(request1.isDone()).isTrue(); + then(request3.isDone()).isTrue(); + + then(request1.join()).isEqualTo("Ok asyncWriteFile"); + then(request3.join()).isEqualTo("Ok asyncReadFile"); + + System.out.println("End"); + } } From db7b3736a4f099723c0d9c18ae9f2baa74ff670e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Antonio=20Bre=C3=B1a=20Moral?= Date: Wed, 30 Dec 2020 16:32:57 +0100 Subject: [PATCH 12/34] Adding new tests with write once and multiple concurrent read operations with different objects. --- .../DataChannelRereaderConcurrencyTest.java | 68 +++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/src/test/java/ev3dev/utils/DataChannelRereaderConcurrencyTest.java b/src/test/java/ev3dev/utils/DataChannelRereaderConcurrencyTest.java index 011fff8b..850e0920 100644 --- a/src/test/java/ev3dev/utils/DataChannelRereaderConcurrencyTest.java +++ b/src/test/java/ev3dev/utils/DataChannelRereaderConcurrencyTest.java @@ -205,4 +205,72 @@ public void given_multiple_DataChannelRereader_when_execute_concurrently_then_Ok System.out.println("End"); } + + /** + * Reader1 <- pairs.txt + * Reader1 <- odds.txt + */ + @Test + public void given_multiple_DataChannelRereader_when_execute_concurrently_then_Ok3() { + + writeFile(fileName, "2"); + writeFile(fileName2, "1"); + + CompletableFuture request1 = asyncReadFile(true); + CompletableFuture request2 = asyncReadFile(false); + + CompletableFuture combinedFuture = CompletableFuture.allOf( + request1, + request2); + + combinedFuture.join(); + + then(request1.isDone()).isTrue(); + then(request2.isDone()).isTrue(); + + then(request1.join()).isEqualTo("Ok asyncReadFile"); + then(request2.join()).isEqualTo("Ok asyncReadFile"); + + System.out.println("End"); + } + + /** + * Writer1 -> pairs.txt Once + * Writer1 -> odds.txt Once + * Reader1 <- pairs.txt + * Reader1 <- odds.txt + * Reader2 <- pairs.txt + * Reader2 <- odds.txt + */ + @Test + public void given_multiple_DataChannelRereader_when_execute_concurrently_then_Ok4() { + + writeFile(fileName, "2"); + writeFile(fileName2, "1"); + + CompletableFuture request1 = asyncReadFile(true); + CompletableFuture request2 = asyncReadFile(false); + CompletableFuture request3 = asyncReadFile2(true); + CompletableFuture request4 = asyncReadFile2(false); + + CompletableFuture combinedFuture = CompletableFuture.allOf( + request1, + request2, + request3, + request4); + + combinedFuture.join(); + + then(request1.isDone()).isTrue(); + then(request2.isDone()).isTrue(); + then(request3.isDone()).isTrue(); + then(request4.isDone()).isTrue(); + + then(request1.join()).isEqualTo("Ok asyncReadFile"); + then(request2.join()).isEqualTo("Ok asyncReadFile"); + then(request3.join()).isEqualTo("Ok asyncReadFile2"); + then(request4.join()).isEqualTo("Ok asyncReadFile2"); + + System.out.println("End"); + } } From 0f83777583584bb5b694d8c882a58aae8a327eff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Antonio=20Bre=C3=B1a=20Moral?= Date: Wed, 30 Dec 2020 16:37:00 +0100 Subject: [PATCH 13/34] Adding new tests with write once and multiple concurrent read operations with different objects. --- .../DataChannelRereader2ConcurrencyTest.java | 68 +++++++++++++++++++ .../DataChannelRereader3ConcurrencyTest.java | 68 +++++++++++++++++++ 2 files changed, 136 insertions(+) diff --git a/src/test/java/ev3dev/utils/DataChannelRereader2ConcurrencyTest.java b/src/test/java/ev3dev/utils/DataChannelRereader2ConcurrencyTest.java index 9797c264..5fcc1f97 100644 --- a/src/test/java/ev3dev/utils/DataChannelRereader2ConcurrencyTest.java +++ b/src/test/java/ev3dev/utils/DataChannelRereader2ConcurrencyTest.java @@ -205,4 +205,72 @@ public void given_multiple_DataChannelRereader_when_execute_concurrently_then_Ok System.out.println("End"); } + + /** + * Reader1 <- pairs.txt + * Reader1 <- odds.txt + */ + @Test + public void given_multiple_DataChannelRereader_when_execute_concurrently_then_Ok3() { + + writeFile(fileName, "2"); + writeFile(fileName2, "1"); + + CompletableFuture request1 = asyncReadFile(true); + CompletableFuture request2 = asyncReadFile(false); + + CompletableFuture combinedFuture = CompletableFuture.allOf( + request1, + request2); + + combinedFuture.join(); + + then(request1.isDone()).isTrue(); + then(request2.isDone()).isTrue(); + + then(request1.join()).isEqualTo("Ok asyncReadFile"); + then(request2.join()).isEqualTo("Ok asyncReadFile"); + + System.out.println("End"); + } + + /** + * Writer1 -> pairs.txt Once + * Writer1 -> odds.txt Once + * Reader1 <- pairs.txt + * Reader1 <- odds.txt + * Reader2 <- pairs.txt + * Reader2 <- odds.txt + */ + @Test + public void given_multiple_DataChannelRereader_when_execute_concurrently_then_Ok4() { + + writeFile(fileName, "2"); + writeFile(fileName2, "1"); + + CompletableFuture request1 = asyncReadFile(true); + CompletableFuture request2 = asyncReadFile(false); + CompletableFuture request3 = asyncReadFile2(true); + CompletableFuture request4 = asyncReadFile2(false); + + CompletableFuture combinedFuture = CompletableFuture.allOf( + request1, + request2, + request3, + request4); + + combinedFuture.join(); + + then(request1.isDone()).isTrue(); + then(request2.isDone()).isTrue(); + then(request3.isDone()).isTrue(); + then(request4.isDone()).isTrue(); + + then(request1.join()).isEqualTo("Ok asyncReadFile"); + then(request2.join()).isEqualTo("Ok asyncReadFile"); + then(request3.join()).isEqualTo("Ok asyncReadFile2"); + then(request4.join()).isEqualTo("Ok asyncReadFile2"); + + System.out.println("End"); + } } diff --git a/src/test/java/ev3dev/utils/DataChannelRereader3ConcurrencyTest.java b/src/test/java/ev3dev/utils/DataChannelRereader3ConcurrencyTest.java index 96bbfb86..19566040 100644 --- a/src/test/java/ev3dev/utils/DataChannelRereader3ConcurrencyTest.java +++ b/src/test/java/ev3dev/utils/DataChannelRereader3ConcurrencyTest.java @@ -152,4 +152,72 @@ public void given_multiple_SysfsOld_when_execute_concurrently_then_Ok2() { System.out.println("End"); } + + /** + * Reader1 <- pairs.txt + * Reader1 <- odds.txt + */ + @Test + public void given_multiple_DataChannelRereader_when_execute_concurrently_then_Ok3() { + + writeFile(fileName, "2"); + writeFile(fileName2, "1"); + + CompletableFuture request1 = asyncReadFile(true); + CompletableFuture request2 = asyncReadFile(false); + + CompletableFuture combinedFuture = CompletableFuture.allOf( + request1, + request2); + + combinedFuture.join(); + + then(request1.isDone()).isTrue(); + then(request2.isDone()).isTrue(); + + then(request1.join()).isEqualTo("Ok asyncReadFile"); + then(request2.join()).isEqualTo("Ok asyncReadFile"); + + System.out.println("End"); + } + + /** + * Writer1 -> pairs.txt Once + * Writer1 -> odds.txt Once + * Reader1 <- pairs.txt + * Reader1 <- odds.txt + * Reader2 <- pairs.txt + * Reader2 <- odds.txt + */ + @Test + public void given_multiple_DataChannelRereader_when_execute_concurrently_then_Ok4() { + + writeFile(fileName, "2"); + writeFile(fileName2, "1"); + + CompletableFuture request1 = asyncReadFile(true); + CompletableFuture request2 = asyncReadFile(false); + CompletableFuture request3 = asyncReadFile(true); + CompletableFuture request4 = asyncReadFile(false); + + CompletableFuture combinedFuture = CompletableFuture.allOf( + request1, + request2, + request3, + request4); + + combinedFuture.join(); + + then(request1.isDone()).isTrue(); + then(request2.isDone()).isTrue(); + then(request3.isDone()).isTrue(); + then(request4.isDone()).isTrue(); + + then(request1.join()).isEqualTo("Ok asyncReadFile"); + then(request2.join()).isEqualTo("Ok asyncReadFile"); + then(request3.join()).isEqualTo("Ok asyncReadFile"); + then(request4.join()).isEqualTo("Ok asyncReadFile"); + + System.out.println("End"); + } } From 1be575c10e9d5b29998f4a74d1844608f1c9acfd Mon Sep 17 00:00:00 2001 From: dwalend Date: Wed, 30 Dec 2020 12:08:48 -0500 Subject: [PATCH 14/34] flattened out that do/while loop that only ran once in DataChannelRereader --- .../java/ev3dev/utils/DataChannelRereader.java | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/main/java/ev3dev/utils/DataChannelRereader.java b/src/main/java/ev3dev/utils/DataChannelRereader.java index 291c035c..6a8388dd 100644 --- a/src/main/java/ev3dev/utils/DataChannelRereader.java +++ b/src/main/java/ev3dev/utils/DataChannelRereader.java @@ -50,15 +50,14 @@ public DataChannelRereader(String pathString) { */ public String readString() { try { - int n; - do { - byteBuffer.clear(); - channel.position(0); - n = channel.read(byteBuffer); - if (n == -1) { - throw new IOException("Premature end of file "); - } - } while (n <= 0); + byteBuffer.clear(); + channel.position(0); + int n = channel.read(byteBuffer); + if (n == -1) { + return ""; + } else if (n < -1) { + throw new RuntimeException("Unexpected read byte count of " + n + " while reading " + path); + } byte[] bytes = byteBuffer.array(); if (bytes[n - 1] == '\n') { From 63c5e7632ceb29368a94f6f219c9f98342104c74 Mon Sep 17 00:00:00 2001 From: dwalend Date: Wed, 30 Dec 2020 13:44:35 -0500 Subject: [PATCH 15/34] Cleaned out deprecation warnings associated with the EV3 LED --- src/main/java/ev3dev/actuators/ev3/EV3Led.java | 9 +++++++++ .../java/ev3dev/utils/DataChannelRewriter.java | 2 +- src/test/java/ev3dev/actuators/ev3/EV3LedTest.java | 14 +++++++------- 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/src/main/java/ev3dev/actuators/ev3/EV3Led.java b/src/main/java/ev3dev/actuators/ev3/EV3Led.java index f7d637e3..78ec0a83 100644 --- a/src/main/java/ev3dev/actuators/ev3/EV3Led.java +++ b/src/main/java/ev3dev/actuators/ev3/EV3Led.java @@ -24,7 +24,15 @@ public enum Direction { private static final Logger log = LoggerFactory.getLogger(EV3Led.class); + /** + * @deprecated Use EV3LedDirection.LEFT instead. + */ + @Deprecated public static final int LEFT = 0; + /** + * @deprecated Use EV3Led.Direction.RIGHT instead. + */ + @Deprecated public static final int RIGHT = 1; private final Direction direction; @@ -65,6 +73,7 @@ public EV3Led(final Direction direction) { * @throws RuntimeException if LED feature is not supported on the current platform. * @deprecated Use {@link #EV3Led(Direction)} instead. */ + @Deprecated public EV3Led(final int button) { checkPlatform(); diff --git a/src/main/java/ev3dev/utils/DataChannelRewriter.java b/src/main/java/ev3dev/utils/DataChannelRewriter.java index 20ed1761..44d7cdeb 100644 --- a/src/main/java/ev3dev/utils/DataChannelRewriter.java +++ b/src/main/java/ev3dev/utils/DataChannelRewriter.java @@ -33,7 +33,7 @@ public DataChannelRewriter(Path path, int bufferLength) { try { this.channel = FileChannel.open(path, StandardOpenOption.WRITE); } catch (IOException e) { - throw new RuntimeException("While opeing " + path,e); + throw new RuntimeException("While opening " + path,e); } } diff --git a/src/test/java/ev3dev/actuators/ev3/EV3LedTest.java b/src/test/java/ev3dev/actuators/ev3/EV3LedTest.java index b83351f2..ff9bae9a 100644 --- a/src/test/java/ev3dev/actuators/ev3/EV3LedTest.java +++ b/src/test/java/ev3dev/actuators/ev3/EV3LedTest.java @@ -35,7 +35,7 @@ public void constructorLeftTest() throws Exception { final FakeBattery fakeBattery = new FakeBattery(EV3DevPlatform.EV3BRICK); - LED led = new EV3Led(EV3Led.LEFT); + @SuppressWarnings("deprecation") LED led = new EV3Led(EV3Led.LEFT); led = new EV3Led(EV3Led.Direction.LEFT); } @@ -44,7 +44,7 @@ public void constructorRightTest() throws Exception { final FakeBattery fakeBattery = new FakeBattery(EV3DevPlatform.EV3BRICK); - LED led = new EV3Led(EV3Led.RIGHT); + @SuppressWarnings("deprecation") LED led = new EV3Led(EV3Led.RIGHT); led = new EV3Led(EV3Led.Direction.RIGHT); } @@ -56,7 +56,7 @@ public void usingLedOnEV3BrickPlatformTest() throws Exception { final FakeBattery fakeBattery = new FakeBattery(EV3DevPlatform.BRICKPI); - LED led = new EV3Led(EV3Led.LEFT); + LED led = new EV3Led(EV3Led.Direction.LEFT); } @Test @@ -66,7 +66,7 @@ public void badButtonTest() throws Exception { final FakeBattery fakeBattery = new FakeBattery(EV3DevPlatform.EV3BRICK); - LED led = new EV3Led(2); + LED led = new EV3Led(EV3Led.Direction.RIGHT); } @Test @@ -85,7 +85,7 @@ public void leftLedPatternsTest() throws Exception { final FakeBattery fakeBattery = new FakeBattery(EV3DevPlatform.EV3BRICK); final FakeLed fakeLed = new FakeLed(EV3DevPlatform.EV3BRICK); - LED led = new EV3Led(EV3Led.LEFT); + LED led = new EV3Led(EV3Led.Direction.LEFT); led.setPattern(1); led.setPattern(2); led.setPattern(3); @@ -104,7 +104,7 @@ public void rightLedPatternsTest() throws Exception { final FakeBattery fakeBattery = new FakeBattery(EV3DevPlatform.EV3BRICK); final FakeLed fakeLed = new FakeLed(EV3DevPlatform.EV3BRICK); - LED led = new EV3Led(EV3Led.RIGHT); + @SuppressWarnings("deprecation") LED led = new EV3Led(EV3Led.RIGHT); led.setPattern(1); led.setPattern(2); led.setPattern(3); @@ -123,7 +123,7 @@ public void getDirectionTest() throws Exception { final FakeBattery fakeBattery = new FakeBattery(EV3DevPlatform.EV3BRICK); final FakeLed fakeLed = new FakeLed(EV3DevPlatform.EV3BRICK); - EV3Led led = new EV3Led(EV3Led.RIGHT); + @SuppressWarnings("deprecation") EV3Led led = new EV3Led(EV3Led.RIGHT); Assert.assertEquals(EV3Led.Direction.RIGHT, led.getDirection()); led = new EV3Led(EV3Led.Direction.RIGHT); From 5afae87ec5f465dd3d31d50d0ca726e8d7e00e22 Mon Sep 17 00:00:00 2001 From: dwalend Date: Wed, 30 Dec 2020 14:25:19 -0500 Subject: [PATCH 16/34] Fixed bad value test --- src/test/java/ev3dev/actuators/ev3/EV3LedTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/ev3dev/actuators/ev3/EV3LedTest.java b/src/test/java/ev3dev/actuators/ev3/EV3LedTest.java index ff9bae9a..15fb9f28 100644 --- a/src/test/java/ev3dev/actuators/ev3/EV3LedTest.java +++ b/src/test/java/ev3dev/actuators/ev3/EV3LedTest.java @@ -66,7 +66,7 @@ public void badButtonTest() throws Exception { final FakeBattery fakeBattery = new FakeBattery(EV3DevPlatform.EV3BRICK); - LED led = new EV3Led(EV3Led.Direction.RIGHT); + LED led = new EV3Led(4); } @Test From 11c631cd3f5baf5761e7a5609df7a8edbf356bd2 Mon Sep 17 00:00:00 2001 From: dwalend Date: Wed, 30 Dec 2020 21:14:53 -0500 Subject: [PATCH 17/34] EV3Led as a first use of DataChannelRewriter --- .../java/ev3dev/actuators/ev3/EV3Led.java | 67 ++++++++++--------- .../ev3dev/utils/DataChannelRewriter.java | 4 +- .../java/ev3dev/actuators/ev3/EV3LedTest.java | 2 +- 3 files changed, 37 insertions(+), 36 deletions(-) diff --git a/src/main/java/ev3dev/actuators/ev3/EV3Led.java b/src/main/java/ev3dev/actuators/ev3/EV3Led.java index 78ec0a83..e54e2590 100644 --- a/src/main/java/ev3dev/actuators/ev3/EV3Led.java +++ b/src/main/java/ev3dev/actuators/ev3/EV3Led.java @@ -2,17 +2,20 @@ import ev3dev.hardware.EV3DevDevice; import ev3dev.hardware.EV3DevPlatform; -import ev3dev.utils.Sysfs; +import ev3dev.utils.DataChannelRewriter; import lejos.hardware.LED; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.io.Closeable; +import java.io.IOException; + /** * This class provides methods for interacting with the LEDs on the EV3Brick. * *

Only EV3Bricks are supported. */ -public class EV3Led extends EV3DevDevice implements LED { +public class EV3Led extends EV3DevDevice implements LED, Closeable { /** * Directions of the LED. @@ -21,6 +24,8 @@ public enum Direction { LEFT, RIGHT } + + private static final Direction[] directionArray = {Direction.LEFT,Direction.RIGHT}; private static final Logger log = LoggerFactory.getLogger(EV3Led.class); @@ -37,8 +42,8 @@ public enum Direction { private final Direction direction; - private final String LED_RED; - private final String LED_GREEN; + private final DataChannelRewriter redWriter; + private final DataChannelRewriter greenWriter; /** * Create an EV3LED object associated with the LED of the specified direction. @@ -58,11 +63,11 @@ public EV3Led(final Direction direction) { this.direction = direction; if (direction == Direction.LEFT) { - LED_RED = ev3DevProperties.getProperty("ev3.led.left.red"); - LED_GREEN = ev3DevProperties.getProperty("ev3.led.left.green"); + redWriter = new DataChannelRewriter(ev3DevProperties.getProperty("ev3.led.left.red")); + greenWriter = new DataChannelRewriter(ev3DevProperties.getProperty("ev3.led.left.green")); } else { - LED_RED = ev3DevProperties.getProperty("ev3.led.right.red"); - LED_GREEN = ev3DevProperties.getProperty("ev3.led.right.green"); + redWriter = new DataChannelRewriter(ev3DevProperties.getProperty("ev3.led.right.red")); + greenWriter = new DataChannelRewriter(ev3DevProperties.getProperty("ev3.led.right.green")); } } @@ -75,21 +80,7 @@ public EV3Led(final Direction direction) { */ @Deprecated public EV3Led(final int button) { - checkPlatform(); - - if (button == LEFT) { - LED_RED = ev3DevProperties.getProperty("ev3.led.left.red"); - LED_GREEN = ev3DevProperties.getProperty("ev3.led.left.green"); - direction = Direction.LEFT; - } else if (button == RIGHT) { - LED_RED = ev3DevProperties.getProperty("ev3.led.right.red"); - LED_GREEN = ev3DevProperties.getProperty("ev3.led.right.green"); - direction = Direction.RIGHT; - } else { - log.error("You are not specifying any button."); - throw new IllegalArgumentException("You are not specifying any button."); - } - + this(directionArray[button]); } /** @@ -105,7 +96,6 @@ private void checkPlatform() { } //TODO Add Enums for patterns - /** * Sets the pattern of light to be shown with this LED. * @@ -118,19 +108,22 @@ private void checkPlatform() { */ @Override public void setPattern(final int pattern) { - //Off + + final String off = Integer.toString(0); + final String on = Integer.toString(255); + if (pattern == 0) { - Sysfs.writeInteger(LED_RED, 0); - Sysfs.writeInteger(LED_GREEN, 0); + greenWriter.writeString(off); + redWriter.writeString(off); } else if (pattern == 1) { - Sysfs.writeInteger(LED_RED, 0); - Sysfs.writeInteger(LED_GREEN, 255); + greenWriter.writeString(on); + redWriter.writeString(off); } else if (pattern == 2) { - Sysfs.writeInteger(LED_RED, 255); - Sysfs.writeInteger(LED_GREEN, 0); + greenWriter.writeString(off); + redWriter.writeString(on); } else if (pattern == 3) { - Sysfs.writeInteger(LED_RED, 255); - Sysfs.writeInteger(LED_GREEN, 255); + greenWriter.writeString(on); + redWriter.writeString(on); } else if (pattern > 3) { log.debug("This feature is not implemented"); } @@ -144,4 +137,12 @@ public void setPattern(final int pattern) { public Direction getDirection() { return direction; } + + @Override + public void close() throws IOException { + greenWriter.close(); + redWriter.close(); + } + + } diff --git a/src/main/java/ev3dev/utils/DataChannelRewriter.java b/src/main/java/ev3dev/utils/DataChannelRewriter.java index 44d7cdeb..d4bfd0d8 100644 --- a/src/main/java/ev3dev/utils/DataChannelRewriter.java +++ b/src/main/java/ev3dev/utils/DataChannelRewriter.java @@ -49,7 +49,7 @@ public DataChannelRewriter(String pathString) { /** * @param string to write. A new line character */ - public void writeString(String string) { + public synchronized void writeString(String string) { try { byteBuffer.clear(); byteBuffer.put(string.getBytes(StandardCharsets.UTF_8)); @@ -69,7 +69,7 @@ public Path getPath() { } @Override - public void close() throws IOException { + public synchronized void close() throws IOException { channel.close(); } } diff --git a/src/test/java/ev3dev/actuators/ev3/EV3LedTest.java b/src/test/java/ev3dev/actuators/ev3/EV3LedTest.java index 15fb9f28..6d9048cd 100644 --- a/src/test/java/ev3dev/actuators/ev3/EV3LedTest.java +++ b/src/test/java/ev3dev/actuators/ev3/EV3LedTest.java @@ -66,7 +66,7 @@ public void badButtonTest() throws Exception { final FakeBattery fakeBattery = new FakeBattery(EV3DevPlatform.EV3BRICK); - LED led = new EV3Led(4); + @SuppressWarnings("deprecation") LED led = new EV3Led(4); } @Test From 5cd2ad81d11e40724b921205ca091dc7b781bbb0 Mon Sep 17 00:00:00 2001 From: dwalend Date: Wed, 30 Dec 2020 21:21:20 -0500 Subject: [PATCH 18/34] synchronized access to DataChannelRereader state-dependent methods and tightened up the readString method - Jakub's review comments --- src/main/java/ev3dev/utils/DataChannelRereader.java | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/main/java/ev3dev/utils/DataChannelRereader.java b/src/main/java/ev3dev/utils/DataChannelRereader.java index 6a8388dd..594da5da 100644 --- a/src/main/java/ev3dev/utils/DataChannelRereader.java +++ b/src/main/java/ev3dev/utils/DataChannelRereader.java @@ -48,11 +48,10 @@ public DataChannelRereader(String pathString) { /** * @return a string made from the bytes in the file; */ - public String readString() { + public synchronized String readString() { try { byteBuffer.clear(); - channel.position(0); - int n = channel.read(byteBuffer); + int n = channel.read(byteBuffer,0); if (n == -1) { return ""; } else if (n < -1) { @@ -70,8 +69,12 @@ public String readString() { } } + public Path getPath() { + return path; + } + @Override - public void close() throws IOException { + public synchronized void close() throws IOException { channel.close(); } } From c1b78979bd5d9dd4eb638b855153f2ec42fcb868 Mon Sep 17 00:00:00 2001 From: dwalend Date: Wed, 30 Dec 2020 21:27:40 -0500 Subject: [PATCH 19/34] 0 bytes read case should also be the empty string --- src/main/java/ev3dev/utils/DataChannelRereader.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/ev3dev/utils/DataChannelRereader.java b/src/main/java/ev3dev/utils/DataChannelRereader.java index 594da5da..4e1790ac 100644 --- a/src/main/java/ev3dev/utils/DataChannelRereader.java +++ b/src/main/java/ev3dev/utils/DataChannelRereader.java @@ -52,7 +52,7 @@ public synchronized String readString() { try { byteBuffer.clear(); int n = channel.read(byteBuffer,0); - if (n == -1) { + if ((n == -1)||(n == 0)) { return ""; } else if (n < -1) { throw new RuntimeException("Unexpected read byte count of " + n + " while reading " + path); From 9b47f5e427b7df1c1c39ed2a295c580ee7d68155 Mon Sep 17 00:00:00 2001 From: dwalend Date: Wed, 30 Dec 2020 21:33:49 -0500 Subject: [PATCH 20/34] cut/paste --- src/main/java/ev3dev/utils/DataChannelRewriter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/ev3dev/utils/DataChannelRewriter.java b/src/main/java/ev3dev/utils/DataChannelRewriter.java index d4bfd0d8..56fa9387 100644 --- a/src/main/java/ev3dev/utils/DataChannelRewriter.java +++ b/src/main/java/ev3dev/utils/DataChannelRewriter.java @@ -60,7 +60,7 @@ public synchronized void writeString(String string) { channel.truncate(byteBuffer.position()); channel.force(false); } catch (IOException e) { - throw new RuntimeException("Problem reading path: " + path, e); + throw new RuntimeException("Problem writing path: " + path, e); } } From 64a976ca32734a64d44b2542b51fd8986ce38e61 Mon Sep 17 00:00:00 2001 From: dwalend Date: Thu, 31 Dec 2020 10:54:32 -0500 Subject: [PATCH 21/34] Polisihing Battery --- src/main/java/ev3dev/sensors/Battery.java | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/main/java/ev3dev/sensors/Battery.java b/src/main/java/ev3dev/sensors/Battery.java index dd3fb619..0a959996 100644 --- a/src/main/java/ev3dev/sensors/Battery.java +++ b/src/main/java/ev3dev/sensors/Battery.java @@ -67,13 +67,13 @@ private Battery() { currentRereader = new DataChannelRereader(batteryPath + "/" + batteryEv3 + "/" + current); } - public int getVoltageMicroVolts() { + public int getVoltageMicroVolt() { return Integer.parseInt(voltageRereader.readString()); } @Override public int getVoltageMilliVolt() { - return getVoltageMicroVolts() / 1000; + return getVoltageMicroVolt() / 1000; } /** @@ -82,23 +82,21 @@ public int getVoltageMilliVolt() { * @return voltage */ public float getVoltage() { - return getVoltageMicroVolts() / 1000000f; + return getVoltageMicroVolt() / 1000000f; } //TODO Review output //TODO Review units /** - * Returns the current of the battery in amps. - * - * @return current + * @return current from the battery in amps, or Float.NaN if run on something other than EV3BRICK */ public float getBatteryCurrent() { if (CURRENT_PLATFORM.equals(EV3DevPlatform.EV3BRICK)) { return Float.parseFloat(currentRereader.readString()); } else { LOGGER.warn("This method is not available for {} & {}", EV3DevPlatform.PISTORMS, EV3DevPlatform.BRICKPI); - return -1f; + return Float.NaN; } } From 7f80fc51660e34e13f07b938d05ab35f57f28856 Mon Sep 17 00:00:00 2001 From: dwalend Date: Thu, 31 Dec 2020 10:57:51 -0500 Subject: [PATCH 22/34] Cleanup checkstyle --- src/main/java/ev3dev/sensors/Battery.java | 7 ++++--- src/main/java/ev3dev/utils/DataChannelRereader.java | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/main/java/ev3dev/sensors/Battery.java b/src/main/java/ev3dev/sensors/Battery.java index 0a959996..e55d5c7d 100644 --- a/src/main/java/ev3dev/sensors/Battery.java +++ b/src/main/java/ev3dev/sensors/Battery.java @@ -71,15 +71,16 @@ public int getVoltageMicroVolt() { return Integer.parseInt(voltageRereader.readString()); } + /** + * @return voltage of the battery in millivolts. + */ @Override public int getVoltageMilliVolt() { return getVoltageMicroVolt() / 1000; } /** - * Returns voltage of the battery in microvolts. - * - * @return voltage + * @return voltage of the battery in microvolts. */ public float getVoltage() { return getVoltageMicroVolt() / 1000000f; diff --git a/src/main/java/ev3dev/utils/DataChannelRereader.java b/src/main/java/ev3dev/utils/DataChannelRereader.java index 4e1790ac..36066091 100644 --- a/src/main/java/ev3dev/utils/DataChannelRereader.java +++ b/src/main/java/ev3dev/utils/DataChannelRereader.java @@ -52,7 +52,7 @@ public synchronized String readString() { try { byteBuffer.clear(); int n = channel.read(byteBuffer,0); - if ((n == -1)||(n == 0)) { + if ((n == -1) || (n == 0)) { return ""; } else if (n < -1) { throw new RuntimeException("Unexpected read byte count of " + n + " while reading " + path); From 5e34415bb412f258958bca7846f212396437714f Mon Sep 17 00:00:00 2001 From: dwalend Date: Thu, 31 Dec 2020 11:30:38 -0500 Subject: [PATCH 23/34] Review comments from Jakub --- src/main/java/ev3dev/utils/DataChannelRewriter.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/main/java/ev3dev/utils/DataChannelRewriter.java b/src/main/java/ev3dev/utils/DataChannelRewriter.java index 56fa9387..3a5a1f09 100644 --- a/src/main/java/ev3dev/utils/DataChannelRewriter.java +++ b/src/main/java/ev3dev/utils/DataChannelRewriter.java @@ -55,9 +55,8 @@ public synchronized void writeString(String string) { byteBuffer.put(string.getBytes(StandardCharsets.UTF_8)); byteBuffer.put(((byte)'\n')); byteBuffer.flip(); - channel.position(0); - channel.write(byteBuffer); - channel.truncate(byteBuffer.position()); + channel.truncate(0); + channel.write(byteBuffer,0); channel.force(false); } catch (IOException e) { throw new RuntimeException("Problem writing path: " + path, e); From 2710d070051b6c34c03ede0ace6840edca2fec8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Van=C4=9Bk?= Date: Wed, 30 Dec 2020 17:34:29 +0100 Subject: [PATCH 24/34] test: add reader-only race test --- .../utils/DataChannelRereader2RaceTest.java | 78 +++++++++++++++++++ .../utils/DataChannelRereaderRaceTest.java | 78 +++++++++++++++++++ 2 files changed, 156 insertions(+) create mode 100644 src/test/java/ev3dev/utils/DataChannelRereader2RaceTest.java create mode 100644 src/test/java/ev3dev/utils/DataChannelRereaderRaceTest.java diff --git a/src/test/java/ev3dev/utils/DataChannelRereader2RaceTest.java b/src/test/java/ev3dev/utils/DataChannelRereader2RaceTest.java new file mode 100644 index 00000000..34956171 --- /dev/null +++ b/src/test/java/ev3dev/utils/DataChannelRereader2RaceTest.java @@ -0,0 +1,78 @@ +package ev3dev.utils; + +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.junit.Before; +import org.junit.Test; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.concurrent.CompletableFuture; +import java.util.stream.IntStream; + +import static org.assertj.core.api.BDDAssertions.then; + +@Slf4j +public class DataChannelRereader2RaceTest { + + final String fileName = "./race2.txt"; + final Integer limit = 10000; + + @Before + @SneakyThrows + public void createFiles() throws IOException { + Files.writeString(Path.of(fileName), "test1234"); + } + + /** + * Reader1 <- race.txt + * Reader2 <- race.txt + * Reader3 <- race.txt + * Reader4 <- race.txt + */ + @Test + public void given_multiple_DataChannelRereader_when_execute_concurrently_then_Ok() { + DataChannelRereader2 reader = new DataChannelRereader2(fileName); + + CompletableFuture rq1 = asyncReadFile(reader); + CompletableFuture rq2 = asyncReadFile(reader); + CompletableFuture rq3 = asyncReadFile(reader); + CompletableFuture rq4 = asyncReadFile(reader); + + CompletableFuture combinedFuture = CompletableFuture.allOf(rq1, rq2, rq3, rq4); + combinedFuture.join(); + + then(rq1.isDone()).isTrue(); + then(rq2.isDone()).isTrue(); + then(rq3.isDone()).isTrue(); + then(rq4.isDone()).isTrue(); + + then(rq1.join()).isEqualTo("Ok asyncReadFile"); + then(rq2.join()).isEqualTo("Ok asyncReadFile"); + then(rq3.join()).isEqualTo("Ok asyncReadFile"); + then(rq4.join()).isEqualTo("Ok asyncReadFile"); + System.out.println("End"); + } + + private void readFile(DataChannelRereader2 reader) { + then(reader.readString()).isEqualTo("test1234"); + } + + private CompletableFuture asyncReadFile(DataChannelRereader2 reader) { + CompletableFuture cf1 = CompletableFuture.supplyAsync(() -> { + IntStream + .rangeClosed(1, limit) + .forEach(i -> readFile(reader)); + return "Ok asyncReadFile"; + }) + .handle((input, exception) -> { + if (exception != null) { + LOGGER.warn(exception.getLocalizedMessage(), exception); + return "Ko asyncReadFile"; + } + return input; + }); + return cf1; + } +} diff --git a/src/test/java/ev3dev/utils/DataChannelRereaderRaceTest.java b/src/test/java/ev3dev/utils/DataChannelRereaderRaceTest.java new file mode 100644 index 00000000..1df8adcd --- /dev/null +++ b/src/test/java/ev3dev/utils/DataChannelRereaderRaceTest.java @@ -0,0 +1,78 @@ +package ev3dev.utils; + +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.junit.Before; +import org.junit.Test; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.concurrent.CompletableFuture; +import java.util.stream.IntStream; + +import static org.assertj.core.api.BDDAssertions.then; + +@Slf4j +public class DataChannelRereaderRaceTest { + + final String fileName = "./race.txt"; + final Integer limit = 10000; + + @Before + @SneakyThrows + public void createFiles() throws IOException { + Files.writeString(Path.of(fileName), "test1234"); + } + + /** + * Reader1 <- race.txt + * Reader2 <- race.txt + * Reader3 <- race.txt + * Reader4 <- race.txt + */ + @Test + public void given_multiple_DataChannelRereader_when_execute_concurrently_then_Ok() { + DataChannelRereader reader = new DataChannelRereader(fileName); + + CompletableFuture rq1 = asyncReadFile(reader); + CompletableFuture rq2 = asyncReadFile(reader); + CompletableFuture rq3 = asyncReadFile(reader); + CompletableFuture rq4 = asyncReadFile(reader); + + CompletableFuture combinedFuture = CompletableFuture.allOf(rq1, rq2, rq3, rq4); + combinedFuture.join(); + + then(rq1.isDone()).isTrue(); + then(rq2.isDone()).isTrue(); + then(rq3.isDone()).isTrue(); + then(rq4.isDone()).isTrue(); + + then(rq1.join()).isEqualTo("Ok asyncReadFile"); + then(rq2.join()).isEqualTo("Ok asyncReadFile"); + then(rq3.join()).isEqualTo("Ok asyncReadFile"); + then(rq4.join()).isEqualTo("Ok asyncReadFile"); + System.out.println("End"); + } + + private void readFile(DataChannelRereader reader) { + then(reader.readString()).isEqualTo("test1234"); + } + + private CompletableFuture asyncReadFile(DataChannelRereader reader) { + CompletableFuture cf1 = CompletableFuture.supplyAsync(() -> { + IntStream + .rangeClosed(1, limit) + .forEach(i -> readFile(reader)); + return "Ok asyncReadFile"; + }) + .handle((input, exception) -> { + if (exception != null) { + LOGGER.warn(exception.getLocalizedMessage(), exception); + return "Ko asyncReadFile"; + } + return input; + }); + return cf1; + } +} From f356d8b186bce6e09817417aa0365eaaed82d6fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Van=C4=9Bk?= Date: Wed, 30 Dec 2020 16:51:57 +0100 Subject: [PATCH 25/34] fix: do not crash DataChannelRereaders when empty file is encountered --- src/main/java/ev3dev/utils/DataChannelRereader2.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/main/java/ev3dev/utils/DataChannelRereader2.java b/src/main/java/ev3dev/utils/DataChannelRereader2.java index 61ab4878..3f747006 100644 --- a/src/main/java/ev3dev/utils/DataChannelRereader2.java +++ b/src/main/java/ev3dev/utils/DataChannelRereader2.java @@ -90,17 +90,18 @@ public String readString() { // try to do the read // only one try, as: // - value >0 indicates success - // - value =0 does not tell us much, as there's a possibility of reading an empty attribute - // - value <0 indicates failure + // - value =0 indicates empty attribute (???) + // - value <0 indicates empty attribute int n = channel.read(buffer, 0); - if (n == -1) { - throw new IOException("Premature end of file " + path); + // minus one reliably occurs on empty file, zero should be similar + if (n <= 0) { + return ""; } // strip trailing newline & return data as a string // rationale: ev3dev sysfs often appends \n, but this breaks parseFloat/parseInt/... byte[] bytes = buffer.array(); - if (n > 0 && bytes[n - 1] == '\n') { + if (bytes[n - 1] == '\n') { return new String(bytes, 0, n - 1, StandardCharsets.UTF_8); } else { return new String(bytes, 0, n, StandardCharsets.UTF_8); From b5be41bbf4e96453bb9c6e11427be5db63abb8e6 Mon Sep 17 00:00:00 2001 From: dwalend Date: Thu, 31 Dec 2020 14:27:41 -0500 Subject: [PATCH 26/34] Formatting fix --- src/main/java/ev3dev/utils/DataChannelRereader.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/ev3dev/utils/DataChannelRereader.java b/src/main/java/ev3dev/utils/DataChannelRereader.java index 4e1790ac..36066091 100644 --- a/src/main/java/ev3dev/utils/DataChannelRereader.java +++ b/src/main/java/ev3dev/utils/DataChannelRereader.java @@ -52,7 +52,7 @@ public synchronized String readString() { try { byteBuffer.clear(); int n = channel.read(byteBuffer,0); - if ((n == -1)||(n == 0)) { + if ((n == -1) || (n == 0)) { return ""; } else if (n < -1) { throw new RuntimeException("Unexpected read byte count of " + n + " while reading " + path); From 26f07447ea34f9a493881257aeb11482614df893 Mon Sep 17 00:00:00 2001 From: dwalend Date: Thu, 31 Dec 2020 15:38:22 -0500 Subject: [PATCH 27/34] Added tests for DataChannelRereaderTest --- .../ev3dev/utils/DataChannelRereaderTest.java | 83 +++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 src/test/java/ev3dev/utils/DataChannelRereaderTest.java diff --git a/src/test/java/ev3dev/utils/DataChannelRereaderTest.java b/src/test/java/ev3dev/utils/DataChannelRereaderTest.java new file mode 100644 index 00000000..e8ec33bc --- /dev/null +++ b/src/test/java/ev3dev/utils/DataChannelRereaderTest.java @@ -0,0 +1,83 @@ +package ev3dev.utils; + +import lombok.SneakyThrows; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import java.nio.file.Files; +import java.nio.file.Path; + +import static org.junit.Assert.assertEquals; + +/** + * Some tests of DataChannelRereader. + * + * @author David Walend + */ +public class DataChannelRereaderTest { + + static Path tempDirectory; + static Path testPath; + static final String testString = "Written String"; + static final String differentTestString = "Different String"; + + @Before + @SneakyThrows + public void createFiles() { + tempDirectory = Files.createTempDirectory("DataChannelRereaderTest"); + testPath = Files.createFile(Path.of(tempDirectory.toString(),"testFile")); + Files.write(testPath, testString.getBytes()); + } + + @After + @SneakyThrows + public void cleanupFiles() { + Files.delete(testPath); + Files.delete(tempDirectory); + } + + + @Test + @SneakyThrows + public void testOpenClose() { + DataChannelRereader rereader = new DataChannelRereader(testPath,32); + rereader.close(); + } + + @Test + @SneakyThrows + public void testOpenReadClose() { + DataChannelRereader rereader = new DataChannelRereader(testPath,32); + String readString = rereader.readString(); + rereader.close(); + + assertEquals(testString,readString); + } + + @Test + @SneakyThrows + public void testClosable() { + try(DataChannelRereader rereader = new DataChannelRereader(testPath,32)){ + String readString = rereader.readString(); + assertEquals(testString,readString); + } + } + + @Test + @SneakyThrows + public void testOpenReadTwoThingsClose() { + DataChannelRereader rereader = new DataChannelRereader(testPath,32); + String readString = rereader.readString(); + assertEquals(testString,readString); + + Files.write(testPath, differentTestString.getBytes()); + + String readString2 = rereader.readString(); + assertEquals(differentTestString,readString2); + + rereader.close(); + } + + +} From b8ceb7438e2505414c931362932e72f6378ee876 Mon Sep 17 00:00:00 2001 From: dwalend Date: Fri, 1 Jan 2021 18:47:47 -0500 Subject: [PATCH 28/34] Test for trouble opening a non-existant file --- src/test/java/ev3dev/utils/DataChannelRereaderTest.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/test/java/ev3dev/utils/DataChannelRereaderTest.java b/src/test/java/ev3dev/utils/DataChannelRereaderTest.java index e8ec33bc..48c2d365 100644 --- a/src/test/java/ev3dev/utils/DataChannelRereaderTest.java +++ b/src/test/java/ev3dev/utils/DataChannelRereaderTest.java @@ -79,5 +79,12 @@ public void testOpenReadTwoThingsClose() { rereader.close(); } + @Test(expected = RuntimeException.class) + @SneakyThrows + public void testOpenNonexistantFile() { + Path badPath = Path.of("/does/not/exist"); + DataChannelRereader rereader = new DataChannelRereader(badPath,32); + rereader.close(); + } } From 40bc3fe7d50c130150903be4f561c885c5989c90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Antonio=20Bre=C3=B1a=20Moral?= Date: Tue, 5 Jan 2021 18:34:26 +0100 Subject: [PATCH 29/34] Adding performance Tests and a test to review DataChannelRereader with JMC --- build.gradle | 9 +- config/checkstyle/suppressions.xml | 2 + docs/performance/jmh-results.json | 3810 +++++++++++++++++ gradle/deploy.gradle | 4 +- src/main/java/ev3dev/sensors/Battery2.java | 116 + src/main/java/ev3dev/sensors/BatteryOld.java | 110 + .../java/ev3dev/utils/BatteryBenchmark.java | 35 + .../ev3dev/utils/BatteryBenchmarkProgram.java | 375 ++ .../ev3dev/utils/DataChannelRereader.java | 2 +- .../utils/DataChannelRereaderJMCTest.java | 77 + src/main/resources/META-INF/MANIFEST.MF | 1 + src/main/resources/logback.xml | 23 + src/main/resources/simplelogger.properties | 18 + .../DataChannelRereader2ConcurrencyTest.java | 3 + .../DataChannelRereader3ConcurrencyTest.java | 3 + .../DataChannelRereaderConcurrencyTest.java | 3 + .../java/ev3dev/utils/SysfsOldRaceTest.java | 78 + src/test/resources/simplelogger.properties | 18 + 18 files changed, 4683 insertions(+), 4 deletions(-) create mode 100644 docs/performance/jmh-results.json create mode 100644 src/main/java/ev3dev/sensors/Battery2.java create mode 100644 src/main/java/ev3dev/sensors/BatteryOld.java create mode 100644 src/main/java/ev3dev/utils/BatteryBenchmark.java create mode 100644 src/main/java/ev3dev/utils/BatteryBenchmarkProgram.java create mode 100644 src/main/java/ev3dev/utils/DataChannelRereaderJMCTest.java create mode 100644 src/main/resources/logback.xml create mode 100644 src/main/resources/simplelogger.properties create mode 100644 src/test/java/ev3dev/utils/SysfsOldRaceTest.java create mode 100644 src/test/resources/simplelogger.properties diff --git a/build.gradle b/build.gradle index 1c3ba8d6..60cdc980 100644 --- a/build.gradle +++ b/build.gradle @@ -39,7 +39,9 @@ dependencies { api("com.github.ev3dev-lang-java:lejos-commons:0.7.3") api("net.java.dev.jna:jna:4.5.2") - testImplementation("ch.qos.logback:logback-classic:1.2.3") + implementation("org.slf4j:slf4j-simple:1.7.25") + + //testImplementation("ch.qos.logback:logback-classic:1.2.3") testImplementation("commons-io:commons-io:2.5") //TODO: Upgrade to JUnit 5 @@ -47,6 +49,11 @@ dependencies { //TODO: Review to add Mockito support testImplementation("org.hamcrest:hamcrest-all:1.3") testImplementation("org.assertj:assertj-core:3.18.1") + + //TODO: Later this dependencies will be for test only testImplementation + api("org.openjdk.jmh:jmh-core:1.26") + annotationProcessor("org.openjdk.jmh:jmh-generator-annprocess:1.26") + } compileJava.options.encoding = 'UTF-8' diff --git a/config/checkstyle/suppressions.xml b/config/checkstyle/suppressions.xml index 240819b4..698c67a6 100644 --- a/config/checkstyle/suppressions.xml +++ b/config/checkstyle/suppressions.xml @@ -30,6 +30,7 @@ |.*/EV3IRSensor.java| |.*/EV3Key.java| |.*/Battery.java| + |.*/BatteryOld.java| |.*/BaseRegulatedMotor.java| |.*/RGBFramebufferProvider.java" /> https://www.kernel.org/doc/Documentation/power/power_supply_class.txt + * @see https://github.com/ev3dev/ev3dev-lang/blob/develop/wrapper-specification.md#direct-attribute-mappings-5 + */ +@Slf4j +public class Battery2 extends EV3DevDevice implements Power, Closeable { + + private final DataChannelRereader2 voltageRereader; + private final DataChannelRereader2 currentRereader; + + private static Battery2 instance; + + /** + * Get a singleton Battery object + * + * @return Battery + */ + public static Battery2 getInstance() { + //TODO Refactor + if (instance == null) { + instance = new Battery2(); + } + return instance; + } + + // Prevent duplicate objects + private Battery2() { + + LOGGER.debug("Init sensor"); + + String battery = ev3DevProperties.getProperty("battery"); + String batteryEv3 = ev3DevProperties.getProperty("ev3.battery"); + String batteryPistorms = ev3DevProperties.getProperty("pistorms.battery"); + String batteryBrickpi = ev3DevProperties.getProperty("brickpi.battery"); + String batteryBrickpi3 = ev3DevProperties.getProperty("brickpi3.battery"); + + //TODO Create separator variable for the whole project + String batteryPath = EV3DevFileSystem.getRootPath() + "/" + battery; + String batteryPathLocal = ""; + if (CURRENT_PLATFORM.equals(EV3DevPlatform.EV3BRICK)) { + batteryPathLocal += batteryPath + "/" + batteryEv3; + } else if (CURRENT_PLATFORM.equals(EV3DevPlatform.PISTORMS)) { + batteryPathLocal += batteryPath + "/" + batteryPistorms; + } else if (CURRENT_PLATFORM.equals(EV3DevPlatform.BRICKPI)) { + batteryPathLocal += batteryPath + "/" + batteryBrickpi; + } else if (CURRENT_PLATFORM.equals(EV3DevPlatform.BRICKPI3)) { + batteryPathLocal += batteryPath + "/" + batteryBrickpi3; + } + String voltage = "voltage_now"; + voltageRereader = new DataChannelRereader2(batteryPathLocal + "/" + voltage); + String current = "current_now"; + currentRereader = new DataChannelRereader2(batteryPath + "/" + batteryEv3 + "/" + current); + } + + public int getVoltageMicroVolts() { + return Integer.parseInt(voltageRereader.readString()); + } + + @Override + public int getVoltageMilliVolt() { + return getVoltageMicroVolts() / 1000; + } + + /** + * Returns voltage of the battery in microvolts. + * + * @return voltage + */ + public float getVoltage() { + return getVoltageMicroVolts() / 1000000f; + } + + //TODO Review output + //TODO Review units + + /** + * Returns the current of the battery in amps. + * + * @return current + */ + public float getBatteryCurrent() { + if (CURRENT_PLATFORM.equals(EV3DevPlatform.EV3BRICK)) { + return Float.parseFloat(currentRereader.readString()); + } else { + LOGGER.warn("This method is not available for {} & {}", EV3DevPlatform.PISTORMS, EV3DevPlatform.BRICKPI); + return -1f; + } + } + + //TODO Review this method in the future. + @Override + public float getMotorCurrent() { + throw new UnsupportedOperationException("This feature is not implemented"); + } + + @Override + public void close() throws IOException { + voltageRereader.close(); + currentRereader.close(); + } +} diff --git a/src/main/java/ev3dev/sensors/BatteryOld.java b/src/main/java/ev3dev/sensors/BatteryOld.java new file mode 100644 index 00000000..02a74753 --- /dev/null +++ b/src/main/java/ev3dev/sensors/BatteryOld.java @@ -0,0 +1,110 @@ +package ev3dev.sensors; + +import ev3dev.hardware.EV3DevDevice; +import ev3dev.hardware.EV3DevFileSystem; +import ev3dev.hardware.EV3DevPlatform; +import ev3dev.utils.Sysfs; +import lejos.hardware.Power; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * The class Battery interacts with EV3Dev to get information about battery used. + * + * @author Juan Antonio Breña Moral + * @see https://www.kernel.org/doc/Documentation/power/power_supply_class.txt + * @see https://github.com/ev3dev/ev3dev-lang/blob/develop/wrapper-specification.md#direct-attribute-mappings-5 + */ +public class BatteryOld extends EV3DevDevice implements Power { + + private static final Logger LOGGER = LoggerFactory.getLogger(Battery.class); + + private final String BATTERY; + private final String BATTERY_EV3; + private final String BATTERY_PISTORMS; + private final String BATTERY_BRICKPI; + private final String BATTERY_BRICKPI3; + + private String BATTERY_PATH; + private final String VOLTAGE = "voltage_now"; + private final String CURRENT = "current_now"; + + private String BATTERY_PATH_LOCAL = ""; + + private static BatteryOld instance; + + /** + * Get a singleton Battery object + * + * @return Battery + */ + public static BatteryOld getInstance() { + //TODO Refactor + if (instance == null) { + instance = new BatteryOld(); + } + return instance; + } + + // Prevent duplicate objects + private BatteryOld() { + + LOGGER.debug("Init sensor"); + + BATTERY = ev3DevProperties.getProperty("battery"); + BATTERY_EV3 = ev3DevProperties.getProperty("ev3.battery"); + BATTERY_PISTORMS = ev3DevProperties.getProperty("pistorms.battery"); + BATTERY_BRICKPI = ev3DevProperties.getProperty("brickpi.battery"); + BATTERY_BRICKPI3 = ev3DevProperties.getProperty("brickpi3.battery"); + + //TODO Create separator variable for the whole project + BATTERY_PATH = EV3DevFileSystem.getRootPath() + "/" + BATTERY; + if (CURRENT_PLATFORM.equals(EV3DevPlatform.EV3BRICK)) { + BATTERY_PATH_LOCAL += BATTERY_PATH + "/" + BATTERY_EV3; + } else if (CURRENT_PLATFORM.equals(EV3DevPlatform.PISTORMS)) { + BATTERY_PATH_LOCAL += BATTERY_PATH + "/" + BATTERY_PISTORMS; + } else if (CURRENT_PLATFORM.equals(EV3DevPlatform.BRICKPI)) { + BATTERY_PATH_LOCAL += BATTERY_PATH + "/" + BATTERY_BRICKPI; + } else if (CURRENT_PLATFORM.equals(EV3DevPlatform.BRICKPI3)) { + BATTERY_PATH_LOCAL += BATTERY_PATH + "/" + BATTERY_BRICKPI3; + } + } + + @Override + public int getVoltageMilliVolt() { + return (int) Sysfs.readFloat(BATTERY_PATH_LOCAL + "/" + VOLTAGE) / 1000; + } + + /** + * Returns voltage of the battery in microvolts. + * + * @return voltage + */ + public float getVoltage() { + return Sysfs.readFloat(BATTERY_PATH_LOCAL + "/" + VOLTAGE) / 1000000; + } + + //TODO Review output + //TODO Review units + + /** + * Returns the current of the battery in amps. + * + * @return current + */ + public float getBatteryCurrent() { + if (CURRENT_PLATFORM.equals(EV3DevPlatform.EV3BRICK)) { + return Sysfs.readFloat(BATTERY_PATH + "/" + BATTERY_EV3 + "/" + CURRENT); + } else { + LOGGER.warn("This method is not available for {} & {}", EV3DevPlatform.PISTORMS, EV3DevPlatform.BRICKPI); + return -1f; + } + } + + //TODO Review this method in the future. + @Override + public float getMotorCurrent() { + throw new UnsupportedOperationException("This feature is not implemented"); + } + +} diff --git a/src/main/java/ev3dev/utils/BatteryBenchmark.java b/src/main/java/ev3dev/utils/BatteryBenchmark.java new file mode 100644 index 00000000..f8572e40 --- /dev/null +++ b/src/main/java/ev3dev/utils/BatteryBenchmark.java @@ -0,0 +1,35 @@ +package ev3dev.utils; + +import ev3dev.sensors.Battery; +import ev3dev.sensors.Battery2; +import ev3dev.sensors.BatteryOld; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.infra.Blackhole; + +public class BatteryBenchmark { + + @State(Scope.Thread) + public static class St { + Battery battery = Battery.getInstance(); + Battery2 battery2 = Battery2.getInstance(); + BatteryOld batteryOld = BatteryOld.getInstance(); + } + + @Benchmark + public void batteryOldMethod(St state, Blackhole b) { + b.consume(state.batteryOld.getVoltage()); + } + + @Benchmark + public void batteryMethod(St state, Blackhole b) { + b.consume(state.battery.getVoltage()); + } + + @Benchmark + public void battery2Method(St state, Blackhole b) { + b.consume(state.battery2.getVoltage()); + } + +} diff --git a/src/main/java/ev3dev/utils/BatteryBenchmarkProgram.java b/src/main/java/ev3dev/utils/BatteryBenchmarkProgram.java new file mode 100644 index 00000000..7766aa28 --- /dev/null +++ b/src/main/java/ev3dev/utils/BatteryBenchmarkProgram.java @@ -0,0 +1,375 @@ +package ev3dev.utils; + +import java.util.concurrent.TimeUnit; + +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.profile.GCProfiler; +import org.openjdk.jmh.profile.StackProfiler; +import org.openjdk.jmh.results.format.ResultFormatType; +import org.openjdk.jmh.runner.Runner; +import org.openjdk.jmh.runner.options.Options; +import org.openjdk.jmh.runner.options.OptionsBuilder; +import org.openjdk.jmh.runner.options.TimeValue; +import org.openjdk.jmh.runner.options.VerboseMode; + +/** + * BatteryBenchmarkProgram + */ +public class BatteryBenchmarkProgram { + + /** + * Main program + * + * @param args args + * @throws Exception ex + */ + public static void main(String[] args) throws Exception { + + Options options = new OptionsBuilder() + .include(BatteryBenchmark.class.getSimpleName()) + + .resultFormat(ResultFormatType.JSON) + .result("/home/robot/jmh-results.json") + .verbosity(VerboseMode.EXTRA) + .mode(Mode.All) + .timeUnit(TimeUnit.MILLISECONDS) + .warmupTime(TimeValue.seconds(0)) + .measurementTime(TimeValue.milliseconds(1)) + .measurementIterations(10) + .threads(Runtime.getRuntime().availableProcessors()) + .warmupIterations(1) + .shouldFailOnError(false) + .shouldDoGC(true) + .forks(2) + .jvmArgs("-Xmx64m", "-Xms64m", "-XX:+UseSerialGC", "-noverify") + .addProfiler(StackProfiler.class) + .addProfiler(GCProfiler.class) + //.addProfiler(LinuxPerfProfiler.class) + //.addProfiler(ClassloaderProfiler.class) + //.addProfiler(CompilerProfiler.class) + //.addProfiler(JmhFlightRecorderProfiler.class) + .build(); + + new Runner(options).run(); + } + +} + +/** + * Benchmark Mode Cnt Score Error Units + * Sysfs_ExistFile_Benchmark.Sysfs2 avgt 10 15.592 ? 27.924 ms/op + * Sysfs_ExistFile_Benchmark.SysfsJNA avgt 10 12.340 ? 8.758 ms/op + * Sysfs_ExistFile_Benchmark.SysfsJNA2 avgt 10 10.810 ? 7.733 ms/op + * Sysfs_ExistFile_Benchmark.SysfsJNA3 avgt 10 8.605 ? 3.080 ms/op + * Sysfs_ExistFile_Benchmark.SysfsOriginal avgt 10 10.002 ? 20.725 ms/op + * Sysfs_existPath_Benchmark.Sysfs2 avgt 10 49.480 ? 46.960 ms/op + * Sysfs_existPath_Benchmark.SysfsJNA avgt 10 46.822 ? 13.254 ms/op + * Sysfs_existPath_Benchmark.SysfsJNA2 avgt 10 42.022 ? 19.543 ms/op + * Sysfs_existPath_Benchmark.SysfsOriginal avgt 10 42.520 ? 27.847 ms/op + * Sysfs_readString_Benchmark.SysfsJNA avgt 10 69.320 ? 22.873 ms/op + * Sysfs_readString_Benchmark.SysfsJNA2 avgt 10 83.479 ? 36.463 ms/op + * Sysfs_readString_Benchmark.SysfsJNA3 avgt 10 89.231 ? 58.068 ms/op + * Sysfs_readString_Benchmark.SysfsOriginal avgt 10 78.398 ? 16.224 ms/op + * Sysfs_writeInteger_Benchmark.Sysfs2 avgt 10 44.641 ? 31.890 ms/op + * Sysfs_writeInteger_Benchmark.SysfsJNA avgt 10 38.574 ? 12.712 ms/op + * Sysfs_writeInteger_Benchmark.SysfsJNA2 avgt 10 36.952 ? 9.491 ms/op + * Sysfs_writeInteger_Benchmark.SysfsJNA3 avgt 10 37.658 ? 13.754 ms/op + * Sysfs_writeInteger_Benchmark.SysfsOriginal avgt 10 41.258 ? 11.446 ms/op + * Sysfs_writeString_Benchmark.Sysfs2 avgt 10 42.764 ? 17.031 ms/op + * Sysfs_writeString_Benchmark.SysfsJNA avgt 10 34.404 ? 6.775 ms/op + * Sysfs_writeString_Benchmark.SysfsJNA2 avgt 10 37.501 ? 6.310 ms/op + * Sysfs_writeString_Benchmark.SysfsJNA3 avgt 10 36.704 ? 30.766 ms/op + * Sysfs_writeString_Benchmark.SysfsOriginal avgt 10 37.589 ? 11.072 ms/op + */ + +/** + Benchmark Mode Cnt Score Error Units + Sysfs_ExistFile_Benchmark.Sysfs2 avgt 20 8.876 ? 7.415 ms/op + Sysfs_ExistFile_Benchmark.Sysfs2:?gc.alloc.rate avgt 20 NaN MB/sec + Sysfs_ExistFile_Benchmark.Sysfs2:?gc.count avgt 20 ? 0 counts + Sysfs_ExistFile_Benchmark.Sysfs2:?stack avgt NaN --- + Sysfs_ExistFile_Benchmark.SysfsJNA avgt 20 17.467 ? 14.597 ms/op + Sysfs_ExistFile_Benchmark.SysfsJNA:?gc.alloc.rate avgt 20 NaN MB/sec + Sysfs_ExistFile_Benchmark.SysfsJNA:?gc.count avgt 20 ? 0 counts + Sysfs_ExistFile_Benchmark.SysfsJNA:?stack avgt NaN --- + Sysfs_ExistFile_Benchmark.SysfsJNA2 avgt 20 19.286 ? 12.194 ms/op + Sysfs_ExistFile_Benchmark.SysfsJNA2:?gc.alloc.rate avgt 20 NaN MB/sec + Sysfs_ExistFile_Benchmark.SysfsJNA2:?gc.count avgt 20 ? 0 counts + Sysfs_ExistFile_Benchmark.SysfsJNA2:?stack avgt NaN --- + Sysfs_ExistFile_Benchmark.SysfsJNA3 avgt 20 21.299 ? 25.011 ms/op + Sysfs_ExistFile_Benchmark.SysfsJNA3:?gc.alloc.rate avgt 20 NaN MB/sec + Sysfs_ExistFile_Benchmark.SysfsJNA3:?gc.count avgt 20 ? 0 counts + Sysfs_ExistFile_Benchmark.SysfsJNA3:?stack avgt NaN --- + Sysfs_ExistFile_Benchmark.SysfsOriginal avgt 20 12.838 ? 15.249 ms/op + Sysfs_ExistFile_Benchmark.SysfsOriginal:?gc.alloc.rate avgt 20 NaN MB/sec + Sysfs_ExistFile_Benchmark.SysfsOriginal:?gc.count avgt 20 ? 0 counts + Sysfs_ExistFile_Benchmark.SysfsOriginal:?stack avgt NaN --- + Sysfs_existPath_Benchmark.Sysfs2 avgt 20 46.367 ? 8.729 ms/op + Sysfs_existPath_Benchmark.Sysfs2:?gc.alloc.rate avgt 20 NaN MB/sec + Sysfs_existPath_Benchmark.Sysfs2:?gc.count avgt 20 ? 0 counts + Sysfs_existPath_Benchmark.Sysfs2:?stack avgt NaN --- + Sysfs_existPath_Benchmark.SysfsJNA avgt 20 81.047 ? 67.046 ms/op + Sysfs_existPath_Benchmark.SysfsJNA:?gc.alloc.rate avgt 20 NaN MB/sec + Sysfs_existPath_Benchmark.SysfsJNA:?gc.count avgt 20 ? 0 counts + Sysfs_existPath_Benchmark.SysfsJNA:?stack avgt NaN --- + Sysfs_existPath_Benchmark.SysfsJNA2 avgt 20 77.890 ? 60.135 ms/op + Sysfs_existPath_Benchmark.SysfsJNA2:?gc.alloc.rate avgt 20 NaN MB/sec + Sysfs_existPath_Benchmark.SysfsJNA2:?gc.count avgt 20 ? 0 counts + Sysfs_existPath_Benchmark.SysfsJNA2:?stack avgt NaN --- + Sysfs_existPath_Benchmark.SysfsOriginal avgt 20 52.415 ? 16.031 ms/op + Sysfs_existPath_Benchmark.SysfsOriginal:?gc.alloc.rate avgt 20 NaN MB/sec + Sysfs_existPath_Benchmark.SysfsOriginal:?gc.count avgt 20 ? 0 counts + Sysfs_existPath_Benchmark.SysfsOriginal:?stack avgt NaN --- + Sysfs_readString_Benchmark.SysfsJNA avgt 20 130.497 ? 64.471 ms/op + Sysfs_readString_Benchmark.SysfsJNA:?gc.alloc.rate avgt 20 NaN MB/sec + Sysfs_readString_Benchmark.SysfsJNA:?gc.count avgt 20 ? 0 counts + Sysfs_readString_Benchmark.SysfsJNA:?stack avgt NaN --- + Sysfs_readString_Benchmark.SysfsJNA2 avgt 20 147.819 ? 130.883 ms/op + Sysfs_readString_Benchmark.SysfsJNA2:?gc.alloc.rate avgt 20 NaN MB/sec + Sysfs_readString_Benchmark.SysfsJNA2:?gc.count avgt 20 ? 0 counts + Sysfs_readString_Benchmark.SysfsJNA2:?stack avgt NaN --- + Sysfs_readString_Benchmark.SysfsJNA3 avgt 20 135.971 ? 106.608 ms/op + Sysfs_readString_Benchmark.SysfsJNA3:?gc.alloc.rate avgt 20 NaN MB/sec + Sysfs_readString_Benchmark.SysfsJNA3:?gc.count avgt 20 ? 0 counts + Sysfs_readString_Benchmark.SysfsJNA3:?stack avgt NaN --- + Sysfs_readString_Benchmark.SysfsOriginal avgt 20 130.898 ? 37.657 ms/op + Sysfs_readString_Benchmark.SysfsOriginal:?gc.alloc.rate avgt 20 NaN MB/sec + Sysfs_readString_Benchmark.SysfsOriginal:?gc.count avgt 20 ? 0 counts + Sysfs_readString_Benchmark.SysfsOriginal:?stack avgt NaN --- + Sysfs_writeInteger_Benchmark.Sysfs2 avgt 20 71.374 ? 43.235 ms/op + Sysfs_writeInteger_Benchmark.Sysfs2:?gc.alloc.rate avgt 20 NaN MB/sec + Sysfs_writeInteger_Benchmark.Sysfs2:?gc.count avgt 20 ? 0 counts + Sysfs_writeInteger_Benchmark.Sysfs2:?stack avgt NaN --- + Sysfs_writeInteger_Benchmark.SysfsJNA avgt 20 101.911 ? 76.781 ms/op + Sysfs_writeInteger_Benchmark.SysfsJNA:?gc.alloc.rate avgt 20 NaN MB/sec + Sysfs_writeInteger_Benchmark.SysfsJNA:?gc.count avgt 20 ? 0 counts + Sysfs_writeInteger_Benchmark.SysfsJNA:?stack avgt NaN --- + Sysfs_writeInteger_Benchmark.SysfsJNA2 avgt 20 95.995 ? 85.353 ms/op + Sysfs_writeInteger_Benchmark.SysfsJNA2:?gc.alloc.rate avgt 20 NaN MB/sec + Sysfs_writeInteger_Benchmark.SysfsJNA2:?gc.count avgt 20 ? 0 counts + Sysfs_writeInteger_Benchmark.SysfsJNA2:?stack avgt NaN --- + Sysfs_writeInteger_Benchmark.SysfsJNA3 avgt 20 104.898 ? 134.129 ms/op + Sysfs_writeInteger_Benchmark.SysfsJNA3:?gc.alloc.rate avgt 20 NaN MB/sec + Sysfs_writeInteger_Benchmark.SysfsJNA3:?gc.count avgt 20 ? 0 counts + Sysfs_writeInteger_Benchmark.SysfsJNA3:?stack avgt NaN --- + Sysfs_writeInteger_Benchmark.SysfsOriginal avgt 20 69.563 ? 29.926 ms/op + Sysfs_writeInteger_Benchmark.SysfsOriginal:?gc.alloc.rate avgt 20 NaN MB/sec + Sysfs_writeInteger_Benchmark.SysfsOriginal:?gc.count avgt 20 ? 0 counts + Sysfs_writeInteger_Benchmark.SysfsOriginal:?stack avgt NaN --- + Sysfs_writeString_Benchmark.Sysfs2 avgt 20 63.268 ? 20.395 ms/op + Sysfs_writeString_Benchmark.Sysfs2:?gc.alloc.rate avgt 20 NaN MB/sec + Sysfs_writeString_Benchmark.Sysfs2:?gc.count avgt 20 ? 0 counts + Sysfs_writeString_Benchmark.Sysfs2:?stack avgt NaN --- + Sysfs_writeString_Benchmark.SysfsJNA avgt 20 77.667 ? 59.439 ms/op + Sysfs_writeString_Benchmark.SysfsJNA:?gc.alloc.rate avgt 20 NaN MB/sec + Sysfs_writeString_Benchmark.SysfsJNA:?gc.count avgt 20 ? 0 counts + Sysfs_writeString_Benchmark.SysfsJNA:?stack avgt NaN --- + Sysfs_writeString_Benchmark.SysfsJNA2 avgt 20 99.891 ? 70.904 ms/op + Sysfs_writeString_Benchmark.SysfsJNA2:?gc.alloc.rate avgt 20 NaN MB/sec + Sysfs_writeString_Benchmark.SysfsJNA2:?gc.count avgt 20 ? 0 counts + Sysfs_writeString_Benchmark.SysfsJNA2:?stack avgt NaN --- + Sysfs_writeString_Benchmark.SysfsJNA3 avgt 20 82.663 ? 88.105 ms/op + Sysfs_writeString_Benchmark.SysfsJNA3:?gc.alloc.rate avgt 20 NaN MB/sec + Sysfs_writeString_Benchmark.SysfsJNA3:?gc.count avgt 20 ? 0 counts + Sysfs_writeString_Benchmark.SysfsJNA3:?stack avgt NaN --- + Sysfs_writeString_Benchmark.SysfsOriginal avgt 20 60.243 ? 16.181 ms/op + Sysfs_writeString_Benchmark.SysfsOriginal:?gc.alloc.rate avgt 20 NaN MB/sec + Sysfs_writeString_Benchmark.SysfsOriginal:?gc.count avgt 20 ? 0 counts + Sysfs_writeString_Benchmark.SysfsOriginal:?stack avgt NaN --- + + */ + +/** + * Benchmark Mode Cnt Score Error Units + * Sysfs_ExistFile_Benchmark.Sysfs2 thrpt 20 0.121 ? 0.057 ops/ms + * Sysfs_ExistFile_Benchmark.Sysfs2:?gc.alloc.rate thrpt 20 NaN MB/sec + * Sysfs_ExistFile_Benchmark.Sysfs2:?gc.count thrpt 20 ? 0 counts + * Sysfs_ExistFile_Benchmark.Sysfs2:?stack thrpt NaN --- + * Sysfs_ExistFile_Benchmark.SysfsJNA thrpt 20 0.088 ? 0.042 ops/ms + * Sysfs_ExistFile_Benchmark.SysfsJNA:?gc.alloc.rate thrpt 20 NaN MB/sec + * Sysfs_ExistFile_Benchmark.SysfsJNA:?gc.count thrpt 20 ? 0 counts + * Sysfs_ExistFile_Benchmark.SysfsJNA:?stack thrpt NaN --- + * Sysfs_ExistFile_Benchmark.SysfsJNA2 thrpt 20 0.079 ? 0.040 ops/ms + * Sysfs_ExistFile_Benchmark.SysfsJNA2:?gc.alloc.rate thrpt 20 NaN MB/sec + * Sysfs_ExistFile_Benchmark.SysfsJNA2:?gc.count thrpt 20 ? 0 counts + * Sysfs_ExistFile_Benchmark.SysfsJNA2:?stack thrpt NaN --- + * Sysfs_ExistFile_Benchmark.SysfsJNA3 thrpt 20 0.085 ? 0.028 ops/ms + * Sysfs_ExistFile_Benchmark.SysfsJNA3:?gc.alloc.rate thrpt 20 NaN MB/sec + * Sysfs_ExistFile_Benchmark.SysfsJNA3:?gc.count thrpt 20 ? 0 counts + * Sysfs_ExistFile_Benchmark.SysfsJNA3:?stack thrpt NaN --- + * Sysfs_ExistFile_Benchmark.SysfsOriginal thrpt 20 0.123 ? 0.052 ops/ms + * Sysfs_ExistFile_Benchmark.SysfsOriginal:?gc.alloc.rate thrpt 20 NaN MB/sec + * Sysfs_ExistFile_Benchmark.SysfsOriginal:?gc.count thrpt 20 ? 0 counts + * Sysfs_ExistFile_Benchmark.SysfsOriginal:?stack thrpt NaN --- + * Sysfs_existPath_Benchmark.Sysfs2 thrpt 20 0.024 ? 0.004 ops/ms + * Sysfs_existPath_Benchmark.Sysfs2:?gc.alloc.rate thrpt 20 NaN MB/sec + * Sysfs_existPath_Benchmark.Sysfs2:?gc.count thrpt 20 ? 0 counts + * Sysfs_existPath_Benchmark.Sysfs2:?stack thrpt NaN --- + * Sysfs_existPath_Benchmark.SysfsJNA thrpt 20 0.022 ? 0.007 ops/ms + * Sysfs_existPath_Benchmark.SysfsJNA:?gc.alloc.rate thrpt 20 NaN MB/sec + * Sysfs_existPath_Benchmark.SysfsJNA:?gc.count thrpt 20 ? 0 counts + * Sysfs_existPath_Benchmark.SysfsJNA:?stack thrpt NaN --- + * Sysfs_existPath_Benchmark.SysfsJNA2 thrpt 20 0.022 ? 0.008 ops/ms + * Sysfs_existPath_Benchmark.SysfsJNA2:?gc.alloc.rate thrpt 20 NaN MB/sec + * Sysfs_existPath_Benchmark.SysfsJNA2:?gc.count thrpt 20 ? 0 counts + * Sysfs_existPath_Benchmark.SysfsJNA2:?stack thrpt NaN --- + * Sysfs_existPath_Benchmark.SysfsOriginal thrpt 20 0.021 ? 0.005 ops/ms + * Sysfs_existPath_Benchmark.SysfsOriginal:?gc.alloc.rate thrpt 20 NaN MB/sec + * Sysfs_existPath_Benchmark.SysfsOriginal:?gc.count thrpt 20 ? 0 counts + * Sysfs_existPath_Benchmark.SysfsOriginal:?stack thrpt NaN --- + * Sysfs_readString_Benchmark.SysfsJNA thrpt 20 0.010 ? 0.003 ops/ms + * Sysfs_readString_Benchmark.SysfsJNA:?gc.alloc.rate thrpt 20 NaN MB/sec + * Sysfs_readString_Benchmark.SysfsJNA:?gc.count thrpt 20 ? 0 counts + * Sysfs_readString_Benchmark.SysfsJNA:?stack thrpt NaN --- + * Sysfs_readString_Benchmark.SysfsJNA2 thrpt 20 0.010 ? 0.003 ops/ms + * Sysfs_readString_Benchmark.SysfsJNA2:?gc.alloc.rate thrpt 20 NaN MB/sec + * Sysfs_readString_Benchmark.SysfsJNA2:?gc.count thrpt 20 ? 0 counts + * Sysfs_readString_Benchmark.SysfsJNA2:?stack thrpt NaN --- + * Sysfs_readString_Benchmark.SysfsJNA3 thrpt 20 0.011 ? 0.004 ops/ms + * Sysfs_readString_Benchmark.SysfsJNA3:?gc.alloc.rate thrpt 20 NaN MB/sec + * Sysfs_readString_Benchmark.SysfsJNA3:?gc.count thrpt 20 ? 0 counts + * Sysfs_readString_Benchmark.SysfsJNA3:?stack thrpt NaN --- + * Sysfs_readString_Benchmark.SysfsOriginal thrpt 20 0.008 ? 0.002 ops/ms + * Sysfs_readString_Benchmark.SysfsOriginal:?gc.alloc.rate thrpt 20 NaN MB/sec + * Sysfs_readString_Benchmark.SysfsOriginal:?gc.count thrpt 20 ? 0 counts + * Sysfs_readString_Benchmark.SysfsOriginal:?stack thrpt NaN --- + * Sysfs_writeInteger_Benchmark.Sysfs2 thrpt 20 0.017 ? 0.004 ops/ms + * Sysfs_writeInteger_Benchmark.Sysfs2:?gc.alloc.rate thrpt 20 NaN MB/sec + * Sysfs_writeInteger_Benchmark.Sysfs2:?gc.count thrpt 20 ? 0 counts + * Sysfs_writeInteger_Benchmark.Sysfs2:?stack thrpt NaN --- + * Sysfs_writeInteger_Benchmark.SysfsJNA thrpt 20 0.016 ? 0.006 ops/ms + * Sysfs_writeInteger_Benchmark.SysfsJNA:?gc.alloc.rate thrpt 20 NaN MB/sec + * Sysfs_writeInteger_Benchmark.SysfsJNA:?gc.count thrpt 20 ? 0 counts + * Sysfs_writeInteger_Benchmark.SysfsJNA:?stack thrpt NaN --- + * Sysfs_writeInteger_Benchmark.SysfsJNA2 thrpt 20 0.016 ? 0.006 ops/ms + * Sysfs_writeInteger_Benchmark.SysfsJNA2:?gc.alloc.rate thrpt 20 NaN MB/sec + * Sysfs_writeInteger_Benchmark.SysfsJNA2:?gc.count thrpt 20 ? 0 counts + * Sysfs_writeInteger_Benchmark.SysfsJNA2:?stack thrpt NaN --- + * Sysfs_writeInteger_Benchmark.SysfsJNA3 thrpt 20 0.017 ? 0.006 ops/ms + * Sysfs_writeInteger_Benchmark.SysfsJNA3:?gc.alloc.rate thrpt 20 NaN MB/sec + * Sysfs_writeInteger_Benchmark.SysfsJNA3:?gc.count thrpt 20 ? 0 counts + * Sysfs_writeInteger_Benchmark.SysfsJNA3:?stack thrpt NaN --- + * Sysfs_writeInteger_Benchmark.SysfsOriginal thrpt 20 0.017 ? 0.004 ops/ms + * Sysfs_writeInteger_Benchmark.SysfsOriginal:?gc.alloc.rate thrpt 20 NaN MB/sec + * Sysfs_writeInteger_Benchmark.SysfsOriginal:?gc.count thrpt 20 ? 0 counts + * Sysfs_writeInteger_Benchmark.SysfsOriginal:?stack thrpt NaN --- + * Sysfs_writeString_Benchmark.Sysfs2 thrpt 20 0.019 ? 0.003 ops/ms + * Sysfs_writeString_Benchmark.Sysfs2:?gc.alloc.rate thrpt 20 NaN MB/sec + * Sysfs_writeString_Benchmark.Sysfs2:?gc.count thrpt 20 ? 0 counts + * Sysfs_writeString_Benchmark.Sysfs2:?stack thrpt NaN --- + * Sysfs_writeString_Benchmark.SysfsJNA thrpt 20 0.015 ? 0.006 ops/ms + * Sysfs_writeString_Benchmark.SysfsJNA:?gc.alloc.rate thrpt 20 NaN MB/sec + * Sysfs_writeString_Benchmark.SysfsJNA:?gc.count thrpt 20 ? 0 counts + * Sysfs_writeString_Benchmark.SysfsJNA:?stack thrpt NaN --- + * Sysfs_writeString_Benchmark.SysfsJNA2 thrpt 20 0.016 ? 0.007 ops/ms + * Sysfs_writeString_Benchmark.SysfsJNA2:?gc.alloc.rate thrpt 20 NaN MB/sec + * Sysfs_writeString_Benchmark.SysfsJNA2:?gc.count thrpt 20 ? 0 counts + * Sysfs_writeString_Benchmark.SysfsJNA2:?stack thrpt NaN --- + * Sysfs_writeString_Benchmark.SysfsJNA3 thrpt 20 0.020 ? 0.008 ops/ms + * Sysfs_writeString_Benchmark.SysfsJNA3:?gc.alloc.rate thrpt 20 NaN MB/sec + * Sysfs_writeString_Benchmark.SysfsJNA3:?gc.count thrpt 20 ? 0 counts + * Sysfs_writeString_Benchmark.SysfsJNA3:?stack thrpt NaN --- + * Sysfs_writeString_Benchmark.SysfsOriginal thrpt 20 0.016 ? 0.003 ops/ms + * Sysfs_writeString_Benchmark.SysfsOriginal:?gc.alloc.rate thrpt 20 NaN MB/sec + * Sysfs_writeString_Benchmark.SysfsOriginal:?gc.count thrpt 20 ? 0 counts + * Sysfs_writeString_Benchmark.SysfsOriginal:?stack thrpt NaN --- + * + * Benchmark result is saved to /home/robot/jmh-results.json + */ + +/** + Benchmark Mode Cnt Score Error Units + Sysfs_ExistFile_Benchmark.Sysfs2 ss 20 15.571 ? 12.105 ms/op + Sysfs_ExistFile_Benchmark.Sysfs2:?gc.alloc.rate ss 20 NaN MB/sec + Sysfs_ExistFile_Benchmark.Sysfs2:?gc.count ss 20 ? 0 counts + Sysfs_ExistFile_Benchmark.Sysfs2:?stack ss NaN --- + Sysfs_ExistFile_Benchmark.SysfsJNA ss 20 19.547 ? 20.092 ms/op + Sysfs_ExistFile_Benchmark.SysfsJNA:?gc.alloc.rate ss 20 NaN MB/sec + Sysfs_ExistFile_Benchmark.SysfsJNA:?gc.count ss 20 ? 0 counts + Sysfs_ExistFile_Benchmark.SysfsJNA:?stack ss NaN --- + Sysfs_ExistFile_Benchmark.SysfsJNA2 ss 20 28.258 ? 48.619 ms/op + Sysfs_ExistFile_Benchmark.SysfsJNA2:?gc.alloc.rate ss 20 NaN MB/sec + Sysfs_ExistFile_Benchmark.SysfsJNA2:?gc.count ss 20 ? 0 counts + Sysfs_ExistFile_Benchmark.SysfsJNA2:?stack ss NaN --- + Sysfs_ExistFile_Benchmark.SysfsJNA3 ss 20 17.829 ? 20.050 ms/op + Sysfs_ExistFile_Benchmark.SysfsJNA3:?gc.alloc.rate ss 20 NaN MB/sec + Sysfs_ExistFile_Benchmark.SysfsJNA3:?gc.count ss 20 ? 0 counts + Sysfs_ExistFile_Benchmark.SysfsJNA3:?stack ss NaN --- + Sysfs_ExistFile_Benchmark.SysfsOriginal ss 20 9.523 ? 3.981 ms/op + Sysfs_ExistFile_Benchmark.SysfsOriginal:?gc.alloc.rate ss 20 NaN MB/sec + Sysfs_ExistFile_Benchmark.SysfsOriginal:?gc.count ss 20 ? 0 counts + Sysfs_ExistFile_Benchmark.SysfsOriginal:?stack ss NaN --- + Sysfs_existPath_Benchmark.Sysfs2 ss 20 39.418 ? 5.533 ms/op + Sysfs_existPath_Benchmark.Sysfs2:?gc.alloc.rate ss 20 NaN MB/sec + Sysfs_existPath_Benchmark.Sysfs2:?gc.count ss 20 ? 0 counts + Sysfs_existPath_Benchmark.Sysfs2:?stack ss NaN --- + Sysfs_existPath_Benchmark.SysfsJNA ss 20 73.290 ? 64.469 ms/op + Sysfs_existPath_Benchmark.SysfsJNA:?gc.alloc.rate ss 20 NaN MB/sec + Sysfs_existPath_Benchmark.SysfsJNA:?gc.count ss 20 ? 0 counts + Sysfs_existPath_Benchmark.SysfsJNA:?stack ss NaN --- + Sysfs_existPath_Benchmark.SysfsJNA2 ss 20 62.707 ? 50.280 ms/op + Sysfs_existPath_Benchmark.SysfsJNA2:?gc.alloc.rate ss 20 NaN MB/sec + Sysfs_existPath_Benchmark.SysfsJNA2:?gc.count ss 20 ? 0 counts + Sysfs_existPath_Benchmark.SysfsJNA2:?stack ss NaN --- + Sysfs_existPath_Benchmark.SysfsOriginal ss 20 43.207 ? 10.250 ms/op + Sysfs_existPath_Benchmark.SysfsOriginal:?gc.alloc.rate ss 20 NaN MB/sec + Sysfs_existPath_Benchmark.SysfsOriginal:?gc.count ss 20 ? 0 counts + Sysfs_existPath_Benchmark.SysfsOriginal:?stack ss NaN --- + Sysfs_readString_Benchmark.SysfsJNA ss 20 114.712 ? 64.723 ms/op + Sysfs_readString_Benchmark.SysfsJNA:?gc.alloc.rate ss 20 NaN MB/sec + Sysfs_readString_Benchmark.SysfsJNA:?gc.count ss 20 ? 0 counts + Sysfs_readString_Benchmark.SysfsJNA:?stack ss NaN --- + Sysfs_readString_Benchmark.SysfsJNA2 ss 20 124.777 ? 69.026 ms/op + Sysfs_readString_Benchmark.SysfsJNA2:?gc.alloc.rate ss 20 NaN MB/sec + Sysfs_readString_Benchmark.SysfsJNA2:?gc.count ss 20 ? 0 counts + Sysfs_readString_Benchmark.SysfsJNA2:?stack ss NaN --- + Sysfs_readString_Benchmark.SysfsJNA3 ss 20 139.290 ? 116.395 ms/op + Sysfs_readString_Benchmark.SysfsJNA3:?gc.alloc.rate ss 20 NaN MB/sec + Sysfs_readString_Benchmark.SysfsJNA3:?gc.count ss 20 ? 0 counts + Sysfs_readString_Benchmark.SysfsJNA3:?stack ss NaN --- + Sysfs_readString_Benchmark.SysfsOriginal ss 20 125.183 ? 35.970 ms/op + Sysfs_readString_Benchmark.SysfsOriginal:?gc.alloc.rate ss 20 NaN MB/sec + Sysfs_readString_Benchmark.SysfsOriginal:?gc.count ss 20 ? 0 counts + Sysfs_readString_Benchmark.SysfsOriginal:?stack ss NaN --- + Sysfs_writeInteger_Benchmark.Sysfs2 ss 20 57.790 ? 13.316 ms/op + Sysfs_writeInteger_Benchmark.Sysfs2:?gc.alloc.rate ss 20 NaN MB/sec + Sysfs_writeInteger_Benchmark.Sysfs2:?gc.count ss 20 ? 0 counts + Sysfs_writeInteger_Benchmark.Sysfs2:?stack ss NaN --- + Sysfs_writeInteger_Benchmark.SysfsJNA ss 20 102.920 ? 66.352 ms/op + Sysfs_writeInteger_Benchmark.SysfsJNA:?gc.alloc.rate ss 20 NaN MB/sec + Sysfs_writeInteger_Benchmark.SysfsJNA:?gc.count ss 20 ? 0 counts + Sysfs_writeInteger_Benchmark.SysfsJNA:?stack ss NaN --- + Sysfs_writeInteger_Benchmark.SysfsJNA2 ss 20 112.213 ? 119.813 ms/op + Sysfs_writeInteger_Benchmark.SysfsJNA2:?gc.alloc.rate ss 20 NaN MB/sec + Sysfs_writeInteger_Benchmark.SysfsJNA2:?gc.count ss 20 ? 0 counts + Sysfs_writeInteger_Benchmark.SysfsJNA2:?stack ss NaN --- + Sysfs_writeInteger_Benchmark.SysfsJNA3 ss 20 82.762 ? 93.211 ms/op + Sysfs_writeInteger_Benchmark.SysfsJNA3:?gc.alloc.rate ss 20 NaN MB/sec + Sysfs_writeInteger_Benchmark.SysfsJNA3:?gc.count ss 20 ? 0 counts + Sysfs_writeInteger_Benchmark.SysfsJNA3:?stack ss NaN --- + Sysfs_writeInteger_Benchmark.SysfsOriginal ss 20 67.545 ? 39.738 ms/op + Sysfs_writeInteger_Benchmark.SysfsOriginal:?gc.alloc.rate ss 20 NaN MB/sec + Sysfs_writeInteger_Benchmark.SysfsOriginal:?gc.count ss 20 ? 0 counts + Sysfs_writeInteger_Benchmark.SysfsOriginal:?stack ss NaN --- + Sysfs_writeString_Benchmark.Sysfs2 ss 20 57.017 ? 19.105 ms/op + Sysfs_writeString_Benchmark.Sysfs2:?gc.alloc.rate ss 20 NaN MB/sec + Sysfs_writeString_Benchmark.Sysfs2:?gc.count ss 20 ? 0 counts + Sysfs_writeString_Benchmark.Sysfs2:?stack ss NaN --- + Sysfs_writeString_Benchmark.SysfsJNA ss 20 75.872 ? 59.289 ms/op + Sysfs_writeString_Benchmark.SysfsJNA:?gc.alloc.rate ss 20 NaN MB/sec + Sysfs_writeString_Benchmark.SysfsJNA:?gc.count ss 20 ? 0 counts + Sysfs_writeString_Benchmark.SysfsJNA:?stack ss NaN --- + Sysfs_writeString_Benchmark.SysfsJNA2 ss 20 93.195 ? 70.036 ms/op + Sysfs_writeString_Benchmark.SysfsJNA2:?gc.alloc.rate ss 20 NaN MB/sec + Sysfs_writeString_Benchmark.SysfsJNA2:?gc.count ss 20 ? 0 counts + Sysfs_writeString_Benchmark.SysfsJNA2:?stack ss NaN --- + Sysfs_writeString_Benchmark.SysfsJNA3 ss 20 89.512 ? 78.663 ms/op + Sysfs_writeString_Benchmark.SysfsJNA3:?gc.alloc.rate ss 20 NaN MB/sec + Sysfs_writeString_Benchmark.SysfsJNA3:?gc.count ss 20 ? 0 counts + Sysfs_writeString_Benchmark.SysfsJNA3:?stack ss NaN --- + Sysfs_writeString_Benchmark.SysfsOriginal ss 20 55.680 ? 15.191 ms/op + Sysfs_writeString_Benchmark.SysfsOriginal:?gc.alloc.rate ss 20 NaN MB/sec + Sysfs_writeString_Benchmark.SysfsOriginal:?gc.count ss 20 ? 0 counts + Sysfs_writeString_Benchmark.SysfsOriginal:?stack ss NaN --- + + */ diff --git a/src/main/java/ev3dev/utils/DataChannelRereader.java b/src/main/java/ev3dev/utils/DataChannelRereader.java index 4e1790ac..36066091 100644 --- a/src/main/java/ev3dev/utils/DataChannelRereader.java +++ b/src/main/java/ev3dev/utils/DataChannelRereader.java @@ -52,7 +52,7 @@ public synchronized String readString() { try { byteBuffer.clear(); int n = channel.read(byteBuffer,0); - if ((n == -1)||(n == 0)) { + if ((n == -1) || (n == 0)) { return ""; } else if (n < -1) { throw new RuntimeException("Unexpected read byte count of " + n + " while reading " + path); diff --git a/src/main/java/ev3dev/utils/DataChannelRereaderJMCTest.java b/src/main/java/ev3dev/utils/DataChannelRereaderJMCTest.java new file mode 100644 index 00000000..dc2c7e2a --- /dev/null +++ b/src/main/java/ev3dev/utils/DataChannelRereaderJMCTest.java @@ -0,0 +1,77 @@ +package ev3dev.utils; + +import lombok.extern.slf4j.Slf4j; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.concurrent.CompletableFuture; +import java.util.stream.IntStream; + +@Slf4j +public class DataChannelRereaderJMCTest { + + final static String fileName = "./race.txt"; + final static Integer limit = 200000; + + public static void createFiles() throws IOException { + Files.writeString(Path.of(fileName), "test1234"); + } + + /** + * Reader1 <- race.txt + * Reader2 <- race.txt + * Reader3 <- race.txt + * Reader4 <- race.txt + */ + public static void main(String[] args) throws Exception{ + + createFiles(); + + DataChannelRereader reader = new DataChannelRereader(fileName); + + CompletableFuture rq1 = asyncReadFile(reader); + CompletableFuture rq2 = asyncReadFile(reader); + CompletableFuture rq3 = asyncReadFile(reader); + CompletableFuture rq4 = asyncReadFile(reader); + + CompletableFuture combinedFuture = CompletableFuture.allOf(rq1, rq2, rq3, rq4); + combinedFuture.join(); + + /* + then(rq1.isDone()).isTrue(); + then(rq2.isDone()).isTrue(); + then(rq3.isDone()).isTrue(); + then(rq4.isDone()).isTrue(); + + then(rq1.join()).isEqualTo("Ok asyncReadFile"); + then(rq2.join()).isEqualTo("Ok asyncReadFile"); + then(rq3.join()).isEqualTo("Ok asyncReadFile"); + then(rq4.join()).isEqualTo("Ok asyncReadFile"); + + System.out.println("End"); + */ + } + + private static void readFile(DataChannelRereader reader) { + reader.readString(); + //then(reader.readString()).isEqualTo("test1234"); + } + + private static CompletableFuture asyncReadFile(DataChannelRereader reader) { + CompletableFuture cf1 = CompletableFuture.supplyAsync(() -> { + IntStream + .rangeClosed(1, limit) + .forEach(i -> readFile(reader)); + return "Ok asyncReadFile"; + }) + .handle((input, exception) -> { + if (exception != null) { + LOGGER.warn(exception.getLocalizedMessage(), exception); + return "Ko asyncReadFile"; + } + return input; + }); + return cf1; + } +} diff --git a/src/main/resources/META-INF/MANIFEST.MF b/src/main/resources/META-INF/MANIFEST.MF index 54a59969..8741f117 100755 --- a/src/main/resources/META-INF/MANIFEST.MF +++ b/src/main/resources/META-INF/MANIFEST.MF @@ -2,3 +2,4 @@ Manifest-Version: 1.0 Implementation-Title: EV3Dev-lang-java Implementation-Version: 2.7.0-SNAPSHOT Implementation-Vendor: Juan Antonio Breña Moral +Main-Class: ev3dev.utils.DataChannelRereaderJMCTest diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml new file mode 100644 index 00000000..dcea232c --- /dev/null +++ b/src/main/resources/logback.xml @@ -0,0 +1,23 @@ + + + + + + + System.err + + + %d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + + + + + + diff --git a/src/main/resources/simplelogger.properties b/src/main/resources/simplelogger.properties new file mode 100644 index 00000000..a1143482 --- /dev/null +++ b/src/main/resources/simplelogger.properties @@ -0,0 +1,18 @@ +# SLF4J's SimpleLogger configuration file +# Simple implementation of Logger that sends all enabled log messages, for all defined loggers, to System.err. + +org.slf4j.simpleLogger.defaultLogLevel=info + +#org.slf4j.simpleLogger.log.ev3dev.hardware=trace +#org.slf4j.simpleLogger.log.ev3dev.utils=trace + + + +org.slf4j.simpleLogger.showDateTime=true +org.slf4j.simpleLogger.dateTimeFormat=yyyy-MM-dd HH:mm:ss +org.slf4j.simpleLogger.showThreadName=true +org.slf4j.simpleLogger.showLogName=true +org.slf4j.simpleLogger.showShortLogName=false + +org.slf4j.simpleLogger.logFile=System.err +#org.slf4j.simpleLogger.logFile=/home/robot/java/programs/logs.log diff --git a/src/test/java/ev3dev/utils/DataChannelRereader2ConcurrencyTest.java b/src/test/java/ev3dev/utils/DataChannelRereader2ConcurrencyTest.java index 5fcc1f97..d129209e 100644 --- a/src/test/java/ev3dev/utils/DataChannelRereader2ConcurrencyTest.java +++ b/src/test/java/ev3dev/utils/DataChannelRereader2ConcurrencyTest.java @@ -6,6 +6,7 @@ import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import static org.assertj.core.api.BDDAssertions.then; @@ -34,6 +35,7 @@ public void createFiles() { * Reader2 <- odds.txt */ @Test + @Ignore public void given_multiple_DataChannelRereader_when_execute_concurrently_then_Ok() { CompletableFuture request1 = asyncWriteFile(true); @@ -178,6 +180,7 @@ private CompletableFuture asyncWriteFile(boolean flag) { * Reader1 <- odds.txt */ @Test + @Ignore public void given_multiple_DataChannelRereader_when_execute_concurrently_then_Ok2() { CompletableFuture request1 = asyncWriteFile(true); diff --git a/src/test/java/ev3dev/utils/DataChannelRereader3ConcurrencyTest.java b/src/test/java/ev3dev/utils/DataChannelRereader3ConcurrencyTest.java index 19566040..85f59f58 100644 --- a/src/test/java/ev3dev/utils/DataChannelRereader3ConcurrencyTest.java +++ b/src/test/java/ev3dev/utils/DataChannelRereader3ConcurrencyTest.java @@ -6,6 +6,7 @@ import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import static org.assertj.core.api.BDDAssertions.then; @@ -98,6 +99,7 @@ private CompletableFuture asyncWriteFile(boolean flag) { * Writer1 -> odds.txt * Reader1 <- odds.txt */ + @Ignore @Test public void given_multiple_SysfsOld_when_execute_concurrently_then_Ok() { @@ -132,6 +134,7 @@ public void given_multiple_SysfsOld_when_execute_concurrently_then_Ok() { * Reader1 <- pairs.txt * */ + @Ignore @Test public void given_multiple_SysfsOld_when_execute_concurrently_then_Ok2() { diff --git a/src/test/java/ev3dev/utils/DataChannelRereaderConcurrencyTest.java b/src/test/java/ev3dev/utils/DataChannelRereaderConcurrencyTest.java index 850e0920..34106caa 100644 --- a/src/test/java/ev3dev/utils/DataChannelRereaderConcurrencyTest.java +++ b/src/test/java/ev3dev/utils/DataChannelRereaderConcurrencyTest.java @@ -6,6 +6,7 @@ import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import static org.assertj.core.api.BDDAssertions.then; @@ -33,6 +34,7 @@ public void createFiles() { * Reader1 <- odds.txt * Reader2 <- odds.txt */ + @Ignore @Test public void given_multiple_DataChannelRereader_when_execute_concurrently_then_Ok() { @@ -177,6 +179,7 @@ private CompletableFuture asyncWriteFile(boolean flag) { * Writer1 -> odds.txt * Reader1 <- odds.txt */ + @Ignore @Test public void given_multiple_DataChannelRereader_when_execute_concurrently_then_Ok2() { diff --git a/src/test/java/ev3dev/utils/SysfsOldRaceTest.java b/src/test/java/ev3dev/utils/SysfsOldRaceTest.java new file mode 100644 index 00000000..0368523e --- /dev/null +++ b/src/test/java/ev3dev/utils/SysfsOldRaceTest.java @@ -0,0 +1,78 @@ +package ev3dev.utils; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.concurrent.CompletableFuture; +import java.util.stream.IntStream; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.junit.Before; +import org.junit.Test; + +import static org.assertj.core.api.BDDAssertions.then; + +@Slf4j +public class SysfsOldRaceTest { + + final String fileName = "./race.txt"; + final Integer limit = 10000; + + @Before + @SneakyThrows + public void createFiles() throws IOException { + Files.writeString(Path.of(fileName), "test1234"); + } + + /** + * Reader1 <- race.txt + * Reader2 <- race.txt + * Reader3 <- race.txt + * Reader4 <- race.txt + */ + @Test + public void given_multiple_DataChannelRereader_when_execute_concurrently_then_Ok() { + DataChannelRereader reader = new DataChannelRereader(fileName); + + CompletableFuture rq1 = asyncReadFile(reader); + CompletableFuture rq2 = asyncReadFile(reader); + CompletableFuture rq3 = asyncReadFile(reader); + CompletableFuture rq4 = asyncReadFile(reader); + + CompletableFuture combinedFuture = CompletableFuture.allOf(rq1, rq2, rq3, rq4); + combinedFuture.join(); + + then(rq1.isDone()).isTrue(); + then(rq2.isDone()).isTrue(); + then(rq3.isDone()).isTrue(); + then(rq4.isDone()).isTrue(); + + then(rq1.join()).isEqualTo("Ok asyncReadFile"); + then(rq2.join()).isEqualTo("Ok asyncReadFile"); + then(rq3.join()).isEqualTo("Ok asyncReadFile"); + then(rq4.join()).isEqualTo("Ok asyncReadFile"); + System.out.println("End"); + } + + private void readFile(DataChannelRereader reader) { + //then(reader.readString()).isEqualTo("test1234"); + then(SysfsOld.readString(fileName)).isEqualTo("test1234"); + } + + private CompletableFuture asyncReadFile(DataChannelRereader reader) { + CompletableFuture cf1 = CompletableFuture.supplyAsync(() -> { + IntStream + .rangeClosed(1, limit) + .forEach(i -> readFile(reader)); + return "Ok asyncReadFile"; + }) + .handle((input, exception) -> { + if (exception != null) { + LOGGER.warn(exception.getLocalizedMessage(), exception); + return "Ko asyncReadFile"; + } + return input; + }); + return cf1; + } +} diff --git a/src/test/resources/simplelogger.properties b/src/test/resources/simplelogger.properties new file mode 100644 index 00000000..a1143482 --- /dev/null +++ b/src/test/resources/simplelogger.properties @@ -0,0 +1,18 @@ +# SLF4J's SimpleLogger configuration file +# Simple implementation of Logger that sends all enabled log messages, for all defined loggers, to System.err. + +org.slf4j.simpleLogger.defaultLogLevel=info + +#org.slf4j.simpleLogger.log.ev3dev.hardware=trace +#org.slf4j.simpleLogger.log.ev3dev.utils=trace + + + +org.slf4j.simpleLogger.showDateTime=true +org.slf4j.simpleLogger.dateTimeFormat=yyyy-MM-dd HH:mm:ss +org.slf4j.simpleLogger.showThreadName=true +org.slf4j.simpleLogger.showLogName=true +org.slf4j.simpleLogger.showShortLogName=false + +org.slf4j.simpleLogger.logFile=System.err +#org.slf4j.simpleLogger.logFile=/home/robot/java/programs/logs.log From 4787e1d6488712dc5b4d9b77f25478a0fbbfe7fd Mon Sep 17 00:00:00 2001 From: dwalend Date: Tue, 5 Jan 2021 22:00:24 -0500 Subject: [PATCH 30/34] Updated test code for review feedback --- .../ev3dev/utils/DataChannelRereaderTest.java | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/test/java/ev3dev/utils/DataChannelRereaderTest.java b/src/test/java/ev3dev/utils/DataChannelRereaderTest.java index 48c2d365..1fbd4127 100644 --- a/src/test/java/ev3dev/utils/DataChannelRereaderTest.java +++ b/src/test/java/ev3dev/utils/DataChannelRereaderTest.java @@ -1,8 +1,9 @@ package ev3dev.utils; import lombok.SneakyThrows; -import org.junit.After; +import org.junit.AfterClass; import org.junit.Before; +import org.junit.BeforeClass; import org.junit.Test; import java.nio.file.Files; @@ -22,17 +23,23 @@ public class DataChannelRereaderTest { static final String testString = "Written String"; static final String differentTestString = "Different String"; - @Before + @BeforeClass @SneakyThrows - public void createFiles() { + public static void createFiles() { tempDirectory = Files.createTempDirectory("DataChannelRereaderTest"); testPath = Files.createFile(Path.of(tempDirectory.toString(),"testFile")); Files.write(testPath, testString.getBytes()); } - @After + @Before + @SneakyThrows + public void writeFile() { + Files.write(testPath, testString.getBytes()); + } + + @AfterClass @SneakyThrows - public void cleanupFiles() { + public static void cleanupFiles() { Files.delete(testPath); Files.delete(tempDirectory); } @@ -81,7 +88,7 @@ public void testOpenReadTwoThingsClose() { @Test(expected = RuntimeException.class) @SneakyThrows - public void testOpenNonexistantFile() { + public void testOpenNonexistentFile() { Path badPath = Path.of("/does/not/exist"); DataChannelRereader rereader = new DataChannelRereader(badPath,32); From 551aa36b902326307acd83eb5b7486101296111a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Antonio=20Bre=C3=B1a=20Moral?= Date: Thu, 7 Jan 2021 15:57:13 +0100 Subject: [PATCH 31/34] Removing old files --- src/main/java/ev3dev/sensors/Battery2.java | 116 ------ src/main/java/ev3dev/sensors/BatteryOld.java | 110 ----- .../java/ev3dev/utils/BatteryBenchmark.java | 35 -- .../ev3dev/utils/BatteryBenchmarkProgram.java | 375 ------------------ .../ev3dev/utils/DataChannelRereader2.java | 118 ------ .../utils/DataChannelRereaderJMCTest.java | 77 ---- src/main/java/ev3dev/utils/Sysfs2.java | 152 ------- src/main/java/ev3dev/utils/SysfsOld.java | 148 ------- .../DataChannelRereader2ConcurrencyTest.java | 279 ------------- .../utils/DataChannelRereader2RaceTest.java | 78 ---- .../DataChannelRereader3ConcurrencyTest.java | 226 ----------- .../java/ev3dev/utils/SysfsOldRaceTest.java | 78 ---- 12 files changed, 1792 deletions(-) delete mode 100644 src/main/java/ev3dev/sensors/Battery2.java delete mode 100644 src/main/java/ev3dev/sensors/BatteryOld.java delete mode 100644 src/main/java/ev3dev/utils/BatteryBenchmark.java delete mode 100644 src/main/java/ev3dev/utils/BatteryBenchmarkProgram.java delete mode 100644 src/main/java/ev3dev/utils/DataChannelRereader2.java delete mode 100644 src/main/java/ev3dev/utils/DataChannelRereaderJMCTest.java delete mode 100644 src/main/java/ev3dev/utils/Sysfs2.java delete mode 100644 src/main/java/ev3dev/utils/SysfsOld.java delete mode 100644 src/test/java/ev3dev/utils/DataChannelRereader2ConcurrencyTest.java delete mode 100644 src/test/java/ev3dev/utils/DataChannelRereader2RaceTest.java delete mode 100644 src/test/java/ev3dev/utils/DataChannelRereader3ConcurrencyTest.java delete mode 100644 src/test/java/ev3dev/utils/SysfsOldRaceTest.java diff --git a/src/main/java/ev3dev/sensors/Battery2.java b/src/main/java/ev3dev/sensors/Battery2.java deleted file mode 100644 index 91afc4c9..00000000 --- a/src/main/java/ev3dev/sensors/Battery2.java +++ /dev/null @@ -1,116 +0,0 @@ -package ev3dev.sensors; - -import ev3dev.hardware.EV3DevDevice; -import ev3dev.hardware.EV3DevFileSystem; -import ev3dev.hardware.EV3DevPlatform; -import ev3dev.utils.DataChannelRereader; -import ev3dev.utils.DataChannelRereader2; -import java.io.Closeable; -import java.io.IOException; -import lejos.hardware.Power; -import lombok.extern.slf4j.Slf4j; - -/** - * The class Battery interacts with EV3Dev to get information about battery used. - * - * @author Juan Antonio Breña Moral - * @see https://www.kernel.org/doc/Documentation/power/power_supply_class.txt - * @see https://github.com/ev3dev/ev3dev-lang/blob/develop/wrapper-specification.md#direct-attribute-mappings-5 - */ -@Slf4j -public class Battery2 extends EV3DevDevice implements Power, Closeable { - - private final DataChannelRereader2 voltageRereader; - private final DataChannelRereader2 currentRereader; - - private static Battery2 instance; - - /** - * Get a singleton Battery object - * - * @return Battery - */ - public static Battery2 getInstance() { - //TODO Refactor - if (instance == null) { - instance = new Battery2(); - } - return instance; - } - - // Prevent duplicate objects - private Battery2() { - - LOGGER.debug("Init sensor"); - - String battery = ev3DevProperties.getProperty("battery"); - String batteryEv3 = ev3DevProperties.getProperty("ev3.battery"); - String batteryPistorms = ev3DevProperties.getProperty("pistorms.battery"); - String batteryBrickpi = ev3DevProperties.getProperty("brickpi.battery"); - String batteryBrickpi3 = ev3DevProperties.getProperty("brickpi3.battery"); - - //TODO Create separator variable for the whole project - String batteryPath = EV3DevFileSystem.getRootPath() + "/" + battery; - String batteryPathLocal = ""; - if (CURRENT_PLATFORM.equals(EV3DevPlatform.EV3BRICK)) { - batteryPathLocal += batteryPath + "/" + batteryEv3; - } else if (CURRENT_PLATFORM.equals(EV3DevPlatform.PISTORMS)) { - batteryPathLocal += batteryPath + "/" + batteryPistorms; - } else if (CURRENT_PLATFORM.equals(EV3DevPlatform.BRICKPI)) { - batteryPathLocal += batteryPath + "/" + batteryBrickpi; - } else if (CURRENT_PLATFORM.equals(EV3DevPlatform.BRICKPI3)) { - batteryPathLocal += batteryPath + "/" + batteryBrickpi3; - } - String voltage = "voltage_now"; - voltageRereader = new DataChannelRereader2(batteryPathLocal + "/" + voltage); - String current = "current_now"; - currentRereader = new DataChannelRereader2(batteryPath + "/" + batteryEv3 + "/" + current); - } - - public int getVoltageMicroVolts() { - return Integer.parseInt(voltageRereader.readString()); - } - - @Override - public int getVoltageMilliVolt() { - return getVoltageMicroVolts() / 1000; - } - - /** - * Returns voltage of the battery in microvolts. - * - * @return voltage - */ - public float getVoltage() { - return getVoltageMicroVolts() / 1000000f; - } - - //TODO Review output - //TODO Review units - - /** - * Returns the current of the battery in amps. - * - * @return current - */ - public float getBatteryCurrent() { - if (CURRENT_PLATFORM.equals(EV3DevPlatform.EV3BRICK)) { - return Float.parseFloat(currentRereader.readString()); - } else { - LOGGER.warn("This method is not available for {} & {}", EV3DevPlatform.PISTORMS, EV3DevPlatform.BRICKPI); - return -1f; - } - } - - //TODO Review this method in the future. - @Override - public float getMotorCurrent() { - throw new UnsupportedOperationException("This feature is not implemented"); - } - - @Override - public void close() throws IOException { - voltageRereader.close(); - currentRereader.close(); - } -} diff --git a/src/main/java/ev3dev/sensors/BatteryOld.java b/src/main/java/ev3dev/sensors/BatteryOld.java deleted file mode 100644 index 02a74753..00000000 --- a/src/main/java/ev3dev/sensors/BatteryOld.java +++ /dev/null @@ -1,110 +0,0 @@ -package ev3dev.sensors; - -import ev3dev.hardware.EV3DevDevice; -import ev3dev.hardware.EV3DevFileSystem; -import ev3dev.hardware.EV3DevPlatform; -import ev3dev.utils.Sysfs; -import lejos.hardware.Power; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * The class Battery interacts with EV3Dev to get information about battery used. - * - * @author Juan Antonio Breña Moral - * @see https://www.kernel.org/doc/Documentation/power/power_supply_class.txt - * @see https://github.com/ev3dev/ev3dev-lang/blob/develop/wrapper-specification.md#direct-attribute-mappings-5 - */ -public class BatteryOld extends EV3DevDevice implements Power { - - private static final Logger LOGGER = LoggerFactory.getLogger(Battery.class); - - private final String BATTERY; - private final String BATTERY_EV3; - private final String BATTERY_PISTORMS; - private final String BATTERY_BRICKPI; - private final String BATTERY_BRICKPI3; - - private String BATTERY_PATH; - private final String VOLTAGE = "voltage_now"; - private final String CURRENT = "current_now"; - - private String BATTERY_PATH_LOCAL = ""; - - private static BatteryOld instance; - - /** - * Get a singleton Battery object - * - * @return Battery - */ - public static BatteryOld getInstance() { - //TODO Refactor - if (instance == null) { - instance = new BatteryOld(); - } - return instance; - } - - // Prevent duplicate objects - private BatteryOld() { - - LOGGER.debug("Init sensor"); - - BATTERY = ev3DevProperties.getProperty("battery"); - BATTERY_EV3 = ev3DevProperties.getProperty("ev3.battery"); - BATTERY_PISTORMS = ev3DevProperties.getProperty("pistorms.battery"); - BATTERY_BRICKPI = ev3DevProperties.getProperty("brickpi.battery"); - BATTERY_BRICKPI3 = ev3DevProperties.getProperty("brickpi3.battery"); - - //TODO Create separator variable for the whole project - BATTERY_PATH = EV3DevFileSystem.getRootPath() + "/" + BATTERY; - if (CURRENT_PLATFORM.equals(EV3DevPlatform.EV3BRICK)) { - BATTERY_PATH_LOCAL += BATTERY_PATH + "/" + BATTERY_EV3; - } else if (CURRENT_PLATFORM.equals(EV3DevPlatform.PISTORMS)) { - BATTERY_PATH_LOCAL += BATTERY_PATH + "/" + BATTERY_PISTORMS; - } else if (CURRENT_PLATFORM.equals(EV3DevPlatform.BRICKPI)) { - BATTERY_PATH_LOCAL += BATTERY_PATH + "/" + BATTERY_BRICKPI; - } else if (CURRENT_PLATFORM.equals(EV3DevPlatform.BRICKPI3)) { - BATTERY_PATH_LOCAL += BATTERY_PATH + "/" + BATTERY_BRICKPI3; - } - } - - @Override - public int getVoltageMilliVolt() { - return (int) Sysfs.readFloat(BATTERY_PATH_LOCAL + "/" + VOLTAGE) / 1000; - } - - /** - * Returns voltage of the battery in microvolts. - * - * @return voltage - */ - public float getVoltage() { - return Sysfs.readFloat(BATTERY_PATH_LOCAL + "/" + VOLTAGE) / 1000000; - } - - //TODO Review output - //TODO Review units - - /** - * Returns the current of the battery in amps. - * - * @return current - */ - public float getBatteryCurrent() { - if (CURRENT_PLATFORM.equals(EV3DevPlatform.EV3BRICK)) { - return Sysfs.readFloat(BATTERY_PATH + "/" + BATTERY_EV3 + "/" + CURRENT); - } else { - LOGGER.warn("This method is not available for {} & {}", EV3DevPlatform.PISTORMS, EV3DevPlatform.BRICKPI); - return -1f; - } - } - - //TODO Review this method in the future. - @Override - public float getMotorCurrent() { - throw new UnsupportedOperationException("This feature is not implemented"); - } - -} diff --git a/src/main/java/ev3dev/utils/BatteryBenchmark.java b/src/main/java/ev3dev/utils/BatteryBenchmark.java deleted file mode 100644 index f8572e40..00000000 --- a/src/main/java/ev3dev/utils/BatteryBenchmark.java +++ /dev/null @@ -1,35 +0,0 @@ -package ev3dev.utils; - -import ev3dev.sensors.Battery; -import ev3dev.sensors.Battery2; -import ev3dev.sensors.BatteryOld; -import org.openjdk.jmh.annotations.Benchmark; -import org.openjdk.jmh.annotations.Scope; -import org.openjdk.jmh.annotations.State; -import org.openjdk.jmh.infra.Blackhole; - -public class BatteryBenchmark { - - @State(Scope.Thread) - public static class St { - Battery battery = Battery.getInstance(); - Battery2 battery2 = Battery2.getInstance(); - BatteryOld batteryOld = BatteryOld.getInstance(); - } - - @Benchmark - public void batteryOldMethod(St state, Blackhole b) { - b.consume(state.batteryOld.getVoltage()); - } - - @Benchmark - public void batteryMethod(St state, Blackhole b) { - b.consume(state.battery.getVoltage()); - } - - @Benchmark - public void battery2Method(St state, Blackhole b) { - b.consume(state.battery2.getVoltage()); - } - -} diff --git a/src/main/java/ev3dev/utils/BatteryBenchmarkProgram.java b/src/main/java/ev3dev/utils/BatteryBenchmarkProgram.java deleted file mode 100644 index 7766aa28..00000000 --- a/src/main/java/ev3dev/utils/BatteryBenchmarkProgram.java +++ /dev/null @@ -1,375 +0,0 @@ -package ev3dev.utils; - -import java.util.concurrent.TimeUnit; - -import org.openjdk.jmh.annotations.Mode; -import org.openjdk.jmh.profile.GCProfiler; -import org.openjdk.jmh.profile.StackProfiler; -import org.openjdk.jmh.results.format.ResultFormatType; -import org.openjdk.jmh.runner.Runner; -import org.openjdk.jmh.runner.options.Options; -import org.openjdk.jmh.runner.options.OptionsBuilder; -import org.openjdk.jmh.runner.options.TimeValue; -import org.openjdk.jmh.runner.options.VerboseMode; - -/** - * BatteryBenchmarkProgram - */ -public class BatteryBenchmarkProgram { - - /** - * Main program - * - * @param args args - * @throws Exception ex - */ - public static void main(String[] args) throws Exception { - - Options options = new OptionsBuilder() - .include(BatteryBenchmark.class.getSimpleName()) - - .resultFormat(ResultFormatType.JSON) - .result("/home/robot/jmh-results.json") - .verbosity(VerboseMode.EXTRA) - .mode(Mode.All) - .timeUnit(TimeUnit.MILLISECONDS) - .warmupTime(TimeValue.seconds(0)) - .measurementTime(TimeValue.milliseconds(1)) - .measurementIterations(10) - .threads(Runtime.getRuntime().availableProcessors()) - .warmupIterations(1) - .shouldFailOnError(false) - .shouldDoGC(true) - .forks(2) - .jvmArgs("-Xmx64m", "-Xms64m", "-XX:+UseSerialGC", "-noverify") - .addProfiler(StackProfiler.class) - .addProfiler(GCProfiler.class) - //.addProfiler(LinuxPerfProfiler.class) - //.addProfiler(ClassloaderProfiler.class) - //.addProfiler(CompilerProfiler.class) - //.addProfiler(JmhFlightRecorderProfiler.class) - .build(); - - new Runner(options).run(); - } - -} - -/** - * Benchmark Mode Cnt Score Error Units - * Sysfs_ExistFile_Benchmark.Sysfs2 avgt 10 15.592 ? 27.924 ms/op - * Sysfs_ExistFile_Benchmark.SysfsJNA avgt 10 12.340 ? 8.758 ms/op - * Sysfs_ExistFile_Benchmark.SysfsJNA2 avgt 10 10.810 ? 7.733 ms/op - * Sysfs_ExistFile_Benchmark.SysfsJNA3 avgt 10 8.605 ? 3.080 ms/op - * Sysfs_ExistFile_Benchmark.SysfsOriginal avgt 10 10.002 ? 20.725 ms/op - * Sysfs_existPath_Benchmark.Sysfs2 avgt 10 49.480 ? 46.960 ms/op - * Sysfs_existPath_Benchmark.SysfsJNA avgt 10 46.822 ? 13.254 ms/op - * Sysfs_existPath_Benchmark.SysfsJNA2 avgt 10 42.022 ? 19.543 ms/op - * Sysfs_existPath_Benchmark.SysfsOriginal avgt 10 42.520 ? 27.847 ms/op - * Sysfs_readString_Benchmark.SysfsJNA avgt 10 69.320 ? 22.873 ms/op - * Sysfs_readString_Benchmark.SysfsJNA2 avgt 10 83.479 ? 36.463 ms/op - * Sysfs_readString_Benchmark.SysfsJNA3 avgt 10 89.231 ? 58.068 ms/op - * Sysfs_readString_Benchmark.SysfsOriginal avgt 10 78.398 ? 16.224 ms/op - * Sysfs_writeInteger_Benchmark.Sysfs2 avgt 10 44.641 ? 31.890 ms/op - * Sysfs_writeInteger_Benchmark.SysfsJNA avgt 10 38.574 ? 12.712 ms/op - * Sysfs_writeInteger_Benchmark.SysfsJNA2 avgt 10 36.952 ? 9.491 ms/op - * Sysfs_writeInteger_Benchmark.SysfsJNA3 avgt 10 37.658 ? 13.754 ms/op - * Sysfs_writeInteger_Benchmark.SysfsOriginal avgt 10 41.258 ? 11.446 ms/op - * Sysfs_writeString_Benchmark.Sysfs2 avgt 10 42.764 ? 17.031 ms/op - * Sysfs_writeString_Benchmark.SysfsJNA avgt 10 34.404 ? 6.775 ms/op - * Sysfs_writeString_Benchmark.SysfsJNA2 avgt 10 37.501 ? 6.310 ms/op - * Sysfs_writeString_Benchmark.SysfsJNA3 avgt 10 36.704 ? 30.766 ms/op - * Sysfs_writeString_Benchmark.SysfsOriginal avgt 10 37.589 ? 11.072 ms/op - */ - -/** - Benchmark Mode Cnt Score Error Units - Sysfs_ExistFile_Benchmark.Sysfs2 avgt 20 8.876 ? 7.415 ms/op - Sysfs_ExistFile_Benchmark.Sysfs2:?gc.alloc.rate avgt 20 NaN MB/sec - Sysfs_ExistFile_Benchmark.Sysfs2:?gc.count avgt 20 ? 0 counts - Sysfs_ExistFile_Benchmark.Sysfs2:?stack avgt NaN --- - Sysfs_ExistFile_Benchmark.SysfsJNA avgt 20 17.467 ? 14.597 ms/op - Sysfs_ExistFile_Benchmark.SysfsJNA:?gc.alloc.rate avgt 20 NaN MB/sec - Sysfs_ExistFile_Benchmark.SysfsJNA:?gc.count avgt 20 ? 0 counts - Sysfs_ExistFile_Benchmark.SysfsJNA:?stack avgt NaN --- - Sysfs_ExistFile_Benchmark.SysfsJNA2 avgt 20 19.286 ? 12.194 ms/op - Sysfs_ExistFile_Benchmark.SysfsJNA2:?gc.alloc.rate avgt 20 NaN MB/sec - Sysfs_ExistFile_Benchmark.SysfsJNA2:?gc.count avgt 20 ? 0 counts - Sysfs_ExistFile_Benchmark.SysfsJNA2:?stack avgt NaN --- - Sysfs_ExistFile_Benchmark.SysfsJNA3 avgt 20 21.299 ? 25.011 ms/op - Sysfs_ExistFile_Benchmark.SysfsJNA3:?gc.alloc.rate avgt 20 NaN MB/sec - Sysfs_ExistFile_Benchmark.SysfsJNA3:?gc.count avgt 20 ? 0 counts - Sysfs_ExistFile_Benchmark.SysfsJNA3:?stack avgt NaN --- - Sysfs_ExistFile_Benchmark.SysfsOriginal avgt 20 12.838 ? 15.249 ms/op - Sysfs_ExistFile_Benchmark.SysfsOriginal:?gc.alloc.rate avgt 20 NaN MB/sec - Sysfs_ExistFile_Benchmark.SysfsOriginal:?gc.count avgt 20 ? 0 counts - Sysfs_ExistFile_Benchmark.SysfsOriginal:?stack avgt NaN --- - Sysfs_existPath_Benchmark.Sysfs2 avgt 20 46.367 ? 8.729 ms/op - Sysfs_existPath_Benchmark.Sysfs2:?gc.alloc.rate avgt 20 NaN MB/sec - Sysfs_existPath_Benchmark.Sysfs2:?gc.count avgt 20 ? 0 counts - Sysfs_existPath_Benchmark.Sysfs2:?stack avgt NaN --- - Sysfs_existPath_Benchmark.SysfsJNA avgt 20 81.047 ? 67.046 ms/op - Sysfs_existPath_Benchmark.SysfsJNA:?gc.alloc.rate avgt 20 NaN MB/sec - Sysfs_existPath_Benchmark.SysfsJNA:?gc.count avgt 20 ? 0 counts - Sysfs_existPath_Benchmark.SysfsJNA:?stack avgt NaN --- - Sysfs_existPath_Benchmark.SysfsJNA2 avgt 20 77.890 ? 60.135 ms/op - Sysfs_existPath_Benchmark.SysfsJNA2:?gc.alloc.rate avgt 20 NaN MB/sec - Sysfs_existPath_Benchmark.SysfsJNA2:?gc.count avgt 20 ? 0 counts - Sysfs_existPath_Benchmark.SysfsJNA2:?stack avgt NaN --- - Sysfs_existPath_Benchmark.SysfsOriginal avgt 20 52.415 ? 16.031 ms/op - Sysfs_existPath_Benchmark.SysfsOriginal:?gc.alloc.rate avgt 20 NaN MB/sec - Sysfs_existPath_Benchmark.SysfsOriginal:?gc.count avgt 20 ? 0 counts - Sysfs_existPath_Benchmark.SysfsOriginal:?stack avgt NaN --- - Sysfs_readString_Benchmark.SysfsJNA avgt 20 130.497 ? 64.471 ms/op - Sysfs_readString_Benchmark.SysfsJNA:?gc.alloc.rate avgt 20 NaN MB/sec - Sysfs_readString_Benchmark.SysfsJNA:?gc.count avgt 20 ? 0 counts - Sysfs_readString_Benchmark.SysfsJNA:?stack avgt NaN --- - Sysfs_readString_Benchmark.SysfsJNA2 avgt 20 147.819 ? 130.883 ms/op - Sysfs_readString_Benchmark.SysfsJNA2:?gc.alloc.rate avgt 20 NaN MB/sec - Sysfs_readString_Benchmark.SysfsJNA2:?gc.count avgt 20 ? 0 counts - Sysfs_readString_Benchmark.SysfsJNA2:?stack avgt NaN --- - Sysfs_readString_Benchmark.SysfsJNA3 avgt 20 135.971 ? 106.608 ms/op - Sysfs_readString_Benchmark.SysfsJNA3:?gc.alloc.rate avgt 20 NaN MB/sec - Sysfs_readString_Benchmark.SysfsJNA3:?gc.count avgt 20 ? 0 counts - Sysfs_readString_Benchmark.SysfsJNA3:?stack avgt NaN --- - Sysfs_readString_Benchmark.SysfsOriginal avgt 20 130.898 ? 37.657 ms/op - Sysfs_readString_Benchmark.SysfsOriginal:?gc.alloc.rate avgt 20 NaN MB/sec - Sysfs_readString_Benchmark.SysfsOriginal:?gc.count avgt 20 ? 0 counts - Sysfs_readString_Benchmark.SysfsOriginal:?stack avgt NaN --- - Sysfs_writeInteger_Benchmark.Sysfs2 avgt 20 71.374 ? 43.235 ms/op - Sysfs_writeInteger_Benchmark.Sysfs2:?gc.alloc.rate avgt 20 NaN MB/sec - Sysfs_writeInteger_Benchmark.Sysfs2:?gc.count avgt 20 ? 0 counts - Sysfs_writeInteger_Benchmark.Sysfs2:?stack avgt NaN --- - Sysfs_writeInteger_Benchmark.SysfsJNA avgt 20 101.911 ? 76.781 ms/op - Sysfs_writeInteger_Benchmark.SysfsJNA:?gc.alloc.rate avgt 20 NaN MB/sec - Sysfs_writeInteger_Benchmark.SysfsJNA:?gc.count avgt 20 ? 0 counts - Sysfs_writeInteger_Benchmark.SysfsJNA:?stack avgt NaN --- - Sysfs_writeInteger_Benchmark.SysfsJNA2 avgt 20 95.995 ? 85.353 ms/op - Sysfs_writeInteger_Benchmark.SysfsJNA2:?gc.alloc.rate avgt 20 NaN MB/sec - Sysfs_writeInteger_Benchmark.SysfsJNA2:?gc.count avgt 20 ? 0 counts - Sysfs_writeInteger_Benchmark.SysfsJNA2:?stack avgt NaN --- - Sysfs_writeInteger_Benchmark.SysfsJNA3 avgt 20 104.898 ? 134.129 ms/op - Sysfs_writeInteger_Benchmark.SysfsJNA3:?gc.alloc.rate avgt 20 NaN MB/sec - Sysfs_writeInteger_Benchmark.SysfsJNA3:?gc.count avgt 20 ? 0 counts - Sysfs_writeInteger_Benchmark.SysfsJNA3:?stack avgt NaN --- - Sysfs_writeInteger_Benchmark.SysfsOriginal avgt 20 69.563 ? 29.926 ms/op - Sysfs_writeInteger_Benchmark.SysfsOriginal:?gc.alloc.rate avgt 20 NaN MB/sec - Sysfs_writeInteger_Benchmark.SysfsOriginal:?gc.count avgt 20 ? 0 counts - Sysfs_writeInteger_Benchmark.SysfsOriginal:?stack avgt NaN --- - Sysfs_writeString_Benchmark.Sysfs2 avgt 20 63.268 ? 20.395 ms/op - Sysfs_writeString_Benchmark.Sysfs2:?gc.alloc.rate avgt 20 NaN MB/sec - Sysfs_writeString_Benchmark.Sysfs2:?gc.count avgt 20 ? 0 counts - Sysfs_writeString_Benchmark.Sysfs2:?stack avgt NaN --- - Sysfs_writeString_Benchmark.SysfsJNA avgt 20 77.667 ? 59.439 ms/op - Sysfs_writeString_Benchmark.SysfsJNA:?gc.alloc.rate avgt 20 NaN MB/sec - Sysfs_writeString_Benchmark.SysfsJNA:?gc.count avgt 20 ? 0 counts - Sysfs_writeString_Benchmark.SysfsJNA:?stack avgt NaN --- - Sysfs_writeString_Benchmark.SysfsJNA2 avgt 20 99.891 ? 70.904 ms/op - Sysfs_writeString_Benchmark.SysfsJNA2:?gc.alloc.rate avgt 20 NaN MB/sec - Sysfs_writeString_Benchmark.SysfsJNA2:?gc.count avgt 20 ? 0 counts - Sysfs_writeString_Benchmark.SysfsJNA2:?stack avgt NaN --- - Sysfs_writeString_Benchmark.SysfsJNA3 avgt 20 82.663 ? 88.105 ms/op - Sysfs_writeString_Benchmark.SysfsJNA3:?gc.alloc.rate avgt 20 NaN MB/sec - Sysfs_writeString_Benchmark.SysfsJNA3:?gc.count avgt 20 ? 0 counts - Sysfs_writeString_Benchmark.SysfsJNA3:?stack avgt NaN --- - Sysfs_writeString_Benchmark.SysfsOriginal avgt 20 60.243 ? 16.181 ms/op - Sysfs_writeString_Benchmark.SysfsOriginal:?gc.alloc.rate avgt 20 NaN MB/sec - Sysfs_writeString_Benchmark.SysfsOriginal:?gc.count avgt 20 ? 0 counts - Sysfs_writeString_Benchmark.SysfsOriginal:?stack avgt NaN --- - - */ - -/** - * Benchmark Mode Cnt Score Error Units - * Sysfs_ExistFile_Benchmark.Sysfs2 thrpt 20 0.121 ? 0.057 ops/ms - * Sysfs_ExistFile_Benchmark.Sysfs2:?gc.alloc.rate thrpt 20 NaN MB/sec - * Sysfs_ExistFile_Benchmark.Sysfs2:?gc.count thrpt 20 ? 0 counts - * Sysfs_ExistFile_Benchmark.Sysfs2:?stack thrpt NaN --- - * Sysfs_ExistFile_Benchmark.SysfsJNA thrpt 20 0.088 ? 0.042 ops/ms - * Sysfs_ExistFile_Benchmark.SysfsJNA:?gc.alloc.rate thrpt 20 NaN MB/sec - * Sysfs_ExistFile_Benchmark.SysfsJNA:?gc.count thrpt 20 ? 0 counts - * Sysfs_ExistFile_Benchmark.SysfsJNA:?stack thrpt NaN --- - * Sysfs_ExistFile_Benchmark.SysfsJNA2 thrpt 20 0.079 ? 0.040 ops/ms - * Sysfs_ExistFile_Benchmark.SysfsJNA2:?gc.alloc.rate thrpt 20 NaN MB/sec - * Sysfs_ExistFile_Benchmark.SysfsJNA2:?gc.count thrpt 20 ? 0 counts - * Sysfs_ExistFile_Benchmark.SysfsJNA2:?stack thrpt NaN --- - * Sysfs_ExistFile_Benchmark.SysfsJNA3 thrpt 20 0.085 ? 0.028 ops/ms - * Sysfs_ExistFile_Benchmark.SysfsJNA3:?gc.alloc.rate thrpt 20 NaN MB/sec - * Sysfs_ExistFile_Benchmark.SysfsJNA3:?gc.count thrpt 20 ? 0 counts - * Sysfs_ExistFile_Benchmark.SysfsJNA3:?stack thrpt NaN --- - * Sysfs_ExistFile_Benchmark.SysfsOriginal thrpt 20 0.123 ? 0.052 ops/ms - * Sysfs_ExistFile_Benchmark.SysfsOriginal:?gc.alloc.rate thrpt 20 NaN MB/sec - * Sysfs_ExistFile_Benchmark.SysfsOriginal:?gc.count thrpt 20 ? 0 counts - * Sysfs_ExistFile_Benchmark.SysfsOriginal:?stack thrpt NaN --- - * Sysfs_existPath_Benchmark.Sysfs2 thrpt 20 0.024 ? 0.004 ops/ms - * Sysfs_existPath_Benchmark.Sysfs2:?gc.alloc.rate thrpt 20 NaN MB/sec - * Sysfs_existPath_Benchmark.Sysfs2:?gc.count thrpt 20 ? 0 counts - * Sysfs_existPath_Benchmark.Sysfs2:?stack thrpt NaN --- - * Sysfs_existPath_Benchmark.SysfsJNA thrpt 20 0.022 ? 0.007 ops/ms - * Sysfs_existPath_Benchmark.SysfsJNA:?gc.alloc.rate thrpt 20 NaN MB/sec - * Sysfs_existPath_Benchmark.SysfsJNA:?gc.count thrpt 20 ? 0 counts - * Sysfs_existPath_Benchmark.SysfsJNA:?stack thrpt NaN --- - * Sysfs_existPath_Benchmark.SysfsJNA2 thrpt 20 0.022 ? 0.008 ops/ms - * Sysfs_existPath_Benchmark.SysfsJNA2:?gc.alloc.rate thrpt 20 NaN MB/sec - * Sysfs_existPath_Benchmark.SysfsJNA2:?gc.count thrpt 20 ? 0 counts - * Sysfs_existPath_Benchmark.SysfsJNA2:?stack thrpt NaN --- - * Sysfs_existPath_Benchmark.SysfsOriginal thrpt 20 0.021 ? 0.005 ops/ms - * Sysfs_existPath_Benchmark.SysfsOriginal:?gc.alloc.rate thrpt 20 NaN MB/sec - * Sysfs_existPath_Benchmark.SysfsOriginal:?gc.count thrpt 20 ? 0 counts - * Sysfs_existPath_Benchmark.SysfsOriginal:?stack thrpt NaN --- - * Sysfs_readString_Benchmark.SysfsJNA thrpt 20 0.010 ? 0.003 ops/ms - * Sysfs_readString_Benchmark.SysfsJNA:?gc.alloc.rate thrpt 20 NaN MB/sec - * Sysfs_readString_Benchmark.SysfsJNA:?gc.count thrpt 20 ? 0 counts - * Sysfs_readString_Benchmark.SysfsJNA:?stack thrpt NaN --- - * Sysfs_readString_Benchmark.SysfsJNA2 thrpt 20 0.010 ? 0.003 ops/ms - * Sysfs_readString_Benchmark.SysfsJNA2:?gc.alloc.rate thrpt 20 NaN MB/sec - * Sysfs_readString_Benchmark.SysfsJNA2:?gc.count thrpt 20 ? 0 counts - * Sysfs_readString_Benchmark.SysfsJNA2:?stack thrpt NaN --- - * Sysfs_readString_Benchmark.SysfsJNA3 thrpt 20 0.011 ? 0.004 ops/ms - * Sysfs_readString_Benchmark.SysfsJNA3:?gc.alloc.rate thrpt 20 NaN MB/sec - * Sysfs_readString_Benchmark.SysfsJNA3:?gc.count thrpt 20 ? 0 counts - * Sysfs_readString_Benchmark.SysfsJNA3:?stack thrpt NaN --- - * Sysfs_readString_Benchmark.SysfsOriginal thrpt 20 0.008 ? 0.002 ops/ms - * Sysfs_readString_Benchmark.SysfsOriginal:?gc.alloc.rate thrpt 20 NaN MB/sec - * Sysfs_readString_Benchmark.SysfsOriginal:?gc.count thrpt 20 ? 0 counts - * Sysfs_readString_Benchmark.SysfsOriginal:?stack thrpt NaN --- - * Sysfs_writeInteger_Benchmark.Sysfs2 thrpt 20 0.017 ? 0.004 ops/ms - * Sysfs_writeInteger_Benchmark.Sysfs2:?gc.alloc.rate thrpt 20 NaN MB/sec - * Sysfs_writeInteger_Benchmark.Sysfs2:?gc.count thrpt 20 ? 0 counts - * Sysfs_writeInteger_Benchmark.Sysfs2:?stack thrpt NaN --- - * Sysfs_writeInteger_Benchmark.SysfsJNA thrpt 20 0.016 ? 0.006 ops/ms - * Sysfs_writeInteger_Benchmark.SysfsJNA:?gc.alloc.rate thrpt 20 NaN MB/sec - * Sysfs_writeInteger_Benchmark.SysfsJNA:?gc.count thrpt 20 ? 0 counts - * Sysfs_writeInteger_Benchmark.SysfsJNA:?stack thrpt NaN --- - * Sysfs_writeInteger_Benchmark.SysfsJNA2 thrpt 20 0.016 ? 0.006 ops/ms - * Sysfs_writeInteger_Benchmark.SysfsJNA2:?gc.alloc.rate thrpt 20 NaN MB/sec - * Sysfs_writeInteger_Benchmark.SysfsJNA2:?gc.count thrpt 20 ? 0 counts - * Sysfs_writeInteger_Benchmark.SysfsJNA2:?stack thrpt NaN --- - * Sysfs_writeInteger_Benchmark.SysfsJNA3 thrpt 20 0.017 ? 0.006 ops/ms - * Sysfs_writeInteger_Benchmark.SysfsJNA3:?gc.alloc.rate thrpt 20 NaN MB/sec - * Sysfs_writeInteger_Benchmark.SysfsJNA3:?gc.count thrpt 20 ? 0 counts - * Sysfs_writeInteger_Benchmark.SysfsJNA3:?stack thrpt NaN --- - * Sysfs_writeInteger_Benchmark.SysfsOriginal thrpt 20 0.017 ? 0.004 ops/ms - * Sysfs_writeInteger_Benchmark.SysfsOriginal:?gc.alloc.rate thrpt 20 NaN MB/sec - * Sysfs_writeInteger_Benchmark.SysfsOriginal:?gc.count thrpt 20 ? 0 counts - * Sysfs_writeInteger_Benchmark.SysfsOriginal:?stack thrpt NaN --- - * Sysfs_writeString_Benchmark.Sysfs2 thrpt 20 0.019 ? 0.003 ops/ms - * Sysfs_writeString_Benchmark.Sysfs2:?gc.alloc.rate thrpt 20 NaN MB/sec - * Sysfs_writeString_Benchmark.Sysfs2:?gc.count thrpt 20 ? 0 counts - * Sysfs_writeString_Benchmark.Sysfs2:?stack thrpt NaN --- - * Sysfs_writeString_Benchmark.SysfsJNA thrpt 20 0.015 ? 0.006 ops/ms - * Sysfs_writeString_Benchmark.SysfsJNA:?gc.alloc.rate thrpt 20 NaN MB/sec - * Sysfs_writeString_Benchmark.SysfsJNA:?gc.count thrpt 20 ? 0 counts - * Sysfs_writeString_Benchmark.SysfsJNA:?stack thrpt NaN --- - * Sysfs_writeString_Benchmark.SysfsJNA2 thrpt 20 0.016 ? 0.007 ops/ms - * Sysfs_writeString_Benchmark.SysfsJNA2:?gc.alloc.rate thrpt 20 NaN MB/sec - * Sysfs_writeString_Benchmark.SysfsJNA2:?gc.count thrpt 20 ? 0 counts - * Sysfs_writeString_Benchmark.SysfsJNA2:?stack thrpt NaN --- - * Sysfs_writeString_Benchmark.SysfsJNA3 thrpt 20 0.020 ? 0.008 ops/ms - * Sysfs_writeString_Benchmark.SysfsJNA3:?gc.alloc.rate thrpt 20 NaN MB/sec - * Sysfs_writeString_Benchmark.SysfsJNA3:?gc.count thrpt 20 ? 0 counts - * Sysfs_writeString_Benchmark.SysfsJNA3:?stack thrpt NaN --- - * Sysfs_writeString_Benchmark.SysfsOriginal thrpt 20 0.016 ? 0.003 ops/ms - * Sysfs_writeString_Benchmark.SysfsOriginal:?gc.alloc.rate thrpt 20 NaN MB/sec - * Sysfs_writeString_Benchmark.SysfsOriginal:?gc.count thrpt 20 ? 0 counts - * Sysfs_writeString_Benchmark.SysfsOriginal:?stack thrpt NaN --- - * - * Benchmark result is saved to /home/robot/jmh-results.json - */ - -/** - Benchmark Mode Cnt Score Error Units - Sysfs_ExistFile_Benchmark.Sysfs2 ss 20 15.571 ? 12.105 ms/op - Sysfs_ExistFile_Benchmark.Sysfs2:?gc.alloc.rate ss 20 NaN MB/sec - Sysfs_ExistFile_Benchmark.Sysfs2:?gc.count ss 20 ? 0 counts - Sysfs_ExistFile_Benchmark.Sysfs2:?stack ss NaN --- - Sysfs_ExistFile_Benchmark.SysfsJNA ss 20 19.547 ? 20.092 ms/op - Sysfs_ExistFile_Benchmark.SysfsJNA:?gc.alloc.rate ss 20 NaN MB/sec - Sysfs_ExistFile_Benchmark.SysfsJNA:?gc.count ss 20 ? 0 counts - Sysfs_ExistFile_Benchmark.SysfsJNA:?stack ss NaN --- - Sysfs_ExistFile_Benchmark.SysfsJNA2 ss 20 28.258 ? 48.619 ms/op - Sysfs_ExistFile_Benchmark.SysfsJNA2:?gc.alloc.rate ss 20 NaN MB/sec - Sysfs_ExistFile_Benchmark.SysfsJNA2:?gc.count ss 20 ? 0 counts - Sysfs_ExistFile_Benchmark.SysfsJNA2:?stack ss NaN --- - Sysfs_ExistFile_Benchmark.SysfsJNA3 ss 20 17.829 ? 20.050 ms/op - Sysfs_ExistFile_Benchmark.SysfsJNA3:?gc.alloc.rate ss 20 NaN MB/sec - Sysfs_ExistFile_Benchmark.SysfsJNA3:?gc.count ss 20 ? 0 counts - Sysfs_ExistFile_Benchmark.SysfsJNA3:?stack ss NaN --- - Sysfs_ExistFile_Benchmark.SysfsOriginal ss 20 9.523 ? 3.981 ms/op - Sysfs_ExistFile_Benchmark.SysfsOriginal:?gc.alloc.rate ss 20 NaN MB/sec - Sysfs_ExistFile_Benchmark.SysfsOriginal:?gc.count ss 20 ? 0 counts - Sysfs_ExistFile_Benchmark.SysfsOriginal:?stack ss NaN --- - Sysfs_existPath_Benchmark.Sysfs2 ss 20 39.418 ? 5.533 ms/op - Sysfs_existPath_Benchmark.Sysfs2:?gc.alloc.rate ss 20 NaN MB/sec - Sysfs_existPath_Benchmark.Sysfs2:?gc.count ss 20 ? 0 counts - Sysfs_existPath_Benchmark.Sysfs2:?stack ss NaN --- - Sysfs_existPath_Benchmark.SysfsJNA ss 20 73.290 ? 64.469 ms/op - Sysfs_existPath_Benchmark.SysfsJNA:?gc.alloc.rate ss 20 NaN MB/sec - Sysfs_existPath_Benchmark.SysfsJNA:?gc.count ss 20 ? 0 counts - Sysfs_existPath_Benchmark.SysfsJNA:?stack ss NaN --- - Sysfs_existPath_Benchmark.SysfsJNA2 ss 20 62.707 ? 50.280 ms/op - Sysfs_existPath_Benchmark.SysfsJNA2:?gc.alloc.rate ss 20 NaN MB/sec - Sysfs_existPath_Benchmark.SysfsJNA2:?gc.count ss 20 ? 0 counts - Sysfs_existPath_Benchmark.SysfsJNA2:?stack ss NaN --- - Sysfs_existPath_Benchmark.SysfsOriginal ss 20 43.207 ? 10.250 ms/op - Sysfs_existPath_Benchmark.SysfsOriginal:?gc.alloc.rate ss 20 NaN MB/sec - Sysfs_existPath_Benchmark.SysfsOriginal:?gc.count ss 20 ? 0 counts - Sysfs_existPath_Benchmark.SysfsOriginal:?stack ss NaN --- - Sysfs_readString_Benchmark.SysfsJNA ss 20 114.712 ? 64.723 ms/op - Sysfs_readString_Benchmark.SysfsJNA:?gc.alloc.rate ss 20 NaN MB/sec - Sysfs_readString_Benchmark.SysfsJNA:?gc.count ss 20 ? 0 counts - Sysfs_readString_Benchmark.SysfsJNA:?stack ss NaN --- - Sysfs_readString_Benchmark.SysfsJNA2 ss 20 124.777 ? 69.026 ms/op - Sysfs_readString_Benchmark.SysfsJNA2:?gc.alloc.rate ss 20 NaN MB/sec - Sysfs_readString_Benchmark.SysfsJNA2:?gc.count ss 20 ? 0 counts - Sysfs_readString_Benchmark.SysfsJNA2:?stack ss NaN --- - Sysfs_readString_Benchmark.SysfsJNA3 ss 20 139.290 ? 116.395 ms/op - Sysfs_readString_Benchmark.SysfsJNA3:?gc.alloc.rate ss 20 NaN MB/sec - Sysfs_readString_Benchmark.SysfsJNA3:?gc.count ss 20 ? 0 counts - Sysfs_readString_Benchmark.SysfsJNA3:?stack ss NaN --- - Sysfs_readString_Benchmark.SysfsOriginal ss 20 125.183 ? 35.970 ms/op - Sysfs_readString_Benchmark.SysfsOriginal:?gc.alloc.rate ss 20 NaN MB/sec - Sysfs_readString_Benchmark.SysfsOriginal:?gc.count ss 20 ? 0 counts - Sysfs_readString_Benchmark.SysfsOriginal:?stack ss NaN --- - Sysfs_writeInteger_Benchmark.Sysfs2 ss 20 57.790 ? 13.316 ms/op - Sysfs_writeInteger_Benchmark.Sysfs2:?gc.alloc.rate ss 20 NaN MB/sec - Sysfs_writeInteger_Benchmark.Sysfs2:?gc.count ss 20 ? 0 counts - Sysfs_writeInteger_Benchmark.Sysfs2:?stack ss NaN --- - Sysfs_writeInteger_Benchmark.SysfsJNA ss 20 102.920 ? 66.352 ms/op - Sysfs_writeInteger_Benchmark.SysfsJNA:?gc.alloc.rate ss 20 NaN MB/sec - Sysfs_writeInteger_Benchmark.SysfsJNA:?gc.count ss 20 ? 0 counts - Sysfs_writeInteger_Benchmark.SysfsJNA:?stack ss NaN --- - Sysfs_writeInteger_Benchmark.SysfsJNA2 ss 20 112.213 ? 119.813 ms/op - Sysfs_writeInteger_Benchmark.SysfsJNA2:?gc.alloc.rate ss 20 NaN MB/sec - Sysfs_writeInteger_Benchmark.SysfsJNA2:?gc.count ss 20 ? 0 counts - Sysfs_writeInteger_Benchmark.SysfsJNA2:?stack ss NaN --- - Sysfs_writeInteger_Benchmark.SysfsJNA3 ss 20 82.762 ? 93.211 ms/op - Sysfs_writeInteger_Benchmark.SysfsJNA3:?gc.alloc.rate ss 20 NaN MB/sec - Sysfs_writeInteger_Benchmark.SysfsJNA3:?gc.count ss 20 ? 0 counts - Sysfs_writeInteger_Benchmark.SysfsJNA3:?stack ss NaN --- - Sysfs_writeInteger_Benchmark.SysfsOriginal ss 20 67.545 ? 39.738 ms/op - Sysfs_writeInteger_Benchmark.SysfsOriginal:?gc.alloc.rate ss 20 NaN MB/sec - Sysfs_writeInteger_Benchmark.SysfsOriginal:?gc.count ss 20 ? 0 counts - Sysfs_writeInteger_Benchmark.SysfsOriginal:?stack ss NaN --- - Sysfs_writeString_Benchmark.Sysfs2 ss 20 57.017 ? 19.105 ms/op - Sysfs_writeString_Benchmark.Sysfs2:?gc.alloc.rate ss 20 NaN MB/sec - Sysfs_writeString_Benchmark.Sysfs2:?gc.count ss 20 ? 0 counts - Sysfs_writeString_Benchmark.Sysfs2:?stack ss NaN --- - Sysfs_writeString_Benchmark.SysfsJNA ss 20 75.872 ? 59.289 ms/op - Sysfs_writeString_Benchmark.SysfsJNA:?gc.alloc.rate ss 20 NaN MB/sec - Sysfs_writeString_Benchmark.SysfsJNA:?gc.count ss 20 ? 0 counts - Sysfs_writeString_Benchmark.SysfsJNA:?stack ss NaN --- - Sysfs_writeString_Benchmark.SysfsJNA2 ss 20 93.195 ? 70.036 ms/op - Sysfs_writeString_Benchmark.SysfsJNA2:?gc.alloc.rate ss 20 NaN MB/sec - Sysfs_writeString_Benchmark.SysfsJNA2:?gc.count ss 20 ? 0 counts - Sysfs_writeString_Benchmark.SysfsJNA2:?stack ss NaN --- - Sysfs_writeString_Benchmark.SysfsJNA3 ss 20 89.512 ? 78.663 ms/op - Sysfs_writeString_Benchmark.SysfsJNA3:?gc.alloc.rate ss 20 NaN MB/sec - Sysfs_writeString_Benchmark.SysfsJNA3:?gc.count ss 20 ? 0 counts - Sysfs_writeString_Benchmark.SysfsJNA3:?stack ss NaN --- - Sysfs_writeString_Benchmark.SysfsOriginal ss 20 55.680 ? 15.191 ms/op - Sysfs_writeString_Benchmark.SysfsOriginal:?gc.alloc.rate ss 20 NaN MB/sec - Sysfs_writeString_Benchmark.SysfsOriginal:?gc.count ss 20 ? 0 counts - Sysfs_writeString_Benchmark.SysfsOriginal:?stack ss NaN --- - - */ diff --git a/src/main/java/ev3dev/utils/DataChannelRereader2.java b/src/main/java/ev3dev/utils/DataChannelRereader2.java deleted file mode 100644 index 3f747006..00000000 --- a/src/main/java/ev3dev/utils/DataChannelRereader2.java +++ /dev/null @@ -1,118 +0,0 @@ -package ev3dev.utils; - -import java.io.Closeable; -import java.io.IOException; -import java.nio.ByteBuffer; -import java.nio.channels.FileChannel; -import java.nio.charset.StandardCharsets; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.nio.file.StandardOpenOption; - -/** - * Reader of streams that can reread the same channel for structured data of - * known length. The focus of this class is on performance. - * - *

Because of its specialization to ev3dev sysfs attributes, it is able - * to read at most 4096 bytes. - * - *

Objects of this class are safe to use from multiple threads when used in - * a standard manner, see documentation of individual methods for details. - * - *

Note: this class contains a static ThreadLocal<ByteBuffer>. - * This may cause problems with massive and long-lived thread pools. - * - * @author David Walend - */ -public class DataChannelRereader2 implements Closeable { - /** - * Thread-local buffer for reading data from sysfs. - * - *

Each NIO read() needs a pre-allocated buffer into which - * data are stored. This makes the code utilizing it responsible - * for buffer management. Here it is solved by keeping around - * a generously sized buffer (4096 = memory page size). - * By making the buffer thread-local, we avoid data races - * on buffer contents. The buffer can also be made static, - * as there is little benefit to keeping it local to class instances. - */ - private static final ThreadLocal byteBuffer = - ThreadLocal.withInitial(() -> ByteBuffer.allocate(4096)); - - /** - * Real file path, primarily for logging purposes. - */ - private final Path path; - - /** - * NIO channel opened for the path. - */ - private final FileChannel channel; - - /** - * Create a DataChannelRereader for the specified path. - * - * @param path path to the file to reread - */ - public DataChannelRereader2(Path path) { - this.path = path; - try { - this.channel = FileChannel.open(path, StandardOpenOption.READ); - } catch (IOException e) { - throw new RuntimeException("Problem opening path: " + path, e); - } - } - - /** - * Create a DataChannelRereader for the specified path. - * - * @param pathString path to the file to reread - */ - public DataChannelRereader2(String pathString) { - this(Paths.get(pathString)); - } - - /** - * Read the current file contents and return them as a string. - * - *

You can safely call this function from multiple threads in parallel. - * However, you must not call this function in parallel with close() or - * after close() was called. - * - * @return String contents of the file without a trailing newline. - */ - public String readString() { - try { - // prepare the thread-local buffer - ByteBuffer buffer = byteBuffer.get(); - buffer.clear(); - - // try to do the read - // only one try, as: - // - value >0 indicates success - // - value =0 indicates empty attribute (???) - // - value <0 indicates empty attribute - int n = channel.read(buffer, 0); - // minus one reliably occurs on empty file, zero should be similar - if (n <= 0) { - return ""; - } - - // strip trailing newline & return data as a string - // rationale: ev3dev sysfs often appends \n, but this breaks parseFloat/parseInt/... - byte[] bytes = buffer.array(); - if (bytes[n - 1] == '\n') { - return new String(bytes, 0, n - 1, StandardCharsets.UTF_8); - } else { - return new String(bytes, 0, n, StandardCharsets.UTF_8); - } - } catch (IOException e) { - throw new RuntimeException("Problem reading path: " + path, e); - } - } - - @Override - public void close() throws IOException { - channel.close(); - } -} diff --git a/src/main/java/ev3dev/utils/DataChannelRereaderJMCTest.java b/src/main/java/ev3dev/utils/DataChannelRereaderJMCTest.java deleted file mode 100644 index dc2c7e2a..00000000 --- a/src/main/java/ev3dev/utils/DataChannelRereaderJMCTest.java +++ /dev/null @@ -1,77 +0,0 @@ -package ev3dev.utils; - -import lombok.extern.slf4j.Slf4j; - -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.concurrent.CompletableFuture; -import java.util.stream.IntStream; - -@Slf4j -public class DataChannelRereaderJMCTest { - - final static String fileName = "./race.txt"; - final static Integer limit = 200000; - - public static void createFiles() throws IOException { - Files.writeString(Path.of(fileName), "test1234"); - } - - /** - * Reader1 <- race.txt - * Reader2 <- race.txt - * Reader3 <- race.txt - * Reader4 <- race.txt - */ - public static void main(String[] args) throws Exception{ - - createFiles(); - - DataChannelRereader reader = new DataChannelRereader(fileName); - - CompletableFuture rq1 = asyncReadFile(reader); - CompletableFuture rq2 = asyncReadFile(reader); - CompletableFuture rq3 = asyncReadFile(reader); - CompletableFuture rq4 = asyncReadFile(reader); - - CompletableFuture combinedFuture = CompletableFuture.allOf(rq1, rq2, rq3, rq4); - combinedFuture.join(); - - /* - then(rq1.isDone()).isTrue(); - then(rq2.isDone()).isTrue(); - then(rq3.isDone()).isTrue(); - then(rq4.isDone()).isTrue(); - - then(rq1.join()).isEqualTo("Ok asyncReadFile"); - then(rq2.join()).isEqualTo("Ok asyncReadFile"); - then(rq3.join()).isEqualTo("Ok asyncReadFile"); - then(rq4.join()).isEqualTo("Ok asyncReadFile"); - - System.out.println("End"); - */ - } - - private static void readFile(DataChannelRereader reader) { - reader.readString(); - //then(reader.readString()).isEqualTo("test1234"); - } - - private static CompletableFuture asyncReadFile(DataChannelRereader reader) { - CompletableFuture cf1 = CompletableFuture.supplyAsync(() -> { - IntStream - .rangeClosed(1, limit) - .forEach(i -> readFile(reader)); - return "Ok asyncReadFile"; - }) - .handle((input, exception) -> { - if (exception != null) { - LOGGER.warn(exception.getLocalizedMessage(), exception); - return "Ko asyncReadFile"; - } - return input; - }); - return cf1; - } -} diff --git a/src/main/java/ev3dev/utils/Sysfs2.java b/src/main/java/ev3dev/utils/Sysfs2.java deleted file mode 100644 index 341126f2..00000000 --- a/src/main/java/ev3dev/utils/Sysfs2.java +++ /dev/null @@ -1,152 +0,0 @@ -package ev3dev.utils; - -import java.io.File; -import java.io.IOException; -import java.io.PrintWriter; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.nio.file.StandardOpenOption; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import lombok.extern.slf4j.Slf4j; - -/** - * The class responsible to interact with Sysfs on EV3Dev - * - * @author Juan Antonio Breña Moral - * @author David Walend - * - */ -@Slf4j -public class Sysfs2 { - - /** - * Write a value in a file. - * - * @param filePath File path - * @param value value to write - * @return A boolean value if the operation was written or not. - */ - public static boolean writeString(final String filePath, final String value) { - if (LOGGER.isTraceEnabled()) { - LOGGER.trace("echo " + value + " > " + filePath); - } - try { - final File file = new File(filePath); - if (file.canWrite()) { - //TODO Review if it possible to improve - PrintWriter out = new PrintWriter(file); - out.println(value); - out.flush(); - out.close(); - //TODO Review - } else { - LOGGER.error("File: '{}' without write permissions.", filePath); - return false; - } - } catch (IOException e) { - LOGGER.error(e.getLocalizedMessage(), e); - return false; - } - return true; - } - - public static boolean writeInteger(final String filePath, final int value) { - return writeString(filePath, new StringBuilder().append(value).toString()); - } - - /** - * Read an Attribute in the Sysfs with containing String values - * - * @param filePath path - * @return value from attribute - */ - public static String readString(final String filePath) { - if (LOGGER.isTraceEnabled()) { - LOGGER.trace("cat " + filePath); - } - try { - try (DataChannelRereader2 rereader = new DataChannelRereader2(filePath)) { - String result = rereader.readString(); - if (LOGGER.isTraceEnabled()) { - LOGGER.trace("value: {}", result); - } - return result; - } - } catch (IOException e) { - LOGGER.error(e.getLocalizedMessage(), e); - throw new RuntimeException("Problem reading path: " + filePath, e); - } - } - - /** - * Read an Attribute in the Sysfs with containing Integer values - * - * @param filePath path - * @return value from attribute - */ - public static int readInteger(final String filePath) { - return Integer.parseInt(readString(filePath)); - } - - /** - * Read an Attribute in the Sysfs with containing Float values - * - * @param filePath path - * @return value from attribute - */ - public static float readFloat(final String filePath) { - return Float.parseFloat(readString(filePath)); - } - - /** - * Retrieve the elements contained in a path - * - * @param filePath path - * @return an List with options from a path - */ - public static List getElements(final String filePath) { - final File f = new File(filePath); - if (existPath(filePath) && (f.listFiles().length > 0)) { - return new ArrayList<>(Arrays.asList(f.listFiles())); - } else { - throw new RuntimeException("The path doesn't exist: " + filePath); - } - } - - /** - * This method is used to detect folders in /sys/class/ - * - * @param filePath path - * @return boolean - */ - public static boolean existPath(final String filePath) { - if (LOGGER.isTraceEnabled()) { - LOGGER.trace("ls " + filePath); - } - final File f = new File(filePath); - return f.exists() && f.isDirectory(); - } - - public static boolean existFile(Path pathToFind) { - return Files.exists(pathToFind); - } - - /** - * Method to write bytes in a path - * - * @param path path - * @param value value to write - * @return Result - */ - public static boolean writeBytes(final String path, final byte[] value) { - try { - Files.write(Paths.get(path), value, StandardOpenOption.WRITE); - } catch (IOException e) { - throw new RuntimeException("Unable to draw the LCD", e); - } - return true; - } -} diff --git a/src/main/java/ev3dev/utils/SysfsOld.java b/src/main/java/ev3dev/utils/SysfsOld.java deleted file mode 100644 index eaedf56d..00000000 --- a/src/main/java/ev3dev/utils/SysfsOld.java +++ /dev/null @@ -1,148 +0,0 @@ -package ev3dev.utils; - -import org.slf4j.Logger; - -import java.io.File; -import java.io.IOException; -import java.io.PrintWriter; -import java.nio.charset.Charset; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.nio.file.StandardOpenOption; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -/** - * The class responsible to interact with Sysfs on EV3Dev - * - * @author Juan Antonio Breña Moral - */ -public class SysfsOld { - - private static final Logger log = org.slf4j.LoggerFactory.getLogger(SysfsOld.class); - - /** - * Write a value in a file. - * - * @param filePath File path - * @param value value to write - * @return A boolean value if the operation was written or not. - */ - public static boolean writeString(final String filePath, final String value) { - if (log.isTraceEnabled()) { - log.trace("echo " + value + " > " + filePath); - } - try { - final File file = new File(filePath); - if (file.canWrite()) { - //TODO Review if it possible to improve - PrintWriter out = new PrintWriter(file); - out.println(value); - out.flush(); - out.close(); - //TODO Review - } else { - log.error("File: '{}' without write permissions.", filePath); - return false; - } - } catch (IOException e) { - log.error(e.getLocalizedMessage(), e); - return false; - } - return true; - } - - public static boolean writeInteger(final String filePath, final int value) { - return writeString(filePath, new StringBuilder().append(value).toString()); - } - - /** - * Read an Attribute in the Sysfs with containing String values - * - * @param filePath path - * @return value from attribute - */ - public static String readString(final String filePath) { - if (log.isTraceEnabled()) { - log.trace("cat " + filePath); - } - try { - final Path path = Paths.get(filePath); - if (existFile(path) && Files.isReadable(path)) { - final String result = Files.readAllLines(path, Charset.forName("UTF-8")).get(0); - if (log.isTraceEnabled()) { - log.trace("value: {}", result); - } - return result; - } - throw new IOException("Problem reading path: " + filePath); - } catch (IOException e) { - log.error(e.getLocalizedMessage(), e); - throw new RuntimeException("Problem reading path: " + filePath, e); - } - } - - /** - * Read an Attribute in the Sysfs with containing Integer values - * - * @param filePath path - * @return value from attribute - */ - public static int readInteger(final String filePath) { - return Integer.parseInt(readString(filePath)); - } - - public static float readFloat(final String filePath) { - return Float.parseFloat(readString(filePath)); - } - - /** - * @param filePath path - * @return an List with options from a path - */ - public static List getElements(final String filePath) { - final File f = new File(filePath); - if (existPath(filePath) && (f.listFiles().length > 0)) { - return new ArrayList<>(Arrays.asList(f.listFiles())); - } else { - throw new RuntimeException("The path doesn't exist: " + filePath); - } - } - - /** - * This method is used to detect folders in /sys/class/ - * - * @param filePath path - * @return boolean - */ - public static boolean existPath(final String filePath) { - if (log.isTraceEnabled()) { - log.trace("ls " + filePath); - } - final File f = new File(filePath); - return f.exists() && f.isDirectory(); - } - - public static boolean existFile(Path pathToFind) { - return Files.exists(pathToFind); - } - - /** - * Method to write bytes in a path - * - * @param path path - * @param value value to write - * @return Result - */ - public static boolean writeBytes(final String path, final byte[] value) { - try { - Files.write(Paths.get(path), value, StandardOpenOption.WRITE); - } catch (IOException e) { - throw new RuntimeException("Unable to draw the LCD", e); - } - return true; - } - -} diff --git a/src/test/java/ev3dev/utils/DataChannelRereader2ConcurrencyTest.java b/src/test/java/ev3dev/utils/DataChannelRereader2ConcurrencyTest.java deleted file mode 100644 index d129209e..00000000 --- a/src/test/java/ev3dev/utils/DataChannelRereader2ConcurrencyTest.java +++ /dev/null @@ -1,279 +0,0 @@ -package ev3dev.utils; - -import java.io.File; -import java.util.concurrent.CompletableFuture; -import java.util.stream.IntStream; -import lombok.SneakyThrows; -import lombok.extern.slf4j.Slf4j; -import org.junit.Before; -import org.junit.Ignore; -import org.junit.Test; - -import static org.assertj.core.api.BDDAssertions.then; - -@Slf4j -public class DataChannelRereader2ConcurrencyTest { - - final String fileName = "./pairs.txt"; - final String fileName2 = "./odds.txt"; - final Integer limit = 1000; - - @Before - @SneakyThrows - public void createFiles() { - new File(fileName).createNewFile(); - new File(fileName2).createNewFile(); - } - - /** - * Writer1 -> pairs.txt - * Reader1 <- pairs.txt - * Reader2 <- pairs.txt - * - * Writer1 -> odds.txt - * Reader1 <- odds.txt - * Reader2 <- odds.txt - */ - @Test - @Ignore - public void given_multiple_DataChannelRereader_when_execute_concurrently_then_Ok() { - - CompletableFuture request1 = asyncWriteFile(true); - CompletableFuture request2 = asyncWriteFile(false); - CompletableFuture request3 = asyncReadFile(true); - CompletableFuture request4 = asyncReadFile(false); - CompletableFuture request5 = asyncReadFile2(true); - CompletableFuture request6 = asyncReadFile2(false); - - CompletableFuture combinedFuture = CompletableFuture.allOf( - request1, - request2, - request3, - request4, - request5, - request6); - - combinedFuture.join(); - - then(request1.isDone()).isTrue(); - then(request2.isDone()).isTrue(); - then(request3.isDone()).isTrue(); - then(request4.isDone()).isTrue(); - then(request5.isDone()).isTrue(); - then(request6.isDone()).isTrue(); - - then(request1.join()).isEqualTo("Ok asyncWriteFile"); - then(request2.join()).isEqualTo("Ok asyncWriteFile"); - then(request3.join()).isEqualTo("Ok asyncReadFile"); - then(request4.join()).isEqualTo("Ok asyncReadFile"); - then(request5.join()).isEqualTo("Ok asyncReadFile2"); - then(request6.join()).isEqualTo("Ok asyncReadFile2"); - - System.out.println("End"); - } - - private void readFile(String file, Boolean flag) { - Integer value = Sysfs2.readInteger(file); - if (flag) { - then(value % 2 == 0).isTrue(); - } else { - then(value % 2 != 0).isTrue(); - } - } - - private void readFile2(String file, Boolean flag) { - DataChannelRereader2 dataChannelRereader = new DataChannelRereader2(file); - Integer value = Integer.parseInt(dataChannelRereader.readString()); - if (flag) { - then(value % 2 == 0).isTrue(); - } else { - then(value % 2 != 0).isTrue(); - } - } - - private CompletableFuture asyncReadFile(boolean flag) { - CompletableFuture cf1 = CompletableFuture.supplyAsync(() -> { - IntStream - .rangeClosed(1, limit) - .forEach(i -> { - if (flag) { - readFile(fileName, flag); - } else { - readFile(fileName2, flag); - } - }); - return "Ok asyncReadFile"; - }) - .handle((input, exception) -> { - if (exception != null) { - LOGGER.warn(exception.getLocalizedMessage(), exception); - return "Ko asyncReadFile"; - } - return input; - }); - return cf1; - } - - private CompletableFuture asyncReadFile2(boolean flag) { - CompletableFuture cf = CompletableFuture.supplyAsync(() -> { - IntStream - .rangeClosed(1, limit) - .forEach(i -> { - if (flag) { - readFile2(fileName, flag); - } else { - readFile2(fileName2, flag); - } - }); - return "Ok asyncReadFile2"; - }) - .handle((input, exception) -> { - if (exception != null) { - LOGGER.warn(exception.getLocalizedMessage(), exception); - return "Ko asyncReadFile2"; - } - return input; - }); - return cf; - } - - private void writeFile(String file, String value) { - Sysfs2.writeString(file, value); - } - - private CompletableFuture asyncWriteFile(boolean flag) { - CompletableFuture cf = CompletableFuture.supplyAsync(() -> { - IntStream - .rangeClosed(1, limit) - .filter(i -> { - if (flag) { - return i % 2 == 0; - } else { - return i % 2 != 0; - } - }) - .forEach(i -> { - if (flag) { - writeFile(fileName, String.valueOf(i)); - } else { - writeFile(fileName2, String.valueOf(i)); - } - }); - return "Ok asyncWriteFile"; - }) - .handle((input, exception) -> { - if (exception != null) { - LOGGER.warn(exception.getLocalizedMessage(), exception); - return "Ko asyncWriteFile"; - } - return input; - }); - - return cf; - } - - /** - * Writer1 -> pairs.txt - * Reader1 <- pairs.txt - * - * Writer1 -> odds.txt - * Reader1 <- odds.txt - */ - @Test - @Ignore - public void given_multiple_DataChannelRereader_when_execute_concurrently_then_Ok2() { - - CompletableFuture request1 = asyncWriteFile(true); - CompletableFuture request2 = asyncWriteFile(false); - CompletableFuture request3 = asyncReadFile(true); - CompletableFuture request4 = asyncReadFile(false); - - CompletableFuture combinedFuture = CompletableFuture.allOf( - request1, - request2, - request3, - request4); - - combinedFuture.join(); - - then(request1.isDone()).isTrue(); - then(request2.isDone()).isTrue(); - then(request3.isDone()).isTrue(); - then(request4.isDone()).isTrue(); - - then(request1.join()).isEqualTo("Ok asyncWriteFile"); - then(request2.join()).isEqualTo("Ok asyncWriteFile"); - then(request3.join()).isEqualTo("Ok asyncReadFile"); - then(request4.join()).isEqualTo("Ok asyncReadFile"); - - System.out.println("End"); - } - - /** - * Reader1 <- pairs.txt - * Reader1 <- odds.txt - */ - @Test - public void given_multiple_DataChannelRereader_when_execute_concurrently_then_Ok3() { - - writeFile(fileName, "2"); - writeFile(fileName2, "1"); - - CompletableFuture request1 = asyncReadFile(true); - CompletableFuture request2 = asyncReadFile(false); - - CompletableFuture combinedFuture = CompletableFuture.allOf( - request1, - request2); - - combinedFuture.join(); - - then(request1.isDone()).isTrue(); - then(request2.isDone()).isTrue(); - - then(request1.join()).isEqualTo("Ok asyncReadFile"); - then(request2.join()).isEqualTo("Ok asyncReadFile"); - - System.out.println("End"); - } - - /** - * Writer1 -> pairs.txt Once - * Writer1 -> odds.txt Once - * Reader1 <- pairs.txt - * Reader1 <- odds.txt - * Reader2 <- pairs.txt - * Reader2 <- odds.txt - */ - @Test - public void given_multiple_DataChannelRereader_when_execute_concurrently_then_Ok4() { - - writeFile(fileName, "2"); - writeFile(fileName2, "1"); - - CompletableFuture request1 = asyncReadFile(true); - CompletableFuture request2 = asyncReadFile(false); - CompletableFuture request3 = asyncReadFile2(true); - CompletableFuture request4 = asyncReadFile2(false); - - CompletableFuture combinedFuture = CompletableFuture.allOf( - request1, - request2, - request3, - request4); - - combinedFuture.join(); - - then(request1.isDone()).isTrue(); - then(request2.isDone()).isTrue(); - then(request3.isDone()).isTrue(); - then(request4.isDone()).isTrue(); - - then(request1.join()).isEqualTo("Ok asyncReadFile"); - then(request2.join()).isEqualTo("Ok asyncReadFile"); - then(request3.join()).isEqualTo("Ok asyncReadFile2"); - then(request4.join()).isEqualTo("Ok asyncReadFile2"); - - System.out.println("End"); - } -} diff --git a/src/test/java/ev3dev/utils/DataChannelRereader2RaceTest.java b/src/test/java/ev3dev/utils/DataChannelRereader2RaceTest.java deleted file mode 100644 index 34956171..00000000 --- a/src/test/java/ev3dev/utils/DataChannelRereader2RaceTest.java +++ /dev/null @@ -1,78 +0,0 @@ -package ev3dev.utils; - -import lombok.SneakyThrows; -import lombok.extern.slf4j.Slf4j; -import org.junit.Before; -import org.junit.Test; - -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.concurrent.CompletableFuture; -import java.util.stream.IntStream; - -import static org.assertj.core.api.BDDAssertions.then; - -@Slf4j -public class DataChannelRereader2RaceTest { - - final String fileName = "./race2.txt"; - final Integer limit = 10000; - - @Before - @SneakyThrows - public void createFiles() throws IOException { - Files.writeString(Path.of(fileName), "test1234"); - } - - /** - * Reader1 <- race.txt - * Reader2 <- race.txt - * Reader3 <- race.txt - * Reader4 <- race.txt - */ - @Test - public void given_multiple_DataChannelRereader_when_execute_concurrently_then_Ok() { - DataChannelRereader2 reader = new DataChannelRereader2(fileName); - - CompletableFuture rq1 = asyncReadFile(reader); - CompletableFuture rq2 = asyncReadFile(reader); - CompletableFuture rq3 = asyncReadFile(reader); - CompletableFuture rq4 = asyncReadFile(reader); - - CompletableFuture combinedFuture = CompletableFuture.allOf(rq1, rq2, rq3, rq4); - combinedFuture.join(); - - then(rq1.isDone()).isTrue(); - then(rq2.isDone()).isTrue(); - then(rq3.isDone()).isTrue(); - then(rq4.isDone()).isTrue(); - - then(rq1.join()).isEqualTo("Ok asyncReadFile"); - then(rq2.join()).isEqualTo("Ok asyncReadFile"); - then(rq3.join()).isEqualTo("Ok asyncReadFile"); - then(rq4.join()).isEqualTo("Ok asyncReadFile"); - System.out.println("End"); - } - - private void readFile(DataChannelRereader2 reader) { - then(reader.readString()).isEqualTo("test1234"); - } - - private CompletableFuture asyncReadFile(DataChannelRereader2 reader) { - CompletableFuture cf1 = CompletableFuture.supplyAsync(() -> { - IntStream - .rangeClosed(1, limit) - .forEach(i -> readFile(reader)); - return "Ok asyncReadFile"; - }) - .handle((input, exception) -> { - if (exception != null) { - LOGGER.warn(exception.getLocalizedMessage(), exception); - return "Ko asyncReadFile"; - } - return input; - }); - return cf1; - } -} diff --git a/src/test/java/ev3dev/utils/DataChannelRereader3ConcurrencyTest.java b/src/test/java/ev3dev/utils/DataChannelRereader3ConcurrencyTest.java deleted file mode 100644 index 85f59f58..00000000 --- a/src/test/java/ev3dev/utils/DataChannelRereader3ConcurrencyTest.java +++ /dev/null @@ -1,226 +0,0 @@ -package ev3dev.utils; - -import java.io.File; -import java.util.concurrent.CompletableFuture; -import java.util.stream.IntStream; -import lombok.SneakyThrows; -import lombok.extern.slf4j.Slf4j; -import org.junit.Before; -import org.junit.Ignore; -import org.junit.Test; - -import static org.assertj.core.api.BDDAssertions.then; - -@Slf4j -public class DataChannelRereader3ConcurrencyTest { - - final String fileName = "./pairs.txt"; - final String fileName2 = "./odds.txt"; - final Integer limit = 1000; - - @Before - @SneakyThrows - public void createFiles() { - new File(fileName).createNewFile(); - new File(fileName2).createNewFile(); - } - - private void readFile(String file, Boolean flag) { - Integer value = SysfsOld.readInteger(file); - if (flag) { - then(value % 2 == 0).isTrue(); - } else { - then(value % 2 != 0).isTrue(); - } - } - - private CompletableFuture asyncReadFile(boolean flag) { - CompletableFuture cf1 = CompletableFuture.supplyAsync(() -> { - IntStream - .rangeClosed(1, limit) - .forEach(i -> { - if (flag) { - readFile(fileName, flag); - } else { - readFile(fileName2, flag); - } - }); - return "Ok asyncReadFile"; - }) - .handle((input, exception) -> { - if (exception != null) { - LOGGER.warn(exception.getLocalizedMessage(), exception); - return "Ko asyncReadFile"; - } - return input; - }); - return cf1; - } - - private void writeFile(String file, String value) { - SysfsOld.writeString(file, value); - } - - private CompletableFuture asyncWriteFile(boolean flag) { - CompletableFuture cf = CompletableFuture.supplyAsync(() -> { - IntStream - .rangeClosed(1, limit) - .filter(i -> { - if (flag) { - return i % 2 == 0; - } else { - return i % 2 != 0; - } - }) - .forEach(i -> { - if (flag) { - writeFile(fileName, String.valueOf(i)); - } else { - writeFile(fileName2, String.valueOf(i)); - } - }); - return "Ok asyncWriteFile"; - }) - .handle((input, exception) -> { - if (exception != null) { - LOGGER.warn(exception.getLocalizedMessage(), exception); - return "Ko asyncWriteFile"; - } - return input; - }); - - return cf; - } - - /** - * Writer1 -> pairs.txt - * Reader1 <- pairs.txt - * - * Writer1 -> odds.txt - * Reader1 <- odds.txt - */ - @Ignore - @Test - public void given_multiple_SysfsOld_when_execute_concurrently_then_Ok() { - - CompletableFuture request1 = asyncWriteFile(true); - CompletableFuture request2 = asyncWriteFile(false); - CompletableFuture request3 = asyncReadFile(true); - CompletableFuture request4 = asyncReadFile(false); - - CompletableFuture combinedFuture = CompletableFuture.allOf( - request1, - request2, - request3, - request4); - - combinedFuture.join(); - - then(request1.isDone()).isTrue(); - then(request2.isDone()).isTrue(); - then(request3.isDone()).isTrue(); - then(request4.isDone()).isTrue(); - - then(request1.join()).isEqualTo("Ok asyncWriteFile"); - then(request2.join()).isEqualTo("Ok asyncWriteFile"); - then(request3.join()).isEqualTo("Ok asyncReadFile"); - then(request4.join()).isEqualTo("Ok asyncReadFile"); - - System.out.println("End"); - } - - /** - * Writer1 -> pairs.txt - * Reader1 <- pairs.txt - * - */ - @Ignore - @Test - public void given_multiple_SysfsOld_when_execute_concurrently_then_Ok2() { - - CompletableFuture request1 = asyncWriteFile(true); - CompletableFuture request3 = asyncReadFile(true); - - CompletableFuture combinedFuture = CompletableFuture.allOf( - request1, - request3); - - combinedFuture.join(); - - then(request1.isDone()).isTrue(); - then(request3.isDone()).isTrue(); - - then(request1.join()).isEqualTo("Ok asyncWriteFile"); - then(request3.join()).isEqualTo("Ok asyncReadFile"); - - System.out.println("End"); - } - - /** - * Reader1 <- pairs.txt - * Reader1 <- odds.txt - */ - @Test - public void given_multiple_DataChannelRereader_when_execute_concurrently_then_Ok3() { - - writeFile(fileName, "2"); - writeFile(fileName2, "1"); - - CompletableFuture request1 = asyncReadFile(true); - CompletableFuture request2 = asyncReadFile(false); - - CompletableFuture combinedFuture = CompletableFuture.allOf( - request1, - request2); - - combinedFuture.join(); - - then(request1.isDone()).isTrue(); - then(request2.isDone()).isTrue(); - - then(request1.join()).isEqualTo("Ok asyncReadFile"); - then(request2.join()).isEqualTo("Ok asyncReadFile"); - - System.out.println("End"); - } - - /** - * Writer1 -> pairs.txt Once - * Writer1 -> odds.txt Once - * Reader1 <- pairs.txt - * Reader1 <- odds.txt - * Reader2 <- pairs.txt - * Reader2 <- odds.txt - */ - @Test - public void given_multiple_DataChannelRereader_when_execute_concurrently_then_Ok4() { - - writeFile(fileName, "2"); - writeFile(fileName2, "1"); - - CompletableFuture request1 = asyncReadFile(true); - CompletableFuture request2 = asyncReadFile(false); - CompletableFuture request3 = asyncReadFile(true); - CompletableFuture request4 = asyncReadFile(false); - - CompletableFuture combinedFuture = CompletableFuture.allOf( - request1, - request2, - request3, - request4); - - combinedFuture.join(); - - then(request1.isDone()).isTrue(); - then(request2.isDone()).isTrue(); - then(request3.isDone()).isTrue(); - then(request4.isDone()).isTrue(); - - then(request1.join()).isEqualTo("Ok asyncReadFile"); - then(request2.join()).isEqualTo("Ok asyncReadFile"); - then(request3.join()).isEqualTo("Ok asyncReadFile"); - then(request4.join()).isEqualTo("Ok asyncReadFile"); - - System.out.println("End"); - } -} diff --git a/src/test/java/ev3dev/utils/SysfsOldRaceTest.java b/src/test/java/ev3dev/utils/SysfsOldRaceTest.java deleted file mode 100644 index 0368523e..00000000 --- a/src/test/java/ev3dev/utils/SysfsOldRaceTest.java +++ /dev/null @@ -1,78 +0,0 @@ -package ev3dev.utils; - -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.concurrent.CompletableFuture; -import java.util.stream.IntStream; -import lombok.SneakyThrows; -import lombok.extern.slf4j.Slf4j; -import org.junit.Before; -import org.junit.Test; - -import static org.assertj.core.api.BDDAssertions.then; - -@Slf4j -public class SysfsOldRaceTest { - - final String fileName = "./race.txt"; - final Integer limit = 10000; - - @Before - @SneakyThrows - public void createFiles() throws IOException { - Files.writeString(Path.of(fileName), "test1234"); - } - - /** - * Reader1 <- race.txt - * Reader2 <- race.txt - * Reader3 <- race.txt - * Reader4 <- race.txt - */ - @Test - public void given_multiple_DataChannelRereader_when_execute_concurrently_then_Ok() { - DataChannelRereader reader = new DataChannelRereader(fileName); - - CompletableFuture rq1 = asyncReadFile(reader); - CompletableFuture rq2 = asyncReadFile(reader); - CompletableFuture rq3 = asyncReadFile(reader); - CompletableFuture rq4 = asyncReadFile(reader); - - CompletableFuture combinedFuture = CompletableFuture.allOf(rq1, rq2, rq3, rq4); - combinedFuture.join(); - - then(rq1.isDone()).isTrue(); - then(rq2.isDone()).isTrue(); - then(rq3.isDone()).isTrue(); - then(rq4.isDone()).isTrue(); - - then(rq1.join()).isEqualTo("Ok asyncReadFile"); - then(rq2.join()).isEqualTo("Ok asyncReadFile"); - then(rq3.join()).isEqualTo("Ok asyncReadFile"); - then(rq4.join()).isEqualTo("Ok asyncReadFile"); - System.out.println("End"); - } - - private void readFile(DataChannelRereader reader) { - //then(reader.readString()).isEqualTo("test1234"); - then(SysfsOld.readString(fileName)).isEqualTo("test1234"); - } - - private CompletableFuture asyncReadFile(DataChannelRereader reader) { - CompletableFuture cf1 = CompletableFuture.supplyAsync(() -> { - IntStream - .rangeClosed(1, limit) - .forEach(i -> readFile(reader)); - return "Ok asyncReadFile"; - }) - .handle((input, exception) -> { - if (exception != null) { - LOGGER.warn(exception.getLocalizedMessage(), exception); - return "Ko asyncReadFile"; - } - return input; - }); - return cf1; - } -} From ad94ee0ea0dbca79684dc64d11d95156fc153867 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Antonio=20Bre=C3=B1a=20Moral?= Date: Thu, 7 Jan 2021 16:47:00 +0100 Subject: [PATCH 32/34] Removing SneakyThrows in the tests. --- .../ev3dev/utils/DataChannelRereaderTest.java | 26 +++++++------------ 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/src/test/java/ev3dev/utils/DataChannelRereaderTest.java b/src/test/java/ev3dev/utils/DataChannelRereaderTest.java index 1fbd4127..86a8352b 100644 --- a/src/test/java/ev3dev/utils/DataChannelRereaderTest.java +++ b/src/test/java/ev3dev/utils/DataChannelRereaderTest.java @@ -1,6 +1,6 @@ package ev3dev.utils; -import lombok.SneakyThrows; +import java.io.IOException; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; @@ -24,37 +24,32 @@ public class DataChannelRereaderTest { static final String differentTestString = "Different String"; @BeforeClass - @SneakyThrows - public static void createFiles() { + public static void createFiles() throws IOException { tempDirectory = Files.createTempDirectory("DataChannelRereaderTest"); testPath = Files.createFile(Path.of(tempDirectory.toString(),"testFile")); Files.write(testPath, testString.getBytes()); } @Before - @SneakyThrows - public void writeFile() { + public void writeFile() throws IOException { Files.write(testPath, testString.getBytes()); } @AfterClass - @SneakyThrows - public static void cleanupFiles() { + public static void cleanupFiles() throws IOException { Files.delete(testPath); Files.delete(tempDirectory); } @Test - @SneakyThrows - public void testOpenClose() { + public void testOpenClose() throws IOException { DataChannelRereader rereader = new DataChannelRereader(testPath,32); rereader.close(); } @Test - @SneakyThrows - public void testOpenReadClose() { + public void testOpenReadClose() throws IOException { DataChannelRereader rereader = new DataChannelRereader(testPath,32); String readString = rereader.readString(); rereader.close(); @@ -63,8 +58,7 @@ public void testOpenReadClose() { } @Test - @SneakyThrows - public void testClosable() { + public void testClosable() throws IOException { try(DataChannelRereader rereader = new DataChannelRereader(testPath,32)){ String readString = rereader.readString(); assertEquals(testString,readString); @@ -72,8 +66,7 @@ public void testClosable() { } @Test - @SneakyThrows - public void testOpenReadTwoThingsClose() { + public void testOpenReadTwoThingsClose() throws IOException { DataChannelRereader rereader = new DataChannelRereader(testPath,32); String readString = rereader.readString(); assertEquals(testString,readString); @@ -87,8 +80,7 @@ public void testOpenReadTwoThingsClose() { } @Test(expected = RuntimeException.class) - @SneakyThrows - public void testOpenNonexistentFile() { + public void testOpenNonexistentFile() throws IOException { Path badPath = Path.of("/does/not/exist"); DataChannelRereader rereader = new DataChannelRereader(badPath,32); From f46dd9c1d661003c392f21ccd4f7c8e9f423b1de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Antonio=20Bre=C3=B1a=20Moral?= Date: Sat, 9 Jan 2021 17:31:09 +0100 Subject: [PATCH 33/34] Updating FakeLed object to Stretch paths Fixing Tests for EV3Led Upgrading properties to remove references to /sys/class Removing some non necessary dependencies in Build path --- build.gradle | 9 +- .../java/ev3dev/actuators/ev3/EV3Led.java | 24 ++-- src/main/resources/META-INF/MANIFEST.MF | 1 - src/main/resources/jessie.properties | 8 +- src/main/resources/logback.xml | 23 ---- src/main/resources/simplelogger.properties | 18 --- src/main/resources/stretch.properties | 8 +- .../java/ev3dev/actuators/ev3/EV3LedTest.java | 109 ++++++++++-------- .../ev3dev/actuators/{ => ev3}/FakeLed.java | 15 ++- 9 files changed, 93 insertions(+), 122 deletions(-) delete mode 100644 src/main/resources/logback.xml delete mode 100644 src/main/resources/simplelogger.properties rename src/test/java/fake_ev3dev/ev3dev/actuators/{ => ev3}/FakeLed.java (82%) diff --git a/build.gradle b/build.gradle index 60cdc980..1c3ba8d6 100644 --- a/build.gradle +++ b/build.gradle @@ -39,9 +39,7 @@ dependencies { api("com.github.ev3dev-lang-java:lejos-commons:0.7.3") api("net.java.dev.jna:jna:4.5.2") - implementation("org.slf4j:slf4j-simple:1.7.25") - - //testImplementation("ch.qos.logback:logback-classic:1.2.3") + testImplementation("ch.qos.logback:logback-classic:1.2.3") testImplementation("commons-io:commons-io:2.5") //TODO: Upgrade to JUnit 5 @@ -49,11 +47,6 @@ dependencies { //TODO: Review to add Mockito support testImplementation("org.hamcrest:hamcrest-all:1.3") testImplementation("org.assertj:assertj-core:3.18.1") - - //TODO: Later this dependencies will be for test only testImplementation - api("org.openjdk.jmh:jmh-core:1.26") - annotationProcessor("org.openjdk.jmh:jmh-generator-annprocess:1.26") - } compileJava.options.encoding = 'UTF-8' diff --git a/src/main/java/ev3dev/actuators/ev3/EV3Led.java b/src/main/java/ev3dev/actuators/ev3/EV3Led.java index e54e2590..7326104f 100644 --- a/src/main/java/ev3dev/actuators/ev3/EV3Led.java +++ b/src/main/java/ev3dev/actuators/ev3/EV3Led.java @@ -1,11 +1,11 @@ package ev3dev.actuators.ev3; import ev3dev.hardware.EV3DevDevice; +import ev3dev.hardware.EV3DevFileSystem; import ev3dev.hardware.EV3DevPlatform; import ev3dev.utils.DataChannelRewriter; import lejos.hardware.LED; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import lombok.extern.slf4j.Slf4j; import java.io.Closeable; import java.io.IOException; @@ -15,6 +15,7 @@ * *

Only EV3Bricks are supported. */ +@Slf4j public class EV3Led extends EV3DevDevice implements LED, Closeable { /** @@ -24,10 +25,8 @@ public enum Direction { LEFT, RIGHT } - - private static final Direction[] directionArray = {Direction.LEFT,Direction.RIGHT}; - private static final Logger log = LoggerFactory.getLogger(EV3Led.class); + private static final Direction[] directionArray = {Direction.LEFT,Direction.RIGHT}; /** * @deprecated Use EV3LedDirection.LEFT instead. @@ -56,18 +55,19 @@ public EV3Led(final Direction direction) { //TODO Refactor if (direction == null) { - log.error("You are not specifying any button."); + LOGGER.error("You are not specifying any button."); throw new IllegalArgumentException("You are not specifying any button."); } this.direction = direction; + String ledPath = EV3DevFileSystem.getRootPath(); if (direction == Direction.LEFT) { - redWriter = new DataChannelRewriter(ev3DevProperties.getProperty("ev3.led.left.red")); - greenWriter = new DataChannelRewriter(ev3DevProperties.getProperty("ev3.led.left.green")); + redWriter = new DataChannelRewriter(ledPath + ev3DevProperties.getProperty("ev3.led.left.red")); + greenWriter = new DataChannelRewriter(ledPath + ev3DevProperties.getProperty("ev3.led.left.green")); } else { - redWriter = new DataChannelRewriter(ev3DevProperties.getProperty("ev3.led.right.red")); - greenWriter = new DataChannelRewriter(ev3DevProperties.getProperty("ev3.led.right.green")); + redWriter = new DataChannelRewriter(ledPath + ev3DevProperties.getProperty("ev3.led.right.red")); + greenWriter = new DataChannelRewriter(ledPath + ev3DevProperties.getProperty("ev3.led.right.green")); } } @@ -90,7 +90,7 @@ public EV3Led(final int button) { */ private void checkPlatform() { if (!CURRENT_PLATFORM.equals(EV3DevPlatform.EV3BRICK)) { - log.error("This actuator is specific of: {}", EV3DevPlatform.EV3BRICK); + LOGGER.error("This actuator is specific of: {}", EV3DevPlatform.EV3BRICK); throw new RuntimeException("This actuator is specific of: " + EV3DevPlatform.EV3BRICK); } } @@ -125,7 +125,7 @@ public void setPattern(final int pattern) { greenWriter.writeString(on); redWriter.writeString(on); } else if (pattern > 3) { - log.debug("This feature is not implemented"); + LOGGER.debug("This feature is not implemented"); } } diff --git a/src/main/resources/META-INF/MANIFEST.MF b/src/main/resources/META-INF/MANIFEST.MF index 8741f117..54a59969 100755 --- a/src/main/resources/META-INF/MANIFEST.MF +++ b/src/main/resources/META-INF/MANIFEST.MF @@ -2,4 +2,3 @@ Manifest-Version: 1.0 Implementation-Title: EV3Dev-lang-java Implementation-Version: 2.7.0-SNAPSHOT Implementation-Vendor: Juan Antonio Breña Moral -Main-Class: ev3dev.utils.DataChannelRereaderJMCTest diff --git a/src/main/resources/jessie.properties b/src/main/resources/jessie.properties index f6044b38..4024e53c 100644 --- a/src/main/resources/jessie.properties +++ b/src/main/resources/jessie.properties @@ -43,10 +43,10 @@ pistorms.sensor.port.3=pistorms:BAS1 pistorms.sensor.port.4=pistorms:BAS2 #LED -ev3.led.left.red=/sys/class/leds/ev3:left:red:ev3dev/brightness -ev3.led.left.green=/sys/class/leds/ev3:left:green:ev3dev/brightness -ev3.led.right.red=/sys/class/leds/ev3:right:red:ev3dev/brightness -ev3.led.right.green=/sys/class/leds/ev3:right:green:ev3dev/brightness +ev3.led.left.red=/leds/ev3:left:red:ev3dev/brightness +ev3.led.left.green=/leds/ev3:left:green:ev3dev/brightness +ev3.led.right.red=/leds/ev3:right:red:ev3dev/brightness +ev3.led.right.green=/leds/ev3:right:green:ev3dev/brightness #KEY ev3.key=/dev/input/by-path/platform-gpio-keys.0-event diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml deleted file mode 100644 index dcea232c..00000000 --- a/src/main/resources/logback.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - System.err - - - %d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n - - - - - - - - - - - - - diff --git a/src/main/resources/simplelogger.properties b/src/main/resources/simplelogger.properties deleted file mode 100644 index a1143482..00000000 --- a/src/main/resources/simplelogger.properties +++ /dev/null @@ -1,18 +0,0 @@ -# SLF4J's SimpleLogger configuration file -# Simple implementation of Logger that sends all enabled log messages, for all defined loggers, to System.err. - -org.slf4j.simpleLogger.defaultLogLevel=info - -#org.slf4j.simpleLogger.log.ev3dev.hardware=trace -#org.slf4j.simpleLogger.log.ev3dev.utils=trace - - - -org.slf4j.simpleLogger.showDateTime=true -org.slf4j.simpleLogger.dateTimeFormat=yyyy-MM-dd HH:mm:ss -org.slf4j.simpleLogger.showThreadName=true -org.slf4j.simpleLogger.showLogName=true -org.slf4j.simpleLogger.showShortLogName=false - -org.slf4j.simpleLogger.logFile=System.err -#org.slf4j.simpleLogger.logFile=/home/robot/java/programs/logs.log diff --git a/src/main/resources/stretch.properties b/src/main/resources/stretch.properties index fc54fe91..801dd7e6 100644 --- a/src/main/resources/stretch.properties +++ b/src/main/resources/stretch.properties @@ -43,10 +43,10 @@ pistorms.sensor.port.3=pistorms:BAS1 pistorms.sensor.port.4=pistorms:BAS2 #LED -ev3.led.left.red=/sys/class/leds/led0:red:brick-status/brightness -ev3.led.left.green=/sys/class/leds/led0:green:brick-status/brightness -ev3.led.right.red=/sys/class/leds/led1:red:brick-status/brightness -ev3.led.right.green=/sys/class/leds/led1:green:brick-status/brightness +ev3.led.left.red=/leds/led0:red:brick-status/brightness +ev3.led.left.green=/leds/led0:green:brick-status/brightness +ev3.led.right.red=/leds/led1:red:brick-status/brightness +ev3.led.right.green=/leds/led1:green:brick-status/brightness #KEY ev3.key=/dev/input/by-path/platform-gpio_keys-event diff --git a/src/test/java/ev3dev/actuators/ev3/EV3LedTest.java b/src/test/java/ev3dev/actuators/ev3/EV3LedTest.java index 6d9048cd..0e8358cb 100644 --- a/src/test/java/ev3dev/actuators/ev3/EV3LedTest.java +++ b/src/test/java/ev3dev/actuators/ev3/EV3LedTest.java @@ -2,89 +2,94 @@ import ev3dev.hardware.EV3DevFileSystem; import ev3dev.hardware.EV3DevPlatform; -import fake_ev3dev.ev3dev.actuators.FakeLed; +import fake_ev3dev.ev3dev.actuators.ev3.FakeLed; import fake_ev3dev.ev3dev.sensors.FakeBattery; import lejos.hardware.LED; -import org.junit.*; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; import org.junit.rules.ExpectedException; import java.io.IOException; +import static org.assertj.core.api.BDDAssertions.then; + public class EV3LedTest { + //TODO Refactor exception cases with JUnit 5 @Rule public ExpectedException thrown = ExpectedException.none(); @Before - public void resetTest() throws IOException, NoSuchFieldException, IllegalAccessException { - - //Reset the singleton - //https://stackoverflow.com/questions/8256989/singleton-and-unit-testing - //Field instance = Sound.class.getDeclaredField("instance"); - //instance.setAccessible(true); - //instance.set(null, null); - - FakeBattery.resetEV3DevInfrastructure(); + public void resetTest() throws IOException { System.setProperty(EV3DevFileSystem.EV3DEV_TESTING_KEY, FakeBattery.EV3DEV_FAKE_SYSTEM_PATH); + FakeBattery.resetEV3DevInfrastructure(); + new FakeBattery(EV3DevPlatform.EV3BRICK); } @Test - public void constructorLeftTest() throws Exception { + public void given_actuator_when_useConstructorLeft_then_Ok() throws Exception { - final FakeBattery fakeBattery = new FakeBattery(EV3DevPlatform.EV3BRICK); + //Given + FakeLed fakeLed = new FakeLed(EV3DevPlatform.EV3BRICK); + //When @SuppressWarnings("deprecation") LED led = new EV3Led(EV3Led.LEFT); - led = new EV3Led(EV3Led.Direction.LEFT); - } - - @Test - public void constructorRightTest() throws Exception { + LED led2 = new EV3Led(EV3Led.Direction.LEFT); - final FakeBattery fakeBattery = new FakeBattery(EV3DevPlatform.EV3BRICK); - - @SuppressWarnings("deprecation") LED led = new EV3Led(EV3Led.RIGHT); - led = new EV3Led(EV3Led.Direction.RIGHT); + //Then + then(led).isNotNull(); + then(led2).isNotNull(); } - @Ignore("Review how to reset a Static classic in JUnit") @Test - public void usingLedOnEV3BrickPlatformTest() throws Exception { + public void given_actuator_when_useConstructorRight_then_Ok() throws Exception { - thrown.expect(RuntimeException.class); + //Given + FakeLed fakeLed = new FakeLed(EV3DevPlatform.EV3BRICK); - final FakeBattery fakeBattery = new FakeBattery(EV3DevPlatform.BRICKPI); + //When + @SuppressWarnings("deprecation") LED led = new EV3Led(EV3Led.RIGHT); + LED led2 = new EV3Led(EV3Led.Direction.RIGHT); - LED led = new EV3Led(EV3Led.Direction.LEFT); + //Then + then(led).isNotNull(); + then(led2).isNotNull(); } @Test - public void badButtonTest() throws Exception { + public void given_actuator_when_useConstructorWithBadParameter_then_Ko() throws Exception { - thrown.expect(RuntimeException.class); - - final FakeBattery fakeBattery = new FakeBattery(EV3DevPlatform.EV3BRICK); + //Given + FakeLed fakeLed = new FakeLed(EV3DevPlatform.EV3BRICK); + //When + //Then + thrown.expect(ArrayIndexOutOfBoundsException.class); @SuppressWarnings("deprecation") LED led = new EV3Led(4); } @Test - public void badDirectionTest() throws Exception { - - thrown.expect(IllegalArgumentException.class); + public void given_actuator_when_useConstructorWithNull_then_Ko() throws Exception { - final FakeBattery fakeBattery = new FakeBattery(EV3DevPlatform.EV3BRICK); + //Given + FakeLed fakeLed = new FakeLed(EV3DevPlatform.EV3BRICK); + //When + //Then + thrown.expect(IllegalArgumentException.class); LED led = new EV3Led(null); } @Test - public void leftLedPatternsTest() throws Exception { + public void given_actuator_when_leftPatterns_then_Ok() throws Exception { - final FakeBattery fakeBattery = new FakeBattery(EV3DevPlatform.EV3BRICK); - final FakeLed fakeLed = new FakeLed(EV3DevPlatform.EV3BRICK); + //Given + FakeLed fakeLed = new FakeLed(EV3DevPlatform.EV3BRICK); + //When LED led = new EV3Led(EV3Led.Direction.LEFT); led.setPattern(1); led.setPattern(2); @@ -96,14 +101,18 @@ public void leftLedPatternsTest() throws Exception { led.setPattern(2); led.setPattern(3); led.setPattern(4); + + //Then + //TODO Currently, it is not possible to execute a verify or something similar } @Test - public void rightLedPatternsTest() throws Exception { + public void given_actuator_when_rightPatterns_then_Ok() throws Exception { - final FakeBattery fakeBattery = new FakeBattery(EV3DevPlatform.EV3BRICK); - final FakeLed fakeLed = new FakeLed(EV3DevPlatform.EV3BRICK); + //Given + FakeLed fakeLed = new FakeLed(EV3DevPlatform.EV3BRICK); + //When @SuppressWarnings("deprecation") LED led = new EV3Led(EV3Led.RIGHT); led.setPattern(1); led.setPattern(2); @@ -115,19 +124,25 @@ public void rightLedPatternsTest() throws Exception { led.setPattern(2); led.setPattern(3); led.setPattern(4); + + //Then + //TODO Currently, it is not possible to execute a verify or something similar } @Test - public void getDirectionTest() throws Exception { + public void given_actuator_when_getDirection_then_Ok() throws Exception { - final FakeBattery fakeBattery = new FakeBattery(EV3DevPlatform.EV3BRICK); - final FakeLed fakeLed = new FakeLed(EV3DevPlatform.EV3BRICK); + //Given + FakeLed fakeLed = new FakeLed(EV3DevPlatform.EV3BRICK); + //When @SuppressWarnings("deprecation") EV3Led led = new EV3Led(EV3Led.RIGHT); - Assert.assertEquals(EV3Led.Direction.RIGHT, led.getDirection()); + EV3Led led2 = new EV3Led(EV3Led.Direction.RIGHT); - led = new EV3Led(EV3Led.Direction.RIGHT); - Assert.assertEquals(EV3Led.Direction.RIGHT, led.getDirection()); + //Then + EV3Led.Direction expectdedDirection = EV3Led.Direction.RIGHT; + then(led.getDirection()).isEqualTo(expectdedDirection); + then(led2.getDirection()).isEqualTo(expectdedDirection); } } diff --git a/src/test/java/fake_ev3dev/ev3dev/actuators/FakeLed.java b/src/test/java/fake_ev3dev/ev3dev/actuators/ev3/FakeLed.java similarity index 82% rename from src/test/java/fake_ev3dev/ev3dev/actuators/FakeLed.java rename to src/test/java/fake_ev3dev/ev3dev/actuators/ev3/FakeLed.java index 23063021..c2478571 100644 --- a/src/test/java/fake_ev3dev/ev3dev/actuators/FakeLed.java +++ b/src/test/java/fake_ev3dev/ev3dev/actuators/ev3/FakeLed.java @@ -1,18 +1,21 @@ -package fake_ev3dev.ev3dev.actuators; +package fake_ev3dev.ev3dev.actuators.ev3; import ev3dev.hardware.EV3DevPlatform; +import ev3dev.utils.Shell; import fake_ev3dev.BaseElement; import java.io.IOException; import java.nio.file.Path; import java.nio.file.Paths; +import lombok.extern.slf4j.Slf4j; +@Slf4j public class FakeLed extends BaseElement{ - public static final String LEFT_LED = "leds/ev3:left"; - public static final String RIGHT_LED = "leds/ev3:right"; - public static final String RED_LED = ":red:ev3dev"; - public static final String GREEN_LED = ":green:ev3dev"; + public static final String LEFT_LED = "leds/led0"; + public static final String RIGHT_LED = "leds/led1"; + public static final String RED_LED = ":red:brick-status"; + public static final String GREEN_LED = ":green:brick-status"; public static final String BRIGHTNESS = "brightness"; public FakeLed(final EV3DevPlatform ev3DevPlatform) throws IOException { @@ -71,6 +74,8 @@ public FakeLed(final EV3DevPlatform ev3DevPlatform) throws IOException { BRIGHTNESS); createFile(ledLeftRedBrightness); + var result = Shell.execute("tree " + EV3DEV_FAKE_SYSTEM_PATH); + LOGGER.info(result); } } From e92b1c952d3812425ee03aece8c53dfe5b44ebcd Mon Sep 17 00:00:00 2001 From: dwalend Date: Wed, 13 Jan 2021 23:11:52 -0500 Subject: [PATCH 34/34] Added a test of DataChannelRewriter --- .../ev3dev/utils/DataChannelRewriterTest.java | 92 +++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 src/test/java/ev3dev/utils/DataChannelRewriterTest.java diff --git a/src/test/java/ev3dev/utils/DataChannelRewriterTest.java b/src/test/java/ev3dev/utils/DataChannelRewriterTest.java new file mode 100644 index 00000000..dcc534b1 --- /dev/null +++ b/src/test/java/ev3dev/utils/DataChannelRewriterTest.java @@ -0,0 +1,92 @@ +package ev3dev.utils; + +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; + +import static org.junit.Assert.assertEquals; + +/** + * Some tests of DataChannelRewriter. + * + * @author David Walend + */ +public class DataChannelRewriterTest { + + static Path tempDirectory; + static Path testPath; + static final String startString = "Original String"; + static final String differentString = "Written String"; + + @BeforeClass + public static void createFiles() throws IOException { + tempDirectory = Files.createTempDirectory("DataChannelRewriterTest"); + testPath = Files.createFile(Path.of(tempDirectory.toString(),"testFile")); + Files.write(testPath, startString.getBytes()); + } + + @Before + public void writeFile() throws IOException { + Files.write(testPath, startString.getBytes()); + } + + @AfterClass + public static void cleanupFiles() throws IOException { + Files.delete(testPath); + Files.delete(tempDirectory); + } + + + @Test + public void testOpenClose() throws IOException { + DataChannelRewriter rewriter = new DataChannelRewriter(testPath,32); + rewriter.close(); + + assertEquals(startString,Files.readString(testPath)); + } + + @Test + public void testOpenReadClose() throws IOException { + DataChannelRewriter rewriter = new DataChannelRewriter(testPath,32); + rewriter.writeString(differentString); + rewriter.close(); + + assertEquals(differentString+"\n",Files.readString(testPath)); + } + + @Test + public void testClosable() throws IOException { + try(DataChannelRewriter rewriter = new DataChannelRewriter(testPath,32)){ + rewriter.writeString(differentString); + } + assertEquals(differentString+"\n",Files.readString(testPath)); + } + + @Test + public void testOpenWriteTwoThingsClose() throws IOException { + DataChannelRewriter rewriter = new DataChannelRewriter(testPath,32); + rewriter.writeString(differentString); + assertEquals(differentString+"\n",Files.readString(testPath)); + + String anotherString = "Another String"; + rewriter.writeString(anotherString); + + assertEquals(anotherString+"\n",Files.readString(testPath)); + + rewriter.close(); + } + + @Test(expected = RuntimeException.class) + public void testOpenNonexistentFile() throws IOException { + Path badPath = Path.of("/does/not/exist"); + + DataChannelRewriter rewriter = new DataChannelRewriter(badPath,32); + rewriter.writeString(differentString); + rewriter.close(); + } +}