1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.rng.examples.stress;
18
19 import org.apache.commons.rng.UniformRandomProvider;
20 import org.apache.commons.rng.core.source32.IntProvider;
21
22 import picocli.CommandLine.Command;
23 import picocli.CommandLine.Mixin;
24 import picocli.CommandLine.Option;
25 import picocli.CommandLine.Parameters;
26
27 import java.io.BufferedWriter;
28 import java.io.File;
29 import java.io.IOException;
30 import java.io.Writer;
31 import java.nio.ByteOrder;
32 import java.nio.IntBuffer;
33 import java.nio.file.Files;
34 import java.util.ArrayList;
35 import java.util.List;
36 import java.util.concurrent.Callable;
37 import java.util.concurrent.ThreadLocalRandom;
38
39
40
41
42
43
44
45
46 @Command(name = "bridge",
47 description = {"Transfer test 32-bit data to a test application sub-process via standard input."})
48 class BridgeTestCommand implements Callable<Void> {
49
50 @Mixin
51 private StandardOptions reusableOptions;
52
53
54 @Parameters(index = "0",
55 description = "The stress test executable.")
56 private File executable;
57
58
59 @Parameters(index = "1..*",
60 description = "The arguments to pass to the executable.",
61 paramLabel = "<argument>")
62 private List<String> executableArguments = new ArrayList<>();
63
64
65 @Option(names = {"--prefix"},
66 description = "Results file prefix (default: ${DEFAULT-VALUE}).")
67 private File fileOutputPrefix = new File("bridge");
68
69
70 @Option(names = {"-b", "--byte-order"},
71 description = {"Byte-order of the transferred data (default: ${DEFAULT-VALUE}).",
72 "Valid values: BIG_ENDIAN, LITTLE_ENDIAN."})
73 private ByteOrder byteOrder = ByteOrder.nativeOrder();
74
75
76
77
78 @Override
79 public Void call() {
80 LogUtils.setLogLevel(reusableOptions.logLevel);
81 ProcessUtils.checkExecutable(executable);
82 ProcessUtils.checkOutputDirectory(fileOutputPrefix);
83 runBridgeTest();
84 return null;
85 }
86
87
88
89
90
91 private void runBridgeTest() {
92 final List<String> command = ProcessUtils.buildSubProcessCommand(executable, executableArguments);
93
94 try {
95 final File dataFile = new File(fileOutputPrefix + ".data");
96 final File outputFile = new File(fileOutputPrefix + ".out");
97 final File errorFile = new File(fileOutputPrefix + ".err");
98
99
100 final IntBuffer buffer = IntBuffer.allocate(Integer.SIZE * 2);
101
102 try (BufferedWriter textOutput = Files.newBufferedWriter(dataFile.toPath())) {
103
104 int value = 1;
105 for (int i = 0; i < Integer.SIZE; i++) {
106 writeInt(textOutput, buffer, value);
107 value <<= 1;
108 }
109
110
111 while (buffer.remaining() != 0) {
112 writeInt(textOutput, buffer, ThreadLocalRandom.current().nextInt());
113 }
114 }
115
116
117 buffer.flip();
118 final UniformRandomProvider rng = new IntProvider() {
119 @Override
120 public int next() {
121 return buffer.get();
122 }
123 };
124
125
126 final ProcessBuilder builder = new ProcessBuilder(command);
127 builder.redirectOutput(ProcessBuilder.Redirect.to(outputFile));
128 builder.redirectError(ProcessBuilder.Redirect.to(errorFile));
129 final Process testingProcess = builder.start();
130
131
132
133
134 final Source64Mode source64 = null;
135 try (RngDataOutput sink = RNGUtils.createDataOutput(rng, source64,
136 testingProcess.getOutputStream(), buffer.capacity() * 4, byteOrder)) {
137 sink.write(rng);
138 }
139
140 final Integer exitValue = ProcessUtils.getExitValue(testingProcess);
141 if (exitValue == null) {
142 LogUtils.error("%s did not exit. Process was killed.", command.get(0));
143 } else {
144 final int value = exitValue;
145 if (value != 0) {
146 LogUtils.error("%s exit code = %d", command.get(0), value);
147 }
148 }
149
150 } catch (IOException ex) {
151 throw new ApplicationException("Failed to run process: " + ex.getMessage(), ex);
152 }
153 }
154
155
156
157
158
159
160
161
162
163
164
165
166 private static void writeInt(Writer textOutput,
167 IntBuffer buffer,
168 int value) throws IOException {
169 OutputCommand.writeInt(textOutput, value);
170 buffer.put(value);
171 }
172 }