Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: jruby/jruby
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: d3606ab50611
Choose a base ref
...
head repository: jruby/jruby
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: a228b5ff6d76
Choose a head ref
  • 3 commits
  • 3 files changed
  • 1 contributor

Commits on Jul 17, 2015

  1. Copy the full SHA
    fc66c22 View commit details
  2. 3
    Copy the full SHA
    6dfa392 View commit details
  3. [Truffle] Add clock_gettime(CLOCK_THREAD_CPUTIME).

    * Only available on Linux for now.
    * Useful to check how much time one specific thread spends on CPU.
    eregon committed Jul 17, 2015
    Copy the full SHA
    a228b5f View commit details
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* Copyright (c) 2015 Oracle and/or its affiliates. All rights reserved. This
* code is released under a tri EPL/GPL/LGPL license. You can use it,
* redistribute it and/or modify it under the terms of the:
*
* Eclipse Public License version 1.0
* GNU General Public License version 2
* GNU Lesser General Public License version 2.1
*/
package org.jruby.truffle.nodes.cast;

import org.jruby.truffle.nodes.RubyNode;
import org.jruby.truffle.runtime.NotProvided;
import org.jruby.truffle.runtime.RubyContext;

import com.oracle.truffle.api.dsl.NodeChild;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.source.SourceSection;

/**
* Return the given default value if the argument is not provided.
*/
@NodeChild(value = "value", type = RubyNode.class)
public abstract class DefaultValueNode extends RubyNode {

private final Object defaultValue;

public DefaultValueNode(RubyContext context, SourceSection sourceSection, Object defaultValue) {
super(context, sourceSection);
this.defaultValue = defaultValue;
}

@Specialization
public Object doDefault(NotProvided value) {
return defaultValue;
}

@Specialization(guards = "wasProvided(value)")
public Object doProvided(Object value) {
return value;
}

}
Original file line number Diff line number Diff line change
@@ -9,60 +9,103 @@
*/
package org.jruby.truffle.nodes.core;

import jnr.ffi.LibraryLoader;
import jnr.ffi.Struct;

import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.dsl.CreateCast;
import com.oracle.truffle.api.dsl.NodeChild;
import com.oracle.truffle.api.dsl.NodeChildren;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.source.SourceSection;

import org.jruby.truffle.nodes.RubyGuards;
import org.jruby.truffle.runtime.NotProvided;
import org.jruby.truffle.nodes.RubyNode;
import org.jruby.truffle.nodes.cast.DefaultValueNodeGen;
import org.jruby.truffle.runtime.RubyContext;
import org.jruby.truffle.runtime.control.RaiseException;
import org.jruby.truffle.runtime.core.RubyBasicObject;
import org.jruby.truffle.runtime.signal.SignalOperations;

import sun.misc.Signal;

