15
15
*/
16
16
package dev .morling .onebrc ;
17
17
18
- import sun .misc .Unsafe ;
19
-
20
18
import java .io .IOException ;
19
+ import java .io .UncheckedIOException ;
21
20
import java .lang .foreign .Arena ;
22
- import java .lang .foreign .MemorySegment ;
23
- import java .lang .reflect .Field ;
24
21
import java .nio .ByteOrder ;
25
22
import java .nio .channels .FileChannel ;
26
23
import java .nio .file .Files ;
34
31
import static java .nio .file .StandardOpenOption .READ ;
35
32
36
33
public class CalculateAverage_iziamos {
37
- private static final Unsafe UNSAFE ;
34
+ private static final sun . misc . Unsafe UNSAFE = initUnsafe () ;
38
35
39
- private static final String FILE = "./measurements.txt" ;
40
- private static final Arena GLOBAL_ARENA = Arena .global ();
41
- private final static MemorySegment WHOLE_FILE_SEGMENT ;
42
- private final static long FILE_SIZE ;
43
- private final static long BASE_POINTER ;
44
- private final static long END_POINTER ;
45
-
46
- static {
36
+ private static sun .misc .Unsafe initUnsafe () {
47
37
try {
48
- final Field theUnsafe = Unsafe .class .getDeclaredField ("theUnsafe" );
38
+ java . lang . reflect . Field theUnsafe = sun . misc . Unsafe .class .getDeclaredField ("theUnsafe" );
49
39
theUnsafe .setAccessible (true );
50
- UNSAFE = (Unsafe ) theUnsafe .get (Unsafe .class );
51
-
52
- final var fileChannel = (FileChannel ) Files .newByteChannel (Path .of (FILE ), READ );
53
- WHOLE_FILE_SEGMENT = fileChannel .map (READ_ONLY , 0 , fileChannel .size (), GLOBAL_ARENA );
54
-
40
+ return (sun .misc .Unsafe ) theUnsafe .get (sun .misc .Unsafe .class );
55
41
}
56
- catch (final NoSuchFieldException | IllegalAccessException | IOException e ) {
42
+ catch (NoSuchFieldException | IllegalAccessException e ) {
57
43
throw new RuntimeException (e );
58
44
}
59
-
60
- FILE_SIZE = WHOLE_FILE_SEGMENT .byteSize ();
61
- BASE_POINTER = WHOLE_FILE_SEGMENT .address ();
62
- END_POINTER = BASE_POINTER + FILE_SIZE ;
63
45
}
64
46
65
- private static final long CHUNK_SIZE = 64 * 1024 * 1024 ;
66
- // private static final long CHUNK_SIZE = Long.MAX_VALUE ;
47
+ private static final String FILE = "./measurements.txt" ;
48
+ private static final Arena GLOBAL_ARENA = Arena . global () ;
67
49
68
50
public static void main (String [] args ) throws Exception {
69
- // Thread.sleep(10_000);
51
+ // final long chunkSize = Long.MAX_VALUE;
52
+ final long chunkSize = 64 * 1024 * 1024 ;
53
+
54
+ final FileChannel fileChannel ;
55
+ try {
56
+ fileChannel = (FileChannel ) Files .newByteChannel (Path .of (FILE ), READ );
57
+ }
58
+ catch (final IOException e ) {
59
+ throw new UncheckedIOException (e );
60
+ }
70
61
71
- final long threadCount = 1 + FILE_SIZE / CHUNK_SIZE ;
62
+ final var seg = fileChannel .map (READ_ONLY , 0 , fileChannel .size (), GLOBAL_ARENA );
63
+
64
+ final long fileSize = seg .byteSize ();
65
+ final long threadCount = 1 + fileSize / chunkSize ;
72
66
73
67
final var processingFutures = new CompletableFuture [(int ) threadCount ];
74
68
for (int i = 0 ; i < threadCount ; ++i ) {
75
- processingFutures [i ] = processSegment (i , CHUNK_SIZE );
69
+ processingFutures [i ] = processSegment (seg . address (), seg . address () + fileSize , i , chunkSize );
76
70
}
77
71
78
72
final long aggregate = (long ) processingFutures [0 ].get ();
@@ -102,15 +96,18 @@ private double round(double value) {
102
96
}
103
97
}
104
98
105
- private static CompletableFuture <Long > processSegment (final long chunkNumber , final long chunkSize ) {
99
+ private static CompletableFuture <Long > processSegment (final long basePointer ,
100
+ final long endPointer ,
101
+ final long chunkNumber ,
102
+ final long chunkSize ) {
106
103
final var ret = new CompletableFuture <Long >();
107
104
108
105
Thread .ofVirtual ().start (() -> {
109
106
final long relativeStart = chunkNumber * chunkSize ;
110
- final long absoluteStart = BASE_POINTER + relativeStart ;
107
+ final long absoluteStart = basePointer + relativeStart ;
111
108
112
- final long absoluteEnd = computeAbsoluteEndWithSlack (absoluteStart + chunkSize );
113
- final long startOffsetAfterSkipping = skipIncomplete (WHOLE_FILE_SEGMENT . address () , absoluteStart );
109
+ final long absoluteEnd = computeAbsoluteEndWithSlack (absoluteStart + chunkSize , endPointer );
110
+ final long startOffsetAfterSkipping = skipIncomplete (basePointer , absoluteStart );
114
111
115
112
final long result = processEvents (startOffsetAfterSkipping , absoluteEnd );
116
113
ret .complete (result );
@@ -119,8 +116,8 @@ private static CompletableFuture<Long> processSegment(final long chunkNumber, fi
119
116
return ret ;
120
117
}
121
118
122
- private static long computeAbsoluteEndWithSlack (final long chunk ) {
123
- return Long .compareUnsigned (END_POINTER , chunk ) > 0 ? chunk : END_POINTER ;
119
+ private static long computeAbsoluteEndWithSlack (final long chunk , final long endPointer ) {
120
+ return Long .compareUnsigned (endPointer , chunk ) > 0 ? chunk : endPointer ;
124
121
}
125
122
126
123
private static long skipIncomplete (final long basePointer , final long start ) {
@@ -142,7 +139,7 @@ private static long processEvents(final long start, final long limit) {
142
139
}
143
140
144
141
private static void scalarLoop (final long start , final long limit , final long result ) {
145
- final LoopCursor cursor = new ScalarLoopCursor (start , limit );
142
+ final LoopCursor cursor = new LoopCursor (start , limit );
146
143
while (cursor .hasMore ()) {
147
144
final long address = cursor .getCurrentAddress ();
148
145
final int length = cursor .getStringLength ();
@@ -152,25 +149,13 @@ private static void scalarLoop(final long start, final long limit, final long re
152
149
}
153
150
}
154
151
155
- public interface LoopCursor {
156
- long getCurrentAddress ();
157
-
158
- int getStringLength ();
159
-
160
- int getHash ();
161
-
162
- int getCurrentValue ();
163
-
164
- boolean hasMore ();
165
- }
166
-
167
- public static class ScalarLoopCursor implements LoopCursor {
152
+ public static class LoopCursor {
168
153
private long pointer ;
169
154
private final long limit ;
170
155
171
156
private int hash = 0 ;
172
157
173
- public ScalarLoopCursor (final long pointer , final long limit ) {
158
+ public LoopCursor (final long pointer , final long limit ) {
174
159
this .pointer = pointer ;
175
160
this .limit = limit ;
176
161
}
0 commit comments