Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[GR-36526] Handle relative path issue for tools. #8241

Merged
merged 5 commits into from
Jan 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@
*
* It is assumed that a field of type c may hold a reference to any subtype of c. It is also assumed
* that any subtype of c is instantiated.
*
* This annotation is only necessary during the image build. It prevents the static analysis from
* wrongly constant-folding a value that is initialized late during the image build and therefore
* not available during analysis.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,13 @@

import com.oracle.svm.core.BuildPhaseProvider.AfterAnalysis;

/** For fields with this annotation no static analysis is done. */
/**
* For fields with this annotation no static analysis is done.
*
* This annotation is only necessary during the image build. It prevents the static analysis from
* wrongly constant-folding a value that is initialized late during the image build and therefore
* not available during analysis.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@Platforms(Platform.HOSTED_ONLY.class)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,15 @@ public Output apply(String s) {
private CoverageTracker tracker;
private Boolean enabled;

/*
* Guest languages could change the working directory of the current process, The JVM assumes
* that the working directory does not change. When this assumption is broken relative file
* paths no longer work correctly. For this reason we save the absolute path to the output file
* at the very start so that we avoid issues of broken relative paths See GR-36526 for more
* context.
*/
private String absoluteOutputPath;

public static CoverageTracker getTracker(Engine engine) {
Instrument instrument = engine.getInstruments().get(ID);
if (instrument == null) {
Expand All @@ -123,11 +132,10 @@ public static void setFactory(Function<Env, CoverageTracker> factory) {
CoverageInstrument.factory = factory;
}

protected static PrintStream chooseOutputStream(TruffleInstrument.Env env, OptionKey<String> option) {
protected static PrintStream chooseOutputStream(Env env, String absoluteOutputPath) {
try {
if (option.hasBeenSet(env.getOptions())) {
final String outputPath = option.getValue(env.getOptions());
final File file = new File(outputPath);
if (absoluteOutputPath != null) {
final File file = new File(absoluteOutputPath);
new PrintStream(env.out()).println("Printing output to " + file.getAbsolutePath());
return new PrintStream(new FileOutputStream(file));
} else {
Expand Down Expand Up @@ -171,6 +179,9 @@ protected void onCreate(Env env) {
enabled = ENABLED.getValue(options);
if (enabled) {
tracker.start(new CoverageTracker.Config(getSourceSectionFilter(options), Count.getValue(options)));
if (CoverageInstrument.OUTPUT_FILE.hasBeenSet(env.getOptions())) {
absoluteOutputPath = new File(CoverageInstrument.OUTPUT_FILE.getValue(env.getOptions())).getAbsolutePath();
}
}
}

Expand All @@ -180,7 +191,7 @@ protected void onFinalize(Env env) {
SourceCoverage[] coverage = tracker.getCoverage();
final OptionValues options = env.getOptions();
final boolean strictLines = StrictLines.getValue(options);
PrintStream out = chooseOutputStream(env, OUTPUT_FILE);
PrintStream out = chooseOutputStream(env, absoluteOutputPath);
switch (OUTPUT.getValue(options)) {
case HISTOGRAM:
new CoverageCLI(out, coverage, strictLines).printHistogramOutput();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,15 +45,15 @@
import org.graalvm.options.OptionStability;
import org.graalvm.options.OptionType;
import org.graalvm.options.OptionValues;
import org.graalvm.shadowed.org.json.JSONArray;
import org.graalvm.shadowed.org.json.JSONObject;

import com.oracle.truffle.api.Option;
import com.oracle.truffle.api.TruffleContext;
import com.oracle.truffle.api.instrumentation.TruffleInstrument;
import com.oracle.truffle.tools.profiler.CPUSampler;
import com.oracle.truffle.tools.profiler.CPUSamplerData;
import com.oracle.truffle.tools.profiler.ProfilerNode;
import org.graalvm.shadowed.org.json.JSONArray;
import org.graalvm.shadowed.org.json.JSONObject;

@Option.Group(CPUSamplerInstrument.ID)
class CPUSamplerCLI extends ProfilerCLI {
Expand Down Expand Up @@ -221,8 +221,8 @@ public int[] apply(String s) {
@Option(name = "SampleContextInitialization", help = "Enables sampling of code executed during context initialization", category = OptionCategory.EXPERT, stability = OptionStability.STABLE) //
static final OptionKey<Boolean> SAMPLE_CONTEXT_INITIALIZATION = new OptionKey<>(false);

static void handleOutput(TruffleInstrument.Env env, CPUSampler sampler) {
PrintStream out = chooseOutputStream(env);
static void handleOutput(TruffleInstrument.Env env, CPUSampler sampler, String absoluteOutputPath) {
PrintStream out = chooseOutputStream(env, absoluteOutputPath);
Map<TruffleContext, CPUSamplerData> data = sampler.getData();
OptionValues options = env.getOptions();
switch (chooseOutput(options)) {
Expand All @@ -242,12 +242,10 @@ static void handleOutput(TruffleInstrument.Env env, CPUSampler sampler) {
}
}

private static PrintStream chooseOutputStream(TruffleInstrument.Env env) {
OptionValues options = env.getOptions();
final String outputPath = getOutputPath(env, options);
if (outputPath != null) {
private static PrintStream chooseOutputStream(TruffleInstrument.Env env, String absoluteOutputPath) {
if (absoluteOutputPath != null) {
try {
final File file = new File(outputPath);
final File file = new File(absoluteOutputPath);
new PrintStream(env.out()).println("Printing output to " + file.getAbsolutePath());
return new PrintStream(new FileOutputStream(file));
} catch (FileNotFoundException e) {
Expand All @@ -257,9 +255,9 @@ private static PrintStream chooseOutputStream(TruffleInstrument.Env env) {
return new PrintStream(env.out());
}

private static String getOutputPath(TruffleInstrument.Env env, OptionValues options) {
static String getOutputPath(OptionValues options) {
if (OUTPUT_FILE.hasBeenSet(options)) {
return OUTPUT_FILE.getValue(env.getOptions());
return OUTPUT_FILE.getValue(options);
}
if (ENABLED.getValue(options).output == Output.FLAMEGRAPH) {
return DEFAULT_FLAMEGRAPH_FILE;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import static com.oracle.truffle.tools.profiler.impl.CPUSamplerCLI.GATHER_HIT_TIMES;
import static com.oracle.truffle.tools.profiler.impl.CPUSamplerCLI.SAMPLE_CONTEXT_INITIALIZATION;

import java.io.File;
import java.lang.reflect.Method;

import org.graalvm.options.OptionDescriptors;
Expand Down Expand Up @@ -61,9 +62,18 @@ public CPUSamplerInstrument() {
* @since 0.30
*/
public static final String ID = "cpusampler";
private static final ProfilerToolFactory<CPUSampler> factory = getDefaultFactory();
static final String VERSION = "0.5.0";
private CPUSampler sampler;
private static final ProfilerToolFactory<CPUSampler> factory = getDefaultFactory();

/*
* Guest languages could change the working directory of the current process, The JVM assumes
* that the working directory does not change. When this assumption is broken relative file
* paths no longer work correctly. For this reason we save the absolute path to the output file
* at the very start so that we avoid issues of broken relative paths See GR-36526 for more
* context.
*/
private String absoluteOutputPath;

@SuppressWarnings("unchecked")
private static ProfilerToolFactory<CPUSampler> getDefaultFactory() {
Expand Down Expand Up @@ -109,6 +119,8 @@ protected void onCreate(Env env) {
sampler.setGatherSelfHitTimes(options.get(GATHER_HIT_TIMES));
sampler.setSampleContextInitialization(options.get(SAMPLE_CONTEXT_INITIALIZATION));
sampler.setCollecting(true);
String outputPath = CPUSamplerCLI.getOutputPath(options);
absoluteOutputPath = (outputPath != null) ? new File(outputPath).getAbsolutePath() : null;
}
env.registerService(sampler);
}
Expand Down Expand Up @@ -142,7 +154,7 @@ protected void onFinalize(Env env) {
OptionValues options = env.getOptions();
CPUSamplerCLI.EnableOptionData enableOptionData = options.get(CPUSamplerCLI.ENABLED);
if (enableOptionData.enabled) {
CPUSamplerCLI.handleOutput(env, sampler);
CPUSamplerCLI.handleOutput(env, sampler, absoluteOutputPath);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@
*/
package com.oracle.truffle.tools.profiler.impl;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Collection;
Expand All @@ -36,12 +39,12 @@
import org.graalvm.options.OptionKey;
import org.graalvm.options.OptionStability;
import org.graalvm.options.OptionType;
import org.graalvm.shadowed.org.json.JSONArray;
import org.graalvm.shadowed.org.json.JSONObject;

import com.oracle.truffle.api.Option;
import com.oracle.truffle.api.instrumentation.TruffleInstrument;
import com.oracle.truffle.tools.profiler.CPUTracer;
import org.graalvm.shadowed.org.json.JSONArray;
import org.graalvm.shadowed.org.json.JSONObject;

@Option.Group(CPUTracerInstrument.ID)
class CPUTracerCLI extends ProfilerCLI {
Expand Down Expand Up @@ -101,8 +104,8 @@ public Output apply(String s) {
@Option(name = "OutputFile", help = "Save output to the given file. Output is printed to standard output stream by default.", usageSyntax = "<path>", category = OptionCategory.USER, stability = OptionStability.STABLE) //
static final OptionKey<String> OUTPUT_FILE = new OptionKey<>("");

public static void handleOutput(TruffleInstrument.Env env, CPUTracer tracer) {
PrintStream out = chooseOutputStream(env, OUTPUT_FILE);
public static void handleOutput(TruffleInstrument.Env env, CPUTracer tracer, String absoluteOutputPath) {
PrintStream out = chooseOutputStream(env, absoluteOutputPath);
switch (env.getOptions().get(OUTPUT)) {
case HISTOGRAM:
printTracerHistogram(out, tracer);
Expand All @@ -113,6 +116,19 @@ public static void handleOutput(TruffleInstrument.Env env, CPUTracer tracer) {
}
}

protected static PrintStream chooseOutputStream(TruffleInstrument.Env env, String absoluteOutputPath) {
try {
if (absoluteOutputPath != null) {
final File file = new File(absoluteOutputPath);
return new PrintStream(new FileOutputStream(file));
} else {
return new PrintStream(env.out());
}
} catch (FileNotFoundException e) {
throw handleFileNotFound();
}
}

private static void printTracerJson(PrintStream out, CPUTracer tracer) {
JSONObject output = new JSONObject();
output.put("tool", CPUTracerInstrument.ID);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
*/
package com.oracle.truffle.tools.profiler.impl;

import java.io.File;
import java.io.PrintStream;
import java.lang.reflect.Method;

Expand Down Expand Up @@ -58,11 +59,19 @@ public CPUTracerInstrument() {
* @since 0.30
*/
public static final String ID = "cputracer";
private static final ProfilerToolFactory<CPUTracer> factory = getDefaultFactory();

static final String VERSION = "0.3.0";
private boolean enabled;
private CPUTracer tracer;
private static final ProfilerToolFactory<CPUTracer> factory = getDefaultFactory();
/*
* Guest languages could change the working directory of the current process, The JVM assumes
* that the working directory does not change. When this assumption is broken relative file
* paths no longer work correctly. For this reason we save the absolute path to the output file
* at the very start so that we avoid issues of broken relative paths See GR-36526 for more
* context.
*/
String absoluteOutputPath;

@SuppressWarnings("unchecked")
private static ProfilerToolFactory<CPUTracer> getDefaultFactory() {
Expand Down Expand Up @@ -111,6 +120,10 @@ protected void onCreate(Env env) {
return;
}
tracer.setCollecting(true);
if (CPUTracerCLI.OUTPUT_FILE.hasBeenSet(env.getOptions())) {
final String outputPath = CPUTracerCLI.OUTPUT_FILE.getValue(env.getOptions());
absoluteOutputPath = new File(outputPath).getAbsolutePath();
}
}
env.registerService(tracer);
}
Expand Down Expand Up @@ -145,7 +158,7 @@ protected OptionDescriptors getOptionDescriptors() {
@Override
protected void onFinalize(Env env) {
if (enabled) {
CPUTracerCLI.handleOutput(env, tracer);
CPUTracerCLI.handleOutput(env, tracer, absoluteOutputPath);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,6 @@
package com.oracle.truffle.tools.profiler.impl;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
Expand All @@ -36,15 +33,13 @@
import java.util.function.Predicate;
import java.util.regex.Pattern;

import org.graalvm.options.OptionKey;
import org.graalvm.shadowed.org.json.JSONObject;

import com.oracle.truffle.api.exception.AbstractTruffleException;
import com.oracle.truffle.api.instrumentation.SourceSectionFilter;
import com.oracle.truffle.api.instrumentation.StandardTags;
import com.oracle.truffle.api.instrumentation.TruffleInstrument;
import com.oracle.truffle.api.source.Source;
import com.oracle.truffle.api.source.SourceSection;
import org.graalvm.shadowed.org.json.JSONObject;

abstract class ProfilerCLI {

Expand Down Expand Up @@ -237,20 +232,6 @@ public int hashCode() {
}
}

protected static PrintStream chooseOutputStream(TruffleInstrument.Env env, OptionKey<String> option) {
try {
if (option.hasBeenSet(env.getOptions())) {
final String outputPath = option.getValue(env.getOptions());
final File file = new File(outputPath);
return new PrintStream(new FileOutputStream(file));
} else {
return new PrintStream(env.out());
}
} catch (FileNotFoundException e) {
throw handleFileNotFound();
}
}

protected static AbstractTruffleException handleFileNotFound() {
return new AbstractTruffleException() {
static final long serialVersionUID = -1;
Expand Down