From 78072af745bb9f33a47c3df7e6f530efcd06e039 Mon Sep 17 00:00:00 2001 From: Marc-Andre Laperle Date: Wed, 27 Aug 2014 23:15:58 -0400 Subject: ctf: Provide a utility for "safe" mapping of a ByteBuffer This works around a bug on Windows which prevents deleting a file after it was mapped. See http://bugs.java.com/view_bug.do?bug_id=4715154 Running TraceSeekBenchmark, I noticed a 10% decreased in performance (3.8s vs 3.4s) on Windows. On Linux, the difference is negligible (2.41s vs 2.40). Change-Id: Ie590709df4149708a37257ee3bc3d3d017f31c21 Signed-off-by: Marc-Andre Laperle Reviewed-on: https://git.eclipse.org/r/32448 Tested-by: Hudson CI --- .../linuxtools/ctf/core/trace/CTFStreamInput.java | 5 +- .../ctf/core/trace/CTFStreamInputPacketReader.java | 4 +- .../linuxtools/ctf/core/trace/CTFTrace.java | 7 +-- .../internal/ctf/core/SafeMappedByteBuffer.java | 60 ++++++++++++++++++++++ 4 files changed, 69 insertions(+), 7 deletions(-) create mode 100644 lttng/org.eclipse.linuxtools.ctf.core/src/org/eclipse/linuxtools/internal/ctf/core/SafeMappedByteBuffer.java (limited to 'lttng/org.eclipse.linuxtools.ctf.core/src') diff --git a/lttng/org.eclipse.linuxtools.ctf.core/src/org/eclipse/linuxtools/ctf/core/trace/CTFStreamInput.java b/lttng/org.eclipse.linuxtools.ctf.core/src/org/eclipse/linuxtools/ctf/core/trace/CTFStreamInput.java index 157b1049c0..db8c6371c6 100644 --- a/lttng/org.eclipse.linuxtools.ctf.core/src/org/eclipse/linuxtools/ctf/core/trace/CTFStreamInput.java +++ b/lttng/org.eclipse.linuxtools.ctf.core/src/org/eclipse/linuxtools/ctf/core/trace/CTFStreamInput.java @@ -14,7 +14,7 @@ package org.eclipse.linuxtools.ctf.core.trace; import java.io.File; import java.io.IOException; -import java.nio.MappedByteBuffer; +import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.nio.channels.FileChannel.MapMode; import java.nio.file.StandardOpenOption; @@ -32,6 +32,7 @@ import org.eclipse.linuxtools.ctf.core.event.types.IntegerDefinition; import org.eclipse.linuxtools.ctf.core.event.types.StringDefinition; import org.eclipse.linuxtools.ctf.core.event.types.StructDeclaration; import org.eclipse.linuxtools.ctf.core.event.types.StructDefinition; +import org.eclipse.linuxtools.internal.ctf.core.SafeMappedByteBuffer; import org.eclipse.linuxtools.internal.ctf.core.event.types.ArrayDefinition; import org.eclipse.linuxtools.internal.ctf.core.trace.StreamInputPacketIndex; import org.eclipse.linuxtools.internal.ctf.core.trace.StreamInputPacketIndexEntry; @@ -289,7 +290,7 @@ public class CTFStreamInput implements IDefinitionScope, AutoCloseable { * Map the packet. */ try (FileChannel fc = FileChannel.open(fFile.toPath(), StandardOpenOption.READ)) { - MappedByteBuffer map = fc.map(MapMode.READ_ONLY, packetOffsetBytes, mapSize); + ByteBuffer map = SafeMappedByteBuffer.map(fc, MapMode.READ_ONLY, packetOffsetBytes, mapSize); if (map == null) { throw new CTFReaderException("Failed to allocate mapped byte buffer"); //$NON-NLS-1$ } diff --git a/lttng/org.eclipse.linuxtools.ctf.core/src/org/eclipse/linuxtools/ctf/core/trace/CTFStreamInputPacketReader.java b/lttng/org.eclipse.linuxtools.ctf.core/src/org/eclipse/linuxtools/ctf/core/trace/CTFStreamInputPacketReader.java index 9509a9929d..29ef23f9ff 100644 --- a/lttng/org.eclipse.linuxtools.ctf.core/src/org/eclipse/linuxtools/ctf/core/trace/CTFStreamInputPacketReader.java +++ b/lttng/org.eclipse.linuxtools.ctf.core/src/org/eclipse/linuxtools/ctf/core/trace/CTFStreamInputPacketReader.java @@ -13,7 +13,6 @@ package org.eclipse.linuxtools.ctf.core.trace; import java.io.IOException; import java.nio.ByteBuffer; -import java.nio.MappedByteBuffer; import java.nio.channels.FileChannel.MapMode; import org.eclipse.jdt.annotation.NonNull; @@ -35,6 +34,7 @@ import org.eclipse.linuxtools.ctf.core.event.types.SimpleDatatypeDefinition; import org.eclipse.linuxtools.ctf.core.event.types.StructDeclaration; import org.eclipse.linuxtools.ctf.core.event.types.StructDefinition; import org.eclipse.linuxtools.ctf.core.event.types.VariantDefinition; +import org.eclipse.linuxtools.internal.ctf.core.SafeMappedByteBuffer; import org.eclipse.linuxtools.internal.ctf.core.event.EventDeclaration; import org.eclipse.linuxtools.internal.ctf.core.event.types.composite.EventHeaderDefinition; import org.eclipse.linuxtools.internal.ctf.core.trace.StreamInputPacketIndexEntry; @@ -221,7 +221,7 @@ public class CTFStreamInputPacketReader implements IDefinitionScope, AutoCloseab @NonNull private ByteBuffer getByteBufferAt(long position, long size) throws CTFReaderException, IOException { - MappedByteBuffer map = fStreamInputReader.getFc().map(MapMode.READ_ONLY, position, size); + ByteBuffer map = SafeMappedByteBuffer.map(fStreamInputReader.getFc(), MapMode.READ_ONLY, position, size); if (map == null) { throw new CTFReaderException("Failed to allocate mapped byte buffer"); //$NON-NLS-1$ } diff --git a/lttng/org.eclipse.linuxtools.ctf.core/src/org/eclipse/linuxtools/ctf/core/trace/CTFTrace.java b/lttng/org.eclipse.linuxtools.ctf.core/src/org/eclipse/linuxtools/ctf/core/trace/CTFTrace.java index 0c2ee5a5cb..3414110a2c 100644 --- a/lttng/org.eclipse.linuxtools.ctf.core/src/org/eclipse/linuxtools/ctf/core/trace/CTFTrace.java +++ b/lttng/org.eclipse.linuxtools.ctf.core/src/org/eclipse/linuxtools/ctf/core/trace/CTFTrace.java @@ -19,8 +19,8 @@ import java.io.FileFilter; import java.io.FileInputStream; import java.io.IOException; import java.io.Serializable; +import java.nio.ByteBuffer; import java.nio.ByteOrder; -import java.nio.MappedByteBuffer; import java.nio.channels.FileChannel; import java.nio.channels.FileChannel.MapMode; import java.util.Arrays; @@ -44,6 +44,7 @@ import org.eclipse.linuxtools.ctf.core.event.types.IDefinition; import org.eclipse.linuxtools.ctf.core.event.types.IntegerDefinition; import org.eclipse.linuxtools.ctf.core.event.types.StructDeclaration; import org.eclipse.linuxtools.ctf.core.event.types.StructDefinition; +import org.eclipse.linuxtools.internal.ctf.core.SafeMappedByteBuffer; import org.eclipse.linuxtools.internal.ctf.core.event.CTFCallsiteComparator; import org.eclipse.linuxtools.internal.ctf.core.event.metadata.exceptions.ParseException; import org.eclipse.linuxtools.internal.ctf.core.event.types.ArrayDefinition; @@ -507,7 +508,7 @@ public class CTFTrace implements IDefinitionScope, AutoCloseable { * if there is a file error */ private CTFStream openStreamInput(File streamFile) throws CTFReaderException { - MappedByteBuffer byteBuffer; + ByteBuffer byteBuffer; BitBuffer streamBitBuffer; CTFStream stream; @@ -519,7 +520,7 @@ public class CTFTrace implements IDefinitionScope, AutoCloseable { try (FileInputStream fis = new FileInputStream(streamFile); FileChannel fc = fis.getChannel()) { /* Map one memory page of 4 kiB */ - byteBuffer = fc.map(MapMode.READ_ONLY, 0, (int) Math.min(fc.size(), 4096L)); + byteBuffer = SafeMappedByteBuffer.map(fc, MapMode.READ_ONLY, 0, (int) Math.min(fc.size(), 4096L)); if (byteBuffer == null) { throw new IllegalStateException("Failed to allocate memory"); //$NON-NLS-1$ } diff --git a/lttng/org.eclipse.linuxtools.ctf.core/src/org/eclipse/linuxtools/internal/ctf/core/SafeMappedByteBuffer.java b/lttng/org.eclipse.linuxtools.ctf.core/src/org/eclipse/linuxtools/internal/ctf/core/SafeMappedByteBuffer.java new file mode 100644 index 0000000000..8b06b2733b --- /dev/null +++ b/lttng/org.eclipse.linuxtools.ctf.core/src/org/eclipse/linuxtools/internal/ctf/core/SafeMappedByteBuffer.java @@ -0,0 +1,60 @@ +/******************************************************************************* + * Copyright (c) 2014 Ericsson + * + * All rights reserved. This program and the accompanying materials are made + * available under the terms of the Eclipse Public License v1.0 which + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Marc-Andre Laperle - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.linuxtools.internal.ctf.core; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.channels.FileChannel; + +import org.eclipse.core.runtime.Platform; + +/** + * A common utility for mapping a ByteBuffer safely to work around a bug on + * Windows which prevents deleting a file after it was mapped. On Windows, the + * ByteBuffer will be allocated and the file will be read instead of being + * mapped. + * + * http://bugs.java.com/view_bug.do?bug_id=4715154 + */ +public class SafeMappedByteBuffer { + + private static final boolean IS_WIN32 = Platform.OS_WIN32.equals(Platform.getOS()); + + /** + * Maps a region of this channel's file directly into memory. On Windows, + * this will allocate a new ByteBuffer and read the file. + * + * @param fc + * the file channel + * @param mode + * the mapping mode + * @param position + * the position within the file + * @param size + * the size of the region to be mapped (or read) + * @return the mapped ByteBuffer + * @throws IOException + * on FileChannel operations failures + */ + public static ByteBuffer map(FileChannel fc, FileChannel.MapMode mode, long position, long size) throws IOException { + ByteBuffer byteBuffer; + if (IS_WIN32) { + byteBuffer = ByteBuffer.allocate((int) size); + fc.read(byteBuffer, position); + } else { + byteBuffer = fc.map(mode, position, size); + } + + return byteBuffer; + } +} -- cgit v1.2.3