@SuppressWarnings("restriction")
@CoreClass(name = "Process")
public abstract class ProcessNodes {

public final static class TimeSpec extends Struct {
public final time_t tv_sec = new time_t();
public final SignedLong tv_nsec = new SignedLong();

public TimeSpec(jnr.ffi.Runtime runtime) {
super(runtime);
}

public long getTVsec() {
return tv_sec.get();
}

public long getTVnsec() {
return tv_nsec.get();
}
}

public interface LibCClockGetTime {
int clock_gettime(int clock_id, TimeSpec timeSpec);
}

public static final int CLOCK_MONOTONIC = 1;
public static final int CLOCK_REALTIME = 2;
public static final int CLOCK_THREAD_CPUTIME_ID = 3; // Linux only

@CoreMethod(names = "clock_gettime", onSingleton = true, required = 1, optional = 1)
public abstract static class ClockGetTimeNode extends CoreMethodArrayArgumentsNode {
@NodeChildren({
@NodeChild(type = RubyNode.class, value = "clock_id"),
@NodeChild(type = RubyNode.class, value = "unit")
})
public abstract static class ClockGetTimeNode extends CoreMethodNode {

private final RubyBasicObject floatSecondSymbol;
private final RubyBasicObject nanosecondSymbol;
private final RubyBasicObject floatSecondSymbol = getContext().getSymbol("float_second");
private final RubyBasicObject nanosecondSymbol = getContext().getSymbol("nanosecond");

public ClockGetTimeNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
floatSecondSymbol = context.getSymbol("float_second");
nanosecondSymbol = context.getSymbol("nanosecond");
}

@Specialization(guards = "isMonotonic(clock_id)")
Object clock_gettime_monotonic(int clock_id, NotProvided unit) {
return clock_gettime_monotonic(CLOCK_MONOTONIC, floatSecondSymbol);
}

@Specialization(guards = "isRealtime(clock_id)")
Object clock_gettime_realtime(int clock_id, NotProvided unit) {
return clock_gettime_realtime(CLOCK_REALTIME, floatSecondSymbol);
@CreateCast("unit")
public RubyNode coerceUnit(RubyNode unit) {
return DefaultValueNodeGen.create(getContext(), getSourceSection(), floatSecondSymbol, unit);
}

@Specialization(guards = {"isMonotonic(clock_id)", "isRubySymbol(unit)"})
Object clock_gettime_monotonic(int clock_id, RubyBasicObject unit) {
@Specialization(guards = { "isMonotonic(clock_id)", "isRubySymbol(unit)" })
protected Object clock_gettime_monotonic(int clock_id, RubyBasicObject unit) {
long time = System.nanoTime();
return timeToUnit(time, unit);
}

@Specialization(guards = {"isRealtime(clock_id)", "isRubySymbol(unit)"})
Object clock_gettime_realtime(int clock_id, RubyBasicObject unit) {
long time = System.currentTimeMillis() * 1000000;
@Specialization(guards = { "isRealtime(clock_id)", "isRubySymbol(unit)" })
protected Object clock_gettime_realtime(int clock_id, RubyBasicObject unit) {
long time = System.currentTimeMillis() * 1_000_000;
return timeToUnit(time, unit);
}

Object timeToUnit(long time, RubyBasicObject unit) {
assert RubyGuards.isRubySymbol(unit);
@Specialization(guards = { "isThreadCPUTime(clock_id)", "isRubySymbol(unit)" })
protected Object clock_gettime_thread_cputime(int clock_id, RubyBasicObject unit,
@Cached("getLibCClockGetTime()") LibCClockGetTime libCClockGetTime) {
TimeSpec timeSpec = new TimeSpec(jnr.ffi.Runtime.getRuntime(libCClockGetTime));
int r = libCClockGetTime.clock_gettime(CLOCK_THREAD_CPUTIME_ID, timeSpec);
if (r != 0) {
CompilerDirectives.transferToInterpreter();
throw new RaiseException(getContext().getCoreLibrary().systemCallError("clock_gettime failed: " + r, this));
}
long nanos = timeSpec.getTVsec() * 1_000_000_000 + timeSpec.getTVnsec();
return timeToUnit(nanos, unit);
}

private Object timeToUnit(long time, RubyBasicObject unit) {
assert RubyGuards.isRubySymbol(unit);
if (unit == nanosecondSymbol) {
return time;
} else if (unit == floatSecondSymbol) {
@@ -72,14 +115,22 @@ Object timeToUnit(long time, RubyBasicObject unit) {
}
}

static boolean isMonotonic(int clock_id) {
protected static boolean isMonotonic(int clock_id) {
return clock_id == CLOCK_MONOTONIC;
}

static boolean isRealtime(int clock_id) {
protected static boolean isRealtime(int clock_id) {
return clock_id == CLOCK_REALTIME;
}

protected static boolean isThreadCPUTime(int clock_id) {
return clock_id == CLOCK_THREAD_CPUTIME_ID;
}

protected static LibCClockGetTime getLibCClockGetTime() {
return LibraryLoader.create(LibCClockGetTime.class).library("c").load();
}

}

@CoreMethod(names = "kill", onSingleton = true, required = 2)
Original file line number Diff line number Diff line change
@@ -16,11 +16,14 @@
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.source.Source;
import com.oracle.truffle.api.source.SourceSection;

import jnr.constants.platform.Errno;

import org.jcodings.Encoding;
import org.jcodings.EncodingDB;
import org.jcodings.transcode.EConvFlags;
import org.jruby.ext.ffi.Platform;
import org.jruby.ext.ffi.Platform.OS_TYPE;
import org.jruby.runtime.Constants;
import org.jruby.runtime.encoding.EncodingService;
import org.jruby.truffle.nodes.RubyGuards;
@@ -512,6 +515,10 @@ private void initializeConstants() {
processModule.setConstant(node, "CLOCK_MONOTONIC", ProcessNodes.CLOCK_MONOTONIC);
processModule.setConstant(node, "CLOCK_REALTIME", ProcessNodes.CLOCK_REALTIME);

if (Platform.getPlatform().getOS() == OS_TYPE.LINUX) {
processModule.setConstant(node, "CLOCK_THREAD_CPUTIME_ID", ProcessNodes.CLOCK_THREAD_CPUTIME_ID);
}

encodingConverterClass.setConstant(node, "INVALID_MASK", EConvFlags.INVALID_MASK);
encodingConverterClass.setConstant(node, "INVALID_REPLACE", EConvFlags.INVALID_REPLACE);
encodingConverterClass.setConstant(node, "UNDEF_MASK", EConvFlags.UNDEF_MASK);