5

I have a piece logging and tracing related code, which called often throughout the code, especially when tracing is switched on. StringBuilder is used to build a String. Strings have reasonable maximum length, I suppose in the order of hundreds of chars.

Question: Is there existing library to do something like this:

// in reality, StringBuilder is final,
// would have to create delegated version instead,
// which is quite a big class because of all the append() overloads
public class SmarterBuilder extends StringBuilder {         

    private final AtomicInteger capRef;

    SmarterBuilder(AtomicInteger capRef) {
        int len = capRef.get(); 
        // optionally save memory with expense of worst-case resizes:
        // len = len * 3 / 4;
        super(len);
        this.capRef = capRef;
    }

    public syncCap() {
        // call when string is fully built
        int cap;
        do {
            cap = capRef.get();
            if (cap >= length()) break;
        } while (!capRef.compareAndSet(cap, length());
    }
}

To take advantage of this, my logging-related class would have a shared capRef variable with suitable scope.

(Bonus Question: I'm curious, is it possible to do syncCap() without looping?)

Motivation: I know default length of StringBuilder is always too little. I could (and currently do) throw in an ad-hoc intitial capacity value of 100, which results in resize in some number of cases, but not always. However, I do not like magic numbers in the source code, and this feature is a case of "optimize once, use in every project".

2 Answers 2

1

Make sure you do the performance measurements to make sure you really are getting some benefit for the extra work.

As an alternative to a StringBuilder-like class, consider a StringBuilderFactory. It could provide two static methods, one to get a StringBuilder, and the other to be called when you finish building a string. You could pass it a StringBuilder as argument, and it would record the length. The getStringBuilder method would use statistics recorded by the other method to choose the initial size.

There are two ways you could avoid looping in syncCap:

  1. Synchronize.
  2. Ignore failures.

The argument for ignoring failures in this situation is that you only need a random sampling of the actual lengths. If another thread is updating at the same time you are getting an up-to-date view of the string lengths anyway.

Sign up to request clarification or add additional context in comments.

1 Comment

I ended up creating a trivial inner factory class with get() and update() methods and right assumptions for that particular case.
0

You could store the string length of each string in a statistic array. run your app, and at shutdown you take the 90% quartil of your string length (sort all str length values, and take the length value at array pos = sortedStrings.size() * 0,9

That way you created an intial string builder size where 90% of your strings will fit in.

Update
The value could be hard coded (like java does for value 10 in ArrayList), or read from a config file, or calclualted automatically in a test phase. But the quartile calculation is not for free, so best you run your project some time, measure the 90% quartil on the fly inside the SmartBuilder, output the 90% quartil from time to time, and later change the property file to use the value.

That way you would get optimal results for each project.
Or if you go one step further: Let your smart Builder update that value from time to time in the config file. But this all is not worth the effort, you would do that only for data that have some millions entries, like digital road maps, etc.

1 Comment

If I read you correctly, you mean this as a way to get good value for hard-coding to the source code? Yes, but I'm looking for a way to do it automatically. The optimization is so small in the grand scheme of things, it makes no sense to spend time on optimizing several hard-coded values (in different parts of same project, in different projects), especially when optimal value might change with next code change anyway. Optimization has to be "free" (or at least very cheap, like adding one extra AtomicInteger to the code).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.