Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openj9
Path: blob/master/jcl/src/openj9.cuda/share/classes/com/ibm/cuda/CudaBuffer.java
12927 views
1
/*[INCLUDE-IF Sidecar18-SE]*/
2
/*******************************************************************************
3
* Copyright (c) 2013, 2018 IBM Corp. and others
4
*
5
* This program and the accompanying materials are made available under
6
* the terms of the Eclipse Public License 2.0 which accompanies this
7
* distribution and is available at https://www.eclipse.org/legal/epl-2.0/
8
* or the Apache License, Version 2.0 which accompanies this distribution and
9
* is available at https://www.apache.org/licenses/LICENSE-2.0.
10
*
11
* This Source Code may also be made available under the following
12
* Secondary Licenses when the conditions for such availability set
13
* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU
14
* General Public License, version 2 with the GNU Classpath
15
* Exception [1] and GNU General Public License, version 2 with the
16
* OpenJDK Assembly Exception [2].
17
*
18
* [1] https://www.gnu.org/software/classpath/license.html
19
* [2] http://openjdk.java.net/legal/assembly-exception.html
20
*
21
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception
22
*******************************************************************************/
23
package com.ibm.cuda;
24
25
import java.nio.Buffer;
26
import java.nio.ByteBuffer;
27
import java.nio.ByteOrder;
28
import java.nio.CharBuffer;
29
import java.nio.DoubleBuffer;
30
import java.nio.FloatBuffer;
31
import java.nio.IntBuffer;
32
import java.nio.LongBuffer;
33
import java.nio.ShortBuffer;
34
import java.util.concurrent.atomic.AtomicLong;
35
36
/**
37
* The {@code CudaBuffer} class represents a region of memory on a specific
38
* device.
39
* <p>
40
* Data may be transferred between the device and the Java host via the
41
* various {@code copyTo} or {@code copyFrom} methods. A buffer may be filled
42
* with a specific pattern through use of one of the {@code fillXxx} methods.
43
* <p>
44
* When no longer required, a buffer must be {@code close}d.
45
*/
46
public final class CudaBuffer implements AutoCloseable {
47
48
private static final ByteOrder DeviceOrder = ByteOrder.LITTLE_ENDIAN;
49
50
private static native long allocate(int deviceId, long byteCount)
51
throws CudaException;
52
53
private static native ByteBuffer allocateDirectBuffer(long capacity);
54
55
private static int chunkBytes(long size) {
56
return size <= Integer.MAX_VALUE ? (int) size : Integer.MAX_VALUE & ~7;
57
}
58
59
private static native void copyFromDevice(int deviceId, long devicePtr,
60
int sourceDeviceId, long sourceAddress, long byteCount)
61
throws CudaException;
62
63
private static native void copyFromHostByte(int deviceId, long devicePtr,
64
byte[] array, int fromIndex, int toIndex) throws CudaException;
65
66
private static native void copyFromHostChar(int deviceId, long devicePtr,
67
char[] array, int fromIndex, int toIndex) throws CudaException;
68
69
private static native void copyFromHostDirect(int deviceId, long devicePtr,
70
Buffer source, long fromOffset, long toOffset) throws CudaException;
71
72
private static native void copyFromHostDouble(int deviceId, long devicePtr,
73
double[] array, int fromIndex, int toIndex) throws CudaException;
74
75
private static native void copyFromHostFloat(int deviceId, long devicePtr,
76
float[] array, int fromIndex, int toIndex) throws CudaException;
77
78
private static native void copyFromHostInt(int deviceId, long devicePtr,
79
int[] array, int fromIndex, int toIndex) throws CudaException;
80
81
private static native void copyFromHostLong(int deviceId, long devicePtr,
82
long[] array, int fromIndex, int toIndex) throws CudaException;
83
84
private static native void copyFromHostShort(int deviceId, long devicePtr,
85
short[] array, int fromIndex, int toIndex) throws CudaException;
86
87
private static native void copyToHostByte(int deviceId, long devicePtr,
88
byte[] array, int fromIndex, int toIndex) throws CudaException;
89
90
private static native void copyToHostChar(int deviceId, long devicePtr,
91
char[] array, int fromIndex, int toIndex) throws CudaException;
92
93
private static native void copyToHostDirect(int deviceId, long devicePtr,
94
Buffer target, long fromOffset, long toOffset) throws CudaException;
95
96
private static native void copyToHostDouble(int deviceId, long devicePtr,
97
double[] array, int fromIndex, int toIndex) throws CudaException;
98
99
private static native void copyToHostFloat(int deviceId, long devicePtr,
100
float[] array, int fromIndex, int toIndex) throws CudaException;
101
102
private static native void copyToHostInt(int deviceId, long devicePtr,
103
int[] array, int fromIndex, int toIndex) throws CudaException;
104
105
private static native void copyToHostLong(int deviceId, long devicePtr,
106
long[] array, int fromIndex, int toIndex) throws CudaException;
107
108
private static native void copyToHostShort(int deviceId, long devicePtr,
109
short[] array, int fromIndex, int toIndex) throws CudaException;
110
111
private static native void fill(int deviceId, long devicePtr,
112
int elementSize, int value, long count) throws CudaException;
113
114
private static native void freeDirectBuffer(Buffer buffer);
115
116
private static void rangeCheck(long length, long fromIndex, long toIndex) {
117
if (fromIndex > toIndex) {
118
throw new IllegalArgumentException(
119
"fromIndex(" + fromIndex + ") > toIndex(" + toIndex + ')'); //$NON-NLS-1$ //$NON-NLS-2$
120
}
121
122
if (fromIndex < 0) {
123
throw new IndexOutOfBoundsException(String.valueOf(fromIndex));
124
}
125
126
if (toIndex > length) {
127
throw new IndexOutOfBoundsException(String.valueOf(toIndex));
128
}
129
}
130
131
private static native void release(int deviceId, long devicePtr)
132
throws CudaException;
133
134
private final int deviceId;
135
136
private final AtomicLong devicePtr;
137
138
private final long length;
139
140
private final CudaBuffer parent;
141
142
private CudaBuffer(CudaBuffer parent, int deviceId, long devicePtr,
143
long length) {
144
super();
145
this.deviceId = deviceId;
146
this.devicePtr = new AtomicLong(devicePtr);
147
this.length = length;
148
this.parent = parent;
149
}
150
151
/**
152
* Allocates a new region on the specified {@code device} of size {@code byteCount} bytes.
153
*
154
* @param device
155
* the device on which the region is to be allocated
156
* @param byteCount
157
* the allocation size in bytes
158
* @throws CudaException
159
* if a CUDA exception occurs
160
*/
161
public CudaBuffer(CudaDevice device, long byteCount) throws CudaException {
162
super();
163
this.deviceId = device.getDeviceId();
164
this.devicePtr = new AtomicLong(allocate(this.deviceId, byteCount));
165
this.length = byteCount;
166
this.parent = null;
167
}
168
169
/**
170
* Returns a sub-region of this buffer. The new buffer begins at the
171
* specified offset and extends to the end of this buffer.
172
*
173
* @param fromOffset
174
* the byte offset of the sub-region within this buffer
175
* @return
176
* the specified sub-region
177
* @throws IllegalStateException
178
* if this buffer has been closed (see {@link #close()})
179
* @throws IndexOutOfBoundsException
180
* if the specified offset is negative or larger than the
181
* length of this buffer
182
*/
183
public CudaBuffer atOffset(long fromOffset) {
184
return slice(fromOffset, length);
185
}
186
187
/**
188
* Releases the region of device memory backing this buffer.
189
* <p>
190
* Closing a buffer created via {@link #atOffset(long)} with a
191
* non-zero offset has no effect: the memory is still accessible via
192
* the parent buffer which must be closed separately.
193
*
194
* @throws CudaException
195
* if a CUDA exception occurs
196
*/
197
@Override
198
public void close() throws CudaException {
199
long address = devicePtr.getAndSet(0);
200
201
if (address != 0 && parent == null) {
202
release(deviceId, address);
203
}
204
}
205
206
/**
207
* Copies all data from the specified {@code array} (on the Java host) to
208
* this buffer (on the device). Equivalent to
209
* <pre>
210
* copyFrom(array, 0, array.length);
211
* </pre>
212
*
213
* @param array
214
* the source array
215
* @throws CudaException
216
* if a CUDA exception occurs
217
* @throws IllegalStateException
218
* if this buffer has been closed (see {@link #close()})
219
* @throws IndexOutOfBoundsException
220
* if the number of source bytes is larger than the length
221
* of this buffer
222
*/
223
public void copyFrom(byte[] array) throws CudaException {
224
copyFrom(array, 0, array.length);
225
}
226
227
/**
228
* Copies data from the specified {@code array} (on the Java host) to this
229
* buffer (on the device). Elements are read from {@code array} beginning
230
* at {@code fromIndex} continuing up to, but excluding, {@code toIndex}
231
* storing them in the same order in this buffer.
232
* <p>
233
* A sub-buffer may be created (see {@link #atOffset(long)}) when the data
234
* are to be copied somewhere other than the beginning of this buffer.
235
*
236
* @param array
237
* the source array
238
* @param fromIndex
239
* the source starting offset (inclusive)
240
* @param toIndex
241
* the source ending offset (exclusive)
242
* @throws CudaException
243
* if a CUDA exception occurs
244
* @throws IllegalArgumentException
245
* if {@code fromIndex > toIndex}
246
* @throws IllegalStateException
247
* if this buffer has been closed (see {@link #close()})
248
* @throws IndexOutOfBoundsException
249
* if {@code fromIndex} is negative, {@code toIndex > array.length},
250
* or the number of source bytes is larger than the length
251
* of this buffer
252
*/
253
public void copyFrom(byte[] array, int fromIndex, int toIndex)
254
throws CudaException {
255
rangeCheck(array.length, fromIndex, toIndex);
256
lengthCheck(toIndex - fromIndex, 0);
257
copyFromHostByte(deviceId, getAddress(), // <br/>
258
array, fromIndex, toIndex);
259
}
260
261
/**
262
* Copies data from the specified {@code source} buffer (on the Java host)
263
* to this buffer (on the device). Elements are read from {@code source}
264
* beginning at {@code position()} continuing up to, but excluding,
265
* {@code limit()} storing them in the same order in this buffer.
266
* The {@code source} buffer position is set to {@code limit()}.
267
* <p>
268
* A sub-buffer may be created (see {@link #atOffset(long)}) when the data
269
* are to be copied somewhere other than the beginning of this buffer.
270
*
271
* @param source
272
* the source buffer
273
* @throws CudaException
274
* if a CUDA exception occurs
275
* @throws IllegalStateException
276
* if this buffer has been closed (see {@link #close()})
277
* @throws IndexOutOfBoundsException
278
* if the number of source bytes is larger than the length
279
* of this buffer
280
*/
281
public void copyFrom(ByteBuffer source) throws CudaException {
282
final int fromIndex = source.position();
283
final int toIndex = source.limit();
284
final int byteCount = toIndex - fromIndex;
285
286
lengthCheck(byteCount, 0);
287
288
if (source.isDirect()) {
289
copyFromHostDirect(deviceId, getAddress(), // <br/>
290
source, fromIndex, toIndex);
291
} else if (source.hasArray()) {
292
final int offset = source.arrayOffset();
293
294
copyFrom(source.array(), fromIndex + offset, toIndex + offset);
295
} else {
296
ByteBuffer tmp = allocateDirectBuffer(byteCount).order(DeviceOrder);
297
298
try {
299
tmp.put(source);
300
copyFromHostDirect(deviceId, getAddress(), // <br/>
301
tmp, 0, byteCount);
302
} finally {
303
freeDirectBuffer(tmp);
304
}
305
}
306
307
source.position(toIndex);
308
}
309
310
/**
311
* Copies all data from the specified {@code array} (on the Java host) to
312
* this buffer (on the device). Equivalent to
313
* <pre>
314
* copyFrom(array, 0, array.length);
315
* </pre>
316
*
317
* @param array
318
* the source array
319
* @throws CudaException
320
* if a CUDA exception occurs
321
* @throws IllegalStateException
322
* if this buffer has been closed (see {@link #close()})
323
* @throws IndexOutOfBoundsException
324
* if the number of source bytes is larger than the length
325
* of this buffer
326
*/
327
public void copyFrom(char[] array) throws CudaException {
328
copyFrom(array, 0, array.length);
329
}
330
331
/**
332
* Copies data from the specified {@code array} (on the Java host) to this
333
* buffer (on the device). Elements are read from {@code array} beginning
334
* at {@code fromIndex} continuing up to, but excluding, {@code toIndex}
335
* storing them in the same order in this buffer.
336
* <p>
337
* A sub-buffer may be created (see {@link #atOffset(long)}) when the data
338
* are to be copied somewhere other than the beginning of this buffer.
339
*
340
* @param array
341
* the source array
342
* @param fromIndex
343
* the source starting offset (inclusive)
344
* @param toIndex
345
* the source ending offset (exclusive)
346
* @throws CudaException
347
* if a CUDA exception occurs
348
* @throws IllegalArgumentException
349
* if {@code fromIndex > toIndex}
350
* @throws IllegalStateException
351
* if this buffer has been closed (see {@link #close()})
352
* @throws IndexOutOfBoundsException
353
* if {@code fromIndex} is negative, {@code toIndex > array.length},
354
* or the number of source bytes is larger than the length
355
* of this buffer
356
*/
357
public void copyFrom(char[] array, int fromIndex, int toIndex)
358
throws CudaException {
359
rangeCheck(array.length, fromIndex, toIndex);
360
lengthCheck(toIndex - fromIndex, 1);
361
copyFromHostChar(deviceId, getAddress(), // <br/>
362
array, fromIndex, toIndex);
363
}
364
365
/**
366
* Copies data from the specified {@code source} buffer (on the Java host)
367
* to this buffer (on the device). Elements are read from {@code source}
368
* beginning at {@code position()} continuing up to, but excluding,
369
* {@code limit()} storing them in the same order in this buffer.
370
* The {@code source} buffer position is set to {@code limit()}.
371
* <p>
372
* A sub-buffer may be created (see {@link #atOffset(long)}) when the data
373
* are to be copied somewhere other than the beginning of this buffer.
374
*
375
* @param source
376
* the source buffer
377
* @throws CudaException
378
* if a CUDA exception occurs
379
* @throws IllegalStateException
380
* if this buffer has been closed (see {@link #close()})
381
* @throws IndexOutOfBoundsException
382
* if the number of source bytes is larger than the length
383
* of this buffer
384
*/
385
public void copyFrom(CharBuffer source) throws CudaException {
386
final int fromIndex = source.position();
387
final int toIndex = source.limit();
388
389
lengthCheck(toIndex - fromIndex, 1);
390
391
if (source.isDirect()) {
392
copyFromHostDirect(deviceId, getAddress(), // <br/>
393
source, (long) fromIndex << 1, (long) toIndex << 1);
394
} else if (source.hasArray()) {
395
final int offset = source.arrayOffset();
396
397
copyFrom(source.array(), fromIndex + offset, toIndex + offset);
398
} else {
399
final long byteCount = (long) (toIndex - fromIndex) << 1;
400
final int chunkSize = chunkBytes(byteCount);
401
final CharBuffer slice = source.slice();
402
final CharBuffer tmp = allocateDirectBuffer(chunkSize) // <br/>
403
.order(DeviceOrder).asCharBuffer();
404
405
try {
406
for (long start = 0; start < byteCount; start += chunkSize) {
407
final long end = Math.min(start + chunkSize, byteCount);
408
409
slice.limit((int) (end >> 1));
410
tmp.clear();
411
tmp.put(slice);
412
copyFromHostDirect(deviceId, getAddress() + start, // <br/>
413
tmp, 0, end - start);
414
}
415
} finally {
416
freeDirectBuffer(tmp);
417
}
418
}
419
420
source.position(toIndex);
421
}
422
423
/**
424
* Copies data from the specified {@code source} buffer (on a device)
425
* to this buffer (on the device). Elements are read from {@code source}
426
* beginning at {@code position()} continuing up to, but excluding,
427
* {@code limit()} storing them in the same order in this buffer.
428
* <p>
429
* A sub-buffer may be created (see {@link #atOffset(long)}) when the data
430
* are to be copied somewhere other than the beginning of this buffer.
431
*
432
* @param source
433
* the source buffer
434
* @param fromOffset
435
* the source starting offset (inclusive)
436
* @param toOffset
437
* the source ending offset (exclusive)
438
* @throws CudaException
439
* if a CUDA exception occurs
440
* @throws IllegalStateException
441
* if this buffer has been closed (see {@link #close()})
442
* @throws IndexOutOfBoundsException
443
* if either {@code fromOffset} or {@code toOffset} is not a legal
444
* offset within the source buffer or the number of source bytes
445
* is larger than the length of this buffer
446
*/
447
public void copyFrom(CudaBuffer source, long fromOffset, long toOffset)
448
throws CudaException {
449
final long byteCount = toOffset - fromOffset;
450
451
rangeCheck(source.length, fromOffset, toOffset);
452
lengthCheck(byteCount, 0);
453
454
copyFromDevice(deviceId, getAddress(), // <br/>
455
source.deviceId, source.getAddress() + fromOffset, // <br/>
456
byteCount);
457
}
458
459
/**
460
* Copies all data from the specified {@code array} (on the Java host) to
461
* this buffer (on the device). Equivalent to
462
* <pre>
463
* copyFrom(array, 0, array.length);
464
* </pre>
465
*
466
* @param array
467
* the source array
468
* @throws CudaException
469
* if a CUDA exception occurs
470
* @throws IllegalStateException
471
* if this buffer has been closed (see {@link #close()})
472
* @throws IndexOutOfBoundsException
473
* if the number of source bytes is larger than the length
474
* of this buffer
475
*/
476
public void copyFrom(double[] array) throws CudaException {
477
copyFrom(array, 0, array.length);
478
}
479
480
/**
481
* Copies data from the specified {@code array} (on the Java host) to this
482
* buffer (on the device). Elements are read from {@code array} beginning
483
* at {@code fromIndex} continuing up to, but excluding, {@code toIndex}
484
* storing them in the same order in this buffer.
485
* <p>
486
* A sub-buffer may be created (see {@link #atOffset(long)}) when the data
487
* are to be copied somewhere other than the beginning of this buffer.
488
*
489
* @param array
490
* the source array
491
* @param fromIndex
492
* the source starting offset (inclusive)
493
* @param toIndex
494
* the source ending offset (exclusive)
495
* @throws CudaException
496
* if a CUDA exception occurs
497
* @throws IllegalArgumentException
498
* if {@code fromIndex > toIndex}
499
* @throws IllegalStateException
500
* if this buffer has been closed (see {@link #close()})
501
* @throws IndexOutOfBoundsException
502
* if {@code fromIndex} is negative, {@code toIndex > array.length},
503
* or the number of source bytes is larger than the length
504
* of this buffer
505
*/
506
public void copyFrom(double[] array, int fromIndex, int toIndex)
507
throws CudaException {
508
rangeCheck(array.length, fromIndex, toIndex);
509
lengthCheck(toIndex - fromIndex, 3);
510
copyFromHostDouble(deviceId, getAddress(), // <br/>
511
array, fromIndex, toIndex);
512
}
513
514
/**
515
* Copies data from the specified {@code source} buffer (on the Java host)
516
* to this buffer (on the device). Elements are read from {@code source}
517
* beginning at {@code position()} continuing up to, but excluding,
518
* {@code limit()} storing them in the same order in this buffer.
519
* The {@code source} buffer position is set to {@code limit()}.
520
* <p>
521
* A sub-buffer may be created (see {@link #atOffset(long)}) when the data
522
* are to be copied somewhere other than the beginning of this buffer.
523
*
524
* @param source
525
* the source buffer
526
* @throws CudaException
527
* if a CUDA exception occurs
528
* @throws IllegalStateException
529
* if this buffer has been closed (see {@link #close()})
530
* @throws IndexOutOfBoundsException
531
* if the number of source bytes is larger than the length
532
* of this buffer
533
*/
534
public void copyFrom(DoubleBuffer source) throws CudaException {
535
final int fromIndex = source.position();
536
final int toIndex = source.limit();
537
538
lengthCheck(toIndex - fromIndex, 3);
539
540
if (source.isDirect()) {
541
copyFromHostDirect(deviceId, getAddress(), // <br/>
542
source, (long) fromIndex << 3, (long) toIndex << 3);
543
} else if (source.hasArray()) {
544
final int offset = source.arrayOffset();
545
546
copyFrom(source.array(), fromIndex + offset, toIndex + offset);
547
} else {
548
final long byteCount = (long) (toIndex - fromIndex) << 3;
549
final int chunkSize = chunkBytes(byteCount);
550
final DoubleBuffer slice = source.slice();
551
final DoubleBuffer tmp = allocateDirectBuffer(chunkSize) // <br/>
552
.order(DeviceOrder).asDoubleBuffer();
553
554
try {
555
for (long start = 0; start < byteCount; start += chunkSize) {
556
final long end = Math.min(start + chunkSize, byteCount);
557
558
slice.limit((int) (end >> 3));
559
tmp.clear();
560
tmp.put(slice);
561
copyFromHostDirect(deviceId, getAddress() + start, // <br/>
562
tmp, 0, end - start);
563
}
564
} finally {
565
freeDirectBuffer(tmp);
566
}
567
}
568
569
source.position(toIndex);
570
}
571
572
/**
573
* Copies all data from the specified {@code array} (on the Java host) to
574
* this buffer (on the device). Equivalent to
575
* <pre>
576
* copyFrom(array, 0, array.length);
577
* </pre>
578
*
579
* @param array
580
* the source array
581
* @throws CudaException
582
* if a CUDA exception occurs
583
* @throws IllegalStateException
584
* if this buffer has been closed (see {@link #close()})
585
* @throws IndexOutOfBoundsException
586
* if the number of source bytes is larger than the length
587
* of this buffer
588
*/
589
public void copyFrom(float[] array) throws CudaException {
590
copyFrom(array, 0, array.length);
591
}
592
593
/**
594
* Copies data from the specified {@code array} (on the Java host) to this
595
* buffer (on the device). Elements are read from {@code array} beginning
596
* at {@code fromIndex} continuing up to, but excluding, {@code toIndex}
597
* storing them in the same order in this buffer.
598
* <p>
599
* A sub-buffer may be created (see {@link #atOffset(long)}) when the data
600
* are to be copied somewhere other than the beginning of this buffer.
601
*
602
* @param array
603
* the source array
604
* @param fromIndex
605
* the source starting offset (inclusive)
606
* @param toIndex
607
* the source ending offset (exclusive)
608
* @throws CudaException
609
* if a CUDA exception occurs
610
* @throws IllegalArgumentException
611
* if {@code fromIndex > toIndex}
612
* @throws IllegalStateException
613
* if this buffer has been closed (see {@link #close()})
614
* @throws IndexOutOfBoundsException
615
* if {@code fromIndex} is negative, {@code toIndex > array.length},
616
* or the number of source bytes is larger than the length
617
* of this buffer
618
*/
619
public void copyFrom(float[] array, int fromIndex, int toIndex)
620
throws CudaException {
621
rangeCheck(array.length, fromIndex, toIndex);
622
lengthCheck(toIndex - fromIndex, 2);
623
copyFromHostFloat(deviceId, getAddress(), // <br/>
624
array, fromIndex, toIndex);
625
}
626
627
/**
628
* Copies data from the specified {@code source} buffer (on the Java host)
629
* to this buffer (on the device). Elements are read from {@code source}
630
* beginning at {@code position()} continuing up to, but excluding,
631
* {@code limit()} storing them in the same order in this buffer.
632
* The {@code source} buffer position is set to {@code limit()}.
633
* <p>
634
* A sub-buffer may be created (see {@link #atOffset(long)}) when the data
635
* are to be copied somewhere other than the beginning of this buffer.
636
*
637
* @param source
638
* the source buffer
639
* @throws CudaException
640
* if a CUDA exception occurs
641
* @throws IllegalStateException
642
* if this buffer has been closed (see {@link #close()})
643
* @throws IndexOutOfBoundsException
644
* if the number of source bytes is larger than the length
645
* of this buffer
646
*/
647
public void copyFrom(FloatBuffer source) throws CudaException {
648
final int fromIndex = source.position();
649
final int toIndex = source.limit();
650
651
lengthCheck(toIndex - fromIndex, 2);
652
653
if (source.isDirect()) {
654
copyFromHostDirect(deviceId, getAddress(), // <br/>
655
source, (long) fromIndex << 2, (long) toIndex << 2);
656
} else if (source.hasArray()) {
657
final int offset = source.arrayOffset();
658
659
copyFrom(source.array(), fromIndex + offset, toIndex + offset);
660
} else {
661
final long byteCount = (long) (toIndex - fromIndex) << 2;
662
final int chunkSize = chunkBytes(byteCount);
663
final FloatBuffer slice = source.slice();
664
final FloatBuffer tmp = allocateDirectBuffer(chunkSize) // <br/>
665
.order(DeviceOrder).asFloatBuffer();
666
667
try {
668
for (long start = 0; start < byteCount; start += chunkSize) {
669
final long end = Math.min(start + chunkSize, byteCount);
670
671
slice.limit((int) (end >> 2));
672
tmp.clear();
673
tmp.put(slice);
674
copyFromHostDirect(deviceId, getAddress() + start, // <br/>
675
tmp, 0, end - start);
676
}
677
} finally {
678
freeDirectBuffer(tmp);
679
}
680
}
681
682
source.position(toIndex);
683
}
684
685
/**
686
* Copies all data from the specified {@code array} (on the Java host) to
687
* this buffer (on the device). Equivalent to
688
* <pre>
689
* copyFrom(array, 0, array.length);
690
* </pre>
691
*
692
* @param array
693
* the source array
694
* @throws CudaException
695
* if a CUDA exception occurs
696
* @throws IllegalStateException
697
* if this buffer has been closed (see {@link #close()})
698
* @throws IndexOutOfBoundsException
699
* if the number of source bytes is larger than the length
700
* of this buffer
701
*/
702
public void copyFrom(int[] array) throws CudaException {
703
copyFrom(array, 0, array.length);
704
}
705
706
/**
707
* Copies data from the specified {@code array} (on the Java host) to this
708
* buffer (on the device). Elements are read from {@code array} beginning
709
* at {@code fromIndex} continuing up to, but excluding, {@code toIndex}
710
* storing them in the same order in this buffer.
711
* <p>
712
* A sub-buffer may be created (see {@link #atOffset(long)}) when the data
713
* are to be copied somewhere other than the beginning of this buffer.
714
*
715
* @param array
716
* the source array
717
* @param fromIndex
718
* the source starting offset (inclusive)
719
* @param toIndex
720
* the source ending offset (exclusive)
721
* @throws CudaException
722
* if a CUDA exception occurs
723
* @throws IllegalArgumentException
724
* if {@code fromIndex > toIndex}
725
* @throws IllegalStateException
726
* if this buffer has been closed (see {@link #close()})
727
* @throws IndexOutOfBoundsException
728
* if {@code fromIndex} is negative, {@code toIndex > array.length},
729
* or the number of source bytes is larger than the length
730
* of this buffer
731
*/
732
public void copyFrom(int[] array, int fromIndex, int toIndex)
733
throws CudaException {
734
rangeCheck(array.length, fromIndex, toIndex);
735
lengthCheck(toIndex - fromIndex, 2);
736
copyFromHostInt(deviceId, getAddress(), // <br/>
737
array, fromIndex, toIndex);
738
}
739
740
/**
741
* Copies data from the specified {@code source} buffer (on the Java host)
742
* to this buffer (on the device). Elements are read from {@code source}
743
* beginning at {@code position()} continuing up to, but excluding,
744
* {@code limit()} storing them in the same order in this buffer.
745
* The {@code source} buffer position is set to {@code limit()}.
746
* <p>
747
* A sub-buffer may be created (see {@link #atOffset(long)}) when the data
748
* are to be copied somewhere other than the beginning of this buffer.
749
*
750
* @param source
751
* the source buffer
752
* @throws CudaException
753
* if a CUDA exception occurs
754
* @throws IllegalStateException
755
* if this buffer has been closed (see {@link #close()})
756
* @throws IndexOutOfBoundsException
757
* if the number of source bytes is larger than the length
758
* of this buffer
759
*/
760
public void copyFrom(IntBuffer source) throws CudaException {
761
final int fromIndex = source.position();
762
final int toIndex = source.limit();
763
764
lengthCheck(toIndex - fromIndex, 2);
765
766
if (source.isDirect()) {
767
copyFromHostDirect(deviceId, getAddress(), // <br/>
768
source, (long) fromIndex << 2, (long) toIndex << 2);
769
} else if (source.hasArray()) {
770
final int offset = source.arrayOffset();
771
772
copyFrom(source.array(), fromIndex + offset, toIndex + offset);
773
} else {
774
final long byteCount = (long) (toIndex - fromIndex) << 2;
775
final int chunkSize = chunkBytes(byteCount);
776
final IntBuffer slice = source.slice();
777
final IntBuffer tmp = allocateDirectBuffer(chunkSize) // <br/>
778
.order(DeviceOrder).asIntBuffer();
779
780
try {
781
for (long start = 0; start < byteCount; start += chunkSize) {
782
final long end = Math.min(start + chunkSize, byteCount);
783
784
slice.limit((int) (end >> 2));
785
tmp.clear();
786
tmp.put(slice);
787
copyFromHostDirect(deviceId, getAddress() + start, // <br/>
788
tmp, 0, end - start);
789
}
790
} finally {
791
freeDirectBuffer(tmp);
792
}
793
}
794
795
source.position(toIndex);
796
}
797
798
/**
799
* Copies all data from the specified {@code array} (on the Java host) to
800
* this buffer (on the device). Equivalent to
801
* <pre>
802
* copyFrom(array, 0, array.length);
803
* </pre>
804
*
805
* @param array
806
* the source array
807
* @throws CudaException
808
* if a CUDA exception occurs
809
* @throws IllegalStateException
810
* if this buffer has been closed (see {@link #close()})
811
* @throws IndexOutOfBoundsException
812
* if the number of source bytes is larger than the length
813
* of this buffer
814
*/
815
public void copyFrom(long[] array) throws CudaException {
816
copyFrom(array, 0, array.length);
817
}
818
819
/**
820
* Copies data from the specified {@code array} (on the Java host) to this
821
* buffer (on the device). Elements are read from {@code array} beginning
822
* at {@code fromIndex} continuing up to, but excluding, {@code toIndex}
823
* storing them in the same order in this buffer.
824
* <p>
825
* A sub-buffer may be created (see {@link #atOffset(long)}) when the data
826
* are to be copied somewhere other than the beginning of this buffer.
827
*
828
* @param array
829
* the source array
830
* @param fromIndex
831
* the source starting offset (inclusive)
832
* @param toIndex
833
* the source ending offset (exclusive)
834
* @throws CudaException
835
* if a CUDA exception occurs
836
* @throws IllegalArgumentException
837
* if {@code fromIndex > toIndex}
838
* @throws IllegalStateException
839
* if this buffer has been closed (see {@link #close()})
840
* @throws IndexOutOfBoundsException
841
* if {@code fromIndex} is negative, {@code toIndex > array.length},
842
* or the number of source bytes is larger than the length
843
* of this buffer
844
*/
845
public void copyFrom(long[] array, int fromIndex, int toIndex)
846
throws CudaException {
847
rangeCheck(array.length, fromIndex, toIndex);
848
lengthCheck(toIndex - fromIndex, 3);
849
copyFromHostLong(deviceId, getAddress(), // <br/>
850
array, fromIndex, toIndex);
851
}
852
853
/**
854
* Copies data from the specified {@code source} buffer (on the Java host)
855
* to this buffer (on the device). Elements are read from {@code source}
856
* beginning at {@code position()} continuing up to, but excluding,
857
* {@code limit()} storing them in the same order in this buffer.
858
* The {@code source} buffer position is set to {@code limit()}.
859
* <p>
860
* A sub-buffer may be created (see {@link #atOffset(long)}) when the data
861
* are to be copied somewhere other than the beginning of this buffer.
862
*
863
* @param source
864
* the source buffer
865
* @throws CudaException
866
* if a CUDA exception occurs
867
* @throws IllegalStateException
868
* if this buffer has been closed (see {@link #close()})
869
* @throws IndexOutOfBoundsException
870
* if the number of source bytes is larger than the length
871
* of this buffer
872
*/
873
public void copyFrom(LongBuffer source) throws CudaException {
874
final int fromIndex = source.position();
875
final int toIndex = source.limit();
876
877
lengthCheck(toIndex - fromIndex, 3);
878
879
if (source.isDirect()) {
880
copyFromHostDirect(deviceId, getAddress(), // <br/>
881
source, (long) fromIndex << 3, (long) toIndex << 3);
882
} else if (source.hasArray()) {
883
final int offset = source.arrayOffset();
884
885
copyFrom(source.array(), fromIndex + offset, toIndex + offset);
886
} else {
887
final long byteCount = (long) (toIndex - fromIndex) << 3;
888
final int chunkSize = chunkBytes(byteCount);
889
final LongBuffer slice = source.slice();
890
final LongBuffer tmp = allocateDirectBuffer(chunkSize) // <br/>
891
.order(DeviceOrder).asLongBuffer();
892
893
try {
894
for (long start = 0; start < byteCount; start += chunkSize) {
895
final long end = Math.min(start + chunkSize, byteCount);
896
897
slice.limit((int) (end >> 3));
898
tmp.clear();
899
tmp.put(slice);
900
copyFromHostDirect(deviceId, getAddress() + start, // <br/>
901
tmp, 0, end - start);
902
}
903
} finally {
904
freeDirectBuffer(tmp);
905
}
906
}
907
908
source.position(toIndex);
909
}
910
911
/**
912
* Copies all data from the specified {@code array} (on the Java host) to
913
* this buffer (on the device). Equivalent to
914
* <pre>
915
* copyFrom(array, 0, array.length);
916
* </pre>
917
*
918
* @param array
919
* the source array
920
* @throws CudaException
921
* if a CUDA exception occurs
922
* @throws IllegalStateException
923
* if this buffer has been closed (see {@link #close()})
924
* @throws IndexOutOfBoundsException
925
* if the number of source bytes is larger than the length
926
* of this buffer
927
*/
928
public void copyFrom(short[] array) throws CudaException {
929
copyFrom(array, 0, array.length);
930
}
931
932
/**
933
* Copies data from the specified {@code array} (on the Java host) to this
934
* buffer (on the device). Elements are read from {@code array} beginning
935
* at {@code fromIndex} continuing up to, but excluding, {@code toIndex}
936
* storing them in the same order in this buffer.
937
* <p>
938
* A sub-buffer may be created (see {@link #atOffset(long)}) when the data
939
* are to be copied somewhere other than the beginning of this buffer.
940
*
941
* @param array
942
* the source array
943
* @param fromIndex
944
* the source starting offset (inclusive)
945
* @param toIndex
946
* the source ending offset (exclusive)
947
* @throws CudaException
948
* if a CUDA exception occurs
949
* @throws IllegalArgumentException
950
* if {@code fromIndex > toIndex}
951
* @throws IllegalStateException
952
* if this buffer has been closed (see {@link #close()})
953
* @throws IndexOutOfBoundsException
954
* if {@code fromIndex} is negative, {@code toIndex > array.length},
955
* or the number of source bytes is larger than the length
956
* of this buffer
957
*/
958
public void copyFrom(short[] array, int fromIndex, int toIndex)
959
throws CudaException {
960
rangeCheck(array.length, fromIndex, toIndex);
961
lengthCheck(toIndex - fromIndex, 1);
962
copyFromHostShort(deviceId, getAddress(), // <br/>
963
array, fromIndex, toIndex);
964
}
965
966
/**
967
* Copies data from the specified {@code source} buffer (on the Java host)
968
* to this buffer (on the device). Elements are read from {@code source}
969
* beginning at {@code position()} continuing up to, but excluding,
970
* {@code limit()} storing them in the same order in this buffer.
971
* The {@code source} buffer position is set to {@code limit()}.
972
* <p>
973
* A sub-buffer may be created (see {@link #atOffset(long)}) when the data
974
* are to be copied somewhere other than the beginning of this buffer.
975
*
976
* @param source
977
* the source buffer
978
* @throws CudaException
979
* if a CUDA exception occurs
980
* @throws IllegalStateException
981
* if this buffer has been closed (see {@link #close()})
982
* @throws IndexOutOfBoundsException
983
* if the number of source bytes is larger than the length
984
* of this buffer
985
*/
986
public void copyFrom(ShortBuffer source) throws CudaException {
987
final int fromIndex = source.position();
988
final int toIndex = source.limit();
989
990
lengthCheck(toIndex - fromIndex, 1);
991
992
if (source.isDirect()) {
993
copyFromHostDirect(deviceId, getAddress(), // <br/>
994
source, (long) fromIndex << 1, (long) toIndex << 1);
995
} else if (source.hasArray()) {
996
final int offset = source.arrayOffset();
997
998
copyFrom(source.array(), fromIndex + offset, toIndex + offset);
999
} else {
1000
final long byteCount = (long) (toIndex - fromIndex) << 1;
1001
final int chunkSize = chunkBytes(byteCount);
1002
final ShortBuffer slice = source.slice();
1003
final ShortBuffer tmp = allocateDirectBuffer(chunkSize) // <br/>
1004
.order(DeviceOrder).asShortBuffer();
1005
1006
try {
1007
for (long start = 0; start < byteCount; start += chunkSize) {
1008
final long end = Math.min(start + chunkSize, byteCount);
1009
1010
slice.limit((int) (end >> 1));
1011
tmp.clear();
1012
tmp.put(slice);
1013
copyFromHostDirect(deviceId, getAddress() + start, // <br/>
1014
tmp, 0, end - start);
1015
}
1016
} finally {
1017
freeDirectBuffer(tmp);
1018
}
1019
}
1020
1021
source.position(toIndex);
1022
}
1023
1024
/**
1025
* Copies data from this buffer (on the device) to the specified
1026
* {@code array} (on the Java host). Equivalent to
1027
* <pre>
1028
* copyTo(array, 0, array.length);
1029
* </pre>
1030
*
1031
* @param array
1032
* the destination array
1033
* @throws CudaException
1034
* if a CUDA exception occurs
1035
* @throws IllegalStateException
1036
* if this buffer has been closed (see {@link #close()})
1037
* @throws IndexOutOfBoundsException
1038
* if the number of required source bytes is larger than the length
1039
* of this buffer
1040
*/
1041
public void copyTo(byte[] array) throws CudaException {
1042
copyTo(array, 0, array.length);
1043
}
1044
1045
/**
1046
* Copies data from this buffer (on the device) to the specified
1047
* {@code array} (on the Java host). Elements are read starting at the
1048
* beginning of this buffer and stored in {@code array} beginning
1049
* at {@code fromIndex} continuing up to, but excluding, {@code toIndex}.
1050
* <p>
1051
* A sub-buffer may be created (see {@link #atOffset(long)}) when the source
1052
* data are not located at the beginning of this buffer.
1053
*
1054
* @param array
1055
* the destination array
1056
* @param fromIndex
1057
* the destination starting offset (inclusive)
1058
* @param toIndex
1059
* the destination ending offset (exclusive)
1060
* @throws CudaException
1061
* if a CUDA exception occurs
1062
* @throws IllegalArgumentException
1063
* if {@code fromIndex > toIndex}
1064
* @throws IllegalStateException
1065
* if this buffer has been closed (see {@link #close()})
1066
* @throws IndexOutOfBoundsException
1067
* if {@code fromIndex} is negative, {@code toIndex > array.length},
1068
* or the number of required source bytes is larger than the length
1069
* of this buffer
1070
*/
1071
public void copyTo(byte[] array, int fromIndex, int toIndex)
1072
throws CudaException {
1073
rangeCheck(array.length, fromIndex, toIndex);
1074
lengthCheck(toIndex - fromIndex, 0);
1075
copyToHostByte(deviceId, getAddress(), // <br/>
1076
array, fromIndex, toIndex);
1077
}
1078
1079
/**
1080
* Copies data from this buffer (on the device) to the specified
1081
* {@code target} buffer (on the Java host). Elements are read starting at
1082
* the beginning of this buffer and stored in {@code target} beginning
1083
* at {@code position()} continuing up to, but excluding, {@code limit()}.
1084
* The {@code target} buffer position is set to {@code limit()}.
1085
* <p>
1086
* A sub-buffer may be created (see {@link #atOffset(long)}) when the source
1087
* data are not located at the beginning of this buffer.
1088
*
1089
* @param target
1090
* the destination buffer
1091
* @throws CudaException
1092
* if a CUDA exception occurs
1093
* @throws IllegalStateException
1094
* if this buffer has been closed (see {@link #close()})
1095
* @throws IndexOutOfBoundsException
1096
* if the number of required source bytes is larger than the length
1097
* of this buffer
1098
*/
1099
public void copyTo(ByteBuffer target) throws CudaException {
1100
final int fromIndex = target.position();
1101
final int toIndex = target.limit();
1102
final int byteCount = toIndex - fromIndex;
1103
1104
lengthCheck(byteCount, 0);
1105
1106
if (target.isDirect()) {
1107
copyToHostDirect(deviceId, getAddress(), // <br/>
1108
target, fromIndex, toIndex);
1109
} else if (target.hasArray()) {
1110
final int offset = target.arrayOffset();
1111
1112
copyTo(target.array(), fromIndex + offset, toIndex + offset);
1113
} else {
1114
ByteBuffer tmp = allocateDirectBuffer(byteCount).order(DeviceOrder);
1115
1116
try {
1117
copyToHostDirect(deviceId, getAddress(), // <br/>
1118
tmp, 0, byteCount);
1119
target.put(tmp);
1120
} finally {
1121
freeDirectBuffer(tmp);
1122
}
1123
}
1124
1125
target.position(toIndex);
1126
}
1127
1128
/**
1129
* Copies data from this buffer (on the device) to the specified
1130
* {@code array} (on the Java host). Equivalent to
1131
* <pre>
1132
* copyTo(array, 0, array.length);
1133
* </pre>
1134
*
1135
* @param array
1136
* the destination array
1137
* @throws CudaException
1138
* if a CUDA exception occurs
1139
* @throws IllegalStateException
1140
* if this buffer has been closed (see {@link #close()})
1141
* @throws IndexOutOfBoundsException
1142
* if the number of required source bytes is larger than the length
1143
* of this buffer
1144
*/
1145
public void copyTo(char[] array) throws CudaException {
1146
copyTo(array, 0, array.length);
1147
}
1148
1149
/**
1150
* Copies data from this buffer (on the device) to the specified
1151
* {@code array} (on the Java host). Elements are read starting at the
1152
* beginning of this buffer and stored in {@code array} beginning
1153
* at {@code fromIndex} continuing up to, but excluding, {@code toIndex}.
1154
* <p>
1155
* A sub-buffer may be created (see {@link #atOffset(long)}) when the source
1156
* data are not located at the beginning of this buffer.
1157
*
1158
* @param array
1159
* the destination array
1160
* @param fromIndex
1161
* the destination starting offset (inclusive)
1162
* @param toIndex
1163
* the destination ending offset (exclusive)
1164
* @throws CudaException
1165
* if a CUDA exception occurs
1166
* @throws IllegalArgumentException
1167
* if {@code fromIndex > toIndex}
1168
* @throws IllegalStateException
1169
* if this buffer has been closed (see {@link #close()})
1170
* @throws IndexOutOfBoundsException
1171
* if {@code fromIndex} is negative, {@code toIndex > array.length},
1172
* or the number of required source bytes is larger than the length
1173
* of this buffer
1174
*/
1175
public void copyTo(char[] array, int fromIndex, int toIndex)
1176
throws CudaException {
1177
rangeCheck(array.length, fromIndex, toIndex);
1178
lengthCheck(toIndex - fromIndex, 1);
1179
copyToHostChar(deviceId, getAddress(), // <br/>
1180
array, fromIndex, toIndex);
1181
}
1182
1183
/**
1184
* Copies data from this buffer (on the device) to the specified
1185
* {@code target} buffer (on the Java host). Elements are read starting at
1186
* the beginning of this buffer and stored in {@code target} beginning
1187
* at {@code position()} continuing up to, but excluding, {@code limit()}.
1188
* The {@code target} buffer position is set to {@code limit()}.
1189
* <p>
1190
* A sub-buffer may be created (see {@link #atOffset(long)}) when the source
1191
* data are not located at the beginning of this buffer.
1192
*
1193
* @param target
1194
* the destination buffer
1195
* @throws CudaException
1196
* if a CUDA exception occurs
1197
* @throws IllegalStateException
1198
* if this buffer has been closed (see {@link #close()})
1199
* @throws IndexOutOfBoundsException
1200
* if the number of required source bytes is larger than the length
1201
* of this buffer
1202
*/
1203
public void copyTo(CharBuffer target) throws CudaException {
1204
final int fromIndex = target.position();
1205
final int toIndex = target.limit();
1206
1207
lengthCheck(toIndex - fromIndex, 1);
1208
1209
if (target.isDirect()) {
1210
copyToHostDirect(deviceId, getAddress(), // <br/>
1211
target, (long) fromIndex << 1, (long) toIndex << 1);
1212
} else if (target.hasArray()) {
1213
final int offset = target.arrayOffset();
1214
1215
copyTo(target.array(), fromIndex + offset, toIndex + offset);
1216
} else {
1217
final long byteCount = (long) (toIndex - fromIndex) << 1;
1218
final int chunkSize = chunkBytes(byteCount);
1219
final CharBuffer tmp = allocateDirectBuffer(chunkSize) // <br/>
1220
.order(DeviceOrder).asCharBuffer();
1221
1222
try {
1223
for (long start = 0; start < byteCount; start += chunkSize) {
1224
final int chunk = (int) Math.min(byteCount - start,
1225
chunkSize);
1226
1227
tmp.position(0).limit(chunk >> 1);
1228
copyToHostDirect(deviceId, getAddress() + start, // <br/>
1229
tmp, 0, chunk);
1230
target.put(tmp);
1231
}
1232
} finally {
1233
freeDirectBuffer(tmp);
1234
}
1235
}
1236
1237
target.position(toIndex);
1238
}
1239
1240
/**
1241
* Copies data from this buffer (on the device) to the specified
1242
* {@code array} (on the Java host). Equivalent to
1243
* <pre>
1244
* copyTo(array, 0, array.length);
1245
* </pre>
1246
*
1247
* @param array
1248
* the destination array
1249
* @throws CudaException
1250
* if a CUDA exception occurs
1251
* @throws IllegalStateException
1252
* if this buffer has been closed (see {@link #close()})
1253
* @throws IndexOutOfBoundsException
1254
* if the number of required source bytes is larger than the length
1255
* of this buffer
1256
*/
1257
public void copyTo(double[] array) throws CudaException {
1258
copyTo(array, 0, array.length);
1259
}
1260
1261
/**
1262
* Copies data from this buffer (on the device) to the specified
1263
* {@code array} (on the Java host). Elements are read starting at the
1264
* beginning of this buffer and stored in {@code array} beginning
1265
* at {@code fromIndex} continuing up to, but excluding, {@code toIndex}.
1266
* <p>
1267
* A sub-buffer may be created (see {@link #atOffset(long)}) when the source
1268
* data are not located at the beginning of this buffer.
1269
*
1270
* @param array
1271
* the destination array
1272
* @param fromIndex
1273
* the destination starting offset (inclusive)
1274
* @param toIndex
1275
* the destination ending offset (exclusive)
1276
* @throws CudaException
1277
* if a CUDA exception occurs
1278
* @throws IllegalArgumentException
1279
* if {@code fromIndex > toIndex}
1280
* @throws IllegalStateException
1281
* if this buffer has been closed (see {@link #close()})
1282
* @throws IndexOutOfBoundsException
1283
* if {@code fromIndex} is negative, {@code toIndex > array.length},
1284
* or the number of required source bytes is larger than the length
1285
* of this buffer
1286
*/
1287
public void copyTo(double[] array, int fromIndex, int toIndex)
1288
throws CudaException {
1289
rangeCheck(array.length, fromIndex, toIndex);
1290
lengthCheck(toIndex - fromIndex, 3);
1291
copyToHostDouble(deviceId, getAddress(), // <br/>
1292
array, fromIndex, toIndex);
1293
}
1294
1295
/**
1296
* Copies data from this buffer (on the device) to the specified
1297
* {@code target} buffer (on the Java host). Elements are read starting at
1298
* the beginning of this buffer and stored in {@code target} beginning
1299
* at {@code position()} continuing up to, but excluding, {@code limit()}.
1300
* The {@code target} buffer position is set to {@code limit()}.
1301
* <p>
1302
* A sub-buffer may be created (see {@link #atOffset(long)}) when the source
1303
* data are not located at the beginning of this buffer.
1304
*
1305
* @param target
1306
* the destination buffer
1307
* @throws CudaException
1308
* if a CUDA exception occurs
1309
* @throws IllegalStateException
1310
* if this buffer has been closed (see {@link #close()})
1311
* @throws IndexOutOfBoundsException
1312
* if the number of required source bytes is larger than the length
1313
* of this buffer
1314
*/
1315
public void copyTo(DoubleBuffer target) throws CudaException {
1316
final int fromIndex = target.position();
1317
final int toIndex = target.limit();
1318
1319
lengthCheck(toIndex - fromIndex, 3);
1320
1321
if (target.isDirect()) {
1322
copyToHostDirect(deviceId, getAddress(), // <br/>
1323
target, (long) fromIndex << 3, (long) toIndex << 3);
1324
} else if (target.hasArray()) {
1325
final int offset = target.arrayOffset();
1326
1327
copyTo(target.array(), fromIndex + offset, toIndex + offset);
1328
} else {
1329
final long byteCount = (long) (toIndex - fromIndex) << 3;
1330
final int chunkSize = chunkBytes(byteCount);
1331
final DoubleBuffer tmp = allocateDirectBuffer(chunkSize) // <br/>
1332
.order(DeviceOrder).asDoubleBuffer();
1333
1334
try {
1335
for (long start = 0; start < byteCount; start += chunkSize) {
1336
final int chunk = (int) Math.min(byteCount - start,
1337
chunkSize);
1338
1339
tmp.position(0).limit(chunk >> 3);
1340
copyToHostDirect(deviceId, getAddress() + start, // <br/>
1341
tmp, 0, chunk);
1342
target.put(tmp);
1343
}
1344
} finally {
1345
freeDirectBuffer(tmp);
1346
}
1347
}
1348
1349
target.position(toIndex);
1350
}
1351
1352
/**
1353
* Copies data from this buffer (on the device) to the specified
1354
* {@code array} (on the Java host). Equivalent to
1355
* <pre>
1356
* copyTo(array, 0, array.length);
1357
* </pre>
1358
*
1359
* @param array
1360
* the destination array
1361
* @throws CudaException
1362
* if a CUDA exception occurs
1363
* @throws IllegalStateException
1364
* if this buffer has been closed (see {@link #close()})
1365
* @throws IndexOutOfBoundsException
1366
* if the number of required source bytes is larger than the length
1367
* of this buffer
1368
*/
1369
public void copyTo(float[] array) throws CudaException {
1370
copyTo(array, 0, array.length);
1371
}
1372
1373
/**
1374
* Copies data from this buffer (on the device) to the specified
1375
* {@code array} (on the Java host). Elements are read starting at the
1376
* beginning of this buffer and stored in {@code array} beginning
1377
* at {@code fromIndex} continuing up to, but excluding, {@code toIndex}.
1378
* <p>
1379
* A sub-buffer may be created (see {@link #atOffset(long)}) when the source
1380
* data are not located at the beginning of this buffer.
1381
*
1382
* @param array
1383
* the destination array
1384
* @param fromIndex
1385
* the destination starting offset (inclusive)
1386
* @param toIndex
1387
* the destination ending offset (exclusive)
1388
* @throws CudaException
1389
* if a CUDA exception occurs
1390
* @throws IllegalArgumentException
1391
* if {@code fromIndex > toIndex}
1392
* @throws IllegalStateException
1393
* if this buffer has been closed (see {@link #close()})
1394
* @throws IndexOutOfBoundsException
1395
* if {@code fromIndex} is negative, {@code toIndex > array.length},
1396
* or the number of required source bytes is larger than the length
1397
* of this buffer
1398
*/
1399
public void copyTo(float[] array, int fromIndex, int toIndex)
1400
throws CudaException {
1401
rangeCheck(array.length, fromIndex, toIndex);
1402
lengthCheck(toIndex - fromIndex, 2);
1403
copyToHostFloat(deviceId, getAddress(), // <br/>
1404
array, fromIndex, toIndex);
1405
}
1406
1407
/**
1408
* Copies data from this buffer (on the device) to the specified
1409
* {@code target} buffer (on the Java host). Elements are read starting at
1410
* the beginning of this buffer and stored in {@code target} beginning
1411
* at {@code position()} continuing up to, but excluding, {@code limit()}.
1412
* The {@code target} buffer position is set to {@code limit()}.
1413
* <p>
1414
* A sub-buffer may be created (see {@link #atOffset(long)}) when the source
1415
* data are not located at the beginning of this buffer.
1416
*
1417
* @param target
1418
* the destination buffer
1419
* @throws CudaException
1420
* if a CUDA exception occurs
1421
* @throws IllegalStateException
1422
* if this buffer has been closed (see {@link #close()})
1423
* @throws IndexOutOfBoundsException
1424
* if the number of required source bytes is larger than the length
1425
* of this buffer
1426
*/
1427
public void copyTo(FloatBuffer target) throws CudaException {
1428
final int fromIndex = target.position();
1429
final int toIndex = target.limit();
1430
1431
lengthCheck(toIndex - fromIndex, 2);
1432
1433
if (target.isDirect()) {
1434
copyToHostDirect(deviceId, getAddress(), // <br/>
1435
target, (long) fromIndex << 2, (long) toIndex << 2);
1436
} else if (target.hasArray()) {
1437
final int offset = target.arrayOffset();
1438
1439
copyTo(target.array(), fromIndex + offset, toIndex + offset);
1440
} else {
1441
final long byteCount = (long) (toIndex - fromIndex) << 2;
1442
final int chunkSize = chunkBytes(byteCount);
1443
final FloatBuffer tmp = allocateDirectBuffer(chunkSize) // <br/>
1444
.order(DeviceOrder).asFloatBuffer();
1445
1446
try {
1447
for (long start = 0; start < byteCount; start += chunkSize) {
1448
final int chunk = (int) Math.min(byteCount - start,
1449
chunkSize);
1450
1451
tmp.position(0).limit(chunk >> 2);
1452
copyToHostDirect(deviceId, getAddress() + start, // <br/>
1453
tmp, 0, chunk);
1454
target.put(tmp);
1455
}
1456
} finally {
1457
freeDirectBuffer(tmp);
1458
}
1459
}
1460
1461
target.position(toIndex);
1462
}
1463
1464
/**
1465
* Copies data from this buffer (on the device) to the specified
1466
* {@code array} (on the Java host). Equivalent to
1467
* <pre>
1468
* copyTo(array, 0, array.length);
1469
* </pre>
1470
*
1471
* @param array
1472
* the destination array
1473
* @throws CudaException
1474
* if a CUDA exception occurs
1475
* @throws IllegalStateException
1476
* if this buffer has been closed (see {@link #close()})
1477
* @throws IndexOutOfBoundsException
1478
* if the number of required source bytes is larger than the length
1479
* of this buffer
1480
*/
1481
public void copyTo(int[] array) throws CudaException {
1482
copyTo(array, 0, array.length);
1483
}
1484
1485
/**
1486
* Copies data from this buffer (on the device) to the specified
1487
* {@code array} (on the Java host). Elements are read starting at the
1488
* beginning of this buffer and stored in {@code array} beginning
1489
* at {@code fromIndex} continuing up to, but excluding, {@code toIndex}.
1490
* <p>
1491
* A sub-buffer may be created (see {@link #atOffset(long)}) when the source
1492
* data are not located at the beginning of this buffer.
1493
*
1494
* @param array
1495
* the destination array
1496
* @param fromIndex
1497
* the destination starting offset (inclusive)
1498
* @param toIndex
1499
* the destination ending offset (exclusive)
1500
* @throws CudaException
1501
* if a CUDA exception occurs
1502
* @throws IllegalArgumentException
1503
* if {@code fromIndex > toIndex}
1504
* @throws IllegalStateException
1505
* if this buffer has been closed (see {@link #close()})
1506
* @throws IndexOutOfBoundsException
1507
* if {@code fromIndex} is negative, {@code toIndex > array.length},
1508
* or the number of required source bytes is larger than the length
1509
* of this buffer
1510
*/
1511
public void copyTo(int[] array, int fromIndex, int toIndex)
1512
throws CudaException {
1513
rangeCheck(array.length, fromIndex, toIndex);
1514
lengthCheck(toIndex - fromIndex, 2);
1515
copyToHostInt(deviceId, getAddress(), // <br/>
1516
array, fromIndex, toIndex);
1517
}
1518
1519
/**
1520
* Copies data from this buffer (on the device) to the specified
1521
* {@code target} buffer (on the Java host). Elements are read starting at
1522
* the beginning of this buffer and stored in {@code target} beginning
1523
* at {@code position()} continuing up to, but excluding, {@code limit()}.
1524
* The {@code target} buffer position is set to {@code limit()}.
1525
* <p>
1526
* A sub-buffer may be created (see {@link #atOffset(long)}) when the source
1527
* data are not located at the beginning of this buffer.
1528
*
1529
* @param target
1530
* the destination buffer
1531
* @throws CudaException
1532
* if a CUDA exception occurs
1533
* @throws IllegalStateException
1534
* if this buffer has been closed (see {@link #close()})
1535
* @throws IndexOutOfBoundsException
1536
* if the number of required source bytes is larger than the length
1537
* of this buffer
1538
*/
1539
public void copyTo(IntBuffer target) throws CudaException {
1540
final int fromIndex = target.position();
1541
final int toIndex = target.limit();
1542
1543
lengthCheck(toIndex - fromIndex, 2);
1544
1545
if (target.isDirect()) {
1546
copyToHostDirect(deviceId, getAddress(), // <br/>
1547
target, (long) fromIndex << 2, (long) toIndex << 2);
1548
} else if (target.hasArray()) {
1549
final int offset = target.arrayOffset();
1550
1551
copyTo(target.array(), fromIndex + offset, toIndex + offset);
1552
} else {
1553
final long byteCount = (long) (toIndex - fromIndex) << 2;
1554
final int chunkSize = chunkBytes(byteCount);
1555
final IntBuffer tmp = allocateDirectBuffer(chunkSize) // <br/>
1556
.order(DeviceOrder).asIntBuffer();
1557
1558
try {
1559
for (long start = 0; start < byteCount; start += chunkSize) {
1560
final int chunk = (int) Math.min(byteCount - start,
1561
chunkSize);
1562
1563
tmp.position(0).limit(chunk >> 2);
1564
copyToHostDirect(deviceId, getAddress() + start, // <br/>
1565
tmp, 0, chunk);
1566
target.put(tmp);
1567
}
1568
} finally {
1569
freeDirectBuffer(tmp);
1570
}
1571
}
1572
1573
target.position(toIndex);
1574
}
1575
1576
/**
1577
* Copies data from this buffer (on the device) to the specified
1578
* {@code array} (on the Java host). Equivalent to
1579
* <pre>
1580
* copyTo(array, 0, array.length);
1581
* </pre>
1582
*
1583
* @param array
1584
* the destination array
1585
* @throws CudaException
1586
* if a CUDA exception occurs
1587
* @throws IllegalStateException
1588
* if this buffer has been closed (see {@link #close()})
1589
* @throws IndexOutOfBoundsException
1590
* if the number of required source bytes is larger than the length
1591
* of this buffer
1592
*/
1593
public void copyTo(long[] array) throws CudaException {
1594
copyTo(array, 0, array.length);
1595
}
1596
1597
/**
1598
* Copies data from this buffer (on the device) to the specified
1599
* {@code array} (on the Java host). Elements are read starting at the
1600
* beginning of this buffer and stored in {@code array} beginning
1601
* at {@code fromIndex} continuing up to, but excluding, {@code toIndex}.
1602
* <p>
1603
* A sub-buffer may be created (see {@link #atOffset(long)}) when the source
1604
* data are not located at the beginning of this buffer.
1605
*
1606
* @param array
1607
* the destination array
1608
* @param fromIndex
1609
* the destination starting offset (inclusive)
1610
* @param toIndex
1611
* the destination ending offset (exclusive)
1612
* @throws CudaException
1613
* if a CUDA exception occurs
1614
* @throws IllegalArgumentException
1615
* if {@code fromIndex > toIndex}
1616
* @throws IllegalStateException
1617
* if this buffer has been closed (see {@link #close()})
1618
* @throws IndexOutOfBoundsException
1619
* if {@code fromIndex} is negative, {@code toIndex > array.length},
1620
* or the number of required source bytes is larger than the length
1621
* of this buffer
1622
*/
1623
public void copyTo(long[] array, int fromIndex, int toIndex)
1624
throws CudaException {
1625
rangeCheck(array.length, fromIndex, toIndex);
1626
lengthCheck(toIndex - fromIndex, 3);
1627
copyToHostLong(deviceId, getAddress(), // <br/>
1628
array, fromIndex, toIndex);
1629
}
1630
1631
/**
1632
* Copies data from this buffer (on the device) to the specified
1633
* {@code target} buffer (on the Java host). Elements are read starting at
1634
* the beginning of this buffer and stored in {@code target} beginning
1635
* at {@code position()} continuing up to, but excluding, {@code limit()}.
1636
* The {@code target} buffer position is set to {@code limit()}.
1637
* <p>
1638
* A sub-buffer may be created (see {@link #atOffset(long)}) when the source
1639
* data are not located at the beginning of this buffer.
1640
*
1641
* @param target
1642
* the destination buffer
1643
* @throws CudaException
1644
* if a CUDA exception occurs
1645
* @throws IllegalStateException
1646
* if this buffer has been closed (see {@link #close()})
1647
* @throws IndexOutOfBoundsException
1648
* if the number of required source bytes is larger than the length
1649
* of this buffer
1650
*/
1651
public void copyTo(LongBuffer target) throws CudaException {
1652
final int fromIndex = target.position();
1653
final int toIndex = target.limit();
1654
1655
lengthCheck(toIndex - fromIndex, 3);
1656
1657
if (target.isDirect()) {
1658
copyToHostDirect(deviceId, getAddress(), // <br/>
1659
target, (long) fromIndex << 3, (long) toIndex << 3);
1660
} else if (target.hasArray()) {
1661
final int offset = target.arrayOffset();
1662
1663
copyTo(target.array(), fromIndex + offset, toIndex + offset);
1664
} else {
1665
final long byteCount = (long) (toIndex - fromIndex) << 3;
1666
final int chunkSize = chunkBytes(byteCount);
1667
final LongBuffer tmp = allocateDirectBuffer(chunkSize) // <br/>
1668
.order(DeviceOrder).asLongBuffer();
1669
1670
try {
1671
for (long start = 0; start < byteCount; start += chunkSize) {
1672
final int chunk = (int) Math.min(byteCount - start,
1673
chunkSize);
1674
1675
tmp.position(0).limit(chunk >> 3);
1676
copyToHostDirect(deviceId, getAddress() + start, // <br/>
1677
tmp, 0, chunk);
1678
target.put(tmp);
1679
}
1680
} finally {
1681
freeDirectBuffer(tmp);
1682
}
1683
}
1684
1685
target.position(toIndex);
1686
}
1687
1688
/**
1689
* Copies data from this buffer (on the device) to the specified
1690
* {@code array} (on the Java host). Equivalent to
1691
* <pre>
1692
* copyTo(array, 0, array.length);
1693
* </pre>
1694
*
1695
* @param array
1696
* the destination array
1697
* @throws CudaException
1698
* if a CUDA exception occurs
1699
* @throws IllegalStateException
1700
* if this buffer has been closed (see {@link #close()})
1701
* @throws IndexOutOfBoundsException
1702
* if the number of required source bytes is larger than the length
1703
* of this buffer
1704
*/
1705
public void copyTo(short[] array) throws CudaException {
1706
copyTo(array, 0, array.length);
1707
}
1708
1709
/**
1710
* Copies data from this buffer (on the device) to the specified
1711
* {@code array} (on the Java host). Elements are read starting at the
1712
* beginning of this buffer and stored in {@code array} beginning
1713
* at {@code fromIndex} continuing up to, but excluding, {@code toIndex}.
1714
* <p>
1715
* A sub-buffer may be created (see {@link #atOffset(long)}) when the source
1716
* data are not located at the beginning of this buffer.
1717
*
1718
* @param array
1719
* the destination array
1720
* @param fromIndex
1721
* the destination starting offset (inclusive)
1722
* @param toIndex
1723
* the destination ending offset (exclusive)
1724
* @throws CudaException
1725
* if a CUDA exception occurs
1726
* @throws IllegalArgumentException
1727
* if {@code fromIndex > toIndex}
1728
* @throws IllegalStateException
1729
* if this buffer has been closed (see {@link #close()})
1730
* @throws IndexOutOfBoundsException
1731
* if {@code fromIndex} is negative, {@code toIndex > array.length},
1732
* or the number of required source bytes is larger than the length
1733
* of this buffer
1734
*/
1735
public void copyTo(short[] array, int fromIndex, int toIndex)
1736
throws CudaException {
1737
rangeCheck(array.length, fromIndex, toIndex);
1738
lengthCheck(toIndex - fromIndex, 1);
1739
copyToHostShort(deviceId, getAddress(), // <br/>
1740
array, fromIndex, toIndex);
1741
}
1742
1743
/**
1744
* Copies data from this buffer (on the device) to the specified
1745
* {@code target} buffer (on the Java host). Elements are read starting at
1746
* the beginning of this buffer and stored in {@code target} beginning
1747
* at {@code position()} continuing up to, but excluding, {@code limit()}.
1748
* The {@code target} buffer position is set to {@code limit()}.
1749
* <p>
1750
* A sub-buffer may be created (see {@link #atOffset(long)}) when the source
1751
* data are not located at the beginning of this buffer.
1752
*
1753
* @param target
1754
* the destination buffer
1755
* @throws CudaException
1756
* if a CUDA exception occurs
1757
* @throws IllegalStateException
1758
* if this buffer has been closed (see {@link #close()})
1759
* @throws IndexOutOfBoundsException
1760
* if the number of required source bytes is larger than the length
1761
* of this buffer
1762
*/
1763
public void copyTo(ShortBuffer target) throws CudaException {
1764
final int fromIndex = target.position();
1765
final int toIndex = target.limit();
1766
1767
lengthCheck(toIndex - fromIndex, 1);
1768
1769
if (target.isDirect()) {
1770
copyToHostDirect(deviceId, getAddress(), // <br/>
1771
target, (long) fromIndex << 1, (long) toIndex << 1);
1772
} else if (target.hasArray()) {
1773
final int offset = target.arrayOffset();
1774
1775
copyTo(target.array(), fromIndex + offset, toIndex + offset);
1776
} else {
1777
final long byteCount = (long) (toIndex - fromIndex) << 1;
1778
final int chunkSize = chunkBytes(byteCount);
1779
final ShortBuffer tmp = allocateDirectBuffer(chunkSize) // <br/>
1780
.order(DeviceOrder).asShortBuffer();
1781
1782
try {
1783
for (long start = 0; start < byteCount; start += chunkSize) {
1784
final int chunk = (int) Math.min(byteCount - start,
1785
chunkSize);
1786
1787
tmp.position(0).limit(chunk >> 1);
1788
copyToHostDirect(deviceId, getAddress() + start, // <br/>
1789
tmp, 0, chunk);
1790
target.put(tmp);
1791
}
1792
} finally {
1793
freeDirectBuffer(tmp);
1794
}
1795
}
1796
1797
target.position(toIndex);
1798
}
1799
1800
/**
1801
* Stores {@code count} copies of {@code value} in this buffer.
1802
* <p>
1803
* A sub-buffer may be created (see {@link #atOffset(long)}) when the values
1804
* are to be stored somewhere other than the beginning of this buffer.
1805
*
1806
* @param value
1807
* the destination array
1808
* @param count
1809
* the destination array
1810
* @throws CudaException
1811
* if a CUDA exception occurs
1812
* @throws IllegalStateException
1813
* if this buffer has been closed (see {@link #close()})
1814
* @throws IndexOutOfBoundsException
1815
* if the space required is larger than the length of this buffer
1816
*/
1817
public void fillByte(byte value, long count) throws CudaException {
1818
lengthCheck(count, 0);
1819
fill(deviceId, getAddress(), Byte.SIZE / 8, value, count);
1820
}
1821
1822
/**
1823
* Stores {@code count} copies of {@code value} in this buffer.
1824
* <p>
1825
* A sub-buffer may be created (see {@link #atOffset(long)}) when the values
1826
* are to be stored somewhere other than the beginning of this buffer.
1827
*
1828
* @param value
1829
* the destination array
1830
* @param count
1831
* the destination array
1832
* @throws CudaException
1833
* if a CUDA exception occurs
1834
* @throws IllegalStateException
1835
* if this buffer has been closed (see {@link #close()})
1836
* @throws IndexOutOfBoundsException
1837
* if the space required is larger than the length of this buffer
1838
*/
1839
public void fillChar(char value, long count) throws CudaException {
1840
lengthCheck(count, 1);
1841
fill(deviceId, getAddress(), Character.SIZE / 8, value, count);
1842
}
1843
1844
/**
1845
* Stores {@code count} copies of {@code value} in this buffer.
1846
* <p>
1847
* A sub-buffer may be created (see {@link #atOffset(long)}) when the values
1848
* are to be stored somewhere other than the beginning of this buffer.
1849
*
1850
* @param value
1851
* the destination array
1852
* @param count
1853
* the destination array
1854
* @throws CudaException
1855
* if a CUDA exception occurs
1856
* @throws IllegalStateException
1857
* if this buffer has been closed (see {@link #close()})
1858
* @throws IndexOutOfBoundsException
1859
* if the space required is larger than the length of this buffer
1860
*/
1861
public void fillFloat(float value, long count) throws CudaException {
1862
fillInt(Float.floatToRawIntBits(value), count);
1863
}
1864
1865
/**
1866
* Stores {@code count} copies of {@code value} in this buffer.
1867
* <p>
1868
* A sub-buffer may be created (see {@link #atOffset(long)}) when the values
1869
* are to be stored somewhere other than the beginning of this buffer.
1870
*
1871
* @param value
1872
* the destination array
1873
* @param count
1874
* the destination array
1875
* @throws CudaException
1876
* if a CUDA exception occurs
1877
* @throws IllegalStateException
1878
* if this buffer has been closed (see {@link #close()})
1879
* @throws IndexOutOfBoundsException
1880
* if the space required is larger than the length of this buffer
1881
*/
1882
public void fillInt(int value, long count) throws CudaException {
1883
lengthCheck(count, 2);
1884
fill(deviceId, getAddress(), Integer.SIZE / 8, value, count);
1885
}
1886
1887
/**
1888
* Stores {@code count} copies of {@code value} in this buffer.
1889
* <p>
1890
* A sub-buffer may be created (see {@link #atOffset(long)}) when the values
1891
* are to be stored somewhere other than the beginning of this buffer.
1892
*
1893
* @param value
1894
* the destination array
1895
* @param count
1896
* the destination array
1897
* @throws CudaException
1898
* if a CUDA exception occurs
1899
* @throws IllegalStateException
1900
* if this buffer has been closed (see {@link #close()})
1901
* @throws IndexOutOfBoundsException
1902
* if the space required is larger than the length of this buffer
1903
*/
1904
public void fillShort(short value, long count) throws CudaException {
1905
lengthCheck(count, 1);
1906
fill(deviceId, getAddress(), Short.SIZE / 8, value, count);
1907
}
1908
1909
long getAddress() {
1910
long address = devicePtr.get();
1911
1912
if (address != 0) {
1913
if (parent == null || parent.devicePtr.get() != 0) {
1914
return address;
1915
}
1916
1917
// the parent buffer has been closed making this buffer invalid
1918
devicePtr.set(0);
1919
}
1920
1921
throw new IllegalStateException();
1922
}
1923
1924
/**
1925
* Returns the length in bytes of this buffer.
1926
*
1927
* @return
1928
* the length in bytes of this buffer
1929
*/
1930
public long getLength() {
1931
return length;
1932
}
1933
1934
private void lengthCheck(long elementCount, int logUnitSize) {
1935
if (!(0 <= elementCount && elementCount <= (length >> logUnitSize))) {
1936
throw new IndexOutOfBoundsException(String.valueOf(elementCount));
1937
}
1938
}
1939
1940
/**
1941
* Returns a sub-region of this buffer. The new buffer begins at the
1942
* specified fromOffset and extends to the specified toOffset (exclusive).
1943
*
1944
* @param fromOffset
1945
* the byte offset of the start of the sub-region within this buffer
1946
* @param toOffset
1947
* the byte offset of the end of the sub-region within this buffer
1948
* @return
1949
* the specified sub-region
1950
* @throws IllegalArgumentException
1951
* if {@code fromOffset > toOffset}
1952
* @throws IllegalStateException
1953
* if this buffer has been closed (see {@link #close()})
1954
* @throws IndexOutOfBoundsException
1955
* if {@code fromOffset} is negative, {@code toOffset > length},
1956
* or the number of source bytes is larger than the length
1957
* of this buffer
1958
*/
1959
public CudaBuffer slice(long fromOffset, long toOffset) {
1960
if (fromOffset == 0 && toOffset == length) {
1961
return this;
1962
} else {
1963
rangeCheck(length, fromOffset, toOffset);
1964
1965
return new CudaBuffer( // <br/>
1966
parent != null ? parent : this, // <br/>
1967
deviceId, // <br/>
1968
getAddress() + fromOffset, // <br/>
1969
toOffset - fromOffset);
1970
}
1971
}
1972
}
1973
1974