TMF: Synchronize an experiment instead of collection of traces
[deliverable/tracecompass.git] / org.eclipse.tracecompass.tmf.core / src / org / eclipse / tracecompass / tmf / core / trace / experiment / TmfExperiment.java
1 /*******************************************************************************
2 * Copyright (c) 2009, 2014 Ericsson, École Polytechnique de Montréal
3 *
4 * All rights reserved. This program and the accompanying materials are
5 * made available under the terms of the Eclipse Public License v1.0 which
6 * accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
8 *
9 * Contributors:
10 * Francois Chouinard - Initial API and implementation
11 * Francois Chouinard - Updated as per TMF Trace Model 1.0
12 * Patrick Tasse - Updated for removal of context clone
13 * Patrick Tasse - Updated for ranks in experiment location
14 * Geneviève Bastien - Added support of experiment synchronization
15 * Added the initExperiment method and default constructor
16 *******************************************************************************/
17
18 package org.eclipse.tracecompass.tmf.core.trace.experiment;
19
20 import java.io.File;
21 import java.nio.ByteBuffer;
22 import java.util.Collections;
23 import java.util.concurrent.locks.Lock;
24 import java.util.concurrent.locks.ReentrantLock;
25
26 import org.eclipse.core.resources.IProject;
27 import org.eclipse.core.resources.IResource;
28 import org.eclipse.core.runtime.CoreException;
29 import org.eclipse.core.runtime.IStatus;
30 import org.eclipse.core.runtime.MultiStatus;
31 import org.eclipse.core.runtime.Status;
32 import org.eclipse.jdt.annotation.Nullable;
33 import org.eclipse.tracecompass.internal.tmf.core.Activator;
34 import org.eclipse.tracecompass.internal.tmf.core.trace.experiment.TmfExperimentContext;
35 import org.eclipse.tracecompass.internal.tmf.core.trace.experiment.TmfExperimentLocation;
36 import org.eclipse.tracecompass.internal.tmf.core.trace.experiment.TmfLocationArray;
37 import org.eclipse.tracecompass.tmf.core.TmfCommonConstants;
38 import org.eclipse.tracecompass.tmf.core.event.ITmfEvent;
39 import org.eclipse.tracecompass.tmf.core.exceptions.TmfTraceException;
40 import org.eclipse.tracecompass.tmf.core.request.ITmfEventRequest;
41 import org.eclipse.tracecompass.tmf.core.signal.TmfSignalHandler;
42 import org.eclipse.tracecompass.tmf.core.signal.TmfTraceOpenedSignal;
43 import org.eclipse.tracecompass.tmf.core.signal.TmfTraceRangeUpdatedSignal;
44 import org.eclipse.tracecompass.tmf.core.signal.TmfTraceSynchronizedSignal;
45 import org.eclipse.tracecompass.tmf.core.synchronization.SynchronizationAlgorithm;
46 import org.eclipse.tracecompass.tmf.core.synchronization.SynchronizationManager;
47 import org.eclipse.tracecompass.tmf.core.timestamp.ITmfTimestamp;
48 import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimeRange;
49 import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimestamp;
50 import org.eclipse.tracecompass.tmf.core.trace.ITmfContext;
51 import org.eclipse.tracecompass.tmf.core.trace.ITmfEventParser;
52 import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
53 import org.eclipse.tracecompass.tmf.core.trace.TmfTrace;
54 import org.eclipse.tracecompass.tmf.core.trace.TmfTraceManager;
55 import org.eclipse.tracecompass.tmf.core.trace.indexer.ITmfPersistentlyIndexable;
56 import org.eclipse.tracecompass.tmf.core.trace.indexer.ITmfTraceIndexer;
57 import org.eclipse.tracecompass.tmf.core.trace.indexer.TmfBTreeTraceIndexer;
58 import org.eclipse.tracecompass.tmf.core.trace.location.ITmfLocation;
59
60 /**
61 * TmfExperiment presents a time-ordered, unified view of a set of ITmfTrace:s
62 * that are part of a tracing experiment.
63 *
64 * @version 1.0
65 * @author Francois Chouinard
66 */
67 public class TmfExperiment extends TmfTrace implements ITmfEventParser, ITmfPersistentlyIndexable {
68
69 // ------------------------------------------------------------------------
70 // Constants
71 // ------------------------------------------------------------------------
72
73 /**
74 * The file name of the Synchronization
75 *
76 * @since 3.0
77 * @deprecated This file name shouldn't be used directly anymore. All
78 * synchronization files have been moved to a folder and you
79 * should use the {@link #getSynchronizationFolder(boolean)}
80 * method to return the path to this folder.
81 */
82 @Deprecated
83 public static final String SYNCHRONIZATION_FILE_NAME = "synchronization.bin"; //$NON-NLS-1$
84
85 /**
86 * The name of the directory containing trace synchronization data. This
87 * directory typically will be preserved when traces are synchronized.
88 * Analysis involved in synchronization can put their supplementary files in
89 * there so they are not deleted when synchronized traces are copied.
90 */
91 private static final String SYNCHRONIZATION_DIRECTORY = "sync_data"; //$NON-NLS-1$
92
93 /**
94 * The default index page size
95 */
96 public static final int DEFAULT_INDEX_PAGE_SIZE = 5000;
97
98 // ------------------------------------------------------------------------
99 // Attributes
100 // ------------------------------------------------------------------------
101
102 /**
103 * The set of traces that constitute the experiment
104 */
105 protected ITmfTrace[] fTraces;
106
107 /**
108 * The set of traces that constitute the experiment
109 */
110 private boolean fInitialized = false;
111
112 /**
113 * Lock for synchronization methods. These methods cannot be 'synchronized'
114 * since it makes it impossible to use an event request on the experiment
115 * during synchronization (the request thread would block)
116 */
117 private final Lock fSyncLock = new ReentrantLock();
118
119 // ------------------------------------------------------------------------
120 // Construction
121 // ------------------------------------------------------------------------
122
123 /**
124 * Default constructor. Should not be used directly, but is needed for
125 * extension points.
126 *
127 * @deprecated Do not call this directly (but do not remove it either!)
128 */
129 @Deprecated
130 public TmfExperiment() {
131 super();
132 }
133
134 /**
135 * Constructor of an experiment, taking the type, path, traces,
136 * indexPageSize and resource
137 *
138 * @param type
139 * The event type
140 * @param path
141 * The experiment path
142 * @param traces
143 * The experiment set of traces
144 * @param indexPageSize
145 * The experiment index page size. You can use
146 * {@link TmfExperiment#DEFAULT_INDEX_PAGE_SIZE} for a default
147 * value.
148 * @param resource
149 * The resource associated to the experiment. You can use 'null'
150 * for no resources (tests, etc.)
151 */
152 public TmfExperiment(final Class<? extends ITmfEvent> type,
153 final String path,
154 final ITmfTrace[] traces,
155 final int indexPageSize,
156 final @Nullable IResource resource) {
157 initExperiment(type, path, traces, indexPageSize, resource);
158 }
159
160 @Override
161 protected ITmfTraceIndexer createIndexer(int interval) {
162 if (getCheckpointSize() > 0) {
163 return new TmfBTreeTraceIndexer(this, interval);
164 }
165 return super.createIndexer(interval);
166 }
167
168 /**
169 * Clears the experiment
170 */
171 @Override
172 public synchronized void dispose() {
173
174 // Clean up the index if applicable
175 if (getIndexer() != null) {
176 getIndexer().dispose();
177 }
178
179 if (fTraces != null) {
180 for (final ITmfTrace trace : fTraces) {
181 trace.dispose();
182 }
183 fTraces = null;
184 }
185 super.dispose();
186 }
187
188 // ------------------------------------------------------------------------
189 // ITmfTrace - Initializers
190 // ------------------------------------------------------------------------
191
192 @Override
193 public void initTrace(final IResource resource, final String path, final Class<? extends ITmfEvent> type) {
194 /* Do nothing for experiments */
195 }
196
197 /**
198 * Initialization of an experiment, taking the type, path, traces,
199 * indexPageSize and resource
200 *
201 * @param type
202 * the event type
203 * @param path
204 * the experiment path
205 * @param traces
206 * the experiment set of traces
207 * @param indexPageSize
208 * the experiment index page size
209 * @param resource
210 * the resource associated to the experiment
211 * @since 3.0
212 */
213 public void initExperiment(final Class<? extends ITmfEvent> type,
214 final String path,
215 final ITmfTrace[] traces,
216 final int indexPageSize,
217 final @Nullable IResource resource) {
218
219 setCacheSize(indexPageSize);
220 setStreamingInterval(0);
221 setParser(this);
222 // traces have to be set before super.initialize()
223 fTraces = traces;
224 try {
225 super.initialize(resource, path, type);
226 } catch (TmfTraceException e) {
227 Activator.logError("Error initializing experiment", e); //$NON-NLS-1$
228 }
229
230 if (resource != null) {
231 this.synchronizeTraces();
232 }
233 }
234
235 /**
236 * @since 2.0
237 */
238 @Override
239 public IStatus validate(final IProject project, final String path) {
240 return Status.OK_STATUS;
241 }
242
243 // ------------------------------------------------------------------------
244 // Accessors
245 // ------------------------------------------------------------------------
246
247 /**
248 * Get the traces contained in this experiment.
249 *
250 * @return The array of contained traces
251 */
252 public ITmfTrace[] getTraces() {
253 return fTraces;
254 }
255
256 /**
257 * Returns the timestamp of the event at the requested index. If none,
258 * returns null.
259 *
260 * @param index
261 * the event index (rank)
262 * @return the corresponding event timestamp
263 * @since 2.0
264 */
265 public ITmfTimestamp getTimestamp(final int index) {
266 final ITmfContext context = seekEvent(index);
267 final ITmfEvent event = getNext(context);
268 context.dispose();
269 return (event != null) ? event.getTimestamp() : null;
270 }
271
272 // ------------------------------------------------------------------------
273 // Request management
274 // ------------------------------------------------------------------------
275
276 /**
277 * @since 2.0
278 */
279 @Override
280 public synchronized ITmfContext armRequest(final ITmfEventRequest request) {
281
282 // Make sure we have something to read from
283 if (fTraces == null) {
284 return null;
285 }
286
287 if (!TmfTimestamp.BIG_BANG.equals(request.getRange().getStartTime())
288 && request.getIndex() == 0) {
289 final ITmfContext context = seekEvent(request.getRange().getStartTime());
290 request.setStartIndex((int) context.getRank());
291 return context;
292
293 }
294
295 return seekEvent(request.getIndex());
296 }
297
298 // ------------------------------------------------------------------------
299 // ITmfTrace trace positioning
300 // ------------------------------------------------------------------------
301
302 /**
303 * @since 3.0
304 */
305 @Override
306 public synchronized ITmfContext seekEvent(final ITmfLocation location) {
307 // Validate the location
308 if (location != null && !(location instanceof TmfExperimentLocation)) {
309 return null; // Throw an exception?
310 }
311 // Make sure we have something to read from
312 if (fTraces == null) {
313 return null;
314 }
315
316 // Initialize the location array if necessary
317 TmfLocationArray locationArray = ((location == null) ?
318 new TmfLocationArray(fTraces.length) :
319 ((TmfExperimentLocation) location).getLocationInfo());
320
321 ITmfLocation[] locations = locationArray.getLocations();
322 long[] ranks = locationArray.getRanks();
323
324 // Create and populate the context's traces contexts
325 final TmfExperimentContext context = new TmfExperimentContext(fTraces.length);
326
327 // Position the traces
328 long rank = 0;
329 for (int i = 0; i < fTraces.length; i++) {
330 // Get the relevant trace attributes
331 final ITmfContext traceContext = fTraces[i].seekEvent(locations[i]);
332 context.setContext(i, traceContext);
333 traceContext.setRank(ranks[i]);
334 // update location after seek
335 locations[i] = traceContext.getLocation();
336 context.setEvent(i, fTraces[i].getNext(traceContext));
337 rank += ranks[i];
338 }
339
340 // Finalize context
341 context.setLocation(new TmfExperimentLocation(new TmfLocationArray(locations, ranks)));
342 context.setLastTrace(TmfExperimentContext.NO_TRACE);
343 context.setRank(rank);
344
345 return context;
346 }
347
348 // ------------------------------------------------------------------------
349 // ITmfTrace - SeekEvent operations (returning a trace context)
350 // ------------------------------------------------------------------------
351
352 @Override
353 public ITmfContext seekEvent(final double ratio) {
354 final ITmfContext context = seekEvent(Math.round(ratio * getNbEvents()));
355 return context;
356 }
357
358 /**
359 * @since 3.0
360 */
361 @Override
362 public double getLocationRatio(final ITmfLocation location) {
363 if (location instanceof TmfExperimentLocation) {
364 long rank = 0;
365 TmfLocationArray locationArray = ((TmfExperimentLocation) location).getLocationInfo();
366 for (int i = 0; i < locationArray.size(); i++) {
367 rank += locationArray.getRank(i);
368 }
369 return (double) rank / getNbEvents();
370 }
371 return 0.0;
372 }
373
374 /**
375 * @since 3.0
376 */
377 @Override
378 public ITmfLocation getCurrentLocation() {
379 // never used
380 return null;
381 }
382
383 // ------------------------------------------------------------------------
384 // ITmfTrace trace positioning
385 // ------------------------------------------------------------------------
386
387 @Override
388 public synchronized ITmfEvent parseEvent(final ITmfContext context) {
389 final ITmfContext tmpContext = seekEvent(context.getLocation());
390 final ITmfEvent event = getNext(tmpContext);
391 return event;
392 }
393
394 @Override
395 public synchronized ITmfEvent getNext(ITmfContext context) {
396
397 // Validate the context
398 if (!(context instanceof TmfExperimentContext)) {
399 return null; // Throw an exception?
400 }
401
402 // Make sure that we have something to read from
403 if (fTraces == null) {
404 return null;
405 }
406
407 TmfExperimentContext expContext = (TmfExperimentContext) context;
408
409 // If an event was consumed previously, first get the next one from that
410 // trace
411 final int lastTrace = expContext.getLastTrace();
412 if (lastTrace != TmfExperimentContext.NO_TRACE) {
413 final ITmfContext traceContext = expContext.getContext(lastTrace);
414 expContext.setEvent(lastTrace, fTraces[lastTrace].getNext(traceContext));
415 expContext.setLastTrace(TmfExperimentContext.NO_TRACE);
416 }
417
418 // Scan the candidate events and identify the "next" trace to read from
419 int trace = TmfExperimentContext.NO_TRACE;
420 ITmfTimestamp timestamp = TmfTimestamp.BIG_CRUNCH;
421 for (int i = 0; i < fTraces.length; i++) {
422 final ITmfEvent event = expContext.getEvent(i);
423 if (event != null && event.getTimestamp() != null) {
424 final ITmfTimestamp otherTS = event.getTimestamp();
425 if (otherTS.compareTo(timestamp) < 0) {
426 trace = i;
427 timestamp = otherTS;
428 }
429 }
430 }
431
432 ITmfEvent event = null;
433 if (trace != TmfExperimentContext.NO_TRACE) {
434 event = expContext.getEvent(trace);
435 if (event != null) {
436 updateAttributes(expContext, event.getTimestamp());
437 expContext.increaseRank();
438 expContext.setLastTrace(trace);
439 final ITmfContext traceContext = expContext.getContext(trace);
440 if (traceContext == null) {
441 throw new IllegalStateException();
442 }
443
444 // Update the experiment location
445 TmfLocationArray locationArray = new TmfLocationArray(
446 ((TmfExperimentLocation) expContext.getLocation()).getLocationInfo(),
447 trace, traceContext.getLocation(), traceContext.getRank());
448 expContext.setLocation(new TmfExperimentLocation(locationArray));
449
450 processEvent(event);
451 }
452 }
453
454 return event;
455 }
456
457 /**
458 * @since 2.0
459 */
460 @Override
461 public ITmfTimestamp getInitialRangeOffset() {
462 if ((fTraces == null) || (fTraces.length == 0)) {
463 return super.getInitialRangeOffset();
464 }
465
466 ITmfTimestamp initTs = TmfTimestamp.BIG_CRUNCH;
467 for (int i = 0; i < fTraces.length; i++) {
468 ITmfTimestamp ts = fTraces[i].getInitialRangeOffset();
469 if (ts.compareTo(initTs) < 0) {
470 initTs = ts;
471 }
472 }
473 return initTs;
474 }
475
476 /**
477 * Get the path to the folder in the supplementary file where
478 * synchronization-related data can be kept so they are not deleted when the
479 * experiment is synchronized. Analysis involved in synchronization can put
480 * their supplementary files in there so they are preserved after
481 * synchronization.
482 *
483 * If the directory does not exist, it will be created. A return value of
484 * <code>null</code> means either the trace resource does not exist or
485 * supplementary resources cannot be kept.
486 *
487 * @param absolute
488 * If <code>true</code>, it returns the absolute path in the file
489 * system, including the supplementary file path. Otherwise, it
490 * returns only the directory name.
491 * @return The path to the folder where synchronization-related
492 * supplementary files can be kept or <code>null</code> if not
493 * available.
494 * @since 3.2
495 */
496 public String getSynchronizationFolder(boolean absolute) {
497 /* Set up the path to the synchronization file we'll use */
498 IResource resource = this.getResource();
499 String syncDirectory = null;
500
501 try {
502 /* get the directory where the file will be stored. */
503 if (resource != null) {
504 String fullDirectory = resource.getPersistentProperty(TmfCommonConstants.TRACE_SUPPLEMENTARY_FOLDER);
505 /* Create the synchronization data directory if not present */
506 if (fullDirectory != null) {
507 fullDirectory = fullDirectory + File.separator + SYNCHRONIZATION_DIRECTORY;
508 File syncDir = new File(fullDirectory);
509 syncDir.mkdirs();
510 }
511 if (absolute) {
512 syncDirectory = fullDirectory;
513 } else {
514 syncDirectory = SYNCHRONIZATION_DIRECTORY;
515 }
516 }
517 } catch (CoreException e) {
518 return null;
519 }
520
521 return syncDirectory;
522 }
523
524 /**
525 * Synchronizes the traces of an experiment. By default it only tries to
526 * read a synchronization file if it exists
527 *
528 * @return The synchronization object
529 * @since 3.0
530 */
531 public SynchronizationAlgorithm synchronizeTraces() {
532 return synchronizeTraces(false);
533 }
534
535 /**
536 * Synchronizes the traces of an experiment.
537 *
538 * @param doSync
539 * Whether to actually synchronize or just try opening a sync
540 * file
541 * @return The synchronization object
542 * @since 3.0
543 */
544 public SynchronizationAlgorithm synchronizeTraces(boolean doSync) {
545 fSyncLock.lock();
546
547 try {
548 String syncDirectory = getSynchronizationFolder(true);
549
550 final File syncFile = (syncDirectory != null) ? new File(syncDirectory + File.separator + SYNCHRONIZATION_FILE_NAME) : null;
551
552 final SynchronizationAlgorithm syncAlgo = SynchronizationManager.synchronizeTraces(syncFile, Collections.<ITmfTrace> singleton(this), doSync);
553
554 final TmfTraceSynchronizedSignal signal = new TmfTraceSynchronizedSignal(this, syncAlgo);
555
556 /* Broadcast in separate thread to prevent deadlock */
557 new Thread() {
558 @Override
559 public void run() {
560 broadcast(signal);
561 }
562 }.start();
563
564 return syncAlgo;
565 } finally {
566 fSyncLock.unlock();
567 }
568 }
569
570 @Override
571 @SuppressWarnings("nls")
572 public synchronized String toString() {
573 return "[TmfExperiment (" + getName() + ")]";
574 }
575
576 // ------------------------------------------------------------------------
577 // Streaming support
578 // ------------------------------------------------------------------------
579
580 private synchronized void initializeStreamingMonitor() {
581
582 if (fInitialized) {
583 return;
584 }
585 fInitialized = true;
586
587 if (getStreamingInterval() == 0) {
588 final ITmfContext context = seekEvent(0);
589 final ITmfEvent event = getNext(context);
590 context.dispose();
591 if (event == null) {
592 return;
593 }
594 final TmfTimeRange timeRange = new TmfTimeRange(event.getTimestamp(), TmfTimestamp.BIG_CRUNCH);
595 final TmfTraceRangeUpdatedSignal signal = new TmfTraceRangeUpdatedSignal(this, this, timeRange);
596
597 // Broadcast in separate thread to prevent deadlock
598 new Thread() {
599 @Override
600 public void run() {
601 broadcast(signal);
602 }
603 }.start();
604 return;
605 }
606
607 final Thread thread = new Thread("Streaming Monitor for experiment " + getName()) { //$NON-NLS-1$
608 private ITmfTimestamp safeTimestamp = null;
609 private ITmfTimestamp lastSafeTimestamp = null;
610 private TmfTimeRange timeRange = null;
611
612 @Override
613 public void run() {
614 while (!executorIsShutdown()) {
615 if (!getIndexer().isIndexing()) {
616 ITmfTimestamp startTimestamp = TmfTimestamp.BIG_CRUNCH;
617 ITmfTimestamp endTimestamp = TmfTimestamp.BIG_BANG;
618 for (final ITmfTrace trace : fTraces) {
619 if (trace.getStartTime().compareTo(startTimestamp) < 0) {
620 startTimestamp = trace.getStartTime();
621 }
622 if (trace.getStreamingInterval() != 0 && trace.getEndTime().compareTo(endTimestamp) > 0) {
623 endTimestamp = trace.getEndTime();
624 }
625 }
626 if (safeTimestamp != null && (lastSafeTimestamp == null || safeTimestamp.compareTo(lastSafeTimestamp) > 0)) {
627 timeRange = new TmfTimeRange(startTimestamp, safeTimestamp);
628 lastSafeTimestamp = safeTimestamp;
629 } else {
630 timeRange = null;
631 }
632 safeTimestamp = endTimestamp;
633 if (timeRange != null) {
634 final TmfTraceRangeUpdatedSignal signal =
635 new TmfTraceRangeUpdatedSignal(TmfExperiment.this, TmfExperiment.this, timeRange);
636 broadcast(signal);
637 }
638 }
639 try {
640 Thread.sleep(getStreamingInterval());
641 } catch (final InterruptedException e) {
642 e.printStackTrace();
643 }
644 }
645 }
646 };
647 thread.start();
648 }
649
650 @Override
651 public long getStreamingInterval() {
652 long interval = 0;
653 for (final ITmfTrace trace : fTraces) {
654 interval = Math.max(interval, trace.getStreamingInterval());
655 }
656 return interval;
657 }
658
659 // ------------------------------------------------------------------------
660 // Signal handlers
661 // ------------------------------------------------------------------------
662
663 @Override
664 @TmfSignalHandler
665 public void traceOpened(TmfTraceOpenedSignal signal) {
666 if (signal.getTrace() == this) {
667 initializeStreamingMonitor();
668
669 /* Initialize the analysis */
670 MultiStatus status = new MultiStatus(Activator.PLUGIN_ID, IStatus.OK, null, null);
671 status.add(executeAnalysis());
672 if (!status.isOK()) {
673 Activator.log(status);
674 }
675 TmfTraceManager.refreshSupplementaryFiles(this);
676 }
677 }
678
679 /**
680 * @since 3.0
681 */
682 @Override
683 public synchronized int getCheckpointSize() {
684 int totalCheckpointSize = 0;
685 try {
686 if (fTraces != null) {
687 for (final ITmfTrace trace : fTraces) {
688 if (!(trace instanceof ITmfPersistentlyIndexable)) {
689 return 0;
690 }
691
692 ITmfPersistentlyIndexable persistableIndexTrace = (ITmfPersistentlyIndexable) trace;
693 int currentTraceCheckpointSize = persistableIndexTrace.getCheckpointSize();
694 if (currentTraceCheckpointSize <= 0) {
695 return 0;
696 }
697 totalCheckpointSize += currentTraceCheckpointSize;
698 // each entry in the TmfLocationArray has a rank in addition
699 // of the location
700 totalCheckpointSize += 8;
701 }
702 }
703 } catch (UnsupportedOperationException e) {
704 return 0;
705 }
706
707 return totalCheckpointSize;
708 }
709
710 /**
711 * @since 3.0
712 */
713 @Override
714 public ITmfLocation restoreLocation(ByteBuffer bufferIn) {
715 ITmfLocation[] locations = new ITmfLocation[fTraces.length];
716 long[] ranks = new long[fTraces.length];
717 for (int i = 0; i < fTraces.length; ++i) {
718 final ITmfTrace trace = fTraces[i];
719 locations[i] = ((ITmfPersistentlyIndexable) trace).restoreLocation(bufferIn);
720 ranks[i] = bufferIn.getLong();
721 }
722 TmfLocationArray arr = new TmfLocationArray(locations, ranks);
723 TmfExperimentLocation l = new TmfExperimentLocation(arr);
724 return l;
725 }
726
727 }
This page took 0.065227 seconds and 6 git commands to generate.