Skip to content

Commit ca47c7e

Browse files
authored
Merge pull request XDagger#25 from LucasMLK/develop
2 parents 473a936 + d3d1fea commit ca47c7e

19 files changed

+1398
-840
lines changed

README.md

Lines changed: 20 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ To include `xdagj-native-randomx` in your project, add the following dependency
115115
<dependency>
116116
<groupId>io.xdag</groupId>
117117
<artifactId>xdagj-native-randomx</artifactId>
118-
<version>0.2.0</version>
118+
<version>0.2.2</version>
119119
</dependency>
120120
```
121121

@@ -138,27 +138,27 @@ public class Example {
138138
byte[] keyBytes = key.getBytes(StandardCharsets.UTF_8);
139139

140140
// Get supported RandomX flags for the current CPU
141-
Set<RandomXFlag> flags = RandomXUtils.getFlagsSet();
141+
Set<RandomXFlag> flags = RandomXUtils.getRecommendedFlags();
142142
System.out.println("Supported flags: " + flags);
143-
int combinedFlags = RandomXFlag.toValue(flags);
144-
System.out.println("Combined flags value: " + combinedFlags);
145143

146-
// Initialize RandomX cache with the supported flags
144+
// Initialize RandomX cache (key will be set via template)
147145
RandomXCache cache = new RandomXCache(flags);
148-
cache.init(keyBytes);
149146

150147
// Create and configure RandomXTemplate using builder pattern
151148
byte[] hash;
152149
try (RandomXTemplate template = RandomXTemplate.builder()
153150
.cache(cache)
154-
.miningMode(false) // Set to false for normal hashing mode
151+
.miningMode(false)
155152
.flags(flags)
156153
.build()) {
157154

158-
// Initialize the template with the configured settings
155+
// Set the key for RandomX operations. This will initialize the cache.
156+
template.changeKey(keyBytes);
157+
158+
// Initialize the template's VM with the configured settings
159159
template.init();
160160

161-
// Calculate hash of the input key
161+
// Calculate hash of the input
162162
hash = template.calculateHash(keyBytes);
163163
}
164164

@@ -184,10 +184,10 @@ public class Example {
184184
### Linux Performance Results
185185
| Benchmark | Mode | Cnt | Score | Error | Units |
186186
|:------------------------------:|:-----:|:---:|:-------:|:------:|:-----:|
187-
| RandomXBenchmark.lightBatch | thrpt | | 328.736 | | ops/s |
188-
| RandomXBenchmark.lightNoBatch | thrpt | | 325.383 | | ops/s |
189-
| RandomXBenchmark.miningBatch | thrpt | | 2777.939 | | ops/s |
190-
| RandomXBenchmark.miningNoBatch | thrpt | | 2817.811 | | ops/s |
187+
| RandomXBenchmark.lightBatch | thrpt | | 416.114 | | ops/s |
188+
| RandomXBenchmark.lightNoBatch | thrpt | | 424.865 | | ops/s |
189+
| RandomXBenchmark.miningBatch | thrpt | | 1818.991 | | ops/s |
190+
| RandomXBenchmark.miningNoBatch | thrpt | | 2191.774 | | ops/s |
191191

192192
---
193193

@@ -196,17 +196,15 @@ public class Example {
196196
- **CPU**: Apple M3 Pro
197197
- **RAM**: 36 GB
198198
- **thread**: 8
199-
- **RandomX Flags**: [DEFAULT, HARD_AES, SECURE]
200-
201-
JIT flag will cause jvm to crash in MacOS
199+
- **RandomX Flags**: [DEFAULT, JIT, SECURE]
202200

203201
### MacOS Performance Results
204-
| Benchmark | Mode | Cnt | Score | Error | Units |
205-
|:------------------------------:|:-----:|:---:|:-------:|:------:|:-----:|
206-
| RandomXBenchmark.lightBatch | thrpt | | 32.864 | | ops/s |
207-
| RandomXBenchmark.lightNoBatch | thrpt | | 33.683 | | ops/s |
208-
| RandomXBenchmark.miningBatch | thrpt | | 554.966 | | ops/s |
209-
| RandomXBenchmark.miningNoBatch | thrpt | | 570.060 | | ops/s |
202+
| Benchmark | Mode | Cnt | Score | Error | Units |
203+
|:------------------------------:|:-----:|:---:|:--------:|:------:|:-----:|
204+
| RandomXBenchmark.lightBatch | thrpt | | 416.114 | | ops/s |
205+
| RandomXBenchmark.lightNoBatch | thrpt | | 424.865 | | ops/s |
206+
| RandomXBenchmark.miningBatch | thrpt | | 1818.991 | | ops/s |
207+
| RandomXBenchmark.miningNoBatch | thrpt | | 2191.774 | | ops/s |
210208

211209
---
212210

src/main/java/io/xdag/crypto/randomx/Example.java

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -40,34 +40,33 @@ public class Example {
4040
* @param args Command line arguments (not used)
4141
*/
4242
public static void main(String[] args) {
43-
// Key to be hashed
43+
// Key (or message) to be hashed
4444
String key = "hello xdagj-native-randomx";
4545
byte[] keyBytes = key.getBytes(StandardCharsets.UTF_8);
46+
System.out.println("Input message: " + key);
4647

47-
// Get supported RandomX flags for the current CPU
48-
Set<RandomXFlag> flags = RandomXUtils.getFlagsSet();
49-
System.out.println("Supported flags: " + flags);
50-
int combinedFlags = RandomXFlag.toValue(flags);
51-
System.out.println("Combined flags value: " + combinedFlags);
48+
// Get recommended RandomX flags for the current CPU
49+
Set<RandomXFlag> flags = RandomXUtils.getRecommendedFlags();
5250

53-
// Initialize RandomX cache with the supported flags
51+
// Allocate RandomX cache with the recommended flags
52+
// The key will be set and cache initialized via RandomXTemplate
5453
RandomXCache cache = new RandomXCache(flags);
55-
cache.init(keyBytes);
5654

57-
// Create and configure RandomXTemplate using builder pattern
55+
// Create and configure RandomXTemplate using a builder pattern
5856
byte[] hash;
5957
try (RandomXTemplate template = RandomXTemplate.builder()
60-
.cache(cache)
61-
.miningMode(false) // Set to false for normal hashing mode
62-
.flags(flags)
58+
.cache(cache) // Provide the cache instance (not yet initialized with key)
59+
.miningMode(false) // Set to false for light hashing mode (no dataset)
60+
.flags(flags) // Provide the base flags
6361
.build()) {
62+
63+
// Set the key for RandomX operations. This will initialize the cache.
64+
template.changeKey(keyBytes);
6465

65-
// Initialize the template with the configured settings
66+
// Initialize the template. This creates the VM.
6667
template.init();
67-
68-
// Calculate hash of the input key
6968
hash = template.calculateHash(keyBytes);
70-
}
69+
} // try-with-resources automatically calls template.close()
7170

7271
// Format and display the results
7372
HexFormat hex = HexFormat.of();

src/main/java/io/xdag/crypto/randomx/RandomXCache.java

Lines changed: 67 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -26,119 +26,108 @@
2626
import com.sun.jna.Memory;
2727
import com.sun.jna.Pointer;
2828
import lombok.Getter;
29-
import org.slf4j.Logger;
30-
import org.slf4j.LoggerFactory;
29+
import lombok.extern.slf4j.Slf4j;
3130

31+
import java.io.Closeable;
3232
import java.util.Set;
33-
import java.util.concurrent.locks.ReentrantLock;
3433

3534
/**
36-
* A class that encapsulates the RandomX cache functionality.
37-
* This class manages the allocation, initialization and release of RandomX cache memory.
38-
* It implements AutoCloseable to ensure proper resource cleanup.
35+
* Represents a RandomX Cache object.
36+
* This class manages the allocation, initialization, and release of the native RandomX cache structure.
3937
*/
40-
@Getter
41-
public class RandomXCache implements AutoCloseable {
42-
private static final Logger logger = LoggerFactory.getLogger(RandomXCache.class);
43-
44-
/**
45-
* Pointer to the allocated RandomX cache memory.
46-
* -- GETTER --
47-
* Returns the pointer to the allocated cache memory.
48-
*/
49-
@Getter
38+
@Slf4j
39+
public class RandomXCache implements Closeable {
5040
private final Pointer cachePointer;
51-
52-
/**
53-
* Pointer to the key used for cache initialization
54-
*/
55-
private volatile Pointer keyPointer;
56-
private int keyLength;
57-
private final ReentrantLock lock = new ReentrantLock();
41+
@Getter
42+
private final Set<RandomXFlag> flags;
5843

5944
/**
60-
* Constructs a new RandomXCache with the specified flags.
61-
* Allocates memory for the cache using the native RandomX library.
45+
* Allocates a new RandomX cache.
6246
*
63-
* @param flags Set of RandomXFlag values that configure the cache behavior
64-
* @throws IllegalArgumentException if flags is null or empty
65-
* @throws IllegalStateException if cache allocation fails
47+
* @param flags Flags used to initialize the cache.
48+
* @throws RuntimeException if cache allocation fails.
6649
*/
6750
public RandomXCache(Set<RandomXFlag> flags) {
68-
if (flags == null || flags.isEmpty()) {
69-
throw new IllegalArgumentException("Flags cannot be null or empty");
70-
}
71-
51+
this.flags = flags;
7252
int combinedFlags = RandomXFlag.toValue(flags);
73-
logger.debug("Allocating RandomX cache with flags: {}", flags);
74-
75-
this.cachePointer = RandomXJNALoader.getInstance().randomx_alloc_cache(combinedFlags);
53+
log.debug("Allocating RandomX cache with flags: {} ({})", flags, combinedFlags);
54+
// Use RandomXNative for allocation
55+
this.cachePointer = RandomXNative.randomx_alloc_cache(combinedFlags);
7656
if (this.cachePointer == null) {
77-
throw new IllegalStateException("Failed to allocate RandomX cache");
57+
String errorMsg = String.format("Failed to allocate RandomX cache with flags: %s (%d)", flags, combinedFlags);
58+
log.error(errorMsg);
59+
throw new RuntimeException(errorMsg);
7860
}
79-
80-
logger.debug("RandomX cache allocated successfully");
61+
log.info("RandomX cache allocated successfully at pointer: {}", Pointer.nativeValue(this.cachePointer));
8162
}
8263

8364
/**
84-
* Initializes the cache with the provided key.
85-
* This method is thread-safe and can be called multiple times with different keys.
65+
* Initializes the RandomX cache with the specified key.
8666
*
87-
* @param key byte array containing the key data
88-
* @throws IllegalArgumentException if key is null or empty
67+
* @param key Key (seed) used to initialize the cache.
68+
* @throws RuntimeException if cache initialization fails.
69+
* @throws IllegalStateException if the cache is not allocated.
8970
*/
9071
public void init(byte[] key) {
72+
if (cachePointer == null) {
73+
throw new IllegalStateException("Cache is not allocated.");
74+
}
9175
if (key == null || key.length == 0) {
92-
throw new IllegalArgumentException("Key cannot be null or empty");
76+
throw new IllegalArgumentException("Key cannot be null or empty for cache initialization.");
9377
}
9478

95-
lock.lock();
79+
// Use JNA Memory to manage native memory
80+
Memory keyPointer = new Memory(key.length);
9681
try {
97-
long startTime = System.nanoTime();
98-
logger.debug("Initializing cache with key length: {}", key.length);
99-
100-
// Free old key pointer if exists
101-
if (keyPointer != null) {
102-
keyPointer.clear(keyLength);
103-
}
104-
105-
// Allocate and initialize new key
106-
keyLength = key.length;
107-
keyPointer = new Memory(key.length);
10882
keyPointer.write(0, key, 0, key.length);
109-
110-
RandomXJNALoader.getInstance().randomx_init_cache(
111-
this.cachePointer,
112-
keyPointer,
113-
key.length
83+
log.debug("Initializing RandomX cache with key of length: {}", key.length);
84+
// Use RandomXNative for initialization
85+
RandomXNative.randomx_init_cache(
86+
this.cachePointer,
87+
keyPointer,
88+
key.length
11489
);
115-
116-
long endTime = System.nanoTime();
117-
logger.debug("Cache initialization completed in {} ms", (endTime - startTime) / 1_000_000);
90+
log.info("RandomX cache initialized successfully.");
91+
} catch (Exception e) {
92+
log.error("Failed to initialize RandomX cache", e);
93+
// Even if initialization fails, attempt to release memory
94+
close(); // Release cachePointer
95+
throw new RuntimeException("Failed to initialize RandomX cache", e);
11896
} finally {
119-
lock.unlock();
97+
// Memory objects do not need to be manually released; JNA's GC will handle it,
98+
// but nullifying the reference immediately might help GC reclaim it faster.
99+
keyPointer = null; // Help GC
120100
}
121101
}
122102

123103
/**
124-
* Releases the allocated cache memory and key memory.
125-
* This method is thread-safe and idempotent.
104+
* Gets the pointer to the underlying native RandomX cache structure.
105+
*
106+
* @return Pointer to the native cache.
107+
* @throws IllegalStateException if the cache is not allocated.
108+
*/
109+
public Pointer getCachePointer() {
110+
if (cachePointer == null) {
111+
throw new IllegalStateException("Cache is not allocated.");
112+
}
113+
return cachePointer;
114+
}
115+
116+
/**
117+
* Releases the resources occupied by the native RandomX cache.
118+
* This method should be called after finishing with the cache to prevent memory leaks.
126119
*/
127120
@Override
128121
public void close() {
129-
lock.lock();
130-
try {
131-
if (keyPointer != null) {
132-
keyPointer.clear(keyLength);
133-
keyPointer = null;
122+
if (cachePointer != null) {
123+
log.debug("Releasing RandomX cache at pointer: {}", Pointer.nativeValue(cachePointer));
124+
try {
125+
// Use RandomXNative for release
126+
RandomXNative.randomx_release_cache(cachePointer);
127+
log.info("RandomX cache released successfully");
128+
} catch (Throwable t) {
129+
log.error("Error occurred while releasing RandomX cache. Pointer: {}", Pointer.nativeValue(cachePointer), t);
134130
}
135-
136-
if (cachePointer != null) {
137-
RandomXJNALoader.getInstance().randomx_release_cache(cachePointer);
138-
logger.debug("RandomX cache released successfully");
139-
}
140-
} finally {
141-
lock.unlock();
142131
}
143132
}
144133
}

0 commit comments

Comments
 (0)