0

I see in JMH a popular problem with ConstantFold, but what if I have inverse problem. I need the static final field as parameter. For example, it's can be some constant variable for some algorithm. But in java-doc I see: {@link Param} fields should be non-final fields.. I made test for the static parameter (with @Param annotation) and for the static final, and I see, that access to static final is ~1.5 - 2 times more productive.

I found a quick solution in reflection:

private static final int SURROGATE = Runtime.getRuntime().availableProcessors(); //example
private static final Field SURROGATE_FIELD;
private static final String MODIFIERS_FIELD = "modifiers";
private static final ReflectionFactory reflection =
        ReflectionFactory.getReflectionFactory();
private static final FieldAccessor SURROGATE_FIELD_ACCESSOR;

static {
    try {
        SURROGATE_FIELD = ConstantFinalFieldBench.class.getDeclaredField("SURROGATE");
        SURROGATE_FIELD.setAccessible(true);
        Field modifiersField =
                Field.class.getDeclaredField(MODIFIERS_FIELD);
        modifiersField.setAccessible(true);
        int modifiers = modifiersField.getInt(SURROGATE_FIELD);
        modifiers &= ~Modifier.FINAL;
        modifiersField.setInt(SURROGATE_FIELD, modifiers);
        SURROGATE_FIELD_ACCESSOR = reflection.newFieldAccessor(
                SURROGATE_FIELD, false
        );
    } catch (Exception ex) {
        throw new Error(ex);
    }
}

@Param({"10"})
private static int paramConst;


@Setup
public void init() throws IllegalAccessException {
    SURROGATE_FIELD_ACCESSOR.setInt(null, paramConst);
}

Access to the "SURROGATE" parameter has performance, like to the final field. But maybe I missed something, or do not know, maybe has another method to do it?! Or it will good point to make support it in future.

Ilya K.
  • 241
  • 2
  • 9

1 Answers1

1

What exactly are you trying to accomplish? Overwriting static finals with horrible Reflection hacks? Good luck with that! You need to follow the language rules, and initialize static final-s with static initializers.

You cannot easily parameterize the values there, because you cannot pass any arguments to static initializer, except for some custom System.getProperty calls, and that's the way it is usually accomplished. JMH does not expose any API to poll the "current" parameters that are usable in static final initializations.

You might try to create a @State class with static, but not final field, put parameter over that field, and then very carefully trigger the initialization of another class that has static final field, that will query the static field in your first class. But, this is very fragile, and might have unforeseen consequences. Like, e.g. you would only be able to pull this off once per JVM, and every subsequent run in the same JVM will silently omit "reading" the @Param.

halfer
  • 19,824
  • 17
  • 99
  • 186
Aleksey Shipilev
  • 18,599
  • 2
  • 67
  • 86
  • My code has fields as 'static final', but I perform benchmark and I want find the best value for this static final constant. Yep, I understand language rules, but I need access to field with 'final field' speed, it's different with non-final field. I checked, static or non static, not matter, it should be final. Maybe I can declare some class with final field and provide factory for this class, dependent on parameter. And inject instance of my class from factory, to benchmark method.. – Ilya K. Nov 03 '15 at 18:12
  • @IlyaK. A reliable benchmark is based on the premise that the benchmark is repeatable. I think that you are trying to measure the wrong thing. Do you want to measure the performance of using a `FieldAccessor` (over the public reflection API)? Then you need to isolate your input values from being inlined, i.e. not make them `static final` and hack them. Also - spoiler - many (i.e. all) performance reflection hacks like the one you are implicitly proposing do not work. Use reflection. If you try to outsmart HotSpot, this almost always backfires. – Rafael Winterhalter Nov 03 '15 at 23:29
  • @IlyaK.: I think your only chance to initialize `static final` without breaking any rule (that will eventually backfire) is to use initial assignments or static initializers. JMH cannot help you there, because it presumes the benchmark state is dependent only on instance data, not the constant class data we cannot overwrite -- the isolation is broken otherwise. See the update. – Aleksey Shipilev Nov 04 '15 at 00:22