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(); + } +} pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy